Torn Quick-Travel (Radial Menu)

Advanced radial navigation with modular search, API integration, mini-apps, and enhanced calibration

// ==UserScript==
// @name         Torn Quick-Travel (Radial Menu)
// @namespace    http://tampermonkey.net/
// @version      1.6.1
// @description  Advanced radial navigation with modular search, API integration, mini-apps, and enhanced calibration
// @author       Sensimillia (2168012)
// @match        https://www.torn.com/*
// @grant        GM_registerMenuCommand
// @grant        GM_notification
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// @connect      api.torn.com
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // ==================== DEBUG MODE ====================
    const DEBUG = false;
    const log = DEBUG ? console.log.bind(console, '[TornRadial]') : () => {};

    // ==================== NOTIFICATION THROTTLER ====================
    class NotificationThrottler {
        constructor() {
            this.lastNotifications = new Map();
            this.throttleTime = 2000; // 2 seconds minimum between same notifications
            this.maxPerMinute = 10;
            this.notificationCount = 0;
            this.resetInterval = null;
            
            this.resetInterval = setInterval(() => {
                this.notificationCount = 0;
            }, 60000);
        }

        canShow(message) {
            if (this.notificationCount >= this.maxPerMinute) {
                log('Notification throttled: rate limit reached');
                return false;
            }

            const now = Date.now();
            const lastTime = this.lastNotifications.get(message);
            
            if (lastTime && (now - lastTime) < this.throttleTime) {
                log('Notification throttled: too soon', message);
                return false;
            }

            this.lastNotifications.set(message, now);
            this.notificationCount++;
            return true;
        }

        destroy() {
            if (this.resetInterval) {
                clearInterval(this.resetInterval);
            }
        }
    }

    const NotificationManager = new NotificationThrottler();

    // ==================== ERROR LOGGER CLASS ====================
    class ErrorLoggerClass {
        constructor() {
            this.logs = [];
            this.maxLogs = 100;
            this.loadLogs();
        }

        log(type, message, error = null) {
            const entry = {
                timestamp: new Date().toISOString(),
                type: type,
                message: message,
                error: error ? {
                    name: error.name,
                    message: error.message,
                    stack: error.stack
                } : null,
                userAgent: navigator.userAgent,
                screenSize: `${window.innerWidth}x${window.innerHeight}`
            };
            
            this.logs.push(entry);
            if (this.logs.length > this.maxLogs) this.logs.shift();
            
            try {
                localStorage.setItem('tornRadialErrorLogs', JSON.stringify(this.logs));
            } catch(e) {
                console.error('Failed to save error logs:', e);
            }
            
            console.error(`[Torn Radial] ${type.toUpperCase()}: ${message}`, error);
        }

        loadLogs() {
            try {
                const stored = localStorage.getItem('tornRadialErrorLogs');
                if (stored) this.logs = JSON.parse(stored);
            } catch(e) {
                console.error('Failed to load error logs:', e);
            }
        }

        getLogs() {
            return this.logs;
        }

        clear() {
            this.logs = [];
            try {
                localStorage.removeItem('tornRadialErrorLogs');
            } catch(e) {
                console.error('Failed to clear error logs:', e);
            }
        }

        exportLogs() {
            const logsText = JSON.stringify(this.logs, null, 2);
            const blob = new Blob([logsText], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `torn-radial-errors-${new Date().toISOString()}.json`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }
    }

    const ErrorLogger = new ErrorLoggerClass();

    // ==================== STORAGE MANAGER CLASS ====================
    class StorageManager {
        get(key, defaultValue) {
            try {
                const item = localStorage.getItem(key);
                return item ? JSON.parse(item) : defaultValue;
            } catch (e) {
                ErrorLogger.log('error', `Error reading ${key} from localStorage`, e);
                return defaultValue;
            }
        }

        set(key, value) {
            try {
                localStorage.setItem(key, JSON.stringify(value));
                return true;
            } catch (e) {
                ErrorLogger.log('error', `Error saving ${key} to localStorage`, e);
                return false;
            }
        }

        remove(key) {
            try {
                localStorage.removeItem(key);
                return true;
            } catch (e) {
                ErrorLogger.log('error', `Error removing ${key} from localStorage`, e);
                return false;
            }
        }

        exportAll() {
            const data = {
                settings: this.get('tornRadialSettings', {}),
                loadouts: this.get('tornRadialLoadouts', {}),
                position: this.get('tornRadialPosition', {}),
                positionMobile: this.get('tornRadialPositionMobile', {}),
                usageStats: this.get('tornRadialUsageStats', {}),
                timers: this.get('tornRadialTimers', []),
                notes: this.get('tornRadialNotes', ''),
                searchHistory: this.get('tornRadialSearchHistory', []),
                calibration: this.get('tornRadialCalibration', {}),
                calibrationMobile: this.get('tornRadialCalibrationMobile', {})
            };
            
            const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `torn-radial-backup-${new Date().toISOString()}.json`;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }

        importAll(jsonData) {
            try {
                const data = JSON.parse(jsonData);
                if (data.settings) this.set('tornRadialSettings', data.settings);
                if (data.loadouts) this.set('tornRadialLoadouts', data.loadouts);
                if (data.position) this.set('tornRadialPosition', data.position);
                if (data.positionMobile) this.set('tornRadialPositionMobile', data.positionMobile);
                if (data.usageStats) this.set('tornRadialUsageStats', data.usageStats);
                if (data.timers) this.set('tornRadialTimers', data.timers);
                if (data.notes) this.set('tornRadialNotes', data.notes);
                if (data.searchHistory) this.set('tornRadialSearchHistory', data.searchHistory);
                if (data.calibration) this.set('tornRadialCalibration', data.calibration);
                if (data.calibrationMobile) this.set('tornRadialCalibrationMobile', data.calibrationMobile);
                return true;
            } catch (e) {
                ErrorLogger.log('error', 'Failed to import data', e);
                return false;
            }
        }
    }

    const Storage = new StorageManager();

    // ==================== DEVICE DETECTION ====================
    const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || window.innerWidth < 768;
    const isPDA = window.innerWidth < 768;

    // ==================== TORN API HANDLER CLASS ====================
    class TornAPI {
        constructor() {
            this.baseUrl = 'https://api.torn.com';
            this.apiKey = Storage.get('tornRadialApiKey', '');
        }

        setApiKey(key) {
            this.apiKey = key;
            Storage.set('tornRadialApiKey', key);
        }

        async request(endpoint) {
            if (!this.apiKey) {
                throw new Error('API key not set');
            }

            return new Promise((resolve, reject) => {
                if (typeof GM_xmlhttpRequest === 'undefined') {
                    reject(new Error('GM_xmlhttpRequest not available'));
                    return;
                }

                GM_xmlhttpRequest({
                    method: 'GET',
                    url: `${this.baseUrl}${endpoint}&key=${this.apiKey}`,
                    onload: (response) => {
                        try {
                            const data = JSON.parse(response.responseText);
                            if (data.error) {
                                reject(new Error(data.error.error));
                            } else {
                                resolve(data);
                            }
                        } catch (e) {
                            reject(e);
                        }
                    },
                    onerror: (error) => reject(error)
                });
            });
        }

        async getUserInfo(userId) {
            return this.request(`/user/${userId}?selections=profile,timestamp`);
        }

        async getBars() {
            return this.request(`/user/?selections=bars`);
        }

        async getCooldowns() {
            return this.request(`/user/?selections=cooldowns`);
        }
    }

    const API = new TornAPI();

    // ==================== SEARCH HANDLER CLASS ====================
    class SearchHandler {
        constructor() {
            this.history = Storage.get('tornRadialSearchHistory', []);
            this.maxHistory = 20;
        }

        addToHistory(query, url, type) {
            const entry = {
                query: query,
                url: url,
                type: type,
                timestamp: Date.now()
            };

            this.history = this.history.filter(h => h.query !== query);
            this.history.unshift(entry);
            this.history = this.history.slice(0, this.maxHistory);
            Storage.set('tornRadialSearchHistory', this.history);
        }

        getHistory() {
            return this.history;
        }

        clearHistory() {
            this.history = [];
            Storage.set('tornRadialSearchHistory', []);
        }

        async search(query) {
        const results = {
        players: [],
        items: [],
        pages: [],
        factions: [],
        companies: []
    };

    const queryLower = query.toLowerCase().trim();

    // Player ID or name search
    if (/^\d+$/.test(query)) {
        // Direct player ID
        results.players.push({
            name: `Player ID: ${query}`,
            url: `/profiles.php?XID=${query}`,
            icon: '👤',
            type: 'player'
        });
    } else if (query.length >= 3) {
        // Player name search
        results.players.push({
            name: `Search Player: "${query}"`,
            url: `/profiles.php?XID=${query}`,
            icon: '👤',
            type: 'player'
        });
    }

    // Faction search
    if (/^\d+$/.test(query)) {
        results.factions.push({
            name: `Faction ID: ${query}`,
            url: `/factions.php?step=profile&ID=${query}`,
            icon: '⚔️',
            type: 'faction'
        });
    }

    // Company search
    if (/^\d+$/.test(query)) {
        results.companies.push({
            name: `Company ID: ${query}`,
            url: `/companies.php?step=profile&ID=${query}`,
            icon: '🏢',
            type: 'company'
        });
    }

    // Item search - match any query with 2+ characters
    if (query.length >= 2) {
        results.items.push({
            name: `Search Items: "${query}"`,
            url: `/imarket.php#/p=shop&step=shop&type=&searchname=${encodeURIComponent(query)}`,
            icon: '🛒',
            type: 'item'
        });
    }

    // Page matches with better keyword detection
    const pageMatches = [
        { keywords: ['gym', 'train', 'stat'], name: 'Gym', url: '/gym.php', icon: '💪' },
        { keywords: ['travel', 'fly', 'airport', 'abroad'], name: 'Travel Agency', url: '/travelagency.php', icon: '✈️' },
        { keywords: ['item', 'inventory', 'inv'], name: 'Items', url: '/item.php', icon: '🎒' },
        { keywords: ['bazaar', 'baz', 'shop'], name: 'Bazaar', url: '/bazaar.php', icon: '🏪' },
        { keywords: ['display', 'cabinet', 'trophy', 'case'], name: 'Display Cabinet', url: '/displaycase.php', icon: '🏆' },
        { keywords: ['faction', 'fac'], name: 'Faction', url: '/factions.php', icon: '⚔️' },
        { keywords: ['crime', 'oc', 'organized'], name: 'Crimes', url: '/crimes.php', icon: '🔫' },
        { keywords: ['hospital', 'hosp', 'revive'], name: 'Hospital', url: '/hospital.php', icon: '🏥' },
        { keywords: ['mission', 'duke'], name: 'Missions', url: '/loader.php?sid=missions', icon: '🎯' },
        { keywords: ['auction'], name: 'Auctions', url: '/auctions.php', icon: '🔨' },
        { keywords: ['message', 'mail', 'inbox'], name: 'Messages', url: '/messages.php', icon: '💬' },
        { keywords: ['event', 'log'], name: 'Events', url: '/events.php', icon: '📅' },
        { keywords: ['forum', 'forums'], name: 'Forums', url: '/forums.php', icon: '💭' },
        { keywords: ['city', 'map'], name: 'City', url: '/city.php', icon: '🏙️' },
        { keywords: ['company', 'job', 'work'], name: 'Job Listings', url: '/joblist.php', icon: '🏢' },
        { keywords: ['property', 'properties', 'home'], name: 'Property', url: '/properties.php', icon: '🏘️' },
        { keywords: ['attack', 'fight', 'log'], name: 'Attack Log', url: '/attacklog.php', icon: '⚡' },
        { keywords: ['bounty', 'bounties'], name: 'Bounties', url: '/bounties.php', icon: '💀' },
        { keywords: ['war', 'rankedwar', 'rw'], name: 'War', url: '/war.php', icon: '💣' },
        { keywords: ['jail', 'prison', 'bust'], name: 'Jail', url: '/jailview.php', icon: '🔒' },
        { keywords: ['newspaper', 'news'], name: 'Newspaper', url: '/newspaper.php', icon: '📰' },
        { keywords: ['home', 'index'], name: 'Home', url: '/index.php', icon: '🏠' },
        { keywords: ['points', 'refill', 'market'], name: 'Points Market', url: '/pmarket.php', icon: '⭐' },
        { keywords: ['race', 'racing', 'track'], name: 'Racing', url: '/loader.php?sid=racing', icon: '🏎️' },
        { keywords: ['casino', 'gamble'], name: 'Casino', url: '/loader.php?sid=casino', icon: '🎰' },
        { keywords: ['education', 'school', 'course'], name: 'Education', url: '/education.php', icon: '📚' },
        { keywords: ['trade'], name: 'Trade', url: '/trade.php', icon: '🤝' },
        { keywords: ['bank', 'vault', 'money'], name: 'Bank', url: '/bank.php', icon: '🏦' },
        { keywords: ['stock', 'stocks', 'exchange'], name: 'Stock Exchange', url: '/stockexchange.php', icon: '📈' },
        { keywords: ['church', 'marry'], name: 'Church', url: '/church.php', icon: '⛪' },
        { keywords: ['museum'], name: 'Museum', url: '/museum.php', icon: '🏛️' },
        { keywords: ['hall', 'fame'], name: 'Hall of Fame', url: '/halloffame.php', icon: '🏆' },
        { keywords: ['competition'], name: 'Competitions', url: '/competition.php', icon: '🎯' }
    ];

    // Find all matching pages
    pageMatches.forEach(match => {
        if (match.keywords.some(k => queryLower.includes(k))) {
            results.pages.push({
                name: match.name,
                url: match.url,
                icon: match.icon,
                type: 'page'
            });
        }
    });

    return results;
}
    }

    const SearchManager = new SearchHandler();

    // ==================== DYNAMIC THEME SYSTEM ====================
    const THEMES = {
        torn: {
            name: 'Torn',
            modalBg: 'rgba(27, 27, 27, 0.98)',
            modalHeaderBg: 'rgba(36, 36, 36, 0.95)',
            modalFooterBg: 'rgba(34, 34, 34, 0.95)',
            sectionBg: 'rgba(36, 36, 36, 0.8)',
            inputBg: 'rgba(51, 51, 51, 0.9)',
            textColor: '#d0d0d0',
            textSecondary: '#9b9b9b',
            borderColor: 'rgba(51, 51, 51, 0.5)',
            mainBtnBg: 'rgba(36, 36, 36, 0.95)',
            mainBtnBorder: 'rgba(74, 163, 223, 0.3)',
            primaryColor: '#4aa3df',
            accentGradient: 'linear-gradient(135deg, #4aa3df 0%, #66baff 100%)',
            dangerColor: '#a33a3a',
            successColor: '#3ea34a'
        },
        light: {
            name: 'Light',
            modalBg: 'rgba(255, 255, 255, 0.95)',
            modalHeaderBg: 'rgba(255, 255, 255, 0.5)',
            modalFooterBg: 'rgba(249, 249, 249, 0.8)',
            sectionBg: 'rgba(255, 255, 255, 0.7)',
            inputBg: 'rgba(120, 120, 128, 0.12)',
            textColor: '#000',
            textSecondary: '#666',
            borderColor: 'rgba(0, 0, 0, 0.08)',
            mainBtnBg: 'rgba(255, 255, 255, 0.95)',
            mainBtnBorder: 'rgba(0, 0, 0, 0.04)',
            primaryColor: '#007AFF',
            accentGradient: 'linear-gradient(135deg, #FF2D55 0%, #FF375F 100%)',
            dangerColor: '#FF3B30',
            successColor: '#34C759'
        },
        dark: {
            name: 'Dark',
            modalBg: 'rgba(28, 28, 30, 0.95)',
            modalHeaderBg: 'rgba(44, 44, 46, 0.5)',
            modalFooterBg: 'rgba(20, 20, 22, 0.8)',
            sectionBg: 'rgba(44, 44, 46, 0.7)',
            inputBg: 'rgba(255, 255, 255, 0.1)',
            textColor: '#FFFFFF',
            textSecondary: '#9b9b9b',
            borderColor: 'rgba(255, 255, 255, 0.12)',
            mainBtnBg: 'rgba(44, 44, 46, 0.95)',
            mainBtnBorder: 'rgba(255, 255, 255, 0.08)',
            primaryColor: '#0A84FF',
            accentGradient: 'linear-gradient(135deg, #FF453A 0%, #FF375F 100%)',
            dangerColor: '#FF453A',
            successColor: '#32D74B'
        },
        cyberpunk: {
            name: 'Cyberpunk',
            modalBg: 'rgba(10, 10, 15, 0.98)',
            modalHeaderBg: 'rgba(20, 20, 30, 0.95)',
            modalFooterBg: 'rgba(15, 15, 20, 0.95)',
            sectionBg: 'rgba(25, 25, 35, 0.8)',
            inputBg: 'rgba(35, 35, 50, 0.9)',
            textColor: '#00ff9f',
            textSecondary: '#7b68ee',
            borderColor: 'rgba(0, 255, 159, 0.3)',
            mainBtnBg: 'rgba(20, 20, 30, 0.95)',
            mainBtnBorder: 'rgba(255, 0, 255, 0.5)',
            primaryColor: '#ff00ff',
            accentGradient: 'linear-gradient(135deg, #ff00ff 0%, #00ffff 100%)',
            dangerColor: '#ff0080',
            successColor: '#00ff9f'
        },
        ocean: {
            name: 'Ocean',
            modalBg: 'rgba(15, 25, 40, 0.98)',
            modalHeaderBg: 'rgba(20, 35, 55, 0.95)',
            modalFooterBg: 'rgba(10, 20, 35, 0.95)',
            sectionBg: 'rgba(25, 40, 60, 0.8)',
            inputBg: 'rgba(30, 50, 75, 0.9)',
            textColor: '#e0f4ff',
            textSecondary: '#6fa8dc',
            borderColor: 'rgba(79, 195, 247, 0.3)',
            mainBtnBg: 'rgba(20, 35, 55, 0.95)',
            mainBtnBorder: 'rgba(79, 195, 247, 0.5)',
            primaryColor: '#4fc3f7',
            accentGradient: 'linear-gradient(135deg, #0288d1 0%, #26c6da 100%)',
            dangerColor: '#ff6e40',
            successColor: '#69f0ae'
        },
        sunset: {
            name: 'Sunset',
            modalBg: 'rgba(40, 20, 30, 0.98)',
            modalHeaderBg: 'rgba(60, 30, 45, 0.95)',
            modalFooterBg: 'rgba(35, 15, 25, 0.95)',
            sectionBg: 'rgba(55, 25, 40, 0.8)',
            inputBg: 'rgba(70, 35, 50, 0.9)',
            textColor: '#ffe0b2',
            textSecondary: '#ffab91',
            borderColor: 'rgba(255, 138, 101, 0.3)',
            mainBtnBg: 'rgba(60, 30, 45, 0.95)',
            mainBtnBorder: 'rgba(255, 138, 101, 0.5)',
            primaryColor: '#ff8a65',
            accentGradient: 'linear-gradient(135deg, #ff6f00 0%, #ff9100 100%)',
            dangerColor: '#d50000',
            successColor: '#76ff03'
        },
        neonNoir: {
            name: 'Neon Noir',
            modalBg: 'rgba(10, 10, 15, 0.98)',
            modalHeaderBg: 'rgba(20, 20, 25, 0.95)',
            modalFooterBg: 'rgba(15, 15, 20, 0.9)',
            sectionBg: 'rgba(25, 25, 30, 0.8)',
            inputBg: 'rgba(40, 40, 50, 0.9)',
            textColor: '#c0c0ff',
            textSecondary: '#8080ff',
            borderColor: 'rgba(120, 120, 255, 0.3)',
            mainBtnBg: 'rgba(20, 20, 25, 0.95)',
            mainBtnBorder: 'rgba(120, 120, 255, 0.4)',
            primaryColor: '#9b59b6',
            accentGradient: 'linear-gradient(135deg, #8e44ad 0%, #3498db 100%)',
            dangerColor: '#e74c3c',
            successColor: '#2ecc71'
        },
        bloodline: {
            name: 'Bloodline',
            modalBg: 'rgba(15, 10, 10, 0.98)',
            modalHeaderBg: 'rgba(25, 15, 15, 0.95)',
            modalFooterBg: 'rgba(20, 10, 10, 0.9)',
            sectionBg: 'rgba(35, 20, 20, 0.8)',
            inputBg: 'rgba(45, 25, 25, 0.9)',
            textColor: '#f0b0b0',
            textSecondary: '#c07070',
            borderColor: 'rgba(255, 80, 80, 0.3)',
            mainBtnBg: 'rgba(30, 15, 15, 0.95)',
            mainBtnBorder: 'rgba(255, 0, 0, 0.4)',
            primaryColor: '#e63946',
            accentGradient: 'linear-gradient(135deg, #b71c1c 0%, #f44336 100%)',
            dangerColor: '#ff5252',
            successColor: '#81c784'
        },
        stealth: {
            name: 'Stealth',
            modalBg: 'rgba(8, 8, 8, 0.98)',
            modalHeaderBg: 'rgba(12, 12, 12, 0.95)',
            modalFooterBg: 'rgba(10, 10, 10, 0.9)',
            sectionBg: 'rgba(15, 15, 15, 0.8)',
            inputBg: 'rgba(25, 25, 25, 0.9)',
            textColor: '#c0c0c0',
            textSecondary: '#888',
            borderColor: 'rgba(255, 255, 255, 0.05)',
            mainBtnBg: 'rgba(18, 18, 18, 0.95)',
            mainBtnBorder: 'rgba(255, 255, 255, 0.1)',
            primaryColor: '#4a90e2',
            accentGradient: 'linear-gradient(135deg, #4a90e2 0%, #00bcd4 100%)',
            dangerColor: '#f44336',
            successColor: '#4caf50'
        },
        terminal: {
            name: 'Terminal',
            modalBg: 'rgba(5, 10, 5, 0.98)',
            modalHeaderBg: 'rgba(10, 15, 10, 0.95)',
            modalFooterBg: 'rgba(8, 12, 8, 0.9)',
            sectionBg: 'rgba(12, 20, 12, 0.8)',
            inputBg: 'rgba(20, 30, 20, 0.9)',
            textColor: '#00ff00',
            textSecondary: '#66ff66',
            borderColor: 'rgba(0, 255, 0, 0.3)',
            mainBtnBg: 'rgba(10, 20, 10, 0.95)',
            mainBtnBorder: 'rgba(0, 255, 0, 0.4)',
            primaryColor: '#00ff66',
            accentGradient: 'linear-gradient(135deg, #00cc00 0%, #00ff99 100%)',
            dangerColor: '#ff0033',
            successColor: '#33ff00'
        }
    };

    function getThemeNames() {
        return Object.keys(THEMES);
    }

    function getTheme(themeName) {
        return THEMES[themeName] || THEMES.torn;
    }
    
    // ==================== DEFAULT DATA ====================
    const DEFAULT_LINKS = [
        { name: 'Home', url: '/index.php', icon: '🏠', color: '#4aa3df' },
        { name: 'Items', url: '/item.php', icon: '🎒', color: '#3ea34a' },
        { name: 'City', url: '/city.php', icon: '🏙️', color: '#66baff' },
        { name: 'Job', url: '/job.php', icon: '💼', color: '#3ea34a' },
        { name: 'Gym', url: '/gym.php', icon: '💪', color: '#a33a3a' },
        { name: 'Crimes', url: '/crimes.php', icon: '🔫', color: '#a33a3a' },
        { name: 'Missions', url: '/loader.php?sid=missions', icon: '🎯', color: '#4aa3df' },
        { name: 'Newspaper', url: '/newspaper.php', icon: '📰', color: '#9b9b9b' }
    ];

    const DEFAULT_LOADOUTS = {
        'default': { name: 'Default', links: [...DEFAULT_LINKS] },
        'trading': { 
            name: 'Trading', 
            links: [
                { name: 'Bazaar', url: '/bazaar.php', icon: '🏪', color: '#3ea34a' },
                { name: 'Item Market', url: '/imarket.php', icon: '💰', color: '#3ea34a' },
                { name: 'Points Market', url: '/pmarket.php', icon: '⭐', color: '#FFD700' },
                { name: 'Auctions', url: '/auctions.php', icon: '🔨', color: '#4aa3df' },
                { name: 'Trade', url: '/trade.php', icon: '🤝', color: '#4aa3df' },
                { name: 'Display Case', url: '/displaycase.php', icon: '🏆', color: '#66baff' },
                { name: 'Items', url: '/item.php', icon: '🎒', color: '#3ea34a' },
                { name: 'Properties', url: '/properties.php', icon: '🏘️', color: '#9b9b9b' }
            ]
        },
        'combat': {
            name: 'Combat',
            links: [
                { name: 'Gym', url: '/gym.php', icon: '💪', color: '#a33a3a' },
                { name: 'Crimes', url: '/crimes.php', icon: '🔫', color: '#a33a3a' },
                { name: 'Hospital', url: '/hospital.php', icon: '🏥', color: '#a33a3a' },
                { name: 'Faction', url: '/factions.php', icon: '⚔️', color: '#66baff' },
                { name: 'War', url: '/war.php', icon: '💣', color: '#a33a3a' },
                { name: 'Bounties', url: '/bounties.php', icon: '💀', color: '#9b9b9b' },
                { name: 'Attacks', url: '/attacks.php', icon: '⚡', color: '#a33a3a' },
                { name: 'Attack Log', url: '/attacklog.php', icon: '📜', color: '#9b9b9b' }
            ]
        },
        'travel': {
            name: 'Travel',
            links: [
                { name: 'Travel', url: '/travel.php', icon: '✈️', color: '#4aa3df' },
                { name: 'Home', url: '/index.php', icon: '🏠', color: '#4aa3df' },
                { name: 'Items', url: '/item.php', icon: '🎒', color: '#3ea34a' },
                { name: 'Bazaar', url: '/bazaar.php', icon: '🏪', color: '#3ea34a' },
                { name: 'City', url: '/city.php', icon: '🏙️', color: '#66baff' },
                { name: 'Laptop', url: '/pc.php', icon: '💻', color: '#9b9b9b' }
            ]
        },
        'social': {
            name: 'Social',
            links: [
                { name: 'Messages', url: '/messages.php', icon: '💬', color: '#4aa3df' },
                { name: 'Events', url: '/events.php', icon: '📅', color: '#66baff' },
                { name: 'Forums', url: '/forums.php', icon: '💭', color: '#9b9b9b' },
                { name: 'Friends', url: '/friends.php', icon: '👥', color: '#3ea34a' },
                { name: 'Faction', url: '/factions.php', icon: '⚔️', color: '#66baff' },
                { name: 'Company', url: '/companies.php', icon: '🏢', color: '#9b9b9b' }
            ]
        }
    };

    // ==================== STATE MANAGEMENT ====================
    let settings = Storage.get('tornRadialSettings', {
        layout: 'circular',
        iconSize: 'medium',
        currentLoadout: 'default',
        theme: 'torn',
        notifications: { enabled: true },
        screenCalibration: null,
        screenCalibrationMobile: null,
        apiKey: ''
    });

    settings = {
        layout: settings.layout || 'circular',
        iconSize: settings.iconSize || 'medium',
        currentLoadout: settings.currentLoadout || 'default',
        theme: settings.theme || 'torn',
        notifications: settings.notifications || { enabled: true },
        screenCalibration: settings.screenCalibration || null,
        screenCalibrationMobile: settings.screenCalibrationMobile || null,
        apiKey: settings.apiKey || ''
    };

    if (settings.apiKey) {
        API.setApiKey(settings.apiKey);
    }

    let loadouts = Storage.get('tornRadialLoadouts', DEFAULT_LOADOUTS);
    let usageStats = Storage.get('tornRadialUsageStats', {});
    let timers = Storage.get('tornRadialTimers', []);

    if (!loadouts || typeof loadouts !== 'object') {
        ErrorLogger.log('error', 'Invalid loadouts structure, restoring defaults');
        loadouts = { ...DEFAULT_LOADOUTS };
    }

    if (!loadouts[settings.currentLoadout]) {
        ErrorLogger.log('error', `Loadout ${settings.currentLoadout} not found, switching to default`);
        settings.currentLoadout = 'default';
        if (!loadouts['default']) {
            loadouts['default'] = DEFAULT_LOADOUTS['default'];
        }
    }

    // Generate favorites
    function generateFavoritesLoadout() {
        const sorted = Object.entries(usageStats)
            .sort((a, b) => b[1] - a[1])
            .slice(0, 8)
            .map(([url]) => {
                for (const loadout of Object.values(loadouts)) {
                    const link = loadout.links?.find(l => l.url === url);
                    if (link) return link;
                }
                return null;
            })
            .filter(Boolean);

        if (sorted.length > 0) {
            loadouts['favorites'] = {
                name: '⭐ Favorites',
                links: sorted
            };
        }
    }

    generateFavoritesLoadout();

    let links = [];
    try {
        links = loadouts[settings.currentLoadout]?.links || [...DEFAULT_LINKS];
        links = links.map((link, i) => ({
            name: link?.name || 'Unnamed',
            url: link?.url || '/index.php',
            icon: link?.icon || '🔗',
            color: link?.color || DEFAULT_LINKS[i]?.color || '#4aa3df'
        }));
    } catch (e) {
        ErrorLogger.log('error', 'Error loading links from loadout', e);
        links = [...DEFAULT_LINKS];
    }

    let isOpen = false;
    let isDragging = false;
    let isAnimating = false;
    let currentX, currentY, initialX, initialY, xOffset = 0, yOffset = 0;
    let startX, startY, hasMoved = false;
    let calibrationMode = false;
    let calibrationStep = 0;
    let selectedSearchIndex = 0;

    // ==================== POSITION MANAGEMENT ====================
    function getSafeInitialPosition() {
        const padding = 100;
        const centerX = window.innerWidth / 2;
        const centerY = window.innerHeight / 2;
        
        return {
            x: Math.max(padding, Math.min(centerX, window.innerWidth - padding)),
            y: Math.max(padding, Math.min(centerY, window.innerHeight - padding))
        };
    }

    // Load position based on device type
    const positionKey = isPDA ? 'tornRadialPositionMobile' : 'tornRadialPosition';
    const savedPos = Storage.get(positionKey, getSafeInitialPosition());

    // ==================== SIZE CONFIGURATIONS ====================
    const sizeConfig = {
        pda: { main: 32, radial: 28, fontSize: 14, radialFont: 12, radius: 65, spacing: 14, maxPerRow: 7 },
        small: { main: 52, radial: 42, fontSize: 20, radialFont: 18, radius: 90, spacing: 16, maxPerRow: 9 },
        medium: { main: 64, radial: 52, fontSize: 28, radialFont: 24, radius: 110, spacing: 16, maxPerRow: 10 },
        large: { main: 76, radial: 62, fontSize: 34, radialFont: 28, radius: 130, spacing: 16, maxPerRow: 12 }
    };

    let currentSize = sizeConfig[settings.iconSize] || sizeConfig.medium;
    const currentTheme = getTheme(settings.theme);

    // ==================== HELPER FUNCTIONS ====================
    function adjustBrightness(color, percent) {
        if (!color || typeof color !== 'string' || !color.startsWith('#')) return '#4aa3df';
        try {
            const num = parseInt(color.replace('#', ''), 16);
            if (isNaN(num)) return '#4aa3df';
            
            const amt = Math.round(2.55 * percent);
            const R = Math.min(255, Math.max(0, (num >> 16) + amt));
            const G = Math.min(255, Math.max(0, (num >> 8 & 0x00FF) + amt));
            const B = Math.min(255, Math.max(0, (num & 0x0000FF) + amt));
            return '#' + ((1 << 24) + (R << 16) + (G << 8) + B).toString(16).slice(1);
        } catch(e) {
            ErrorLogger.log('error', 'Color adjustment failed', e);
            return '#4aa3df';
        }
    }

    function showNotification(message, duration = 3000) {
        if (!NotificationManager.canShow(message)) {
            return;
        }

        try {
            const notification = document.createElement('div');
            notification.className = 'torn-radial-notification';
            notification.textContent = message;
            document.body.appendChild(notification);
            
            setTimeout(() => {
                notification.style.transition = 'all 0.3s ease-out';
                notification.style.opacity = '0';
                notification.style.transform = 'translateX(400px)';
                setTimeout(() => notification.remove(), 300);
            }, duration);
        } catch(e) {
            ErrorLogger.log('error', 'Failed to show notification', e);
        }
    }

    function trackUsage(url) {
        try {
            if (!usageStats[url]) usageStats[url] = 0;
            usageStats[url]++;
            Storage.set('tornRadialUsageStats', usageStats);
            
            if (Object.keys(usageStats).length >= 8) {
                generateFavoritesLoadout();
                Storage.set('tornRadialLoadouts', loadouts);
            }
        } catch(e) {
            ErrorLogger.log('error', 'Failed to track usage', e);
        }
    }

    function calculatePosition(index, total, layout) {
        try {
            const radius = currentSize?.radius || 110;
            const spacing = currentSize?.spacing || 16;
            const maxPerRow = currentSize?.maxPerRow || 8;
            let x = 0, y = 0;

            switch(layout) {
                case 'horizontal': {
                    const isLeftSide = (savedPos?.x || 50) < window.innerWidth / 2;
                    const isTopHalf = (savedPos?.y || 50) < window.innerHeight / 2;
                    
                    const row = Math.floor(index / maxPerRow);
                    const posInRow = index % maxPerRow;
                    
                    x = isLeftSide ? 
                        (posInRow + 1) * (currentSize.radial + spacing) : 
                        -(posInRow + 1) * (currentSize.radial + spacing);
                    
                    const rowOffset = (currentSize.radial + spacing) * 0.8;
                    y = isTopHalf ? 
                        row * rowOffset : 
                        -row * rowOffset;
                    break;
                }
                case 'vertical': {
                    const isTopHalf = (savedPos?.y || 50) < window.innerHeight / 2;
                    const isLeftSide = (savedPos?.x || 50) < window.innerWidth / 2;
                    
                    const col = Math.floor(index / maxPerRow);
                    const posInCol = index % maxPerRow;
                    
                    y = isTopHalf ? 
                        (posInCol + 1) * (currentSize.radial + spacing) : 
                        -(posInCol + 1) * (currentSize.radial + spacing);
                    
                    const colOffset = (currentSize.radial + spacing) * 0.8;
                    x = isLeftSide ? 
                        col * colOffset : 
                        -col * colOffset;
                    break;
                }
                case 'circular':
                default: {
                    const maxPerRing = 12;
                    const ring = Math.floor(index / maxPerRing);
                    const posInRing = index % maxPerRing;
                    const totalInRing = Math.min(maxPerRing, total - (ring * maxPerRing));
                    
                    const ringRadius = radius + (ring * (currentSize.radial + spacing));
                    const angleStep = (2 * Math.PI) / totalInRing;
                    const angle = angleStep * posInRing - Math.PI / 2;
                    
                    x = Math.cos(angle) * ringRadius;
                    y = Math.sin(angle) * ringRadius;
                    break;
                }
            }

            return { x, y };
        } catch(e) {
            ErrorLogger.log('error', 'Position calculation failed', e);
            return { x: 0, y: 0 };
        }
    }

    // Enhanced bounds checking with device-specific calibration
    function checkBounds(pos) {
        try {
            const menuX = savedPos.x;
            const menuY = savedPos.y;
            const buttonRadius = currentSize.radial / 2;
            
            const itemX = menuX + pos.x;
            const itemY = menuY + pos.y;
            
            // Get calibration based on device type
            const calibration = isPDA ? settings.screenCalibrationMobile : settings.screenCalibration;
            
            let bounds;
            if (calibration) {
                // STRICT: Use exact calibration points
                bounds = {
                    left: calibration.topLeft.x + buttonRadius,
                    right: calibration.bottomRight.x - buttonRadius,
                    top: calibration.topLeft.y + buttonRadius,
                    bottom: calibration.bottomRight.y - buttonRadius
                };
                
                log('Calibration bounds:', bounds);
                log('Item position:', itemX, itemY);
            } else {
                bounds = {
                    left: 10 + buttonRadius,
                    right: window.innerWidth - 90 - buttonRadius,
                    top: 25 + buttonRadius,
                    bottom: window.innerHeight - 25 - buttonRadius
                };
            }
            
            let needsReposition = false;
            let newX = menuX;
            let newY = menuY;
            
            // Check if ANY item exceeds bounds
            if (itemX < bounds.left) {
                newX = menuX + (bounds.left - itemX);
                needsReposition = true;
                log('Item exceeds left bound, adjusting');
            } else if (itemX > bounds.right) {
                newX = menuX - (itemX - bounds.right);
                needsReposition = true;
                log('Item exceeds right bound, adjusting');
            }
            
            if (itemY < bounds.top) {
                newY = menuY + (bounds.top - itemY);
                needsReposition = true;
                log('Item exceeds top bound, adjusting');
            } else if (itemY > bounds.bottom) {
                newY = menuY - (itemY - bounds.bottom);
                needsReposition = true;
                log('Item exceeds bottom bound, adjusting');
            }
            
            if (needsReposition) {
                savedPos.x = Math.round(newX);
                savedPos.y = Math.round(newY);
                container.style.left = savedPos.x + 'px';
                container.style.top = savedPos.y + 'px';
                Storage.set(positionKey, savedPos);
                
                showNotification('⚠️ Menu repositioned to stay within bounds');
                
                setTimeout(() => {
                    createRadialItems();
                }, 100);
            }
        } catch(e) {
            ErrorLogger.log('error', 'Failed to check bounds', e);
        }
    }

    // PDA responsive scaling
    function getResponsiveSize(baseSize) {
        if (isPDA) {
            return Math.round(baseSize * 0.8);
        }
        return baseSize;
    }

    function getResponsiveFontSize(baseFontSize) {
        if (isPDA) {
            return Math.round(baseFontSize * 0.85);
        }
        return baseFontSize;
    }
    
    // ==================== CSS INJECTION ====================
    const style = document.createElement('style');
    style.textContent = `
        @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600;700&display=swap');

        * {
            font-family: -apple-system, BlinkMacSystemFont, 'Roboto', 'Segoe UI', sans-serif;
        }

        #torn-radial-container {
            position: fixed;
            left: ${savedPos.x}px;
            top: ${savedPos.y}px;
            z-index: 999999;
            pointer-events: none;
            transform-origin: center center;
        }

        #torn-radial-btn {
            width: ${currentSize.main}px;
            height: ${currentSize.main}px;
            border-radius: 50%;
            background: ${currentTheme.mainBtnBg};
            backdrop-filter: saturate(180%) blur(20px);
            -webkit-backdrop-filter: saturate(180%) blur(20px);
            border: 2px solid ${currentTheme.mainBtnBorder};
            cursor: pointer;
            pointer-events: auto;
            box-shadow: 
                0 12px 48px rgba(0, 0, 0, 0.15),
                0 2px 8px rgba(0, 0, 0, 0.08);
            transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: ${currentSize.fontSize}px;
            user-select: none;
            position: relative;
            color: ${currentTheme.primaryColor};
        }

        #torn-radial-btn:active {
            transform: scale(0.92);
        }

        #torn-radial-btn:hover {
            transform: scale(1.05);
            box-shadow: 
                0 16px 56px rgba(0, 0, 0, 0.2),
                0 4px 12px rgba(0, 0, 0, 0.1),
                0 0 0 4px ${currentTheme.primaryColor}33;
            animation: pulse-glow 2s infinite;
        }

        @keyframes pulse-glow {
            0%, 100% { box-shadow: 0 16px 56px rgba(0, 0, 0, 0.2), 0 4px 12px rgba(0, 0, 0, 0.1), 0 0 0 4px ${currentTheme.primaryColor}33; }
            50% { box-shadow: 0 16px 56px rgba(0, 0, 0, 0.2), 0 4px 12px rgba(0, 0, 0, 0.1), 0 0 0 8px ${currentTheme.primaryColor}55; }
        }

        #torn-radial-btn.dragging {
            cursor: grabbing;
            transform: scale(1.1);
            box-shadow: 
                0 20px 64px rgba(0, 0, 0, 0.25),
                0 6px 16px rgba(0, 0, 0, 0.15);
        }

        .radial-item {
            position: absolute;
            width: ${currentSize.radial}px;
            height: ${currentSize.radial}px;
            border-radius: 50%;
            cursor: pointer;
            pointer-events: auto;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: ${currentSize.radialFont}px;
            box-shadow: 
                0 8px 24px rgba(0, 0, 0, 0.2),
                0 2px 6px rgba(0, 0, 0, 0.12);
            transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
            opacity: 0;
            transform: scale(0);
            text-decoration: none;
            left: ${(currentSize.main - currentSize.radial) / 2}px;
            top: ${(currentSize.main - currentSize.radial) / 2}px;
            backdrop-filter: saturate(180%) blur(20px);
            -webkit-backdrop-filter: saturate(180%) blur(20px);
            will-change: transform, opacity;
        }

        .radial-item::before {
            content: attr(title);
            position: absolute;
            bottom: -36px;
            left: 50%;
            transform: translateX(-50%) scale(0);
            background: rgba(0, 0, 0, 0.92);
            backdrop-filter: saturate(180%) blur(20px);
            -webkit-backdrop-filter: saturate(180%) blur(20px);
            color: white;
            padding: 6px 12px;
            border-radius: 8px;
            font-size: ${isPDA ? '10px' : '12px'};
            font-weight: 600;
            white-space: nowrap;
            pointer-events: none;
            opacity: 0;
            transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            letter-spacing: 0.3px;
            z-index: 100;
        }

        .radial-item:hover::before {
            opacity: 1;
            transform: translateX(-50%) scale(1);
            bottom: -40px;
        }

        .radial-item:active {
            transform: scale(0.85) !important;
        }

        .radial-item:hover {
            transform: scale(1.15) !important;
            box-shadow: 
                0 12px 32px rgba(0, 0, 0, 0.25),
                0 4px 8px rgba(0, 0, 0, 0.15);
            z-index: 10;
        }

        .radial-item.open {
            opacity: 1;
        }

        .radial-item.settings {
            background: linear-gradient(135deg, #8E8E93 0%, #636366 100%);
        }

        .radial-item.search-icon {
            background: ${currentTheme.accentGradient};
        }

        .radial-item.calculator {
            background: linear-gradient(135deg, #FF9500 0%, #FF6B00 100%);
        }

        .radial-item.mini-apps {
            background: linear-gradient(135deg, ${currentTheme.successColor} 0%, #2FB350 100%);
        }

        /* Search Overlay */
        #torn-radial-search-overlay {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.8);
            backdrop-filter: blur(20px);
            z-index: 1000001;
            justify-content: center;
            align-items: center;
            animation: fadeIn 0.3s ease;
        }

        #torn-radial-search-overlay.show {
            display: flex;
        }

        .search-container {
            background: ${currentTheme.modalBg};
            border-radius: ${isPDA ? '16px' : '20px'};
            padding: ${isPDA ? '20px' : '30px'};
            max-width: ${isPDA ? '95%' : '700px'};
            width: 90%;
            max-height: 80vh;
            overflow-y: auto;
            box-shadow: 0 32px 64px rgba(0, 0, 0, 0.5);
        }

        .radial-search-container h2 {
            margin: 0 0 ${isPDA ? '16px' : '20px'} 0;
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '18px' : '24px'};
        }

        .search-input-wrapper {
            position: relative;
            margin-bottom: ${isPDA ? '16px' : '20px'};
        }

        .search-input {
            width: 100%;
            padding: ${isPDA ? '12px 16px' : '16px 20px'};
            border: 2px solid ${currentTheme.borderColor};
            border-radius: ${isPDA ? '10px' : '12px'};
            background: ${currentTheme.inputBg};
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '14px' : '16px'};
            transition: all 0.2s ease;
        }

        .radial-search-input:focus {
            outline: none;
            border-color: ${currentTheme.primaryColor};
            box-shadow: 0 0 0 4px ${currentTheme.primaryColor}26;
        }

        .search-results {
            max-height: 400px;
            overflow-y: auto;
        }

        .search-category {
            margin: ${isPDA ? '16px 0' : '20px 0'};
        }

        .search-category-title {
            font-size: ${isPDA ? '12px' : '14px'};
            font-weight: 600;
            color: ${currentTheme.textSecondary};
            text-transform: uppercase;
            margin-bottom: 8px;
            letter-spacing: 0.5px;
        }

        .search-result-item {
            padding: ${isPDA ? '10px 12px' : '12px 16px'};
            background: ${currentTheme.sectionBg};
            margin: 8px 0;
            border-radius: ${isPDA ? '8px' : '10px'};
            cursor: pointer;
            transition: all 0.2s ease;
            color: ${currentTheme.textColor};
            display: flex;
            align-items: center;
            gap: 12px;
            font-size: ${isPDA ? '13px' : '14px'};
        }

        .radial-search-result-item.selected {
            background: ${currentTheme.primaryColor};
            color: white;
        }

        .radial-search-result-item:hover {
            background: ${currentTheme.primaryColor};
            color: white;
            transform: translateX(4px);
        }

        .radial-search-history {
            margin-top: ${isPDA ? '16px' : '20px'};
            padding-top: ${isPDA ? '16px' : '20px'};
            border-top: 1px solid ${currentTheme.borderColor};
        }

        .search-history-title {
            font-size: ${isPDA ? '11px' : '12px'};
            color: ${currentTheme.textSecondary};
            margin-bottom: 8px;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .search-clear-history {
            background: none;
            border: none;
            color: ${currentTheme.dangerColor};
            cursor: pointer;
            font-size: ${isPDA ? '10px' : '11px'};
            padding: 4px 8px;
            border-radius: 4px;
            transition: all 0.2s ease;
        }

        .radial-search-clear-history:hover {
            background: rgba(163, 58, 58, 0.2);
        }

        .search-no-results {
            text-align: center;
            padding: ${isPDA ? '30px 16px' : '40px 20px'};
            color: ${currentTheme.textSecondary};
            font-size: ${isPDA ? '13px' : '14px'};
        }

        /* Calculator */
        #torn-radial-calculator {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.8);
            backdrop-filter: blur(20px);
            z-index: 1000001;
            justify-content: center;
            align-items: center;
            animation: fadeIn 0.3s ease;
            padding: 20px;
        }

        #torn-radial-calculator.show {
            display: flex;
        }

        .calculator-container {
            background: ${currentTheme.modalBg};
            border-radius: ${isPDA ? '16px' : '20px'};
            padding: 0;
            max-width: ${isPDA ? '95%' : '400px'};
            width: 100%;
            box-shadow: 0 32px 64px rgba(0, 0, 0, 0.5);
            overflow: hidden;
        }

        .calculator-header {
            padding: ${isPDA ? '16px 20px' : '20px 24px'};
            border-bottom: 1px solid ${currentTheme.borderColor};
            background: ${currentTheme.modalHeaderBg};
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .calculator-header h2 {
            margin: 0;
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '16px' : '20px'};
        }

        .calculator-display {
            padding: ${isPDA ? '20px 16px' : '30px 20px'};
            background: ${currentTheme.sectionBg};
            text-align: right;
            font-size: ${isPDA ? '28px' : '36px'};
            font-weight: 300;
            color: ${currentTheme.textColor};
            min-height: ${isPDA ? '60px' : '80px'};
            word-break: break-all;
            font-family: 'Courier New', monospace;
        }

        .calculator-buttons {
            padding: ${isPDA ? '16px' : '20px'};
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: ${isPDA ? '8px' : '12px'};
        }

        .calc-btn {
            padding: ${isPDA ? '16px' : '20px'};
            border: none;
            border-radius: ${isPDA ? '10px' : '12px'};
            background: ${currentTheme.inputBg};
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '16px' : '18px'};
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s ease;
        }

        .calc-btn:hover {
            background: ${currentTheme.borderColor};
            transform: scale(1.05);
        }

        .calc-btn:active {
            transform: scale(0.95);
        }

        .calc-btn.operator {
            background: ${currentTheme.primaryColor};
            color: white;
        }

        .calc-btn.equals {
            background: ${currentTheme.successColor};
            color: white;
            grid-column: span 2;
        }

        .calc-btn.clear {
            background: ${currentTheme.dangerColor};
            color: white;
        }

        /* Mini Apps Overlay */
        #torn-radial-mini-apps {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.8);
            backdrop-filter: blur(20px);
            z-index: 1000001;
            justify-content: center;
            align-items: center;
            animation: fadeIn 0.3s ease;
            padding: 20px;
            overflow-y: auto;
        }

        #torn-radial-mini-apps.show {
            display: flex;
        }

        .mini-apps-container {
            background: ${currentTheme.modalBg};
            border-radius: ${isPDA ? '16px' : '20px'};
            padding: 0;
            max-width: ${isPDA ? '95%' : '800px'};
            width: 100%;
            max-height: 90vh;
            overflow: hidden;
            display: flex;
            flex-direction: column;
            box-shadow: 0 32px 64px rgba(0, 0, 0, 0.5);
        }

        .mini-apps-header {
            padding: ${isPDA ? '16px 20px' : '20px 24px'};
            border-bottom: 1px solid ${currentTheme.borderColor};
            background: ${currentTheme.modalHeaderBg};
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .mini-apps-header h2 {
            margin: 0;
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '18px' : '22px'};
        }

        .mini-apps-body {
            padding: ${isPDA ? '16px' : '24px'};
            overflow-y: auto;
            flex: 1;
        }

        .mini-app-section {
            background: ${currentTheme.sectionBg};
            padding: ${isPDA ? '16px' : '20px'};
            margin-bottom: ${isPDA ? '16px' : '20px'};
            border-radius: ${isPDA ? '12px' : '14px'};
            border: 1px solid ${currentTheme.borderColor};
        }

        .mini-app-section h3 {
            margin: 0 0 ${isPDA ? '12px' : '16px'} 0;
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '16px' : '18px'};
        }

        .timer-item {
            background: ${currentTheme.inputBg};
            padding: ${isPDA ? '10px 12px' : '12px 16px'};
            margin: 8px 0;
            border-radius: ${isPDA ? '8px' : '10px'};
            display: flex;
            justify-content: space-between;
            align-items: center;
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '13px' : '14px'};
        }

        .timer-controls {
            display: flex;
            gap: 8px;
        }

        .timer-btn {
            padding: ${isPDA ? '5px 10px' : '6px 12px'};
            border: none;
            border-radius: ${isPDA ? '6px' : '8px'};
            background: ${currentTheme.primaryColor};
            color: white;
            font-size: ${isPDA ? '11px' : '12px'};
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s ease;
        }

        .timer-btn:hover {
            opacity: 0.8;
        }

        .timer-btn.danger {
            background: ${currentTheme.dangerColor};
        }

        /* API Monitor Section */
        .api-bars {
            display: grid;
            grid-template-columns: repeat(${isPDA ? '1' : '2'}, 1fr);
            gap: ${isPDA ? '10px' : '12px'};
        }

        .api-bar {
            background: ${currentTheme.inputBg};
            padding: ${isPDA ? '10px' : '12px'};
            border-radius: ${isPDA ? '8px' : '10px'};
        }

        .api-bar-label {
            font-size: ${isPDA ? '11px' : '12px'};
            color: ${currentTheme.textSecondary};
            margin-bottom: 4px;
        }

        .api-bar-value {
            font-size: ${isPDA ? '16px' : '18px'};
            font-weight: 600;
            color: ${currentTheme.textColor};
        }

        .api-bar-progress {
            height: 4px;
            background: ${currentTheme.borderColor};
            border-radius: 2px;
            margin-top: 8px;
            overflow: hidden;
        }

        .api-bar-progress-fill {
            height: 100%;
            background: ${currentTheme.primaryColor};
            transition: width 0.3s ease;
        }

        /* Calibration Overlay */
        #torn-radial-calibration {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.9);
            z-index: 1000002;
            cursor: crosshair;
        }

        #torn-radial-calibration.show {
            display: block;
        }

        .calibration-instruction {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: ${currentTheme.modalBg};
            padding: ${isPDA ? '20px 30px' : '30px 40px'};
            border-radius: ${isPDA ? '16px' : '20px'};
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '18px' : '24px'};
            font-weight: 600;
            text-align: center;
            box-shadow: 0 32px 64px rgba(0, 0, 0, 0.5);
            pointer-events: none;
            max-width: ${isPDA ? '80%' : 'none'};
        }

        .calibration-point {
            position: absolute;
            width: ${isPDA ? '16px' : '20px'};
            height: ${isPDA ? '16px' : '20px'};
            background: ${currentTheme.primaryColor};
            border: 3px solid white;
            border-radius: 50%;
            transform: translate(-50%, -50%);
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
            animation: pulse 1.5s infinite;
        }

        @keyframes pulse {
            0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
            50% { transform: translate(-50%, -50%) scale(1.3); opacity: 0.7; }
        }

        .calibration-cancel {
            position: fixed;
            bottom: ${isPDA ? '20px' : '40px'};
            left: 50%;
            transform: translateX(-50%);
            padding: ${isPDA ? '10px 20px' : '12px 24px'};
            background: ${currentTheme.dangerColor};
            color: white;
            border: none;
            border-radius: ${isPDA ? '10px' : '12px'};
            font-size: ${isPDA ? '14px' : '16px'};
            font-weight: 600;
            cursor: pointer;
            pointer-events: auto;
            box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
        }
        
    /* Settings Modal - Tabbed Interface */
        #torn-radial-modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.6);
            backdrop-filter: blur(40px);
            -webkit-backdrop-filter: blur(40px);
            z-index: 1000000;
            justify-content: center;
            align-items: center;
            animation: fadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            padding: ${isPDA ? '10px' : '20px'};
            overflow-y: auto;
        }

        #torn-radial-modal.show {
            display: flex;
        }

        @keyframes fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }

        @keyframes slideUp {
            from {
                opacity: 0;
                transform: scale(0.9) translateY(20px);
            }
            to {
                opacity: 1;
                transform: scale(1) translateY(0);
            }
        }

        .modal-content {
            background: ${currentTheme.modalBg};
            backdrop-filter: saturate(180%) blur(20px);
            -webkit-backdrop-filter: saturate(180%) blur(20px);
            border-radius: ${isPDA ? '16px' : '20px'};
            padding: 0;
            max-width: ${isPDA ? '100%' : '800px'};
            width: 100%;
            max-height: ${isPDA ? '95vh' : '90vh'};
            overflow: hidden;
            display: flex;
            flex-direction: column;
            box-shadow: 
                0 32px 64px rgba(0, 0, 0, 0.25),
                0 0 0 0.5px ${currentTheme.borderColor};
            color: ${currentTheme.textColor};
            animation: slideUp 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            margin: auto;
        }

        .modal-header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: ${isPDA ? '12px 16px' : '16px 24px'};
            border-bottom: 0.5px solid ${currentTheme.borderColor};
            background: ${currentTheme.modalHeaderBg};
            flex-shrink: 0;
        }

        .modal-header-title {
            display: flex;
            align-items: center;
            gap: 8px;
            flex: 1;
        }

        .modal-content h2 {
            margin: 0;
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '16px' : '20px'};
            font-weight: 700;
            letter-spacing: -0.3px;
        }

        .error-log-btn {
            width: ${isPDA ? '26px' : '32px'};
            height: ${isPDA ? '26px' : '32px'};
            border-radius: 50%;
            background: ${currentTheme.inputBg};
            border: none;
            font-size: ${isPDA ? '13px' : '16px'};
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.2s ease;
            margin-right: 8px;
        }

        .error-log-btn:hover {
            background: rgba(255, 152, 0, 0.2);
            transform: scale(1.05);
        }

        .modal-close {
            width: ${isPDA ? '26px' : '32px'};
            height: ${isPDA ? '26px' : '32px'};
            border-radius: 50%;
            background: ${currentTheme.inputBg};
            border: none;
            color: ${currentTheme.textSecondary};
            font-size: ${isPDA ? '16px' : '20px'};
            font-weight: 600;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.2s ease;
        }

        .modal-close:hover {
            background: ${currentTheme.dangerColor};
            color: white;
        }

        .modal-close:active {
            transform: scale(0.9);
        }

        /* Tab Navigation */
        .modal-tabs {
            display: flex;
            padding: ${isPDA ? '8px 12px' : '12px 16px'};
            background: ${currentTheme.modalHeaderBg};
            border-bottom: 1px solid ${currentTheme.borderColor};
            gap: ${isPDA ? '4px' : '8px'};
            overflow-x: auto;
            flex-shrink: 0;
        }

        .modal-tab {
            padding: ${isPDA ? '6px 12px' : '8px 16px'};
            border: none;
            border-radius: ${isPDA ? '8px' : '10px'};
            background: transparent;
            color: ${currentTheme.textSecondary};
            font-size: ${isPDA ? '12px' : '14px'};
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s ease;
            white-space: nowrap;
            flex-shrink: 0;
        }

        .modal-tab:hover {
            background: ${currentTheme.inputBg};
            color: ${currentTheme.textColor};
        }

        .modal-tab.active {
            background: ${currentTheme.primaryColor};
            color: white;
            box-shadow: 0 2px 8px ${currentTheme.primaryColor}33;
        }

        .modal-body {
            padding: ${isPDA ? '12px 16px' : '20px 24px'};
            overflow-y: auto;
            flex: 1;
            min-height: 0;
        }

        .modal-body::-webkit-scrollbar {
            width: 6px;
        }

        .modal-body::-webkit-scrollbar-track {
            background: transparent;
        }

        .modal-body::-webkit-scrollbar-thumb {
            background: rgba(74, 163, 223, 0.3);
            border-radius: 10px;
        }

        .tab-content {
            display: none;
        }

        .tab-content.active {
            display: block;
            animation: fadeIn 0.3s ease;
        }

        .loadout-selector {
            background: ${currentTheme.sectionBg};
            padding: ${isPDA ? '12px' : '16px'};
            margin-bottom: ${isPDA ? '12px' : '16px'};
            border-radius: ${isPDA ? '12px' : '14px'};
            border: 0.5px solid ${currentTheme.borderColor};
        }

        .loadout-selector h3 {
            margin: 0 0 ${isPDA ? '10px' : '12px'} 0;
            font-size: ${isPDA ? '14px' : '16px'};
            font-weight: 600;
            color: ${currentTheme.textColor};
        }

        .loadout-tabs {
            display: flex;
            gap: ${isPDA ? '6px' : '8px'};
            flex-wrap: wrap;
            margin-bottom: ${isPDA ? '10px' : '12px'};
        }

        .loadout-tab {
            padding: ${isPDA ? '6px 10px' : '8px 14px'};
            border: none;
            border-radius: ${isPDA ? '8px' : '10px'};
            background: ${currentTheme.inputBg};
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '11px' : '13px'};
            font-weight: 500;
            cursor: pointer;
            transition: all 0.2s ease;
        }

        .loadout-tab.active {
            background: ${currentTheme.primaryColor};
            color: white;
            box-shadow: 0 2px 8px ${currentTheme.primaryColor}33;
        }

        .loadout-tab:hover:not(.active) {
            background: ${currentTheme.borderColor};
        }

        .loadout-actions {
            display: grid;
            grid-template-columns: repeat(${isPDA ? '1' : '3'}, 1fr);
            gap: ${isPDA ? '6px' : '8px'};
            margin-top: ${isPDA ? '10px' : '12px'};
        }

        .loadout-actions button {
            padding: ${isPDA ? '8px 12px' : '10px 16px'};
            border: none;
            border-radius: ${isPDA ? '8px' : '10px'};
            background: rgba(62, 163, 74, 0.2);
            color: ${currentTheme.successColor};
            font-size: ${isPDA ? '11px' : '13px'};
            font-weight: 600;
            cursor: pointer;
            transition: all 0.2s ease;
        }

        .loadout-actions button:hover {
            background: rgba(62, 163, 74, 0.3);
        }

        .loadout-actions button.delete {
            background: rgba(163, 58, 58, 0.2);
            color: ${currentTheme.dangerColor};
        }

        .loadout-actions button.delete:hover {
            background: rgba(163, 58, 58, 0.3);
        }

        .settings-section {
            background: ${currentTheme.sectionBg};
            padding: ${isPDA ? '12px' : '16px'};
            margin-bottom: ${isPDA ? '12px' : '16px'};
            border-radius: ${isPDA ? '12px' : '14px'};
            border: 0.5px solid ${currentTheme.borderColor};
        }

        .settings-section h3 {
            margin: 0 0 ${isPDA ? '10px' : '14px'} 0;
            font-size: ${isPDA ? '14px' : '16px'};
            font-weight: 600;
            color: ${currentTheme.textColor};
        }

        .setting-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin: ${isPDA ? '8px 0' : '12px 0'};
            gap: ${isPDA ? '8px' : '12px'};
            flex-wrap: ${isPDA ? 'wrap' : 'nowrap'};
        }

        .setting-item label {
            font-size: ${isPDA ? '12px' : '14px'};
            font-weight: 500;
            color: ${currentTheme.textColor};
            flex: ${isPDA ? '1 1 100%' : '1'};
        }

        .setting-item select,
        .setting-item input[type="text"],
        .setting-item input[type="password"] {
            padding: ${isPDA ? '8px 10px' : '10px 12px'};
            border: none;
            border-radius: ${isPDA ? '8px' : '10px'};
            background: ${currentTheme.inputBg};
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '12px' : '14px'};
            font-weight: 500;
            cursor: pointer;
            transition: all 0.2s ease;
            min-width: ${isPDA ? '100%' : '140px'};
        }

        .setting-item input[type="checkbox"] {
            width: ${isPDA ? '18px' : '20px'};
            height: ${isPDA ? '18px' : '20px'};
            min-width: ${isPDA ? '18px' : '20px'};
            cursor: pointer;
        }

        .setting-item select:focus,
        .setting-item input[type="text"]:focus,
        .setting-item input[type="password"]:focus {
            outline: none;
            border: 2px solid ${currentTheme.primaryColor};
            box-shadow: 0 0 0 4px ${currentTheme.primaryColor}26;
        }

        .link-item {
            background: ${currentTheme.sectionBg};
            padding: ${isPDA ? '10px' : '14px'};
            margin: ${isPDA ? '8px 0' : '12px 0'};
            border-radius: ${isPDA ? '12px' : '14px'};
            display: grid;
            grid-template-columns: ${isPDA ? '36px 1fr' : '50px 1fr 1fr 50px 40px 80px'};
            gap: ${isPDA ? '8px' : '10px'};
            align-items: center;
            border: 0.5px solid ${currentTheme.borderColor};
            transition: all 0.2s ease;
        }

        .link-item:hover {
            background: ${currentTheme.inputBg};
            transform: translateX(2px);
            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
        }

        .link-item input {
            padding: ${isPDA ? '8px' : '10px 12px'};
            border: none;
            border-radius: ${isPDA ? '8px' : '10px'};
            background: ${currentTheme.inputBg};
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '12px' : '14px'};
            font-weight: 500;
            transition: all 0.2s ease;
        }

        .link-item input:focus {
            outline: none;
            border: 2px solid ${currentTheme.primaryColor};
            box-shadow: 0 0 0 4px ${currentTheme.primaryColor}26;
        }

        .link-item input:first-child {
            text-align: center;
            font-size: ${isPDA ? '16px' : '20px'};
            padding: ${isPDA ? '8px' : '10px'};
        }

        ${isPDA ? `
        .link-item input:nth-child(2),
        .link-item input:nth-child(3) {
            grid-column: span 2;
        }
        
        .link-item .color-picker-wrapper,
        .link-item .delete-btn,
        .link-item .reorder-controls {
            grid-column: span 1;
        }
        ` : ''}

        .color-picker-wrapper {
            position: relative;
        }

        .color-picker {
            width: ${isPDA ? '36px' : '50px'};
            height: ${isPDA ? '34px' : '42px'};
            border-radius: ${isPDA ? '8px' : '10px'};
            border: none;
            cursor: pointer;
            transition: all 0.2s ease;
        }

        .color-picker::-webkit-color-swatch-wrapper {
            padding: 4px;
        }

        .color-picker::-webkit-color-swatch {
            border: none;
            border-radius: ${isPDA ? '6px' : '8px'};
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
        }

        .delete-btn {
            width: ${isPDA ? '34px' : '40px'};
            height: ${isPDA ? '34px' : '40px'};
            border: none;
            border-radius: ${isPDA ? '8px' : '10px'};
            cursor: pointer;
            background: rgba(163, 58, 58, 0.2);
            color: ${currentTheme.dangerColor};
            font-size: ${isPDA ? '14px' : '18px'};
            transition: all 0.2s ease;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .delete-btn:hover {
            background: rgba(163, 58, 58, 0.3);
            transform: scale(1.05);
        }

        .delete-btn:active {
            transform: scale(0.95);
        }

        .reorder-controls {
            display: flex;
            flex-direction: column;
            gap: 4px;
        }

        .reorder-btn {
            width: ${isPDA ? '34px' : '36px'};
            height: ${isPDA ? '15px' : '18px'};
            border: none;
            border-radius: ${isPDA ? '5px' : '6px'};
            cursor: pointer;
            background: ${currentTheme.inputBg};
            color: ${currentTheme.textColor};
            font-size: ${isPDA ? '10px' : '12px'};
            transition: all 0.2s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            font-weight: bold;
        }

        .reorder-btn:hover:not(:disabled) {
            background: ${currentTheme.primaryColor};
            color: white;
            transform: scale(1.05);
        }

        .reorder-btn:active:not(:disabled) {
            transform: scale(0.95);
        }

        .reorder-btn:disabled {
            opacity: 0.3;
            cursor: not-allowed;
        }

        .modal-footer {
            padding: ${isPDA ? '10px 12px' : '14px 20px'};
            border-top: 0.5px solid ${currentTheme.borderColor};
            background: ${currentTheme.modalFooterBg};
            display: grid;
            grid-template-columns: ${isPDA ? '1fr' : 'repeat(2, 1fr)'};
            gap: ${isPDA ? '8px' : '10px'};
            flex-shrink: 0;
        }

        .modal-footer button {
            padding: ${isPDA ? '10px 14px' : '12px 18px'};
            border: none;
            border-radius: ${isPDA ? '10px' : '12px'};
            cursor: pointer;
            font-size: ${isPDA ? '12px' : '14px'};
            font-weight: 600;
            transition: all 0.2s ease;
            letter-spacing: -0.2px;
        }

        .modal-footer button:active {
            transform: scale(0.96);
        }

        .btn-primary {
            background: ${currentTheme.primaryColor};
            color: white;
            box-shadow: 0 4px 12px ${currentTheme.primaryColor}4D;
        }

        .btn-primary:hover {
            opacity: 0.9;
            box-shadow: 0 6px 16px ${currentTheme.primaryColor}66;
        }

        .btn-secondary {
            background: ${currentTheme.inputBg};
            color: ${currentTheme.textColor};
        }

        .btn-secondary:hover {
            opacity: 0.8;
        }

        .btn-success {
            background: ${currentTheme.successColor};
            color: white;
            box-shadow: 0 4px 12px rgba(62, 163, 74, 0.3);
        }

        .btn-success:hover {
            opacity: 0.9;
            box-shadow: 0 6px 16px rgba(62, 163, 74, 0.4);
        }

        .btn-coffee {
            background: ${currentTheme.accentGradient};
            color: white;
            box-shadow: 0 4px 12px ${currentTheme.primaryColor}33;
            grid-column: ${isPDA ? 'span 1' : 'span 2'};
        }

        .btn-coffee:hover {
            opacity: 0.9;
            box-shadow: 0 6px 16px ${currentTheme.primaryColor}66;
        }

        .btn-calibrate {
            background: linear-gradient(135deg, #FF9500 0%, #FF6B00 100%);
            color: white;
        }

        .btn-calibrate:hover {
            opacity: 0.9;
        }

        .add-current-page-btn {
            background: ${currentTheme.successColor};
            color: white;
            padding: ${isPDA ? '10px 16px' : '12px 20px'};
            border: none;
            border-radius: ${isPDA ? '10px' : '12px'};
            cursor: pointer;
            font-weight: 600;
            font-size: ${isPDA ? '12px' : '14px'};
            width: 100%;
            margin-bottom: ${isPDA ? '10px' : '12px'};
            transition: all 0.2s ease;
        }

        .add-current-page-btn:hover {
            opacity: 0.9;
            transform: translateY(-2px);
        }

        /* About Section Styles */
        .about-section {
            background: ${currentTheme.sectionBg};
            padding: ${isPDA ? '16px' : '20px'};
            margin-bottom: ${isPDA ? '12px' : '16px'};
            border-radius: ${isPDA ? '12px' : '14px'};
            border: 0.5px solid ${currentTheme.borderColor};
        }

        .about-section h3 {
            margin: 0 0 ${isPDA ? '12px' : '16px'} 0;
            font-size: ${isPDA ? '16px' : '18px'};
            font-weight: 600;
            color: ${currentTheme.textColor};
        }

        .about-section p {
            margin: ${isPDA ? '8px 0' : '10px 0'};
            font-size: ${isPDA ? '12px' : '14px'};
            color: ${currentTheme.textSecondary};
            line-height: 1.6;
        }

        .about-section ul {
            margin: ${isPDA ? '8px 0' : '12px 0'};
            padding-left: ${isPDA ? '20px' : '24px'};
        }

        .about-section li {
            margin: ${isPDA ? '6px 0' : '8px 0'};
            font-size: ${isPDA ? '12px' : '14px'};
            color: ${currentTheme.textSecondary};
            line-height: 1.5;
        }

        .version-badge {
            display: inline-block;
            background: ${currentTheme.primaryColor};
            color: white;
            padding: ${isPDA ? '4px 8px' : '4px 12px'};
            border-radius: ${isPDA ? '6px' : '8px'};
            font-size: ${isPDA ? '11px' : '12px'};
            font-weight: 600;
            margin-bottom: ${isPDA ? '8px' : '12px'};
        }

        /* Donators Section */
        .donators-list {
            display: grid;
            grid-template-columns: repeat(${isPDA ? '1' : '2'}, 1fr);
            gap: ${isPDA ? '8px' : '12px'};
            margin-top: ${isPDA ? '12px' : '16px'};
        }

        .donator-item {
            background: ${currentTheme.inputBg};
            padding: ${isPDA ? '10px 12px' : '12px 16px'};
            border-radius: ${isPDA ? '8px' : '10px'};
            display: flex;
            align-items: center;
            gap: ${isPDA ? '8px' : '12px'};
            transition: all 0.2s ease;
        }

        .donator-item:hover {
            background: ${currentTheme.borderColor};
            transform: translateX(2px);
        }

        .donator-icon {
            font-size: ${isPDA ? '20px' : '24px'};
        }

        .donator-info {
            flex: 1;
        }

        .donator-name {
            font-size: ${isPDA ? '13px' : '14px'};
            font-weight: 600;
            color: ${currentTheme.textColor};
        }

        .donator-amount {
            font-size: ${isPDA ? '11px' : '12px'};
            color: ${currentTheme.textSecondary};
        }

        /* Notification Toast */
        .torn-radial-notification {
            position: fixed;
            top: ${isPDA ? '10px' : '20px'};
            right: ${isPDA ? '10px' : '20px'};
            background: ${currentTheme.modalBg};
            border: 2px solid ${currentTheme.primaryColor};
            color: ${currentTheme.textColor};
            padding: ${isPDA ? '12px 16px' : '16px 24px'};
            border-radius: ${isPDA ? '10px' : '12px'};
            font-size: ${isPDA ? '12px' : '14px'};
            font-weight: 600;
            z-index: 9999999;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
            animation: slideInRight 0.3s ease-out;
            max-width: ${isPDA ? '80%' : '400px'};
        }

        @keyframes slideInRight {
            from {
                transform: translateX(400px);
                opacity: 0;
            }
            to {
                transform: translateX(0);
                opacity: 1;
            }
        }
    `;
    document.head.appendChild(style);
    
    // ==================== CREATE RADIAL ITEMS ====================
    const container = document.createElement('div');
    container.id = 'torn-radial-container';
    document.body.appendChild(container);

    const btn = document.createElement('div');
    btn.id = 'torn-radial-btn';
    btn.innerHTML = '⚡';
    btn.title = 'Quick Travel Menu';
    container.appendChild(btn);

    function createRadialItems() {
        try {
            const existingItems = document.querySelectorAll('.radial-item');
            existingItems.forEach(el => {
                try {
                    el.remove();
                } catch(e) {
                    ErrorLogger.log('warning', 'Failed to remove existing item', e);
                }
            });

            if (!Array.isArray(links) || links.length === 0) {
                ErrorLogger.log('error', 'No links available to create');
                return;
            }

            // 3 extra items: search, calculator, mini-apps, settings (search now has icon)
            const total = links.length + 4;

            // Create link items
            links.forEach((link, i) => {
                try {
                    const pos = calculatePosition(i, total, settings.layout);

                    const item = document.createElement('a');
                    item.className = 'radial-item';
                    item.href = link.url || '/index.php';
                    item.innerHTML = link.icon || '🔗';
                    item.title = link.name || 'Unnamed';
                    item.style.background = `linear-gradient(135deg, ${link.color || '#4aa3df'} 0%, ${adjustBrightness(link.color || '#4aa3df', -20)} 100%)`;
                    item.dataset.x = pos.x;
                    item.dataset.y = pos.y;
                    
                    item.addEventListener('click', (e) => {
                        e.preventDefault();
                        trackUsage(link.url);
                        window.location.href = link.url;
                    });
                    
                    container.appendChild(item);
                    checkBounds(pos);
                } catch(e) {
                    ErrorLogger.log('error', `Failed to create link ${i}: ${link.name}`, e);
                }
            });

            // Search button (NOW HAS ITS OWN ICON!)
            try {
                const pos = calculatePosition(links.length, total, settings.layout);
                const searchItem = document.createElement('div');
                searchItem.className = 'radial-item search-icon';
                searchItem.innerHTML = '👀';
                searchItem.title = 'Search';
                searchItem.dataset.x = pos.x;
                searchItem.dataset.y = pos.y;
                searchItem.addEventListener('click', openSearch);
                container.appendChild(searchItem);
                checkBounds(pos);
            } catch(e) {
                ErrorLogger.log('error', 'Failed to create search button', e);
            }

            // Calculator button
            try {
                const pos = calculatePosition(links.length + 1, total, settings.layout);
                const calcItem = document.createElement('div');
                calcItem.className = 'radial-item calculator';
                calcItem.innerHTML = '🔢';
                calcItem.title = 'Calculator';
                calcItem.dataset.x = pos.x;
                calcItem.dataset.y = pos.y;
                calcItem.addEventListener('click', openCalculator);
                container.appendChild(calcItem);
                checkBounds(pos);
            } catch(e) {
                ErrorLogger.log('error', 'Failed to create calculator button', e);
            }

            // Mini-apps button
            try {
                const pos = calculatePosition(links.length + 2, total, settings.layout);
                const miniAppsItem = document.createElement('div');
                miniAppsItem.className = 'radial-item mini-apps';
                miniAppsItem.innerHTML = '🛠️';
                miniAppsItem.title = 'Mini Apps';
                miniAppsItem.dataset.x = pos.x;
                miniAppsItem.dataset.y = pos.y;
                miniAppsItem.addEventListener('click', openMiniApps);
                container.appendChild(miniAppsItem);
                checkBounds(pos);
            } catch(e) {
                ErrorLogger.log('error', 'Failed to create mini-apps button', e);
            }

            // Settings button
            try {
                const pos = calculatePosition(links.length + 3, total, settings.layout);
                const settingsItem = document.createElement('div');
                settingsItem.className = 'radial-item settings';
                settingsItem.innerHTML = '⚙️';
                settingsItem.title = 'Settings';
                settingsItem.dataset.x = pos.x;
                settingsItem.dataset.y = pos.y;
                settingsItem.addEventListener('click', openSettings);
                container.appendChild(settingsItem);
                checkBounds(pos);
            } catch(e) {
                ErrorLogger.log('error', 'Failed to create settings button', e);
            }
        } catch(e) {
            ErrorLogger.log('error', 'Fatal error in createRadialItems', e);
        }
    }

    createRadialItems();

    // ==================== MENU TOGGLE ====================
    function toggleMenu(e) {
        if (isDragging || isAnimating) return;
        
        try {
            isAnimating = true;
            isOpen = !isOpen;
            const items = document.querySelectorAll('.radial-item');

            if (!items || items.length === 0) {
                isAnimating = false;
                ErrorLogger.log('error', 'No radial items found to toggle');
                return;
            }

            if (isOpen) {
                items.forEach((item, i) => {
                    setTimeout(() => {
                        try {
                            item.classList.add('open');
                            const x = parseFloat(item.dataset.x) || 0;
                            const y = parseFloat(item.dataset.y) || 0;
                            item.style.transform = `translate(${x}px, ${y}px) scale(1)`;
                        } catch(e) {
                            ErrorLogger.log('error', `Failed to open item ${i}`, e);
                        }
                    }, i * 35);
                });
                
                setTimeout(() => { isAnimating = false; }, items.length * 35 + 300);
            } else {
                items.forEach((item, i) => {
                    setTimeout(() => {
                        try {
                            item.classList.remove('open');
                            const x = parseFloat(item.dataset.x) || 0;
                            const y = parseFloat(item.dataset.y) || 0;
                            item.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) scale(0.3)`;
                            
                            setTimeout(() => {
                                if (!isOpen) {
                                    item.style.transform = 'translate(0, 0) scale(0)';
                                }
                            }, 200);
                        } catch(e) {
                            ErrorLogger.log('error', `Failed to close item ${i}`, e);
                        }
                    }, i * 20);
                });
                
                setTimeout(() => { isAnimating = false; }, items.length * 20 + 400);
            }
        } catch(e) {
            ErrorLogger.log('error', 'Failed to toggle menu', e);
            isAnimating = false;
        }
    }

    // ==================== DRAG FUNCTIONALITY ====================
    function dragStart(e) {
        if (e.target !== btn) return;
        
        try {
            hasMoved = false;
            isDragging = false;
            
            if (e.type === 'touchstart') {
                startX = e.touches[0].clientX;
                startY = e.touches[0].clientY;
                initialX = e.touches[0].clientX;
                initialY = e.touches[0].clientY;
            } else {
                startX = e.clientX;
                startY = e.clientY;
                initialX = e.clientX;
                initialY = e.clientY;
            }

            xOffset = parseInt(container.style.left) || savedPos.x;
            yOffset = parseInt(container.style.top) || savedPos.y;

            document.addEventListener('mousemove', drag);
            document.addEventListener('touchmove', drag, { passive: false });
            document.addEventListener('mouseup', dragEnd);
            document.addEventListener('touchend', dragEnd);
        } catch(e) {
            ErrorLogger.log('error', 'Drag start failed', e);
        }
    }

    function drag(e) {
        try {
            e.preventDefault();

            if (e.type === 'touchmove') {
                currentX = e.touches[0].clientX;
                currentY = e.touches[0].clientY;
            } else {
                currentX = e.clientX;
                currentY = e.clientY;
            }

            const deltaX = currentX - startX;
            const deltaY = currentY - startY;
            const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);

            if (distance > 5 && !isDragging) {
                isDragging = true;
                hasMoved = true;
                btn.classList.add('dragging');
            }

            if (isDragging) {
                const moveX = currentX - initialX;
                const moveY = currentY - initialY;
                container.style.left = (xOffset + moveX) + 'px';
                container.style.top = (yOffset + moveY) + 'px';
            }
        } catch(e) {
            ErrorLogger.log('error', 'Drag movement failed', e);
        }
    }

    function dragEnd(e) {
        try {
            document.removeEventListener('mousemove', drag);
            document.removeEventListener('touchmove', drag);
            document.removeEventListener('mouseup', dragEnd);
            document.removeEventListener('touchend', dragEnd);
            
            if (isDragging && hasMoved) {
                let newX = parseInt(container.style.left);
                let newY = parseInt(container.style.top);
                
                const padding = 5;
                const buttonRadius = currentSize.main / 2;
                
                const minX = padding + buttonRadius;
                const maxX = window.innerWidth - padding - buttonRadius;
                const minY = padding + buttonRadius;
                const maxY = window.innerHeight - padding - buttonRadius;
                
                newX = Math.max(minX, Math.min(newX, maxX));
                newY = Math.max(minY, Math.min(newY, maxY));
                
                savedPos.x = Math.round(newX);
                savedPos.y = Math.round(newY);
                container.style.left = savedPos.x + 'px';
                container.style.top = savedPos.y + 'px';
                Storage.set(positionKey, savedPos);
                
                createRadialItems();
                if (isOpen) {
                    isOpen = false;
                    setTimeout(() => toggleMenu(), 100);
                }
            }
            
            btn.classList.remove('dragging');
            
            setTimeout(() => {
                isDragging = false;
                hasMoved = false;
            }, 50);
        } catch(e) {
            ErrorLogger.log('error', 'Drag end failed', e);
        }
    }

    btn.addEventListener('mousedown', dragStart);
    btn.addEventListener('touchstart', dragStart, { passive: false });
    
    btn.addEventListener('click', (e) => {
        if (!hasMoved && !isDragging) {
            toggleMenu(e);
        }
    });

    // ==================== SEARCH FUNCTIONALITY ====================
    const searchOverlay = document.createElement('div');
    searchOverlay.id = 'torn-radial-search-overlay';
    searchOverlay.innerHTML = `
        <div class="search-container">
            <h2>🔍 Quick Search</h2>
            <div class="search-input-wrapper">
                <input type="text" class="search-input" id="torn-search-input" placeholder="Search players, items, pages..." autocomplete="off">
            </div>
            <div class="search-results" id="torn-search-results"></div>
            <div class="search-history" id="torn-search-history" style="display: none;">
                <div class="search-history-title">
                    <span>Recent Searches</span>
                    <button class="search-clear-history" id="clear-search-history">Clear</button>
                </div>
                <div id="search-history-items"></div>
            </div>
        </div>
    `;
    document.body.appendChild(searchOverlay);

    function openSearch() {
        if (isOpen) toggleMenu();
        searchOverlay.classList.add('show');
        setTimeout(() => {
            document.getElementById('torn-search-input').focus();
        }, 100);
        renderSearchHistory();
    }

    function renderSearchHistory() {
        const history = SearchManager.getHistory();
        const historySection = document.getElementById('torn-search-history');
        const historyItems = document.getElementById('search-history-items');
        
        if (history.length > 0) {
            historySection.style.display = 'block';
            historyItems.innerHTML = history.slice(0, 5).map(h => `
                <div class="search-result-item" onclick="window.location.href='${h.url}'">
                    ${getSearchIcon(h.type)} ${h.query}
                </div>
            `).join('');
        } else {
            historySection.style.display = 'none';
        }
    }

    function getSearchIcon(type) {
        const icons = {
            player: '👤',
            item: '🛒',
            page: '📄',
            faction: '⚔️',
            company: '🏢'
        };
        return icons[type] || '🔗';
    }

    searchOverlay.addEventListener('click', (e) => {
        if (e.target === searchOverlay) {
            searchOverlay.classList.remove('show');
        }
    });

    document.getElementById('torn-search-input').addEventListener('input', async (e) => {
        const query = e.target.value.trim();
        const resultsDiv = document.getElementById('torn-search-results');
        
        if (!query) {
            resultsDiv.innerHTML = '';
            renderSearchHistory();
            selectedSearchIndex = 0;
            return;
        }

        document.getElementById('torn-search-history').style.display = 'none';

        try {
            const results = await SearchManager.search(query);
            
            let html = '';
            let allResults = [];

            if (results.players.length > 0) {
                html += '<div class="search-category"><div class="search-category-title">Players</div>';
                results.players.forEach((r, i) => {
                    allResults.push(r);
                    html += `<div class="search-result-item ${i === selectedSearchIndex ? 'selected' : ''}" data-url="${r.url}" data-type="${r.type}">${r.icon} ${r.name}</div>`;
                });
                html += '</div>';
            }

            if (results.items.length > 0) {
                html += '<div class="search-category"><div class="search-category-title">Items</div>';
                results.items.forEach(r => {
                    allResults.push(r);
                    html += `<div class="search-result-item" data-url="${r.url}" data-type="${r.type}">${r.icon} ${r.name}</div>`;
                });
                html += '</div>';
            }

            if (results.pages.length > 0) {
                html += '<div class="search-category"><div class="search-category-title">Pages</div>';
                results.pages.forEach(r => {
                    allResults.push(r);
                    html += `<div class="search-result-item" data-url="${r.url}" data-type="${r.type}">${r.icon} ${r.name}</div>`;
                });
                html += '</div>';
            }

            if (html === '') {
                html = '<div class="search-no-results">No results found. Try a different search term.</div>';
            }

            resultsDiv.innerHTML = html;

            // Add click handlers
            resultsDiv.querySelectorAll('.search-result-item').forEach(item => {
                item.addEventListener('click', () => {
                    const url = item.dataset.url;
                    const type = item.dataset.type;
                    SearchManager.addToHistory(query, url, type);
                    window.location.href = url;
                });
            });

        } catch(e) {
            ErrorLogger.log('error', 'Search failed', e);
            resultsDiv.innerHTML = '<div class="search-no-results">Search error. Please try again.</div>';
        }
    });

    // Keyboard navigation for search
    document.getElementById('torn-search-input').addEventListener('keydown', (e) => {
        const items = document.querySelectorAll('.search-result-item');
        
        if (e.key === 'ArrowDown') {
            e.preventDefault();
            selectedSearchIndex = Math.min(selectedSearchIndex + 1, items.length - 1);
            updateSearchSelection(items);
        } else if (e.key === 'ArrowUp') {
            e.preventDefault();
            selectedSearchIndex = Math.max(selectedSearchIndex - 1, 0);
            updateSearchSelection(items);
        } else if (e.key === 'Enter') {
            e.preventDefault();
            if (items[selectedSearchIndex]) {
                items[selectedSearchIndex].click();
            }
        } else if (e.key === 'Escape') {
            searchOverlay.classList.remove('show');
        }
    });

    function updateSearchSelection(items) {
        items.forEach((item, i) => {
            if (i === selectedSearchIndex) {
                item.classList.add('selected');
                item.scrollIntoView({ block: 'nearest' });
            } else {
                item.classList.remove('selected');
            }
        });
    }

    document.getElementById('clear-search-history').addEventListener('click', () => {
        SearchManager.clearHistory();
        renderSearchHistory();
        showNotification('✅ Search history cleared');
    });

    // ==================== CALCULATOR FUNCTIONALITY ====================
    const calculatorOverlay = document.createElement('div');
    calculatorOverlay.id = 'torn-radial-calculator';
    calculatorOverlay.innerHTML = `
        <div class="calculator-container">
            <div class="calculator-header">
                <h2>🔢 Calculator</h2>
                <button class="modal-close" id="calculator-close">✕</button>
            </div>
            <div class="calculator-display" id="calc-display">0</div>
            <div class="calculator-buttons">
                <button class="calc-btn clear" data-value="C">C</button>
                <button class="calc-btn operator" data-value="/">/</button>
                <button class="calc-btn operator" data-value="*">×</button>
                <button class="calc-btn operator" data-value="-">-</button>
                
                <button class="calc-btn" data-value="7">7</button>
                <button class="calc-btn" data-value="8">8</button>
                <button class="calc-btn" data-value="9">9</button>
                <button class="calc-btn operator" data-value="+">+</button>
                
                <button class="calc-btn" data-value="4">4</button>
                <button class="calc-btn" data-value="5">5</button>
                <button class="calc-btn" data-value="6">6</button>
                <button class="calc-btn operator" data-value="%">%</button>
                
                <button class="calc-btn" data-value="1">1</button>
                <button class="calc-btn" data-value="2">2</button>
                <button class="calc-btn" data-value="3">3</button>
                <button class="calc-btn equals" data-value="=">=</button>
                
                <button class="calc-btn" data-value="0" style="grid-column: span 2;">0</button>
                <button class="calc-btn" data-value=".">.</button>
            </div>
        </div>
    `;
    document.body.appendChild(calculatorOverlay);

    let calcCurrentValue = '0';
    let calcPreviousValue = null;
    let calcOperation = null;

    function openCalculator() {
        if (isOpen) toggleMenu();
        calculatorOverlay.classList.add('show');
        calcCurrentValue = '0';
        calcPreviousValue = null;
        calcOperation = null;
        updateCalcDisplay();
    }

    function updateCalcDisplay() {
        document.getElementById('calc-display').textContent = calcCurrentValue;
    }

    function handleCalcInput(value) {
        if (value === 'C') {
            calcCurrentValue = '0';
            calcPreviousValue = null;
            calcOperation = null;
        } else if (['+', '-', '*', '/', '%'].includes(value)) {
            if (calcPreviousValue !== null && calcOperation !== null) {
                calculateResult();
            }
            calcPreviousValue = parseFloat(calcCurrentValue);
            calcOperation = value;
            calcCurrentValue = '0';
        } else if (value === '=') {
            calculateResult();
        } else if (value === '.') {
            if (!calcCurrentValue.includes('.')) {
                calcCurrentValue += '.';
            }
        } else {
            if (calcCurrentValue === '0') {
                calcCurrentValue = value;
            } else {
                calcCurrentValue += value;
            }
        }
        updateCalcDisplay();
    }

    function calculateResult() {
        if (calcPreviousValue === null || calcOperation === null) return;
        
        const current = parseFloat(calcCurrentValue);
        const previous = calcPreviousValue;
        let result;

        switch(calcOperation) {
            case '+':
                result = previous + current;
                break;
            case '-':
                result = previous - current;
                break;
            case '*':
                result = previous * current;
                break;
            case '/':
                result = previous / current;
                break;
            case '%':
                result = (previous * current) / 100;
                break;
        }

        calcCurrentValue = result.toString();
        calcPreviousValue = null;
        calcOperation = null;
    }

    calculatorOverlay.querySelectorAll('.calc-btn').forEach(btn => {
        btn.addEventListener('click', () => {
            handleCalcInput(btn.dataset.value);
        });
    });

    document.getElementById('calculator-close').addEventListener('click', () => {
        calculatorOverlay.classList.remove('show');
    });

    calculatorOverlay.addEventListener('click', (e) => {
        if (e.target === calculatorOverlay) {
            calculatorOverlay.classList.remove('show');
        }
    });

    // Keyboard support for calculator
    document.addEventListener('keydown', (e) => {
        if (calculatorOverlay.classList.contains('show')) {
            const key = e.key;
            if (/[0-9.]/.test(key) || ['+', '-', '*', '/', '%'].includes(key)) {
                e.preventDefault();
                handleCalcInput(key === '*' ? '*' : key);
            } else if (key === 'Enter' || key === '=') {
                e.preventDefault();
                handleCalcInput('=');
            } else if (key === 'Escape' || key === 'c' || key === 'C') {
                e.preventDefault();
                handleCalcInput('C');
            } else if (key === 'Backspace') {
                e.preventDefault();
                calcCurrentValue = calcCurrentValue.slice(0, -1) || '0';
                updateCalcDisplay();
            }
        }
    });
    
    // ==================== MINI APPS ====================
    const miniAppsOverlay = document.createElement('div');
    miniAppsOverlay.id = 'torn-radial-mini-apps';
    miniAppsOverlay.innerHTML = `
        <div class="mini-apps-container">
            <div class="mini-apps-header">
                <h2>🛠️ Mini Apps</h2>
                <button class="modal-close" id="mini-apps-close">✕</button>
            </div>
            <div class="mini-apps-body">
                <div class="mini-app-section">
                    <h3>⏱️ Timer Manager</h3>
                    <div id="timers-list"></div>
                    <div style="display: flex; gap: 8px; margin-top: 12px; flex-wrap: ${isPDA ? 'wrap' : 'nowrap'};">
                        <input type="text" id="timer-name" placeholder="Timer name" style="flex: 1; padding: 10px; border-radius: 8px; border: none; background: ${currentTheme.inputBg}; color: ${currentTheme.textColor}; min-width: ${isPDA ? '100%' : 'auto'};">
                        <input type="number" id="timer-minutes" placeholder="Minutes" style="width: ${isPDA ? '100%' : '100px'}; padding: 10px; border-radius: 8px; border: none; background: ${currentTheme.inputBg}; color: ${currentTheme.textColor};">
                        <button class="timer-btn" id="add-timer-btn" style="padding: 10px 16px;">Add</button>
                    </div>
                </div>
                <div class="mini-app-section" id="api-monitor-section">
    <h3>📊 API Monitor</h3>
    <div id="api-status">
        <p style="color: ${currentTheme.textSecondary}; font-size: 12px; margin: 0 0 12px 0;">Configure your API key in settings to enable real-time monitoring</p>
    </div>
    <div id="api-data-container" style="display: none;">
        <!-- Stats Bars -->
        <div class="api-bars" id="api-bars">
            <div class="api-bar">
                <div class="api-bar-label">Energy</div>
                <div class="api-bar-value" id="energy-value">-/-</div>
                <div class="api-bar-progress">
                    <div class="api-bar-progress-fill" id="energy-progress" style="width: 0%;"></div>
                </div>
                <div class="api-bar-label" style="font-size: 10px; margin-top: 4px;" id="energy-time">-</div>
            </div>
            <div class="api-bar">
                <div class="api-bar-label">Nerve</div>
                <div class="api-bar-value" id="nerve-value">-/-</div>
                <div class="api-bar-progress">
                    <div class="api-bar-progress-fill" id="nerve-progress" style="width: 0%;"></div>
                </div>
                <div class="api-bar-label" style="font-size: 10px; margin-top: 4px;" id="nerve-time">-</div>
            </div>
            <div class="api-bar">
                <div class="api-bar-label">Happy</div>
                <div class="api-bar-value" id="happy-value">-/-</div>
                <div class="api-bar-progress">
                    <div class="api-bar-progress-fill" id="happy-progress" style="width: 0%;"></div>
                </div>
                <div class="api-bar-label" style="font-size: 10px; margin-top: 4px;" id="happy-time">-</div>
            </div>
            <div class="api-bar">
                <div class="api-bar-label">Life</div>
                <div class="api-bar-value" id="life-value">-/-</div>
                <div class="api-bar-progress">
                    <div class="api-bar-progress-fill" id="life-progress" style="width: 0%;"></div>
                </div>
            </div>
        </div>
        
        <!-- Money Info -->
        <div style="display: grid; grid-template-columns: repeat(${isPDA ? '1' : '2'}, 1fr); gap: 12px; margin-top: 12px;">
            <div class="api-bar">
                <div class="api-bar-label">Cash on Hand</div>
                <div class="api-bar-value" id="money-hand">$0</div>
            </div>
            <div class="api-bar" id="vault-container" style="display: none;">
                <div class="api-bar-label">Vault</div>
                <div class="api-bar-value" id="money-vault">$0</div>
            </div>
        </div>
        
        <!-- Company Info -->
        <div id="company-info" style="display: none; margin-top: 12px;">
            <div class="api-bar">
                <div class="api-bar-label">Company: <span id="company-name">-</span></div>
                <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-top: 8px; font-size: ${isPDA ? '11px' : '12px'};">
                    <div>Position: <span id="company-position" style="font-weight: 600;">-</span></div>
                    <div>Employees: <span id="company-employees" style="font-weight: 600;">-</span></div>
                </div>
                </div>
            </div>
        </div>
            <button class="timer-btn" id="refresh-api-btn" style="width: 100%; margin-top: 12px; display: none; padding: 10px;">Refresh Data</button>
        </div>
                
                
                <div class="mini-app-section">
                    <h3>📝 Quick Notes</h3>
                    <textarea id="quick-notes" placeholder="Jot down quick notes..." style="width: 100%; min-height: 120px; padding: 12px; border-radius: 8px; border: none; background: ${currentTheme.inputBg}; color: ${currentTheme.textColor}; font-family: monospace; resize: vertical;"></textarea>
                    <button class="timer-btn" id="save-notes-btn" style="margin-top: 8px; width: 100%; padding: 10px;">Save Notes</button>
                </div>
                
                <div class="mini-app-section">
                    <h3>⚔️ Faction Shortcuts</h3>
                    <div style="display: grid; grid-template-columns: repeat(${isPDA ? '1' : '2'}, 1fr); gap: 8px;">
                        <a href="/factions.php?step=your" class="timer-btn" style="text-decoration: none; text-align: center; display: block; padding: 10px;">Faction Home</a>
                        <a href="/factions.php?step=your#/tab=crimes" class="timer-btn" style="text-decoration: none; text-align: center; display: block; padding: 10px;">OC</a>
                        <a href="/factions.php?step=your#/tab=armoury" class="timer-btn" style="text-decoration: none; text-align: center; display: block; padding: 10px;">Armory</a>
                        <a href="/factions.php?step=your#/tab=controls" class="timer-btn" style="text-decoration: none; text-align: center; display: block; padding: 10px;">Controls</a>
                    </div>
                </div>
            </div>
        </div>
    `;
    document.body.appendChild(miniAppsOverlay);

    function openMiniApps() {
        if (isOpen) toggleMenu();
        miniAppsOverlay.classList.add('show');
        renderTimers();
        loadNotes();
        updateAPIMonitor();
    }

    function renderTimers() {
        const timersList = document.getElementById('timers-list');
        if (!timers || timers.length === 0) {
            timersList.innerHTML = '<div style="text-align: center; padding: 20px; color: ' + currentTheme.textSecondary + ';">No active timers</div>';
            return;
        }

        timersList.innerHTML = timers.map((timer, i) => {
            const remaining = Math.max(0, timer.endTime - Date.now());
            const minutes = Math.floor(remaining / 60000);
            const seconds = Math.floor((remaining % 60000) / 1000);
            
            return `
                <div class="timer-item">
                    <div>
                        <div style="font-weight: 600;">${timer.name}</div>
                        <div style="font-size: 12px; color: ${currentTheme.textSecondary};">${minutes}m ${seconds}s remaining</div>
                    </div>
                    <button class="timer-btn danger" onclick="window.tornRadialRemoveTimer(${i})">Remove</button>
                </div>
            `;
        }).join('');
    }

    window.tornRadialRemoveTimer = function(index) {
        timers.splice(index, 1);
        Storage.set('tornRadialTimers', timers);
        renderTimers();
    };

    document.getElementById('add-timer-btn').addEventListener('click', () => {
        const name = document.getElementById('timer-name').value.trim();
        const minutes = parseInt(document.getElementById('timer-minutes').value);
        
        if (!name || !minutes || minutes <= 0) {
            showNotification('⚠️ Please enter timer name and duration');
            return;
        }

        const timer = {
            name: name,
            endTime: Date.now() + (minutes * 60000)
        };

        timers.push(timer);
        Storage.set('tornRadialTimers', timers);
        
        document.getElementById('timer-name').value = '';
        document.getElementById('timer-minutes').value = '';
        
        renderTimers();
        showNotification(`✅ Timer "${name}" added for ${minutes} minutes`);
        
        setTimeout(() => {
            if (settings.notifications.enabled) {
                showNotification(`⏰ Timer Complete: ${name}`);
                if (typeof GM_notification !== 'undefined') {
                    GM_notification({
                        title: 'Torn Radial Timer',
                        text: `Timer "${name}" has finished!`,
                        timeout: 5000
                    });
                }
            }
        }, minutes * 60000);
    });

    // API Monitor
    async function updateAPIMonitor() {
    if (!settings.apiKey) {
        document.getElementById('api-data-container').style.display = 'none';
        document.getElementById('refresh-api-btn').style.display = 'none';
        return;
    }

    try {
        // Fetch bars, money, and basic profile
        const [barsData, moneyData, profileData] = await Promise.all([
            API.request('/user/?selections=bars'),
            API.request('/user/?selections=money'),
            API.request('/user/?selections=profile,job')
        ]);

        document.getElementById('api-data-container').style.display = 'block';
        document.getElementById('refresh-api-btn').style.display = 'block';
        document.getElementById('api-status').style.display = 'none';

        // Helper function to format time
        const formatTime = (seconds) => {
            if (seconds <= 0) return 'Full';
            const hours = Math.floor(seconds / 3600);
            const mins = Math.floor((seconds % 3600) / 60);
            if (hours > 0) return `${hours}h ${mins}m`;
            return `${mins}m`;
        };

        // Update Energy
        const energyCurrent = barsData.energy.current;
        const energyMax = barsData.energy.maximum;
        const energyPercent = (energyCurrent / energyMax) * 100;
        const energyFulltime = barsData.energy.fulltime || 0;
        document.getElementById('energy-value').textContent = `${energyCurrent}/${energyMax}`;
        document.getElementById('energy-progress').style.width = energyPercent + '%';
        document.getElementById('energy-time').textContent = energyFulltime > 0 ? `Full in ${formatTime(energyFulltime)}` : 'Full';

        // Update Nerve
        const nerveCurrent = barsData.nerve.current;
        const nerveMax = barsData.nerve.maximum;
        const nervePercent = (nerveCurrent / nerveMax) * 100;
        const nerveFulltime = barsData.nerve.fulltime || 0;
        document.getElementById('nerve-value').textContent = `${nerveCurrent}/${nerveMax}`;
        document.getElementById('nerve-progress').style.width = nervePercent + '%';
        document.getElementById('nerve-time').textContent = nerveFulltime > 0 ? `Full in ${formatTime(nerveFulltime)}` : 'Full';

        // Update Happy
        const happyCurrent = barsData.happy.current;
        const happyMax = barsData.happy.maximum;
        const happyPercent = (happyCurrent / happyMax) * 100;
        const happyFulltime = barsData.happy.fulltime || 0;
        document.getElementById('happy-value').textContent = `${happyCurrent}/${happyMax}`;
        document.getElementById('happy-progress').style.width = happyPercent + '%';
        document.getElementById('happy-time').textContent = happyFulltime > 0 ? `Full in ${formatTime(happyFulltime)}` : 'Full';

        // Update Life
        const lifeCurrent = barsData.life.current;
        const lifeMax = barsData.life.maximum;
        const lifePercent = (lifeCurrent / lifeMax) * 100;
        document.getElementById('life-value').textContent = `${Math.floor(lifeCurrent)}/${lifeMax}`;
        document.getElementById('life-progress').style.width = lifePercent + '%';

        // Update Money
        const formatMoney = (amount) => {
            return '$' + amount.toLocaleString();
        };
        document.getElementById('money-hand').textContent = formatMoney(moneyData.money_onhand || 0);
        
        // Show vault if user has one
        if (moneyData.vault_amount !== undefined) {
            document.getElementById('vault-container').style.display = 'block';
            document.getElementById('money-vault').textContent = formatMoney(moneyData.vault_amount || 0);
        }

        // Update Company Info (if they own/work at one)
        if (profileData.job && profileData.job.company_id) {
            try {
                const companyData = await API.request(`/company/?selections=profile,employees`);
                document.getElementById('company-info').style.display = 'block';
                document.getElementById('company-name').textContent = companyData.company.name || 'Unknown';
                document.getElementById('company-position').textContent = profileData.job.position || 'Employee';
                document.getElementById('company-employees').textContent = Object.keys(companyData.company_employees || {}).length || '0';
            } catch(e) {
                // Not a company owner, hide section
                document.getElementById('company-info').style.display = 'none';
            }
        } else {
            document.getElementById('company-info').style.display = 'none';
        }

        } catch(e) {
        ErrorLogger.log('error', 'Failed to fetch API data', e);
        document.getElementById('api-status').innerHTML = '<p style="color: ' + currentTheme.dangerColor + '; font-size: 12px;">Failed to fetch API data. Check your API key.</p>';
        document.getElementById('api-status').style.display = 'block';
        document.getElementById('api-data-container').style.display = 'none';
        }
      }

    document.getElementById('refresh-api-btn').addEventListener('click', () => {
        updateAPIMonitor();
        showNotification('🔄 API data refreshed');
    });

    // Notes
    function loadNotes() {
        const notes = Storage.get('tornRadialNotes', '');
        document.getElementById('quick-notes').value = notes;
    }

    document.getElementById('save-notes-btn').addEventListener('click', () => {
        const notes = document.getElementById('quick-notes').value;
        Storage.set('tornRadialNotes', notes);
        showNotification('✅ Notes saved!');
    });

    document.getElementById('mini-apps-close').addEventListener('click', () => {
        miniAppsOverlay.classList.remove('show');
    });

    miniAppsOverlay.addEventListener('click', (e) => {
        if (e.target === miniAppsOverlay) {
            miniAppsOverlay.classList.remove('show');
        }
    });

    // Timer update loop
    setInterval(() => {
        if (miniAppsOverlay.classList.contains('show')) {
            renderTimers();
        }
        
        timers = timers.filter(timer => {
            if (Date.now() >= timer.endTime) {
                if (settings.notifications.enabled) {
                    showNotification(`⏰ Timer Complete: ${timer.name}`);
                    if (typeof GM_notification !== 'undefined') {
                        GM_notification({
                            title: 'Torn Radial Timer',
                            text: `Timer "${timer.name}" has finished!`,
                            timeout: 5000
                        });
                    }
                }
                return false;
            }
            return true;
        });
        Storage.set('tornRadialTimers', timers);
    }, 1000);

    // ==================== SCREEN CALIBRATION ====================
    const calibrationOverlay = document.createElement('div');
    calibrationOverlay.id = 'torn-radial-calibration';
    calibrationOverlay.innerHTML = `
        <div class="calibration-instruction">Click the TOP-LEFT corner of your safe area</div>
        <button class="calibration-cancel" id="calibration-cancel-btn">Cancel (ESC)</button>
    `;
    document.body.appendChild(calibrationOverlay);

    function startCalibration() {
        calibrationMode = true;
        calibrationStep = 0;
        calibrationOverlay.classList.add('show');
        const deviceType = isPDA ? 'mobile' : 'desktop';
        document.querySelector('.calibration-instruction').textContent = `Click the TOP-LEFT corner of your safe area (${deviceType} mode)`;
    }

    calibrationOverlay.addEventListener('click', (e) => {
        if (e.target.classList.contains('calibration-cancel') || e.target.id === 'calibration-cancel-btn') {
            calibrationMode = false;
            calibrationOverlay.classList.remove('show');
            const points = document.querySelectorAll('.calibration-point');
            points.forEach(p => p.remove());
            return;
        }

        if (calibrationMode) {
            if (calibrationStep === 0) {
                const point = document.createElement('div');
                point.className = 'calibration-point';
                point.style.left = e.clientX + 'px';
                point.style.top = e.clientY + 'px';
                calibrationOverlay.appendChild(point);
                
                const tempCalibration = {
                    topLeft: { x: e.clientX, y: e.clientY }
                };
                
                if (isPDA) {
                    settings.screenCalibrationMobile = tempCalibration;
                } else {
                    settings.screenCalibration = tempCalibration;
                }
                
                calibrationStep = 1;
                const deviceType = isPDA ? 'mobile' : 'desktop';
                document.querySelector('.calibration-instruction').textContent = `Click the BOTTOM-RIGHT corner of your safe area (${deviceType} mode)`;
            } else if (calibrationStep === 1) {
                const point = document.createElement('div');
                point.className = 'calibration-point';
                point.style.left = e.clientX + 'px';
                point.style.top = e.clientY + 'px';
                calibrationOverlay.appendChild(point);
                
                if (isPDA) {
                    settings.screenCalibrationMobile.bottomRight = { x: e.clientX, y: e.clientY };
                } else {
                    settings.screenCalibration.bottomRight = { x: e.clientX, y: e.clientY };
                }
                
                Storage.set('tornRadialSettings', settings);
                
                calibrationMode = false;
                const deviceType = isPDA ? 'Mobile' : 'Desktop';
                showNotification(`✅ ${deviceType} screen calibration complete!`);
                
                setTimeout(() => {
                    calibrationOverlay.classList.remove('show');
                    const points = document.querySelectorAll('.calibration-point');
                    points.forEach(p => p.remove());
                    
                    createRadialItems();
                }, 1000);
            }
        }
    });

    document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape' && calibrationMode) {
            calibrationMode = false;
            calibrationOverlay.classList.remove('show');
            const points = document.querySelectorAll('.calibration-point');
            points.forEach(p => p.remove());
        }
        
        // Global keyboard shortcut
        if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'R') {
            e.preventDefault();
            openSettings();
            showNotification('⚙️ Settings opened via keyboard shortcut');
        }
    });

    // ==================== SETTINGS MODAL WITH TABS ====================
    function moveLink(fromIndex, direction) {
        try {
            const toIndex = direction === 'up' ? fromIndex - 1 : fromIndex + 1;
            
            if (toIndex < 0 || toIndex >= links.length) return;
            
            const temp = links[fromIndex];
            links[fromIndex] = links[toIndex];
            links[toIndex] = temp;
            
            if (!loadouts[settings.currentLoadout]) {
                loadouts[settings.currentLoadout] = { name: settings.currentLoadout, links: [] };
            }
            loadouts[settings.currentLoadout].links = JSON.parse(JSON.stringify(links));
            Storage.set('tornRadialLoadouts', loadouts);
            
            renderLinksContainer();
        } catch(e) {
            ErrorLogger.log('error', 'Failed to move link', e);
        }
    }

    const modal = document.createElement('div');
    modal.id = 'torn-radial-modal';
    
    // Generate theme options dynamically
    const themeOptions = getThemeNames().map(themeName => 
        `<option value="${themeName}">${THEMES[themeName].name}</option>`
    ).join('');

    modal.innerHTML = `
        <div class="modal-content">
            <div class="modal-header">
                <div class="modal-header-title">
                    <h2>⚙️ Quick Travel Settings</h2>
                </div>
                <button class="error-log-btn" id="show-error-log" title="View Error Log">🐞</button>
                <button class="modal-close" id="modal-close-btn">✕</button>
            </div>
            <div class="modal-tabs">
                <button class="modal-tab active" data-tab="general">General</button>
                <button class="modal-tab" data-tab="appearance">Appearance</button>
                <button class="modal-tab" data-tab="advanced">Advanced</button>
                <button class="modal-tab" data-tab="about">About</button>
                <button class="modal-tab" data-tab="donators">Donators</button>
            </div>
            <div class="modal-body">
                <!-- GENERAL TAB -->
                <div class="tab-content active" data-tab="general">
                    <div class="loadout-selector">
                        <h3>📋 Loadouts</h3>
                        <div class="loadout-tabs" id="loadout-tabs"></div>
                        <div class="loadout-actions">
                            <button id="new-loadout-btn">➕ New</button>
                            <button id="rename-loadout-btn">✏️ Rename</button>
                            <button class="delete" id="delete-loadout-btn">🗑️ Delete</button>
                        </div>
                    </div>
                    
                    <button class="add-current-page-btn" id="add-current-page-btn">📄 Add Current Page to Loadout</button>
                    
                    <div id="links-container"></div>
                </div>

                <!-- APPEARANCE TAB -->
                <div class="tab-content" data-tab="appearance">
                    <div class="settings-section">
                        <h3>🎨 Visual Settings</h3>
                        <div class="setting-item">
                            <label>Theme</label>
                            <select id="theme-select">
                                ${themeOptions}
                            </select>
                        </div>
                        <div class="setting-item">
                            <label>Layout</label>
                            <select id="layout-select">
                                <option value="circular">Circular</option>
                                <option value="vertical">Vertical</option>
                                <option value="horizontal">Horizontal</option>
                            </select>
                        </div>
                        <div class="setting-item">
                            <label>Size</label>
                            <select id="size-select">
                                <option value="pda">PDA</option>
                                <option value="small">Small</option>
                                <option value="medium">Medium</option>
                                <option value="large">Large</option>
                            </select>
                        </div>
                    </div>
                </div>

                <!-- ADVANCED TAB -->
                <div class="tab-content" data-tab="advanced">
                    <div class="settings-section">
                        <h3>🔔 Notifications</h3>
                        <div class="setting-item">
                            <label>Enable Notifications</label>
                            <input type="checkbox" id="notif-enabled">
                        </div>
                    </div>
                    
                    <div class="settings-section">
                        <h3>🔑 API Configuration</h3>
                        <div class="setting-item" style="flex-direction: column; align-items: stretch;">
                            <label>Torn API Key</label>
                            <input type="password" id="api-key-input" placeholder="Enter your Torn API key" style="width: 100%; margin-top: 8px;">
                            <p style="font-size: ${isPDA ? '10px' : '11px'}; color: ${currentTheme.textSecondary}; margin: 8px 0 0 0;">Used for API Monitor in Mini Apps. Get your key at torn.com/preferences.php#tab=api</p>
                        </div>
                    </div>

                    <div class="settings-section">
                        <h3>📐 Calibration</h3>
                        <p style="font-size: ${isPDA ? '11px' : '12px'}; color: ${currentTheme.textSecondary}; margin: 0 0 12px 0;">
                            Current device: <strong>${isPDA ? 'Mobile/PDA' : 'Desktop'}</strong>
                        </p>
                        <p style="font-size: ${isPDA ? '11px' : '12px'}; color: ${currentTheme.textSecondary}; margin: 0 0 12px 0;">
                            Calibration ensures all menu items stay within your screen boundaries. Each device type (desktop/mobile) has separate calibration settings.
                        </p>
                        <button class="btn-calibrate" id="calibrate-btn-advanced" style="width: 100%; padding: ${isPDA ? '10px' : '12px'};">
                            📐 Calibrate ${isPDA ? 'Mobile' : 'Desktop'} Screen
                        </button>
                    </div>
                </div>

                <!-- ABOUT TAB -->
                <div class="tab-content" data-tab="about">
                    <div class="about-section">
                        <h3>ℹ️ About Torn Quick-Travel</h3>
                        <div class="version-badge">v1.6.1</div>
                        <p><strong>Author:</strong> Sensimillia (2168012)</p>
                        <p>Radial navigation menu for Torn City with enhanced features, API integration, customization options.</p>
                    </div>

                    <div class="about-section">
                        <h3>✨ What's New in v1.6.1</h3>
                        <ul>
                            <li><strong>🔍 Search Icon:</strong> Search has its own radial menu icon for easy access (WIP)</li>
                            <li><strong>📱 PDA Mode:</strong> Fully responsive settings UI that scales perfectly on mobile devices</li>
                            <li><strong>🎨 Tabbed Settings:</strong> Cleaner, organized interface with categorized tabs</li>
                            <li><strong>📐 Dual Calibration:</strong> Separate screen calibration for desktop and mobile/PDA modes (WIP)</li>
                            <li><strong>🔔 Smart Notifications:</strong> Throttled notification system prevents spam and browser crashes</li>
                            <li><strong>⚡ Optimized Code:</strong> Dynamic theme system and better structured architecture</li>
                            <li><strong>🧹 Cleaner Menu:</strong> Removed redundant script manager items</li>
                        </ul>
                    </div>

                    <div class="about-section">
                        <h3>🎯 Features</h3>
                        <ul>
                            <li>Customizable radial menu with multiple layouts</li>
                            <li>Multiple loadout presets for different activities</li>
                            <li>Smart search with history and categorized results</li>
                            <li>Built-in calculator with keyboard support</li>
                            <li>Timer manager and quick notes</li>
                            <li>API integration for real-time stats monitoring</li>
                            <li>10 beautiful themes to choose from</li>
                            <li>Import/Export settings for backup and sharing</li>
                            <li>Usage statistics and automatic favorites</li>
                            <li>Comprehensive error logging system</li>
                        </ul>
                    </div>

                    <div class="about-section">
                        <h3>⌨️ Keyboard Shortcuts</h3>
                        <ul>
                            <li><strong>Ctrl/Cmd + Shift + R:</strong> Open settings</li>
                            <li><strong>↑↓ + Enter:</strong> Navigate search results</li>
                            <li><strong>Escape:</strong> Close overlays/cancel calibration</li>
                            <li><strong>Calculator:</strong> Full keyboard support for all operations</li>
                        </ul>
                    </div>

                    <div class="about-section">
                        <h3>💡 Tips</h3>
                        <ul>
                            <li>Drag the main button to reposition the menu anywhere on screen</li>
                            <li>Use calibration to set safe boundaries for your specific screen layout</li>
                            <li>Add frequently visited pages directly from any Torn page</li>
                            <li>The Favorites loadout auto-generates from your most-used links</li>
                            <li>Export your settings regularly to prevent data loss</li>
                        </ul>
                    </div>
                </div>

                <!-- DONATORS TAB -->
                <div class="tab-content" data-tab="donators">
                    <div class="about-section">
                        <h3>💖 Thank You to Our Supporters</h3>
                        <p style="font-size: ${isPDA ? '12px' : '14px'}; color: ${currentTheme.textSecondary};">
                            These amazing people have supported the development of Torn Quick-Travel. Your contributions help keep this project alive and evolving!
                        </p>
                    </div>

                    <div class="about-section">
                        <div class="donators-list" id="donators-list">
                            <!-- Placeholder for future donators -->
                            <div class="donator-item">
                                <div class="donator-icon">🌟</div>
                                <div class="donator-info">
                                    <div class="donator-name">Caio [2488372]</div>
                                    <div class="donator-amount">30x Can of Crocozade</div>
                                </div>
                            </div>
                        </div>
                    </div>

                    <div class="about-section">
                        <h3>☕ Support Development</h3>
                        <p style="font-size: ${isPDA ? '12px' : '14px'}; color: ${currentTheme.textSecondary}; margin-bottom: 12px;">
                            If you enjoy using Torn Quick-Travel and would like to support its continued development, consider sending a small donation in-game or leaving a positive review!
                        </p>
                        <button class="btn-coffee" id="coffee-btn-about" style="width: 100%; padding: ${isPDA ? '12px' : '14px'};">
                            ☕ Visit My Profile
                        </button>
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button class="btn-success" id="add-link-btn">➕ Add Link</button>
                <button class="btn-secondary" id="restore-btn">🔄 Restore</button>
                <button class="btn-secondary" id="export-btn">📤 Export</button>
                <button class="btn-secondary" id="import-btn">📥 Import</button>
                <button class="btn-primary" id="save-btn">💾 Save Changes</button>
            </div>
        </div>
    `;
    document.body.appendChild(modal);

    // Tab switching functionality
    const tabButtons = modal.querySelectorAll('.modal-tab');
    const tabContents = modal.querySelectorAll('.tab-content');

    tabButtons.forEach(button => {
        button.addEventListener('click', () => {
            const targetTab = button.dataset.tab;
            
            // Update button states
            tabButtons.forEach(btn => btn.classList.remove('active'));
            button.classList.add('active');
            
            // Update content visibility
            tabContents.forEach(content => {
                if (content.dataset.tab === targetTab) {
                    content.classList.add('active');
                } else {
                    content.classList.remove('active');
                }
            });
        });
    });

    modal.addEventListener('click', (e) => {
        if (e.target === modal) closeSettings();
    });

    document.getElementById('show-error-log').addEventListener('click', (e) => {
        e.preventDefault();
        showErrorLog();
    });

    function renderLoadoutTabs() {
        try {
            const tabsContainer = document.getElementById('loadout-tabs');
            if (!tabsContainer) return;
            
            tabsContainer.innerHTML = '';
            
            Object.keys(loadouts).forEach(key => {
                const tab = document.createElement('button');
                tab.className = 'loadout-tab';
                tab.textContent = loadouts[key]?.name || key;
                tab.dataset.loadout = key;
                
                if (key === settings.currentLoadout) {
                    tab.classList.add('active');
                }
                
                tab.addEventListener('click', () => switchLoadout(key));
                tabsContainer.appendChild(tab);
            });
        } catch(e) {
            ErrorLogger.log('error', 'Failed to render loadout tabs', e);
        }
    }

    function switchLoadout(loadoutKey) {
        try {
            if (!loadouts[loadoutKey]) {
                ErrorLogger.log('error', `Loadout not found: ${loadoutKey}`);
                return;
            }
            
            settings.currentLoadout = loadoutKey;
            links = loadouts[loadoutKey].links.map(link => ({
                name: link?.name || 'Unnamed',
                url: link?.url || '/index.php',
                icon: link?.icon || '🔗',
                color: link?.color || '#4aa3df'
            }));
            
            renderLoadoutTabs();
            renderLinksContainer();
        } catch(e) {
            ErrorLogger.log('error', 'Failed to switch loadout', e);
        }
    }

    function renderLinksContainer() {
        try {
            const linksContainer = document.getElementById('links-container');
            if (!linksContainer) return;
            
            linksContainer.innerHTML = '';

            links.forEach((link, i) => {
                const linkItem = document.createElement('div');
                linkItem.className = 'link-item';
                linkItem.innerHTML = `
                    <input type="text" value="${link.icon}" placeholder="Icon" maxlength="2" data-index="${i}" data-field="icon">
                    <input type="text" value="${link.name}" placeholder="Name" data-index="${i}" data-field="name">
                    <input type="text" value="${link.url}" placeholder="URL" data-index="${i}" data-field="url">
                    <div class="color-picker-wrapper">
                        <input type="color" class="color-picker" value="${link.color}" data-index="${i}" data-field="color">
                    </div>
                    <button class="delete-btn" data-index="${i}" title="Delete">🗑️</button>
                    <div class="reorder-controls">
                        <button class="reorder-btn" data-index="${i}" data-direction="up" ${i === 0 ? 'disabled' : ''} title="Move Up">▲</button>
                        <button class="reorder-btn" data-index="${i}" data-direction="down" ${i === links.length - 1 ? 'disabled' : ''} title="Move Down">▼</button>
                    </div>
                `;
                linksContainer.appendChild(linkItem);
            });

            linksContainer.querySelectorAll('.delete-btn').forEach(btn => {
                btn.addEventListener('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    const index = parseInt(this.dataset.index);
                    if (confirm(`Remove "${links[index].name}"?`)) {
                        try {
                            links.splice(index, 1);
                            saveCurrentLoadout();
                            renderLinksContainer();
                        } catch(err) {
                            ErrorLogger.log('error', 'Failed to delete link', err);
                            showNotification('❌ Failed to delete link');
                        }
                    }
                });
            });

            linksContainer.querySelectorAll('.reorder-btn').forEach(btn => {
                btn.addEventListener('click', function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    if (!this.disabled) {
                        const index = parseInt(this.dataset.index);
                        const direction = this.dataset.direction;
                        moveLink(index, direction);
                    }
                });
            });
        } catch(e) {
            ErrorLogger.log('error', 'Failed to render links container', e);
        }
    }

    function openSettings() {
        try {
            if (isOpen) toggleMenu();
            
            document.getElementById('theme-select').value = settings.theme;
            document.getElementById('layout-select').value = settings.layout;
            document.getElementById('size-select').value = settings.iconSize;
            document.getElementById('notif-enabled').checked = settings.notifications.enabled;
            document.getElementById('api-key-input').value = settings.apiKey || '';
            
            renderLoadoutTabs();
            renderLinksContainer();
            
            modal.classList.add('show');
        } catch(e) {
            ErrorLogger.log('error', 'Failed to open settings', e);
        }
    }

    function saveCurrentLoadout() {
        try {
            document.querySelectorAll('.link-item input').forEach(input => {
                const index = parseInt(input.dataset.index);
                const field = input.dataset.field;
                if (links[index] && field) {
                    links[index][field] = input.value;
                }
            });

            if (!loadouts[settings.currentLoadout]) {
                loadouts[settings.currentLoadout] = { name: settings.currentLoadout, links: [] };
            }
            
            loadouts[settings.currentLoadout].links = JSON.parse(JSON.stringify(links));
            Storage.set('tornRadialLoadouts', loadouts);
        } catch(e) {
            ErrorLogger.log('error', 'Failed to save loadout', e);
        }
    }

    function closeSettings() {
        try {
            const oldLayout = settings.layout;
            const oldSize = settings.iconSize;
            const oldTheme = settings.theme;
            
            settings.theme = document.getElementById('theme-select').value;
            settings.layout = document.getElementById('layout-select').value;
            settings.iconSize = document.getElementById('size-select').value;
            settings.notifications.enabled = document.getElementById('notif-enabled').checked;
            
            const newApiKey = document.getElementById('api-key-input').value.trim();
            if (newApiKey !== settings.apiKey) {
                settings.apiKey = newApiKey;
                API.setApiKey(newApiKey);
            }
            
            Storage.set('tornRadialSettings', settings);

            saveCurrentLoadout();
            
            modal.classList.remove('show');
            
            if (oldLayout !== settings.layout || oldSize !== settings.iconSize || oldTheme !== settings.theme) {
                location.reload();
            } else {
                createRadialItems();
            }
        } catch(e) {
            ErrorLogger.log('error', 'Failed to close settings', e);
        }
    }

    // Event listeners
    document.getElementById('modal-close-btn').addEventListener('click', (e) => {
        e.preventDefault();
        closeSettings();
    });

    document.getElementById('save-btn').addEventListener('click', (e) => {
        e.preventDefault();
        closeSettings();
    });

    document.getElementById('add-link-btn').addEventListener('click', (e) => {
        e.preventDefault();
        try {
            saveCurrentLoadout();
            links.push({ name: 'New Link', url: '/index.php', icon: '🔗', color: '#4aa3df' });
            saveCurrentLoadout();
            renderLinksContainer();
            
            // Switch to General tab when adding link
            document.querySelector('.modal-tab[data-tab="general"]').click();
        } catch(e) {
            ErrorLogger.log('error', 'Failed to add link', e);
        }
    });

    document.getElementById('add-current-page-btn').addEventListener('click', (e) => {
        e.preventDefault();
        addCurrentPage();
    });

    document.getElementById('restore-btn').addEventListener('click', (e) => {
        e.preventDefault();
        if (confirm('Restore default links for this loadout?')) {
            try {
                links = JSON.parse(JSON.stringify(DEFAULT_LINKS));
                saveCurrentLoadout();
                renderLinksContainer();
                showNotification('✅ Loadout restored to defaults');
            } catch(e) {
                ErrorLogger.log('error', 'Failed to restore defaults', e);
            }
        }
    });

    document.getElementById('export-btn').addEventListener('click', (e) => {
        e.preventDefault();
        Storage.exportAll();
        showNotification('✅ Data exported successfully');
    });

    document.getElementById('import-btn').addEventListener('click', (e) => {
        e.preventDefault();
        importLoadouts();
    });

    document.getElementById('calibrate-btn-advanced').addEventListener('click', (e) => {
        e.preventDefault();
        modal.classList.remove('show');
        setTimeout(() => {
            startCalibration();
        }, 300);
    });

    document.getElementById('new-loadout-btn').addEventListener('click', (e) => {
        e.preventDefault();
        try {
            const name = prompt('Enter loadout name:');
            if (name && name.trim()) {
                const key = name.toLowerCase().replace(/[^a-z0-9]/g, '_');
                if (loadouts[key]) {
                    showNotification('⚠️ A loadout with this name already exists!');
                    return;
                }
                loadouts[key] = { name: name.trim(), links: [...DEFAULT_LINKS] };
                Storage.set('tornRadialLoadouts', loadouts);
                switchLoadout(key);
                showNotification(`✅ Loadout "${name}" created`);
            }
        } catch(e) {
            ErrorLogger.log('error', 'Failed to create loadout', e);
        }
    });

    document.getElementById('rename-loadout-btn').addEventListener('click', (e) => {
        e.preventDefault();
        try {
            if (settings.currentLoadout === 'default') {
                showNotification('⚠️ Cannot rename the default loadout!');
                return;
            }
            const newName = prompt('Enter new name:', loadouts[settings.currentLoadout].name);
            if (newName && newName.trim()) {
                loadouts[settings.currentLoadout].name = newName.trim();
                Storage.set('tornRadialLoadouts', loadouts);
                renderLoadoutTabs();
                showNotification(`✅ Loadout renamed to "${newName}"`);
            }
        } catch(e) {
            ErrorLogger.log('error', 'Failed to rename loadout', e);
        }
    });

    document.getElementById('delete-loadout-btn').addEventListener('click', (e) => {
        e.preventDefault();
        try {
            if (settings.currentLoadout === 'default') {
                showNotification('⚠️ Cannot delete the default loadout!');
                return;
            }
            if (confirm(`Delete "${loadouts[settings.currentLoadout].name}" loadout?`)) {
                const deletedName = loadouts[settings.currentLoadout].name;
                delete loadouts[settings.currentLoadout];
                Storage.set('tornRadialLoadouts', loadouts);
                switchLoadout('default');
                showNotification(`✅ Loadout "${deletedName}" deleted`);
            }
        } catch(e) {
            ErrorLogger.log('error', 'Failed to delete loadout', e);
        }
    });

    document.getElementById('coffee-btn-about').addEventListener('click', (e) => {
        e.preventDefault();
        window.open('https://www.torn.com/profiles.php?XID=2168012#/', '_blank');
    });

    // ==================== HELPER FUNCTIONS FOR SETTINGS ====================
    function addCurrentPage() {
        const currentUrl = window.location.pathname + window.location.search;
        const pageName = prompt('Enter a name for this page:', document.title.split(' - ')[0] || 'Current Page');
        
        if (pageName && pageName.trim()) {
            const newLink = {
                name: pageName.trim(),
                url: currentUrl,
                icon: '📄',
                color: currentTheme.primaryColor
            };
            
            links.push(newLink);
            saveCurrentLoadout();
            renderLinksContainer();
            showNotification(`✅ Added "${pageName}" to current loadout`);
        }
    }

    function importLoadouts() {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = '.json';
        input.onchange = (e) => {
            const file = e.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.onload = (e) => {
                    try {
                        if (Storage.importAll(e.target.result)) {
                            showNotification('✅ Data imported successfully!');
                            setTimeout(() => location.reload(), 1500);
                        } else {
                            showNotification('❌ Import failed - invalid file');
                        }
                    } catch(err) {
                        ErrorLogger.log('error', 'Import failed', err);
                        showNotification('❌ Import failed - invalid file');
                    }
                };
                reader.readAsText(file);
            }
        };
        input.click();
    }

    // ==================== ERROR LOG MODAL ====================
    const errorLogModal = document.createElement('div');
    errorLogModal.id = 'error-log-modal';
    errorLogModal.innerHTML = `
        <div class="error-log-content" style="background: ${currentTheme.modalBg}; border-radius: ${isPDA ? '16px' : '20px'}; padding: 0; max-width: ${isPDA ? '95%' : '800px'}; width: 100%; max-height: 90vh; display: flex; flex-direction: column; box-shadow: 0 32px 64px rgba(0, 0, 0, 0.4);">
            <div class="error-log-header" style="padding: ${isPDA ? '16px 20px' : '20px 24px'}; border-bottom: 1px solid ${currentTheme.borderColor}; background: ${currentTheme.modalHeaderBg}; display: flex; justify-content: space-between; align-items: center;">
                <h2 style="margin: 0; font-size: ${isPDA ? '16px' : '20px'}; color: ${currentTheme.textColor};">🐞 Error Log</h2>
                <button class="modal-close" id="error-log-close">✕</button>
            </div>
            <div class="error-log-body" id="error-log-body" style="padding: ${isPDA ? '16px' : '20px'}; overflow-y: auto; flex: 1; font-family: 'Courier New', monospace; font-size: ${isPDA ? '11px' : '12px'}; color: ${currentTheme.textColor};"></div>
            <div class="error-log-footer" style="padding: ${isPDA ? '12px 16px' : '16px 24px'}; border-top: 1px solid ${currentTheme.borderColor}; background: ${currentTheme.modalFooterBg}; display: flex; gap: ${isPDA ? '8px' : '12px'};">
                <button class="btn-secondary" id="export-log-btn" style="flex: 1; padding: ${isPDA ? '10px' : '12px'}; border: none; border-radius: ${isPDA ? '8px' : '10px'}; font-weight: 600; cursor: pointer;">💾 Export</button>
                <button class="btn-secondary" id="clear-log-btn" style="flex: 1; padding: ${isPDA ? '10px' : '12px'}; border: none; border-radius: ${isPDA ? '8px' : '10px'}; font-weight: 600; cursor: pointer;">🗑️ Clear</button>
                <button class="btn-primary" id="close-log-btn" style="flex: 1; padding: ${isPDA ? '10px' : '12px'}; border: none; border-radius: ${isPDA ? '8px' : '10px'}; font-weight: 600; cursor: pointer;">Close</button>
            </div>
        </div>
    `;
    errorLogModal.style.cssText = `display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); z-index: 1000001; justify-content: center; align-items: center; padding: ${isPDA ? '10px' : '20px'};`;
    document.body.appendChild(errorLogModal);

    function showErrorLog() {
        try {
            const logBody = document.getElementById('error-log-body');
            const logs = ErrorLogger.getLogs();
            
            if (logs.length === 0) {
                logBody.innerHTML = '<div style="text-align: center; padding: 40px; opacity: 0.5;">No errors logged</div>';
            } else {
                logBody.innerHTML = logs.reverse().map(log => `
                    <div style="background: ${currentTheme.sectionBg}; padding: ${isPDA ? '10px' : '12px'}; margin-bottom: ${isPDA ? '10px' : '12px'}; border-radius: ${isPDA ? '8px' : '10px'}; border-left: 4px solid ${log.type === 'error' ? '#FF3B30' : log.type === 'warning' ? '#FF9500' : '#007AFF'};">
                        <div style="display: flex; justify-content: space-between; margin-bottom: 8px; font-weight: bold; font-size: ${isPDA ? '10px' : '11px'};">
                            <span style="text-transform: uppercase;">${log.type}</span>
                            <span style="opacity: 0.7; font-size: ${isPDA ? '9px' : '10px'};">${new Date(log.timestamp).toLocaleString()}</span>
                        </div>
                        <div style="margin-bottom: 8px;">${log.message}</div>
                        ${log.error ? `<div style="font-size: ${isPDA ? '9px' : '10px'}; opacity: 0.6; white-space: pre-wrap; word-break: break-all;">${log.error.message}\n${log.error.stack || ''}</div>` : ''}
                    </div>
                `).join('');
            }
            
            errorLogModal.style.display = 'flex';
        } catch(e) {
            ErrorLogger.log('error', 'Failed to show error log', e);
            alert('Error displaying log. Check console.');
        }
    }

    document.getElementById('error-log-close').addEventListener('click', () => {
        errorLogModal.style.display = 'none';
    });

    document.getElementById('close-log-btn').addEventListener('click', () => {
        errorLogModal.style.display = 'none';
    });

    document.getElementById('export-log-btn').addEventListener('click', () => {
        try {
            ErrorLogger.exportLogs();
            showNotification('✅ Error logs exported');
        } catch(e) {
            ErrorLogger.log('error', 'Failed to export logs', e);
            showNotification('❌ Failed to export logs');
        }
    });

    document.getElementById('clear-log-btn').addEventListener('click', () => {
        if (confirm('Clear all error logs?')) {
            ErrorLogger.clear();
            showErrorLog();
            showNotification('✅ Error logs cleared');
        }
    });

    errorLogModal.addEventListener('click', (e) => {
        if (e.target === errorLogModal) {
            errorLogModal.style.display = 'none';
        }
    });

    // ==================== RESET FUNCTIONS ====================
    function resetPosition() {
        try {
            const safePos = getSafeInitialPosition();
            savedPos.x = safePos.x;
            savedPos.y = safePos.y;
            container.style.left = safePos.x + 'px';
            container.style.top = safePos.y + 'px';
            Storage.set(positionKey, savedPos);
            
            createRadialItems();
            if (isOpen) {
                isOpen = false;
                setTimeout(() => toggleMenu(), 100);
            }
            
            showNotification('✅ Menu position reset to center');
            return true;
        } catch(e) {
            ErrorLogger.log('error', 'Failed to reset position', e);
            return false;
        }
    }

    function fullReset() {
        try {
            if (confirm('⚠️ FULL RESET will:\n- Delete ALL custom loadouts\n- Reset ALL settings to defaults\n- Clear error logs\n- Clear usage statistics\n\nThis CANNOT be undone!\n\nAre you absolutely sure?')) {
                if (confirm('Last chance! This will delete everything. Continue?')) {
                    localStorage.removeItem('tornRadialSettings');
                    localStorage.removeItem('tornRadialLoadouts');
                    localStorage.removeItem('tornRadialPosition');
                    localStorage.removeItem('tornRadialPositionMobile');
                    localStorage.removeItem('tornRadialErrorLogs');
                    localStorage.removeItem('tornRadialUsageStats');
                    localStorage.removeItem('tornRadialTimers');
                    localStorage.removeItem('tornRadialSearchHistory');
                    localStorage.removeItem('tornRadialNotes');
                    localStorage.removeItem('tornRadialApiKey');
                    localStorage.removeItem('tornRadialCalibration');
                    localStorage.removeItem('tornRadialCalibrationMobile');
                    alert('✅ Full reset complete! Refreshing page...');
                    location.reload();
                    return true;
                }
            }
            return false;
        } catch(e) {
            alert('Reset failed. Try clearing localStorage manually.');
            console.error('Reset error:', e);
            return false;
        }
    }

    // ==================== MENU COMMANDS (CLEANED UP) ====================
    if (typeof GM_registerMenuCommand !== 'undefined') {
        GM_registerMenuCommand('⚙️ Open Settings', () => {
            openSettings();
        });
        
        GM_registerMenuCommand('📐 Calibrate Screen', () => {
            startCalibration();
        });
        
        GM_registerMenuCommand('📤 Export All Data', () => {
            Storage.exportAll();
            showNotification('✅ Data exported successfully');
        });
        
        GM_registerMenuCommand('📥 Import Data', () => {
            const input = document.createElement('input');
            input.type = 'file';
            input.accept = '.json';
            input.onchange = (e) => {
                const file = e.target.files[0];
                if (file) {
                    const reader = new FileReader();
                    reader.onload = (e) => {
                        if (Storage.importAll(e.target.result)) {
                            alert('Import successful! Page will reload.');
                            location.reload();
                        } else {
                            alert('Import failed. Check file format.');
                        }
                    };
                    reader.readAsText(file);
                }
            };
            input.click();
        });
        
        GM_registerMenuCommand('🎯 Reset Position', () => {
            if (resetPosition()) {
                alert('Menu position has been reset to center!');
            }
        });
        
        GM_registerMenuCommand('⚠️ Full Reset', () => {
            fullReset();
        });
        
        GM_registerMenuCommand('🐞 View Error Log', () => {
            showErrorLog();
        });
    }

    // ==================== CONSOLE API ====================
    window.tornRadialReset = fullReset;
    window.tornRadialResetPosition = resetPosition;
    window.tornRadialSettings = openSettings;
    window.tornRadialSearch = openSearch;
    window.tornRadialCalculator = openCalculator;
    window.tornRadialMiniApps = openMiniApps;
    window.tornRadialCalibrate = startCalibration;
    window.tornRadialExport = () => Storage.exportAll();
    window.tornRadialAddCurrentPage = addCurrentPage;

    // ==================== STARTUP LOG ====================
    console.log('%c🎯 Torn Quick-Travel v1.6.1', 'font-size: 16px; font-weight: bold; color: #4aa3df;');
    console.log('%c✨ NEW in v1.6.1:', 'font-size: 14px; font-weight: bold; color: #3ea34a;');
    console.log('%c  🔍 Search Icon - Now visible in radial menu!', 'font-size: 12px; color: #4aa3df;');
    console.log('%c  📱 PDA Mode - Fully responsive settings UI', 'font-size: 12px; color: #4aa3df;');
    console.log('%c  🎨 Tabbed Settings - Organized interface', 'font-size: 12px; color: #4aa3df;');
    console.log('%c  📐 Dual Calibration - Separate desktop/mobile settings', 'font-size: 12px; color: #4aa3df;');
    console.log('%c  🔔 Smart Notifications - Throttled to prevent spam', 'font-size: 12px; color: #4aa3df;');
    console.log('%c  ⚡ Optimized Code - Dynamic themes & better structure', 'font-size: 12px; color: #4aa3df;');
    console.log('%c⚙️ Keyboard: Ctrl/Cmd + Shift + R', 'font-size: 12px; color: #3ea34a;');
    console.log('%c🎯 Console API:', 'font-size: 12px; color: #FF9500;');
    console.log('%c  tornRadialSettings() - Open settings', 'font-size: 11px; color: #9b9b9b;');
    console.log('%c  tornRadialSearch() - Open search', 'font-size: 11px; color: #9b9b9b;');
    console.log('%c  tornRadialCalculator() - Open calculator', 'font-size: 11px; color: #9b9b9b;');
    console.log('%c  tornRadialMiniApps() - Open mini apps', 'font-size: 11px; color: #9b9b9b;');
    console.log('%c  tornRadialCalibrate() - Start calibration', 'font-size: 11px; color: #9b9b9b;');
    console.log('%c  tornRadialAddCurrentPage() - Add current page', 'font-size: 11px; color: #9b9b9b;');
    console.log('%c  tornRadialExport() - Export all data', 'font-size: 11px; color: #9b9b9b;');
    console.log('%c  tornRadialResetPosition() - Reset position', 'font-size: 11px; color: #9b9b9b;');
    console.log('%c  tornRadialReset() - Full reset (delete all)', 'font-size: 11px; color: #a33a3a;');
    if (typeof GM_registerMenuCommand !== 'undefined') {
        console.log('%c📱 Menu: Click your userscript extension icon', 'font-size: 12px; color: #AF52DE;');
    }
    console.log('%c📱 Device Mode: ' + (isPDA ? 'Mobile/PDA' : 'Desktop'), 'font-size: 12px; font-weight: bold; color: #FF9500;');

    // Cleanup on page unload
    window.addEventListener('beforeunload', () => {
        NotificationManager.destroy();
    });

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址