Nitro Type - Leaderboards

This script adds a custom Startrack Leaderboards tab to Nitro Type, providing advanced leaderboard functionality with multiple timeframes, intelligent caching, and a polished UI that closely matches the original Nitro Type leaderboard design.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

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

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Nitro Type - Leaderboards
// @namespace    https://nitrotype.info
// @version      11.0.1
// @description  This script adds a custom Startrack Leaderboards tab to Nitro Type, providing advanced leaderboard functionality with multiple timeframes, intelligent caching, and a polished UI that closely matches the original Nitro Type leaderboard design.
// @author       Combined Logic (SuperJoelzy + Captain.Loveridge)
// @license      MIT
// @match        https://www.nitrotype.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        unsafeWindow
// @connect      ntstartrack.org
// @run-at       document-start
// ==/UserScript==
(function() {
    'use strict';
    // ─── Mod Menu Manifest Bridge ───────────────────────────────────────────────
    const NTCFG_LEADERBOARDS_MANIFEST_ID = "leaderboards";
    const NTCFG_LEADERBOARDS_MANIFEST_KEY = `ntcfg:manifest:${NTCFG_LEADERBOARDS_MANIFEST_ID}`;
    const NTCFG_LEADERBOARDS_VALUE_PREFIX = `ntcfg:${NTCFG_LEADERBOARDS_MANIFEST_ID}:`;
    const NTCFG_LEADERBOARDS_BRIDGE_VERSION = "1.0.0-bridge.1";
    const SETTINGS_STORAGE_VERSION = 1;
    const STORAGE_VERSION_KEY = `${NTCFG_LEADERBOARDS_VALUE_PREFIX}__storage_version`;
    const STORAGE_MIGRATED_AT_KEY = `${NTCFG_LEADERBOARDS_VALUE_PREFIX}__migrated_at`;
    const STORAGE_CLEANUP_AFTER_KEY = `${NTCFG_LEADERBOARDS_VALUE_PREFIX}__cleanup_after`;
    const LEGACY_CLEANUP_GRACE_MS = 30 * 24 * 60 * 60 * 1000;
    const LEADERBOARDS_SHARED_SETTINGS = {
        DEFAULT_VIEW: {
            type: 'select',
            label: 'Default View',
            default: 'individual',
            group: 'Views',
            description: 'Which leaderboard view to show by default.',
            options: [
                { label: 'Individual', value: 'individual' },
                { label: 'Team', value: 'team' }
            ]
        },
        DEFAULT_TIMEFRAME: {
            type: 'select',
            label: 'Default Timeframe',
            default: 'season',
            group: 'Views',
            description: 'Which timeframe to show by default.',
            options: [
                { label: 'Season', value: 'season' },
                { label: 'Last 24 Hours', value: '24hr' },
                { label: 'Last 7 Days', value: '7day' }
            ]
        },
        HIGHLIGHT_POSITION_CHANGE: {
            type: 'boolean',
            label: 'Highlight Position Changes',
            default: true,
            group: 'Views',
            description: 'Show position change arrows next to leaderboard entries.'
        },
        SHOW_MANUAL_REFRESH: {
            type: 'boolean',
            label: 'Show Manual Refresh Button',
            default: true,
            group: 'Views',
            description: 'Display the manual refresh button on the leaderboard.'
        },
        CACHE_DURATION_MINUTES: {
            type: 'number',
            label: 'Cache Duration (minutes)',
            default: 60,
            group: 'Sync',
            description: 'How long to keep cached leaderboard data before re-fetching.',
            min: 1,
            max: 120,
            step: 1
        },
        ANTI_FLICKER_MODE: {
            type: 'boolean',
            label: 'Anti-Flicker Mode',
            default: true,
            group: 'Presentation',
            description: 'Hide page content briefly while the leaderboard loads to prevent flickering.'
        },
        SHOW_ROUTE_TAB: {
            type: 'boolean',
            label: 'Show Leaderboards Nav Tab',
            default: true,
            group: 'Presentation',
            description: 'Display the Leaderboards tab in the top navigation bar.'
        },
        SHOW_DROPDOWN_LINK: {
            type: 'boolean',
            label: 'Show Leaderboards in Dropdown',
            default: false,
            group: 'Presentation',
            description: 'Add a Leaderboards link to the account dropdown menu.'
        },
        HIDE_CLASS_TAB: {
            type: 'boolean',
            label: 'Hide Class Tab',
            default: false,
            group: 'Presentation',
            description: 'Hide the Class/Classes tab from the navigation bar.'
        },
        DEBUG_LOGGING: {
            type: 'boolean',
            label: 'Debug Logging',
            default: false,
            group: 'Advanced',
            description: 'Enable verbose console logging for troubleshooting.'
        }
    };
    const getNtcfgLeaderboardsStorageKey = (settingKey) => `${NTCFG_LEADERBOARDS_VALUE_PREFIX}${settingKey}`;
    const canUseGMStorage = () => typeof GM_getValue === 'function' && typeof GM_setValue === 'function';
    const readCanonicalValue = (storageKey) => {
        if (!canUseGMStorage()) return undefined;
        try {
            return GM_getValue(storageKey);
        } catch {
            return undefined;
        }
    };
    const writeCanonicalValue = (storageKey, value) => {
        if (!canUseGMStorage()) return;
        try {
            GM_setValue(storageKey, value);
        } catch {
            // ignore storage sync failures
        }
    };
    const readStorageMetaNumber = (storageKey, fallback = 0) => {
        const raw = readCanonicalValue(storageKey);
        const parsed = Number(raw);
        return Number.isFinite(parsed) ? parsed : fallback;
    };
    const dispatchLeaderboardsActionResult = (requestId, status, error = '') => {
        if (!requestId) return;
        try {
            document.dispatchEvent(new CustomEvent('ntcfg:action-result', {
                detail: {
                    requestId,
                    script: NTCFG_LEADERBOARDS_MANIFEST_ID,
                    status,
                    error
                }
            }));
        } catch {
            // ignore dispatch failures
        }
    };
    const coerceNtcfgLeaderboardsValue = (settingKey, value) => {
        const meta = LEADERBOARDS_SHARED_SETTINGS[settingKey];
        if (!meta) return value;
        if (meta.type === 'boolean') {
            if (typeof value === 'string') {
                const raw = value.trim().toLowerCase();
                if (raw === 'false' || raw === '0' || raw === 'off') return false;
                if (raw === 'true' || raw === '1' || raw === 'on') return true;
            }
            return !!value;
        }
        if (meta.type === 'number') {
            const fallback = Number(meta.default);
            const parsed = Number(value);
            let normalized = Number.isFinite(parsed) ? parsed : fallback;
            const min = Number(meta.min);
            const max = Number(meta.max);
            const step = Number(meta.step);
            if (Number.isFinite(step) && step >= 1) {
                normalized = Math.round(normalized);
            }
            if (Number.isFinite(min)) {
                normalized = Math.max(min, normalized);
            }
            if (Number.isFinite(max)) {
                normalized = Math.min(max, normalized);
            }
            return normalized;
        }
        if (meta.type === 'select') {
            const raw = String(value ?? '').trim();
            const options = Array.isArray(meta.options) ? meta.options : [];
            return options.some((option) => String(option.value) === raw) ? raw : meta.default;
        }
        return String(value ?? meta.default);
    };
    const readNtcfgLeaderboardsValue = (settingKey) => {
        const meta = LEADERBOARDS_SHARED_SETTINGS[settingKey];
        if (!meta) return undefined;
        try {
            const canonical = readCanonicalValue(getNtcfgLeaderboardsStorageKey(settingKey));
            if (canonical !== undefined) {
                return coerceNtcfgLeaderboardsValue(settingKey, canonical);
            }
            const raw = localStorage.getItem(getNtcfgLeaderboardsStorageKey(settingKey));
            if (raw == null) return meta.default;
            const parsed = JSON.parse(raw);
            return coerceNtcfgLeaderboardsValue(settingKey, parsed);
        } catch {
            return meta.default;
        }
    };
    const writeNtcfgLeaderboardsValue = (settingKey, value) => {
        try {
            writeCanonicalValue(getNtcfgLeaderboardsStorageKey(settingKey), value);
            const serialized = JSON.stringify(value);
            if (localStorage.getItem(getNtcfgLeaderboardsStorageKey(settingKey)) !== serialized) {
                localStorage.setItem(getNtcfgLeaderboardsStorageKey(settingKey), serialized);
            }
        } catch {
            // ignore storage sync failures
        }
    };
    const registerNtcfgLeaderboardsManifest = () => {
        try {
            const manifest = {
                id: NTCFG_LEADERBOARDS_MANIFEST_ID,
                name: 'Startrack Leaderboard Integration',
                version: NTCFG_LEADERBOARDS_BRIDGE_VERSION,
                scriptVersion: typeof GM_info !== 'undefined' ? GM_info.script.version : '',
                storageVersion: SETTINGS_STORAGE_VERSION,
                supportsGlobalReset: true,
                description: 'Custom Startrack-powered leaderboards with multiple timeframes and caching.',
                sections: [
                    { id: 'views', title: 'Views', subtitle: 'Default view and display preferences.', resetButton: true },
                    { id: 'sync', title: 'Sync', subtitle: 'Cache and data refresh settings.', resetButton: true },
                    { id: 'presentation', title: 'Presentation', subtitle: 'Visual behavior and navigation controls.', resetButton: true },
                    { id: 'advanced', title: 'Advanced', subtitle: 'Debug and diagnostic controls.', resetButton: true }
                ],
                settings: LEADERBOARDS_SHARED_SETTINGS
            };
            const serialized = JSON.stringify(manifest);
            if (localStorage.getItem(NTCFG_LEADERBOARDS_MANIFEST_KEY) !== serialized) {
                localStorage.setItem(NTCFG_LEADERBOARDS_MANIFEST_KEY, serialized);
            }
        } catch {
            // ignore manifest registration failures
        }
    };
    // Direct apply: writes to localStorage (used for same-tab ntcfg:change events from mod menu)
    const applyNtcfgLeaderboardsValueDirect = (settingKey, value) => {
        const meta = LEADERBOARDS_SHARED_SETTINGS[settingKey];
        if (!meta) return;
        const normalized = coerceNtcfgLeaderboardsValue(settingKey, value);
        writeNtcfgLeaderboardsValue(settingKey, normalized);
        // Sync DEBUG_LOGGING bidirectionally with the existing ntStartrackDebug localStorage key
        if (settingKey === 'DEBUG_LOGGING') {
            syncLeaderboardsDebugToggle(normalized);
        }
        applyLeaderboardsSettingSideEffects(settingKey);
    };
    // Deduped apply: compares before writing (used for cross-tab storage events)
    const applyNtcfgLeaderboardsValueIfChanged = (settingKey, value) => {
        const meta = LEADERBOARDS_SHARED_SETTINGS[settingKey];
        if (!meta) return;
        const normalized = coerceNtcfgLeaderboardsValue(settingKey, value);
        const currentValue = readNtcfgLeaderboardsValue(settingKey);
        if (JSON.stringify(currentValue) !== JSON.stringify(normalized)) {
            writeNtcfgLeaderboardsValue(settingKey, normalized);
            if (settingKey === 'DEBUG_LOGGING') {
                syncLeaderboardsDebugToggle(normalized);
            }
            applyLeaderboardsSettingSideEffects(settingKey);
        }
    };
    // Bidirectional sync for DEBUG_LOGGING <-> ntStartrackDebug localStorage key
    const syncLeaderboardsDebugToggle = (enabled) => {
        try {
            localStorage.setItem('ntStartrackDebug', enabled ? '1' : '0');
        } catch {
            // ignore storage errors
        }
    };
    // Helper to check if a specific leaderboards feature is enabled via ntcfg
    function isNtcfgLeaderboardsFeatureEnabled(settingKey) {
        const val = readNtcfgLeaderboardsValue(settingKey);
        return val !== false;
    }
    // Seed localStorage values from defaults for any settings not yet stored
    const seedNtcfgLeaderboardsDefaults = () => {
        Object.keys(LEADERBOARDS_SHARED_SETTINGS).forEach((settingKey) => {
            const meta = LEADERBOARDS_SHARED_SETTINGS[settingKey];
            const storageKey = getNtcfgLeaderboardsStorageKey(settingKey);
            if (readCanonicalValue(storageKey) === undefined && localStorage.getItem(storageKey) == null) {
                writeNtcfgLeaderboardsValue(settingKey, meta.default);
            }
            // Sync DEBUG_LOGGING bidirectionally with existing ntStartrackDebug key
            if (settingKey === 'DEBUG_LOGGING') {
                const debugVal = localStorage.getItem('ntStartrackDebug');
                if (debugVal === '1') {
                    writeNtcfgLeaderboardsValue(settingKey, true);
                }
            }
        });
    };
    const syncAllNtcfgLeaderboardsSettings = () => {
        Object.keys(LEADERBOARDS_SHARED_SETTINGS).forEach((settingKey) => {
            writeNtcfgLeaderboardsValue(settingKey, readNtcfgLeaderboardsValue(settingKey));
        });
    };
    // Listen for mod menu changes (same tab)
    document.addEventListener('ntcfg:change', (event) => {
        if (event?.detail?.script !== NTCFG_LEADERBOARDS_MANIFEST_ID) return;
        applyNtcfgLeaderboardsValueDirect(event.detail.key, event.detail.value);
    });
    document.addEventListener('ntcfg:action', (event) => {
        const detail = event?.detail || {};
        if (detail.script !== '*') return;
        if (detail.key !== 'clear-settings' || detail.scope !== 'prefs+caches') return;
        try {
            Object.keys(LEADERBOARDS_SHARED_SETTINGS).forEach((settingKey) => {
                writeNtcfgLeaderboardsValue(settingKey, LEADERBOARDS_SHARED_SETTINGS[settingKey].default);
            });
            try {
                Object.keys(localStorage).forEach((key) => {
                    if (key.startsWith('ntStartrackCache_') ||
                        key.startsWith('ntStartrackCacheExp_') ||
                        key.startsWith('ntStartrackCacheTime_') ||
                        key === 'ntStartrackSeasonCache' ||
                        key === 'ntStartrackDailySyncCT' ||
                        key === 'ntStartrackHourlySyncCT' ||
                        key === 'ntCarDataMap' ||
                        key === 'ntCarDataMapTimestamp' ||
                        key === 'ntStartrackDebug' ||
                        key === 'ntStartrackDebugSeasonOnly') {
                        localStorage.removeItem(key);
                    }
                });
            } catch {
                // ignore localStorage cleanup failures
            }
            writeCanonicalValue(STORAGE_VERSION_KEY, SETTINGS_STORAGE_VERSION);
            writeCanonicalValue(STORAGE_MIGRATED_AT_KEY, Date.now());
            writeCanonicalValue(STORAGE_CLEANUP_AFTER_KEY, Date.now() + LEGACY_CLEANUP_GRACE_MS);
            registerNtcfgLeaderboardsManifest();
            syncAllNtcfgLeaderboardsSettings();
            applyAllLeaderboardsSettingSideEffects();
            document.dispatchEvent(new CustomEvent('ntcfg:manifest-updated', {
                detail: { script: NTCFG_LEADERBOARDS_MANIFEST_ID }
            }));
            dispatchLeaderboardsActionResult(detail.requestId, 'success');
        } catch (error) {
            dispatchLeaderboardsActionResult(detail.requestId, 'error', error?.message || String(error));
        }
    });
    // Listen for cross-tab changes
    window.addEventListener('storage', (event) => {
        const storageKey = String(event?.key || '');
        if (!storageKey.startsWith(NTCFG_LEADERBOARDS_VALUE_PREFIX) || event.newValue == null) return;
        const settingKey = storageKey.slice(NTCFG_LEADERBOARDS_VALUE_PREFIX.length);
        if (!LEADERBOARDS_SHARED_SETTINGS[settingKey]) return;
        try {
            applyNtcfgLeaderboardsValueIfChanged(settingKey, JSON.parse(event.newValue));
        } catch {
            // ignore invalid synced payloads
        }
    });
    const ensureLeaderboardsStorageMigration = () => {
        const currentVersion = readStorageMetaNumber(STORAGE_VERSION_KEY, 0);
        const migratedAt = readStorageMetaNumber(STORAGE_MIGRATED_AT_KEY, 0);
        const now = Date.now();
        if (currentVersion < SETTINGS_STORAGE_VERSION) {
            syncAllNtcfgLeaderboardsSettings();
            writeCanonicalValue(STORAGE_VERSION_KEY, SETTINGS_STORAGE_VERSION);
            if (!migratedAt) {
                writeCanonicalValue(STORAGE_MIGRATED_AT_KEY, now);
                writeCanonicalValue(STORAGE_CLEANUP_AFTER_KEY, now + LEGACY_CLEANUP_GRACE_MS);
            }
        }
        const cleanupAfter = readStorageMetaNumber(STORAGE_CLEANUP_AFTER_KEY, 0);
        if (cleanupAfter && now >= cleanupAfter) {
            try {
                localStorage.removeItem('ntStartrackDebug');
            } catch {
                // ignore legacy cleanup failures
            }
        }
    };
    // Register manifest and seed defaults
    ensureLeaderboardsStorageMigration();
    registerNtcfgLeaderboardsManifest();
    seedNtcfgLeaderboardsDefaults();
    syncAllNtcfgLeaderboardsSettings();
    // Alive signal — write BEFORE dispatching manifest-updated so the mod menu sees this script as alive when it re-renders.
    try { localStorage.setItem('ntcfg:alive:' + NTCFG_LEADERBOARDS_MANIFEST_ID, String(Date.now())); } catch { /* ignore */ }

    try {
        document.dispatchEvent(new CustomEvent('ntcfg:manifest-updated', {
            detail: { script: NTCFG_LEADERBOARDS_MANIFEST_ID }
        }));
    } catch {
        // ignore event dispatch failures
    }

    function initNTRouteHelper(targetWindow = window) {
        const hostWindow = targetWindow || window;
        const existing = hostWindow.NTRouteHelper;
        if (existing && existing.__ntRouteHelperReady && typeof existing.subscribe === 'function') {
            return existing;
        }

        const helper = existing || {};
        const listeners = helper.listeners instanceof Set ? helper.listeners : new Set();
        let currentKey = `${hostWindow.location.pathname}${hostWindow.location.search}${hostWindow.location.hash}`;

        const notify = (reason) => {
            const nextKey = `${hostWindow.location.pathname}${hostWindow.location.search}${hostWindow.location.hash}`;
            if (reason !== 'init' && nextKey === currentKey) return;
            const previousKey = currentKey;
            currentKey = nextKey;
            listeners.forEach((listener) => {
                try {
                    listener({
                        reason,
                        previous: previousKey,
                        current: nextKey,
                        pathname: hostWindow.location.pathname
                    });
                } catch (error) {
                    console.error('[NTRouteHelper] listener error', error);
                }
            });
            helper.currentKey = currentKey;
        };

        if (!helper.__ntRouteHelperWrapped) {
            const wrapHistoryMethod = (methodName) => {
                const current = hostWindow.history[methodName];
                if (typeof current !== 'function' || current.__ntRouteHelperWrapped) return;
                const wrapped = function() {
                    const result = current.apply(this, arguments);
                    queueMicrotask(() => notify(methodName));
                    return result;
                };
                wrapped.__ntRouteHelperWrapped = true;
                wrapped.__ntRouteHelperOriginal = current;
                hostWindow.history[methodName] = wrapped;
            };
            wrapHistoryMethod('pushState');
            wrapHistoryMethod('replaceState');
            hostWindow.addEventListener('popstate', () => queueMicrotask(() => notify('popstate')));
            helper.__ntRouteHelperWrapped = true;
        }

        helper.listeners = listeners;
        helper.currentKey = currentKey;
        helper.version = '1.0.0';
        helper.__ntRouteHelperReady = true;
        helper.subscribe = function(listener, options = {}) {
            if (typeof listener !== 'function') return () => {};
            listeners.add(listener);
            if (options.immediate !== false) {
                try {
                    listener({
                        reason: 'init',
                        previous: currentKey,
                        current: currentKey,
                        pathname: hostWindow.location.pathname
                    });
                } catch (error) {
                    console.error('[NTRouteHelper] immediate listener error', error);
                }
            }
            return () => listeners.delete(listener);
        };
        helper.notify = notify;

        hostWindow.NTRouteHelper = helper;
        return helper;
    }

    // ─── End Mod Menu Manifest Bridge ───────────────────────────────────────────
    // =================================================================
    // 1. CSS & ANTI-FLICKER SYSTEM
    // =================================================================
    const globalStyles = `
        /* Curtain Logic */
        html.is-leaderboard-route main.structure-content {
            opacity: 0 !important;
            visibility: hidden !important;
        }
        html.is-leaderboard-route main.structure-content.custom-loaded {
            opacity: 1 !important;
            visibility: visible !important;
            transition: opacity 0.15s ease-in;
        }
        /* Spin Animation for Refresh Icon */
        @keyframes nt-spin { 100% { transform: rotate(360deg); } }
        .icon-spin { animation: nt-spin 1s linear infinite; }
        /* Refresh Button Styling */
        #manual-refresh-btn {
            transition: opacity 0.2s, color 0.2s;
            cursor: pointer;
            vertical-align: middle;
        }
        #manual-refresh-btn:hover {
            opacity: 1 !important;
            color: #fff !important;
        }
        /* Position Change Arrows */
        .position-change {
            font-size: 10px;
            font-weight: bold;
            margin-right: 4px;
            vertical-align: middle;
            display: inline-flex;
            align-items: center;
            gap: 1px;
        }
        .position-change--up {
            color: #28a745;
        }
        .position-change--down {
            color: #dc3545;
        }
    `;
    const styleEl = document.createElement('style');
    styleEl.textContent = globalStyles;
    (document.head || document.documentElement).appendChild(styleEl);
    // Hide Class Tab CSS — injected at document-start to prevent flicker
    const hideClassTabStyle = document.createElement('style');
    hideClassTabStyle.id = 'ntcfg-hide-class-tab';
    hideClassTabStyle.textContent = `
        a[href*="/class"], a[href*="/classes"] {
            display: none !important;
            opacity: 0 !important;
        }
        .nav-list-item:has(a[href*="/class"]),
        .nav-list-item:has(a[href*="/classes"]) {
            display: none !important;
            width: 0 !important;
            margin: 0 !important;
            padding: 0 !important;
            border: none !important;
        }
    `;
    function syncHideClassTabState() {
        if (readNtcfgLeaderboardsValue('HIDE_CLASS_TAB')) {
            if (!document.getElementById('ntcfg-hide-class-tab')) {
                (document.head || document.documentElement).appendChild(hideClassTabStyle);
            }
        } else {
            document.getElementById('ntcfg-hide-class-tab')?.remove();
        }
    }
    syncHideClassTabState();
    // Listen for live toggle changes
    document.addEventListener('ntcfg:change', (event) => {
        if (event?.detail?.script !== NTCFG_LEADERBOARDS_MANIFEST_ID) return;
        if (event.detail.key === 'HIDE_CLASS_TAB') {
            syncHideClassTabState();
        }
    });
    function updateRouteStatus() {
        if (location.pathname === '/leaderboards' && isNtcfgLeaderboardsFeatureEnabled('ANTI_FLICKER_MODE')) {
            document.documentElement.classList.add('is-leaderboard-route');
        } else {
            document.documentElement.classList.remove('is-leaderboard-route');
            const main = document.querySelector('main.structure-content');
            if (main) main.classList.remove('custom-loaded');
        }
    }
    updateRouteStatus();
    const ntRouteHelper = initNTRouteHelper(window);
    // =================================================================
    // 2. SHARED OPTIMIZATION LAYER (Compat across scripts)
    // =================================================================
    function initNTShared() {
        const shared = window.NTShared || {};
        shared.version = '2.0.0';
        const existingCache = shared.cache;
        const hasMapCache = existingCache instanceof Map;
        const cacheMap = shared.cacheMap || (hasMapCache ? existingCache : new Map());
        const cacheObj = shared.cacheObj || (!hasMapCache && existingCache && typeof existingCache === 'object' ? existingCache : {
            individual: { data: null, timestamp: 0, expiresAt: 0 },
            team: { data: null, timestamp: 0, expiresAt: 0 },
            isbot: new Map()
        });
        if (!cacheObj.individual) cacheObj.individual = { data: null, timestamp: 0, expiresAt: 0 };
        if (!cacheObj.team) cacheObj.team = { data: null, timestamp: 0, expiresAt: 0 };
        if (!cacheObj.isbot) cacheObj.isbot = new Map();
        const isbot = shared.isbot || cacheObj.isbot || new Map();
        cacheObj.isbot = isbot;
        if (!shared.cache) shared.cache = cacheObj;
        shared.cacheMap = cacheMap;
        shared.cacheObj = cacheObj;
        shared.isbot = isbot;
        shared._makeKey = shared._makeKey || function(view, timeframe, startKey, endKey) {
            return `${view}_${timeframe}_${startKey}_${endKey}`;
        };
        const BOT_STATUS_TTL_MS = shared.BOT_STATUS_TTL_MS || (24 * 60 * 60 * 1000);
        const BOT_STATUS_MAX_ENTRIES = shared.BOT_STATUS_MAX_ENTRIES || 5000;
        shared.BOT_STATUS_TTL_MS = BOT_STATUS_TTL_MS;
        shared.BOT_STATUS_MAX_ENTRIES = BOT_STATUS_MAX_ENTRIES;
        const syncState = shared._syncState || {
            initialized: false,
            tabId: `tab_${Math.random().toString(36).slice(2)}_${Date.now()}`,
            broadcastChannel: null,
            storageKey: 'ntSharedCacheSyncV1'
        };
        shared._syncState = syncState;
        function emitLocalUpdate(detail) {
            window.dispatchEvent(new CustomEvent('nt-cache-updated', { detail: detail }));
        }
        function normalizeBotEntry(raw, now) {
            if (!raw) return null;
            if (raw && typeof raw === 'object' && raw.status && typeof raw.ts === 'number') return raw;
            return { status: raw, ts: now };
        }
        function pruneBotCache() {
            const now = Date.now();
            isbot.forEach((value, key) => {
                const entry = normalizeBotEntry(value, now);
                if (!entry) {
                    isbot.delete(key);
                    return;
                }
                if (now - entry.ts > BOT_STATUS_TTL_MS) {
                    isbot.delete(key);
                    return;
                }
                if (entry !== value) isbot.set(key, entry);
            });
            if (isbot.size <= BOT_STATUS_MAX_ENTRIES) return;
            const entries = Array.from(isbot.entries())
                .map(([key, value]) => [key, normalizeBotEntry(value, now)])
                .filter(([, value]) => !!value)
                .sort((a, b) => a[1].ts - b[1].ts);
            const overflow = entries.length - BOT_STATUS_MAX_ENTRIES;
            for (let i = 0; i < overflow; i++) {
                isbot.delete(entries[i][0]);
            }
        }
        function postCrossTabUpdate(payload) {
            if (!payload || !syncState.initialized) return;
            const message = Object.assign({}, payload, {
                __ntSharedSync: true,
                origin: syncState.tabId,
                sentAt: Date.now()
            });
            if (syncState.broadcastChannel) {
                try { syncState.broadcastChannel.postMessage(message); } catch (e) {}
            }
            try {
                localStorage.setItem(syncState.storageKey, JSON.stringify(message));
                localStorage.removeItem(syncState.storageKey);
            } catch (e) {}
        }
        function setLegacyCacheInternal(type, data, expiresAt, options = {}) {
            if (!cacheObj[type]) cacheObj[type] = { data: null, timestamp: 0, expiresAt: 0 };
            const now = options.timestamp || Date.now();
            cacheObj[type].data = data;
            cacheObj[type].timestamp = now;
            cacheObj[type].expiresAt = expiresAt || (now + 3600000);
            emitLocalUpdate({ type, data, expiresAt: cacheObj[type].expiresAt, source: options.source || 'local' });
            if (options.broadcast !== false) {
                postCrossTabUpdate({
                    kind: 'legacy',
                    type: type,
                    data: data,
                    expiresAt: cacheObj[type].expiresAt,
                    timestamp: now
                });
            }
        }
        function setKeyedCacheInternal(key, data, expiresAt, options = {}) {
            const now = options.timestamp || Date.now();
            const ttl = expiresAt || (now + 3600000);
            cacheMap.set(key, { data: data, timestamp: now, expiresAt: ttl });
            emitLocalUpdate({ key, data, expiresAt: ttl, source: options.source || 'local' });
            if (options.broadcast !== false) {
                postCrossTabUpdate({
                    kind: 'keyed',
                    key: key,
                    data: data,
                    expiresAt: ttl,
                    timestamp: now
                });
            }
        }
        function setBotStatusInternal(username, status, options = {}) {
            if (!username) return;
            const key = username.toLowerCase();
            const now = options.timestamp || Date.now();
            isbot.set(key, { status: status, ts: now });
            pruneBotCache();
            emitLocalUpdate({ type: 'isbot', username: key, data: status, source: options.source || 'local' });
            if (options.broadcast !== false) {
                postCrossTabUpdate({
                    kind: 'isbot',
                    username: key,
                    status: status,
                    timestamp: now
                });
            }
        }
        function applyCrossTabMessage(message, source) {
            if (!message || message.origin === syncState.tabId) return;
            if (message.kind === 'legacy' && message.type) {
                setLegacyCacheInternal(message.type, message.data, message.expiresAt, {
                    broadcast: false,
                    timestamp: message.timestamp,
                    source: source || 'remote'
                });
                return;
            }
            if (message.kind === 'keyed' && message.key) {
                setKeyedCacheInternal(message.key, message.data, message.expiresAt, {
                    broadcast: false,
                    timestamp: message.timestamp,
                    source: source || 'remote'
                });
                return;
            }
            if (message.kind === 'isbot' && message.username) {
                setBotStatusInternal(message.username, message.status, {
                    broadcast: false,
                    timestamp: message.timestamp,
                    source: source || 'remote'
                });
            }
        }
        if (!syncState.initialized) {
            syncState.initialized = true;
            if (typeof BroadcastChannel !== 'undefined') {
                try {
                    syncState.broadcastChannel = new BroadcastChannel('ntSharedCacheSyncV1');
                    syncState.broadcastChannel.onmessage = function(event) {
                        const message = event ? event.data : null;
                        if (!message || !message.__ntSharedSync) return;
                        applyCrossTabMessage(message, 'broadcast');
                    };
                } catch (e) {}
            }
            window.addEventListener('storage', (event) => {
                if (!event || event.key !== syncState.storageKey || !event.newValue) return;
                try {
                    const message = JSON.parse(event.newValue);
                    if (!message || !message.__ntSharedSync) return;
                    applyCrossTabMessage(message, 'storage');
                } catch (e) {}
            });
        }
        shared.setLegacyCache = function(type, data, expiresAt) {
            setLegacyCacheInternal(type, data, expiresAt);
        };
        shared.setCache = function(key, data, expiresAt) {
            if (typeof key === 'string' && cacheObj[key]) {
                setLegacyCacheInternal(key, data, expiresAt);
                return;
            }
            setKeyedCacheInternal(key, data, expiresAt);
        };
        shared.getCache = function(key, maxAge) {
            const now = Date.now();
            const maxAgeMs = typeof maxAge === 'number' ? maxAge : Number.POSITIVE_INFINITY;
            if (typeof key === 'string' && cacheObj[key]) {
                const cached = cacheObj[key];
                if (!cached || !cached.data) return null;
                const age = now - (cached.timestamp || 0);
                if (age < maxAgeMs && now < (cached.expiresAt || 0)) return cached.data;
                return null;
            }
            const cached = cacheMap.get(key);
            if (!cached || !cached.data) return null;
            const age = now - (cached.timestamp || 0);
            if (age < maxAgeMs && now < cached.expiresAt) return cached.data;
            return null;
        };
        shared.getTimestamp = function(key) {
            if (typeof key === 'string' && cacheObj[key]) return cacheObj[key].timestamp || null;
            const cached = cacheMap.get(key);
            return cached?.timestamp || null;
        };
        shared.getLegacyCache = function(type, maxAge) {
            return shared.getCache(type, maxAge);
        };
        shared.getBotStatus = function(username) {
            if (!username) return null;
            const key = username.toLowerCase();
            const value = isbot.get(key);
            if (!value) return null;
            const entry = normalizeBotEntry(value, Date.now());
            if (!entry) return null;
            if (Date.now() - entry.ts > BOT_STATUS_TTL_MS) {
                isbot.delete(key);
                return null;
            }
            if (entry !== value) isbot.set(key, entry);
            return entry.status;
        };
        shared.setBotStatus = function(username, status) {
            setBotStatusInternal(username, status);
        };
        window.NTShared = shared;
        return shared;
    }
    initNTShared();
    // --- CONFIGURATION ---
    const TAB_CLASS = 'nt-custom-leaderboards';
    const LEADERBOARD_PATH = '/leaderboards';
    const CACHE_KEY = 'ntStartrackCache_';
    const SHARED_CACHE_PREFIX = 'ntStartrackCacheExp_';
    const CACHE_TIMESTAMP_KEY = 'ntStartrackCacheTime_';
    const SEASON_CACHE_KEY = 'ntStartrackSeasonCache';
    const SHARED_LEADERBOARD_SCHEMA_VERSION = 1;
    const SHARED_LEADERBOARD_BOT_POLICY = 'server_filtered';
    function getCacheDurationMs() {
        const minutes = readNtcfgLeaderboardsValue('CACHE_DURATION_MINUTES');
        return (typeof minutes === 'number' && minutes > 0 ? minutes : 60) * 60 * 1000;
    }
    const DAILY_SYNC_KEY = 'ntStartrackDailySyncCT';
    const HOURLY_SYNC_KEY = 'ntStartrackHourlySyncCT';
    const SEASON_REFRESH_MS = 6 * 60 * 60 * 1000;
    const DEBUG_FLAG_KEY = 'ntStartrackDebug';
    const DEBUG_SEASON_ONLY_KEY = 'ntStartrackDebugSeasonOnly';
    const BOOTSTRAP_SCRIPT_PATH_FALLBACK = '/index/faf5993982a8235165748e39847ee73ba1dea710-1847/bootstrap.js';
    const BACKGROUND_SYNC_DELAY_MS = 350;
    const ASYNC_DELAY = 50;
    const DEBUG_PARAM_ENABLED = /(?:\?|&)ntdebug=1(?:&|$)/.test(window.location.search);
    const DEBUG_ENABLED = DEBUG_PARAM_ENABLED || localStorage.getItem(DEBUG_FLAG_KEY) === '1' || readNtcfgLeaderboardsValue('DEBUG_LOGGING') === true;
    const DEBUG_SEASON_ONLY = localStorage.getItem(DEBUG_SEASON_ONLY_KEY) === '1';
    // --- STATE ---
    let cacheQueue = [];
    let isCaching = false;
    let forceBackgroundUpdate = false;
    let initialCacheComplete = false;
    let carDataMap = {};
    let carDataLoaded = false;
    let carDataLoadAttempts = 0;
    const MAX_CAR_LOAD_ATTEMPTS = 10;
    let lastCheckedHour = null;
    let hourlyCheckInterval = null;
    let pageRenderInProgress = false;
    let seasonBootstrapFetchInFlight = false;
    let seasonBootstrapLastAttemptMs = 0;
    // Dynamic season data (loaded from NTBOOTSTRAP)
    let currentSeason = {
        seasonID: null,
        name: 'Season',
        startCT: null,
        endCT: null,
        startStampUTC: null,
        endStampUTC: null
    };
    let state = {
        view: readNtcfgLeaderboardsValue('DEFAULT_VIEW') || 'individual',
        timeframe: readNtcfgLeaderboardsValue('DEFAULT_TIMEFRAME') || 'season',
        currentDate: getCurrentCT(),
        dateRange: { start: null, end: null }
    };
    function shouldLogDebug(payload) {
        if (!DEBUG_ENABLED) return false;
        if (!DEBUG_SEASON_ONLY) return true;
        if (!payload || typeof payload !== 'object') return false;
        const tf = payload.timeframe || payload.targetTimeframe || payload.stateTimeframe;
        return tf === 'season' || payload.reason === 'season';
    }
    function debugLog(event, payload) {
        if (!shouldLogDebug(payload)) return;
        const ts = new Date().toISOString();
        if (payload === undefined) {
            console.log(`[Startrack][DBG ${ts}] ${event}`);
            return;
        }
        console.log(`[Startrack][DBG ${ts}] ${event}`, payload);
    }
    function shortCacheKey(cacheKey) {
        if (!cacheKey) return '';
        return cacheKey.replace(CACHE_KEY, '');
    }
    function getCacheFreshness(cacheKey, ttlMs = getCacheDurationMs()) {
        const timestampKey = CACHE_TIMESTAMP_KEY + cacheKey;
        const rawTimestamp = localStorage.getItem(timestampKey);
        if (!rawTimestamp) {
            return { hasTimestamp: false, fresh: false, ageMs: null, ttlMs: ttlMs };
        }
        const timestamp = parseInt(rawTimestamp, 10);
        const ageMs = Date.now() - timestamp;
        return { hasTimestamp: true, fresh: ageMs < ttlMs, ageMs: ageMs, ttlMs: ttlMs, timestamp: timestamp };
    }
    const timeframes = [
        { key: 'season', label: 'Season', hasNav: false },
        { key: '24hr', label: 'Last 24 Hours', hasNav: false },
        { key: '60min', label: '60 Minutes', hasNav: false },
        { key: '7day', label: 'Last 7 Days', hasNav: false },
        { key: 'daily', label: 'Daily', hasNav: true },
        { key: 'weekly', label: 'Weekly', hasNav: true },
        { key: 'monthly', label: 'Monthly', hasNav: true }
        // { key: 'custom', label: 'Custom', hasNav: false }  // TODO: Add custom date picker UI
    ];
    // =================================================================
    // 3. TIMEZONE & SEASON UTILITIES
    // =================================================================
    function getCurrentCT() {
        const now = new Date();
        const ctString = now.toLocaleString("en-US", { timeZone: "America/Chicago" });
        return new Date(ctString);
    }
    function getCTDateKey() {
        const ct = getCurrentCT();
        const y = ct.getFullYear();
        const m = String(ct.getMonth() + 1).padStart(2, '0');
        const d = String(ct.getDate()).padStart(2, '0');
        return `${y}-${m}-${d}`;
    }
    function getCTHourKey() {
        const ct = getCurrentCT();
        const y = ct.getFullYear();
        const m = String(ct.getMonth() + 1).padStart(2, '0');
        const d = String(ct.getDate()).padStart(2, '0');
        const h = String(ct.getHours()).padStart(2, '0');
        return `${y}-${m}-${d}-${h}`;
    }
    function getMsUntilNextCTMidnight() {
        const ct = getCurrentCT();
        const next = new Date(ct);
        next.setHours(24, 0, 0, 0);
        return Math.max(0, next.getTime() - ct.getTime());
    }
    function getCacheTTLForTimeframe(timeframe) {
        if (timeframe === 'season') return SEASON_REFRESH_MS;
        if (timeframe === 'daily' || timeframe === 'weekly' || timeframe === 'monthly') {
            return getMsUntilNextCTMidnight();
        }
        if (timeframe === '60min' || timeframe === '24hr' || timeframe === '7day') {
            return getCacheDurationMs();
        }
        return getCacheDurationMs();
    }
    function getCurrentHour() { return new Date().getHours(); }
    function getSharedRowLimit(view) { return view === 'individual' ? 300 : 50; }
    function getSharedCacheKey(tempState) {
        return getCacheKey(tempState).replace(CACHE_KEY, SHARED_CACHE_PREFIX);
    }
    function sanitizeLeaderboardRows(view, rows) {
        if (!Array.isArray(rows)) return [];
        let removedBotRows = 0;
        const sanitized = rows.filter((entry) => {
            if (!entry || typeof entry !== 'object') return false;
            if (entry.bot === 1) {
                removedBotRows += 1;
                return false;
            }
            if (view === 'individual') {
                return !!String(entry.Username || entry.username || '').trim();
            }
            return !!String(entry.TeamTag || entry.teamTag || entry.TeamName || entry.teamName || '').trim();
        });
        if (removedBotRows > 0) {
            debugLog('Unexpected bot rows removed from payload', {
                view,
                removedBotRows
            });
        }
        return sanitized;
    }
    function buildSharedLeaderboardPayload(view, timeframe, rows, writtenAt, expiresAt) {
        return {
            schemaVersion: SHARED_LEADERBOARD_SCHEMA_VERSION,
            source: `leaderboards@${typeof GM_info !== 'undefined' ? GM_info.script.version : 'unknown'}`,
            botPolicy: SHARED_LEADERBOARD_BOT_POLICY,
            view,
            timeframe,
            rowLimit: getSharedRowLimit(view),
            writtenAt,
            expiresAt,
            rows: Array.isArray(rows) ? rows.slice(0, getSharedRowLimit(view)) : []
        };
    }
    function saveSharedPayloadToLocalStorage(cacheKey, payload) {
        if (!cacheKey || !payload) return;
        try {
            localStorage.setItem(cacheKey, JSON.stringify(payload));
            localStorage.setItem(CACHE_TIMESTAMP_KEY + cacheKey, String(payload.writtenAt || Date.now()));
        } catch (error) {
            debugLog('Shared payload localStorage write failed', {
                key: shortCacheKey(cacheKey),
                message: error && error.message ? error.message : String(error)
            });
        }
    }
    // Convert Unix timestamp (UTC seconds) to CT-formatted string for Startrack API
    function utcToCTString(unixTimestamp) {
        const date = new Date(unixTimestamp * 1000);
        const ctString = date.toLocaleString("en-US", { timeZone: "America/Chicago" });
        const ctDate = new Date(ctString);
        return formatDate(ctDate);
    }
    // Convert Unix timestamp to user's local timezone for display
    function utcToLocalDate(unixTimestamp) {
        return new Date(unixTimestamp * 1000);
    }
    // Check if cache should be refreshed (within 1 week of season end)
    function shouldRefreshSeasonCache(endStampUTC) {
        if (!endStampUTC) return true;
        const oneWeekMs = 7 * 24 * 60 * 60 * 1000;
        const endMs = endStampUTC * 1000;
        const now = Date.now();
        return (endMs - now) < oneWeekMs;
    }
    function hasValidSeasonData() {
        return !!(
            currentSeason &&
            currentSeason.startCT &&
            currentSeason.endCT &&
            currentSeason.startStampUTC &&
            currentSeason.endStampUTC
        );
    }
    function parseActiveSeasonsFromBootstrapPayload(bootstrapData) {
        if (!Array.isArray(bootstrapData)) return null;
        const seasonsData = bootstrapData.find(item => Array.isArray(item) && item[0] === 'ACTIVE_SEASONS');
        if (!seasonsData || !Array.isArray(seasonsData[1]) || seasonsData[1].length === 0) return null;
        return seasonsData[1];
    }
    function parseActiveSeasonsFromBootstrapScript(scriptText) {
        if (!scriptText || typeof scriptText !== 'string') return null;
        const match = scriptText.match(/\["ACTIVE_SEASONS",(\[[\s\S]*?\])\],\["ACTIVE_EVENTS"/);
        if (!match || !match[1]) return null;
        try {
            const parsed = JSON.parse(match[1]);
            return Array.isArray(parsed) && parsed.length > 0 ? parsed : null;
        } catch (e) {
            return null;
        }
    }
    function pickActiveSeason(seasons) {
        if (!Array.isArray(seasons) || seasons.length === 0) return null;
        const now = Math.floor(Date.now() / 1000);
        const active = seasons.find(s => now >= s.startStamp && now < s.endStamp);
        if (active) return active;
        return seasons.slice().sort((a, b) => (b.startStamp || 0) - (a.startStamp || 0))[0] || null;
    }
    function applySeasonFromRecord(seasonRecord, source) {
        if (!seasonRecord) return false;
        currentSeason = {
            seasonID: seasonRecord.seasonID,
            name: seasonRecord.name,
            startStampUTC: seasonRecord.startStamp,
            endStampUTC: seasonRecord.endStamp,
            startCT: utcToCTString(seasonRecord.startStamp),
            endCT: utcToCTString(seasonRecord.endStamp)
        };
        localStorage.setItem(SEASON_CACHE_KEY, JSON.stringify(currentSeason));
        debugLog('Season loaded', {
            source: source,
            seasonName: currentSeason.name,
            targetTimeframe: 'season'
        });
        debugLog('Season source selected', {
            source: source,
            seasonName: currentSeason.name,
            seasonID: currentSeason.seasonID,
            startStampUTC: currentSeason.startStampUTC,
            endStampUTC: currentSeason.endStampUTC,
            targetTimeframe: 'season'
        });
        return true;
    }
    function getBootstrapScriptUrl() {
        const scriptEl = document.querySelector('script[src*="/bootstrap.js"]');
        if (scriptEl && scriptEl.src) return scriptEl.src;
        return new URL(BOOTSTRAP_SCRIPT_PATH_FALLBACK, window.location.origin).href;
    }
    function fetchSeasonDataFromBootstrapScript() {
        const now = Date.now();
        const retryDelayMs = 5 * 60 * 1000;
        if (seasonBootstrapFetchInFlight) return;
        if (now - seasonBootstrapLastAttemptMs < retryDelayMs) return;
        seasonBootstrapFetchInFlight = true;
        seasonBootstrapLastAttemptMs = now;
        const bootstrapUrl = getBootstrapScriptUrl();
        debugLog('Season bootstrap script fetch start', {
            source: 'bootstrap-script',
            url: bootstrapUrl,
            targetTimeframe: 'season'
        });
        GM_xmlhttpRequest({
            method: 'GET',
            url: bootstrapUrl,
            onload: function(response) {
                seasonBootstrapFetchInFlight = false;
                if (response.status !== 200 || !response.responseText) {
                    debugLog('Season bootstrap script fetch failed', {
                        source: 'bootstrap-script',
                        status: response.status,
                        targetTimeframe: 'season'
                    });
                    return;
                }
                const seasons = parseActiveSeasonsFromBootstrapScript(response.responseText);
                const activeSeason = pickActiveSeason(seasons || []);
                if (!activeSeason) {
                    debugLog('Season bootstrap script parse returned no seasons', {
                        source: 'bootstrap-script',
                        targetTimeframe: 'season'
                    });
                    return;
                }
                if (!applySeasonFromRecord(activeSeason, 'bootstrap-script')) {
                    return;
                }
                if (location.pathname === LEADERBOARD_PATH && state.timeframe === 'season') {
                    fetchLeaderboardData(true);
                } else {
                    startBackgroundSync('season-bootstrap', {
                        timeframes: ['season'],
                        includeNav: false,
                        includeCurrent: true,
                        force: true
                    });
                }
            },
            onerror: function() {
                seasonBootstrapFetchInFlight = false;
                debugLog('Season bootstrap script fetch transport error', {
                    source: 'bootstrap-script',
                    targetTimeframe: 'season'
                });
            }
        });
    }
    // Load season data from NTBOOTSTRAP, cache, or bootstrap script fallback
    function loadSeasonData() {
        // 1. Check localStorage cache first
        try {
            const cached = localStorage.getItem(SEASON_CACHE_KEY);
            if (cached) {
                const seasonCache = JSON.parse(cached);
                const shouldRefresh = shouldRefreshSeasonCache(seasonCache.endStampUTC);
                debugLog('Season cache check', {
                    source: 'localStorage',
                    seasonName: seasonCache.name,
                    endStampUTC: seasonCache.endStampUTC,
                    shouldRefresh: shouldRefresh,
                    targetTimeframe: 'season'
                });
                if (!shouldRefresh) {
                    currentSeason = seasonCache;
                    debugLog('Season cache hit (fresh)', {
                        source: 'localStorage',
                        seasonName: currentSeason.name,
                        targetTimeframe: 'season'
                    });
                    debugLog('Season source selected', {
                        source: 'localStorage-fresh',
                        seasonName: currentSeason.name,
                        targetTimeframe: 'season'
                    });
                    return true;
                }
            }
        } catch (e) {
            console.warn('[Startrack] Error reading season cache:', e);
            debugLog('Season cache read error', {
                message: e && e.message ? e.message : String(e),
                targetTimeframe: 'season'
            });
        }
        // 2. Parse NTBOOTSTRAP for ACTIVE_SEASONS
        if (typeof NTBOOTSTRAP === 'function') {
            try {
                const bootstrapData = NTBOOTSTRAP();
                const seasons = parseActiveSeasonsFromBootstrapPayload(bootstrapData);
                const activeSeason = pickActiveSeason(seasons || []);
                if (activeSeason && applySeasonFromRecord(activeSeason, 'NTBOOTSTRAP')) {
                    return true;
                }
            } catch (e) {
                console.warn('[Startrack] Error parsing NTBOOTSTRAP for seasons:', e);
                debugLog('Season bootstrap parse error', {
                    message: e && e.message ? e.message : String(e),
                    targetTimeframe: 'season'
                });
            }
        }
        // 3. Fallback: use expired cache if available while we request fresh season metadata
        try {
            const cached = localStorage.getItem(SEASON_CACHE_KEY);
            if (cached) {
                currentSeason = JSON.parse(cached);
                debugLog('Season cache hit (expired fallback)', {
                    source: 'localStorage',
                    seasonName: currentSeason.name,
                    targetTimeframe: 'season'
                });
                debugLog('Season source selected', {
                    source: 'localStorage-expired-fallback',
                    seasonName: currentSeason.name,
                    targetTimeframe: 'season'
                });
                fetchSeasonDataFromBootstrapScript();
                return hasValidSeasonData();
            }
        } catch (e) {}
        // 4. No season metadata available yet, fetch asynchronously from bootstrap script
        fetchSeasonDataFromBootstrapScript();
        console.warn('[Startrack] Season metadata not available yet; skipping season fetch until bootstrap data is loaded');
        debugLog('Season source selected', {
            source: 'pending-bootstrap-script',
            seasonName: currentSeason.name || 'Season',
            targetTimeframe: 'season'
        });
        return hasValidSeasonData();
    }
    // Format season dates for display (user's local timezone)
    function getSeasonDisplayDates() {
        if (!currentSeason.startStampUTC || !currentSeason.endStampUTC) {
            return { startDisplay: 'Unknown', endDisplay: 'Unknown' };
        }
        const startLocal = utcToLocalDate(currentSeason.startStampUTC);
        const endLocal = utcToLocalDate(currentSeason.endStampUTC);
        const options = { month: 'short', day: 'numeric', year: 'numeric' };
        return {
            startDisplay: startLocal.toLocaleDateString(undefined, options),
            endDisplay: endLocal.toLocaleDateString(undefined, options)
        };
    }
    // =================================================================
    // 4. POSITION CHANGE HELPER
    // =================================================================
    function getPositionChangeHTML(change) {
        if (!isNtcfgLeaderboardsFeatureEnabled('HIGHLIGHT_POSITION_CHANGE')) return '';
        const parsedChange = parseInt(change, 10);
        if (isNaN(parsedChange) || parsedChange === 0) {
            return `<div class="rank-change rank-change--none"><svg class="icon icon-arrow-up"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/site/images/icons/icons.css.svg#icon-arrow-up"></use></svg><div>-</div><svg class="icon icon-arrow-down"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/site/images/icons/icons.css.svg#icon-arrow-down"></use></svg></div>`;
        }
        if (parsedChange > 0) {
            return `<div class="rank-change rank-change--up"><svg class="icon icon-arrow-up"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/site/images/icons/icons.css.svg#icon-arrow-up"></use></svg><div>${parsedChange}</div><svg class="icon icon-arrow-down"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/site/images/icons/icons.css.svg#icon-arrow-down"></use></svg></div>`;
        } else {
            return `<div class="rank-change rank-change--down"><svg class="icon icon-arrow-up"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/site/images/icons/icons.css.svg#icon-arrow-up"></use></svg><div>${Math.abs(parsedChange)}</div><svg class="icon icon-arrow-down"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/site/images/icons/icons.css.svg#icon-arrow-down"></use></svg></div>`;
        }
    }
    // =================================================================
    // 5. CAR DATA LOADING (DEFERRED WITH RETRY)
    // =================================================================
    function loadCarData(callback) {
        // Check cache timestamp first
        const cacheTimestamp = localStorage.getItem('ntCarDataMapTimestamp');
        const cacheAge = cacheTimestamp ? Date.now() - parseInt(cacheTimestamp) : Infinity;
        const SEVEN_DAYS = 7 * 24 * 60 * 60 * 1000;
        // Try loading from cache if it's less than 7 days old
        if (cacheAge < SEVEN_DAYS) {
            const cached = localStorage.getItem('ntCarDataMap');
            if (cached) {
                try {
                    carDataMap = JSON.parse(cached);
                    if (Object.keys(carDataMap).length > 0) {
                        carDataLoaded = true;
                        debugLog('Car data loaded from cache', {
                            count: Object.keys(carDataMap).length
                        });
                        if (callback) callback(true);
                        return;
                    }
                } catch (e) {
                    console.warn('[Startrack] Failed to parse cached car data');
                }
            }
        }
        // Try to load from NTBOOTSTRAP
        if (typeof NTBOOTSTRAP === 'function') {
            try {
                const bootstrapData = NTBOOTSTRAP();
                const carsData = bootstrapData.find(item => item[0] === 'CARS');
                if (carsData && carsData[1] && carsData[1].length > 0) {
                    carsData[1].forEach(car => {
                        if (car.carID && car.options && car.options.smallSrc) {
                            carDataMap[car.carID] = car.options.smallSrc;
                        }
                    });
                    if (Object.keys(carDataMap).length > 0) {
                        localStorage.setItem('ntCarDataMap', JSON.stringify(carDataMap));
                        localStorage.setItem('ntCarDataMapTimestamp', Date.now().toString());
                        carDataLoaded = true;
                        debugLog('Car data loaded from NTBOOTSTRAP', {
                            count: Object.keys(carDataMap).length
                        });
                        if (callback) callback(true);
                        return;
                    }
                }
            } catch (e) {
                console.warn('[Startrack] Error loading from NTBOOTSTRAP:', e);
            }
        }
        // NTBOOTSTRAP not available yet - retry
        carDataLoadAttempts++;
        if (carDataLoadAttempts < MAX_CAR_LOAD_ATTEMPTS) {
            debugLog('Car data retry scheduled', {
                attempt: carDataLoadAttempts,
                maxAttempts: MAX_CAR_LOAD_ATTEMPTS
            });
            setTimeout(() => loadCarData(callback), 500);
            return;
        }
        // Max attempts reached - try expired cache as fallback
        const cached = localStorage.getItem('ntCarDataMap');
        if (cached) {
            try {
                carDataMap = JSON.parse(cached);
                if (Object.keys(carDataMap).length > 0) {
                    carDataLoaded = true;
                    debugLog('Car data loaded from expired cache fallback', {
                        count: Object.keys(carDataMap).length
                    });
                    if (callback) callback(true);
                    return;
                }
            } catch (e) {}
        }
        console.error('[Startrack] Failed to load car data after all attempts');
        carDataLoaded = true; // Mark as loaded to prevent infinite retries
        if (callback) callback(false);
    }
    function getCarImage(carID, carHueAngle) {
        const smallSrc = carDataMap[carID];
        if (smallSrc) {
            // If car has a hue angle, use painted version
            if (carHueAngle !== null && carHueAngle !== undefined && carHueAngle !== 0) {
                // Format: /cars/painted/{smallSrc without .png}_{hue}.png
                const baseImage = smallSrc.replace('.png', '');
                const url = `https://www.nitrotype.com/cars/painted/${baseImage}_${carHueAngle}.png`;
                // Debug: uncomment to trace image URLs
                // console.log(`[Startrack] Car ${carID}: painted → ${url}`);
                return url;
            }
            // Unpainted car - use smallSrc directly
            // Debug: uncomment to trace image URLs
            // console.log(`[Startrack] Car ${carID}: unpainted → /cars/${smallSrc}`);
            return `https://www.nitrotype.com/cars/${smallSrc}`;
        }
        // Fallback - unpainted rental car (identifiable error state)
        debugLog('Unknown car ID fallback used', {
            carID: carID,
            loadedCars: Object.keys(carDataMap).length
        });
        return `https://www.nitrotype.com/cars/9_small_1.png`;
    }
    // =================================================================
    // 6. OTHER UTILITIES
    // =================================================================
    function startHourlyCheck() {
        lastCheckedHour = getCurrentHour();
        if (hourlyCheckInterval) clearInterval(hourlyCheckInterval);
        hourlyCheckInterval = setInterval(() => {
            const currentHour = getCurrentHour();
            if (currentHour !== lastCheckedHour && location.pathname === LEADERBOARD_PATH) {
                lastCheckedHour = currentHour;
                state.currentDate = getCurrentCT();
                if (['60min', '24hr', '7day'].includes(state.timeframe)) fetchLeaderboardData(true);
            } else if (currentHour !== lastCheckedHour) {
                lastCheckedHour = currentHour;
            }
        }, 60000);
    }
    function stopHourlyCheck() {
        if (hourlyCheckInterval) { clearInterval(hourlyCheckInterval); hourlyCheckInterval = null; }
    }
    function formatDate(date) {
        if (!date) return '';
        const d = new Date(date);
        const y = d.getFullYear();
        const m = ('0' + (d.getMonth() + 1)).slice(-2);
        const day = ('0' + d.getDate()).slice(-2);
        const h = ('0' + d.getHours()).slice(-2);
        const min = ('0' + d.getMinutes()).slice(-2);
        const s = ('0' + d.getSeconds()).slice(-2);
        return `${y}-${m}-${day} ${h}:${min}:${s}`;
    }
    function getStartOfDay(date) { const d = new Date(date); d.setHours(0, 0, 0, 0); return d; }
    function getEndOfDay(date) { const d = new Date(date); d.setHours(23, 59, 59, 999); return d; }
    function calculateDateRange(tempState) {
        let start, end;
        const current = new Date(tempState.currentDate);
        const timeframe = tempState.timeframe || state.timeframe;
        const now = getCurrentCT();
        if (timeframe === 'season') {
            // Use dynamic season data only when metadata is valid
            if (!hasValidSeasonData()) return { start: null, end: null };
            return { start: currentSeason.startCT, end: currentSeason.endCT };
        }
        else if (timeframe === '60min') { end = now; start = new Date(now.getTime() - (60 * 60 * 1000)); }
        else if (timeframe === '24hr') { end = now; start = new Date(now.getTime() - (24 * 60 * 60 * 1000)); }
        else if (timeframe === '7day') { end = now; start = new Date(now.getTime() - (7 * 24 * 60 * 60 * 1000)); }
        else if (timeframe === 'daily') { start = getStartOfDay(current); end = getEndOfDay(current); }
        else if (timeframe === 'weekly') {
            const dayOfWeek = current.getDay();
            start = getStartOfDay(current);
            start.setDate(start.getDate() - dayOfWeek);
            end = new Date(start);
            end.setDate(end.getDate() + 6);
            end = getEndOfDay(end);
        } else if (timeframe === 'monthly') {
            start = new Date(current.getFullYear(), current.getMonth(), 1);
            end = new Date(current.getFullYear(), current.getMonth() + 1, 0);
            end = getEndOfDay(end);
        } else if (timeframe === 'custom') {
            start = tempState.dateRange?.start || getStartOfDay(now);
            end = tempState.dateRange?.end || getEndOfDay(now);
        }
        return { start: formatDate(start), end: formatDate(end) };
    }
    function navigateDate(direction) {
        const current = state.currentDate;
        const date = new Date(current);
        if (state.timeframe === 'daily') date.setDate(current.getDate() + direction);
        else if (state.timeframe === 'weekly') date.setDate(current.getDate() + (7 * direction));
        else if (state.timeframe === 'monthly') date.setMonth(current.getMonth() + direction);
        state.currentDate = date;
        fetchLeaderboardData();
    }
    function setIndicator(message, isUpdating = true) {
        const indicatorEl = document.getElementById('update-indicator');
        if (indicatorEl) {
            indicatorEl.textContent = message;
            indicatorEl.style.color = isUpdating ? '#FFC107' : '#28A745';
            const refreshBtn = document.getElementById('manual-refresh-btn');
            if (refreshBtn && !isUpdating) {
                const svg = refreshBtn.querySelector('svg');
                if (svg) svg.classList.remove('icon-spin');
            }
            document.querySelectorAll('[data-timeframe]').forEach(btn => {
                btn.classList.remove('is-active', 'is-frozen');
                if (btn.dataset.timeframe === state.timeframe) btn.classList.add('is-active', 'is-frozen');
            });
            document.querySelectorAll('[data-view]').forEach(btn => {
                btn.classList.remove('is-active');
                if (btn.dataset.view === state.view) btn.classList.add('is-active');
            });
        }
    }
    // Generate a cache key for both localStorage and RAM cache
    function getCacheKey(tempState) {
        const s = tempState || state;
        const ranges = calculateDateRange(s);
        let startKey = ranges.start;
        let endKey = ranges.end;
        if (s.timeframe === '60min' || s.timeframe === '24hr' || s.timeframe === '7day') {
            const roundToHour = (dateStr) => {
                const date = new Date(dateStr.replace(' ', 'T'));
                date.setMinutes(0, 0, 0);
                return formatDate(date);
            };
            startKey = roundToHour(ranges.start);
            endKey = roundToHour(ranges.end);
        }
        return `${CACHE_KEY}${s.view}_${s.timeframe}_${startKey}_${endKey}`;
    }
    // --- HTML BUILDING ---
    function buildLeaderboardHTML() {
        const currentTF = timeframes.find(t => t.key === state.timeframe);
        const hasNav = currentTF?.hasNav || false;
        const isCustom = state.timeframe === 'custom';
        return `
            <section class="card card--b card--o card--shadow card--f card--grit well well--b well--l">
                <div class="card-cap bg--gradient">
                    <h1 class="h2 tbs">Startrack Leaderboards</h1>
                </div>
                <div class="well--p well--l_p">
                    <div class="row row--o well well--b well--l">
                        <div class="tabs tabs--a tabs--leaderboards">
                            <button class="tab" data-view="individual">
                                <div class="bucket bucket--c bucket--xs"><div class="bucket-media"><svg class="icon icon-racer"><use xlink:href="/dist/site/images/icons/icons.css.svg#icon-racer"></use></svg></div><div class="bucket-content">Top Racers</div></div>
                            </button>
                            <button class="tab" data-view="team">
                                <div class="bucket bucket--c bucket--xs"><div class="bucket-media"><svg class="icon icon-team"><use xlink:href="/dist/site/images/icons/icons.css.svg#icon-team"></use></svg></div><div class="bucket-content">Top Teams</div></div>
                            </button>
                        </div>
                        <div class="card card--d card--o card--sq card--f">
                            <div class="well--p well--pt">
                                <div class="row row--o has-btn">
                                    ${timeframes.map(tf => `<button type="button" class="btn btn--dark btn--outline btn--thin" data-timeframe="${tf.key}">${tf.label}</button>`).join('')}
                                </div>
                                <div class="divider divider--a mbf"></div>
                                <div class="seasonLeader seasonLeader--default" style="position: relative;">
                                    <div class="split split--start row">
                                        <div class="split-cell">
                                            <h1 class="seasonLeader-title" id="date-title">Loading...</h1>
                                            <p class="seasonLeader-date" id="date-range"></p>
                                        </div>
                                    </div>
                                    <div style="position: absolute; bottom: 10px; width: 100%; text-align: center; left: 0; pointer-events: none;">
                                        <div style="pointer-events: auto; display: inline-flex; align-items: center; justify-content: center;">
                                            <span id="update-indicator" class="mrxs tsm">Loading...</span>
                                            ${isNtcfgLeaderboardsFeatureEnabled('SHOW_MANUAL_REFRESH') ? `<button id="manual-refresh-btn" class="btn btn--bare" title="Manual Refresh - Syncs All Tabs" style="padding: 2px; opacity: 0.6; line-height: 0;">
                                                <svg style="width: 14px; height: 14px; fill: currentColor;" viewBox="0 0 24 24">
                                                    <path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 3.33-3.85 5.63-7.29 5.63-4.14 0-7.5-3.36-7.5-7.5s3.36-7.5 7.5-7.5c2.07 0 3.94.83 5.36 2.24L13 12h7V5l-2.35 1.35z"/>
                                                </svg>
                                            </button>` : ''}
                                        </div>
                                    </div>
                                </div>
                                ${hasNav ? `
                                    <div class="row row--o mtm">
                                        <button class="btn btn--secondary btn--thin" id="nav-prev">&lt; Previous</button>
                                        <button class="btn btn--secondary btn--thin" id="nav-today">Today</button>
                                        <button class="btn btn--secondary btn--thin" id="nav-next">Next &gt;</button>
                                    </div>
                                ` : ''}
                                ${isCustom ? `
                                    <div class="row row--o mtm">
                                        <label class="tsm tc-ts">Start:</label>
                                        <input type="date" id="start-date" class="input input--mini mlxs mrm" value="${state.dateRange.start ? state.dateRange.start.toISOString().split('T')[0] : ''}">
                                        <label class="tsm tc-ts">End:</label>
                                        <input type="date" id="end-date" class="input input--mini mlxs mrm" value="${state.dateRange.end ? state.dateRange.end.toISOString().split('T')[0] : ''}">
                                        <button class="btn btn--primary btn--thin" id="update-custom">Update</button>
                                    </div>
                                ` : ''}
                                <div id="leaderboard-table-container">
                                    <div class="tac pxl mtl">
                                        <div class="loading-spinner loading-spinner--ts" style="margin: 0 auto;"></div>
                                        <div class="mtm">Loading content...</div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </section>
        `;
    }
    // --- CACHE MGMT ---
    function cleanOldCache() {
        try {
            const keys = Object.keys(localStorage);
            const cacheKeys = keys.filter(k => k.startsWith(CACHE_KEY));
            if (cacheKeys.length > 50) {
                cacheKeys.sort().slice(0, cacheKeys.length - 50).forEach(key => {
                    localStorage.removeItem(key);
                    localStorage.removeItem(CACHE_TIMESTAMP_KEY + key);
                });
            }
            // Remove orphaned timestamp keys
            keys.filter(k => k.startsWith(CACHE_TIMESTAMP_KEY)).forEach(tsKey => {
                const baseKey = tsKey.slice(CACHE_TIMESTAMP_KEY.length);
                if (!localStorage.getItem(baseKey)) localStorage.removeItem(tsKey);
            });
        } catch (e) {}
    }
    function isCacheFresh(cacheKey, ttlMs = getCacheDurationMs()) {
        const timestampKey = CACHE_TIMESTAMP_KEY + cacheKey;
        const timestamp = localStorage.getItem(timestampKey);
        if (!timestamp) return false;
        return (Date.now() - parseInt(timestamp)) < ttlMs;
    }
    function saveToCache(cacheKey, data) {
        try {
            localStorage.setItem(cacheKey, data);
            const savedAt = Date.now();
            localStorage.setItem(CACHE_TIMESTAMP_KEY + cacheKey, savedAt.toString());
            debugLog('Cache write success', {
                key: shortCacheKey(cacheKey),
                size: typeof data === 'string' ? data.length : null
            });
        } catch (quotaError) {
            cleanOldCache();
            try {
                localStorage.setItem(cacheKey, data);
                localStorage.setItem(CACHE_TIMESTAMP_KEY + cacheKey, Date.now().toString());
                debugLog('Cache write success after cleanup', {
                    key: shortCacheKey(cacheKey),
                    size: typeof data === 'string' ? data.length : null
                });
            } catch (e2) {}
        }
    }
    // --- RENDER TABLE ---
    function renderTable(data, specificTime = null) {
        const container = document.getElementById('leaderboard-table-container');
        if (!container) return;
        if (!data || data.length === 0) {
            container.innerHTML = '<div class="tac pxl tsm tc-ts">No data available.</div>';
            setIndicator('Updated', false);
            return;
        }
        const top100 = data.slice(0, 100);
        const isIndividual = state.view === 'individual';
        const hasPositionData = top100.some(item => item.position_change !== null && item.position_change !== undefined);
        let html = '<table class="table table--selectable table--striped table--fixed table--leaderboard">';
        html += '<thead class="table-head"><tr class="table-row">';
        const rankChangeHeader = hasPositionData ? '<th scope="col" class="table-cell table-cell--rank-change"></th>' : '';
        html += isIndividual
            ? `${rankChangeHeader}<th scope="col" class="table-cell table-cell--place"></th><th scope="col" class="table-cell table-cell--racer">Racer</th><th scope="col" class="table-cell table-cell--speed">WPM</th><th scope="col" class="table-cell table-cell--races">Accuracy</th><th scope="col" class="table-cell table-cell--races">Races</th><th scope="col" class="table-cell table-cell--points">Points</th>`
            : `${rankChangeHeader}<th scope="col" class="table-cell table-cell--place"></th><th scope="col" class="table-cell table-cell--tag">Tag</th><th scope="col" class="table-cell table-cell--team">Team</th><th scope="col" class="table-cell table-cell--speed">WPM</th><th scope="col" class="table-cell table-cell--races">Accuracy</th><th scope="col" class="table-cell table-cell--races">Races</th><th scope="col" class="table-cell table-cell--points">Points</th>`;
        html += '</tr></thead><tbody class="table-body">';
        top100.forEach((item, index) => {
            const rank = index + 1;
            let rowClass = 'table-row';
            const posChangeHTML = getPositionChangeHTML(item.position_change);
            const rankChangeCellHtml = hasPositionData ? `<td class="table-cell tac table-cell--rank-change">${posChangeHTML}</td>` : '';
            // Rank visual HTML
            let medalHTML = `<div class="mhc"><span class="h3 tc-ts">${rank}</span></div>`;
            if (rank === 1) {
                rowClass = 'table-row table-row--gold';
                medalHTML = `<div class="mhc"><img class="db" src="/dist/site/images/medals/gold-sm.png"></div>`;
            } else if (rank === 2) {
                rowClass = 'table-row table-row--silver';
                medalHTML = `<div class="mhc"><img class="db" src="/dist/site/images/medals/silver-sm.png"></div>`;
            } else if (rank === 3) {
                rowClass = 'table-row table-row--bronze';
                medalHTML = `<div class="mhc"><img class="db" src="/dist/site/images/medals/bronze-sm.png"></div>`;
            }
            const wpm = parseFloat(item.WPM).toFixed(1);
            const acc = (parseFloat(item.Accuracy) * 100).toFixed(2);
            const points = Math.round(parseFloat(item.Points)).toLocaleString();
            if (isIndividual) {
                html += `<tr class="${rowClass}" data-username="${item.Username || ''}" style="cursor: pointer;">${rankChangeCellHtml}<td class="table-cell table-cell--place tac">${medalHTML}</td>`;
                const teamTag = item.TeamTag || '--';
                const displayName = item.CurrentDisplayName || item.Username;
                const tagColor = item.tagColor || 'fff';
                const isGold = item.membership === 'gold';
                const carImage = getCarImage(item.carID || 1, item.carHueAngle);
                const title = item.title || 'Untitled';
                html += `
                    <td class="table-cell table-cell--racer">
                        <div class="bucket bucket--s bucket--c">
                            <div class="bucket-media bucket-media--w90"><img class="db" src="${carImage}"></div>
                            <div class="bucket-content">
                                <div class="df df--align-center">
                                    ${isGold ? '<div class="prxxs"><img alt="NT Gold" class="icon icon-nt-gold-s" src="https://www.nitrotype.com/dist/site/images/themes/profiles/gold/nt-gold-icon.png"></div>' : ''}
                                    <div class="prxs df df--align-center" title="${displayName}">
                                        <a href="https://www.nitrotype.com/team/${teamTag}" class="link link--bare mrxxs twb" style="color: #${tagColor};">[${teamTag}]</a>
                                        <span class="type-ellip ${isGold ? 'type-gold' : ''} tss">${displayName}</span>
                                    </div>
                                </div>
                                <div class="tsxs tc-fuel tsi db">"${title}"</div>
                            </div>
                        </div>
                    </td>
                    <td class="table-cell table-cell--speed">${wpm}</td>
                    <td class="table-cell table-cell--races">${acc}%</td>
                    <td class="table-cell table-cell--races">${item.Races}</td>
                    <td class="table-cell table-cell--points">${points}</td>
                `;
            } else {
                const teamTag = item.TeamTag || '----';
                const teamName = item.TeamName || `${teamTag} Team`;
                const tagColor = item.tagColor || 'B3C8DD';
                html += `<tr class="${rowClass}" data-teamtag="${item.TeamTag || ''}" style="cursor: pointer;">${rankChangeCellHtml}<td class="table-cell table-cell--place tac">${medalHTML}</td>`;
                html += `
                    <td class="table-cell table-cell--tag"><span class="twb" style="color: #${tagColor};">[${teamTag}]</span></td>
                    <td class="table-cell table-cell--team"><span class="tc-lemon">"${teamName}"</span></td>
                    <td class="table-cell table-cell--speed">${wpm}</td>
                    <td class="table-cell table-cell--races">${acc}%</td>
                    <td class="table-cell table-cell--races">${item.Races}</td>
                    <td class="table-cell table-cell--points">${points}</td>
                `;
            }
            html += '</tr>';
        });
        html += '</tbody></table>';
        container.innerHTML = html;
        if (isIndividual) {
            document.querySelectorAll('.table-row[data-username]').forEach(row => {
                row.addEventListener('click', (e) => {
                    if (!e.target.closest('a[href*="/team/"]')) window.location.href = `https://www.nitrotype.com/racer/${row.dataset.username}`;
                });
            });
        } else {
            document.querySelectorAll('.table-row[data-teamtag]').forEach(row => {
                row.addEventListener('click', () => window.location.href = `https://www.nitrotype.com/team/${row.dataset.teamtag}`);
            });
        }
        const cacheKey = getCacheKey();
        let timeToDisplay = specificTime || localStorage.getItem(CACHE_TIMESTAMP_KEY + cacheKey);
        if (!timeToDisplay) timeToDisplay = Date.now().toString();
        const updateTime = new Date(parseInt(timeToDisplay));
        setIndicator(`Last updated: ${updateTime.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })}`, false);
        if (!initialCacheComplete && !isCaching) {
            initialCacheComplete = true;
            isCaching = true;
            setTimeout(() => { populateCacheQueue(); cacheAllViews(); }, 1000);
        }
    }
    function updateDateDisplay() {
        const titleEl = document.getElementById('date-title');
        const rangeEl = document.getElementById('date-range');
        if (!titleEl || !rangeEl) return;
        const ranges = calculateDateRange(state);
        const hasRange = !!(ranges && ranges.start && ranges.end);
        const start = hasRange ? new Date(ranges.start.replace(' ', 'T')) : null;
        const end = hasRange ? new Date(ranges.end.replace(' ', 'T')) : null;
        if (state.timeframe === 'season') {
            // Use dynamic season name and dates
            titleEl.textContent = currentSeason.name || 'Season';
            const seasonDates = getSeasonDisplayDates();
            rangeEl.textContent = `${seasonDates.startDisplay} - ${seasonDates.endDisplay}`;
        }
        else if (state.timeframe === 'daily') { titleEl.textContent = 'Daily'; rangeEl.textContent = start ? start.toLocaleDateString() : 'Loading...'; }
        else if (state.timeframe === 'weekly') { titleEl.textContent = 'Weekly'; rangeEl.textContent = (start && end) ? `${start.toLocaleDateString()} - ${end.toLocaleDateString()}` : 'Loading...'; }
        else if (state.timeframe === 'monthly') { titleEl.textContent = 'Monthly'; rangeEl.textContent = start ? start.toLocaleDateString(undefined, { month: 'long', year: 'numeric' }) : 'Loading...'; }
        else if (state.timeframe === 'custom') { titleEl.textContent = 'Custom Range'; rangeEl.textContent = (start && end) ? `${start.toLocaleDateString()} - ${end.toLocaleDateString()}` : 'Loading...'; }
        else { titleEl.textContent = timeframes.find(t => t.key === state.timeframe)?.label || 'Leaderboards'; rangeEl.textContent = ''; }
    }
    function populateCacheQueue(options = {}) {
        cacheQueue = [];
        const views = options.views || ['individual', 'team'];
        const currentCT = getCurrentCT();
        const now = getCurrentCT();
        now.setMinutes(0, 0, 0);
        const timeframesFilter = Array.isArray(options.timeframes) ? new Set(options.timeframes) : null;
        const includeNav = options.includeNav !== false;
        const includeCurrent = options.includeCurrent === true ||
            (options.includeCurrent === undefined && location.pathname !== LEADERBOARD_PATH);
        const shouldInclude = (key) => !timeframesFilter || timeframesFilter.has(key);
        const priorityTimeframes = ['season', '24hr', '60min', '7day'];
        const prioritySet = new Set(priorityTimeframes);
        // Always fetch Season first: individual -> team
        if (shouldInclude('season')) {
            if (hasValidSeasonData()) {
                cacheQueue.push({ view: 'individual', timeframe: 'season', currentDate: now });
                cacheQueue.push({ view: 'team', timeframe: 'season', currentDate: now });
            } else {
                debugLog('Season queue skipped (metadata unavailable)', {
                    reason: options.reason || 'unknown',
                    targetTimeframe: 'season'
                });
            }
        }
        timeframes
            .filter(t => prioritySet.has(t.key) && t.key !== 'season' && shouldInclude(t.key))
            .forEach(tf => {
                views.forEach(view => cacheQueue.push({ view: view, timeframe: tf.key, currentDate: now }));
            });
        if (includeNav) {
            const dynamicTFs = timeframes.filter(t => t.hasNav && shouldInclude(t.key));
            views.forEach(view => {
                dynamicTFs.forEach(tf => {
                    let date = new Date(currentCT.getFullYear(), currentCT.getMonth(), currentCT.getDate());
                    cacheQueue.push({ view: view, timeframe: tf.key, currentDate: date });
                });
            });
        }
        if (!includeCurrent) {
            const currentKey = getCacheKey();
            cacheQueue = cacheQueue.filter(item => getCacheKey(item) !== currentKey);
        }
        debugLog('Cache queue prepared', {
            reason: options.reason || 'unknown',
            includeNav: includeNav,
            includeCurrent: includeCurrent,
            force: options.force === true,
            count: cacheQueue.length,
            order: cacheQueue.map(item => `${item.view}:${item.timeframe}`),
            targetTimeframe: cacheQueue[0]?.timeframe || null
        });
    }
    function cacheAllViews() {
        try {
            if (cacheQueue.length === 0) {
                debugLog('Cache queue drained', { reason: 'complete' });
                isCaching = false;
                forceBackgroundUpdate = false;
                return;
            }
            const nextItem = cacheQueue.shift();
            const nextKey = getCacheKey(nextItem);
            const ttl = getCacheTTLForTimeframe(nextItem.timeframe);
            const scheduleNext = () => setTimeout(cacheAllViews, BACKGROUND_SYNC_DELAY_MS);
            const freshness = getCacheFreshness(nextKey, ttl);
            if (!forceBackgroundUpdate && localStorage.getItem(nextKey) && isCacheFresh(nextKey, ttl)) {
                debugLog('Cache queue item skipped (fresh cache)', {
                    view: nextItem.view,
                    timeframe: nextItem.timeframe,
                    key: shortCacheKey(nextKey),
                    ageMs: freshness.ageMs,
                    ttlMs: ttl,
                    queueRemaining: cacheQueue.length,
                    targetTimeframe: nextItem.timeframe
                });
                scheduleNext();
                return;
            }
            debugLog('Cache queue item fetching', {
                view: nextItem.view,
                timeframe: nextItem.timeframe,
                key: shortCacheKey(nextKey),
                forceBackgroundUpdate: forceBackgroundUpdate,
                ageMs: freshness.ageMs,
                ttlMs: ttl,
                queueRemaining: cacheQueue.length,
                targetTimeframe: nextItem.timeframe
            });
            fetchFreshData(nextKey, nextItem.view, nextItem.timeframe, nextItem.currentDate, scheduleNext);
        } catch (error) {
            console.error('Error in cache queue:', error);
            debugLog('Cache queue error', { message: error && error.message ? error.message : String(error) });
            isCaching = false;
            forceBackgroundUpdate = false;
        }
    }
    function startBackgroundSync(reason, options = {}) {
        try {
            loadSeasonData();
            if (isCaching) {
                debugLog('Background sync skipped (already running)', { reason: reason });
                return false;
            }
            forceBackgroundUpdate = options.force === true;
            populateCacheQueue({ ...options, reason: reason });
            isCaching = true;
            cacheAllViews();
            debugLog('Background sync started', {
                reason: reason,
                force: forceBackgroundUpdate,
                options: options
            });
            return true;
        } catch (error) {
            console.error('[Startrack] Background sync failed to start:', error);
            debugLog('Background sync failed', {
                reason: reason,
                message: error && error.message ? error.message : String(error)
            });
            return false;
        }
    }
    function maybeStartDailyBackgroundSync() {
        try {
            const todayKey = getCTDateKey();
            const lastKey = localStorage.getItem(DAILY_SYNC_KEY);
            if (lastKey === todayKey) {
                debugLog('Daily sync skipped (already ran for CT day)', {
                    todayKey: todayKey,
                    lastKey: lastKey,
                    targetTimeframe: 'season'
                });
                return;
            }
            if (startBackgroundSync('daily', { includeCurrent: true })) {
                localStorage.setItem(DAILY_SYNC_KEY, todayKey);
                debugLog('Daily sync marker updated', {
                    todayKey: todayKey,
                    targetTimeframe: 'season'
                });
            }
        } catch (error) {
            console.warn('[Startrack] Daily sync check failed:', error);
            debugLog('Daily sync error', {
                message: error && error.message ? error.message : String(error),
                targetTimeframe: 'season'
            });
        }
    }
    function maybeStartHourlyBackgroundSync() {
        try {
            const hourKey = getCTHourKey();
            const lastKey = localStorage.getItem(HOURLY_SYNC_KEY);
            if (lastKey === hourKey) {
                debugLog('Hourly sync skipped (already ran for CT hour)', {
                    hourKey: hourKey,
                    lastKey: lastKey,
                    targetTimeframe: 'season'
                });
                return;
            }
            const started = startBackgroundSync('hourly', {
                timeframes: ['season', '60min', '24hr'],
                includeNav: false,
                includeCurrent: true,
                force: true
            });
            if (started) {
                localStorage.setItem(HOURLY_SYNC_KEY, hourKey);
                debugLog('Hourly sync marker updated', {
                    hourKey: hourKey,
                    targetTimeframe: 'season'
                });
            }
        } catch (error) {
            console.warn('[Startrack] Hourly sync check failed:', error);
            debugLog('Hourly sync error', {
                message: error && error.message ? error.message : String(error),
                targetTimeframe: 'season'
            });
        }
    }
    function startGlobalCacheMaintenance() {
        if (window.__ntGlobalCacheInterval) return;
        window.__ntGlobalCacheInterval = setInterval(() => {
            maybeStartDailyBackgroundSync();
            maybeStartHourlyBackgroundSync();
        }, 60000);
    }
    function stopGlobalCacheMaintenance() {
        if (!window.__ntGlobalCacheInterval) return;
        clearInterval(window.__ntGlobalCacheInterval);
        window.__ntGlobalCacheInterval = null;
    }
    function syncBackgroundWorkToRoute() {
        maybeStartDailyBackgroundSync();
        maybeStartHourlyBackgroundSync();
        startGlobalCacheMaintenance();
    }
    function initDebugAPI() {
        const debugApi = {
            enable: function() {
                localStorage.setItem(DEBUG_FLAG_KEY, '1');
                console.log('[Startrack][DBG] Enabled. Reload the page to start logging.');
            },
            disable: function() {
                localStorage.removeItem(DEBUG_FLAG_KEY);
                localStorage.removeItem(DEBUG_SEASON_ONLY_KEY);
                console.log('[Startrack][DBG] Disabled. Reload the page to stop logging.');
            },
            seasonOnly: function(enabled = true) {
                if (enabled) localStorage.setItem(DEBUG_SEASON_ONLY_KEY, '1');
                else localStorage.removeItem(DEBUG_SEASON_ONLY_KEY);
                console.log(`[Startrack][DBG] seasonOnly=${enabled ? 'ON' : 'OFF'}. Reload the page to apply.`);
            },
            status: function() {
                const status = {
                    debugEnabled: DEBUG_ENABLED,
                    debugSeasonOnly: DEBUG_SEASON_ONLY,
                    debugParamEnabled: DEBUG_PARAM_ENABLED,
                    currentState: { view: state.view, timeframe: state.timeframe },
                    ctDateKey: getCTDateKey(),
                    ctHourKey: getCTHourKey(),
                    lastDailySyncKey: localStorage.getItem(DAILY_SYNC_KEY),
                    lastHourlySyncKey: localStorage.getItem(HOURLY_SYNC_KEY),
                    seasonName: currentSeason.name,
                    seasonStartUTC: currentSeason.startStampUTC,
                    seasonEndUTC: currentSeason.endStampUTC
                };
                console.log('[Startrack][DBG] Status', status);
                return status;
            },
            inspect: function(view = 'individual', timeframe = 'season') {
                const tempState = { view: view, timeframe: timeframe, currentDate: getCurrentCT() };
                const key = getCacheKey(tempState);
                const ttl = getCacheTTLForTimeframe(timeframe);
                const freshness = getCacheFreshness(key, ttl);
                const result = {
                    view: view,
                    timeframe: timeframe,
                    key: shortCacheKey(key),
                    hasData: !!localStorage.getItem(key),
                    hasTimestamp: freshness.hasTimestamp,
                    ageMs: freshness.ageMs,
                    ttlMs: freshness.ttlMs,
                    fresh: freshness.fresh
                };
                console.log('[Startrack][DBG] Inspect', result);
                return result;
            }
        };
        window.NTStartrackDebug = debugApi;
        if (typeof unsafeWindow !== 'undefined' && unsafeWindow) {
            unsafeWindow.NTStartrackDebug = debugApi;
        }
        if (DEBUG_ENABLED) {
            console.log(`[Startrack][DBG] Enabled${DEBUG_SEASON_ONLY ? ' (season-only)' : ''}. API: window.NTStartrackDebug.status(), .inspect(), .seasonOnly(), .disable()`);
        }
    }
    function fetchLeaderboardData(forceRefresh = false) {
        if (state.timeframe === 'season' && !hasValidSeasonData()) {
            loadSeasonData();
            debugLog('Leaderboard fetch deferred (season metadata unavailable)', {
                view: state.view,
                timeframe: state.timeframe,
                forceRefresh: forceRefresh,
                stateTimeframe: state.timeframe
            });
            updateDateDisplay();
            setIndicator('Season metadata loading...', true);
            const container = document.getElementById('leaderboard-table-container');
            if (container) {
                container.innerHTML = `<div class="tac pxl mtl"><div class="loading-spinner loading-spinner--ts" style="margin: 0 auto;"></div><div class="mtm">Loading season metadata...</div></div>`;
            }
            return;
        }
        const cacheKey = getCacheKey();
        const ttl = getCacheTTLForTimeframe(state.timeframe);
        const freshness = getCacheFreshness(cacheKey, ttl);
        debugLog('Leaderboard fetch start', {
            view: state.view,
            timeframe: state.timeframe,
            forceRefresh: forceRefresh,
            key: shortCacheKey(cacheKey),
            hasLocalStorage: !!localStorage.getItem(cacheKey),
            hasTimestamp: freshness.hasTimestamp,
            ageMs: freshness.ageMs,
            ttlMs: ttl,
            freshByTimestamp: freshness.fresh,
            stateTimeframe: state.timeframe
        });
        // Check RAM cache first (now properly keyed)
        if (window.NTShared && window.NTShared.getCache && !forceRefresh) {
            const sharedData = window.NTShared.getCache(cacheKey);
            if (sharedData) {
                debugLog('Leaderboard served from RAM cache', {
                    view: state.view,
                    timeframe: state.timeframe,
                    key: shortCacheKey(cacheKey),
                    count: Array.isArray(sharedData) ? sharedData.length : null,
                    stateTimeframe: state.timeframe
                });
                updateDateDisplay();
                const sharedTS = window.NTShared.getTimestamp(cacheKey);
                renderTable(sharedData, sharedTS);
                return;
            }
        }
        // Check localStorage cache
        const cachedData = localStorage.getItem(cacheKey);
        updateDateDisplay();
        if (cachedData) {
            try {
                const data = JSON.parse(cachedData);
                renderTable(data);
                if (isCacheFresh(cacheKey, ttl) && !forceRefresh) {
                    debugLog('Leaderboard served from localStorage cache', {
                        view: state.view,
                        timeframe: state.timeframe,
                        key: shortCacheKey(cacheKey),
                        count: Array.isArray(data) ? data.length : null,
                        ageMs: freshness.ageMs,
                        ttlMs: ttl,
                        stateTimeframe: state.timeframe
                    });
                    return;
                }
                debugLog('Leaderboard localStorage cache stale, revalidating', {
                    view: state.view,
                    timeframe: state.timeframe,
                    key: shortCacheKey(cacheKey),
                    ageMs: freshness.ageMs,
                    ttlMs: ttl,
                    stateTimeframe: state.timeframe
                });
                setIndicator('Updating...', true);
                fetchFreshData(cacheKey);
                return;
            }
            catch (e) {
                debugLog('Leaderboard cache parse failed', {
                    key: shortCacheKey(cacheKey),
                    message: e && e.message ? e.message : String(e),
                    stateTimeframe: state.timeframe
                });
                localStorage.removeItem(cacheKey);
            }
        }
        debugLog('Leaderboard cache miss, fetching network', {
            view: state.view,
            timeframe: state.timeframe,
            key: shortCacheKey(cacheKey),
            stateTimeframe: state.timeframe
        });
        const container = document.getElementById('leaderboard-table-container');
        if (container) container.innerHTML = `<div class="tac pxl mtl"><div class="loading-spinner loading-spinner--ts" style="margin: 0 auto;"></div><div class="mtm">Loading data...</div></div>`;
        setIndicator('Updating...', true);
        fetchFreshData(cacheKey);
    }
    function fetchFreshData(cacheKey, view = state.view, timeframe = state.timeframe, currentDate = state.currentDate, callback) {
        const tempState = { view, timeframe, currentDate };
        const requestStartedAt = Date.now();
        let ranges = calculateDateRange(tempState);
        if (!ranges || !ranges.start || !ranges.end) {
            debugLog('Network fetch skipped (missing date range)', {
                view: view,
                timeframe: timeframe,
                key: shortCacheKey(cacheKey),
                stateTimeframe: state.timeframe
            });
            if (view === state.view && timeframe === state.timeframe) {
                setIndicator('Season metadata loading...', true);
            }
            if (callback) callback();
            return;
        }
        if (['60min', '24hr', '7day'].includes(timeframe)) {
            const roundToHour = (d) => { const date = new Date(d.replace(' ', 'T')); date.setMinutes(0, 0, 0); return formatDate(date); };
            ranges = { start: roundToHour(ranges.start), end: roundToHour(ranges.end) };
        }
        const apiUrl = view === 'individual' ? 'https://ntstartrack.org/api/individual-leaderboard' : 'https://ntstartrack.org/api/team-leaderboard';
        const url = `${apiUrl}?start_time=${encodeURIComponent(ranges.start)}&end_time=${encodeURIComponent(ranges.end)}&showbot=FALSE&include_position_change=true&cb=${new Date().getTime()}`;
        debugLog('Network fetch start', {
            view: view,
            timeframe: timeframe,
            key: shortCacheKey(cacheKey),
            start: ranges.start,
            end: ranges.end,
            url: url,
            stateTimeframe: state.timeframe
        });
        if (view === state.view && timeframe === state.timeframe) setIndicator('Updating...', true);
        GM_xmlhttpRequest({
            method: 'GET',
            url: url,
            onload: function(response) {
                if (response.status === 200) {
                    setTimeout(() => {
                        try {
                            if (!response.responseText || response.responseText.trim().length === 0) throw new Error('Empty');
                            let data = JSON.parse(response.responseText);
                            if (!Array.isArray(data)) throw new Error('Invalid format');
                            data = sanitizeLeaderboardRows(view, data);
                            const now = Date.now();
                            const ttl = getCacheTTLForTimeframe(timeframe);
                            const legacyLimit = view === 'individual' ? 300 : 50;
                            const legacyData = data.slice(0, legacyLimit);
                            const top100 = data.slice(0, 100);
                            saveToCache(cacheKey, JSON.stringify(top100));
                            // Save to RAM cache with proper key
                            if (window.NTShared && window.NTShared.setCache) {
                                window.NTShared.setCache(cacheKey, top100, now + ttl);
                            }
                            // Provide legacy 7-day cache for badge scripts
                            if (timeframe === '7day' && window.NTShared && window.NTShared.setLegacyCache) {
                                window.NTShared.setLegacyCache(view, legacyData, now + ttl);
                            }
                            if (timeframe === '7day') {
                                const sharedCacheKey = getSharedCacheKey(tempState);
                                const sharedPayload = buildSharedLeaderboardPayload(view, timeframe, legacyData, now, now + ttl);
                                if (window.NTShared && window.NTShared.setCache) {
                                    window.NTShared.setCache(sharedCacheKey, sharedPayload, sharedPayload.expiresAt);
                                }
                                saveSharedPayloadToLocalStorage(sharedCacheKey, sharedPayload);
                            }
                            debugLog('Network fetch success', {
                                view: view,
                                timeframe: timeframe,
                                key: shortCacheKey(cacheKey),
                                status: response.status,
                                rows: data.length,
                                renderedRows: top100.length,
                                elapsedMs: Date.now() - requestStartedAt,
                                ttlMs: ttl,
                                stateTimeframe: state.timeframe
                            });
                            if (view === state.view && timeframe === state.timeframe) renderTable(data, now);
                            if (callback) callback();
                        } catch (e) {
                            console.error(e);
                            debugLog('Network fetch parse/render error', {
                                view: view,
                                timeframe: timeframe,
                                key: shortCacheKey(cacheKey),
                                message: e && e.message ? e.message : String(e),
                                elapsedMs: Date.now() - requestStartedAt,
                                stateTimeframe: state.timeframe
                            });
                            if (view === state.view && timeframe === state.timeframe) {
                                setIndicator(`Update failed`, false);
                                document.documentElement.classList.remove('is-leaderboard-route');
                                const main = document.querySelector('main.structure-content');
                                if (main) main.classList.remove('custom-loaded');
                            }
                            if (callback) callback();
                        }
                    }, ASYNC_DELAY);
                } else {
                    debugLog('Network fetch failed status', {
                        view: view,
                        timeframe: timeframe,
                        key: shortCacheKey(cacheKey),
                        status: response.status,
                        elapsedMs: Date.now() - requestStartedAt,
                        stateTimeframe: state.timeframe
                    });
                    if (view === state.view && timeframe === state.timeframe) {
                        setIndicator(`Update failed`, false);
                        document.documentElement.classList.remove('is-leaderboard-route');
                        const main = document.querySelector('main.structure-content');
                        if (main) main.classList.remove('custom-loaded');
                    }
                    if (callback) callback();
                }
            },
            onerror: function() {
                debugLog('Network fetch transport error', {
                    view: view,
                    timeframe: timeframe,
                    key: shortCacheKey(cacheKey),
                    elapsedMs: Date.now() - requestStartedAt,
                    stateTimeframe: state.timeframe
                });
                if (view === state.view && timeframe === state.timeframe) {
                    setIndicator('Update failed', false);
                    document.documentElement.classList.remove('is-leaderboard-route');
                    const main = document.querySelector('main.structure-content');
                    if (main) main.classList.remove('custom-loaded');
                }
                if (callback) callback();
            }
        });
    }
    function attachListeners() {
        document.querySelectorAll('[data-view]').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const view = e.currentTarget.dataset.view;
                if (state.view !== view) { state.view = view; fetchLeaderboardData(false); }
            });
        });
        document.querySelectorAll('[data-timeframe]').forEach(btn => {
            btn.addEventListener('click', (e) => {
                const tf = e.currentTarget.dataset.timeframe;
                if (state.timeframe !== tf) { state.timeframe = tf; state.currentDate = getCurrentCT(); fetchLeaderboardData(false); }
            });
        });
        document.getElementById('nav-prev')?.addEventListener('click', () => navigateDate(-1));
        document.getElementById('nav-next')?.addEventListener('click', () => navigateDate(1));
        document.getElementById('nav-today')?.addEventListener('click', () => { state.currentDate = getCurrentCT(); fetchLeaderboardData(true); });
        const refreshBtn = document.getElementById('manual-refresh-btn');
        if (refreshBtn) {
            refreshBtn.addEventListener('click', (e) => {
                const icon = e.currentTarget.querySelector('svg');
                if(icon) icon.classList.add('icon-spin');
                fetchLeaderboardData(true);
                debugLog('Manual refresh requested full background sync', {
                    reason: 'manual-refresh-button'
                });
                forceBackgroundUpdate = true;
                populateCacheQueue();
                if (!isCaching) {
                    isCaching = true;
                    cacheAllViews();
                }
            });
        }
        document.getElementById('update-custom')?.addEventListener('click', () => {
            const startVal = document.getElementById('start-date')?.value;
            const endVal = document.getElementById('end-date')?.value;
            if (startVal && endVal) {
                state.dateRange.start = getStartOfDay(new Date(startVal + 'T00:00:00'));
                state.dateRange.end = getEndOfDay(new Date(endVal + 'T00:00:00'));
                fetchLeaderboardData(true);
            }
        });
    }
    function renderLeaderboardPage(forceRefresh = false) {
        if (pageRenderInProgress) return;
        pageRenderInProgress = true;
        const mainContent = document.querySelector('main.structure-content');
        if (!mainContent) {
            pageRenderInProgress = false;
            return;
        }
        try {
            // Load season data first (this can use NTBOOTSTRAP or cache)
            loadSeasonData();
            // Build HTML immediately
            mainContent.innerHTML = buildLeaderboardHTML();
            requestAnimationFrame(() => { mainContent.classList.add('custom-loaded'); });
            attachListeners();
            setActiveTab();
            setTabTitle();
            startHourlyCheck();
            // Defer car loading with retry mechanism
            loadCarData((success) => {
                if (success) {
                    debugLog('Car data ready, fetching leaderboard', { success: true });
                }
                // Fetch leaderboard data after car data is loaded (or failed)
                fetchLeaderboardData(forceRefresh);
            });
        } catch (error) {
            console.error('Error rendering leaderboard page:', error);
            document.documentElement.classList.remove('is-leaderboard-route');
            if (mainContent) mainContent.classList.remove('custom-loaded');
        } finally {
            pageRenderInProgress = false;
        }
    }
    function setActiveTab() {
        document.querySelectorAll('.nav-list-item').forEach(li => li.classList.remove('is-current'));
        const tab = document.querySelector('.' + TAB_CLASS);
        if (tab) tab.classList.add('is-current');
    }
    function setTabTitle() {
        if (window.location.pathname === LEADERBOARD_PATH) document.title = 'Leaderboards | Nitro Type';
    }
    function insertLeaderboardDropdownLink() {
        if (!isNtcfgLeaderboardsFeatureEnabled('SHOW_DROPDOWN_LINK')) return;
        // Don't duplicate
        if (document.querySelector('.ntcfg-leaderboards-dropdown-item')) return;
        const dropdown = document.querySelector('.dropdown--account .dropdown-items');
        if (!dropdown) return;
        // Insert above "My Public Profile" (icon-eye), or fall back to end of list
        const profileItem = Array.from(dropdown.querySelectorAll('.dropdown-item')).find(
            li => li.querySelector('a[href*="/racer/"]')
        );
        const li = document.createElement('li');
        li.className = 'list-item dropdown-item ntcfg-leaderboards-dropdown-item';
        if (location.pathname === LEADERBOARD_PATH) li.classList.add('is-current');
        li.innerHTML = `<a class="dropdown-link" href="${LEADERBOARD_PATH}"><svg class="icon icon-trophy mrxs" style="width:16px;height:16px;vertical-align:middle;"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/site/images/icons/icons.css.svg#icon-trophy"></use></svg>Leaderboards</a>`;
        if (profileItem) {
            profileItem.before(li);
        } else {
            dropdown.appendChild(li);
        }
    }
    function removeLeaderboardDropdownLink() {
        document.querySelectorAll('.ntcfg-leaderboards-dropdown-item').forEach((el) => el.remove());
    }
    function insertLeaderboardTab() {
        if (!isNtcfgLeaderboardsFeatureEnabled('SHOW_ROUTE_TAB')) return;
        if (document.querySelector(`a[href="${LEADERBOARD_PATH}"]`)) return;
        const navList = document.querySelector('.nav-list');
        if (!navList) return;
        const li = document.createElement('li');
        li.className = `nav-list-item ${TAB_CLASS}`;
        li.innerHTML = `<a href="${LEADERBOARD_PATH}" class="nav-link"><span class="has-notify">Leaderboards</span></a>`;
        const news = Array.from(navList.children).find(li => li.textContent.trim().includes('News'));
        if (news) news.before(li);
        else navList.appendChild(li);
    }
    function removeLeaderboardTab() {
        document.querySelectorAll('.' + TAB_CLASS).forEach((el) => el.remove());
    }
    function rerenderLeaderboardPageFromSettings() {
        if (location.pathname === LEADERBOARD_PATH) {
            renderLeaderboardPage(true);
        }
    }
    function applyLeaderboardsSettingSideEffects(settingKey) {
        if (!settingKey) return;
        if (settingKey === 'HIDE_CLASS_TAB') {
            syncHideClassTabState();
            return;
        }
        if (settingKey === 'SHOW_ROUTE_TAB') {
            if (isNtcfgLeaderboardsFeatureEnabled('SHOW_ROUTE_TAB')) insertLeaderboardTab();
            else removeLeaderboardTab();
            return;
        }
        if (settingKey === 'SHOW_DROPDOWN_LINK') {
            if (isNtcfgLeaderboardsFeatureEnabled('SHOW_DROPDOWN_LINK')) insertLeaderboardDropdownLink();
            else removeLeaderboardDropdownLink();
            return;
        }
        if (settingKey === 'SHOW_MANUAL_REFRESH' || settingKey === 'HIGHLIGHT_POSITION_CHANGE') {
            rerenderLeaderboardPageFromSettings();
        }
    }
    function applyAllLeaderboardsSettingSideEffects() {
        syncHideClassTabState();
        if (isNtcfgLeaderboardsFeatureEnabled('SHOW_ROUTE_TAB')) insertLeaderboardTab();
        else removeLeaderboardTab();
        if (isNtcfgLeaderboardsFeatureEnabled('SHOW_DROPDOWN_LINK')) insertLeaderboardDropdownLink();
        else removeLeaderboardDropdownLink();
        rerenderLeaderboardPageFromSettings();
    }
    function handlePage() {
        insertLeaderboardTab();
        insertLeaderboardDropdownLink();
        if (location.pathname === LEADERBOARD_PATH) {
            if (document.getElementById('leaderboard-table-container')) { setActiveTab(); return; }
            const main = document.querySelector('main.structure-content');
            if (main && (main.children.length === 0 || main.querySelector('.error'))) renderLeaderboardPage();
        } else {
            document.querySelector('.' + TAB_CLASS)?.classList.remove('is-current');
            stopHourlyCheck();
        }
    }
    function fastInject() {
        insertLeaderboardTab();
        insertLeaderboardDropdownLink();
        if (location.pathname === LEADERBOARD_PATH) {
            const waitForMain = new MutationObserver(() => {
                const main = document.querySelector('main.structure-content');
                if (main) {
                    if (main.children.length === 0 || main.querySelector('.error') || main.textContent.includes("Page Not Found")) {
                         renderLeaderboardPage();
                         waitForMain.disconnect();
                    }
                }
            });
            waitForMain.observe(document.documentElement, { childList: true, subtree: true });
        }
    }
    initDebugAPI();
    ntRouteHelper.subscribe(() => {
        updateRouteStatus();
        syncBackgroundWorkToRoute();
        handlePage();
    }, { immediate: false });
    fastInject();
    syncBackgroundWorkToRoute();
    handlePage();
    const navObserver = new MutationObserver((mutations) => {
        if (!document.querySelector(`a[href="${LEADERBOARD_PATH}"]`)) {
            insertLeaderboardTab();
            insertLeaderboardDropdownLink();
        }
        if (location.pathname === LEADERBOARD_PATH) {
            const main = document.querySelector('main.structure-content');
            if (main && (main.children.length === 0 || main.querySelector('.error') || main.textContent.includes("Page Not Found"))) {
                if (!main.classList.contains('custom-loaded')) {
                    renderLeaderboardPage();
                }
            }
        }
        handlePage();
    });
    navObserver.observe(document.documentElement, { childList: true, subtree: true });
})();