Nitro Type - Toolkit

Quality-of-life utilities: shop leaks, keyboard shortcuts & more.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Nitro Type - Toolkit
// @namespace    https://nitrotype.info
// @version      3.0.1
// @description  Quality-of-life utilities: shop leaks, keyboard shortcuts & more.
// @author       Captain.Loveridge
// @icon         https://nitrotype.info/assets/icons/nitro-type-mod-suite.png
// @match        https://www.nitrotype.com/*
// @match        *://*.nitrotype.com/settings/mods*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        unsafeWindow
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // ─── Singleton Guard ─────────────────────────────────────────────────────────
    const pageWindow = (typeof unsafeWindow !== 'undefined' && unsafeWindow) ? unsafeWindow : window;
    const SCRIPT_SINGLETON_KEY = '__ntToolkitSingleton';
    if (pageWindow[SCRIPT_SINGLETON_KEY]) {
        try { console.info('[TOOLKIT] Duplicate instance detected; skipping.'); } catch (e) { }
        return;
    }
    pageWindow[SCRIPT_SINGLETON_KEY] = true;

    // ─── Constants ───────────────────────────────────────────────────────────────
    const TOOLKIT_LOG_PREFIX = '[TOOLKIT]';
    const NTCFG_MANIFEST_ID = 'toolkit';
    const NTCFG_MANIFEST_KEY = `ntcfg:manifest:${NTCFG_MANIFEST_ID}`;
    const NTCFG_VALUE_PREFIX = `ntcfg:${NTCFG_MANIFEST_ID}:`;
    const NTCFG_BRIDGE_VERSION = '1.0.0-bridge.1';
    const SETTINGS_STORAGE_VERSION = 2;
    const STORAGE_VERSION_KEY = `${NTCFG_VALUE_PREFIX}__storage_version`;
    const STORAGE_MIGRATED_AT_KEY = `${NTCFG_VALUE_PREFIX}__migrated_at`;
    const STORAGE_CLEANUP_AFTER_KEY = `${NTCFG_VALUE_PREFIX}__cleanup_after`;
    const LEGACY_CLEANUP_GRACE_MS = 30 * 24 * 60 * 60 * 1000;
    const EARLY_CASH_GIFT_STYLE_ID = 'toolkit-early-cash-gift-style';
    const EARLY_CASH_MASK_STYLE_ID = 'toolkit-early-cash-mask-style';
    const EARLY_FRIEND_REQUEST_STYLE_ID = 'toolkit-early-friend-request-style';
    const EARLY_FRIEND_ONLINE_STYLE_ID = 'toolkit-early-friend-online-style';
    const EARLY_RACE_INVITE_STYLE_ID = 'toolkit-early-race-invite-style';
    const EARLY_HIDE_ADS_STYLE_ID = 'toolkit-early-hide-ads-style';
    const CLEAR_NOTIFICATIONS_ATTR = 'data-ntk-clear-notifications-hidden';
    const CLEAR_NOTIFICATIONS_DISPLAY_ATTR = 'data-ntk-clear-notifications-display';
    const HIDE_ADS_STORAGE_KEY = `${NTCFG_VALUE_PREFIX}HIDE_ADS`;
    const HIDE_ADS_BOOTSTRAP_CSS = [
        '.ad, .profile-ad, .structure-leaderboard.ad--container--side, .ad--side-extra, .ad--container, .news-ads { display: none !important; }',
        '.structure.structure--nitrotype { grid-template-columns: [spacer-start] minmax(0, 1fr) [main-start] 1024px [end] minmax(0, 1fr) !important; }'
    ].join('\n');
    const HIDE_FRIEND_ONLINE_POPUP_CSS = [
        '.notification--friend-online { display: none !important; }',
        '.notification--friend-online--info { display: none !important; }',
        '.growl:has(.notification--friend-online--info) { display: none !important; }',
        '.notification:has(.notification--friend-online--info) { display: none !important; }'
    ].join('\n');

    const readBootstrapBoolean = (storageKey, fallback = false) => {
        try {
            if (typeof GM_getValue === 'function') {
                const gmValue = GM_getValue(storageKey);
                if (gmValue !== undefined) return !!gmValue;
            }
        } catch { /* ignore */ }
        try {
            const raw = localStorage.getItem(storageKey);
            if (raw != null) return !!JSON.parse(raw);
        } catch { /* ignore */ }
        return fallback;
    };

    const bootstrapHideAdsStyle = () => {
        if (!readBootstrapBoolean(HIDE_ADS_STORAGE_KEY, false)) return;
        if (document.getElementById(EARLY_HIDE_ADS_STYLE_ID)) return;
        const style = document.createElement('style');
        style.id = EARLY_HIDE_ADS_STYLE_ID;
        style.textContent = HIDE_ADS_BOOTSTRAP_CSS;
        (document.head || document.documentElement).appendChild(style);
    };

    bootstrapHideAdsStyle();

    // ─── Shared Settings (Mod Menu Manifest) ─────────────────────────────────────
    // /profile is a special path that resolves to the current user's racer page
    // /team auto-redirects to the user's team on NT's side
    // Bump SHORTCUTS_VERSION when adding new defaults — triggers auto-merge for existing users.
    const SHORTCUTS_VERSION = 3;
    const SHORTCUTS_VERSION_KEY = `${NTCFG_VALUE_PREFIX}__shortcuts_version`;
    const SHORTCUT_CODE_TO_KEY = Object.freeze({
        Backquote: '`',
        Minus: '-',
        Equal: '=',
        BracketLeft: '[',
        BracketRight: ']',
        Backslash: '\\',
        Semicolon: ';',
        Quote: '\'',
        Comma: ',',
        Period: '.',
        Slash: '/',
        Space: ' ',
        NumpadDecimal: '.',
        NumpadDivide: '/',
        NumpadMultiply: '*',
        NumpadSubtract: '-',
        NumpadAdd: '+'
    });
    const SHORTCUT_CODE_LABELS = Object.freeze({
        Space: 'Space',
        Enter: 'Enter',
        NumpadEnter: 'Numpad Enter',
        Escape: 'Esc',
        Tab: 'Tab',
        Backspace: 'Backspace',
        Delete: 'Delete',
        Insert: 'Insert',
        Home: 'Home',
        End: 'End',
        PageUp: 'Page Up',
        PageDown: 'Page Down',
        ArrowUp: 'Up',
        ArrowDown: 'Down',
        ArrowLeft: 'Left',
        ArrowRight: 'Right'
    });
    const SHORTCUT_KEY_TO_CODE = Object.freeze({
        '`': 'Backquote',
        '-': 'Minus',
        '=': 'Equal',
        '[': 'BracketLeft',
        ']': 'BracketRight',
        '\\': 'Backslash',
        ';': 'Semicolon',
        '\'': 'Quote',
        ',': 'Comma',
        '.': 'Period',
        '/': 'Slash',
        ' ': 'Space',
        '*': 'NumpadMultiply',
        '+': 'NumpadAdd',
        ESC: 'Escape',
        ESCAPE: 'Escape',
        TAB: 'Tab',
        ENTER: 'Enter',
        RETURN: 'Enter',
        SPACE: 'Space',
        BACKSPACE: 'Backspace',
        DELETE: 'Delete',
        DEL: 'Delete',
        INSERT: 'Insert',
        HOME: 'Home',
        END: 'End',
        PAGEUP: 'PageUp',
        PAGEDOWN: 'PageDown',
        UP: 'ArrowUp',
        ARROWUP: 'ArrowUp',
        DOWN: 'ArrowDown',
        ARROWDOWN: 'ArrowDown',
        LEFT: 'ArrowLeft',
        ARROWLEFT: 'ArrowLeft',
        RIGHT: 'ArrowRight',
        ARROWRIGHT: 'ArrowRight'
    });

    function getShortcutDisplayLabelFromCode(code) {
        const normalized = String(code || '').trim();
        if (!normalized) return '';
        if (/^Key[A-Z]$/i.test(normalized)) return normalized.slice(3).toUpperCase();
        if (/^Digit[0-9]$/.test(normalized)) return normalized.slice(5);
        if (/^Numpad[0-9]$/.test(normalized)) return normalized.slice(6);
        if (SHORTCUT_CODE_TO_KEY[normalized]) {
            return normalized === 'Space' ? 'Space' : SHORTCUT_CODE_TO_KEY[normalized];
        }
        if (/^F\d{1,2}$/i.test(normalized)) return normalized.toUpperCase();
        return SHORTCUT_CODE_LABELS[normalized] || normalized;
    }

    function inferShortcutCodeFromStoredKey(value) {
        const raw = String(value ?? '');
        if (!raw && raw !== ' ') return '';
        if (raw === ' ') return 'Space';

        const trimmed = raw.trim();
        if (!trimmed) return '';
        if (/^[A-Z]$/i.test(trimmed)) return `Key${trimmed.toUpperCase()}`;
        if (/^[0-9]$/.test(trimmed)) return `Digit${trimmed}`;
        if (/^F\d{1,2}$/i.test(trimmed)) return trimmed.toUpperCase();
        if (SHORTCUT_KEY_TO_CODE[trimmed]) return SHORTCUT_KEY_TO_CODE[trimmed];

        const upper = trimmed.toUpperCase();
        return SHORTCUT_KEY_TO_CODE[upper] || '';
    }

    function normalizeShortcutCodeValue(code, fallbackKey = '') {
        const rawCode = String(code || '').trim();
        if (!rawCode) return inferShortcutCodeFromStoredKey(fallbackKey);
        if (/^Key[A-Z]$/i.test(rawCode)) return `Key${rawCode.slice(3).toUpperCase()}`;
        if (/^Digit[0-9]$/.test(rawCode)) return rawCode;
        if (/^Numpad[0-9]$/.test(rawCode)) return rawCode;
        if (/^F\d{1,2}$/i.test(rawCode)) return rawCode.toUpperCase();
        return rawCode;
    }

    function normalizeShortcutStoredKey(value, fallbackCode = '') {
        const fallbackLabel = getShortcutDisplayLabelFromCode(fallbackCode);
        if (fallbackLabel) return fallbackLabel;

        const raw = String(value ?? '');
        if (!raw && raw !== ' ') return '';
        if (raw === ' ') return 'Space';

        const trimmed = raw.trim();
        if (!trimmed) return '';
        if (trimmed.length === 1) {
            return /^[a-z]$/i.test(trimmed) ? trimmed.toUpperCase() : trimmed;
        }

        const inferredCode = inferShortcutCodeFromStoredKey(trimmed);
        if (inferredCode) return getShortcutDisplayLabelFromCode(inferredCode);
        if (/^Key[A-Z]$/i.test(trimmed) || /^Digit[0-9]$/.test(trimmed) || /^Numpad[0-9]$/.test(trimmed) || /^F\d{1,2}$/i.test(trimmed)) {
            return getShortcutDisplayLabelFromCode(trimmed);
        }
        return trimmed;
    }

    function normalizeShortcutBinding(entry = {}) {
        const path = String(entry.path || '');
        const action = String(entry.action || (path.startsWith('toggle:') ? 'toggle' : path.startsWith('action:') ? 'trigger' : 'navigate'));
        const code = normalizeShortcutCodeValue(entry.code, entry.key);
        const key = normalizeShortcutStoredKey(entry.key, code);
        return {
            code,
            key,
            path,
            mod1: String(entry.mod1 || 'alt'),
            mod2: String(entry.mod2 || 'none'),
            action
        };
    }

    function getShortcutBindingId(entry = {}) {
        const normalized = normalizeShortcutBinding(entry);
        const primary = normalized.code || normalized.key;
        return primary ? [normalized.mod1, normalized.mod2, primary].join('::') : '';
    }

    function createDefaultShortcut(code, path) {
        return {
            code,
            key: getShortcutDisplayLabelFromCode(code),
            path,
            mod1: 'alt',
            mod2: 'none',
            action: 'navigate'
        };
    }

    const DEFAULT_SHORTCUTS = [
        createDefaultShortcut('KeyR', '/race'),
        createDefaultShortcut('KeyG', '/garage'),
        createDefaultShortcut('KeyF', '/friends'),
        createDefaultShortcut('KeyS', '/shop'),
        createDefaultShortcut('KeyP', '/profile'),
        createDefaultShortcut('KeyT', '/team'),
        createDefaultShortcut('KeyA', '/achievements'),
        createDefaultShortcut('KeyM', '/settings/mods'),
        createDefaultShortcut('KeyE', '/season'),
        createDefaultShortcut('KeyL', '/leagues'),
        createDefaultShortcut('KeyB', '/leaderboards'),
        createDefaultShortcut('KeyI', '/stats')
    ];

    const TOOLKIT_SETTINGS = {
        // ── Garage ─────────────────────────────────────────────────────────────
        ENABLE_GARAGE_EXPANSION: {
            type: 'boolean',
            label: 'Garage Expansion',
            default: true,
            group: 'Garage',
            description: 'Add a plus button on the garage page to set the number of visible garage sections.'
        },
        GARAGE_EXPANSION_ACTION: {
            type: 'action',
            label: 'Open Garage Expansion',
            style: 'primary',
            group: 'Garage',
            help: 'Set the number of garage sections directly from the mod menu.',
            visibleWhen: { key: 'ENABLE_GARAGE_EXPANSION', eq: true }
        },
        ENABLE_GARAGE_REARRANGE_TOOLS: {
            type: 'boolean',
            label: 'Garage Rearrange Tools',
            default: true,
            group: 'Garage',
            description: 'Add selection, search, move, sort, import/export, and dockable tools while rearranging cars.'
        },
        ENABLE_CUSTOMIZER_SHUFFLE: {
            type: 'boolean',
            label: 'Customizer Shuffle',
            default: true,
            group: 'Garage',
            description: 'Add preview/pool controls and optional race-based auto shuffle for cars and supported loot.'
        },
        HIDE_BUY_CASH: {
            type: 'boolean',
            label: 'Hide Buy Cash Button',
            default: false,
            group: 'Garage',
            description: 'Hide the buy cash button in the Garage.'
        },
        // ── Profile ──────────────────────────────────────────────────────────────
        ENABLE_CAR_ICON: {
            type: 'boolean',
            label: 'Car Profile Icon',
            default: false,
            group: 'Profile',
            description: 'Replace the green profile icon in the top-right with your current car.'
        },
        ENABLE_SEND_CASH_FORMAT: {
            type: 'boolean',
            label: 'Readable Cash Amounts',
            default: true,
            group: 'Profile',
            description: 'Format large numbers with commas in the Send Cash modal.'
        },
        DONATION_LINK_STYLE: {
            type: 'select',
            label: 'Donation Profile Link',
            default: 'username',
            group: 'Profile',
            description: 'Show a clickable link to the donor\'s profile in cash gift modals.',
            options: [
                { value: 'off', label: 'Off' },
                { value: 'username', label: 'Username Only' },
                { value: 'full_url', label: 'Full URL (nitrotype.com/racer/username)' }
            ]
        },
        DONATION_LINK_NEW_TAB: {
            type: 'boolean',
            label: 'Open Donation Link in New Tab',
            default: false,
            group: 'Profile',
            description: 'Open the donor profile link in a new browser tab instead of redirecting.',
            visibleWhen: { key: 'DONATION_LINK_STYLE', neq: 'off' }
        },
        // ── Team ─────────────────────────────────────────────────────────────────
        ENABLE_BANNED_LABELS: {
            type: 'boolean',
            label: 'Banned/Warned Labels',
            default: true,
            group: 'Team',
            description: 'Show ban/warn status badges on team and friends lists.'
        },
        ENABLE_MOTD_FILTER: {
            type: 'boolean',
            label: 'MOTD Offensive Filter',
            default: true,
            group: 'Team',
            description: 'Pre-check MOTD text for possibly offensive words before saving.'
        },
        CUSTOM_MOTD_WORDS: {
            type: 'text',
            label: 'Custom Filter Words',
            default: '',
            group: 'Team',
            description: 'Additional words to flag, separated by commas (e.g. "word1, word2, word3").',
            placeholder: 'word1, word2, word3',
            visibleWhen: { key: 'ENABLE_MOTD_FILTER', eq: true }
        },
        // ── Shop ──────────────────────────────────────────────────────────────────
        ENABLE_SHOP_LEAKS: {
            type: 'boolean',
            label: 'Shop Leaks',
            default: true,
            group: 'Shop',
            description: 'Show a preview of tomorrow\'s featured and daily shop items on the shop page.'
        },
        SHOP_NOTE: {
            type: 'note',
            group: 'Shop',
            message: 'Shop notification options (Hide Shop Notifications, Smart Shop Notifications) are available in the Notifications tab.',
            tone: 'info'
        },
        // ── Appearance ───────────────────────────────────────────────────────────
        HIDE_SEASON_BANNER: {
            type: 'boolean',
            label: 'Hide Season Banner',
            default: false,
            group: 'Appearance',
            description: 'Hide the seasonal event banner at the top of the page.'
        },
        HIDE_ADS: {
            type: 'boolean',
            label: 'Hide Ads',
            default: false,
            group: 'Appearance',
            description: 'Hide ad containers on the page.'
        },
        HIDE_FOOTER: {
            type: 'boolean',
            label: 'Hide Footer',
            default: false,
            group: 'Appearance',
            description: 'Hide the page footer.'
        },
        HIDE_ALT_LOGINS: {
            type: 'boolean',
            label: 'Hide Alternative Login Options',
            default: false,
            group: 'Appearance',
            description: 'Hide third-party login options on the login and race pages.'
        },
        HIDE_RACE_STICKERS: {
            type: 'boolean',
            label: 'Hide Race Stickers',
            default: false,
            group: 'Appearance',
            description: 'Hide the sticker picker and sticker bubbles during races while leaving canned chat visible.'
        },
        HIDE_CASH_DISPLAY: {
            type: 'boolean',
            label: 'Hide Cash Display',
            default: false,
            group: 'Appearance',
            description: 'Hide your Nitro Cash balance across all pages.'
        },
        HIDE_CASH_MODE: {
            type: 'select',
            label: 'Cash Display Mode',
            default: 'hidden',
            group: 'Appearance',
            description: 'How to hide the cash amount.',
            options: [
                { value: 'hidden', label: 'Hidden (blank space)' },
                { value: 'redacted', label: 'REDACTED' },
                { value: 'stars', label: '*******' },
                { value: 'custom', label: 'Custom Message' }
            ],
            visibleWhen: { key: 'HIDE_CASH_DISPLAY', eq: true }
        },
        HIDE_CASH_CUSTOM_TEXT: {
            type: 'text',
            label: 'Custom Cash Text',
            default: '',
            group: 'Appearance',
            description: 'Custom text to display in place of your cash balance.',
            placeholder: 'Enter custom text...',
            visibleWhen: { key: 'HIDE_CASH_MODE', eq: 'custom' }
        },
        HIDE_CASH_TOTAL_SPENT: {
            type: 'boolean',
            label: 'Hide Total Spent',
            default: false,
            group: 'Appearance',
            description: 'Also hide the Total Spent value on the stats page.',
            visibleWhen: { key: 'HIDE_CASH_DISPLAY', eq: true }
        },
        // ── Notifications ────────────────────────────────────────────────────────
        HIDE_NOTIFY_ALL: {
            type: 'boolean',
            label: 'Disable All Notifications',
            default: false,
            group: 'Notifications',
            description: 'Hide all notification badges on the navigation bar.'
        },
        HIDE_NOTIFY_SHOP: {
            type: 'boolean',
            label: 'Hide Shop Notifications',
            default: false,
            group: 'Notifications',
            description: 'Hide the notification badge on the Shop nav item.',
            disabledWhen: { key: 'HIDE_NOTIFY_ALL', eq: true }
        },
        SMART_SHOP_NOTIFY: {
            type: 'boolean',
            label: 'Smart Shop Notifications',
            default: false,
            group: 'Notifications',
            description: 'Only show the Shop notification when there are unowned items in the current daily rotation.',
            visibleWhen: { key: 'HIDE_NOTIFY_SHOP', eq: false },
            disabledWhen: { key: 'HIDE_NOTIFY_ALL', eq: true }
        },
        HIDE_NOTIFY_FRIENDS: {
            type: 'boolean',
            label: 'Hide Friends Notifications',
            default: false,
            group: 'Notifications',
            description: 'Hide the notification badge on the Friends nav item.',
            disabledWhen: { key: 'HIDE_NOTIFY_ALL', eq: true }
        },
        HIDE_FRIEND_REQUEST_POPUPS: {
            type: 'boolean',
            label: 'Hide Friend Request Popups',
            default: false,
            group: 'Notifications',
            description: 'Hide the top-left friend request popup notification.'
        },
        HIDE_FRIEND_ONLINE_POPUPS: {
            type: 'boolean',
            label: 'Hide Friend Online Popups',
            default: false,
            group: 'Notifications',
            description: 'Hide the bottom-right "Your friend is online!" popup notification.'
        },
        HIDE_RACE_INVITE_POPUPS: {
            type: 'boolean',
            label: 'Hide Race Invite Popups',
            default: false,
            group: 'Notifications',
            description: 'Hide the top-left race invite popup notification.'
        },
        HIDE_NOTIFY_TEAM: {
            type: 'boolean',
            label: 'Hide Team Notifications',
            default: false,
            group: 'Notifications',
            description: 'Hide the notification badge on the Team nav item.',
            disabledWhen: { key: 'HIDE_NOTIFY_ALL', eq: true }
        },
        HIDE_NOTIFY_NEWS: {
            type: 'boolean',
            label: 'Hide News Notifications',
            default: false,
            group: 'Notifications',
            description: 'Hide the notification badge on the News nav item.',
            disabledWhen: { key: 'HIDE_NOTIFY_ALL', eq: true }
        },
        HIDE_NOTIFY_ACHIEVEMENTS: {
            type: 'boolean',
            label: 'Hide Achievements Notifications',
            default: false,
            group: 'Notifications',
            description: 'Hide the notification badge on the Achievements nav item.',
            disabledWhen: { key: 'HIDE_NOTIFY_ALL', eq: true }
        },
        HIDE_CASH_GIFTS: {
            type: 'boolean',
            label: 'Hide Cash Gifts',
            default: false,
            group: 'Notifications',
            description: 'Hide cash gift corner notifications and the "You\'ve Got Cash" popup.'
        },
        // ── Keyboard Shortcuts ───────────────────────────────────────────────────
        ENABLE_KEYBOARD_SHORTCUTS: {
            type: 'boolean',
            label: 'Keyboard Shortcuts',
            default: true,
            group: 'Shortcuts',
            description: 'Quick page navigation with modifier+key shortcuts.'
        },
        KEYBOARD_SHORTCUTS_NOTE: {
            type: 'note',
            group: 'Shortcuts',
            message: 'Keyboard shortcuts do not work on the race page due to Nitro Type\'s keyboard lockdown. They work on all other pages.',
            tone: 'info'
        },
        KEYBOARD_SHORTCUT_MAP: {
            type: 'keymap',
            label: 'Shortcut Mappings',
            default: DEFAULT_SHORTCUTS,
            group: 'Shortcuts',
            description: 'Customize page shortcuts, boolean toggles, and action buttons. The Mod Menu key picker supports letters, digits, symbols, arrows, Enter, Esc, Space, and function keys.',
            visibleWhen: { key: 'ENABLE_KEYBOARD_SHORTCUTS', eq: true }
        }
    };

    // ─── Settings Read/Write Utilities ────────────────────────────────────────────
    const getStorageKey = (settingKey) => `${NTCFG_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 */ }
    };

    const deleteCanonicalValue = (storageKey) => {
        if (typeof GM_deleteValue !== 'function') return;
        try {
            GM_deleteValue(storageKey);
        } catch { /* ignore */ }
    };

    const readStorageMetaNumber = (storageKey, fallback = 0) => {
        const raw = readCanonicalValue(storageKey);
        const parsed = Number(raw);
        return Number.isFinite(parsed) ? parsed : fallback;
    };

    const dispatchActionResult = (requestId, status, error = '') => {
        if (!requestId) return;
        try {
            document.dispatchEvent(new CustomEvent('ntcfg:action-result', {
                detail: {
                    requestId,
                    script: NTCFG_MANIFEST_ID,
                    status,
                    error
                }
            }));
        } catch { /* ignore */ }
    };

    const readSetting = (settingKey) => {
        const meta = TOOLKIT_SETTINGS[settingKey];
        if (!meta) return undefined;
        const storageKey = getStorageKey(settingKey);
        try {
            const canonical = readCanonicalValue(storageKey);
            if (canonical !== undefined) {
                return meta.type === 'boolean' ? !!canonical : canonical;
            }
            const raw = localStorage.getItem(storageKey);
            if (raw == null) return meta.default;
            const parsed = JSON.parse(raw);
            if (meta.type === 'boolean') return !!parsed;
            return parsed;
        } catch {
            return meta.default;
        }
    };

    const writeSetting = (settingKey, value) => {
        const meta = TOOLKIT_SETTINGS[settingKey];
        if (!meta) return;
        const normalized = meta.type === 'boolean' ? !!value : value;
        const storageKey = getStorageKey(settingKey);
        try {
            writeCanonicalValue(storageKey, normalized);
            const serialized = JSON.stringify(normalized);
            if (localStorage.getItem(storageKey) !== serialized) {
                localStorage.setItem(storageKey, serialized);
            }
        } catch { /* ignore storage failures */ }
    };

    const applySetting = (settingKey, value) => {
        const meta = TOOLKIT_SETTINGS[settingKey];
        if (!meta) return;
        writeSetting(settingKey, meta.type === 'boolean' ? !!value : value);
        applySettingSideEffects(settingKey);
    };

    const isFeatureEnabled = (settingKey) => readSetting(settingKey) !== false;

    const isAppearanceSetting = (settingKey) => String(settingKey || '').startsWith('HIDE_') || settingKey === 'SMART_SHOP_NOTIFY';

    const applySettingSideEffects = (settingKey) => {
        if (!settingKey) return;

        if (isAppearanceSetting(settingKey)) {
            cleanupSmartShopNotify();
            applyAppearanceStyles();
            syncClearNotificationsButton();
            return;
        }

        switch (settingKey) {
            case 'ENABLE_CAR_ICON':
                cleanupCarIcon();
                if (readSetting('ENABLE_CAR_ICON')) syncToolkitGlobalUiImmediate();
                break;
            case 'ENABLE_BANNED_LABELS':
                cleanupBannedLabels();
                if (readSetting('ENABLE_BANNED_LABELS')) {
                    handleBannedLabels();
                    syncBannedLabelsRetryPoll();
                } else {
                    stopBannedLabelsRetryPoll();
                }
                break;
            case 'ENABLE_SEND_CASH_FORMAT':
                cleanupSendCashFormat();
                if (readSetting('ENABLE_SEND_CASH_FORMAT')) handleSendCashFormat();
                break;
            case 'DONATION_LINK_STYLE':
            case 'DONATION_LINK_NEW_TAB':
                cleanupDonationLink();
                if ((readSetting('DONATION_LINK_STYLE') || 'off') !== 'off') handleDonationLink();
                break;
            case 'ENABLE_MOTD_FILTER':
            case 'CUSTOM_MOTD_WORDS':
                cleanupMOTDFilter();
                if (readSetting('ENABLE_MOTD_FILTER')) handleMOTDFilter();
                break;
            case 'ENABLE_GARAGE_EXPANSION':
                cleanupGarageExpansion();
                if (readSetting('ENABLE_GARAGE_EXPANSION')) syncGarageExpansionImmediate();
                break;
            case 'ENABLE_GARAGE_REARRANGE_TOOLS':
            case 'ENABLE_CUSTOMIZER_SHUFFLE':
                syncGarageToolsFeature();
                break;
            case 'ENABLE_SHOP_LEAKS':
                cleanupShopPreview();
                if (readSetting('ENABLE_SHOP_LEAKS')) handleShopPreview();
                break;
            default:
                break;
        }
    };

    const applyAllLiveSettingSideEffects = () => {
        cleanupSmartShopNotify();
        applyAppearanceStyles();
        syncClearNotificationsButton();

        cleanupCarIcon();
        if (readSetting('ENABLE_CAR_ICON')) syncToolkitGlobalUiImmediate();

        cleanupBannedLabels();
        if (readSetting('ENABLE_BANNED_LABELS')) {
            handleBannedLabels();
            syncBannedLabelsRetryPoll();
        } else {
            stopBannedLabelsRetryPoll();
        }

        cleanupSendCashFormat();
        if (readSetting('ENABLE_SEND_CASH_FORMAT')) handleSendCashFormat();

        cleanupDonationLink();
        if ((readSetting('DONATION_LINK_STYLE') || 'off') !== 'off') handleDonationLink();

        cleanupMOTDFilter();
        if (readSetting('ENABLE_MOTD_FILTER')) handleMOTDFilter();

        cleanupGarageExpansion();
        if (readSetting('ENABLE_GARAGE_EXPANSION')) syncGarageExpansionImmediate();
        syncGarageToolsFeature();

        cleanupShopPreview();
        if (readSetting('ENABLE_SHOP_LEAKS')) handleShopPreview();
    };

    // ─── Donation Link Migration ────────────────────────────────────────────────
    // Migrate old boolean ENABLE_DONATION_LINK + DONATION_LINK_FULL_URL to new select DONATION_LINK_STYLE
    const readShortcutsVersion = () => {
        const canonical = readCanonicalValue(SHORTCUTS_VERSION_KEY);
        if (canonical !== undefined) {
            const parsed = parseInt(canonical, 10);
            return Number.isFinite(parsed) ? parsed : 0;
        }
        return parseInt(localStorage.getItem(SHORTCUTS_VERSION_KEY), 10) || 0;
    };

    const writeShortcutsVersion = (value) => {
        writeCanonicalValue(SHORTCUTS_VERSION_KEY, value);
        try {
            localStorage.setItem(SHORTCUTS_VERSION_KEY, String(value));
        } catch { /* ignore */ }
    };

    (() => {
        try {
            const oldKey = `${NTCFG_VALUE_PREFIX}ENABLE_DONATION_LINK`;
            const oldVal = localStorage.getItem(oldKey);
            if (oldVal != null) {
                const wasEnabled = JSON.parse(oldVal);
                if (!wasEnabled) {
                    writeSetting('DONATION_LINK_STYLE', 'off');
                } else {
                    const oldFullUrl = localStorage.getItem(`${NTCFG_VALUE_PREFIX}DONATION_LINK_FULL_URL`);
                    writeSetting('DONATION_LINK_STYLE', oldFullUrl && JSON.parse(oldFullUrl) ? 'full_url' : 'username');
                }
                localStorage.removeItem(oldKey);
                localStorage.removeItem(`${NTCFG_VALUE_PREFIX}DONATION_LINK_FULL_URL`);
            }
        } catch { /* ignore */ }
    })();

    // ─── Shortcut Defaults Migration ─────────────────────────────────────────────
    // When SHORTCUTS_VERSION bumps, merge any new default shortcuts into the user's
    // saved list without overwriting their customizations.
    (() => {
        try {
            const storedVersion = readShortcutsVersion();
            const saved = readSetting('KEYBOARD_SHORTCUT_MAP');
            if (Array.isArray(saved) && saved.length > 0) {
                let nextShortcuts = saved.map((shortcut) => normalizeShortcutBinding(shortcut));
                const existingBindings = new Set(nextShortcuts.map((shortcut) => getShortcutBindingId(shortcut)).filter(Boolean));
                const additions = DEFAULT_SHORTCUTS.filter((shortcut) => !existingBindings.has(getShortcutBindingId(shortcut)));
                if (additions.length > 0) {
                    nextShortcuts = nextShortcuts.concat(additions);
                }
                if (storedVersion < SHORTCUTS_VERSION || JSON.stringify(nextShortcuts) !== JSON.stringify(saved)) {
                    writeSetting('KEYBOARD_SHORTCUT_MAP', nextShortcuts);
                }
            }
            if (storedVersion < SHORTCUTS_VERSION) {
                writeShortcutsVersion(SHORTCUTS_VERSION);
            }
        } catch { /* ignore */ }
    })();

    // ─── Manifest Registration ────────────────────────────────────────────────────
    const registerManifest = () => {
        try {
            const manifest = {
                id: NTCFG_MANIFEST_ID,
                name: 'Toolkit',
                version: NTCFG_BRIDGE_VERSION,
                scriptVersion: typeof GM_info !== 'undefined' ? GM_info.script.version : '',
                storageVersion: SETTINGS_STORAGE_VERSION,
                supportsGlobalReset: true,
                description: 'Quality-of-life utilities: banned labels, cash formatting, donation links, MOTD filter, appearance toggles, keyboard shortcuts.',
                sections: [
                    { id: 'garage', title: 'Garage', subtitle: 'Garage section management and display options.', resetButton: 'Reset Garage to Defaults' },
                    { id: 'profile', title: 'Profile', subtitle: 'Profile icon, cash formatting, and donation links.', resetButton: 'Reset Profile to Defaults' },
                    { id: 'team', title: 'Team', subtitle: 'Team member labels and MOTD tools.', resetButton: 'Reset Team to Defaults' },
                    { id: 'shop', title: 'Shop', subtitle: 'Shop page previews and features.', resetButton: 'Reset Shop to Defaults' },
                    { id: 'appearance', title: 'Appearance', subtitle: 'Hide or show page elements.', resetButton: 'Reset Appearance to Defaults' },
                    { id: 'notifications', title: 'Notifications', subtitle: 'Control which navigation bar notification badges are visible.', resetButton: 'Reset Notifications to Defaults' },
                    { id: 'shortcuts', title: 'Keyboard Shortcuts', subtitle: 'Quick navigation with customizable shortcuts.', resetButton: 'Reset Shortcuts to Defaults' }
                ],
                settings: TOOLKIT_SETTINGS
            };
            const serialized = JSON.stringify(manifest);
            if (localStorage.getItem(NTCFG_MANIFEST_KEY) !== serialized) {
                localStorage.setItem(NTCFG_MANIFEST_KEY, serialized);
            }
        } catch { /* ignore */ }
    };

    const syncAllSettings = () => {
        Object.keys(TOOLKIT_SETTINGS).forEach((key) => {
            writeSetting(key, readSetting(key));
        });
    };

    const cleanupLegacyToolkitStorage = () => {
        try {
            localStorage.removeItem(`${NTCFG_VALUE_PREFIX}ENABLE_DONATION_LINK`);
            localStorage.removeItem(`${NTCFG_VALUE_PREFIX}DONATION_LINK_FULL_URL`);
        } catch { /* ignore */ }
    };

    const migrateBooleanSettingKey = (oldSettingKey, newSettingKey) => {
        const oldStorageKey = getStorageKey(oldSettingKey);
        const newStorageKey = getStorageKey(newSettingKey);
        try {
            if (readCanonicalValue(newStorageKey) !== undefined || localStorage.getItem(newStorageKey) != null) return;
            const canonical = readCanonicalValue(oldStorageKey);
            if (canonical !== undefined) {
                writeSetting(newSettingKey, !!canonical);
                return;
            }
            const raw = localStorage.getItem(oldStorageKey);
            if (raw != null) writeSetting(newSettingKey, !!JSON.parse(raw));
        } catch { /* ignore */ }
    };

    const ensureToolkitStorageMigration = () => {
        const currentVersion = readStorageMetaNumber(STORAGE_VERSION_KEY, 0);
        const migratedAt = readStorageMetaNumber(STORAGE_MIGRATED_AT_KEY, 0);
        const now = Date.now();

        migrateBooleanSettingKey('ENABLE_GARAGE_ORGANIZER', 'ENABLE_GARAGE_EXPANSION');

        if (currentVersion < SETTINGS_STORAGE_VERSION) {
            syncAllSettings();
            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) {
            cleanupLegacyToolkitStorage();
        }
    };

    const resetToolkitSettingsToDefaults = () => {
        Object.entries(TOOLKIT_SETTINGS).forEach(([settingKey, meta]) => {
            if (meta.type === 'note' || meta.type === 'action') return;
            writeSetting(settingKey, meta.default);
        });
        writeShortcutsVersion(SHORTCUTS_VERSION);
    };

    // Listen for mod menu changes (same tab)
    document.addEventListener('ntcfg:change', (event) => {
        if (event?.detail?.script !== NTCFG_MANIFEST_ID) return;
        applySetting(event.detail.key, event.detail.value);
    });

    // Listen for mod menu action buttons
    document.addEventListener('ntcfg:action', (event) => {
        const detail = event?.detail || {};
        const isTargeted = detail.script === NTCFG_MANIFEST_ID;
        const isGlobal = detail.script === '*';
        if (!isTargeted && !isGlobal) return;

        if (detail.key === 'clear-settings' && detail.scope === 'prefs+caches') {
            try {
                resetToolkitSettingsToDefaults();
                cleanupLegacyToolkitStorage();
                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);
                registerManifest();
                syncAllSettings();
                applyAllLiveSettingSideEffects();
                document.dispatchEvent(new CustomEvent('ntcfg:manifest-updated', {
                    detail: { script: NTCFG_MANIFEST_ID }
                }));
                dispatchActionResult(detail.requestId, 'success');
            } catch (error) {
                dispatchActionResult(detail.requestId, 'error', error?.message || String(error));
            }
            return;
        }

        if ((detail.key === 'GARAGE_EXPANSION_ACTION' || detail.key === 'GARAGE_ORGANIZER_ACTION') && isTargeted) {
            try {
                const persist = JSON.parse(localStorage.getItem('persist:nt'));
                const user = JSON.parse(persist.user);
                const garage = user.garage;
                if (!Array.isArray(garage)) return;
                const totalCars = user.totalCars || user.carsOwned || 0;
                const currentSections = Math.ceil(garage.length / 30);
                showGarageExpansionModal(currentSections, totalCars);
            } catch (e) {
                console.error(TOOLKIT_LOG_PREFIX, 'Garage expansion action error:', e);
            }
        }
    });

    // Listen for cross-tab changes
    window.addEventListener('storage', (event) => {
        const key = String(event?.key || '');
        if (!key.startsWith(NTCFG_VALUE_PREFIX) || event.newValue == null) return;
        const settingKey = key.slice(NTCFG_VALUE_PREFIX.length);
        if (!TOOLKIT_SETTINGS[settingKey]) return;
        try { applySetting(settingKey, JSON.parse(event.newValue)); } catch { /* ignore */ }
    });

    ensureToolkitStorageMigration();
    registerManifest();
    syncAllSettings();
    syncEarlyCashGiftStyle();
    syncEarlyCashMaskStyle();
    syncEarlyFriendRequestStyle();
    syncEarlyRaceInviteStyle();
    syncEarlyHideAdsStyle();

    const publishToolkitManifestHeartbeat = () => {
        try { localStorage.setItem('ntcfg:alive:' + NTCFG_MANIFEST_ID, String(Date.now())); } catch { /* ignore */ }
        try {
            document.dispatchEvent(new CustomEvent('ntcfg:manifest-updated', {
                detail: { script: NTCFG_MANIFEST_ID }
            }));
        } catch { /* ignore */ }
    };
    publishToolkitManifestHeartbeat();

    // ─── Shared Utilities ─────────────────────────────────────────────────────────

    /** Get player_token from localStorage; returns null when missing or already JWT-expired. */
    const getLiveTokenOuter = () => {
        const token = String(localStorage.getItem('player_token') || '').trim();
        if (!token) return null;
        try {
            const payload = JSON.parse(atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')));
            if (payload.exp && payload.exp < Date.now() / 1000) return null;
        } catch { /* not a standard JWT or missing exp — allow */ }
        return token;
    };

    /** Traverse React fiber tree to find component instance. */
    const findReact = (dom, traverseUp = 0) => {
        if (!dom) return null;
        const key = Object.keys(dom).find((k) => k.startsWith('__reactFiber$'));
        const domFiber = dom[key];
        if (domFiber == null) return null;
        const getCompFiber = (fiber) => {
            let parentFiber = fiber?.return;
            while (typeof parentFiber?.type === 'string') {
                parentFiber = parentFiber?.return;
            }
            return parentFiber;
        };
        let compFiber = getCompFiber(domFiber);
        for (let i = 0; i < traverseUp && compFiber; i++) {
            compFiber = getCompFiber(compFiber);
        }
        return compFiber?.stateNode;
    };

    /** Get React fiber from a DOM node (lower-level than findReact). */
    const getReactFiber = (dom) => {
        if (!dom) return null;
        const key = Object.keys(dom).find((k) =>
            k.startsWith('__reactFiber$') || k.startsWith('__reactInternalInstance$')
        );
        return key ? dom[key] : null;
    };

    /** Walk up fiber tree looking for props containing a given key. */
    const findReactProp = (dom, propName, maxSteps = 30) => {
        let fiber = getReactFiber(dom);
        let steps = 0;
        while (fiber && steps++ < maxSteps) {
            const props = fiber.memoizedProps || fiber.pendingProps || null;
            if (props && propName in props) return props[propName];
            const stateNode = fiber.stateNode;
            if (stateNode?.props && propName in stateNode.props) return stateNode.props[propName];
            fiber = fiber.return;
        }
        return undefined;
    };

    const extractUsernameFromHref = (href) => {
        const parts = String(href || '').split('/').filter(Boolean);
        const username = parts[parts.length - 1] || '';
        return username ? decodeURIComponent(username) : '';
    };

    /** Escape HTML entities for safe injection. */
    const escapeHtml = (value) => {
        return String(value ?? '')
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;');
    };

    /** Normalize a pathname by stripping trailing slashes. */
    const normalizePath = (pathname) => {
        if (!pathname || pathname === '/') return '/';
        return pathname.replace(/\/+$/, '') || '/';
    };

    /** SPA-friendly navigation using history API. */
    const spaNavigate = (path) => {
        try {
            history.pushState({}, '', path);
            window.dispatchEvent(new PopStateEvent('popstate'));
        } catch {
            window.location.href = path;
        }
    };

    /** Check if user is currently in an active race (actively typing, not lobby/results). */
    const isInActiveRace = () => {
        const container = document.getElementById('raceContainer');
        if (!container) return false;
        // Only block during actual typing — check for the race text AND no results yet
        const hasRaceText = !!container.querySelector('.dash-copy');
        const hasResults = !!container.querySelector('.race-results');
        // Active typing = race text exists but results haven't appeared
        return hasRaceText && !hasResults;
    };


    /** Get current user data from localStorage. */
    const getCurrentUser = () => {
        try {
            const persist = JSON.parse(localStorage.getItem('persist:nt'));
            return JSON.parse(persist.user);
        } catch {
            return null;
        }
    };

    // ─── SPA Navigation Hooks ─────────────────────────────────────────────────────
    const originalPushState = history.pushState;
    history.pushState = function () {
        const result = originalPushState.apply(this, arguments);
        onRouteChange();
        return result;
    };

    const originalReplaceState = history.replaceState;
    history.replaceState = function () {
        const result = originalReplaceState.apply(this, arguments);
        onRouteChange();
        return result;
    };

    window.addEventListener('popstate', onRouteChange);

    function onRouteChange() {
        syncToolkitGlobalUiImmediate();
        syncBannedLabelsRetryPoll();
        syncGarageExpansionImmediate();
        syncGarageToolsFeature();
        const path = normalizePath(window.location.pathname);
        if (!readSetting('ENABLE_SHOP_LEAKS')) return;

        if (path === '/shop') {
            try { scheduleShopPreviewRepairWave('default'); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'Shop route recovery error:', e); }
        } else if (path.startsWith('/shop/')) {
            try { cleanupShopPreview(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'Shop route cleanup error:', e); }
        }
    }

    // ─── Observer Manager Integration ─────────────────────────────────────────────
    function initObserverManager() {
        const existing = window.NTObserverManager || {};
        if (existing.version !== '1.0.0' && existing.observer && typeof existing.observer.disconnect === 'function') {
            try { existing.observer.disconnect(); } catch (e) { }
            existing.observer = null;
        }
        if (existing.debounceTimer) {
            clearTimeout(existing.debounceTimer);
            existing.debounceTimer = null;
        }
        existing.callbacks = existing.callbacks || {};
        existing.version = '1.0.0';
        existing.register = function (scriptName, callback) {
            this.callbacks[scriptName] = callback;
            if (!this.observer) {
                this.observer = new MutationObserver(() => {
                    clearTimeout(this.debounceTimer);
                    this.debounceTimer = setTimeout(() => {
                        Object.values(this.callbacks).forEach((cb) => {
                            try { cb(); } catch (e) { console.error('[Observer Error]', e); }
                        });
                    }, 250);
                });
                this.observer.observe(document.body, {
                    childList: true,
                    subtree: true,
                    attributes: true,
                    attributeFilter: ['class', 'style', 'aria-hidden']
                });
            }
        };
        window.NTObserverManager = existing;
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 1: Banned/Warned Labels (/team/*, /friends)
    // ─────────────────────────────────────────────────────────────────────────────
    const BANNED_ATTR = 'data-toolkit-banned';
    const BANNED_SEPARATOR_ATTR = 'data-toolkit-banned-separator';
    const TEAM_MEMBER_STATUS_CACHE_TTL_MS = 60 * 1000;
    const BANNED_LABELS_RETRY_INTERVAL_MS = 300;
    const BANNED_LABELS_RETRY_MAX_ATTEMPTS = 40;
    const teamMemberStatusCache = new Map();
    const teamMemberStatusInflight = new Map();
    let bannedLabelsRetryTimer = null;
    let bannedLabelsRetryAttempts = 0;
    let bannedLabelsRetryPath = '';

    function cleanupBannedLabels() {
        document.querySelectorAll('.toolkit-status-badge').forEach((badge) => badge.remove());
        document.querySelectorAll('[' + BANNED_SEPARATOR_ATTR + ']').forEach((node) => node.remove());
        document.querySelectorAll('[' + BANNED_ATTR + ']').forEach((node) => node.removeAttribute(BANNED_ATTR));
    }

    /** Create a styled banned/warned badge element. */
    function createStatusBadge(status) {
        const badge = document.createElement('span');
        badge.className = 'toolkit-status-badge';
        badge.style.cssText = 'display:inline-block;margin-left:6px;padding:1px 5px;border-radius:3px;font-size:10px;font-weight:700;letter-spacing:0.5px;text-transform:uppercase;vertical-align:middle;line-height:1.4;';
        if (status === 'banned') {
            badge.textContent = 'BANNED';
            badge.style.color = '#fff';
            badge.style.backgroundColor = 'rgba(214, 47, 58, 0.8)';
        } else {
            badge.textContent = 'WARNED';
            badge.style.color = '#fff';
            badge.style.backgroundColor = 'rgba(255, 159, 28, 0.8)';
        }
        return badge;
    }

    function getTeamTagFromPath(pathname = window.location.pathname) {
        const parts = normalizePath(pathname).split('/').filter(Boolean);
        if (parts[0] !== 'team' || !parts[1] || parts[1] === 'create' || parts[1] === 'edit') return '';
        try {
            return decodeURIComponent(parts[1]);
        } catch {
            return parts[1];
        }
    }

    function normalizeMemberLookup(value) {
        return String(value || '')
            .replace(/[\u200b-\u200d\ufeff]/g, '')
            .replace(/\s+/g, ' ')
            .trim()
            .toLowerCase();
    }

    function createMemberLookupMaps(members) {
        const membersByUsername = new Map();
        const membersByDisplayName = new Map();
        const membersByDisplayNameGroup = new Map();
        members.forEach((member) => {
            const username = normalizeMemberLookup(member?.username);
            const displayName = normalizeMemberLookup(member?.displayName || member?.username);
            if (username && !membersByUsername.has(username)) membersByUsername.set(username, member);
            if (displayName) {
                if (!membersByDisplayNameGroup.has(displayName)) membersByDisplayNameGroup.set(displayName, []);
                membersByDisplayNameGroup.get(displayName).push(member);
            }
        });
        membersByDisplayNameGroup.forEach((group, displayName) => {
            if (group.length === 1) membersByDisplayName.set(displayName, group[0]);
        });
        return { membersByUsername, membersByDisplayName, membersByDisplayNameGroup };
    }

    function getRowUsername(row, nameContainer) {
        const taggedNode = row.querySelector('[data-nt-username], [data-username], [data-status-processed-for]');
        const candidates = [
            row.getAttribute('data-nt-username'),
            row.getAttribute('data-username'),
            row.getAttribute('data-status-processed-for'),
            nameContainer.getAttribute('data-nt-username'),
            nameContainer.getAttribute('data-username'),
            nameContainer.getAttribute('data-status-processed-for'),
            taggedNode?.getAttribute('data-nt-username'),
            taggedNode?.getAttribute('data-username'),
            taggedNode?.getAttribute('data-status-processed-for'),
            extractUsernameFromHref(nameContainer.querySelector('a[href*="/racer/"]')?.getAttribute('href'))
        ];
        return normalizeMemberLookup(candidates.find((value) => normalizeMemberLookup(value)) || '');
    }

    function parseRosterNumber(value) {
        const parsed = parseInt(String(value || '').replace(/[^\d-]/g, ''), 10);
        return Number.isFinite(parsed) ? parsed : 0;
    }

    function getMemberAverageSpeed(member) {
        const typed = Number(member?.typed) || 0;
        const secs = Number(member?.secs) || 0;
        if (typed > 0 && secs > 0) return Math.round(typed / 5 / (secs / 60));
        return parseRosterNumber(member?.avgSpeed);
    }

    function getMemberStatsSignature(member) {
        return {
            averageSpeed: getMemberAverageSpeed(member),
            highestSpeed: parseRosterNumber(member?.highestSpeed),
            racesPlayed: parseRosterNumber(member?.racesPlayed),
            played: parseRosterNumber(member?.played)
        };
    }

    function getRowStatsSignature(row) {
        const speedCell = row.querySelector('.table-cell--speed');
        const raceCells = [...row.querySelectorAll('.table-cell--races')];
        return {
            averageSpeed: parseRosterNumber(speedCell?.textContent),
            highestSpeed: parseRosterNumber(speedCell?.nextElementSibling?.textContent),
            racesPlayed: parseRosterNumber(raceCells[0]?.textContent),
            played: parseRosterNumber(raceCells[1]?.textContent)
        };
    }

    function signatureMatchesMember(rowSignature, member) {
        const memberSignature = getMemberStatsSignature(member);
        return ['averageSpeed', 'highestSpeed', 'racesPlayed', 'played'].every((key) => {
            return !rowSignature[key] || !memberSignature[key] || rowSignature[key] === memberSignature[key];
        });
    }

    function findRosterMember(row, username, displayName, lookupMaps) {
        if (username) {
            const member = lookupMaps.membersByUsername.get(username);
            if (member) return member;
        }

        const exactDisplayMember = lookupMaps.membersByDisplayName.get(displayName);
        if (exactDisplayMember) return exactDisplayMember;

        const displayGroup = lookupMaps.membersByDisplayNameGroup.get(displayName) || [];
        if (displayGroup.length <= 1) return null;

        const rowSignature = getRowStatsSignature(row);
        const statMatches = displayGroup.filter((member) => signatureMatchesMember(rowSignature, member));
        return statMatches.length === 1 ? statMatches[0] : null;
    }

    function removeRowStatusBadge(row) {
        row.querySelectorAll('.toolkit-status-badge').forEach((badge) => badge.remove());
        row.querySelectorAll('[' + BANNED_SEPARATOR_ATTR + ']').forEach((node) => node.remove());
    }

    function removeRosterTopBadges(nameContainer) {
        nameContainer.querySelectorAll('[data-badge-type="racer"], [data-badge-type="team"]').forEach((badge) => badge.remove());
    }

    function insertRosterStatusBadge(row, nameContainer, status) {
        const existingBadge = row.querySelector('.toolkit-status-badge');
        removeRosterTopBadges(nameContainer);
        if (row.getAttribute(BANNED_ATTR) === status && existingBadge?.textContent?.trim().toLowerCase() === status) {
            return;
        }

        removeRowStatusBadge(row);
        const badge = createStatusBadge(status);

        const nameEl = nameContainer.querySelector('.type-ellip');
        if (nameEl) {
            let insertAfter = nameEl;
            while (insertAfter.nextElementSibling &&
                insertAfter.nextElementSibling.hasAttribute &&
                (insertAfter.nextElementSibling.hasAttribute('data-badge-scope') ||
                    insertAfter.nextElementSibling.classList?.contains('profile-badge'))) {
                insertAfter = insertAfter.nextElementSibling;
            }
            insertAfter.parentNode.insertBefore(badge, insertAfter.nextSibling);
        } else {
            nameContainer.appendChild(badge);
        }
    }

    function applyBannedLabelsFromMembers(teamTable, members) {
        if (!Array.isArray(members) || members.length === 0) return false;

        const lookupMaps = createMemberLookupMaps(members);
        let matchedRows = 0;

        // ── Team header: captain badge ──────────────────────────────────────────
        const headerContainer = document.querySelector('.tsm.tbs');
        if (headerContainer) {
            const captainLink = headerContainer.querySelector('a.link');
            const captainUsername = extractUsernameFromHref(captainLink?.getAttribute('href'));
            const captainMember = captainUsername ? lookupMaps.membersByUsername.get(normalizeMemberLookup(captainUsername)) : null;

            if (captainMember) {
                const captainStatus = normalizeMemberLookup(captainMember.status);
                if (captainStatus === 'banned' || captainStatus === 'warned') {
                    const existingBadge = headerContainer.querySelector('.toolkit-status-badge');
                    const alreadyRendered = headerContainer.getAttribute(BANNED_ATTR) === captainStatus
                        && existingBadge?.textContent?.trim().toLowerCase() === captainStatus;

                    if (!alreadyRendered) {
                        headerContainer.querySelectorAll('.toolkit-status-badge').forEach((badge) => badge.remove());
                        headerContainer.setAttribute(BANNED_ATTR, captainStatus);
                        const badge = createStatusBadge(captainStatus);
                        const captainLabel = headerContainer.querySelector('.tsxs.ttu.tsi.mls');
                        if (captainLabel) {
                            captainLabel.after(badge);
                        } else if (captainLink) {
                            captainLink.after(badge);
                        } else {
                            headerContainer.appendChild(badge);
                        }
                    }
                } else {
                    headerContainer.querySelectorAll('.toolkit-status-badge').forEach((badge) => badge.remove());
                    headerContainer.setAttribute(BANNED_ATTR, 'ok');
                }
            }
        }

        // ── Roster rows ─────────────────────────────────────────────────────────
        const rows = teamTable.querySelectorAll('.table-row');
        rows.forEach((row) => {
            const nameContainer = row.querySelector('.player-name--container[title]');
            if (!nameContainer) return;

            const nameSpan = nameContainer.querySelector('.type-ellip');
            if (!nameSpan) return;

            const displayName = normalizeMemberLookup(nameSpan.textContent);
            const username = getRowUsername(row, nameContainer);
            const member = findRosterMember(row, username, displayName, lookupMaps);

            if (!member) return;

            matchedRows += 1;
            const status = normalizeMemberLookup(member.status);
            if (status !== 'banned' && status !== 'warned') {
                row.setAttribute(BANNED_ATTR, 'ok');
                removeRowStatusBadge(row);
                return;
            }

            row.setAttribute(BANNED_ATTR, status);
            insertRosterStatusBadge(row, nameContainer, status);
        });

        return matchedRows > 0;
    }

    function getTeamOverviewTable() {
        return document.querySelector('.table.table--striped.table--selectable.table--team.table--teamOverview');
    }

    function getFriendsTable() {
        return document.querySelector('.table.table--selectable.table--striped.table--friends');
    }

    function getFriendsRows(friendsTable = getFriendsTable()) {
        if (!friendsTable) return [];
        return Array.from(friendsTable.querySelectorAll('.table-row'))
            .filter((row) => !!row.querySelector('.player-name--container[title]'));
    }

    function getFriendRenderedStatus(row) {
        const statusText = row.querySelector('.friends-list--friend-status--text');
        if (!statusText) return '';
        const directTextNode = Array.from(statusText.childNodes || [])
            .find((node) => node.nodeType === 3 && String(node.textContent || '').trim());
        return normalizeMemberLookup(directTextNode?.textContent || statusText.textContent);
    }

    function applyBannedLabelsFromFriends() {
        const friendsTable = getFriendsTable();
        if (!friendsTable) return false;

        let processedRows = 0;
        getFriendsRows(friendsTable).forEach((row) => {
            const nameContainer = row.querySelector('.player-name--container[title]');
            if (!nameContainer) return;

            processedRows += 1;
            const status = getFriendRenderedStatus(row);
            if (status !== 'banned' && status !== 'warned') {
                row.setAttribute(BANNED_ATTR, 'ok');
                removeRowStatusBadge(row);
                return;
            }

            row.setAttribute(BANNED_ATTR, status);
            insertRosterStatusBadge(row, nameContainer, status);
        });

        return processedRows > 0;
    }

    function shouldRetryFriendsBannedLabels(friendsTable = getFriendsTable()) {
        if (!friendsTable) return true;

        const rows = getFriendsRows(friendsTable);
        if (rows.length === 0) return true;

        return rows.some((row) => !row.hasAttribute(BANNED_ATTR))
            || rows.some((row) => {
                const status = getFriendRenderedStatus(row);
                return (status === 'banned' || status === 'warned') && !row.querySelector('.toolkit-status-badge');
            });
    }

    function shouldRetryBannedLabels() {
        if (!isFeatureEnabled('ENABLE_BANNED_LABELS')) return false;
        const path = normalizePath(window.location.pathname);

        if (path === '/friends') {
            return shouldRetryFriendsBannedLabels();
        }

        if (!getTeamTagFromPath()) return false;

        const teamTable = getTeamOverviewTable();
        if (!teamTable) return true;

        const rows = teamTable.querySelectorAll('.table-row');
        if (rows.length === 0) return true;

        return !teamTable.querySelector('.table-row[' + BANNED_ATTR + ']');
    }

    function stopBannedLabelsRetryPoll() {
        if (bannedLabelsRetryTimer) {
            clearInterval(bannedLabelsRetryTimer);
            bannedLabelsRetryTimer = null;
        }
        bannedLabelsRetryAttempts = 0;
        bannedLabelsRetryPath = '';
    }

    function startBannedLabelsRetryPoll() {
        if (bannedLabelsRetryTimer) return;

        bannedLabelsRetryPath = normalizePath(window.location.pathname);
        bannedLabelsRetryAttempts = 0;
        bannedLabelsRetryTimer = setInterval(() => {
            if (normalizePath(window.location.pathname) !== bannedLabelsRetryPath || !shouldRetryBannedLabels()) {
                stopBannedLabelsRetryPoll();
                return;
            }

            bannedLabelsRetryAttempts++;
            try { handleBannedLabels(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'BannedLabels retry error:', e); }

            if (!shouldRetryBannedLabels() || bannedLabelsRetryAttempts >= BANNED_LABELS_RETRY_MAX_ATTEMPTS) {
                stopBannedLabelsRetryPoll();
            }
        }, BANNED_LABELS_RETRY_INTERVAL_MS);
    }

    function syncBannedLabelsRetryPoll() {
        if (shouldRetryBannedLabels()) {
            startBannedLabelsRetryPoll();
        } else {
            stopBannedLabelsRetryPoll();
        }
    }

    function fetchTeamMembersForBannedLabels(teamTag) {
        const normalizedTeamTag = String(teamTag || '').trim();
        if (!normalizedTeamTag) return Promise.resolve(null);

        const cacheKey = normalizedTeamTag.toLowerCase();
        const cached = teamMemberStatusCache.get(cacheKey);
        if (cached && Date.now() - cached.timestamp < TEAM_MEMBER_STATUS_CACHE_TTL_MS) {
            return Promise.resolve(cached.members);
        }

        const inflight = teamMemberStatusInflight.get(cacheKey);
        if (inflight) return inflight;

        const requestUrl = new URL('/api/v2/teams/' + encodeURIComponent(normalizedTeamTag), window.location.origin).href;
        const request = new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.open('GET', requestUrl, true);
            xhr.withCredentials = true;
            try { xhr.setRequestHeader('Accept', 'application/json'); } catch { /* ignore */ }
            xhr.onload = () => {
                if (xhr.status < 200 || xhr.status >= 300) {
                    reject(new Error('HTTP ' + xhr.status));
                    return;
                }
                try {
                    resolve(JSON.parse(xhr.responseText || '{}'));
                } catch (error) {
                    reject(error);
                }
            };
            xhr.onerror = () => reject(new Error('Network error'));
            xhr.send(null);
        })
            .then((data) => {
                const members = data?.results?.members;
                if (!Array.isArray(members)) return null;
                teamMemberStatusCache.set(cacheKey, {
                    members,
                    timestamp: Date.now()
                });
                return members;
            })
            .catch((error) => {
                console.warn(TOOLKIT_LOG_PREFIX, 'Team member status fetch failed:', error?.message || error);
                return null;
            })
            .finally(() => {
                teamMemberStatusInflight.delete(cacheKey);
            });

        teamMemberStatusInflight.set(cacheKey, request);
        return request;
    }

    function handleBannedLabels() {
        if (!isFeatureEnabled('ENABLE_BANNED_LABELS')) return;

        if (normalizePath(window.location.pathname) === '/friends') {
            return applyBannedLabelsFromFriends();
        }

        const teamTable = getTeamOverviewTable();
        if (!teamTable) return false;

        const teamTag = getTeamTagFromPath();
        if (teamTag) {
            fetchTeamMembersForBannedLabels(teamTag).then((members) => {
                if (!members || normalizeMemberLookup(getTeamTagFromPath()) !== normalizeMemberLookup(teamTag)) return;
                const currentTeamTable = getTeamOverviewTable();
                if (currentTeamTable && applyBannedLabelsFromMembers(currentTeamTable, members)) {
                    stopBannedLabelsRetryPoll();
                }
            }).catch((error) => {
                console.error(TOOLKIT_LOG_PREFIX, 'BannedLabels async error:', error);
            });
        }

        // React internals are a quick fallback while the API request is pending.
        const members = findTeamMembers(teamTable);
        if (members && members.length > 0) {
            if (applyBannedLabelsFromMembers(teamTable, members)) stopBannedLabelsRetryPoll();
        }

        return true;
    }

    /** Extract team members array from React fiber tree. */
    function isToolkitMemberRecord(value) {
        return !!value
            && typeof value === 'object'
            && (typeof value.username === 'string'
                || typeof value.displayName === 'string'
                || typeof value.status === 'string');
    }

    function findToolkitMembersInValue(value, depth = 0, visited = new WeakSet()) {
        if (depth > 6 || value == null) return null;
        if (Array.isArray(value)) {
            if (value.length > 0 && value.every(isToolkitMemberRecord)) {
                return value;
            }
            for (const item of value) {
                const nested = findToolkitMembersInValue(item, depth + 1, visited);
                if (nested) return nested;
            }
            return null;
        }
        if (typeof value !== 'object') return null;
        if (visited.has(value)) return null;
        visited.add(value);

        const priorityKeys = ['members', 'teamMembers', 'roster', 'users', 'items', 'data', 'props', 'state'];
        for (const key of priorityKeys) {
            if (!(key in value)) continue;
            const nested = findToolkitMembersInValue(value[key], depth + 1, visited);
            if (nested) return nested;
        }

        for (const nestedValue of Object.values(value)) {
            const nested = findToolkitMembersInValue(nestedValue, depth + 1, visited);
            if (nested) return nested;
        }
        return null;
    }

    function findTeamMembers(teamTable) {
        try {
            // Walk up from the table or a card container to find the members prop
            const card = teamTable.closest('.card') || teamTable.closest('section') || teamTable.parentElement;
            if (!card) return null;

            const directMembers = findToolkitMembersInValue(findReactProp(teamTable, 'members', 60));
            if (directMembers) return directMembers;

            let fiber = getReactFiber(card);
            let steps = 0;
            while (fiber && steps++ < 40) {
                const props = fiber.memoizedProps || fiber.pendingProps || {};
                const directFromProps = findToolkitMembersInValue(props);
                if (directFromProps) return directFromProps;
                const state = fiber.memoizedState;
                const directFromState = findToolkitMembersInValue(state);
                if (directFromState) return directFromState;
                const directFromStateNode = findToolkitMembersInValue(fiber.stateNode?.props)
                    || findToolkitMembersInValue(fiber.stateNode?.state);
                if (directFromStateNode) return directFromStateNode;
                fiber = fiber.return;
            }

            // Fallback: try from the root section
            const root = document.querySelector('#root section.card');
            if (root) {
                const reactObj = findReact(root);
                const fallbackMembers = findToolkitMembersInValue(reactObj?.props)
                    || findToolkitMembersInValue(reactObj?.state);
                if (fallbackMembers) return fallbackMembers;
            }

            return null;
        } catch (e) {
            console.error(TOOLKIT_LOG_PREFIX, 'Error finding team members:', e);
            return null;
        }
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 2: Send Cash Readable Amount (/racer/*)
    // ─────────────────────────────────────────────────────────────────────────────
    const CASH_FORMAT_ATTR = 'data-toolkit-cashformat';
    const CASH_PREVIEW_ROW_ATTR = 'data-toolkit-cash-preview-row';
    const NUMERIC_REGEXP = /^[0-9]+$/;

    function cleanupSendCashFormat() {
        document.querySelectorAll('[' + CASH_FORMAT_ATTR + ']').forEach((node) => node.removeAttribute(CASH_FORMAT_ATTR));
        document.querySelectorAll('[' + CASH_PREVIEW_ROW_ATTR + ']').forEach((node) => node.remove());
    }

    function handleSendCashFormat() {
        if (!isFeatureEnabled('ENABLE_SEND_CASH_FORMAT')) return;

        // Look for the Send Cash modal's input
        const modals = document.querySelectorAll('.modal');
        modals.forEach((modal) => {
            const cashInput = modal.querySelector('.input.as-nitro-cash input.input-field');
            if (!cashInput) return;
            if (cashInput.hasAttribute(CASH_FORMAT_ATTR)) return;
            cashInput.setAttribute(CASH_FORMAT_ATTR, '1');

            // Create preview node using NT's native styling
            const preview = document.createElement('div');
            preview.className = 'tar tc-i tss mtxs';
            preview.style.minHeight = '1.2em';
            preview.setAttribute(CASH_PREVIEW_ROW_ATTR, '1');

            const prefixSpan = document.createElement('span');
            prefixSpan.className = 'as-nitro-cash--prefix';
            prefixSpan.setAttribute('data-ntk-cash-preview', '1');
            preview.appendChild(prefixSpan);

            const updatePreview = (value) => {
                if (NUMERIC_REGEXP.test(value) && value.length > 0) {
                    prefixSpan.textContent = '$' + parseInt(value, 10).toLocaleString();
                } else {
                    prefixSpan.textContent = '';
                }
            };

            cashInput.addEventListener('input', (e) => updatePreview(e.target.value));
            cashInput.addEventListener('change', (e) => updatePreview(e.target.value));

            // Insert preview below the input
            const inputContainer = cashInput.closest('.input.as-nitro-cash');
            if (inputContainer) {
                inputContainer.appendChild(preview);
                // Fix layout if needed
                const splitFlag = cashInput.closest('.split.split--flag');
                if (splitFlag) splitFlag.classList.remove('split--flag');
            }

            // Initialize with current value
            updatePreview(cashInput.value);
        });
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 3: Donation Profile Link (/racer/*, /garage)
    // ─────────────────────────────────────────────────────────────────────────────
    const DONATION_LINK_ATTR = 'data-toolkit-donation-link';
    const DONATION_LINK_ROW_ATTR = 'data-toolkit-donation-link-row';

    function cleanupDonationLink() {
        document.querySelectorAll('[' + DONATION_LINK_ROW_ATTR + ']').forEach((node) => node.remove());
        document.querySelectorAll('.modal[' + DONATION_LINK_ATTR + ']').forEach((node) => node.removeAttribute(DONATION_LINK_ATTR));
    }

    function handleDonationLink() {
        const linkStyle = readSetting('DONATION_LINK_STYLE');
        if (!linkStyle || linkStyle === 'off') return;

        // Look for the "You've Got Cash" modal
        const modals = document.querySelectorAll('.modal');
        modals.forEach((modal) => {
            if (modal.hasAttribute(DONATION_LINK_ATTR)) return;

            const header = modal.querySelector('.modal-header h2');
            if (!header || header.textContent.trim() !== "You've Got Cash") return;

            modal.setAttribute(DONATION_LINK_ATTR, '1');

            const body = modal.querySelector('.modal-body');
            if (!body) return;

            // Get donor username from React internals
            let donorUsername = null;
            try {
                const reactObj = findReact(body);
                if (reactObj?.props?.gift?.username) {
                    donorUsername = reactObj.props.gift.username;
                }
            } catch { /* fallback below */ }

            // Fallback: try to find username from fiber props
            if (!donorUsername) {
                try {
                    donorUsername = findReactProp(body, 'gift', 40)?.username;
                } catch { /* give up */ }
            }

            if (!donorUsername) return;

            const profileUrl = `/racer/${encodeURIComponent(donorUsername)}`;

            // Find the well container to append the link row
            const rowContainer = body.querySelector('.well.well--b.well--s');
            if (!rowContainer) return;

            // Create link row using NT's native split layout
            const linkText = linkStyle === 'full_url'
                ? 'nitrotype.com/racer/' + donorUsername
                : donorUsername;

            const linkRow = document.createElement('div');
            linkRow.className = 'split split--flag';
            linkRow.setAttribute(DONATION_LINK_ROW_ATTR, '1');
            linkRow.innerHTML =
                '<div class="split-cell tal">' +
                '<span class="tc-ts tsxs ttu">Profile Link:</span>' +
                '</div>' +
                '<div class="split-cell">' +
                '<a class="link link--i" href="' + escapeHtml(profileUrl) + '">' +
                escapeHtml(linkText) +
                '</a>' +
                '</div>';

            // Set link behavior — new tab or same-tab redirect
            const link = linkRow.querySelector('a');
            if (link) {
                const openNewTab = readSetting('DONATION_LINK_NEW_TAB');
                if (openNewTab) {
                    link.target = '_blank';
                    link.rel = 'noopener noreferrer';
                }
                // Same-tab: just let the native <a href> handle it (full page load)
            }

            rowContainer.appendChild(linkRow);
        });
    }

    let toolkitModalRefreshTimer = null;

    function handleModalFeatures(path = normalizePath(window.location.pathname)) {
        if (!document.querySelector('.modal')) return;
        try { handleSendCashFormat(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'SendCash error:', e); }
        try { handleDonationLink(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'DonationLink error:', e); }
        if (path.startsWith('/team/')) {
            try { handleMOTDFilter(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'MOTDFilter modal error:', e); }
        }
    }

    function scheduleModalFeatureRefresh(delay = 300) {
        clearTimeout(toolkitModalRefreshTimer);
        toolkitModalRefreshTimer = setTimeout(() => {
            toolkitModalRefreshTimer = null;
            handleModalFeatures();
        }, delay);
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 4: MOTD Offensive Filter (/team/*)
    // ─────────────────────────────────────────────────────────────────────────────
    const MOTD_FILTER_ATTR = 'data-toolkit-motd-filter';

    function cleanupMOTDFilter() {
        document.querySelectorAll('.toolkit-motd-review').forEach((node) => node.remove());
        document.querySelectorAll('[' + MOTD_FILTER_ATTR + ']').forEach((node) => node.removeAttribute(MOTD_FILTER_ATTR));
    }

    // Embedded offensive word dictionary — sourced from Toonidy's Google Sheet,
    // maintained locally to avoid external dependency.
    // To add/remove words: edit this array directly.
    const OFFENSIVE_WORDS = [
        '!0li', '!o!i', '!oli', '!u57', '!u5t', '!us7', '!ust', '(um', '(un7', '(unt',
        '***', '1d10t', '33x', '34tmy', '37d', '3ex', '3kr3m', '3krem', '3td',
        '4!de', '4166a', '416ga', '41d3', '420', '43s', '4fr1c4', '4fr1ca', '4fric4',
        '4frica', '4frika', '4id3', '4ide', '4igga', '4ld3', '4r53', '4r5e', '4rs3',
        '4rse', '4y!r', '4yir', '4ylr',
        '5!xtyn!n3', '5!xtyn!ne', '5!xtynin3', '5!xtynine', '57d', '5h!7', '5h074',
        '5h07a', '5h0t4', '5hi7', '5hit', '5hot4', '5hota', '5ixtyn!n3', '5p!c',
        '5p1c', '5pic', '5td',
        '666', '69',
        '7!75', '7!t5', '71t5', '71ts', '7it5', '7w47', '7w4t', '7wat',
        '8!7h', '8!th', '817h', '81th', '84n6', '84n9', '84ng', '8ang', '8i7h', '8ith',
        '9/11',
        '@ss',
        'a!d3', 'a!de', 'a$$', 'a1d3', 'a1d5', 'a1de', 'a1ds', 'a33', 'a35', 'a3s',
        'a53', 'a55', 'a5s', 'afr1c4', 'afr1ca', 'afr1ka', 'afric4', 'africa', 'afrik4',
        'afrika', 'aid3', 'aid5', 'aide', 'aids', 'aigga', 'ald3', 'alde', 'anal', 'anus',
        'ar53', 'ar5e', 'ars3', 'arse', 'as3', 'as5', 'ass', 'ay!r', 'ayir', 'aylr',
        'b!7h', 'b!th', 'b00b', 'b17h', 'b1th', 'b4n6', 'b4n9', 'b4ng', 'ba!!!',
        'ba!ll', 'bal!l', 'ball!', 'balll', 'balls', 'ban6', 'ban9', 'bang', 'bi7h',
        'bigd', 'bith', 'bm7ch', 'bmtch', 'boob', 'br34s7', 'br34st', 'br3as7',
        'br3ast', 'bre4s7', 'bre4st', 'breas7', 'breast', 'bu77h', 'bu7th', 'but7h',
        'butho', 'butma', 'butth',
        'c0ck', 'cnts', 'cock', 'cr4p', 'crap', 'cum', 'cun7', 'cunt',
        'd!k3', 'd!ke', 'd0n6', 'd0n9', 'd0ng', 'd1k3', 'd1ke', 'd360', 'd390', 'd39o',
        'd3g0', 'd3go', 'd4dy', 'dady', 'damn', 'day90', 'daygo', 'de60', 'de90',
        'de9o', 'deg0', 'dego', 'dik3', 'dike', 'don6', 'don9', 'dong', 'douche',
        'dup4', 'dupa',
        'e4tmy', 'eatmy', 'ekr3m', 'ekrem',
        'f177', 'f46', 'f49', 'f4g', 'f4r7', 'f4rt', 'f94', 'fa6', 'fa9', 'fag', 'far7',
        'fart', 'fitt', 'fu!k', 'fuc', 'fuck', 'fuik', 'fuk', 'fulk', 'fvck',
        'g00k', 'g9y', 'gay', 'gey', 'gook',
        'h0or', 'h0r', 'h0r3', 'h0re', 'h0rn!', 'h0rni', 'h0rny', 'h3rp3', 'h3rpe',
        'h4t3r', 'h4ter', 'h4x0r', 'hat3r', 'hater', 'herp3', 'herpe', 'ho0r', 'hoe',
        'hoor', 'hor3', 'hore', 'horn!', 'horni', 'horny', 'hump',
        'idiot',
        'k!11', 'k!ll', 'k111', 'ki11', 'kkk', 'kl11', 'kun7', 'kunt',
        'l0!i', 'l0!l', 'l0l1', 'l0ll', 'ldlot', 'lo!i', 'lol1', 'loli', 'lu57',
        'lu5t', 'lus7', 'lust',
        'm!!f', 'm!lf', 'm0r0n', 'm0ron', 'm3h4rd', 'm3hard', 'meh4rd', 'mehard',
        'mexican', 'mi!f', 'milf', 'mor0n', 'moron', 'mother',
        'n!g4', 'n!ga', 'n!p5', 'n!ps', 'n119r', 'n19r', 'n1g4', 'n1ga', 'n1gr',
        'n1p5', 'n1ps', 'n4z!', 'n4z1', 'n4zi', 'n5fW', 'n@z1', 'n@zi', 'naz!',
        'naz1', 'nazi', 'nig4', 'niga', 'nigger', 'nip5', 'nips', 'nlg4', 'nlga',
        'nlp5', 'nlps', 'nsfw', 'nw0rd', 'nword',
        'p!33', 'p!35', 'p!53', 'p!5s', 'p!s5', 'p!ss', 'p00p', 'p133', 'p135', 'p153',
        'p3n', 'p3n15', 'p3n1s', 'p3ni5', 'p3nis', 'p3rs3', 'p3rse', 'p4ck!', 'p4cki',
        'p4ckl', 'pack!', 'packi', 'packl', 'pecker', 'pedo', 'pen15', 'peni5',
        'penis', 'pers3', 'perse', 'phuck', 'pi33', 'pi35', 'pi3s', 'pi53', 'pi55',
        'pi5s', 'pis3', 'pis5', 'piss', 'pl33', 'pl3s', 'pl5s', 'pls3', 'pls5', 'plss',
        'poop', 'porn', 'pu70', 'pu7o', 'pusse', 'put0', 'puto',
        'r4pe', 'rape', 're74r', 'retar',
        's!xtyn!n3', 's!xtyn!ne', 's!xtynin3', 's!xtynine', 's33x', 's3ex', 's3x',
        's7d', 's7up1d', 's7updi', 'se3x', 'seex', 'sex', 'sh!7', 'sh!t', 'sh007',
        'sh00t', 'sh074', 'sh07a', 'sh0ta', 'shi7', 'shit', 'sho74', 'sho7a', 'shoo7',
        'shoot', 'shot4', 'shota', 'sixtyn!n3', 'sixtyn!ne', 'sixtynin3',
        'sixtynine', 'sp!c', 'sp1c', 'sp3rm', 'sperm', 'spic', 'std', 'stfu',
        'stup1d', 'stupid',
        't!75', 't!t5', 't!ts', 't175', 't177', 't17s', 't1t5', 't1tt', 'ti75',
        'tits', 'titt', 'tw4t', 'twa7', 'twat',
        'urmom', 'urmother', 'urmum',
        'w00se', 'w0n6', 'w0n9', 'w0ng', 'w33d', 'w33nu', 'w3ed', 'w3enu', 'we3d',
        'we3nu', 'weed', 'weenu', 'whore', 'won6', 'won9', 'wong',
        'xxx',
        '\u042F', '\uD83C\uDD70', '\uD83C\uDD71\uFE0F'
    ];

    /** Build full word list including any user-added custom words. */
    function getDictionaryWords() {
        const customRaw = readSetting('CUSTOM_MOTD_WORDS') || '';
        if (!customRaw.trim()) return OFFENSIVE_WORDS;
        const custom = customRaw.split(',').map(w => w.trim().toLowerCase()).filter(Boolean);
        return OFFENSIVE_WORDS.concat(custom);
    }

    // ─── Unicode-aware string splitting (runes) ──────────────────────────────────
    const HIGH_SURROGATE_START = 0xd800;
    const HIGH_SURROGATE_END = 0xdbff;
    const LOW_SURROGATE_START = 0xdc00;
    const REGIONAL_INDICATOR_START = 0x1f1e6;
    const REGIONAL_INDICATOR_END = 0x1f1ff;
    const FITZPATRICK_MODIFIER_START = 0x1f3fb;
    const FITZPATRICK_MODIFIER_END = 0x1f3ff;
    const VARIATION_MODIFIER_START = 0xfe00;
    const VARIATION_MODIFIER_END = 0xfe0f;
    const DIACRITICAL_MARKS_START = 0x20d0;
    const DIACRITICAL_MARKS_END = 0x20ff;
    const ZWJ = 0x200d;
    const GRAPHEMS = [
        0x0308, 0x0937, 0x0937, 0x093f, 0x093f, 0x0ba8,
        0x0bbf, 0x0bcd, 0x0e31, 0x0e33, 0x0e40, 0x0e49,
        0x1100, 0x1161, 0x11a8
    ];

    function runes(string) {
        if (typeof string !== 'string') return [];
        const result = [];
        let i = 0;
        let increment = 0;
        while (i < string.length) {
            increment += runesNextUnits(i + increment, string);
            if (isGraphem(string[i + increment])) increment++;
            if (isVariationSelector(string[i + increment])) increment++;
            if (isDiacriticalMark(string[i + increment])) increment++;
            if (isZeroWidthJoiner(string[i + increment])) { increment++; continue; }
            result.push(string.substring(i, i + increment));
            i += increment;
            increment = 0;
        }
        return result;
    }

    function runesNextUnits(i, string) {
        const current = string[i];
        if (!isFirstOfSurrogatePair(current) || i === string.length - 1) return 1;
        const currentPair = current + string[i + 1];
        const nextPair = string.substring(i + 2, i + 5);
        if (isRegionalIndicator(currentPair) && isRegionalIndicator(nextPair)) return 4;
        if (isFitzpatrickModifier(nextPair)) return 4;
        return 2;
    }

    function betweenInclusive(value, lower, upper) { return value >= lower && value <= upper; }
    function isFirstOfSurrogatePair(s) { return s && betweenInclusive(s.charCodeAt(0), HIGH_SURROGATE_START, HIGH_SURROGATE_END); }
    function codePointFromSurrogatePair(pair) {
        return ((pair.charCodeAt(0) - HIGH_SURROGATE_START) << 10) + (pair.charCodeAt(1) - LOW_SURROGATE_START) + 0x10000;
    }
    function isRegionalIndicator(s) { return s && s.length >= 2 && betweenInclusive(codePointFromSurrogatePair(s), REGIONAL_INDICATOR_START, REGIONAL_INDICATOR_END); }
    function isFitzpatrickModifier(s) { return s && s.length >= 2 && betweenInclusive(codePointFromSurrogatePair(s), FITZPATRICK_MODIFIER_START, FITZPATRICK_MODIFIER_END); }
    function isVariationSelector(s) { return typeof s === 'string' && betweenInclusive(s.charCodeAt(0), VARIATION_MODIFIER_START, VARIATION_MODIFIER_END); }
    function isDiacriticalMark(s) { return typeof s === 'string' && betweenInclusive(s.charCodeAt(0), DIACRITICAL_MARKS_START, DIACRITICAL_MARKS_END); }
    function isGraphem(s) { return typeof s === 'string' && GRAPHEMS.indexOf(s.charCodeAt(0)) !== -1; }
    function isZeroWidthJoiner(s) { return typeof s === 'string' && s.charCodeAt(0) === ZWJ; }

    /** Find offensive words in text, skipping punctuation/spacing between letters. */
    function findBadWords(textRunes) {
        const foundWords = [];
        const foundLetters = [];

        getDictionaryWords().forEach((word) => {
            const wordChunks = runes(word);
            for (let i = 0; i < textRunes.length; i++) {
                if (textRunes[i].toLowerCase() !== wordChunks[0].toLowerCase()) continue;

                const matched = [i];
                let wordIndex = 1;
                let j = i + 1;

                for (; j < textRunes.length && wordIndex < wordChunks.length; j++) {
                    const checkLetter = textRunes[j].toLowerCase();
                    const offensiveLetter = wordChunks[wordIndex].toLowerCase();

                    if (checkLetter === offensiveLetter) {
                        matched.push(j);
                        wordIndex++;
                        continue;
                    }

                    // Skip punctuation, spacing, or unmatched numbers
                    if (
                        checkLetter === null ||
                        (/[0-9]/.test(checkLetter) && !/^[0-9]+$/.test(word)) ||
                        (!/[a-z0-9]/i.test(checkLetter) &&
                            !/(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/.test(checkLetter))
                    ) {
                        continue;
                    }

                    break; // Character didn't match and wasn't skippable
                }

                if (matched.length === wordChunks.length) {
                    if (!foundWords.includes(word)) foundWords.push(word);
                    matched.forEach((idx) => {
                        if (!foundLetters.includes(idx)) foundLetters.push(idx);
                    });
                }
            }
        });

        return [foundWords, foundLetters];
    }

    // ─── MOTD Filter UI ──────────────────────────────────────────────────────────

    /** Inject MOTD filter styles once. */
    let motdStylesInjected = false;
    function injectMOTDStyles() {
        if (motdStylesInjected) return;
        motdStylesInjected = true;
        const style = document.createElement('style');
        style.textContent = `
            .toolkit-motd-review { margin-top: 12px; border-radius: 8px; padding: 12px; background-color: #2a2d3e; }
            .toolkit-motd-review.hidden { display: none; }
            .toolkit-motd-body { display: flex; flex-flow: row wrap; padding: 10px; background-color: #1a1d2e; border-radius: 6px; font-family: "Roboto Mono", "Courier New", monospace; font-size: 12px; }
            .toolkit-motd-word { display: flex; margin-right: 1ch; }
            .toolkit-motd-letter { color: rgba(255, 255, 255, 0.3); }
            .toolkit-motd-letter.offensive { color: #d62f3a; font-weight: 700; }
            .toolkit-motd-letter.invalid { color: #ff9f1c; font-weight: 700; text-decoration: underline wavy; }
            .toolkit-motd-actions { display: flex; justify-content: space-between; align-items: center; margin-top: 8px; }
            .toolkit-motd-helper { color: #888; font-size: 12px; }
            .toolkit-motd-warnings { margin-top: 8px; border: 1px solid #d62f3a; border-radius: 6px; padding: 10px; background-color: rgba(214, 47, 58, 0.15); color: rgba(255, 255, 255, 0.85); font-size: 13px; }
            .toolkit-motd-warnings ul { margin: 4px 0 0 16px; padding: 0; }
            .toolkit-motd-warnings li { margin-bottom: 2px; }
            .toolkit-motd-check-btn { padding: 6px 14px; border-radius: 6px; border: 1px solid rgba(255,255,255,0.15); background: rgba(255,255,255,0.08); color: #fff; font-size: 12px; cursor: pointer; transition: background 0.15s; }
            .toolkit-motd-check-btn:hover { background: rgba(255,255,255,0.15); }
        `;
        document.head.appendChild(style);
    }

    function handleMOTDFilter() {
        if (!isFeatureEnabled('ENABLE_MOTD_FILTER')) return;

        const path = window.location.pathname;
        if (!path.startsWith('/team/')) return;

        // Check if user is captain/officer
        const currentUser = getCurrentUser();
        if (!currentUser?.tag || !['captain', 'officer'].includes(currentUser.teamRole)) return;

        // Check we're on our own team page
        const teamTag = path.split('/').filter(Boolean).pop();
        if (!teamTag || teamTag.toLowerCase() !== currentUser.tag.toLowerCase()) return;

        // Watch for the MOTD modal
        const modals = document.querySelectorAll('.modal');
        modals.forEach((modal) => {
            if (modal.hasAttribute(MOTD_FILTER_ATTR)) return;

            const textarea = modal.querySelector('textarea.input-field');
            if (!textarea) return;

            modal.setAttribute(MOTD_FILTER_ATTR, '1');
            injectMOTDStyles();

            // Create the review UI
            const reviewContainer = document.createElement('div');
            reviewContainer.className = 'toolkit-motd-review hidden';

            const reviewBody = document.createElement('div');
            reviewBody.className = 'toolkit-motd-body';

            const warnings = document.createElement('div');
            warnings.className = 'toolkit-motd-warnings';
            warnings.style.display = 'none';

            const actions = document.createElement('div');
            actions.className = 'toolkit-motd-actions';

            const helper = document.createElement('span');
            helper.className = 'toolkit-motd-helper';
            helper.textContent = 'Precautionary check — some flagged words may be allowed by Nitro Type, and some may not be detected.';

            const checkBtn = document.createElement('button');
            checkBtn.type = 'button';
            checkBtn.className = 'toolkit-motd-check-btn';
            checkBtn.textContent = 'Check for Issues';

            actions.appendChild(helper);
            actions.appendChild(checkBtn);

            reviewContainer.appendChild(reviewBody);
            reviewContainer.appendChild(warnings);
            reviewContainer.appendChild(actions);

            // Insert after the textarea's parent form or input container
            const form = textarea.closest('form') || textarea.parentElement;
            if (form) {
                form.appendChild(reviewContainer);
            }

            /** Run the check. */
            const runCheck = () => {
                const text = textarea.value;
                if (!text.trim()) {
                    reviewContainer.classList.add('hidden');
                    return;
                }

                const letters = runes(text);
                const [badWords, badLetters] = findBadWords(letters);

                // Render the letter-by-letter review
                reviewBody.innerHTML = '';
                let wordFragment = document.createDocumentFragment();
                let hasLetters = false;

                for (let i = 0; i < letters.length; i++) {
                    const char = letters[i];
                    if (char === ' ') {
                        if (hasLetters) {
                            const wordDiv = document.createElement('div');
                            wordDiv.className = 'toolkit-motd-word';
                            wordDiv.appendChild(wordFragment);
                            reviewBody.appendChild(wordDiv);
                            wordFragment = document.createDocumentFragment();
                            hasLetters = false;
                        }
                        continue;
                    }
                    const letterDiv = document.createElement('div');
                    letterDiv.className = 'toolkit-motd-letter';
                    letterDiv.textContent = char;
                    if (badLetters.includes(i)) {
                        letterDiv.classList.add('offensive');
                    }
                    wordFragment.appendChild(letterDiv);
                    hasLetters = true;
                }
                if (hasLetters) {
                    const wordDiv = document.createElement('div');
                    wordDiv.className = 'toolkit-motd-word';
                    wordDiv.appendChild(wordFragment);
                    reviewBody.appendChild(wordDiv);
                }

                // Check for non-Latin characters (NT only allows Latin letters, numbers, standard punctuation)
                const invalidChars = [];
                const invalidPositions = new Set();
                for (let i = 0; i < letters.length; i++) {
                    const ch = letters[i];
                    // Allow Latin letters, digits, standard punctuation, whitespace
                    if (!/^[\x20-\x7E\n\r\t]+$/.test(ch)) {
                        invalidChars.push(ch);
                        invalidPositions.add(i);
                    }
                }

                // Mark invalid characters in the review
                invalidPositions.forEach(i => {
                    const els = reviewBody.querySelectorAll('.toolkit-motd-letter');
                    // Map index to element accounting for spaces
                    let elIdx = 0;
                    let letterCount = 0;
                    for (let j = 0; j <= i && elIdx < els.length; j++) {
                        if (letters[j] !== ' ') {
                            if (j === i) { els[elIdx].classList.add('invalid'); break; }
                            elIdx++;
                        }
                    }
                });

                // Show warnings
                const warningParts = [];
                if (invalidChars.length > 0) {
                    const unique = [...new Set(invalidChars)];
                    warningParts.push('<p>Contains characters not allowed by Nitro Type (only Latin letters, numbers, and standard punctuation):</p><ul>' +
                        unique.map(c => '<li>' + escapeHtml(c) + ' (U+' + c.codePointAt(0).toString(16).toUpperCase().padStart(4, '0') + ')</li>').join('') +
                        '</ul>');
                }
                if (badWords.length > 0) {
                    warningParts.push('<p>Possibly offensive words found:</p><ul>' +
                        badWords.map(w => '<li>' + escapeHtml(w) + '</li>').join('') +
                        '</ul>');
                }

                if (warningParts.length > 0) {
                    warnings.style.display = '';
                    warnings.innerHTML = warningParts.join('');
                } else {
                    warnings.style.display = 'none';
                }

                reviewContainer.classList.remove('hidden');
            };

            checkBtn.addEventListener('click', runCheck);

            // Live check as the user types (debounced)
            let debounceTimer = null;
            textarea.addEventListener('input', () => {
                clearTimeout(debounceTimer);
                debounceTimer = setTimeout(runCheck, 300);
            });

            // Also intercept NT's own error message about offensive content
            const inputAlert = modal.querySelector('.input-alert .bucket-content');
            if (inputAlert) {
                const errorObserver = new MutationObserver(([mutation]) => {
                    if (mutation.addedNodes.length === 0) return;
                    const errorNode = mutation.addedNodes[0];
                    if (errorNode.textContent && errorNode.textContent.startsWith('This contains words that are possibly offensive')) {
                        errorNode.textContent = 'Message contains possibly offensive content. Use the checker below to review.';
                        runCheck();
                    }
                });
                errorObserver.observe(inputAlert, { childList: true });
            }
        });
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 6: Appearance Toggles (CSS-based)
    // ─────────────────────────────────────────────────────────────────────────────
    const TOOLKIT_STYLE_ID = 'toolkit-appearance-styles';
    const SMART_NOTIFY_ATTR = 'data-toolkit-smart-notify';
    const CASH_MASK_ATTR = 'data-toolkit-hide-cash';
    const CASH_GIFT_MODAL_ATTR = 'data-toolkit-hidden-cash-gift';
    const CASH_GIFT_MODAL_DISPLAY_ATTR = 'data-toolkit-hidden-cash-gift-display';
    let cashMaskObserver = null;
    let cashGiftObserver = null;
    let toolkitGlobalUiRetryPollTimer = null;
    let toolkitGlobalUiRetryAttempts = 0;
    let toolkitGlobalUiFastSyncTimer = null;
    let toolkitBodyWaitObserver = null;

    function cleanupSmartShopNotify() {
        document.querySelectorAll('a[href="/shop"] .notify[' + SMART_NOTIFY_ATTR + ']').forEach((shopNotify) => {
            if (shopNotify.dataset.toolkitOriginalDisplay !== undefined) {
                shopNotify.style.display = shopNotify.dataset.toolkitOriginalDisplay;
            } else {
                shopNotify.style.removeProperty('display');
            }
            if (shopNotify.dataset.toolkitOriginalCount) {
                shopNotify.setAttribute('data-count', shopNotify.dataset.toolkitOriginalCount);
            } else {
                shopNotify.removeAttribute('data-count');
            }
            delete shopNotify.dataset.toolkitOriginalDisplay;
            delete shopNotify.dataset.toolkitOriginalCount;
            shopNotify.removeAttribute(SMART_NOTIFY_ATTR);
        });
    }

    function cleanupCashMaskTargets() {
        document.querySelectorAll('[' + CASH_MASK_ATTR + ']').forEach((node) => {
            node.removeAttribute(CASH_MASK_ATTR);
        });
    }

    function getModalHeaderText(modal) {
        const heading = modal?.querySelector('.modal-header h2, h2');
        return heading ? heading.textContent.trim() : '';
    }

    function getDirectCashMaskSelectors() {
        const selectors = [
            '.profile--content--current-cash .as-nitro-cash--prefix',
            '.page-shop--sidebar-cash-balance .as-nitro-cash--prefix',
            '.stat-box--details .as-nitro-cash--prefix',
            '.nt-cash-status.as-nitro-cash--prefix'
        ];
        if (readSetting('HIDE_CASH_TOTAL_SPENT')) {
            selectors.push('.stat-box--extra .as-nitro-cash--prefix');
        }
        return selectors;
    }

    function getCashMaskReplacementText() {
        const mode = readSetting('HIDE_CASH_MODE') || 'hidden';
        if (mode === 'redacted') return 'REDACTED';
        if (mode === 'stars') return '*******';
        if (mode === 'custom') {
            return (readSetting('HIDE_CASH_CUSTOM_TEXT') || '').replace(/\\/g, '\\\\').replace(/'/g, "\\'");
        }
        return '';
    }

    function shouldMaskSendCashBalanceNode(node, modal) {
        if (!node || !modal || node.hasAttribute('data-ntk-cash-preview')) return false;
        let current = node;
        let depth = 0;
        while (current && current !== modal && depth < 8) {
            const text = String(current.textContent || '').toLowerCase();
            if (text.includes('available')) return true;
            current = current.parentElement;
            depth += 1;
        }
        return false;
    }

    function markCashMaskTargets() {
        cleanupCashMaskTargets();
        if (!readSetting('HIDE_CASH_DISPLAY')) return;

        const selectors = getDirectCashMaskSelectors();

        selectors.forEach((selector) => {
            document.querySelectorAll(selector).forEach((node) => {
                node.setAttribute(CASH_MASK_ATTR, '1');
            });
        });

        document.querySelectorAll('.modal').forEach((modal) => {
            if (getModalHeaderText(modal) !== 'Send Cash') return;
            modal.querySelectorAll('.as-nitro-cash--prefix:not([data-ntk-cash-preview])').forEach((node) => {
                if (shouldMaskSendCashBalanceNode(node, modal)) {
                    node.setAttribute(CASH_MASK_ATTR, '1');
                }
            });
        });

        if (readSetting('HIDE_CASH_TOTAL_SPENT')) {
            document.querySelectorAll('.stat-box--extra .as-nitro-cash--prefix').forEach((node) => {
                node.setAttribute(CASH_MASK_ATTR, '1');
            });
        }
    }

    function syncEarlyCashMaskStyle() {
        const existing = document.getElementById(EARLY_CASH_MASK_STYLE_ID);
        if (!readSetting('HIDE_CASH_DISPLAY')) {
            existing?.remove();
            return;
        }

        const selectors = getDirectCashMaskSelectors();
        if (selectors.length === 0) {
            existing?.remove();
            return;
        }

        const mode = readSetting('HIDE_CASH_MODE') || 'hidden';
        const selectorList = selectors.join(', ');
        const rules = [];

        if (mode === 'hidden') {
            rules.push(selectorList + ' { visibility: hidden !important; }');
            rules.push('.profile--content--current-cash { display: none !important; }');
        } else {
            const replacementText = getCashMaskReplacementText();
            rules.push(selectorList + ' { font-size: 0 !important; }');
            rules.push(selectorList + '::after { content: \'' + replacementText + '\'; font-size: 1rem; }');
        }

        if (existing) {
            existing.textContent = rules.join('\n');
            return;
        }

        const style = document.createElement('style');
        style.id = EARLY_CASH_MASK_STYLE_ID;
        style.textContent = rules.join('\n');
        (document.head || document.documentElement).appendChild(style);
    }

    function restoreCashGiftModal(modal) {
        if (!modal?.hasAttribute(CASH_GIFT_MODAL_ATTR)) return;
        const originalDisplay = modal.getAttribute(CASH_GIFT_MODAL_DISPLAY_ATTR) || '';
        if (originalDisplay) {
            modal.style.setProperty('display', originalDisplay);
        } else {
            modal.style.removeProperty('display');
        }
        modal.removeAttribute(CASH_GIFT_MODAL_ATTR);
        modal.removeAttribute(CASH_GIFT_MODAL_DISPLAY_ATTR);
    }

    function cleanupCashGiftModals() {
        document.querySelectorAll('.modal[' + CASH_GIFT_MODAL_ATTR + ']').forEach(restoreCashGiftModal);
    }

    function syncEarlyCashGiftStyle() {
        const existing = document.getElementById(EARLY_CASH_GIFT_STYLE_ID);
        if (!readSetting('HIDE_CASH_GIFTS')) {
            existing?.remove();
            return;
        }
        if (existing) return;
        const style = document.createElement('style');
        style.id = EARLY_CASH_GIFT_STYLE_ID;
        style.textContent = '.growl.growl--cash { display: none !important; }';
        (document.head || document.documentElement).appendChild(style);
    }

    function syncEarlyFriendRequestStyle() {
        const existing = document.getElementById(EARLY_FRIEND_REQUEST_STYLE_ID);
        if (!readSetting('HIDE_FRIEND_REQUEST_POPUPS')) {
            existing?.remove();
            return;
        }
        const css = '.growl.growl--flag:has(a[href="/friends"]) { display: none !important; }';
        if (existing) {
            existing.textContent = css;
            return;
        }
        const style = document.createElement('style');
        style.id = EARLY_FRIEND_REQUEST_STYLE_ID;
        style.textContent = css;
        (document.head || document.documentElement).appendChild(style);
    }

    function syncEarlyFriendOnlineStyle() {
        const existing = document.getElementById(EARLY_FRIEND_ONLINE_STYLE_ID);
        if (!readSetting('HIDE_FRIEND_ONLINE_POPUPS')) {
            existing?.remove();
            return;
        }
        if (existing) {
            existing.textContent = HIDE_FRIEND_ONLINE_POPUP_CSS;
            return;
        }
        const style = document.createElement('style');
        style.id = EARLY_FRIEND_ONLINE_STYLE_ID;
        style.textContent = HIDE_FRIEND_ONLINE_POPUP_CSS;
        (document.head || document.documentElement).appendChild(style);
    }

    function syncEarlyRaceInviteStyle() {
        const existing = document.getElementById(EARLY_RACE_INVITE_STYLE_ID);
        if (!readSetting('HIDE_RACE_INVITE_POPUPS')) {
            existing?.remove();
            return;
        }
        const css = '.growl.growl--flag:has(a[href^="/race/"]) { display: none !important; }';
        if (existing) {
            existing.textContent = css;
            return;
        }
        const style = document.createElement('style');
        style.id = EARLY_RACE_INVITE_STYLE_ID;
        style.textContent = css;
        (document.head || document.documentElement).appendChild(style);
    }

    function syncEarlyHideAdsStyle() {
        const existing = document.getElementById(EARLY_HIDE_ADS_STYLE_ID);
        if (!readSetting('HIDE_ADS')) {
            existing?.remove();
            return;
        }

        if (existing) {
            existing.textContent = HIDE_ADS_BOOTSTRAP_CSS;
            return;
        }

        const style = document.createElement('style');
        style.id = EARLY_HIDE_ADS_STYLE_ID;
        style.textContent = HIDE_ADS_BOOTSTRAP_CSS;
        (document.head || document.documentElement).appendChild(style);
    }

    function syncCashGiftModals() {
        const shouldHide = !!readSetting('HIDE_CASH_GIFTS');
        document.querySelectorAll('.modal').forEach((modal) => {
            const isCashGiftModal = getModalHeaderText(modal) === "You've Got Cash";
            if (!isCashGiftModal) {
                restoreCashGiftModal(modal);
                return;
            }
            if (!shouldHide) {
                restoreCashGiftModal(modal);
                return;
            }
            if (modal.hasAttribute(CASH_GIFT_MODAL_ATTR)) return;
            modal.setAttribute(CASH_GIFT_MODAL_ATTR, '1');
            modal.setAttribute(CASH_GIFT_MODAL_DISPLAY_ATTR, modal.style.getPropertyValue('display') || '');
            modal.style.setProperty('display', 'none', 'important');
        });
    }

    function normalizeControlText(text) {
        return String(text || '').replace(/\s+/g, ' ').trim().toLowerCase();
    }

    function isNodeVisiblyRendered(node) {
        if (!node || !node.isConnected) return false;
        const style = getComputedStyle(node);
        if (style.display === 'none' || style.visibility === 'hidden') return false;
        return node.getClientRects().length > 0;
    }

    function hasVisibleGrowlNotifications() {
        return Array.from(document.querySelectorAll('.growl'))
            .some((node) => isNodeVisiblyRendered(node));
    }

    function restoreClearNotificationsButton(node) {
        if (!node?.hasAttribute?.(CLEAR_NOTIFICATIONS_ATTR)) return;
        const originalDisplay = node.getAttribute(CLEAR_NOTIFICATIONS_DISPLAY_ATTR) || '';
        if (originalDisplay) {
            node.style.setProperty('display', originalDisplay);
        } else {
            node.style.removeProperty('display');
        }
        node.removeAttribute(CLEAR_NOTIFICATIONS_ATTR);
        node.removeAttribute(CLEAR_NOTIFICATIONS_DISPLAY_ATTR);
    }

    function cleanupClearNotificationsButton() {
        document
            .querySelectorAll('[' + CLEAR_NOTIFICATIONS_ATTR + ']')
            .forEach((node) => restoreClearNotificationsButton(node));
    }

    function findClearNotificationsButtons() {
        const exactText = 'clear all notifications';
        const classMatches = Array.from(document.querySelectorAll('.growl-closeAll'));
        const textMatches = Array.from(document.querySelectorAll('button, a, [role="button"], .btn, div, span'))
            .filter((node) => normalizeControlText(node.textContent) === exactText)
            .map((node) => node.closest('button, a, [role="button"], .btn') || node);

        return [...classMatches, ...textMatches]
            .map((node) => node.closest('button, a, [role="button"], .btn') || node)
            .filter((node, index, list) => node && list.indexOf(node) === index);
    }

    function syncClearNotificationsButton() {
        if (hasVisibleGrowlNotifications()) {
            cleanupClearNotificationsButton();
            return;
        }

        findClearNotificationsButtons().forEach((node) => {
            if (node.hasAttribute(CLEAR_NOTIFICATIONS_ATTR)) return;
            node.setAttribute(CLEAR_NOTIFICATIONS_ATTR, '1');
            node.setAttribute(CLEAR_NOTIFICATIONS_DISPLAY_ATTR, node.style.getPropertyValue('display') || '');
            node.style.setProperty('display', 'none', 'important');
        });
    }

    function initCashGiftObserver() {
        if (cashGiftObserver || !document.body) return;
        cashGiftObserver = new MutationObserver(() => {
            try { syncCashGiftModals(); } catch { /* ignore */ }
        });
        cashGiftObserver.observe(document.body, {
            childList: true,
            subtree: true
        });
        syncCashGiftModals();
    }

    function initCashMaskObserver() {
        if (cashMaskObserver || !document.body) return;
        cashMaskObserver = new MutationObserver(() => {
            try { markCashMaskTargets(); } catch { /* ignore */ }
        });
        cashMaskObserver.observe(document.body, {
            childList: true,
            subtree: true
        });
        markCashMaskTargets();
    }

    /**
     * Smart Shop Notify: update the shop badge to show only unowned item count.
     * Hides the badge entirely if everything is owned.
     * Must run after NTGLOBALS is loaded and the nav badge is in the DOM.
     */
    function applySmartShopNotify() {
        const pw = (typeof unsafeWindow !== 'undefined' && unsafeWindow) ? unsafeWindow : window;
        const SHOP = pw.NTGLOBALS?.SHOP;
        if (!SHOP) return; // NTGLOBALS not loaded yet — will retry via poll/observer

        const shopNotify = document.querySelector('a[href="/shop"] .notify');
        if (!shopNotify) return; // Badge not in DOM yet — will retry

        // Don't re-process if we already handled this badge
        if (shopNotify.hasAttribute(SMART_NOTIFY_ATTR)) return;

        try {
            shopNotify.dataset.toolkitOriginalDisplay = shopNotify.style.display || '';
            shopNotify.dataset.toolkitOriginalCount = shopNotify.getAttribute('data-count') || '';
            const now = Math.floor(Date.now() / 1000);
            const currentDaily = SHOP.find(r => r.category === 'daily1' && r.startStamp <= now && r.expiration > now);
            const currentFeatured = SHOP.find(r => r.category === 'featured' && r.startStamp <= now && r.expiration > now);

            let ownedCarIDs = new Set();
            let ownedLootIDs = new Set();
            try {
                const persist = JSON.parse(localStorage.getItem('persist:nt'));
                const user = JSON.parse(persist.user);
                if (user.cars) user.cars.forEach(c => ownedCarIDs.add(c[0]));
                if (user.loot) user.loot.forEach(l => ownedLootIDs.add(l.lootID));
            } catch { /* ignore */ }

            const allItems = [
                ...(currentDaily?.items || []),
                ...(currentFeatured?.items || [])
            ];
            const unownedCount = allItems.filter(item => {
                if (item.type === 'car') return !ownedCarIDs.has(item.id);
                if (item.type === 'loot') return !ownedLootIDs.has(item.id);
                return false;
            }).length;

            shopNotify.setAttribute(SMART_NOTIFY_ATTR, '1');

            if (unownedCount === 0) {
                shopNotify.style.display = 'none';
            } else {
                shopNotify.setAttribute('data-count', unownedCount);
            }
        } catch (e) {
            console.warn(TOOLKIT_LOG_PREFIX, 'Smart shop notify error:', e.message);
        }
    }

    function applyAppearanceStyles() {
        // Remove existing toolkit style block to rebuild
        const existing = document.getElementById(TOOLKIT_STYLE_ID);
        if (existing) existing.remove();

        syncEarlyCashGiftStyle();
        syncEarlyCashMaskStyle();
        syncEarlyFriendRequestStyle();
        syncEarlyFriendOnlineStyle();
        syncEarlyRaceInviteStyle();
        syncEarlyHideAdsStyle();
        markCashMaskTargets();
        syncCashGiftModals();

        const rules = [];

        if (readSetting('HIDE_SEASON_BANNER')) rules.push('.seasonTeaser { display: none !important; }');
        if (readSetting('HIDE_ADS')) {
            rules.push(getHideAdsCSS());
        }
        if (readSetting('HIDE_FOOTER')) rules.push('footer { display: none !important; }');
        if (readSetting('HIDE_BUY_CASH')) rules.push('.profile--content--current-cash .bucket-media { display: none !important; }');
        if (readSetting('HIDE_NOTIFY_ALL')) {
            rules.push('.notify { display: none !important; }');
        } else {
            const notifyPages = [
                ['HIDE_NOTIFY_SHOP', 'shop'],
                ['HIDE_NOTIFY_FRIENDS', 'friends'],
                ['HIDE_NOTIFY_TEAM', 'team', true],
                ['HIDE_NOTIFY_NEWS', 'news'],
                ['HIDE_NOTIFY_ACHIEVEMENTS', 'achievements']
            ];
            notifyPages.forEach(([key, page, startsWith]) => {
                if (readSetting(key)) {
                    const sel = startsWith
                        ? 'a[href^="/' + page + '"] .notify'
                        : 'a[href="/' + page + '"] .notify';
                    rules.push(sel + ' { display: none !important; }');
                }
            });

            // Smart Shop Notify: CSS fallback to hide badge if JS hasn't run yet
            if (!readSetting('HIDE_NOTIFY_SHOP') && readSetting('SMART_SHOP_NOTIFY')) {
                applySmartShopNotify();
            } else {
                cleanupSmartShopNotify();
            }
        }

        if (readSetting('HIDE_CASH_GIFTS')) {
            rules.push('.growl.growl--cash { display: none !important; }');
        }

        if (readSetting('HIDE_FRIEND_REQUEST_POPUPS')) {
            rules.push('.growl.growl--flag:has(a[href="/friends"]) { display: none !important; }');
        }

        if (readSetting('HIDE_FRIEND_ONLINE_POPUPS')) {
            rules.push(HIDE_FRIEND_ONLINE_POPUP_CSS);
        }

        if (readSetting('HIDE_RACE_INVITE_POPUPS')) {
            rules.push('.growl.growl--flag:has(a[href^="/race/"]) { display: none !important; }');
        }

        if (readSetting('HIDE_RACE_STICKERS')) {
            rules.push('.raceChat-pickers .raceChat-picker--sticker { display: none !important; }');
            rules.push('.raceChat-bubbles .raceChat-bubble--container:has(.raceChat-bubble--image:not([style*="/dist/site/images/chat/canned/"])) { display: none !important; }');
        }

        if (readSetting('HIDE_CASH_DISPLAY')) {
            const mode = readSetting('HIDE_CASH_MODE') || 'hidden';
            if (mode === 'hidden') {
                rules.push('[' + CASH_MASK_ATTR + '="1"] { visibility: hidden !important; }');
                // Hide the entire cash section on garage/profile when showing nothing
                rules.push('.profile--content--current-cash { display: none !important; }');
            } else {
                rules.push('[' + CASH_MASK_ATTR + '="1"] { font-size: 0 !important; }');
                const replacementText = getCashMaskReplacementText();
                rules.push('[' + CASH_MASK_ATTR + '="1"]::after { content: \'' + replacementText + '\'; font-size: 1rem; }');
                rules.push('[' + CASH_MASK_ATTR + '="1"] [' + CASH_MASK_ATTR + '="1"]::after { content: none !important; }');
            }
        }

        if (readSetting('HIDE_ALT_LOGINS')) {
            rules.push('.split.split--divided > :not(:last-child) { display: none !important; }');
            rules.push('.race-results--qualifying--signup > :not(.race-results--qualifying--form) { display: none !important; }');
        }

        if (rules.length === 0) return;

        const style = document.createElement('style');
        style.id = TOOLKIT_STYLE_ID;
        style.textContent = rules.join('\n');
        (document.head || document.documentElement).appendChild(style);
    }

    function getHideAdsCSS() {
        return HIDE_ADS_BOOTSTRAP_CSS;
    }



    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 12: Garage Rearrange Tools + Customizer Shuffle (Toolkit port)
    // ─────────────────────────────────────────────────────────────────────────────
    const garageToolsModule = (function createGarageToolsModule() {
    'use strict';

    var pageWindow = (typeof unsafeWindow !== 'undefined' && unsafeWindow) ? unsafeWindow : window;
    var pageDocument = pageWindow.document || document;
    var LOG_PREFIX = '[TOOLKIT:Garage]';
    var SINGLETON_KEY = '__ntGarageOrganizerExperimentalSingleton';
    var API_KEY = 'NTGarageOrganizerExperimental';
    var STYLE_ID = 'ntgo-garage-organizer-style';
    var SVG_NS = 'http://www.w3.org/2000/svg';
    var SLOT_CLASS = 'ntgo-slot';
    var SLOT_NUMBER_CLASS = 'ntgo-slot-number';
    var SECTION_LABEL_CLASS = 'ntgo-section-label';
    var SELECT_BUTTON_CLASS = 'ntgo-select-button';
    var SELECTED_CLASS = 'ntgo-selected';
    var SOURCE_CLASS = 'ntgo-source';
    var TARGET_CLASS = 'ntgo-target';
    var EMPTY_TARGET_CLASS = 'ntgo-empty-target';
    var PULSE_CLASS = 'ntgo-pulse';
    var TOOLBAR_CLASS = 'ntgo-toolbar';
    var RESULT_CLASS = 'ntgo-result';
    var INSERT_MARKER_CLASS = 'ntgo-insert-marker';
    var EXPORT_BUTTON_CLASS = 'ntgo-profile-export-button';
    var GARAGE_REARRANGING_BODY_CLASS = 'ntgo-garage-rearranging';
    var SHUFFLE_CONTROLS_CLASS = 'ntgo-shuffle-controls';
    var SHUFFLE_CONTROLS_HOST_CLASS = 'ntgo-shuffle-controls-host';
    var SHUFFLE_BUTTON_CLASS = 'ntgo-shuffle-button';
    var SHUFFLE_POOL_BUTTON_CLASS = 'ntgo-shuffle-pool-button';
    var SHUFFLE_TOGGLE_CLASS = 'ntgo-shuffle-toggle';
    var SHUFFLE_MODE_PREVIEW_CLASS = 'ntgo-shuffle-mode-preview';
    var SHUFFLE_MODE_POOL_CLASS = 'ntgo-shuffle-mode-pool';
    var SHUFFLE_PREVIEW_TOOLS_CLASS = 'ntgo-shuffle-preview-tools';
    var SHUFFLE_POOL_TOOLS_CLASS = 'ntgo-shuffle-pool-tools';
    var SHUFFLE_POOL_SELECTED_CLASS = 'ntgo-shuffle-pool-selected';
    var SHUFFLE_POOL_MODE_CLASS = 'ntgo-shuffle-pool-mode';
    var SHUFFLE_POOL_PREVIEW_CLASS = 'ntgo-shuffle-pool-preview';
    var SHUFFLE_POOL_PREVIEW_GRID_CLASS = 'ntgo-shuffle-pool-preview-grid';
    var SHUFFLE_POOL_PREVIEW_ITEM_CLASS = 'ntgo-shuffle-pool-preview-item';
    var SHUFFLE_POOL_PREVIEW_EMPTY_CLASS = 'ntgo-shuffle-pool-preview-empty';
    var SHUFFLE_POOL_PREVIEW_REMOVE_CLASS = 'ntgo-shuffle-pool-preview-remove';
    var EQUIP_SOUND_URL = '/dist/site/misc/sounds/global/ogg/swoosh.ogg';
    var AUTO_SHUFFLE_STORAGE_KEY = 'ntgoAutoShuffle';
    var AUTO_SHUFFLE_TYPE_STORAGE_KEY = 'ntgoAutoShuffleType';
    var AUTO_SHUFFLE_LAST_SESSION_RACES_KEY = 'ntgoAutoShuffleLastSessionRaces';
    var AUTO_SHUFFLE_RACE_DELAY_MS = 1000;
    var SHUFFLE_POOL_STORAGE_KEY = 'ntgoShufflePool';
    var SHUFFLE_POOL_ORDER_STORAGE_KEY = 'ntgoShufflePoolOrder';
    var SHUFFLE_POOL_CYCLE_MODE_STORAGE_KEY = 'ntgoShufflePoolCycleMode';
    var SHUFFLE_POOL_ORDER_INDEX_STORAGE_KEY = 'ntgoShufflePoolOrderIndex';
    var NO_TRAIL_VALUE = '0';
    var SHUFFLE_POOL_SNAPSHOT_STORAGE_KEY = 'ntgoShufflePoolSnapshot';
    var TOOLBAR_ORIENTATION_STORAGE_KEY = 'ntgoToolbarOrientation';
    var DEBUG_VISUAL_HOOK_KEY = 'ntgoDebugVisualHook';
    var MAX_SEARCH_RESULTS = 8;
    var MAX_UNDO_HISTORY = 5;
    var INSERT_EDGE_PX = 12;
    var SLOTS_PER_SECTION = 30;
    var TOOLBAR_DOCK_ORIENTATIONS = ['bottom', 'top', 'left', 'right'];
    var TOOLBAR_DOCK_DRAG_THRESHOLD_PX = 8;
    var RARITY_RANKS = {
        common: 1,
        uncommon: 2,
        rare: 3,
        epic: 4,
        legendary: 5,
        admin: 6
    };

    function getToolkitGarageDataStorageKey(legacyKey) {
        return NTCFG_VALUE_PREFIX + 'GARAGE_TOOLS:' + String(legacyKey || '');
    }

    function writeToolkitGarageStorageRaw(legacyKey, value) {
        var raw = value == null ? '' : String(value);
        var storageKey = getToolkitGarageDataStorageKey(legacyKey);
        try {
            if (typeof writeCanonicalValue === 'function') writeCanonicalValue(storageKey, raw);
        } catch (e) { }
        try {
            pageWindow.localStorage.setItem(storageKey, JSON.stringify(raw));
        } catch (e) { }
    }

    function readToolkitGarageStorageRaw(legacyKey) {
        var storageKey = getToolkitGarageDataStorageKey(legacyKey);
        var canonical;
        var raw;
        var parsed;
        try {
            if (typeof readCanonicalValue === 'function') {
                canonical = readCanonicalValue(storageKey);
                if (canonical !== undefined) return String(canonical);
            }
        } catch (e) { }
        try {
            raw = pageWindow.localStorage.getItem(storageKey);
            if (raw != null) {
                try {
                    parsed = JSON.parse(raw);
                    return parsed == null ? '' : String(parsed);
                } catch (e) {
                    return String(raw);
                }
            }
        } catch (e) { }
        try {
            raw = pageWindow.localStorage.getItem(legacyKey);
            if (raw != null) {
                writeToolkitGarageStorageRaw(legacyKey, raw);
                return String(raw);
            }
        } catch (e) { }
        return null;
    }

    if (pageWindow[API_KEY] && !pageWindow[API_KEY].toolkitOwned) {
        try { console.warn(LOG_PREFIX + ' Standalone Garage Organizer is already running; Toolkit garage tools skipped.'); } catch (e) { }
        return { external: true, start: function () { return false; }, sync: function () { return false; }, stop: function () { }, refresh: function () { } };
    }
    if (pageWindow[SINGLETON_KEY] && !(pageWindow[API_KEY] && pageWindow[API_KEY].toolkitOwned)) {
        try { console.warn(LOG_PREFIX + ' Standalone Garage Organizer singleton detected; Toolkit garage tools skipped.'); } catch (e) { }
        return { external: true, start: function () { return false; }, sync: function () { return false; }, stop: function () { }, refresh: function () { } };
    }
    pageWindow[SINGLETON_KEY] = true;

    var state = {
        started: false,
        active: false,
        garage: null,
        toolbar: null,
        statusNode: null,
        searchInput: null,
        searchResults: null,
        searchMatches: [],
        moveInput: null,
        moveSectionInput: null,
        moveSectionSlotInput: null,
        insertInput: null,
        sortSelect: null,
        sortGapsInput: null,
        rangeInput: null,
        sectionInput: null,
        importFileInput: null,
        applyButton: null,
        clearButton: null,
        undoButton: null,
        previewNode: null,
        selectionNode: null,
        observer: null,
        carCatalog: null,
        lootCatalog: null,
        activePreviewReactCtx: null,
        customizerShuffleControls: null,
        customizerShufflePositionHandler: null,
        customizerPoolPreview: null,
        customizerPoolFilter: '',
        customizerPoolSort: 'pool',
        customizerPoolMode: false,
        customizerPoolType: null,
        customizerPoolDrag: null,
        customizerPoolSuppressClickUntil: 0,
        customizerTabSwitchTimer: 0,
        autoShuffleSessionTimer: 0,
        refreshTimer: 0,
        targetTimer: 0,
        sourceSlot: null,
        targetSlot: null,
        insertTarget: null,
        insertMarker: null,
        selectedKeys: {},
        focusedSection: null,
        blockDrag: null,
        syntheticDragDepth: 0,
        preview: null,
        applying: false,
        dirty: false,
        directApplying: false,
        normalEquipApplying: false,
        lastEquippedCarID: null,
        cancelRequested: false,
        undoHistory: [],
        operationUndoCaptured: false,
        restoringUndo: false,
        currentActionLabel: '',
        toolbarMode: 'select',
        toolbarOrientation: 'bottom',
        toolbarDockDrag: null,
        statusTooltipNode: null,
        lastSyncPath: ''
    };

    function logInfo() {
        try { console.info.apply(console, [LOG_PREFIX].concat(Array.prototype.slice.call(arguments))); } catch (e) { }
    }

    function logWarn() {
        try { console.warn.apply(console, [LOG_PREFIX].concat(Array.prototype.slice.call(arguments))); } catch (e) { }
    }

    function debugVisualHookLog(type, data) {
        var logs;
        if (readToolkitGarageStorageRaw(DEBUG_VISUAL_HOOK_KEY) !== '1') return;
        try {
            logs = JSON.parse(readToolkitGarageStorageRaw(DEBUG_VISUAL_HOOK_KEY + ':logs') || '[]');
        } catch (e) {
            logs = [];
        }
        logs.push({
            t: new Date().toISOString(),
            type: type,
            href: pageWindow.location.href,
            data: data || {}
        });
        if (logs.length > 300) logs = logs.slice(-300);
        try {
            writeToolkitGarageStorageRaw(DEBUG_VISUAL_HOOK_KEY + ':logs', JSON.stringify(logs));
        } catch (e) { }
        try { console.debug(LOG_PREFIX, 'visual hook', type, data || {}); } catch (e) { }
    }

    function getDebugNodeSummary(node) {
        if (!node || node.nodeType !== 1) return null;
        return {
            tag: node.tagName,
            className: String(node.className || '').slice(0, 200),
            id: String(node.id || ''),
            text: normalizeText(node.textContent).slice(0, 140),
            style: String(node.getAttribute('style') || '').slice(0, 260),
            src: String(node.currentSrc || node.src || node.getAttribute('src') || '').slice(0, 260)
        };
    }

    function snapshotActivePreview(label) {
        var preview = pageDocument.querySelector('.profile--active-car--preview, .animated-car-preview');
        var canvas = preview && preview.querySelector('canvas');
        var name = pageDocument.querySelector('.profile--active-car--car-name');
        var profile = pageDocument.querySelector('.profile');
        debugVisualHookLog(label || 'active-preview:snapshot', {
            preview: getDebugNodeSummary(preview),
            canvas: getDebugNodeSummary(canvas),
            name: name ? normalizeText(name.textContent) : '',
            profileClass: profile ? String(profile.className || '') : ''
        });
    }

    function installDebugVisualHook() {
        var observer;
        var originalPlay;
        if (readToolkitGarageStorageRaw(DEBUG_VISUAL_HOOK_KEY) !== '1') return;
        if (pageWindow.__ntgoDebugVisualHookInstalled) return;
        pageWindow.__ntgoDebugVisualHookInstalled = true;
        pageWindow.__ntgoDumpVisualHook = function () {
            try {
                return JSON.parse(readToolkitGarageStorageRaw(DEBUG_VISUAL_HOOK_KEY + ':logs') || '[]');
            } catch (e) {
                return [];
            }
        };
        pageWindow.__ntkGarageDumpVisualHook = pageWindow.__ntgoDumpVisualHook;

        debugVisualHookLog('hook:installed', {
            title: pageDocument.title,
            userKeys: (function () {
                var bundle = readPersistedUserState();
                return bundle && bundle.user ? Object.keys(bundle.user).slice(0, 80) : [];
            }())
        });
        snapshotActivePreview('active-preview:initial');

        try {
            originalPlay = pageWindow.HTMLMediaElement && pageWindow.HTMLMediaElement.prototype.play;
            if (originalPlay && !pageWindow.__ntgoDebugVisualHookPatchedPlay) {
                pageWindow.__ntgoDebugVisualHookPatchedPlay = true;
                pageWindow.HTMLMediaElement.prototype.play = function () {
                    debugVisualHookLog('audio:play', { src: String(this.currentSrc || this.src || '') });
                    return originalPlay.apply(this, arguments);
                };
            }
        } catch (e) { }

        observer = new MutationObserver(function (mutations) {
            mutations.forEach(function (mutation) {
                var target = mutation.target;
                var interesting = target && target.nodeType === 1 && (
                    target.closest('.profile--active-car') ||
                    target.closest('.animated-car-preview') ||
                    target.closest('.profile') ||
                    target.matches('.profile--active-car--car-name, canvas')
                );
                if (!interesting) return;
                if (mutation.type === 'attributes') {
                    debugVisualHookLog('mutation:attr', {
                        attr: mutation.attributeName,
                        target: getDebugNodeSummary(target)
                    });
                } else if (mutation.type === 'childList') {
                    debugVisualHookLog('mutation:childList', {
                        target: getDebugNodeSummary(target),
                        added: Array.prototype.slice.call(mutation.addedNodes || []).map(getDebugNodeSummary).filter(Boolean).slice(0, 6),
                        removed: Array.prototype.slice.call(mutation.removedNodes || []).map(getDebugNodeSummary).filter(Boolean).slice(0, 6)
                    });
                    snapshotActivePreview('active-preview:after-childList');
                }
            });
        });
        if (pageDocument.body) {
            observer.observe(pageDocument.body, {
                subtree: true,
                childList: true,
                attributes: true,
                attributeFilter: ['class', 'style', 'src', 'width', 'height', 'mode']
            });
        }
        pageWindow.setTimeout(function () { snapshotActivePreview('active-preview:after-1s'); }, 1000);
        pageWindow.setTimeout(function () { snapshotActivePreview('active-preview:after-3s'); }, 3000);
    }

    function isGaragePage() {
        return /^\/garage(?:\/|$)/.test(pageWindow.location.pathname || '');
    }

    function isGarageRoute() {
        return /^\/garage(?:\/|$)/.test(pageWindow.location.pathname || '') ||
            /^\/racer\/[^/]+(?:\/|$)/.test(pageWindow.location.pathname || '') ||
            /^\/race(?:\/|$)/.test(pageWindow.location.pathname || '');
    }

    function isRacerProfilePage() {
        return /^\/racer\/[^/]+(?:\/|$)/.test(pageWindow.location.pathname || '');
    }

    function isRacePage() {
        return /^\/race(?:\/|$)/.test(pageWindow.location.pathname || '');
    }

    function isCustomizerPage() {
        return /^\/garage\/customizer(?:\/|$)/.test(pageWindow.location.pathname || '');
    }

    function getGarageToolsPathKey() {
        return String(pageWindow.location.pathname || '').replace(/\/+$/, '') || '/';
    }

    function getGarageRoot() {
        return pageDocument.querySelector('.garage');
    }

    function isRearranging() {
        var garage = getGarageRoot();
        return !!(garage && garage.classList.contains('is-rearranging'));
    }

    function getSlots() {
        var garage = state.garage || getGarageRoot();
        return garage ? Array.prototype.slice.call(garage.querySelectorAll('.garage-spot')) : [];
    }

    function getSlotIndex(slot) {
        var raw = slot && slot.getAttribute('data-ntgo-slot-index');
        var index = raw == null ? NaN : parseInt(raw, 10);
        if (!isNaN(index)) return index;
        return getSlots().indexOf(slot);
    }

    function getVehicle(slot) {
        return slot ? slot.querySelector('.garage-vehicle') : null;
    }

    function normalizeText(value) {
        return String(value || '').replace(/\s+/g, ' ').trim();
    }

    function normalizeRarity(value) {
        var label;
        if (value && typeof value === 'object') {
            label = value.name || value.title || value.label || value.type || value.value || '';
        } else {
            label = value;
        }
        return normalizeText(label);
    }

    function normalizeCategory(value) {
        var label;
        if (value && typeof value === 'object') {
            label = value.name || value.title || value.label || value.category || value.group || value.value || '';
        } else {
            label = value;
        }
        return normalizeText(label);
    }

    function getRarityRank(value) {
        var label = normalizeRarity(value);
        var numeric = Number(label);
        var key;
        if (label && isFinite(numeric)) return numeric + 1;
        key = label.toLowerCase().replace(/[^a-z0-9]/g, '');
        return RARITY_RANKS[key] || 0;
    }

    function getSourceFileName(src) {
        var cleanSrc = String(src || '').split('?')[0].split('#')[0];
        try {
            cleanSrc = decodeURIComponent(cleanSrc);
        } catch (e) { }
        return cleanSrc.split('/').pop() || '';
    }

    function getCarIdFromSource(src) {
        var fileName = getSourceFileName(src);
        var numericMatch = fileName.match(/^(\d+)(?:_|\.|$)/);
        var slugMatch = fileName.match(/^(.+?)(?:_small|_large|\.png|$)/);
        return {
            id: numericMatch ? numericMatch[1] : '',
            fileName: fileName,
            slug: slugMatch && slugMatch[1] ? slugMatch[1] : fileName.replace(/\.[^.]+$/, '')
        };
    }

    function readBootstrapCars() {
        var bootstrapData;
        var i;
        var key;
        var payload;

        try {
            if (pageWindow.NTGLOBALS && Array.isArray(pageWindow.NTGLOBALS.CARS) && pageWindow.NTGLOBALS.CARS.length) {
                return pageWindow.NTGLOBALS.CARS;
            }
        } catch (e) { }

        try {
            if (typeof pageWindow.NTBOOTSTRAP === 'function') {
                bootstrapData = pageWindow.NTBOOTSTRAP();
                if (Array.isArray(bootstrapData)) {
                    for (i = 0; i < bootstrapData.length; i += 1) {
                        if (Array.isArray(bootstrapData[i]) && bootstrapData[i][0] === 'CARS') {
                            return Array.isArray(bootstrapData[i][1]) ? bootstrapData[i][1] : [];
                        }
                    }
                }
            }
        } catch (e) { }

        try {
            payload = [];
            var cachedMap = JSON.parse(pageWindow.localStorage.getItem('ntCarDataMap') || '{}');
            Object.keys(cachedMap || {}).forEach(function (carID) {
                if (!cachedMap[carID]) return;
                payload.push({
                    carID: carID,
                    options: { smallSrc: cachedMap[carID] }
                });
            });
            if (payload.length) return payload;
        } catch (e) { }

        try {
            key = pageDocument.querySelector('script[src*="/bootstrap.js"]');
            if (!key || !key.src || !pageWindow.XMLHttpRequest) return [];

            var xhr = new pageWindow.XMLHttpRequest();
            xhr.open('GET', key.src, false);
            xhr.send(null);
            if (xhr.status < 200 || xhr.status >= 300 || !xhr.responseText) return [];

            payload = [];
            var regex = /"carID":(\d+)[\s\S]{0,900}?"smallSrc":"([^"]+)"/g;
            var match = null;
            while ((match = regex.exec(xhr.responseText)) !== null) {
                payload.push({
                    carID: match[1],
                    options: { smallSrc: match[2] }
                });
            }
            return payload;
        } catch (e) {
            logWarn('Car bootstrap lookup failed', e && e.message ? e.message : e);
        }

        return [];
    }

    function addCatalogSource(catalog, entry, src) {
        var sourceInfo;
        var fullSrc;
        if (!src) return;
        sourceInfo = getCarIdFromSource(src);
        fullSrc = String(src);
        catalog.bySource[fullSrc] = entry;
        if (sourceInfo.fileName) catalog.byFile[sourceInfo.fileName.toLowerCase()] = entry;
        if (sourceInfo.slug) catalog.bySlug[sourceInfo.slug.toLowerCase()] = entry;
    }

    function buildCarCatalog() {
        var catalog = { byID: {}, byFile: {}, bySlug: {}, bySource: {}, byName: {} };
        var cars = readBootstrapCars();

        cars.forEach(function (car) {
            var options = car && car.options ? car.options : {};
            var carID = String(car && (car.carID || car.id || car.car_id) || '').trim();
            var name = normalizeText(car && (car.name || car.title || car.displayName));
            var rarity = normalizeRarity(car && (car.rarityName || car.rarityTitle || car.rarity || car.rarityID || car.rarity_id || options.rarity));
            var category = normalizeCategory(car && (
                car.categoryName ||
                car.categoryTitle ||
                car.category ||
                car.groupName ||
                car.group ||
                car.collectionName ||
                car.collection ||
                car.eventName ||
                car.event ||
                car.seasonName ||
                car.season ||
                options.categoryName ||
                options.categoryTitle ||
                options.category ||
                options.group ||
                options.collection ||
                options.event ||
                options.season
            ));
            var entry;
            if (!carID) return;

            entry = {
                carID: carID,
                name: name,
                rarity: rarity,
                rarityRank: getRarityRank(rarity),
                category: category,
                smallSrc: options.smallSrc || options.small_src || '',
                largeSrc: options.largeSrc || options.large_src || ''
            };

            catalog.byID[carID] = entry;
            if (name) catalog.byName[name.toLowerCase()] = entry;
            addCatalogSource(catalog, entry, entry.smallSrc);
            addCatalogSource(catalog, entry, entry.largeSrc);
            if (entry.smallSrc) addCatalogSource(catalog, entry, '/cars/' + entry.smallSrc);
            if (entry.largeSrc) addCatalogSource(catalog, entry, '/cars/' + entry.largeSrc);
        });

        return catalog;
    }

    function getCarCatalog() {
        if (!state.carCatalog) {
            state.carCatalog = buildCarCatalog();
        }
        return state.carCatalog;
    }

    function readBootstrapLoot() {
        var bootstrapData;
        var i;
        try {
            if (pageWindow.NTGLOBALS && Array.isArray(pageWindow.NTGLOBALS.LOOT) && pageWindow.NTGLOBALS.LOOT.length) {
                return pageWindow.NTGLOBALS.LOOT;
            }
        } catch (e) { }
        try {
            if (typeof pageWindow.NTBOOTSTRAP === 'function') {
                bootstrapData = pageWindow.NTBOOTSTRAP();
                if (Array.isArray(bootstrapData)) {
                    for (i = 0; i < bootstrapData.length; i += 1) {
                        if (Array.isArray(bootstrapData[i]) && bootstrapData[i][0] === 'LOOT') {
                            return Array.isArray(bootstrapData[i][1]) ? bootstrapData[i][1] : [];
                        }
                    }
                }
            }
        } catch (e) { }
        return [];
    }

    function getLootOptionSource(loot) {
        var options = loot && loot.options ? loot.options : {};
        return (
            options.src ||
            options.smallSrc ||
            options.small_src ||
            options.largeSrc ||
            options.large_src ||
            loot && (loot.src || loot.smallSrc || loot.small_src || loot.assetKey) ||
            ''
        );
    }

    function addLootCatalogSource(catalog, entry, src) {
        var fileName;
        var fullSrc;
        if (!src) return;
        fullSrc = String(src);
        fileName = getSourceFileName(fullSrc).toLowerCase();
        catalog.bySource[fullSrc] = entry;
        if (fileName) catalog.byFile[fileName] = entry;
        if (entry.type && fileName) catalog.byTypeFile[entry.type + ':' + fileName] = entry;
    }

    function buildLootCatalog() {
        var catalog = { byID: {}, byName: {}, bySource: {}, byFile: {}, byTypeFile: {} };
        var seen = {};
        function addLoot(loot) {
            var options = loot && loot.options ? loot.options : {};
            var lootID = String(loot && (loot.lootID || loot.id || loot.loot_id) || '').trim();
            var type = String(loot && loot.type || '').trim();
            var name = normalizeText(loot && (loot.name || loot.title || loot.displayName));
            var source = getLootOptionSource(loot);
            var entry;
            if (!lootID || !type || seen[lootID]) return;
            seen[lootID] = true;
            entry = {
                lootID: lootID,
                type: type,
                name: name,
                src: source,
                assetKey: loot && loot.assetKey || '',
                rarity: options.rarity || loot && loot.rarity || ''
            };
            catalog.byID[lootID] = entry;
            if (name) {
                catalog.byName[name.toLowerCase()] = entry;
                catalog.byName[type + ':' + name.toLowerCase()] = entry;
            }
            addLootCatalogSource(catalog, entry, source);
            addLootCatalogSource(catalog, entry, entry.assetKey);
        }

        readBootstrapLoot().forEach(addLoot);
        try {
            ((readPersistedUserState() || {}).user || {}).loot.forEach(addLoot);
        } catch (e) { }
        return catalog;
    }

    function getLootCatalog() {
        if (!state.lootCatalog) {
            state.lootCatalog = buildLootCatalog();
        }
        return state.lootCatalog;
    }

    function resolveLootCatalogEntry(src, name, type) {
        var catalog = getLootCatalog();
        var fileName = getSourceFileName(src).toLowerCase();
        var normalizedName = normalizeText(name).toLowerCase();
        return (
            (fileName && catalog.byTypeFile[String(type) + ':' + fileName]) ||
            catalog.bySource[String(src || '')] ||
            (fileName ? catalog.byFile[fileName] : null) ||
            (normalizedName ? catalog.byName[String(type) + ':' + normalizedName] : null) ||
            (normalizedName ? catalog.byName[normalizedName] : null) ||
            null
        );
    }

    function resolveCatalogEntry(src, name, sourceInfo) {
        var catalog = getCarCatalog();
        var fileName = (sourceInfo && sourceInfo.fileName ? sourceInfo.fileName : getSourceFileName(src)).toLowerCase();
        var slug = (sourceInfo && sourceInfo.slug ? sourceInfo.slug : '').toLowerCase();
        var normalizedName = normalizeText(name).toLowerCase();
        return (
            catalog.bySource[String(src || '')] ||
            (fileName ? catalog.byFile[fileName] : null) ||
            (slug ? catalog.bySlug[slug] : null) ||
            (normalizedName ? catalog.byName[normalizedName] : null) ||
            null
        );
    }


    function getCarInfo(slot) {
        var index = getSlotIndex(slot);
        var vehicle = getVehicle(slot);
        var image = vehicle ? vehicle.querySelector('img, .garage-vehichleImage, .garage-vehicleImage, [data-tip]') : null;
        var backgroundImage = '';
        var styleImageMatch;
        var name = normalizeText(
            (image && (image.getAttribute('data-tip') || image.getAttribute('alt') || image.getAttribute('title'))) ||
            (vehicle && (vehicle.getAttribute('data-tip') || vehicle.getAttribute('title'))) ||
            ''
        );
        var src = image ? String(image.currentSrc || image.src || image.getAttribute('src') || '') : '';
        if (!src && image) {
            backgroundImage = String(image.style && image.style.backgroundImage || '');
            if (!backgroundImage && pageWindow.getComputedStyle) {
                try {
                    backgroundImage = String(pageWindow.getComputedStyle(image).backgroundImage || '');
                } catch (e) { }
            }
            styleImageMatch = backgroundImage.match(/url\((?:["']?)(.*?)(?:["']?)\)/i);
            if (styleImageMatch && styleImageMatch[1]) {
                src = styleImageMatch[1];
            }
        }
        var isEmpty = !slot || slot.classList.contains('is-empty') || !vehicle || (!name && !src);
        var carSource = getCarIdFromSource(src);
        var catalogEntry = isEmpty ? null : resolveCatalogEntry(src, name, carSource);
        var key = isEmpty ? '' : [src, name].join('::');

        return {
            slot: slot,
            index: index,
            number: index + 1,
            vehicle: vehicle,
            image: image,
            name: name || (catalogEntry && catalogEntry.name) || (isEmpty ? 'No Car Found' : 'Unnamed Car'),
            src: src,
            carID: (catalogEntry && catalogEntry.carID) || carSource.id,
            rarity: (catalogEntry && catalogEntry.rarity) || '',
            rarityRank: catalogEntry && catalogEntry.rarityRank ? catalogEntry.rarityRank : 0,
            category: (catalogEntry && catalogEntry.category) || '',
            carSlug: carSource.slug,
            key: key,
            isEmpty: isEmpty
        };
    }

    function getLiveToken() {
        var token = String(pageWindow.localStorage.getItem('player_token') || '').trim();
        if (!token) return null;
        try {
            var payload = JSON.parse(atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')));
            if (payload.exp && payload.exp < Date.now() / 1000) return null;
        } catch (e) { /* not a standard JWT or missing exp — allow */ }
        return token;
    }

    function readPersistedUserState() {
        var raw;
        var persist;
        var user;
        try {
            raw = pageWindow.localStorage.getItem('persist:nt');
            if (!raw) return null;
            persist = JSON.parse(raw);
            user = JSON.parse(persist.user || '{}');
            return { persist: persist, user: user };
        } catch (e) {
            logWarn('Unable to read Nitro Type user state', e && e.message ? e.message : e);
        }
        return null;
    }

    function patchPersistedUserFields(fieldUpdater) {
        var raw;
        var persist;
        var user;
        try {
            raw = pageWindow.localStorage.getItem('persist:nt');
            if (!raw) return;
            persist = JSON.parse(raw);
            user = JSON.parse(persist.user || '{}');
            fieldUpdater(user);
            persist.user = JSON.stringify(user);
            pageWindow.localStorage.setItem('persist:nt', JSON.stringify(persist));
        } catch (e) {
            logWarn('Unable to update Nitro Type user state', e && e.message ? e.message : e);
        }
    }

    function writePersistedUserState(bundle) {
        if (!bundle || !bundle.user) return;
        patchPersistedUserFields(function (freshUser) {
            Object.keys(bundle.user).forEach(function (key) {
                freshUser[key] = bundle.user[key];
            });
        });
    }

    function getLootDefaults(type) {
        var config;
        try {
            config = pageWindow.NTGLOBALS && pageWindow.NTGLOBALS.LOOT_CONFIG && pageWindow.NTGLOBALS.LOOT_CONFIG[type];
            return config && Array.isArray(config.defaults) ? config.defaults.slice() : [];
        } catch (e) { }
        return [];
    }

    function getEquippedLootID(user, type) {
        var loot = Array.isArray(user && user.loot) ? user.loot : [];
        var match = loot.find(function (item) {
            return item && item.type === type && item.equipped;
        });
        var defaults = getLootDefaults(type);
        if (match && match.lootID != null) return match.lootID;
        if (type === 'trail') return Number(NO_TRAIL_VALUE);
        return defaults.length ? defaults[0] : null;
    }

    function getEquippedLootItem(user, type) {
        var loot = Array.isArray(user && user.loot) ? user.loot : [];
        return loot.find(function (item) {
            return item && item.type === type && item.equipped;
        }) || null;
    }

    function getEquippedStickerIDs(user) {
        var loot = Array.isArray(user && user.loot) ? user.loot : [];
        var equipped = loot.filter(function (item) {
            return item && item.type === 'sticker' && item.equipped;
        }).sort(function (a, b) {
            return Number(a.equipped || 0) - Number(b.equipped || 0);
        }).map(function (item) {
            return item.lootID;
        });
        return equipped.length ? equipped : getLootDefaults('sticker');
    }

    function getCarHueAngle(user, carID) {
        var cars = Array.isArray(user && user.cars) ? user.cars : [];
        var id = String(carID);
        var i;
        var car;
        for (i = 0; i < cars.length; i += 1) {
            car = cars[i];
            if (Array.isArray(car) && String(car[0]) === id) {
                return Number(car[2] || 0);
            }
        }
        return String(user && user.carID) === id ? Number(user.carHueAngle || 0) : 0;
    }

    function buildEquipConfigForCar(user, carID) {
        return buildEquipConfig(user, { carID: carID });
    }

    function buildEquipConfig(user, overrides) {
        var options = overrides || {};
        var carID = options.carID != null ? options.carID : user && user.carID;
        var hueAngle = options.hueAngle != null ? Number(options.hueAngle || 0) : getCarHueAngle(user, carID);
        return {
            config: [
                { id: Number(carID), hueAngle: hueAngle, type: 'car' },
                { id: options.titleID != null ? options.titleID : getEquippedLootID(user, 'title'), type: 'title' },
                { ids: options.stickerIDs || getEquippedStickerIDs(user), type: 'stickers' },
                { id: options.trailID != null ? options.trailID : getEquippedLootID(user, 'trail'), type: 'trail' },
                { id: options.nametagID != null ? options.nametagID : getEquippedLootID(user, 'nametag'), type: 'nametag' },
                { id: options.nitroID != null ? options.nitroID : getEquippedLootID(user, 'nitro'), type: 'nitro' },
                { disablePerk: options.disablePerk != null ? Number(options.disablePerk ? 1 : 0) : (user && user.disablePerk ? 1 : 0), type: 'perk' }
            ],
            hueAngle: hueAngle
        };
    }

    function updatePersistedEquippedCar(bundle, carID, hueAngle) {
        var numericID = Number(carID);
        patchPersistedUserFields(function (user) {
            var cars = Array.isArray(user.cars) ? user.cars : [];
            user.carID = isNaN(numericID) ? carID : numericID;
            user.carHueAngle = Number(hueAngle || 0);
            cars.forEach(function (car) {
                if (Array.isArray(car) && String(car[0]) === String(carID)) {
                    car[2] = Number(hueAngle || 0);
                }
            });
        });
        if (bundle && bundle.user) {
            bundle.user.carID = isNaN(numericID) ? carID : numericID;
            bundle.user.carHueAngle = Number(hueAngle || 0);
        }
    }

    function updatePersistedEquippedLoot(bundle, type, lootID) {
        if (!type) return;
        patchPersistedUserFields(function (user) {
            var loot = Array.isArray(user.loot) ? user.loot : [];
            loot.forEach(function (item) {
                if (!item || item.type !== type) return;
                item.equipped = String(item.lootID) === String(lootID) ? 1 : 0;
            });
        });
        if (bundle && bundle.user && Array.isArray(bundle.user.loot)) {
            bundle.user.loot.forEach(function (item) {
                if (!item || item.type !== type) return;
                item.equipped = String(item.lootID) === String(lootID) ? 1 : 0;
            });
        }
    }

    function playEquipSound() {
        var audio;
        try {
            audio = new pageWindow.Audio(EQUIP_SOUND_URL);
            audio.volume = 0.55;
            audio.play().catch(function () { });
        } catch (e) { }
    }

    function findReactFiberNode(element) {
        var key;
        if (!element) return null;
        key = Object.keys(element).find(function (name) {
            return name.indexOf('__reactFiber') === 0 || name.indexOf('__reactInternalInstance') === 0;
        });
        return key ? element[key] : null;
    }

    function getReactComponentNodeFromSelector(selector) {
        var canvas = pageDocument.querySelector(selector);
        var container = canvas && (
            canvas.closest('.animated-car-preview') ||
            canvas.closest('.animated-asset-preview') ||
            canvas.parentElement
        );
        var node = findReactFiberNode(container);
        while (node && !(node.type && typeof node.type === 'function')) {
            node = node.return;
        }
        return node || null;
    }

    function extractActivePreviewReactContext() {
        var React = null;
        var ReactDOM = null;
        var moduleID;
        var carNode;
        var scanNode;
        var CarComponent = null;
        var getCarUrl = null;
        var getCarMetaData = null;
        var getLootMetaData = null;

        if (state.activePreviewReactCtx) return state.activePreviewReactCtx;
        if (!pageWindow.webpackJsonp || !pageWindow.webpackJsonp.push) return null;

        try {
            moduleID = '__ntgo_react_' + Date.now();
            pageWindow.webpackJsonp.push([[moduleID], (function () {
                var modules = {};
                modules[moduleID] = function (module, exports, req) {
                    Object.keys(req.m || {}).forEach(function (id) {
                        var mod;
                        try {
                            mod = req(id);
                            if (mod && mod.createElement && mod.Component && !React) React = mod;
                            if (mod && mod.render && mod.createPortal && !ReactDOM) ReactDOM = mod;
                        } catch (e) { }
                    });
                };
                return modules;
            }()), [[moduleID]]]);
        } catch (e) {
            logWarn('Animated preview React extraction failed', e && e.message ? e.message : e);
            return null;
        }

        if (!React || !ReactDOM) return null;

        carNode = getReactComponentNodeFromSelector('.animated-car-preview canvas');
        if (!carNode) return null;
        CarComponent = carNode.type;
        scanNode = carNode;
        while (scanNode) {
            if (scanNode.memoizedProps) {
                if (scanNode.memoizedProps.getCarMetaData && !getCarMetaData) {
                    getCarMetaData = scanNode.memoizedProps.getCarMetaData;
                }
                if (scanNode.memoizedProps.getLootMetaData && !getLootMetaData) {
                    getLootMetaData = scanNode.memoizedProps.getLootMetaData;
                }
                if (scanNode.memoizedProps.getCarUrl && !getCarUrl) {
                    getCarUrl = scanNode.memoizedProps.getCarUrl;
                }
            }
            scanNode = scanNode.return;
        }

        if (!CarComponent || !getCarMetaData || !getCarUrl) return null;
        state.activePreviewReactCtx = {
            React: React,
            ReactDOM: ReactDOM,
            CarComponent: CarComponent,
            getCarUrl: getCarUrl,
            getCarMetaData: getCarMetaData,
            getLootMetaData: getLootMetaData
        };
        return state.activePreviewReactCtx;
    }

    function getActiveCarPreviewMount() {
        var mount = pageDocument.querySelector('.profile--active-car--preview-container');
        if (mount) return mount;
        mount = pageDocument.querySelector('.profile--active-car--preview');
        if (mount && mount.parentElement) return mount.parentElement;
        mount = pageDocument.querySelector('.animated-car-preview');
        return mount && mount.parentElement ? mount.parentElement : null;
    }

    function applyActivePreviewClasses(user) {
        var profile = pageDocument.querySelector('.profile');
        var preview = pageDocument.querySelector('.animated-car-preview');
        if (preview) preview.classList.add('profile--active-car--preview');
        if (!profile) return;
        profile.classList.toggle('with-trail', !!(getEquippedLootItem(user, 'trail') || {}).assetKey);
    }

    function updateActiveCarDisplay(info, user, hueAngle) {
        var nameNode = pageDocument.querySelector('.profile--active-car--car-name');
        var ctx;
        var mount;
        var meta;
        var trail = getEquippedLootItem(user, 'trail');
        var nitro = getEquippedLootItem(user, 'nitro');

        if (nameNode && info && info.name) {
            nameNode.textContent = info.name;
        }
        if (!info || !info.carID || !user) return false;

        ctx = extractActivePreviewReactContext();
        mount = getActiveCarPreviewMount();
        if (!ctx || !mount) {
            logWarn('Animated active car preview is unavailable; skipping immediate visual rerender.');
            return false;
        }

        try {
            meta = ctx.getCarMetaData(Number(info.carID));
            if (!meta) return false;
            ctx.ReactDOM.render(
                ctx.React.createElement(ctx.CarComponent, {
                    carID: Number(info.carID),
                    hue: Number(hueAngle || 0),
                    getCarUrl: ctx.getCarUrl,
                    getCarMetaData: ctx.getCarMetaData,
                    getLootMetaData: ctx.getLootMetaData,
                    metaData: meta,
                    trailKey: trail && trail.assetKey ? trail.assetKey : null,
                    nitroKey: nitro && nitro.assetKey ? nitro.assetKey : null,
                    disablePerk: user && user.disablePerk ? 1 : 0,
                    animate: true,
                    scale: 1,
                    transparent: true,
                    backgroundColor: 0,
                    useWebGL: true,
                    offsetX: 0,
                    offsetY: 0
                }),
                mount
            );
            pageWindow.setTimeout(function () { applyActivePreviewClasses(user); }, 0);
            return true;
        } catch (e) {
            logWarn('Animated active car preview rerender failed', e && e.message ? e.message : e);
        }
        return false;
    }

    function refreshAnimatedPreviewFromUser(user) {
        if (!user || !user.carID) return false;
        return updateActiveCarDisplay({
            carID: user.carID,
            name: getCarNameByID(user.carID),
            number: 0
        }, user, user.carHueAngle || getCarHueAngle(user, user.carID));
    }

    function getAutoShuffleStorageKey(type) {
        return AUTO_SHUFFLE_STORAGE_KEY + ':' + String(type || 'cars');
    }

    function getShuffleSupportedTypes() {
        return ['cars', 'paint', 'trail', 'nitro', 'nametag', 'title'];
    }

    function isShuffleSupportedType(type) {
        return getShuffleSupportedTypes().indexOf(String(type || '')) !== -1;
    }

    function getAutoShuffleTypes() {
        return getShuffleSupportedTypes();
    }

    function getShufflePoolStorageKey(type) {
        return SHUFFLE_POOL_STORAGE_KEY + ':' + String(type || 'cars');
    }

    function getShufflePoolOrderStorageKey(type) {
        return SHUFFLE_POOL_ORDER_STORAGE_KEY + ':' + String(type || 'cars');
    }

    function getShufflePoolCycleModeStorageKey(type) {
        return SHUFFLE_POOL_CYCLE_MODE_STORAGE_KEY + ':' + String(type || 'cars');
    }

    function getShufflePoolSnapshotStorageKey(type) {
        return SHUFFLE_POOL_SNAPSHOT_STORAGE_KEY + ':' + String(type || 'cars');
    }

    function normalizeToolbarOrientation(value) {
        var normalized = String(value || '').toLowerCase();
        return TOOLBAR_DOCK_ORIENTATIONS.indexOf(normalized) !== -1 ? normalized : 'bottom';
    }

    function readToolbarOrientation() {
        try {
            return normalizeToolbarOrientation(readToolkitGarageStorageRaw(TOOLBAR_ORIENTATION_STORAGE_KEY));
        } catch (e) {
            return 'bottom';
        }
    }

    function writeToolbarOrientation(value) {
        try {
            writeToolkitGarageStorageRaw(TOOLBAR_ORIENTATION_STORAGE_KEY, normalizeToolbarOrientation(value));
        } catch (e) { }
    }

    function getToolbarOrientationLabel(value) {
        var orientation = normalizeToolbarOrientation(value);
        return orientation.charAt(0).toUpperCase() + orientation.slice(1);
    }

    function setToolbarOrientation(value, options) {
        var orientation = normalizeToolbarOrientation(value);
        var shouldPersist = !options || options.persist !== false;
        state.toolbarOrientation = orientation;
        if (shouldPersist) writeToolbarOrientation(orientation);
        if (state.toolbar) {
            TOOLBAR_DOCK_ORIENTATIONS.forEach(function (dock) {
                state.toolbar.classList.toggle('ntgo-toolbar--' + dock, dock === orientation);
            });
            state.toolbar.setAttribute('data-ntgo-orientation', orientation);
        }
        positionSearchResults();
        scheduleStatusTooltipSync();
    }

    function normalizeShuffleValue(type, value) {
        var number;
        if (value == null) return null;
        number = Number(value);
        if (isNaN(number)) return null;
        if (type === 'paint') {
            number = Math.round(number) % 360;
            if (number < 0) number += 360;
            return String(number);
        }
        return String(Math.round(number));
    }

    function isNoTrailValue(type, value) {
        return String(type || '') === 'trail' && normalizeShuffleValue(type, value) === NO_TRAIL_VALUE;
    }

    function isNoTrailCustomizerItem(item, type) {
        var removeNode;
        var tooltipText;
        if (String(type || '') !== 'trail' || !item) return false;
        removeNode = item.querySelector('.customizer--item-selector-item--remove');
        tooltipText = getCustomizerItemTooltipText(item);
        return !!(
            removeNode && /no\s+trail/i.test(normalizeText(removeNode.textContent)) ||
            /remove\s+trail/i.test(tooltipText)
        );
    }

    function allowsOrderedPoolDuplicates(type) {
        return isShuffleSupportedType(type) && String(type || '') !== 'cars';
    }

    function uniqueValues(values) {
        var seen = {};
        var result = [];
        (Array.isArray(values) ? values : []).forEach(function (value) {
            var key = String(value);
            if (!key || seen[key]) return;
            seen[key] = true;
            result.push(key);
        });
        return result;
    }

    function getShufflePool(type) {
        var raw;
        var values;
        if (!isShuffleSupportedType(type)) return [];
        try {
            raw = readToolkitGarageStorageRaw(getShufflePoolStorageKey(type));
            values = raw ? JSON.parse(raw) : [];
        } catch (e) {
            values = [];
        }
        return uniqueValues((Array.isArray(values) ? values : []).map(function (value) {
            return normalizeShuffleValue(type, value);
        }).filter(Boolean));
    }

    function setShufflePool(type, values) {
        if (!isShuffleSupportedType(type)) return;
        writeToolkitGarageStorageRaw(getShufflePoolStorageKey(type), JSON.stringify(uniqueValues((values || []).map(function (value) {
            return normalizeShuffleValue(type, value);
        }).filter(Boolean))));
    }

    function getShufflePoolOrder(type) {
        var pool = getShufflePool(type);
        var selected = {};
        var seen = {};
        var raw;
        var values;
        var result = [];
        var allowDuplicates = allowsOrderedPoolDuplicates(type);
        if (!isShuffleSupportedType(type)) return [];
        pool.forEach(function (value) {
            selected[String(value)] = true;
        });
        try {
            raw = readToolkitGarageStorageRaw(getShufflePoolOrderStorageKey(type));
            values = raw ? JSON.parse(raw) : [];
        } catch (e) {
            values = [];
        }
        (Array.isArray(values) ? values : []).forEach(function (value) {
            var normalized = normalizeShuffleValue(type, value);
            if (!normalized || !selected[String(normalized)]) return;
            if (!allowDuplicates && seen[String(normalized)]) return;
            seen[String(normalized)] = true;
            result.push(String(normalized));
        });
        pool.forEach(function (value) {
            if (seen[String(value)]) return;
            seen[String(value)] = true;
            result.push(String(value));
        });
        return result;
    }

    function setShufflePoolOrder(type, values) {
        var pool = getShufflePool(type);
        var selected = {};
        var normalizedValues;
        if (!isShuffleSupportedType(type)) return;
        pool.forEach(function (value) {
            selected[String(value)] = true;
        });
        normalizedValues = (values || []).map(function (value) {
            return normalizeShuffleValue(type, value);
        }).filter(function (value) {
            return value && selected[String(value)];
        });
        if (!allowsOrderedPoolDuplicates(type)) normalizedValues = uniqueValues(normalizedValues);
        writeToolkitGarageStorageRaw(getShufflePoolOrderStorageKey(type), JSON.stringify(normalizedValues));
    }

    function normalizeShufflePoolCycleMode(mode) {
        return mode === 'ordered' || mode === 'ignore' ? mode : 'random';
    }

    function getShufflePoolCycleMode(type) {
        return normalizeShufflePoolCycleMode(readToolkitGarageStorageRaw(getShufflePoolCycleModeStorageKey(type)));
    }

    function setShufflePoolCycleMode(type, mode) {
        if (!isShuffleSupportedType(type)) return;
        mode = normalizeShufflePoolCycleMode(mode);
        writeToolkitGarageStorageRaw(getShufflePoolCycleModeStorageKey(type), mode);
        if (mode === 'ordered') {
            state.customizerPoolSort = 'order';
            setShufflePoolOrderIndex(0);
        }
    }

    function getShufflePoolOrderIndex() {
        var value = Number(readToolkitGarageStorageRaw(SHUFFLE_POOL_ORDER_INDEX_STORAGE_KEY));
        return value && !isNaN(value) && value > 0 ? Math.floor(value) : 0;
    }

    function setShufflePoolOrderIndex(value) {
        writeToolkitGarageStorageRaw(SHUFFLE_POOL_ORDER_INDEX_STORAGE_KEY, String(Math.max(0, Math.floor(Number(value) || 0))));
    }

    function advanceShufflePoolOrderIndex() {
        setShufflePoolOrderIndex(getShufflePoolOrderIndex() + 1);
    }

    function getOrderedAutoShufflePoolLength(user, type) {
        if (getShufflePoolCycleMode(type) !== 'ordered') return 0;
        if (!isShufflePoolOrderFullyAvailable(user, type)) return 0;
        return getShufflePoolOrder(type).length;
    }

    function getSharedAutoShuffleOrderIndex(user, enabledTypes, orderIndex) {
        var lengths = [];
        var sharedLength;
        (enabledTypes || []).forEach(function (type) {
            var length = getOrderedAutoShufflePoolLength(user, type);
            if (length > 0) lengths.push(length);
        });
        if (!lengths.length) return Math.max(0, Math.floor(Number(orderIndex) || 0));
        sharedLength = Math.min.apply(Math, lengths);
        if (!sharedLength || !isFinite(sharedLength)) return 0;
        return Math.max(0, Math.floor(Number(orderIndex) || 0)) % sharedLength;
    }

    function setShufflePoolValueSelected(type, value, selected) {
        var normalized = normalizeShuffleValue(type, value);
        var pool;
        var index;
        if (!normalized || !isShuffleSupportedType(type)) return false;
        pool = getShufflePool(type);
        index = pool.indexOf(normalized);
        if (selected && index === -1) {
            pool.push(normalized);
            setShufflePool(type, pool);
            setShufflePoolOrder(type, getShufflePoolOrder(type));
            return true;
        }
        if (!selected && index !== -1) {
            pool.splice(index, 1);
            setShufflePool(type, pool);
            setShufflePoolOrder(type, getShufflePoolOrder(type));
            return true;
        }
        return false;
    }

    function addShufflePoolOrderOccurrence(type, value) {
        var normalized = normalizeShuffleValue(type, value);
        var pool;
        var order;
        if (!normalized || !allowsOrderedPoolDuplicates(type)) return false;
        pool = getShufflePool(type);
        if (pool.indexOf(normalized) === -1) {
            pool.push(normalized);
            setShufflePool(type, pool);
        }
        order = getShufflePoolOrder(type);
        order.push(normalized);
        setShufflePoolOrder(type, order);
        return true;
    }

    function removeShufflePoolOrderOccurrence(type, value, orderIndex) {
        var normalized = normalizeShuffleValue(type, value);
        var order;
        var index;
        var pool;
        if (!normalized || !allowsOrderedPoolDuplicates(type)) return false;
        order = getShufflePoolOrder(type);
        index = Number(orderIndex);
        if (!isNaN(index) && index >= 0 && index < order.length && order[index] === normalized) {
            order.splice(index, 1);
        } else {
            index = order.indexOf(normalized);
            if (index === -1) return false;
            order.splice(index, 1);
        }
        if (order.indexOf(normalized) === -1) {
            pool = getShufflePool(type).filter(function (poolValue) {
                return poolValue !== normalized;
            });
            setShufflePool(type, pool);
        }
        setShufflePoolOrder(type, order);
        return true;
    }

    function isAutoShuffleEnabled(type) {
        var key = String(type || 'cars');
        var value = readToolkitGarageStorageRaw(getAutoShuffleStorageKey(key));
        if (value != null) return value === '1';
        return readToolkitGarageStorageRaw('ntgoAutoShuffleCar') === '1' &&
            (readToolkitGarageStorageRaw(AUTO_SHUFFLE_TYPE_STORAGE_KEY) || 'cars') === key;
    }

    function getEnabledAutoShuffleTypes() {
        return getAutoShuffleTypes().filter(function (type) {
            return isAutoShuffleEnabled(type);
        });
    }

    function syncAutoShuffleSessionWatcher() {
        if (!isToolkitCustomizerShuffleEnabled() || !getEnabledAutoShuffleTypes().length) {
            stopAutoShuffleSessionWatcher();
            return;
        }
        startAutoShuffleSessionWatcher();
    }

    function setAutoShuffleEnabled(enabled, type) {
        var bundle = readPersistedUserState();
        var sessionRaces = Number(bundle && bundle.user && bundle.user.sessionRaces || 0);
        var tabInfo = getCustomizerTabInfo();
        var key = String(type || tabInfo.key || 'cars');
        writeToolkitGarageStorageRaw(getAutoShuffleStorageKey(key), enabled ? '1' : '0');
        writeToolkitGarageStorageRaw(AUTO_SHUFFLE_LAST_SESSION_RACES_KEY, String(sessionRaces));
        updateCustomizerShuffleToggle();
        syncAutoShuffleSessionWatcher();
        logInfo('Auto shuffle ' + (enabled ? 'enabled for ' + (type ? key : tabInfo.label) : 'disabled for ' + (type ? key : tabInfo.label)) + '.');
    }

    function getOwnedCarIDs(user) {
        var cars = Array.isArray(user && user.cars) ? user.cars : [];
        return cars.map(function (car) {
            return Array.isArray(car) ? Number(car[0]) : Number(car && (car.carID || car.id));
        }).filter(function (carID) {
            return carID && !isNaN(carID);
        });
    }

    function pickRandomOwnedCarID(user) {
        var currentID = String(user && user.carID);
        var candidates = getOwnedCarIDs(user).filter(function (carID) {
            return String(carID) !== currentID;
        });
        if (!candidates.length) candidates = getOwnedCarIDs(user);
        if (!candidates.length) return null;
        return candidates[Math.floor(Math.random() * candidates.length)];
    }

    function getCarNameByID(carID) {
        var entry = getCarCatalog().byID[String(carID)];
        return entry && entry.name ? entry.name : 'Car #' + carID;
    }

    function equipCarByID(carID, reason, displayName, slotNumber, options) {
        var bundle;
        var equip;
        var token;
        var info;
        var settings = options || {};
        if (state.normalEquipApplying || !carID) return Promise.resolve(false);

        bundle = readPersistedUserState();
        if (!bundle || !bundle.user) {
            logWarn('Could not equip car: Nitro Type user state is unavailable.');
            return Promise.resolve(false);
        }
        token = getLiveToken();
        if (!token) {
            logWarn('Could not equip car: Nitro Type session token is unavailable or expired.');
            return Promise.resolve(false);
        }
        if (String(bundle.user.carID) === String(carID)) {
            logInfo(getCarNameByID(carID) + ' is already equipped.');
            return Promise.resolve(false);
        }

        state.normalEquipApplying = true;
        equip = buildEquipConfigForCar(bundle.user, carID);
        info = {
            carID: carID,
            name: displayName || getCarNameByID(carID),
            number: slotNumber || 0
        };

        return pageWindow.fetch('/api/v2/loot/equip', {
            method: 'POST',
            credentials: 'include',
            headers: {
                'Accept': 'application/json',
                'Authorization': 'Bearer ' + token,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(equip.config)
        }).then(function (response) {
            if (!response.ok) throw new Error('HTTP ' + response.status);
            updatePersistedEquippedCar(bundle, carID, equip.hueAngle);
            state.lastEquippedCarID = String(carID);
            if (settings.playSound !== false) playEquipSound();
            if (settings.updatePreview !== false) updateActiveCarDisplay(info, bundle.user, equip.hueAngle);
            logInfo((reason || 'Shuffle') + ' equipped ' + info.name + '.');
            return true;
        }).catch(function (error) {
            logWarn('Garage car equip failed', error && error.message ? error.message : error);
            return false;
        }).then(function (result) {
            state.normalEquipApplying = false;
            return result;
        });
    }

    function shuffleRandomOwnedCar(reason, options) {
        var bundle = readPersistedUserState();
        var carID;
        if (!bundle || !bundle.user) {
            logWarn('Could not shuffle car: Nitro Type user state is unavailable.');
            return Promise.resolve(false);
        }
        carID = pickRandomOwnedCarID(bundle.user);
        if (!carID) {
            logWarn('Could not shuffle car: no owned cars were found.');
            return Promise.resolve(false);
        }
        return equipCarByID(carID, reason || 'Shuffle', null, 0, options);
    }

    function getOwnedLootItems(user, type) {
        var loot = Array.isArray(user && user.loot) ? user.loot : [];
        return loot.filter(function (item) {
            return item && item.type === type && item.lootID != null;
        });
    }

    function pickRandomOwnedLootItem(user, type) {
        var equipped = getEquippedLootItem(user, type);
        var candidates = getOwnedLootItems(user, type).filter(function (item) {
            return !equipped || String(item.lootID) !== String(equipped.lootID);
        });
        if (!candidates.length) candidates = getOwnedLootItems(user, type);
        if (!candidates.length) return null;
        return candidates[Math.floor(Math.random() * candidates.length)];
    }

    function getOwnedShuffleValues(user, type) {
        var values = [];
        var value;
        if (type === 'cars') {
            return getOwnedCarIDs(user).map(function (carID) { return String(carID); });
        }
        if (type === 'paint') {
            for (value = 0; value < 360; value += 20) values.push(String(value));
            return values;
        }
        if (!isShuffleSupportedType(type)) return [];
        if (type === 'trail') values.push(NO_TRAIL_VALUE);
        return uniqueValues(values.concat(getOwnedLootItems(user, type).map(function (item) {
            return normalizeShuffleValue(type, item.lootID);
        }).filter(Boolean)));
    }

    function getCurrentShuffleValue(user, type) {
        var equipped;
        if (type === 'cars') return normalizeShuffleValue(type, user && user.carID);
        if (type === 'paint') return normalizeShuffleValue(type, user && user.carHueAngle);
        if (type === 'trail' && !getEquippedLootItem(user, type)) return NO_TRAIL_VALUE;
        equipped = getEquippedLootID(user, type);
        return normalizeShuffleValue(type, equipped);
    }

    function getValidShufflePoolValues(user, type) {
        var owned = getOwnedShuffleValueMap(user, type);
        return getShufflePool(type).filter(function (value) {
            return !!owned[String(value)];
        });
    }

    function getValidShufflePoolOrderValues(user, type) {
        var owned = getOwnedShuffleValueMap(user, type);
        return getShufflePoolOrder(type).filter(function (value) {
            return !!owned[String(value)];
        });
    }

    function getOwnedShuffleValueMap(user, type) {
        var owned = {};
        getOwnedShuffleValues(user, type).forEach(function (value) {
            owned[String(value)] = true;
        });
        return owned;
    }

    function getUnavailableShufflePoolValues(user, type) {
        var owned = getOwnedShuffleValueMap(user, type);
        return getShufflePool(type).filter(function (value) {
            return !owned[String(value)];
        });
    }

    function getUnavailableShufflePoolOrderValues(user, type) {
        var owned = getOwnedShuffleValueMap(user, type);
        return getShufflePoolOrder(type).filter(function (value) {
            return !owned[String(value)];
        });
    }

    function isShufflePoolOrderFullyAvailable(user, type) {
        var order = getShufflePoolOrder(type);
        if (!order.length) return true;
        return getUnavailableShufflePoolOrderValues(user, type).length === 0;
    }

    function getShuffleCandidates(user, type) {
        var pool = getValidShufflePoolValues(user, type);
        var values = pool.length ? pool : getOwnedShuffleValues(user, type);
        return uniqueValues(values);
    }

    function pickShuffleValue(user, type, options) {
        var settings = options || {};
        var rawPool = settings.ignorePool ? [] : getShufflePool(type);
        var pool = settings.ignorePool ? [] : getValidShufflePoolValues(user, type);
        var usingPool = rawPool.length > 0;
        var current = getCurrentShuffleValue(user, type);
        var orderedPool;
        var candidates = usingPool ? uniqueValues(pool) : uniqueValues(getOwnedShuffleValues(user, type));
        var nonCurrent = candidates.filter(function (value) {
            return String(value) !== String(current);
        });
        if (settings.ordered && usingPool) {
            if (!isShufflePoolOrderFullyAvailable(user, type)) return null;
            orderedPool = getValidShufflePoolOrderValues(user, type);
            if (!orderedPool.length) return null;
            return orderedPool[Math.max(0, Math.floor(Number(settings.orderIndex) || 0)) % orderedPool.length];
        }
        if (nonCurrent.length) {
            candidates = nonCurrent;
        } else if (usingPool) {
            return null;
        }
        if (!candidates.length) return null;
        return candidates[Math.floor(Math.random() * candidates.length)];
    }

    function shuffleArray(values) {
        var copy = values.slice();
        var i;
        var j;
        var temp;
        for (i = copy.length - 1; i > 0; i -= 1) {
            j = Math.floor(Math.random() * (i + 1));
            temp = copy[i];
            copy[i] = copy[j];
            copy[j] = temp;
        }
        return copy;
    }

    function equipConfig(equip, bundle, afterPersist, reason, options) {
        var token = getLiveToken();
        var settings = options || {};
        if (state.normalEquipApplying) return Promise.resolve(false);
        if (!token) {
            logWarn('Could not equip shuffled item: Nitro Type session token is unavailable or expired.');
            return Promise.resolve(false);
        }
        state.normalEquipApplying = true;
        return pageWindow.fetch('/api/v2/loot/equip', {
            method: 'POST',
            credentials: 'include',
            headers: {
                'Accept': 'application/json',
                'Authorization': 'Bearer ' + token,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(equip.config)
        }).then(function (response) {
            if (!response.ok) throw new Error('HTTP ' + response.status);
            if (typeof afterPersist === 'function') afterPersist();
            if (settings.playSound !== false) playEquipSound();
            if (settings.updatePreview) refreshAnimatedPreviewFromUser(bundle && bundle.user);
            logInfo(reason || 'Shuffled item.');
            return true;
        }).catch(function (error) {
            logWarn('Shuffle equip failed', error && error.message ? error.message : error);
            return false;
        }).then(function (result) {
            state.normalEquipApplying = false;
            return result;
        });
    }

    function shuffleRandomPaint(reason, options) {
        var bundle = readPersistedUserState();
        var settings = options || {};
        var hue;
        var equip;
        if (!bundle || !bundle.user || !bundle.user.carID) return Promise.resolve(false);
        hue = Number(pickShuffleValue(bundle.user, 'paint', { ignorePool: settings.ignorePool === true }));
        if (isNaN(hue)) return Promise.resolve(false);
        equip = buildEquipConfig(bundle.user, { carID: bundle.user.carID, hueAngle: hue });
        return equipConfig(equip, bundle, function () {
            updatePersistedEquippedCar(bundle, bundle.user.carID, hue);
        }, reason || 'Shuffled paint.', { playSound: settings.playSound === true, updatePreview: settings.updatePreview });
    }

    function shuffleRandomOwnedLootType(type, reason, options) {
        var bundle = readPersistedUserState();
        var settings = options || {};
        var value;
        var item;
        var overrides = {};
        var equip;
        if (!bundle || !bundle.user) return Promise.resolve(false);
        if (type === 'cars') {
            value = pickShuffleValue(bundle.user, 'cars', { ignorePool: settings.ignorePool === true });
            if (!value) return Promise.resolve(false);
            return equipCarByID(Number(value), reason || 'Shuffle', null, 0, {
                playSound: settings.playSound === true,
                updatePreview: settings.updatePreview
            }).then(function (result) { return result; });
        }
        if (type === 'paint') return shuffleRandomPaint(reason, settings);
        if (type === 'sticker' || type === 'perk') return Promise.resolve(false);
        value = pickShuffleValue(bundle.user, type, { ignorePool: settings.ignorePool === true });
        if (!value) return Promise.resolve(false);
        item = Number(value);
        if (type === 'trail') overrides.trailID = item;
        if (type === 'nitro') overrides.nitroID = item;
        if (type === 'nametag') overrides.nametagID = item;
        if (type === 'title') overrides.titleID = item;
        equip = buildEquipConfig(bundle.user, overrides);
        return equipConfig(equip, bundle, function () {
            updatePersistedEquippedLoot(bundle, type, item);
        }, reason || 'Shuffled ' + type + '.', { playSound: settings.playSound === true, updatePreview: settings.updatePreview });
    }

    function getCustomizerTabInfo() {
        var tab = pageDocument.querySelector('.customizer--tab.is-current');
        var label = normalizeText(tab && tab.textContent).toLowerCase();
        var path = String(pageWindow.location.pathname || '').split('/').filter(Boolean).pop() || '';
        var key = path || label;
        var map = {
            cars: { key: 'cars', label: 'Car', auto: true },
            car: { key: 'cars', label: 'Car', auto: true },
            paint: { key: 'paint', label: 'Paint', auto: true },
            trails: { key: 'trail', label: 'Trail', auto: true },
            trail: { key: 'trail', label: 'Trail', auto: true },
            nitros: { key: 'nitro', label: 'Nitro', auto: true },
            nitro: { key: 'nitro', label: 'Nitro', auto: true },
            nametags: { key: 'nametag', label: 'Nametag', auto: true },
            nametag: { key: 'nametag', label: 'Nametag', auto: true },
            stickers: { key: 'sticker', label: 'Sticker', auto: false },
            sticker: { key: 'sticker', label: 'Sticker', auto: false },
            titles: { key: 'title', label: 'Title', auto: true },
            title: { key: 'title', label: 'Title', auto: true },
            perk: { key: 'perk', label: 'Perk', auto: false }
        };
        return map[key] || map[label] || { key: key || 'cars', label: label || 'Item', auto: true };
    }

    function isCustomizerPoolPreviewNode(node) {
        return !!(node && node.closest && node.closest('.' + SHUFFLE_POOL_PREVIEW_CLASS));
    }

    function getAllCustomizerSelectorItems() {
        return Array.prototype.slice.call(pageDocument.querySelectorAll('.customizer--item-selector-item')).filter(function (item) {
            if (isCustomizerPoolPreviewNode(item)) return false;
            if (item.closest('.customizer--tabs')) return false;
            return true;
        });
    }

    function getVisibleCustomizerItems() {
        return getAllCustomizerSelectorItems().filter(function (item) {
            var rect = item.getBoundingClientRect();
            if (rect.width < 20 || rect.height < 20) return false;
            if (rect.right <= 0 || rect.bottom <= 0) return false;
            if (rect.left >= pageWindow.innerWidth || rect.top >= pageWindow.innerHeight) return false;
            return true;
        });
    }

    function getCustomizerItems() {
        return getAllCustomizerSelectorItems().filter(function (item) {
            var rect = item.getBoundingClientRect();
            if (rect.width < 20 || rect.height < 20) return false;
            return true;
        });
    }

    function readNumericAttribute(element, names) {
        var i;
        var value;
        if (!element) return null;
        for (i = 0; i < names.length; i += 1) {
            value = element.getAttribute && element.getAttribute(names[i]);
            if (value != null && value !== '' && !isNaN(Number(value))) return Number(value);
        }
        return null;
    }

    function collectObjectValues(value, output, seen, depth) {
        var keys;
        if (depth > 4 || value == null) return;
        if (typeof value !== 'object') return;
        if (value.nodeType || value === pageWindow || value === pageDocument) return;
        if (seen.indexOf(value) !== -1) return;
        seen.push(value);
        output.push(value);
        keys = Object.keys(value);
        keys.slice(0, 60).forEach(function (key) {
            if (/^(__|_owner|ref|children)$/i.test(key)) return;
            try {
                collectObjectValues(value[key], output, seen, depth + 1);
            } catch (e) { }
        });
    }

    function getCustomizerItemReactObjects(item) {
        var objects = [];
        var seen = [];
        var fiber = findReactFiberNode(item);
        var node = fiber;
        var depth = 0;
        function collectFiberNode(fiberNode, childDepth) {
            var sibling;
            if (!fiberNode || childDepth > 4) return;
            collectObjectValues(fiberNode.memoizedProps, objects, seen, 0);
            collectObjectValues(fiberNode.pendingProps, objects, seen, 0);
            if (fiberNode.child) collectFiberNode(fiberNode.child, childDepth + 1);
            sibling = fiberNode.sibling;
            while (sibling && childDepth < 2) {
                collectFiberNode(sibling, childDepth + 1);
                sibling = sibling.sibling;
            }
        }
        while (node && depth < 8) {
            collectObjectValues(node.memoizedProps, objects, seen, 0);
            collectObjectValues(node.pendingProps, objects, seen, 0);
            if (depth < 2 && node.child) collectFiberNode(node.child, 0);
            node = node.return;
            depth += 1;
        }
        return objects;
    }

    function getObjectNumber(object, names) {
        var i;
        var value;
        if (!object) return null;
        for (i = 0; i < names.length; i += 1) {
            if (!Object.prototype.hasOwnProperty.call(object, names[i])) continue;
            value = object[names[i]];
            if (value != null && value !== '' && !isNaN(Number(value))) return Number(value);
        }
        return null;
    }

    function inferCustomizerItemIDFromReact(item, type) {
        var objects = getCustomizerItemReactObjects(item);
        var names;
        var value = null;
        var typedValue = null;
        if (type === 'cars') names = ['carID', 'carId', 'car_id'];
        else if (type === 'paint') names = ['hueAngle', 'hue', 'hueValue', 'angle'];
        else names = ['lootID', 'lootId', 'loot_id'];
        objects.some(function (object) {
            var objectType = object && (object.type || object.lootType || object.category);
            var direct = getObjectNumber(object, names);
            if (direct != null && value == null) value = direct;
            if (direct != null && String(objectType || '') === String(type)) {
                typedValue = direct;
                return true;
            }
            return false;
        });
        return typedValue != null ? typedValue : value;
    }

    function getElementImageSource(element) {
        var src = element ? String(element.currentSrc || element.src || element.getAttribute('src') || '') : '';
        var backgroundImage;
        var match;
        if (src || !element) return src;
        backgroundImage = String(element.style && element.style.backgroundImage || element.getAttribute('style') || '');
        if (!backgroundImage && pageWindow.getComputedStyle) {
            try {
                backgroundImage = String(pageWindow.getComputedStyle(element).backgroundImage || '');
            } catch (e) { }
        }
        match = backgroundImage.match(/url\((?:["']?)(.*?)(?:["']?)\)/i);
        return match && match[1] ? match[1] : '';
    }

    function getCustomizerItemTooltipText(item) {
        var tooltip = item && item.querySelector('.customizer--tooltip');
        var text = normalizeText(
            (tooltip && tooltip.textContent) ||
            (item && item.getAttribute && (item.getAttribute('data-tip') || item.getAttribute('title') || item.getAttribute('aria-label'))) ||
            ''
        );
        return text;
    }

    function getCustomizerItemDisplayText(item) {
        var source;
        var text;
        if (!item) return '';
        source = item.querySelector(
            '.customizer--item-selector-item--container,' +
            '.rarity-frame--content,' +
            '.customizer--item-selector-item--content'
        ) || item;
        text = normalizeText(source && source.textContent);
        [
            'Gold Only',
            'New',
            'Equipped',
            'Preview',
            'Favorite',
            'Hide',
            'Pool',
            'Remove'
        ].forEach(function (label) {
            text = text.replace(new RegExp('(?:^|\\s)' + label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '(?=\\s|$)', 'gi'), ' ');
        });
        return normalizeText(text);
    }

    function getCustomizerItemSource(item) {
        var sourceNode;
        var nodes;
        var i;
        var src;
        if (!item) return '';
        sourceNode = item.querySelector('.customizer--item-selector-item--vehicle, img, [style*="url("]');
        src = getElementImageSource(sourceNode);
        if (src) return src;
        nodes = Array.prototype.slice.call(item.querySelectorAll('img,[style]'));
        for (i = 0; i < nodes.length; i += 1) {
            src = getElementImageSource(nodes[i]);
            if (src) return src;
        }
        return '';
    }

    function inferCarIDFromCustomizerElement(item) {
        var vehicle = item && item.querySelector('.customizer--item-selector-item--vehicle, img, [style*="/cars/"]');
        var src = getElementImageSource(vehicle) || getCustomizerItemSource(item);
        var name = normalizeText(
            getCustomizerItemTooltipText(item) ||
            (vehicle && (vehicle.getAttribute('data-tip') || vehicle.getAttribute('alt') || vehicle.getAttribute('title'))) ||
            (item && item.textContent)
        );
        var sourceInfo;
        var catalogEntry;
        if (!src && !name) return null;
        sourceInfo = getCarIdFromSource(src);
        catalogEntry = resolveCatalogEntry(src, name, sourceInfo);
        return (catalogEntry && catalogEntry.carID) || sourceInfo.id || null;
    }

    function inferLootIDFromCustomizerElement(item, type) {
        var src = getCustomizerItemSource(item);
        var name = getCustomizerItemTooltipText(item) || getCustomizerItemDisplayText(item);
        var entry;
        var userLoot;
        var matches;
        if (!item || !type) return null;
        if (isNoTrailCustomizerItem(item, type)) return NO_TRAIL_VALUE;
        entry = resolveLootCatalogEntry(src, name, type);
        if (entry && String(entry.type) === String(type)) return entry.lootID;
        try {
            userLoot = ((readPersistedUserState() || {}).user || {}).loot || [];
            matches = userLoot.filter(function (loot) {
                var lootName = normalizeText(loot && (loot.name || loot.title || loot.displayName)).toLowerCase();
                if (!loot || String(loot.type) !== String(type)) return false;
                return !!(name && lootName && lootName === name.toLowerCase());
            });
            if (matches.length === 1 && matches[0].lootID != null) return matches[0].lootID;
        } catch (e) { }
        return null;
    }

    function inferPaintHueFromElement(item) {
        var text = item && item.textContent;
        var styleText = '';
        var match;
        if (!item) return null;
        Array.prototype.slice.call(item.querySelectorAll('*')).concat([item]).forEach(function (node) {
            var style = node.getAttribute && (node.getAttribute('style') || '');
            styleText += ' ' + style;
        });
        match = styleText.match(/hue-rotate\(([-\d.]+)deg\)/i) || styleText.match(/hue(?:Angle)?\s*[:(]\s*([-\d.]+)/i);
        if (match && !isNaN(Number(match[1]))) return Number(match[1]);
        match = String(text || '').match(/\b([0-9]{1,3})\s*°/);
        if (match && !isNaN(Number(match[1]))) return Number(match[1]);
        return null;
    }

    function getCustomizerItemIdentitySignature(item, type) {
        if (!item) return '';
        return [
            String(type || ''),
            getCustomizerItemSource(item),
            getCustomizerItemTooltipText(item),
            getCustomizerItemDisplayText(item),
            item.querySelector('.customizer--item-selector-item--remove') ? 'remove' : ''
        ].join('|');
    }

    function clearStoredCustomizerItemIdentity(item) {
        if (!item || !item.removeAttribute) return;
        item.removeAttribute('data-ntgo-shuffle-type');
        item.removeAttribute('data-ntgo-shuffle-value');
        item.removeAttribute('data-ntgo-shuffle-miss');
        item.removeAttribute('data-ntgo-shuffle-signature');
    }

    function getCustomizerItemIdentity(item, type, options) {
        var settings = options || {};
        var allowReact = settings.allowReact !== false;
        var allowStoredIdentity = settings.allowStoredIdentity !== false;
        var value;
        var signature;
        var storedSignature;
        var attrNames = [
            'data-loot-id', 'data-lootid', 'data-nt-loot-id',
            'data-car-id', 'data-carid', 'data-id', 'lootid', 'carid'
        ];
        if (!item || !isShuffleSupportedType(type)) return null;
        signature = getCustomizerItemIdentitySignature(item, type);
        if (allowStoredIdentity && item.getAttribute('data-ntgo-shuffle-type') === String(type) && item.getAttribute('data-ntgo-shuffle-value')) {
            storedSignature = item.getAttribute('data-ntgo-shuffle-signature') || '';
            if (storedSignature && storedSignature === signature) {
                value = normalizeShuffleValue(type, item.getAttribute('data-ntgo-shuffle-value'));
                return value == null ? null : { type: type, value: value };
            }
            clearStoredCustomizerItemIdentity(item);
        }
        value = readNumericAttribute(item, attrNames);
        if (value == null) value = readNumericAttribute(item.querySelector('[data-loot-id],[data-lootid],[data-car-id],[data-carid],[data-id]'), attrNames);
        if (value == null && type === 'cars') value = inferCarIDFromCustomizerElement(item);
        if (value == null && type !== 'cars' && type !== 'paint') value = inferLootIDFromCustomizerElement(item, type);
        if (value == null && type === 'paint') value = inferPaintHueFromElement(item);
        if (value == null && allowReact) value = inferCustomizerItemIDFromReact(item, type);
        value = normalizeShuffleValue(type, value);
        if (value != null) {
            if (allowStoredIdentity) {
                item.setAttribute('data-ntgo-shuffle-type', String(type));
                item.setAttribute('data-ntgo-shuffle-value', String(value));
                item.setAttribute('data-ntgo-shuffle-signature', signature);
            } else {
                item.removeAttribute('data-ntgo-shuffle-type');
                item.removeAttribute('data-ntgo-shuffle-value');
                item.removeAttribute('data-ntgo-shuffle-signature');
            }
            item.removeAttribute('data-ntgo-shuffle-miss');
        } else {
            if (allowStoredIdentity) {
                item.setAttribute('data-ntgo-shuffle-type', String(type));
                item.setAttribute('data-ntgo-shuffle-miss', '1');
                item.setAttribute('data-ntgo-shuffle-signature', signature);
            } else {
                item.removeAttribute('data-ntgo-shuffle-type');
                item.removeAttribute('data-ntgo-shuffle-miss');
                item.removeAttribute('data-ntgo-shuffle-signature');
            }
            item.removeAttribute('data-ntgo-shuffle-value');
        }
        return value == null ? null : { type: type, value: value };
    }

    function clearCustomizerPoolItemAnnotations() {
        Array.prototype.slice.call(pageDocument.querySelectorAll('.' + SHUFFLE_POOL_SELECTED_CLASS)).forEach(function (item) {
            if (isCustomizerPoolPreviewNode(item)) return;
            item.classList.remove(SHUFFLE_POOL_SELECTED_CLASS);
        });
    }

    function getPoolCatalogLabel(type, value) {
        var entry;
        if (type === 'cars') {
            entry = getCarCatalog().byID[String(value)];
            return entry && entry.name ? entry.name : 'Car #' + value;
        }
        if (type === 'paint') return 'Paint ' + value + ' deg';
        if (isNoTrailValue(type, value)) return 'No Trail';
        entry = getLootCatalog().byID[String(value)];
        return entry && entry.name ? entry.name : getCustomizerTabInfo().label + ' #' + value;
    }

    function getPoolCatalogSource(type, value) {
        var entry;
        var src;
        if (type === 'cars') {
            entry = getCarCatalog().byID[String(value)];
            src = entry && (entry.smallSrc || entry.largeSrc);
            if (!src) return '';
            if (/^(?:https?:)?\/\//i.test(src) || src.charAt(0) === '/' || /^data:/i.test(src)) return src;
            return '/cars/' + src;
        }
        if (isNoTrailValue(type, value)) return '';
        entry = getLootCatalog().byID[String(value)];
        src = entry && (entry.src || entry.assetKey);
        if (!src) return '';
        if (/^(?:https?:)?\/\//i.test(src) || src.charAt(0) === '/' || /^data:/i.test(src)) return src;
        return src;
    }

    function getCustomizerPoolItemName(item, tabInfo, value) {
        if (isNoTrailValue(tabInfo && tabInfo.key, value)) return 'No Trail';
        return getCustomizerItemTooltipText(item) || getCustomizerItemDisplayText(item) || getPoolCatalogLabel(tabInfo.key, value);
    }

    function getCustomizerItemIdentityForPool(item, type) {
        var identity = getCustomizerItemIdentity(item, type, { allowReact: false });
        if (identity || type === 'title') return identity;
        return getCustomizerItemIdentity(item, type);
    }

    function getPoolRarityFrameClass(type, value) {
        var entry;
        var rarity;
        if (isNoTrailValue(type, value)) return '';
        if (type === 'cars') {
            entry = getCarCatalog().byID[String(value)];
            rarity = String(entry && entry.rarity || '').toLowerCase().replace(/[^a-z0-9_-]/g, '');
            return rarity ? 'rarity-frame--' + rarity : '';
        }
        if (type === 'paint') return '';
        entry = getLootCatalog().byID[String(value)];
        rarity = String(entry && entry.rarity || 'uncommon').toLowerCase().replace(/[^a-z0-9_-]/g, '');
        return rarity ? 'rarity-frame--' + rarity : 'rarity-frame--uncommon';
    }

    function getCustomizerPoolSnapshots(type) {
        var raw;
        var snapshots;
        if (!isShuffleSupportedType(type)) return {};
        try {
            raw = readToolkitGarageStorageRaw(getShufflePoolSnapshotStorageKey(type));
            snapshots = raw ? JSON.parse(raw) : {};
        } catch (e) {
            snapshots = {};
        }
        return snapshots && typeof snapshots === 'object' && !Array.isArray(snapshots) ? snapshots : {};
    }

    function setCustomizerPoolSnapshots(type, snapshots) {
        if (!isShuffleSupportedType(type)) return;
        writeToolkitGarageStorageRaw(getShufflePoolSnapshotStorageKey(type), JSON.stringify(snapshots && typeof snapshots === 'object' ? snapshots : {}));
    }

    function getCustomizerItemRarityFrameClass(item) {
        var frame;
        var match;
        if (!item) return '';
        frame = item.querySelector('.rarity-frame');
        if (!frame) return '';
        match = String(frame.className || '').match(/\brarity-frame--(common|uncommon|rare|epic|legendary|admin)\b/i);
        return match && match[0] ? match[0].toLowerCase() : '';
    }

    function captureCustomizerPoolSnapshot(tabInfo, item, value, name) {
        var snapshot = {};
        var source;
        var rarityClass;
        if (!tabInfo || !item || value == null) return null;
        source = getCustomizerItemSource(item) || getPoolCatalogSource(tabInfo.key, value);
        rarityClass = getCustomizerItemRarityFrameClass(item) || getPoolRarityFrameClass(tabInfo.key, value);
        snapshot.value = String(value);
        snapshot.name = name || getCustomizerPoolItemName(item, tabInfo, value);
        snapshot.source = source || '';
        snapshot.rarityClass = rarityClass || '';
        snapshot.remove = isNoTrailValue(tabInfo.key, value) || isNoTrailCustomizerItem(item, tabInfo.key);
        return snapshot;
    }

    function saveCustomizerPoolSnapshot(tabInfo, item, value, name) {
        var normalized = normalizeShuffleValue(tabInfo && tabInfo.key, value);
        var snapshots;
        var snapshot;
        if (!tabInfo || !normalized) return;
        snapshot = captureCustomizerPoolSnapshot(tabInfo, item, normalized, name);
        if (!snapshot) return;
        snapshots = getCustomizerPoolSnapshots(tabInfo.key);
        snapshots[String(normalized)] = snapshot;
        setCustomizerPoolSnapshots(tabInfo.key, snapshots);
    }

    function createTextCustomizerPoolItem(tabInfo, value, name) {
        var item = pageDocument.createElement('div');
        var content = pageDocument.createElement('div');
        var frame = pageDocument.createElement('div');
        var frameExtra = pageDocument.createElement('div');
        var frameContent = pageDocument.createElement('div');
        var container = pageDocument.createElement('div');
        var wrapper = pageDocument.createElement('div');
        var label = pageDocument.createElement('div');

        item.className = 'customizer--item-selector-item';
        content.className = 'customizer--item-selector-item--content';
        frame.className = 'rarity-frame ' + getPoolRarityFrameClass(tabInfo.key, value) + ' rarity-frame--small';
        frameExtra.className = 'rarity-frame--extra';
        frameContent.className = 'rarity-frame--content';
        container.className = 'customizer--item-selector-item--container';
        label.className = 'customizer--item-selector-item--name';
        label.textContent = name || getPoolCatalogLabel(tabInfo.key, value);

        wrapper.appendChild(label);
        container.appendChild(wrapper);
        frameContent.appendChild(container);
        frame.appendChild(frameExtra);
        frame.appendChild(frameContent);
        content.appendChild(frame);
        item.appendChild(content);
        return item;
    }

    function createNoTrailCustomizerPoolItem() {
        var item = pageDocument.createElement('div');
        var content = pageDocument.createElement('div');
        var container = pageDocument.createElement('div');
        var wrapper = pageDocument.createElement('div');
        var remove = pageDocument.createElement('div');
        var tooltip = pageDocument.createElement('div');

        item.className = 'customizer--item-selector-item';
        content.className = 'customizer--item-selector-item--content';
        container.className = 'customizer--item-selector-item--container';
        remove.className = 'customizer--item-selector-item--remove';
        remove.textContent = 'No Trail';
        tooltip.className = 'customizer--tooltip';
        tooltip.textContent = 'Remove Trail';

        wrapper.appendChild(remove);
        wrapper.appendChild(tooltip);
        container.appendChild(wrapper);
        content.appendChild(container);
        item.appendChild(content);
        return item;
    }

    function createFallbackCustomizerPoolItem(tabInfo, value, snapshot) {
        var item = pageDocument.createElement('div');
        var content = pageDocument.createElement('div');
        var frame = pageDocument.createElement('div');
        var frameExtra = pageDocument.createElement('div');
        var frameContent = pageDocument.createElement('div');
        var container = pageDocument.createElement('div');
        var wrapper = pageDocument.createElement('div');
        var visual = pageDocument.createElement('div');
        var tooltip = pageDocument.createElement('div');
        var saved = snapshot || {};
        var source = saved.source || getPoolCatalogSource(tabInfo.key, value);
        var label = saved.name || getPoolCatalogLabel(tabInfo.key, value);
        var rarityClass = saved.rarityClass || getPoolRarityFrameClass(tabInfo.key, value);

        if (isNoTrailValue(tabInfo.key, value)) return createNoTrailCustomizerPoolItem();

        item.className = 'customizer--item-selector-item';
        content.className = 'customizer--item-selector-item--content';
        frame.className = 'rarity-frame ' + rarityClass + ' rarity-frame--small';
        frameExtra.className = 'rarity-frame--extra';
        frameContent.className = 'rarity-frame--content';
        container.className = 'customizer--item-selector-item--container';
        visual.className = tabInfo.key === 'paint' ? 'paint-select-preview' : 'customizer--item-selector-item--vehicle';
        tooltip.className = 'customizer--tooltip';
        tooltip.textContent = label;

        if (source) {
            visual.style.backgroundImage = 'url("' + source.replace(/"/g, '\\"') + '")';
        } else if (tabInfo.key === 'paint') {
            visual.style.background = 'hsl(' + Number(value || 0) + ', 78%, 54%)';
        }

        wrapper.appendChild(visual);
        wrapper.appendChild(tooltip);
        container.appendChild(wrapper);
        frameContent.appendChild(container);
        frame.appendChild(frameExtra);
        frame.appendChild(frameContent);
        content.appendChild(frame);
        item.appendChild(content);
        return item;
    }

    function decorateCustomizerPoolPreviewItem(item, tabInfo, value, name, options) {
        var removeButton;
        var orderBadge;
        var tooltip;
        var tooltipHost;
        var settings = options || {};
        var rawOrderIndex = settings.orderIndex == null ? '' : String(settings.orderIndex);
        var tooltipText = name || getPoolCatalogLabel(tabInfo.key, value);
        var available = settings.available !== false;
        item.classList.remove('is-equipped', 'is-selected', 'is-current', 'is-previewed', 'is-hovered');
        item.classList.add(SHUFFLE_POOL_PREVIEW_ITEM_CLASS, SHUFFLE_POOL_SELECTED_CLASS);
        item.classList.toggle('is-unavailable', !available);
        item.setAttribute('data-ntgo-shuffle-type', String(tabInfo.key));
        item.setAttribute('data-ntgo-shuffle-value', String(value));
        item.setAttribute('data-ntgo-available', available ? '1' : '0');
        if (rawOrderIndex) item.setAttribute('data-ntgo-order-index', rawOrderIndex);
        else item.removeAttribute('data-ntgo-order-index');
        item.setAttribute('role', 'button');
        item.setAttribute('tabindex', '0');
        item.removeAttribute('title');
        item.setAttribute('aria-label', 'Remove ' + tooltipText + ' from pool' + (available ? '' : '. Not owned on this account'));
        if (settings.draggable) {
            item.setAttribute('draggable', 'true');
            item.setAttribute('aria-label', tooltipText + ', order ' + settings.orderNumber + (available ? '' : ', not owned on this account') + '. Drag to reorder or click to remove from pool');
        } else {
            item.removeAttribute('draggable');
        }
        if (settings.orderNumber) {
            item.setAttribute('data-ntgo-order-number', String(settings.orderNumber));
        } else {
            item.removeAttribute('data-ntgo-order-number');
        }

        Array.prototype.slice.call(item.querySelectorAll('.customizer--item-selector-item--controls')).forEach(function (controls) {
            controls.remove();
        });
        Array.prototype.slice.call(item.querySelectorAll('.customizer--tooltip,.rarity-frame--details,.rarity-frame--tooltip')).forEach(function (tooltip) {
            tooltip.remove();
        });
        Array.prototype.slice.call(item.querySelectorAll('button,input,select,a')).forEach(function (control) {
            control.setAttribute('tabindex', '-1');
            control.setAttribute('aria-hidden', 'true');
        });

        if (tabInfo.key !== 'title') {
            tooltip = pageDocument.createElement('div');
            tooltip.className = 'customizer--tooltip';
            tooltip.textContent = tooltipText;
            tooltipHost = item.querySelector('.customizer--item-selector-item--content') || item;
            tooltipHost.appendChild(tooltip);
        }

        if (settings.orderNumber) {
            orderBadge = pageDocument.createElement('div');
            orderBadge.className = 'ntgo-shuffle-pool-order-badge';
            orderBadge.textContent = String(settings.orderNumber);
            orderBadge.setAttribute('aria-hidden', 'true');
            item.appendChild(orderBadge);
        }

        removeButton = pageDocument.createElement('button');
        removeButton.type = 'button';
        removeButton.className = SHUFFLE_POOL_PREVIEW_REMOVE_CLASS;
        removeButton.textContent = 'x';
        removeButton.setAttribute('aria-hidden', 'true');
        item.appendChild(removeButton);
        return item;
    }

    function collectCustomizerPoolPreviewEntries(tabInfo) {
        var bundle = readPersistedUserState();
        var user = bundle && bundle.user;
        var pool = getShufflePool(tabInfo.key);
        var poolOrder = getShufflePoolOrder(tabInfo.key);
        var order = {};
        var orderView = getShufflePoolCycleMode(tabInfo.key) === 'ordered' || state.customizerPoolSort === 'order';
        var entries = [];
        var itemByValue = {};
        var nameByValue = {};
        var snapshotByValue = getCustomizerPoolSnapshots(tabInfo.key);
        var ownedByValue = user ? getOwnedShuffleValueMap(user, tabInfo.key) : null;
        function isAvailable(value) {
            return !ownedByValue || !!ownedByValue[String(value)];
        }

        pool.forEach(function (value, index) {
            order[String(value)] = index;
        });

        getAllCustomizerSelectorItems().forEach(function (item) {
            var identity;
            var value;
            if (!pool.length) return;
            identity = getCustomizerItemIdentityForPool(item, tabInfo.key);
            value = identity && identity.value;
            if (!value || order[String(value)] == null || itemByValue[String(value)]) return;
            itemByValue[String(value)] = item;
            nameByValue[String(value)] = getCustomizerPoolItemName(item, tabInfo, value);
            saveCustomizerPoolSnapshot(tabInfo, item, value, nameByValue[String(value)]);
            snapshotByValue[String(value)] = captureCustomizerPoolSnapshot(tabInfo, item, value, nameByValue[String(value)]) || snapshotByValue[String(value)];
        });

        if (orderView) {
            poolOrder.forEach(function (value, index) {
                if (order[String(value)] == null) return;
                entries.push({
                    index: order[String(value)],
                    orderIndex: index,
                    value: String(value),
                    name: nameByValue[String(value)] || snapshotByValue[String(value)] && snapshotByValue[String(value)].name || getPoolCatalogLabel(tabInfo.key, value),
                    item: itemByValue[String(value)] || null,
                    snapshot: snapshotByValue[String(value)] || null,
                    available: isAvailable(value)
                });
            });
        } else {
            pool.forEach(function (value, index) {
                entries.push({
                    index: index,
                    orderIndex: index,
                    value: String(value),
                    name: nameByValue[String(value)] || snapshotByValue[String(value)] && snapshotByValue[String(value)].name || getPoolCatalogLabel(tabInfo.key, value),
                    item: itemByValue[String(value)] || null,
                    snapshot: snapshotByValue[String(value)] || null,
                    available: isAvailable(value)
                });
            });
        }

        entries.sort(function (a, b) { return a.index - b.index; });
        return entries;
    }

    function getCustomizerPoolVisibleEntries(entries) {
        var filter = normalizeText(state.customizerPoolFilter).toLowerCase();
        var visible = entries.slice();
        if (filter) {
            visible = visible.filter(function (entry) {
                return String(entry.value).indexOf(filter) !== -1 ||
                    normalizeText(entry.name).toLowerCase().indexOf(filter) !== -1;
            });
        }
        if (state.customizerPoolSort === 'pool') {
            visible.sort(function (a, b) {
                return b.index - a.index;
            });
        } else if (state.customizerPoolSort === 'name') {
            visible.sort(function (a, b) {
                return normalizeText(a.name).localeCompare(normalizeText(b.name)) || Number(a.value) - Number(b.value);
            });
        } else if (state.customizerPoolSort === 'id') {
            visible.sort(function (a, b) {
                return Number(a.value) - Number(b.value);
            });
        } else if (state.customizerPoolSort === 'order') {
            visible.sort(function (a, b) {
                return a.orderIndex - b.orderIndex || a.index - b.index;
            });
        }
        return visible;
    }

    function refocusCustomizerPoolFilter(position) {
        pageWindow.requestAnimationFrame(function () {
            var input = state.customizerShuffleControls && state.customizerShuffleControls.querySelector('.ntgo-shuffle-pool-filter-input');
            if (!input && state.customizerPoolPreview) input = state.customizerPoolPreview.querySelector('.ntgo-shuffle-pool-filter-input');
            if (!input) return;
            input.focus();
            try {
                input.setSelectionRange(position, position);
            } catch (e) { }
        });
    }

    function removeCustomizerPoolPreview() {
        var previewer = state.customizerPoolPreview && state.customizerPoolPreview.parentElement;
        function clearPreviewVars(node) {
            if (!node || !node.style) return;
            node.style.removeProperty('--ntgo-pool-width');
            node.style.removeProperty('--ntgo-pool-height');
            node.style.removeProperty('--ntgo-pool-left');
            node.style.removeProperty('--ntgo-pool-top');
            node.style.removeProperty('--ntgo-pool-radius-top-left');
            node.style.removeProperty('--ntgo-pool-radius-top-right');
            node.style.removeProperty('--ntgo-pool-radius-bottom-right');
            node.style.removeProperty('--ntgo-pool-radius-bottom-left');
        }
        if (state.customizerPoolPreview) {
            state.customizerPoolPreview.remove();
            state.customizerPoolPreview = null;
        }
        state.customizerPoolDrag = null;
        clearCustomizerPoolDropState();
        if (!previewer) previewer = pageDocument.querySelector('.customizer--previewer');
        clearPreviewVars(previewer);
        clearPreviewVars(previewer && previewer.parentElement);
        clearPreviewVars(state.customizerShuffleControls);
    }

    function removeCustomizerShuffleControls() {
        var controls = state.customizerShuffleControls || pageDocument.querySelector('.' + SHUFFLE_CONTROLS_CLASS);
        if (state.customizerShufflePositionHandler) {
            pageWindow.removeEventListener('resize', state.customizerShufflePositionHandler);
            state.customizerShufflePositionHandler = null;
        }
        if (controls) controls.remove();
        state.customizerShuffleControls = null;
    }

    function getCustomizerPreviewCanvasLength(canvas, dimension, fallback) {
        var styleValue;
        var attrValue;
        if (!canvas) return fallback;
        styleValue = canvas.style && canvas.style[dimension];
        if (styleValue && /px$/.test(styleValue)) return styleValue;
        attrValue = Number(canvas.getAttribute(dimension));
        if (attrValue && !isNaN(attrValue)) return Math.round(attrValue / 2) + 'px';
        return fallback;
    }

    function syncCustomizerPoolPreviewSize(previewer) {
        var canvas = previewer && previewer.querySelector('canvas');
        var selector = pageDocument.querySelector('.customizer--item-selector:not(.' + SHUFFLE_POOL_PREVIEW_CLASS + ')');
        var previewerStyle;
        var selectorStyle;
        var width;
        var height;
        var left;
        var top;
        var radiusTopLeft;
        var radiusTopRight;
        var radiusBottomRight;
        var radiusBottomLeft;
        function setPreviewVars(node) {
            if (!node || !node.style) return;
            node.style.setProperty('--ntgo-pool-width', width);
            node.style.setProperty('--ntgo-pool-height', height);
            node.style.setProperty('--ntgo-pool-left', left);
            node.style.setProperty('--ntgo-pool-top', top);
            node.style.setProperty('--ntgo-pool-radius-top-left', radiusTopLeft);
            node.style.setProperty('--ntgo-pool-radius-top-right', radiusTopRight);
            node.style.setProperty('--ntgo-pool-radius-bottom-right', radiusBottomRight);
            node.style.setProperty('--ntgo-pool-radius-bottom-left', radiusBottomLeft);
        }
        if (!previewer || !previewer.style) return;
        previewerStyle = pageWindow.getComputedStyle ? pageWindow.getComputedStyle(previewer) : null;
        selectorStyle = selector && pageWindow.getComputedStyle ? pageWindow.getComputedStyle(selector) : null;
        width = getCustomizerPreviewCanvasLength(canvas, 'width', '559px');
        height = getCustomizerPreviewCanvasLength(canvas, 'height', '500px');
        left = previewerStyle && previewerStyle.left ? previewerStyle.left : '10px';
        top = selectorStyle && selectorStyle.top ? selectorStyle.top : '90px';
        radiusTopLeft = previewerStyle && previewerStyle.borderTopLeftRadius ? previewerStyle.borderTopLeftRadius : '6px';
        radiusTopRight = previewerStyle && previewerStyle.borderTopRightRadius ? previewerStyle.borderTopRightRadius : '6px';
        radiusBottomRight = previewerStyle && previewerStyle.borderBottomRightRadius ? previewerStyle.borderBottomRightRadius : '6px';
        radiusBottomLeft = previewerStyle && previewerStyle.borderBottomLeftRadius ? previewerStyle.borderBottomLeftRadius : '6px';
        setPreviewVars(previewer);
        setPreviewVars(previewer.parentElement);
        setPreviewVars(state.customizerShuffleControls);
    }

    function renderCustomizerPoolPreview(tabInfo) {
        var previewer;
        var selector;
        var panel;
        var content;
        var container;
        var scroller;
        var grid;
        var empty;
        var emptyTitle;
        var emptyText;
        var entries;
        var visibleEntries;
        var signature;
        var orderView;
        var canDragOrder;
        var cycleMode;

        if (!state.customizerPoolMode || state.customizerPoolType !== tabInfo.key || !isShuffleSupportedType(tabInfo.key)) {
            removeCustomizerPoolPreview();
            return;
        }

        previewer = pageDocument.querySelector('.customizer--previewer');
        selector = pageDocument.querySelector('.customizer--item-selector:not(.' + SHUFFLE_POOL_PREVIEW_CLASS + ')');
        if (!previewer) {
            removeCustomizerPoolPreview();
            return;
        }

        syncCustomizerPoolPreviewSize(previewer);
        cycleMode = getShufflePoolCycleMode(tabInfo.key);
        if (cycleMode === 'ordered') state.customizerPoolSort = 'order';
        entries = collectCustomizerPoolPreviewEntries(tabInfo);
        visibleEntries = getCustomizerPoolVisibleEntries(entries);
        orderView = state.customizerPoolSort === 'order';
        canDragOrder = orderView && !state.customizerPoolFilter;
        signature = tabInfo.key + '|' + cycleMode + '|' + state.customizerPoolFilter + '|' + state.customizerPoolSort + '|' + entries.map(function (entry) {
            return entry.value + ':' + entry.name + ':' + entry.index + ':' + entry.orderIndex + ':' + (entry.available ? '1' : '0');
        }).join(',') + '|drag:' + (canDragOrder ? '1' : '0');

        panel = state.customizerPoolPreview;
        if (!panel || !panel.isConnected || panel.parentElement !== previewer) {
            panel = pageDocument.createElement('div');
            previewer.appendChild(panel);
            state.customizerPoolPreview = panel;
        } else if (panel.getAttribute('data-ntgo-signature') === signature) {
            return;
        }

        panel.className = SHUFFLE_POOL_PREVIEW_CLASS + ' ' + (selector && selector.className ? String(selector.className).replace(SHUFFLE_POOL_PREVIEW_CLASS, '') : 'customizer--item-selector show-search scrollable');
        panel.setAttribute('data-ntgo-pool-type', String(tabInfo.key));
        panel.setAttribute('data-ntgo-pool-sort', String(state.customizerPoolSort || 'pool'));
        panel.setAttribute('data-ntgo-cycle-mode', String(cycleMode));
        panel.classList.toggle('is-order-view', orderView);
        panel.classList.toggle('is-order-draggable', canDragOrder);
        panel.classList.toggle('is-pool-ignored', cycleMode === 'ignore');
        panel.setAttribute('data-ntgo-signature', signature);
        panel.textContent = '';

        content = pageDocument.createElement('div');
        content.className = 'customizer--item-selector-content ntgo-shuffle-pool-preview-content';
        panel.appendChild(content);

        container = pageDocument.createElement('div');
        container.className = 'customizer--item-selector-container ntgo-shuffle-pool-preview-container';
        content.appendChild(container);

        scroller = pageDocument.createElement('div');
        scroller.className = 'ntgo-shuffle-pool-preview-scroller';
        container.appendChild(scroller);

        grid = pageDocument.createElement('div');
        grid.className = SHUFFLE_POOL_PREVIEW_GRID_CLASS + ' customizer--item-selector-items';
        scroller.appendChild(grid);

        if (!entries.length || !visibleEntries.length) {
            empty = pageDocument.createElement('div');
            empty.className = SHUFFLE_POOL_PREVIEW_EMPTY_CLASS;
            if (entries.length) {
                empty.textContent = 'No matches';
            } else {
                emptyTitle = pageDocument.createElement('div');
                emptyTitle.className = 'ntgo-shuffle-pool-preview-empty-title';
                emptyTitle.textContent = 'Pool empty';
                empty.appendChild(emptyTitle);

                emptyText = pageDocument.createElement('div');
                emptyText.className = 'ntgo-shuffle-pool-preview-empty-text';
                emptyText.textContent = 'Select items from the list on the right. Auto shuffle will only choose from your pool.';
                empty.appendChild(emptyText);
            }
            grid.appendChild(empty);
            return;
        }

        visibleEntries.forEach(function (entry) {
            var clone = tabInfo.key === 'title'
                ? createTextCustomizerPoolItem(tabInfo, entry.value, entry.name)
                : (entry.item ? entry.item.cloneNode(true) : createFallbackCustomizerPoolItem(tabInfo, entry.value, entry.snapshot));
            grid.appendChild(decorateCustomizerPoolPreviewItem(clone, tabInfo, entry.value, entry.name, {
                orderNumber: orderView ? entry.orderIndex + 1 : 0,
                orderIndex: orderView ? entry.orderIndex : null,
                draggable: canDragOrder,
                available: entry.available
            }));
        });
    }

    function annotateCustomizerPoolItems() {
        var tabInfo = getCustomizerTabInfo();
        var pool;
        var selected = {};

        if (!state.customizerPoolMode || state.customizerPoolType !== tabInfo.key || !isShuffleSupportedType(tabInfo.key)) {
            clearCustomizerPoolItemAnnotations();
            removeCustomizerPoolPreview();
            return;
        }

        pool = getShufflePool(tabInfo.key);
        if (!pool.length) {
            clearCustomizerPoolItemAnnotations();
            renderCustomizerPoolPreview(tabInfo);
            return;
        }

        pool.forEach(function (value) {
            selected[String(value)] = true;
        });

        getAllCustomizerSelectorItems().forEach(function (item) {
            var identity = getCustomizerItemIdentityForPool(item, tabInfo.key);
            item.classList.toggle(SHUFFLE_POOL_SELECTED_CLASS, !!(identity && selected[String(identity.value)]));
        });

        renderCustomizerPoolPreview(tabInfo);
    }

    function toggleCustomizerPoolItem(tabInfo, item) {
        var identity;
        var pool;
        var isSelected;
        var added;
        var name;
        var duplicateMode;
        if (!item || !tabInfo || !isShuffleSupportedType(tabInfo.key)) return false;
        identity = getCustomizerItemIdentityForPool(item, tabInfo.key) || getCustomizerItemIdentity(item, tabInfo.key);
        if (!identity || !identity.value) {
            logWarn('Could not identify this ' + tabInfo.label + ' for the shuffle pool.');
            return false;
        }
        pool = getShufflePool(tabInfo.key);
        isSelected = pool.indexOf(String(identity.value)) !== -1;
        duplicateMode = isSelected && getShufflePoolCycleMode(tabInfo.key) === 'ordered' && allowsOrderedPoolDuplicates(tabInfo.key);
        name = getCustomizerPoolItemName(item, tabInfo, identity.value);
        saveCustomizerPoolSnapshot(tabInfo, item, identity.value, name);
        added = duplicateMode
            ? addShufflePoolOrderOccurrence(tabInfo.key, identity.value)
            : setShufflePoolValueSelected(tabInfo.key, identity.value, !isSelected);
        item.classList.toggle(SHUFFLE_POOL_SELECTED_CLASS, duplicateMode || !isSelected);
        updateCustomizerShuffleToggle();
        annotateCustomizerPoolItems();
        if (added) {
            logInfo((duplicateMode ? 'Added another ' : (!isSelected ? 'Added ' : 'Removed ')) + name + ' ' + (duplicateMode || !isSelected ? 'to' : 'from') + ' the shuffle pool.');
        }
        return true;
    }

    function removeCustomizerPoolValue(tabInfo, value, orderIndex) {
        var changed = getShufflePoolCycleMode(tabInfo.key) === 'ordered' && allowsOrderedPoolDuplicates(tabInfo.key)
            ? removeShufflePoolOrderOccurrence(tabInfo.key, value, orderIndex)
            : setShufflePoolValueSelected(tabInfo.key, value, false);
        updateCustomizerShuffleToggle();
        annotateCustomizerPoolItems();
        if (changed) logInfo('Removed ' + getPoolCatalogLabel(tabInfo.key, value) + ' from the shuffle pool.');
        return changed;
    }

    function moveCustomizerPoolOrderValue(type, value, targetValue, afterTarget, fromOrderIndex, targetOrderIndex) {
        var normalized = normalizeShuffleValue(type, value);
        var target = normalizeShuffleValue(type, targetValue);
        var order;
        var fromIndex;
        var targetIndex;
        var insertIndex;
        if (!normalized || !target) return false;
        order = getShufflePoolOrder(type);
        fromIndex = Number(fromOrderIndex);
        targetIndex = Number(targetOrderIndex);
        if (isNaN(fromIndex) || fromIndex < 0 || fromIndex >= order.length || order[fromIndex] !== normalized) {
            fromIndex = order.indexOf(normalized);
        }
        if (isNaN(targetIndex) || targetIndex < 0 || targetIndex >= order.length || order[targetIndex] !== target) {
            targetIndex = order.indexOf(target);
        }
        if (fromIndex === -1 || targetIndex === -1) return false;
        if (fromIndex === targetIndex) return false;
        order.splice(fromIndex, 1);
        if (fromIndex < targetIndex) targetIndex -= 1;
        insertIndex = targetIndex + (afterTarget ? 1 : 0);
        if (insertIndex < 0) insertIndex = 0;
        if (insertIndex > order.length) insertIndex = order.length;
        order.splice(insertIndex, 0, normalized);
        setShufflePoolOrder(type, order);
        setShufflePoolOrderIndex(0);
        return true;
    }

    function getCustomizerPoolDropTarget(event) {
        var previewItem = event && event.target && event.target.closest ? event.target.closest('.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS) : null;
        var rect;
        var after = false;
        if (!previewItem || !isCustomizerPoolPreviewNode(previewItem)) return null;
        rect = previewItem.getBoundingClientRect();
        if (rect.width && rect.height) {
            after = event.clientY > rect.top + rect.height * 0.62 ||
                (event.clientY > rect.top + rect.height * 0.35 && event.clientX > rect.left + rect.width / 2);
        }
        return {
            item: previewItem,
            value: previewItem.getAttribute('data-ntgo-shuffle-value'),
            orderIndex: previewItem.getAttribute('data-ntgo-order-index'),
            after: after
        };
    }

    function clearCustomizerPoolDropState() {
        Array.prototype.slice.call(pageDocument.querySelectorAll('.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '.is-order-drop-before,.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '.is-order-drop-after,.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '.is-order-dragging')).forEach(function (item) {
            item.classList.remove('is-order-drop-before', 'is-order-drop-after', 'is-order-dragging');
        });
    }

    function handleCustomizerPoolDragStart(event) {
        var tabInfo;
        var previewItem;
        var value;
        if (!state.customizerPoolMode || !isCustomizerPage() || state.customizerPoolSort !== 'order' || state.customizerPoolFilter) return false;
        tabInfo = getCustomizerTabInfo();
        if (state.customizerPoolType !== tabInfo.key || !isShuffleSupportedType(tabInfo.key)) return false;
        previewItem = event.target && event.target.closest ? event.target.closest('.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS) : null;
        if (!previewItem || !isCustomizerPoolPreviewNode(previewItem)) return false;
        value = previewItem.getAttribute('data-ntgo-shuffle-value');
        if (!value) return false;
        state.customizerPoolDrag = {
            type: tabInfo.key,
            value: String(value),
            orderIndex: previewItem.getAttribute('data-ntgo-order-index')
        };
        previewItem.classList.add('is-order-dragging');
        if (event.dataTransfer) {
            event.dataTransfer.effectAllowed = 'move';
            try { event.dataTransfer.setData('text/plain', String(value)); } catch (e) { }
        }
        event.stopPropagation();
        if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
        return true;
    }

    function handleCustomizerPoolDragTarget(event) {
        var target;
        if (!state.customizerPoolDrag) return false;
        event.preventDefault();
        event.stopPropagation();
        if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
        target = getCustomizerPoolDropTarget(event);
        clearCustomizerPoolDropState();
        if (target && target.value && String(target.orderIndex) !== String(state.customizerPoolDrag.orderIndex)) {
            target.item.classList.add(target.after ? 'is-order-drop-after' : 'is-order-drop-before');
        }
        if (event.dataTransfer) event.dataTransfer.dropEffect = 'move';
        return true;
    }

    function handleCustomizerPoolDrop(event) {
        var target;
        var changed;
        if (!state.customizerPoolDrag) return false;
        event.preventDefault();
        event.stopPropagation();
        if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
        target = getCustomizerPoolDropTarget(event);
        if (target && target.value) {
            changed = moveCustomizerPoolOrderValue(state.customizerPoolDrag.type, state.customizerPoolDrag.value, target.value, target.after, state.customizerPoolDrag.orderIndex, target.orderIndex);
        }
        state.customizerPoolDrag = null;
        state.customizerPoolSuppressClickUntil = Date.now() + 400;
        clearCustomizerPoolDropState();
        if (changed) {
            updateCustomizerShuffleToggle();
            renderCustomizerPoolPreview(getCustomizerTabInfo());
        }
        return true;
    }

    function handleCustomizerPoolDragEnd(event) {
        if (!state.customizerPoolDrag) return false;
        state.customizerPoolDrag = null;
        state.customizerPoolSuppressClickUntil = Date.now() + 300;
        clearCustomizerPoolDropState();
        if (event) {
            event.stopPropagation();
            if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
        }
        return true;
    }

    function getCustomizerItemClickTarget(item) {
        var rect;
        var centerTarget;
        if (!item) return null;
        rect = item.getBoundingClientRect();
        if (rect.width && rect.height && pageDocument.elementFromPoint) {
            centerTarget = pageDocument.elementFromPoint(rect.left + rect.width / 2, rect.top + rect.height / 2);
            if (centerTarget && (centerTarget === item || item.contains(centerTarget))) {
                return centerTarget;
            }
        }
        return item.querySelector(
            '.customizer--item-selector-item--vehicle,' +
            '.customizer--item-selector-item--container,' +
            '.paint-select-preview,' +
            '.customizer--item-selector-item--content'
        ) || item;
    }

    function dispatchCustomizerItemClick(item) {
        var target = getCustomizerItemClickTarget(item);
        var rect = target && target.getBoundingClientRect ? target.getBoundingClientRect() : null;
        var eventInit = {
            bubbles: true,
            cancelable: true,
            view: pageWindow
        };
        if (!target) return false;
        if (rect) {
            eventInit.clientX = Math.max(1, Math.min(pageWindow.innerWidth - 1, rect.left + rect.width / 2));
            eventInit.clientY = Math.max(1, Math.min(pageWindow.innerHeight - 1, rect.top + rect.height / 2));
        }
        ['pointerdown', 'mousedown', 'mouseup', 'click'].forEach(function (type) {
            target.dispatchEvent(new MouseEvent(type, eventInit));
        });
        return true;
    }

    function getScrollableAncestors(node) {
        var ancestors = [];
        var current = node && node.parentElement;
        var style;
        while (current && current !== pageDocument.body && current !== pageDocument.documentElement) {
            style = pageWindow.getComputedStyle ? pageWindow.getComputedStyle(current) : null;
            if ((current.scrollHeight > current.clientHeight || current.scrollWidth > current.clientWidth) &&
                    (!style || /(auto|scroll|overlay)/.test(style.overflow + style.overflowY + style.overflowX))) {
                ancestors.push({
                    node: current,
                    top: current.scrollTop,
                    left: current.scrollLeft
                });
            }
            current = current.parentElement;
        }
        ancestors.push({
            node: pageWindow,
            top: pageWindow.pageYOffset || pageDocument.documentElement.scrollTop || pageDocument.body.scrollTop || 0,
            left: pageWindow.pageXOffset || pageDocument.documentElement.scrollLeft || pageDocument.body.scrollLeft || 0
        });
        return ancestors;
    }

    function restoreScrollPositions(positions) {
        positions.forEach(function (entry) {
            if (!entry || !entry.node) return;
            if (entry.node === pageWindow) {
                pageWindow.scrollTo(entry.left, entry.top);
            } else {
                entry.node.scrollTop = entry.top;
                entry.node.scrollLeft = entry.left;
            }
        });
    }

    function dispatchCustomizerItemClickWhenVisible(item) {
        var positions;
        if (!item) return false;
        try {
            positions = getScrollableAncestors(item);
            try {
                item.scrollIntoView({ block: 'center', inline: 'nearest' });
            } catch (e) {
                try { item.scrollIntoView(); } catch (ex) { }
            }
            dispatchCustomizerItemClick(item);
            restoreScrollPositions(positions);
            pageWindow.requestAnimationFrame(function () {
                restoreScrollPositions(positions);
            });
            return true;
        } catch (e) {
            logWarn('Customizer shuffle click failed', e && e.message ? e.message : e);
            if (positions) restoreScrollPositions(positions);
        }
        return false;
    }

    function shuffleCustomizerVisibleItem(options) {
        var settings = options || {};
        var tabInfo = getCustomizerTabInfo();
        var pool = settings.ignorePool ? [] : getShufflePool(tabInfo.key);
        var selected = {};
        var items = getCustomizerItems();
        var candidates;
        var currentValue;
        var identity;
        if (!isShuffleSupportedType(tabInfo.key)) return false;
        pool.forEach(function (value) { selected[String(value)] = true; });
        currentValue = getCurrentShuffleValue((readPersistedUserState() || {}).user || {}, tabInfo.key);
        candidates = items.filter(function (item) {
            identity = getCustomizerItemIdentityForPool(item, tabInfo.key);
            if (pool.length && (!identity || !selected[String(identity.value)])) return false;
            if (identity && currentValue != null && String(identity.value) === String(currentValue)) return false;
            return !item.classList.contains('is-equipped') && !item.classList.contains('is-selected') && !item.classList.contains('is-current');
        });
        var target;
        if (!candidates.length && pool.length) {
            logWarn('Could not shuffle from pool: no selected ' + tabInfo.label + ' tiles are currently available.');
            return false;
        }
        if (!candidates.length) candidates = items;
        if (!candidates.length) {
            logWarn('Could not shuffle customizer item: no selectable items were found.');
            return false;
        }
        target = candidates[Math.floor(Math.random() * candidates.length)];
        return dispatchCustomizerItemClickWhenVisible(target);
    }

    function getStoredAutoShuffleSessionRaces() {
        var raw = readToolkitGarageStorageRaw(AUTO_SHUFFLE_LAST_SESSION_RACES_KEY);
        var value = raw == null ? NaN : Number(raw);
        return isNaN(value) ? null : value;
    }

    function setStoredAutoShuffleSessionRaces(value) {
        writeToolkitGarageStorageRaw(AUTO_SHUFFLE_LAST_SESSION_RACES_KEY, String(Number(value || 0)));
    }

    function createAutoShuffleTask(user, type, orderIndex) {
        var cycleMode = getShufflePoolCycleMode(type);
        var orderedMode = cycleMode === 'ordered';
        var ignorePool = cycleMode === 'ignore';
        var hasOrderedPool = orderedMode && getShufflePoolOrder(type).length > 0;
        var value = pickShuffleValue(user, type, { ignorePool: ignorePool, ordered: hasOrderedPool, orderIndex: orderIndex });
        var numberValue;
        if (value == null) return null;
        numberValue = Number(value);
        if (isNaN(numberValue)) return null;
        return {
            type: type,
            value: numberValue,
            ordered: hasOrderedPool,
            label: type === 'paint' ? 'Paint ' + numberValue + ' deg' : getPoolCatalogLabel(type, numberValue)
        };
    }

    function buildAutoShuffleTaskEquip(bundle, task) {
        var overrides = {};
        if (task.type === 'cars') {
            overrides.carID = task.value;
            overrides.hueAngle = getCarHueAngle(bundle.user, task.value);
        } else if (task.type === 'paint') {
            overrides.carID = bundle.user.carID;
            overrides.hueAngle = task.value;
        } else if (task.type === 'trail') {
            overrides.trailID = task.value;
        } else if (task.type === 'nitro') {
            overrides.nitroID = task.value;
        } else if (task.type === 'nametag') {
            overrides.nametagID = task.value;
        } else if (task.type === 'title') {
            overrides.titleID = task.value;
        }
        return buildEquipConfig(bundle.user, overrides);
    }

    function persistAutoShuffleTask(bundle, task, equip) {
        if (task.type === 'cars') {
            updatePersistedEquippedCar(bundle, task.value, equip.hueAngle);
        } else if (task.type === 'paint') {
            updatePersistedEquippedCar(bundle, bundle.user.carID, equip.hueAngle);
        } else if (task.type === 'trail' || task.type === 'nitro' || task.type === 'nametag' || task.type === 'title') {
            updatePersistedEquippedLoot(bundle, task.type, task.value);
        }
    }

    function readEquipResponsePayload(response) {
        return response.text().then(function (text) {
            if (!text) return null;
            try {
                return JSON.parse(text);
            } catch (e) {
                return null;
            }
        });
    }

    function getAutoShufflePayloadFailureMessage(payload) {
        var error;
        if (!payload || typeof payload !== 'object') return '';
        if (payload.success === false || payload.ok === false || String(payload.status || '').toLowerCase() === 'error') {
            error = payload.error || payload.errors || payload.message || payload.statusText || 'API rejected equip request';
        } else if (payload.error) {
            error = payload.error;
        } else if (Array.isArray(payload.errors) && payload.errors.length) {
            error = payload.errors[0];
        }
        if (!error) return '';
        if (typeof error === 'string') return error;
        return error.message || error.detail || error.title || 'API rejected equip request';
    }

    function findAutoShuffleUserPayload(value, seen, depth) {
        var keys;
        var found = null;
        if (!value || typeof value !== 'object' || depth > 6) return null;
        if (seen.indexOf(value) !== -1) return null;
        seen.push(value);
        if (!Array.isArray(value) && Array.isArray(value.loot) && (value.carID != null || value.userID != null || value.username != null || value.displayName != null)) {
            return value;
        }
        if (Array.isArray(value)) {
            value.some(function (item) {
                found = findAutoShuffleUserPayload(item, seen, depth + 1);
                return !!found;
            });
            return found;
        }
        keys = Object.keys(value);
        keys.some(function (key) {
            found = findAutoShuffleUserPayload(value[key], seen, depth + 1);
            return !!found;
        });
        return found;
    }

    function findAutoShuffleEquipConfigPayload(value, seen, depth) {
        var keys;
        var found = null;
        if (!value || typeof value !== 'object' || depth > 6) return null;
        if (seen.indexOf(value) !== -1) return null;
        seen.push(value);
        if (Array.isArray(value) && value.some(function (item) {
            return item && typeof item === 'object' && typeof item.type === 'string' &&
                (item.id != null || item.ids != null || item.hueAngle != null || item.disablePerk != null);
        })) {
            return value;
        }
        if (Array.isArray(value)) {
            value.some(function (item) {
                found = findAutoShuffleEquipConfigPayload(item, seen, depth + 1);
                return !!found;
            });
            return found;
        }
        keys = Object.keys(value);
        keys.some(function (key) {
            found = findAutoShuffleEquipConfigPayload(value[key], seen, depth + 1);
            return !!found;
        });
        return found;
    }

    function autoShuffleTaskMatchesUser(user, task) {
        var equipped;
        if (!user || !task) return false;
        if (task.type === 'cars') return String(user.carID) === String(task.value);
        if (task.type === 'paint') {
            return String(normalizeShuffleValue('paint', getCarHueAngle(user, user.carID))) === String(normalizeShuffleValue('paint', task.value));
        }
        if (isNoTrailValue(task.type, task.value)) return !getEquippedLootItem(user, 'trail');
        equipped = getEquippedLootItem(user, task.type);
        return !!(equipped && String(equipped.lootID) === String(task.value));
    }

    function autoShuffleTaskMatchesEquipConfig(config, task) {
        var apiType;
        var entry;
        if (!Array.isArray(config) || !task) return false;
        apiType = task.type === 'cars' || task.type === 'paint' ? 'car' : task.type;
        entry = config.filter(function (item) {
            return item && String(item.type) === apiType;
        })[0];
        if (!entry) return false;
        if (task.type === 'paint') return String(normalizeShuffleValue('paint', entry.hueAngle)) === String(normalizeShuffleValue('paint', task.value));
        if (isNoTrailValue(task.type, task.value)) return entry.id == null || String(entry.id) === NO_TRAIL_VALUE;
        return String(entry.id) === String(task.value);
    }

    function validateAutoShuffleEquipPayload(payload, task) {
        var failure = getAutoShufflePayloadFailureMessage(payload);
        var user;
        var config;
        if (failure) throw new Error(failure);
        if (!payload || typeof payload !== 'object') return false;
        user = findAutoShuffleUserPayload(payload, [], 0);
        if (user && autoShuffleTaskMatchesUser(user, task)) return true;
        config = findAutoShuffleEquipConfigPayload(payload, [], 0);
        if (config) {
            if (!autoShuffleTaskMatchesEquipConfig(config, task)) throw new Error('API response did not confirm ' + task.label + '.');
            return true;
        }
        return false;
    }

    function postAutoShuffleTask(bundle, token, task) {
        var equip = buildAutoShuffleTaskEquip(bundle, task);
        return pageWindow.fetch('/api/v2/loot/equip', {
            method: 'POST',
            credentials: 'include',
            headers: {
                'Accept': 'application/json',
                'Authorization': 'Bearer ' + token,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(equip.config)
        }).then(function (response) {
            if (!response.ok) throw new Error('HTTP ' + response.status);
            return readEquipResponsePayload(response);
        }).then(function (payload) {
            var confirmed = validateAutoShuffleEquipPayload(payload, task);
            persistAutoShuffleTask(bundle, task, equip);
            logInfo('Auto shuffle ' + (confirmed ? 'confirmed ' : 'accepted ') + task.label + '.');
            return true;
        }).catch(function (error) {
            if (error) error.ntgoTaskLabel = task.label;
            throw error;
        });
    }

    function runAutoShuffleChain(enabledTypes) {
        var bundle = readPersistedUserState();
        var token;
        var user;
        var tasks = [];
        var baseOrderIndex = getShufflePoolOrderIndex();
        var orderIndex;
        var usedOrderedPool = false;
        var blockedOrderedTypes = [];
        var chain;

        if (!bundle || !bundle.user) return;
        user = bundle.user;
        (enabledTypes || []).forEach(function (type) {
            if (getShufflePoolCycleMode(type) === 'ordered' && getShufflePoolOrder(type).length && !isShufflePoolOrderFullyAvailable(user, type)) {
                blockedOrderedTypes.push(type);
            }
        });
        if (blockedOrderedTypes.length) {
            logWarn('Auto shuffle skipped: ordered pool has unavailable items for ' + blockedOrderedTypes.join(', ') + '.');
            return;
        }
        orderIndex = getSharedAutoShuffleOrderIndex(user, enabledTypes, baseOrderIndex);
        token = getLiveToken();
        if (!token) {
            logWarn('Auto shuffle skipped: session token unavailable or expired.');
            return;
        }
        if (state.normalEquipApplying) {
            logInfo('Auto shuffle skipped: another equip request is already running.');
            return;
        }

        enabledTypes.forEach(function (type) {
            var task = createAutoShuffleTask(user, type, orderIndex);
            if (!task) return;
            tasks.push(task);
            if (task.ordered) usedOrderedPool = true;
        });

        if (!tasks.length) {
            logInfo('Auto shuffle: nothing to change.');
            return;
        }

        state.normalEquipApplying = true;
        logInfo('Auto shuffle queue: ' + tasks.map(function (task) { return task.label; }).join(', ') + '.');
        chain = tasks.reduce(function (promise, task) {
            return promise.then(function () {
                return postAutoShuffleTask(bundle, token, task);
            });
        }, Promise.resolve());

        chain.then(function () {
            if (usedOrderedPool) advanceShufflePoolOrderIndex();
            logInfo('Auto shuffle complete.');
        }).catch(function (error) {
            logWarn('Auto shuffle stopped at ' + (error && error.ntgoTaskLabel ? error.ntgoTaskLabel : 'a queued item') + '.', error && error.message ? error.message : error);
        }).then(function () {
            state.normalEquipApplying = false;
        });
    }

    function checkAutoShuffleSessionRaces() {
        var bundle = readPersistedUserState();
        var current;
        var last;
        var enabledTypes;
        if (!bundle || !bundle.user) return;

        current = Number(bundle.user.sessionRaces || 0);
        last = getStoredAutoShuffleSessionRaces();
        enabledTypes = getEnabledAutoShuffleTypes();
        if (last == null || current < last || !enabledTypes.length) {
            setStoredAutoShuffleSessionRaces(current);
            return;
        }
        if (current > last) {
            setStoredAutoShuffleSessionRaces(current);
            logInfo('New race detected (session ' + last + ' → ' + current + '). Shuffling in ' + Math.round(AUTO_SHUFFLE_RACE_DELAY_MS / 1000) + ' second...');
            pageWindow.setTimeout(function () {
                runAutoShuffleChain(enabledTypes);
            }, AUTO_SHUFFLE_RACE_DELAY_MS);
        }
    }

    function startAutoShuffleSessionWatcher() {
        if (state.autoShuffleSessionTimer) return;
        checkAutoShuffleSessionRaces();
        state.autoShuffleSessionTimer = pageWindow.setInterval(checkAutoShuffleSessionRaces, 1000);
    }

    function stopAutoShuffleSessionWatcher() {
        if (!state.autoShuffleSessionTimer) return;
        pageWindow.clearInterval(state.autoShuffleSessionTimer);
        state.autoShuffleSessionTimer = 0;
    }

    function resetCustomizerTitlePreviewTilt() {
        var titlePreview = pageDocument.querySelector('.customizer--preview.title-preview');
        var tiltNode = titlePreview && titlePreview.querySelector('.title-preview--card > div');
        if (!tiltNode || !tiltNode.style) return;
        tiltNode.style.transform = 'rotateX(0deg) rotateY(0deg)';
        tiltNode.style.transition = 'transform 0.5s';
    }

    function setCustomizerPoolMode(enabled, type) {
        var key = type || getCustomizerTabInfo().key;
        if (key === 'title') resetCustomizerTitlePreviewTilt();
        state.customizerPoolMode = !!(enabled && isShuffleSupportedType(key));
        state.customizerPoolType = state.customizerPoolMode ? key : null;
        state.customizerPoolDrag = null;
        pageDocument.body.classList.toggle(SHUFFLE_POOL_MODE_CLASS, state.customizerPoolMode);
        clearCustomizerPoolItemAnnotations();
        if (!state.customizerPoolMode) removeCustomizerPoolPreview();
        updateCustomizerShuffleToggle();
        annotateCustomizerPoolItems();
    }

    function isCustomizerPoolBlockedClickTarget(target) {
        return !!(target && target.closest && (
            target.closest('.' + SHUFFLE_CONTROLS_CLASS) ||
            target.closest('.customizer--tabs') ||
            target.closest('.customizer--item-selector-item--controls') ||
            target.closest('.customizer--item-selector-item--favorite') ||
            target.closest('.customizer--item-selector-item--hide')
        ));
    }

    function handleCustomizerPoolItemEvent(event) {
        var tabInfo;
        var item;
        var previewItem;
        var value;
        if (!state.customizerPoolMode || !isCustomizerPage()) return;
        tabInfo = getCustomizerTabInfo();
        if (state.customizerPoolType !== tabInfo.key || !isShuffleSupportedType(tabInfo.key)) {
            setCustomizerPoolMode(false);
            return;
        }
        if (Date.now() < state.customizerPoolSuppressClickUntil) {
            event.preventDefault();
            event.stopPropagation();
            if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
            return;
        }

        previewItem = event.target && event.target.closest ? event.target.closest('.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS) : null;
        if (previewItem && isCustomizerPoolPreviewNode(previewItem)) {
            event.preventDefault();
            event.stopPropagation();
            if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
            value = previewItem.getAttribute('data-ntgo-shuffle-value');
            if (value) removeCustomizerPoolValue(tabInfo, value, previewItem.getAttribute('data-ntgo-order-index'));
            return;
        }

        if (isCustomizerPoolBlockedClickTarget(event.target)) return;
        item = event.target && event.target.closest ? event.target.closest('.customizer--item-selector-item') : null;
        if (!item || isCustomizerPoolPreviewNode(item)) return;
        event.preventDefault();
        event.stopPropagation();
        if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
        toggleCustomizerPoolItem(tabInfo, item);
    }

    function handleCustomizerPoolPointerDown(event) {
        var tabInfo;
        var item;
        var previewItem;
        if (!state.customizerPoolMode || !isCustomizerPage()) return;
        tabInfo = getCustomizerTabInfo();
        if (state.customizerPoolType !== tabInfo.key || !isShuffleSupportedType(tabInfo.key)) return;

        previewItem = event.target && event.target.closest ? event.target.closest('.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS) : null;
        item = event.target && event.target.closest ? event.target.closest('.customizer--item-selector-item') : null;
        if ((!previewItem || !isCustomizerPoolPreviewNode(previewItem)) &&
                (!item || isCustomizerPoolPreviewNode(item) || isCustomizerPoolBlockedClickTarget(event.target))) {
            return;
        }

        event.stopPropagation();
        if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
    }

    function syncCustomizerTabState() {
        var tabInfo;
        if (!isCustomizerPage()) return;
        ensureCustomizerShuffleControls();
        tabInfo = getCustomizerTabInfo();
        if (state.customizerPoolMode && state.customizerPoolType !== tabInfo.key) {
            setCustomizerPoolMode(false, tabInfo.key);
        } else {
            clearCustomizerPoolItemAnnotations();
            updateCustomizerShuffleToggle();
            annotateCustomizerPoolItems();
        }
    }

    function scheduleCustomizerTabSync() {
        if (state.customizerTabSwitchTimer) pageWindow.clearTimeout(state.customizerTabSwitchTimer);
        if (pageWindow.requestAnimationFrame) {
            pageWindow.requestAnimationFrame(syncCustomizerTabState);
        } else {
            syncCustomizerTabState();
        }
        state.customizerTabSwitchTimer = pageWindow.setTimeout(function () {
            state.customizerTabSwitchTimer = 0;
            syncCustomizerTabState();
        }, 60);
    }

    function onCustomizerTabClick(event) {
        if (!isCustomizerPage()) return;
        if (!(event.target && event.target.closest && event.target.closest('.customizer--tab'))) return;
        scheduleCustomizerTabSync();
    }

    function positionCustomizerShuffleControls() {
        var controls = state.customizerShuffleControls;
        var previewer = pageDocument.querySelector('.customizer--previewer');
        if (!controls || controls.hidden || !previewer) return;
        syncCustomizerPoolPreviewSize(previewer);
    }

    function updateCustomizerPoolToolbarSortOptions(sortSelect, tabInfo) {
        var option;
        var orderedMode = getShufflePoolCycleMode(tabInfo.key) === 'ordered';
        if (!sortSelect) return;
        if (orderedMode) state.customizerPoolSort = 'order';
        if (sortSelect.getAttribute('data-ntgo-type') !== tabInfo.key) {
            sortSelect.textContent = '';
            [
                { value: 'pool', label: 'Newest First' },
                { value: 'order', label: 'Order' },
                { value: 'name', label: 'Name' },
                { value: 'id', label: tabInfo.key === 'cars' ? 'Car ID' : 'Item ID' }
            ].forEach(function (entry) {
                option = pageDocument.createElement('option');
                option.className = 'ntgo-shuffle-pool-sort-option';
                option.value = entry.value;
                option.textContent = entry.label;
                sortSelect.appendChild(option);
            });
            sortSelect.setAttribute('data-ntgo-type', tabInfo.key);
        }
        if (sortSelect.value !== (state.customizerPoolSort || 'pool')) {
            sortSelect.value = state.customizerPoolSort || 'pool';
        }
        sortSelect.disabled = orderedMode;
        sortSelect.setAttribute('aria-disabled', orderedMode ? 'true' : 'false');
        sortSelect.setAttribute('title', orderedMode ? 'Ordered Auto uses pool order.' : 'Choose how to sort the pool view.');
    }

    function updateCustomizerShuffleToggle() {
        var controls = state.customizerShuffleControls;
        var toggle = controls && controls.querySelector('.' + SHUFFLE_TOGGLE_CLASS);
        var shuffle = controls && controls.querySelector('.' + SHUFFLE_BUTTON_CLASS);
        var previewButton = controls && controls.querySelector('.' + SHUFFLE_MODE_PREVIEW_CLASS);
        var poolButton = controls && controls.querySelector('.' + SHUFFLE_POOL_BUTTON_CLASS);
        var previewTools = controls && controls.querySelector('.' + SHUFFLE_PREVIEW_TOOLS_CLASS);
        var poolTools = controls && controls.querySelector('.' + SHUFFLE_POOL_TOOLS_CLASS);
        var filterInput = controls && controls.querySelector('.ntgo-shuffle-pool-filter-input');
        var filterClear = controls && controls.querySelector('.ntgo-shuffle-pool-filter-clear');
        var sortSelect = controls && controls.querySelector('.ntgo-shuffle-pool-sort-select');
        var cycleSelect = controls && controls.querySelector('.ntgo-shuffle-pool-cycle-select');
        var tooltip;
        var bundle = readPersistedUserState();
        var user = bundle && bundle.user;
        var tabInfo = getCustomizerTabInfo();
        var enabled = isAutoShuffleEnabled(tabInfo.key);
        var poolCount = getShufflePool(tabInfo.key).length;
        var availablePoolCount = user ? getValidShufflePoolValues(user, tabInfo.key).length : poolCount;
        var unavailablePoolCount = user ? getUnavailableShufflePoolValues(user, tabInfo.key).length : 0;
        var unavailableOrderCount = user ? getUnavailableShufflePoolOrderValues(user, tabInfo.key).length : 0;
        var cycleMode = getShufflePoolCycleMode(tabInfo.key);
        var labelLower = tabInfo.label.toLowerCase();
        var pluralLabel = labelLower + (/[sxz]$|ch$|sh$/.test(labelLower) ? 'es' : 's');
        var poolLabel = pluralLabel.charAt(0).toUpperCase() + pluralLabel.slice(1);
        var supported = tabInfo.auto !== false && isShuffleSupportedType(tabInfo.key);
        var poolActive = state.customizerPoolMode && state.customizerPoolType === tabInfo.key;
        var orderedUnavailable = cycleMode === 'ordered' && getShufflePoolOrder(tabInfo.key).length > 0 && unavailableOrderCount > 0;
        var poolTooltipBody;
        if (cycleMode === 'ordered') state.customizerPoolSort = 'order';
        if (cycleMode === 'ignore') {
            poolTooltipBody = '<span class="ntgo-info-tooltip-line">Pool ignored.</span>' +
                '<span class="ntgo-info-tooltip-line">All owned ' + pluralLabel + ' will be cycled.</span>';
        } else if (poolCount) {
            poolTooltipBody = '<span class="ntgo-info-tooltip-line">' + poolLabel + ' in pool: <b>' + poolCount + '</b> - ' +
                (cycleMode === 'ordered'
                    ? (orderedUnavailable ? 'ordered is paused on this account.' : 'cycled in pool order.')
                    : (availablePoolCount ? 'only ' + (availablePoolCount === 1 ? 'this available ' + labelLower : 'these ' + availablePoolCount + ' available ' + pluralLabel) + ' will be cycled.' : 'no pooled ' + pluralLabel + ' are available on this account.')) +
                '</span>' +
                (unavailablePoolCount ? '<span class="ntgo-info-tooltip-line"><b>' + unavailablePoolCount + '</b> not owned on this account and skipped.</span>' : '');
        } else {
            poolTooltipBody = '<span class="ntgo-info-tooltip-line">No pool selected.</span>' +
                '<span class="ntgo-info-tooltip-line">All owned ' + pluralLabel + ' will be cycled.</span>';
        }
        if (controls) {
            controls.hidden = !supported;
            controls.setAttribute('data-ntgo-mode', poolActive ? 'pool' : 'preview');
        }
        if (shuffle) {
            shuffle.removeAttribute('title');
            shuffle.setAttribute('aria-label', 'Shuffle ' + tabInfo.label);
            Array.prototype.slice.call(shuffle.querySelectorAll('.ntgo-info-tooltip')).forEach(function (node) {
                node.remove();
            });
            shuffle.textContent = 'Shuffle';
        }
        if (previewButton) {
            previewButton.textContent = 'Preview';
            previewButton.classList.toggle('is-active', !poolActive);
            previewButton.setAttribute('aria-pressed', !poolActive ? 'true' : 'false');
            previewButton.setAttribute('title', 'Show ' + tabInfo.label + ' preview');
            previewButton.setAttribute('aria-label', previewButton.getAttribute('title'));
        }
        if (poolButton) {
            poolButton.textContent = poolCount ? 'Pool | ' + poolCount : 'Pool';
            poolButton.classList.toggle('is-active', poolActive);
            poolButton.setAttribute('aria-pressed', poolActive ? 'true' : 'false');
            poolButton.setAttribute('title', poolCount ? tabInfo.label + ' shuffle pool: ' + poolCount + ' selected' + (unavailablePoolCount ? ' (' + unavailablePoolCount + ' not owned on this account)' : '') : 'Open ' + tabInfo.label + ' shuffle pool');
            poolButton.setAttribute('aria-label', poolButton.getAttribute('title'));
        }
        if (previewTools) previewTools.hidden = poolActive;
        if (poolTools) poolTools.hidden = !poolActive;
        if (filterInput && filterInput.value !== (state.customizerPoolFilter || '')) {
            filterInput.value = state.customizerPoolFilter || '';
        }
        if (filterClear) filterClear.hidden = !state.customizerPoolFilter;
        updateCustomizerPoolToolbarSortOptions(sortSelect, tabInfo);
        if (cycleSelect) {
            var orderedOption = cycleSelect.querySelector('option[value="ordered"]');
            if (orderedOption) {
                orderedOption.disabled = unavailableOrderCount > 0;
                orderedOption.textContent = unavailableOrderCount > 0 ? 'Ordered (Missing)' : 'Ordered';
            }
            cycleSelect.classList.toggle('has-unavailable-order', unavailableOrderCount > 0);
            cycleSelect.setAttribute('title', unavailableOrderCount > 0 ? 'Ordered needs every pool item to be owned on this account.' : 'Choose whether Auto uses the pool randomly, in order, or ignores it.');
            if (cycleSelect.value !== cycleMode) cycleSelect.value = cycleMode;
        }
        if (toggle) {
            var toggleLabel = toggle.querySelector('.ntgo-toggle-label');
            var toggleState = toggle.querySelector('.ntgo-toggle-state');
            if (!toggleLabel) {
                toggleLabel = pageDocument.createElement('span');
                toggleLabel.className = 'ntgo-toggle-label';
                toggle.insertBefore(toggleLabel, toggle.firstChild);
            }
            if (!toggleState) {
                toggleState = pageDocument.createElement('span');
                toggleState.className = 'ntgo-toggle-state';
                tooltip = toggle.querySelector('.ntgo-info-tooltip');
                if (tooltip) toggle.insertBefore(toggleState, tooltip);
                else toggle.appendChild(toggleState);
            }
            toggleLabel.textContent = 'Auto';
            toggleState.textContent = enabled ? 'On' : 'Off';
            toggle.classList.toggle('is-active', enabled);
            toggle.setAttribute('aria-pressed', enabled ? 'true' : 'false');
            toggle.removeAttribute('title');
            toggle.setAttribute('aria-label', 'Auto shuffle ' + tabInfo.label + ': ' + (enabled ? 'On' : 'Off'));
            tooltip = toggle.querySelector('.ntgo-info-tooltip');
            if (tooltip) {
                tooltip.innerHTML = '<strong>Auto Shuffle</strong>' +
                    '<span class="ntgo-info-tooltip-line">Changes your <b>' + labelLower + '</b> each race after 2 in a row.</span>' +
                    poolTooltipBody +
                    '<span class="ntgo-info-tooltip-subtext">' + (orderedUnavailable ? 'Ordered Auto resumes when every ordered slot is available.' : (cycleMode === 'ordered' && poolCount ? 'Ordered pools advance together after each Auto Shuffle.' : 'Skips currently equipped when possible.')) + '</span>';
            }
        }
        positionCustomizerShuffleControls();
        pageWindow.requestAnimationFrame(positionCustomizerShuffleControls);
    }

    function ensureCustomizerShuffleControls() {
        var previewer;
        var controlsHost;
        var controls;
        var modeSwitch;
        var previewButton;
        var shuffleButton;
        var poolButton;
        var previewTools;
        var poolTools;
        var filterWrap;
        var filterInput;
        var filterClear;
        var sortWrap;
        var sortLabel;
        var sortSelect;
        var cycleWrap;
        var cycleLabel;
        var cycleSelect;
        var toggleButton;
        if (!isToolkitCustomizerShuffleEnabled()) {
            state.customizerPoolMode = false;
            state.customizerPoolType = null;
            if (pageDocument.body) pageDocument.body.classList.remove(SHUFFLE_POOL_MODE_CLASS);
            removeCustomizerPoolPreview();
            removeCustomizerShuffleControls();
            return;
        }
        if (!isCustomizerPage()) {
            if (state.customizerTabSwitchTimer) {
                pageWindow.clearTimeout(state.customizerTabSwitchTimer);
                state.customizerTabSwitchTimer = 0;
            }
            state.customizerPoolMode = false;
            state.customizerPoolType = null;
            if (pageDocument.body) pageDocument.body.classList.remove(SHUFFLE_POOL_MODE_CLASS);
            removeCustomizerPoolPreview();
            removeCustomizerShuffleControls();
            return;
        }

        previewer = pageDocument.querySelector('.customizer--previewer');
        if (!previewer) return;
        controlsHost = previewer.closest('.customizer--preview') || previewer.parentElement;
        if (!controlsHost) return;
        if (controlsHost.classList) controlsHost.classList.add(SHUFFLE_CONTROLS_HOST_CLASS);
        controls = state.customizerShuffleControls;
        if (!controls || !controls.isConnected) controls = pageDocument.querySelector('.' + SHUFFLE_CONTROLS_CLASS);
        if (!controls) {
            controls = pageDocument.createElement('div');
            controls.className = SHUFFLE_CONTROLS_CLASS;
            controls.addEventListener('click', function (event) {
                event.stopPropagation();
            });
            controls.addEventListener('pointerdown', function (event) {
                event.stopPropagation();
            });

            modeSwitch = pageDocument.createElement('div');
            modeSwitch.className = 'ntgo-shuffle-mode-switch';

            previewButton = pageDocument.createElement('button');
            previewButton.type = 'button';
            previewButton.className = 'ntgo-shuffle-mode-button ' + SHUFFLE_MODE_PREVIEW_CLASS;
            previewButton.textContent = 'Preview';
            previewButton.addEventListener('click', function (event) {
                event.preventDefault();
                event.stopPropagation();
                if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
                try {
                    var tabInfo = getCustomizerTabInfo();
                    setCustomizerPoolMode(false, tabInfo.key);
                } catch (e) {
                    logWarn('Preview mode toggle failed', e && e.message ? e.message : e);
                }
            });

            poolButton = pageDocument.createElement('button');
            poolButton.type = 'button';
            poolButton.className = 'ntgo-shuffle-mode-button ' + SHUFFLE_POOL_BUTTON_CLASS + ' ' + SHUFFLE_MODE_POOL_CLASS;
            poolButton.textContent = 'Pool';
            poolButton.addEventListener('click', function (event) {
                event.preventDefault();
                event.stopPropagation();
                if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
                try {
                    var tabInfo = getCustomizerTabInfo();
                    setCustomizerPoolMode(true, tabInfo.key);
                } catch (e) {
                    logWarn('Shuffle pool mode failed', e && e.message ? e.message : e);
                }
            });

            modeSwitch.appendChild(previewButton);
            modeSwitch.appendChild(poolButton);

            previewTools = pageDocument.createElement('div');
            previewTools.className = SHUFFLE_PREVIEW_TOOLS_CLASS;
            shuffleButton = pageDocument.createElement('button');
            shuffleButton.type = 'button';
            shuffleButton.className = SHUFFLE_BUTTON_CLASS;
            shuffleButton.textContent = 'Shuffle';
            shuffleButton.addEventListener('click', function (event) {
                event.preventDefault();
                event.stopPropagation();
                if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
                try {
                    var tabInfo = getCustomizerTabInfo();
                    if (shuffleCustomizerVisibleItem({ ignorePool: true })) return;
                    shuffleRandomOwnedLootType(tabInfo.key, 'Shuffled ' + tabInfo.label + '.', {
                        playSound: false,
                        updatePreview: true,
                        ignorePool: true
                    });
                } catch (e) {
                    logWarn('Customizer shuffle failed', e && e.message ? e.message : e);
                }
            });
            previewTools.appendChild(shuffleButton);

            poolTools = pageDocument.createElement('div');
            poolTools.className = SHUFFLE_POOL_TOOLS_CLASS;
            filterWrap = pageDocument.createElement('div');
            filterWrap.className = 'customizer--item-selector-controls--filter ntgo-shuffle-toolbar-filter';
            filterInput = pageDocument.createElement('input');
            filterInput.type = 'search';
            filterInput.className = 'input-field customizer--item-selector-controls--filter-input ntgo-shuffle-pool-filter-input';
            filterInput.placeholder = 'Search Pool';
            filterInput.addEventListener('input', function () {
                var tabInfo = getCustomizerTabInfo();
                state.customizerPoolFilter = filterInput.value;
                updateCustomizerShuffleToggle();
                renderCustomizerPoolPreview(tabInfo);
                refocusCustomizerPoolFilter(state.customizerPoolFilter.length);
            });
            filterClear = pageDocument.createElement('button');
            filterClear.type = 'button';
            filterClear.className = 'customizer--item-selector-controls--filter-clear ntgo-shuffle-pool-filter-clear';
            filterClear.textContent = 'x';
            filterClear.addEventListener('click', function (event) {
                event.preventDefault();
                event.stopPropagation();
                if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
                state.customizerPoolFilter = '';
                filterInput.value = '';
                updateCustomizerShuffleToggle();
                renderCustomizerPoolPreview(getCustomizerTabInfo());
                refocusCustomizerPoolFilter(0);
            });
            filterWrap.appendChild(filterInput);
            filterWrap.appendChild(filterClear);

            sortWrap = pageDocument.createElement('div');
            sortWrap.className = 'customizer--item-selector-controls--sort ntgo-shuffle-toolbar-sort';
            sortLabel = pageDocument.createElement('div');
            sortLabel.className = 'customizer--item-selector-controls--sort-label';
            sortLabel.textContent = 'Sort By';
            sortSelect = pageDocument.createElement('select');
            sortSelect.className = 'input-select customizer--item-selector-controls--sort-options ntgo-shuffle-pool-sort-select';
            sortSelect.addEventListener('change', function () {
                var tabInfo = getCustomizerTabInfo();
                if (getShufflePoolCycleMode(tabInfo.key) === 'ordered') {
                    state.customizerPoolSort = 'order';
                    sortSelect.value = 'order';
                } else {
                    state.customizerPoolSort = sortSelect.value || 'pool';
                }
                renderCustomizerPoolPreview(tabInfo);
            });
            sortWrap.appendChild(sortLabel);
            sortWrap.appendChild(sortSelect);
            cycleWrap = pageDocument.createElement('div');
            cycleWrap.className = 'customizer--item-selector-controls--sort ntgo-shuffle-toolbar-cycle';
            cycleLabel = pageDocument.createElement('div');
            cycleLabel.className = 'customizer--item-selector-controls--sort-label';
            cycleLabel.textContent = 'Auto';
            cycleSelect = pageDocument.createElement('select');
            cycleSelect.className = 'input-select customizer--item-selector-controls--sort-options ntgo-shuffle-pool-cycle-select';
            [
                { value: 'random', label: 'Random' },
                { value: 'ordered', label: 'Ordered' },
                { value: 'ignore', label: 'Ignore Pool' }
            ].forEach(function (entry) {
                var option = pageDocument.createElement('option');
                option.value = entry.value;
                option.textContent = entry.label;
                cycleSelect.appendChild(option);
            });
            cycleSelect.addEventListener('change', function () {
                var tabInfo = getCustomizerTabInfo();
                var bundle = readPersistedUserState();
                var user = bundle && bundle.user;
                if (cycleSelect.value === 'ordered' && user && getShufflePoolOrder(tabInfo.key).length && !isShufflePoolOrderFullyAvailable(user, tabInfo.key)) {
                    logWarn('Ordered mode is unavailable because this account does not own every ordered pool item.');
                    cycleSelect.value = getShufflePoolCycleMode(tabInfo.key);
                    updateCustomizerShuffleToggle();
                    renderCustomizerPoolPreview(tabInfo);
                    return;
                }
                setShufflePoolCycleMode(tabInfo.key, cycleSelect.value);
                updateCustomizerShuffleToggle();
                renderCustomizerPoolPreview(tabInfo);
            });
            cycleWrap.appendChild(cycleLabel);
            cycleWrap.appendChild(cycleSelect);
            poolTools.appendChild(filterWrap);
            poolTools.appendChild(cycleWrap);
            poolTools.appendChild(sortWrap);

            toggleButton = pageDocument.createElement('button');
            toggleButton.type = 'button';
            toggleButton.className = SHUFFLE_TOGGLE_CLASS;
            toggleButton.addEventListener('click', function (event) {
                event.preventDefault();
                event.stopPropagation();
                if (typeof event.stopImmediatePropagation === 'function') event.stopImmediatePropagation();
                try {
                    var tabInfo = getCustomizerTabInfo();
                    setAutoShuffleEnabled(!isAutoShuffleEnabled(tabInfo.key), tabInfo.key);
                } catch (e) {
                    logWarn('Auto shuffle toggle failed', e && e.message ? e.message : e);
                }
            });

            var infoTooltip = pageDocument.createElement('span');
            infoTooltip.className = 'ntgo-info-tooltip';
            infoTooltip.innerHTML = '<strong>Auto Shuffle</strong> changes this tab\'s loot after races.';
            toggleButton.appendChild(infoTooltip);

            controls.appendChild(modeSwitch);
            controls.appendChild(previewTools);
            controls.appendChild(poolTools);
            controls.appendChild(toggleButton);
        }
        if (controls.parentNode !== controlsHost) controlsHost.appendChild(controls);
        state.customizerShuffleControls = controls;
        if (!state.customizerShufflePositionHandler) {
            state.customizerShufflePositionHandler = function () {
                pageWindow.requestAnimationFrame(positionCustomizerShuffleControls);
            };
            pageWindow.addEventListener('resize', state.customizerShufflePositionHandler);
        }
        updateCustomizerShuffleToggle();
        annotateCustomizerPoolItems();
    }

    function equipGarageCarFromSlot(slot) {
        var info = getCarInfo(slot);
        if (state.normalEquipApplying || !info || info.isEmpty || !info.carID) return;

        equipCarByID(info.carID, 'Garage slot #' + info.number, info.name, info.number);
    }

    function findSlotByKey(key) {
        if (!key) return null;
        var slots = getSlots();
        for (var i = 0; i < slots.length; i += 1) {
            if (getCarInfo(slots[i]).key === key) return slots[i];
        }
        return null;
    }

    function getSelectedInfos() {
        return getSlots()
            .map(getCarInfo)
            .filter(function (info) { return info.key && state.selectedKeys[info.key]; })
            .sort(function (a, b) { return a.index - b.index; });
    }

    function getSelectedRunForKey(key) {
        var selected = getSelectedInfos();
        var anchorIndex = -1;
        var startIndex;
        var endIndex;
        var i;

        if (!key) return [];
        for (i = 0; i < selected.length; i += 1) {
            if (selected[i].key === key) {
                anchorIndex = i;
                break;
            }
        }
        if (anchorIndex === -1) return [];

        startIndex = anchorIndex;
        while (startIndex > 0 && selected[startIndex - 1].index === selected[startIndex].index - 1) {
            startIndex -= 1;
        }

        endIndex = anchorIndex;
        while (endIndex + 1 < selected.length && selected[endIndex + 1].index === selected[endIndex].index + 1) {
            endIndex += 1;
        }

        return selected.slice(startIndex, endIndex + 1);
    }

    function isContiguousInfos(infos) {
        var i;
        if (!infos.length) return false;
        for (i = 1; i < infos.length; i += 1) {
            if (infos[i].index !== infos[i - 1].index + 1) return false;
        }
        return true;
    }

    function getSlotInfoAtIndex(index) {
        var slot = getSlots()[index];
        return slot ? getCarInfo(slot) : null;
    }

    function findFirstEmptyInfoAfter(index) {
        var slots = getSlots();
        var i;
        var info;
        for (i = index + 1; i < slots.length; i += 1) {
            info = getCarInfo(slots[i]);
            if (info.isEmpty) return info;
        }
        return null;
    }

    function findEmptyInfosAfter(index, count) {
        var slots = getSlots();
        var matches = [];
        var i;
        var info;
        for (i = index + 1; i < slots.length && matches.length < count; i += 1) {
            info = getCarInfo(slots[i]);
            if (info.isEmpty) matches.push(info);
        }
        return matches;
    }

    function getEmptyRangeInfos(startIndex, count) {
        var slots = getSlots();
        var matches = [];
        var i;
        var info;
        if (startIndex < 0 || startIndex + count > slots.length) return [];

        for (i = startIndex; i < startIndex + count; i += 1) {
            info = getCarInfo(slots[i]);
            if (!info.isEmpty) return [];
            matches.push(info);
        }

        return matches;
    }

    function getRangeInfos(startIndex, count) {
        var slots = getSlots();
        var matches = [];
        var i;
        if (startIndex < 0 || startIndex + count > slots.length) return [];

        for (i = startIndex; i < startIndex + count; i += 1) {
            matches.push(getCarInfo(slots[i]));
        }

        return matches;
    }

    function rangesOverlap(startA, endA, startB, endB) {
        return startA <= endB && startB <= endA;
    }

    function findLastEmptyInfoBetween(startIndex, endIndex) {
        var slots = getSlots();
        var i;
        var info;
        for (i = Math.min(endIndex, slots.length - 1); i >= Math.max(startIndex, 0); i -= 1) {
            info = getCarInfo(slots[i]);
            if (info.isEmpty) return info;
        }
        return null;
    }

    function waitForGarageSettled() {
        return new Promise(function (resolve) {
            pageWindow.setTimeout(function () {
                annotateSlots();
                resolve();
            }, 140);
        });
    }

    function buildSingleInsertPlan(selected, targetInfo) {
        var selectedInfo;
        var bufferInfo;

        if (selected.length !== 1) {
            return {
                ok: false,
                reason: 'Insert Apply is currently limited to one selected car while we validate the shift behavior.'
            };
        }

        selectedInfo = selected[0];
        if (selectedInfo.index === targetInfo.index) {
            return {
                ok: false,
                reason: 'The selected car is already in that slot.'
            };
        }

        if (targetInfo.isEmpty) {
            return {
                ok: true,
                kind: 'empty-target',
                selectedKey: selectedInfo.key,
                name: selectedInfo.name,
                sourceIndex: selectedInfo.index,
                sourceNumber: selectedInfo.number,
                targetIndex: targetInfo.index,
                targetNumber: targetInfo.number
            };
        }

        if (selectedInfo.index < targetInfo.index) {
            return {
                ok: false,
                reason: 'Insert Apply currently supports moving one car to an earlier occupied slot. Use normal Move To for later slots while we validate insert shifting.'
            };
        }

        bufferInfo = findFirstEmptyInfoAfter(selectedInfo.index);
        if (!bufferInfo) {
            return {
                ok: false,
                reason: 'Insert needs an empty buffer slot after the selected car for this first test.'
            };
        }

        return {
            ok: true,
            kind: 'insert-one-earlier',
            selectedKey: selectedInfo.key,
            name: selectedInfo.name,
            sourceIndex: selectedInfo.index,
            sourceNumber: selectedInfo.number,
            targetIndex: targetInfo.index,
            targetNumber: targetInfo.number,
            bufferIndex: bufferInfo.index,
            bufferNumber: bufferInfo.number,
            shiftCount: selectedInfo.index - targetInfo.index
        };
    }

    function buildAdjacentBlockDragPlan(targetSlot, sourceKey, allowInsert) {
        var selected = getSelectedRunForKey(sourceKey);
        var targetInfo = getCarInfo(targetSlot);
        var first;
        var last;
        var finalStartIndex;
        var affectedEndIndex;
        var bufferInfos;
        var bufferAfterIndex;
        var directTargetInfos;
        var targetRangeInfos;
        var targetEndIndex;

        if (selected.length < 2) {
            return { ok: false, reason: 'Drag a car inside a selected run of two or more adjacent cars.' };
        }

        first = selected[0];
        last = selected[selected.length - 1];

        if (!targetInfo) {
            return { ok: false, reason: 'Drop the selected block onto a valid garage slot.' };
        }

        targetEndIndex = targetInfo.index + selected.length - 1;

        if (targetInfo.index === first.index) {
            return { ok: false, reason: 'The selected block already starts at that slot.' };
        }

        if (targetInfo.isEmpty && targetInfo.index === first.index - 1) {
            return {
                ok: true,
                mode: 'adjacent-gap',
                direction: 'left',
                count: selected.length,
                firstIndex: first.index,
                firstNumber: first.number,
                lastIndex: last.index,
                lastNumber: last.number,
                selectedKeys: selected.map(function (info) { return info.key; }),
                targetNumber: targetInfo.number
            };
        }

        if (targetInfo.isEmpty && targetInfo.index === last.index + 1) {
            return {
                ok: true,
                mode: 'adjacent-gap',
                direction: 'right',
                count: selected.length,
                firstIndex: first.index,
                firstNumber: first.number,
                lastIndex: last.index,
                lastNumber: last.number,
                selectedKeys: selected.map(function (info) { return info.key; }),
                targetNumber: targetInfo.number
            };
        }

        if (targetInfo.isEmpty) {
            directTargetInfos = getEmptyRangeInfos(targetInfo.index, selected.length);
            if (directTargetInfos.length === selected.length) {
                return {
                    ok: true,
                    mode: 'direct-empty',
                    direction: targetInfo.index < first.index ? 'left' : 'right',
                    count: selected.length,
                    firstIndex: first.index,
                    firstNumber: first.number,
                    lastIndex: last.index,
                    lastNumber: last.number,
                    finalStartIndex: targetInfo.index,
                    selectedKeys: selected.map(function (info) { return info.key; }),
                    targetIndexes: directTargetInfos.map(function (info) { return info.index; }),
                    targetNumber: targetInfo.number
                };
            }
        }

        if (
            targetInfo.index < first.index &&
            targetEndIndex >= first.index
        ) {
            targetRangeInfos = getRangeInfos(targetInfo.index, selected.length);
            if (targetRangeInfos.length === selected.length) {
                return {
                    ok: true,
                    mode: 'overlap-move',
                    direction: 'left',
                    count: selected.length,
                    firstIndex: first.index,
                    firstNumber: first.number,
                    lastIndex: last.index,
                    lastNumber: last.number,
                    finalStartIndex: targetInfo.index,
                    selectedKeys: selected.map(function (info) { return info.key; }),
                    targetIndexes: targetRangeInfos.map(function (info) { return info.index; }),
                    targetNumber: targetInfo.number
                };
            }
        }

        if (
            targetInfo.index > first.index &&
            targetInfo.index <= last.index
        ) {
            if (targetEndIndex >= getSlots().length) {
                return { ok: false, reason: 'Block move needs enough slots after the drop target for the selected block.' };
            }
            targetRangeInfos = getRangeInfos(targetInfo.index, selected.length);
            if (targetRangeInfos.length === selected.length) {
                return {
                    ok: true,
                    mode: 'overlap-move',
                    direction: 'right',
                    count: selected.length,
                    firstIndex: first.index,
                    firstNumber: first.number,
                    lastIndex: last.index,
                    lastNumber: last.number,
                    finalStartIndex: targetInfo.index,
                    selectedKeys: selected.map(function (info) { return info.key; }),
                    targetIndexes: targetRangeInfos.map(function (info) { return info.index; }),
                    targetNumber: targetInfo.number
                };
            }
        }

        if (
            !rangesOverlap(first.index, last.index, targetInfo.index, targetEndIndex)
        ) {
            targetRangeInfos = getRangeInfos(targetInfo.index, selected.length);
            if (targetRangeInfos.length === selected.length) {
                return {
                    ok: true,
                    mode: 'range-swap',
                    direction: targetInfo.index < first.index ? 'left' : 'right',
                    count: selected.length,
                    firstIndex: first.index,
                    firstNumber: first.number,
                    lastIndex: last.index,
                    lastNumber: last.number,
                    selectedKeys: selected.map(function (info) { return info.key; }),
                    targetIndexes: targetRangeInfos.map(function (info) { return info.index; }),
                    targetNumber: targetInfo.number
                };
            }
        }

        if (!allowInsert) {
            if (targetEndIndex >= getSlots().length) {
                return { ok: false, reason: 'Block swap needs enough slots after the drop target for the selected block.' };
            }
            return { ok: false, reason: 'Drop far enough outside the selected block to swap with a same-sized range.' };
        }

        if (targetInfo.index < first.index) {
            finalStartIndex = targetInfo.index;
            affectedEndIndex = first.index - 1;
            bufferAfterIndex = last.index;
            bufferInfos = findEmptyInfosAfter(bufferAfterIndex, selected.length);
            if (bufferInfos.length < selected.length) {
                return { ok: false, reason: 'Block insert needs ' + selected.length + ' empty buffer slots after the selected run.' };
            }

            return {
                ok: true,
                mode: 'buffered-insert',
                direction: 'left',
                count: selected.length,
                firstIndex: first.index,
                firstNumber: first.number,
                lastIndex: last.index,
                lastNumber: last.number,
                finalStartIndex: finalStartIndex,
                affectedStartIndex: targetInfo.index,
                affectedEndIndex: affectedEndIndex,
                selectedKeys: selected.map(function (info) { return info.key; }),
                bufferIndexes: bufferInfos.map(function (info) { return info.index; }),
                targetNumber: targetInfo.number
            };
        }

        finalStartIndex = targetInfo.index;
        if (finalStartIndex <= first.index) {
            return { ok: false, reason: 'Drop farther to the right or use the adjacent empty slot for a one-slot move.' };
        }

        affectedEndIndex = targetInfo.index + selected.length - 1;
        if (affectedEndIndex >= getSlots().length) {
            return { ok: false, reason: 'That target is outside the garage.' };
        }

        bufferAfterIndex = affectedEndIndex;
        bufferInfos = findEmptyInfosAfter(bufferAfterIndex, selected.length);
        if (bufferInfos.length < selected.length) {
            return { ok: false, reason: 'Block insert needs ' + selected.length + ' empty buffer slots after the destination range.' };
        }

        return {
            ok: true,
            mode: 'buffered-insert',
            direction: 'right',
            count: selected.length,
            firstIndex: first.index,
            firstNumber: first.number,
            lastIndex: last.index,
            lastNumber: last.number,
            finalStartIndex: finalStartIndex,
            affectedStartIndex: last.index + 1,
            affectedEndIndex: affectedEndIndex,
            selectedKeys: selected.map(function (info) { return info.key; }),
            bufferIndexes: bufferInfos.map(function (info) { return info.index; }),
            targetNumber: targetInfo.number
        };
    }

    function ensureStyles() {
        var style = pageDocument.getElementById(STYLE_ID);
        var isNewStyle = false;
        if (!style) {
            style = pageDocument.createElement('style');
            style.id = STYLE_ID;
            isNewStyle = true;
        }
        style.textContent = [
            '.garage.is-rearranging{position:relative;}',
            '.garage.is-rearranging .garage-spot.' + SLOT_CLASS + '{position:relative;overflow:visible;}',
            '.garage.is-rearranging .garage-spot.' + SLOT_CLASS + '>.garage-vehicle{position:relative;z-index:1;}',
            '.garage.is-rearranging .garage-spot.' + SELECTED_CLASS + '{z-index:12;}',
            '.garage.is-rearranging .garage-spot.' + SELECTED_CLASS + '::before{content:""!important;position:absolute!important;left:-3px!important;right:-3px!important;top:-3px!important;bottom:-3px!important;width:auto!important;height:auto!important;box-sizing:border-box!important;border:3px solid rgba(244,182,63,.92)!important;background:transparent!important;z-index:6!important;pointer-events:none!important;}',
            '.' + SLOT_NUMBER_CLASS + '{position:absolute;left:50%;z-index:1;width:58px;height:18px;transform:translateX(-50%);pointer-events:none;opacity:.74;}',
            '.' + SLOT_NUMBER_CLASS + '--top{top:auto;bottom:-4px;}',
            '.' + SLOT_NUMBER_CLASS + '--bottom{top:-2px;bottom:auto;}',
            '.' + SLOT_NUMBER_CLASS + ' text{fill:rgba(228,234,248,.78);stroke:rgba(13,18,30,.64);stroke-width:.85px;font:750 13px/1 Montserrat,Arial,sans-serif;paint-order:stroke;}',
            '.' + SECTION_LABEL_CLASS + '{position:absolute;z-index:0;pointer-events:none;opacity:.58;filter:drop-shadow(0 3px 5px rgba(0,0,0,.42));}',
            '.' + SECTION_LABEL_CLASS + ' text{fill:rgba(203,211,230,.58);stroke:rgba(13,18,30,.52);stroke-width:.9px;font:750 34px/1 Montserrat,Arial,sans-serif;letter-spacing:.08em;paint-order:stroke;}',
            '.' + SECTION_LABEL_CLASS + '.is-active{opacity:.72;filter:drop-shadow(0 0 10px rgba(244,182,63,.22)) drop-shadow(0 4px 6px rgba(0,0,0,.44));}',
            '.' + SECTION_LABEL_CLASS + '.is-active text{fill:rgba(239,199,104,.68);stroke:rgba(17,22,35,.58);}',
            '.' + SELECT_BUTTON_CLASS + '{position:absolute;right:6px;top:6px;z-index:7;width:22px;height:22px;border-radius:50%;border:1px solid rgba(255,215,108,.85);background:#f4b63f;box-shadow:0 2px 8px rgba(0,0,0,.35);color:#101522;font:700 13px/20px Montserrat,Arial,sans-serif;cursor:pointer;opacity:1;}',
            '.garage-spot.' + SELECTED_CLASS + '>.' + SELECT_BUTTON_CLASS + '{background:#f4b63f;border-color:#ffd76c;color:#101522;}',
            '.garage-spot.' + SELECTED_CLASS + '{box-shadow:none;}',
            '.garage-spot.' + SOURCE_CLASS + '{box-shadow:0 0 0 3px rgba(95,255,152,.9);}',
            '.garage-spot.' + TARGET_CLASS + '{box-shadow:0 0 0 3px rgba(28,153,244,.95);}',
            '.garage-spot.' + EMPTY_TARGET_CLASS + '{box-shadow:inset 0 0 0 4px rgba(95,255,152,.55);}',
            'body.' + GARAGE_REARRANGING_BODY_CLASS + ' .profile.is-garage{z-index:100009!important;overflow:visible!important;}',
            'body.' + GARAGE_REARRANGING_BODY_CLASS + ' .__react_component_tooltip.reactTooltip{z-index:100010!important;}',
            '.profile--active-car--preview-container>.animated-car-preview{width:100%;height:300px;}',
            '.profile--active-car--preview-container>.animated-car-preview canvas{display:block;}',
            '.' + SHUFFLE_CONTROLS_HOST_CLASS + '{position:relative;}',
            '.' + SHUFFLE_CONTROLS_HOST_CLASS + '>.' + SHUFFLE_CONTROLS_CLASS + '{position:absolute;left:var(--ntgo-pool-left,10px);top:var(--ntgo-pool-top,90px);z-index:70;box-sizing:border-box;width:var(--ntgo-pool-width,559px);min-height:82px;display:grid;grid-template-columns:auto minmax(0,1fr) 50px;grid-template-rows:32px 32px;align-items:center;column-gap:8px;row-gap:6px;padding:5px 7px;border:1px solid #747da0;border-radius:var(--ntgo-pool-radius-top-left,6px) var(--ntgo-pool-radius-top-right,6px) 0 0;background:#474d67;color:#eef2ff;box-shadow:0 2px 8px rgba(0,0,0,.18);font-family:Montserrat,Arial,sans-serif;pointer-events:auto;}',
            '.' + SHUFFLE_CONTROLS_CLASS + '[hidden],.' + SHUFFLE_BUTTON_CLASS + '[hidden],.' + SHUFFLE_POOL_BUTTON_CLASS + '[hidden],.' + SHUFFLE_TOGGLE_CLASS + '[hidden],.' + SHUFFLE_PREVIEW_TOOLS_CLASS + '[hidden],.' + SHUFFLE_POOL_TOOLS_CLASS + '[hidden],.ntgo-shuffle-pool-filter-clear[hidden]{display:none!important;}',
            '.ntgo-shuffle-mode-switch{display:flex;align-items:center;gap:3px;min-width:0;padding:2px;border:1px solid rgba(135,145,184,.38);border-radius:6px;background:rgba(17,22,36,.52);}',
            '.ntgo-shuffle-mode-button{height:30px;border:0;border-radius:4px;background:transparent;color:#c8cfe2;padding:0 9px;font:800 11px/30px Montserrat,Arial,sans-serif;text-transform:uppercase;white-space:nowrap;cursor:pointer;box-shadow:none;}',
            '.ntgo-shuffle-mode-button.is-active{background:#d62f3a;color:#fff;box-shadow:inset 0 -2px 0 rgba(0,0,0,.24);}',
            '.' + SHUFFLE_PREVIEW_TOOLS_CLASS + ',.' + SHUFFLE_POOL_TOOLS_CLASS + '{display:flex;align-items:center;gap:8px;min-width:0;}',
            '.' + SHUFFLE_PREVIEW_TOOLS_CLASS + ',.' + SHUFFLE_POOL_TOOLS_CLASS + '{grid-column:1/-1;grid-row:2;}',
            '.' + SHUFFLE_PREVIEW_TOOLS_CLASS + '{justify-content:flex-start;}',
            '.' + SHUFFLE_POOL_TOOLS_CLASS + '{justify-content:flex-start;}',
            '.' + SHUFFLE_BUTTON_CLASS + ',.' + SHUFFLE_TOGGLE_CLASS + '{height:32px;min-width:44px;border:0;border-radius:5px;background:#d62f3a;color:#fff;box-shadow:inset 0 -2px 0 rgba(0,0,0,.24),0 2px 6px rgba(0,0,0,.2);font-family:Montserrat,Arial,sans-serif;text-transform:uppercase;white-space:nowrap;cursor:pointer;touch-action:manipulation;}',
            '.' + SHUFFLE_BUTTON_CLASS + '{position:relative;overflow:visible;padding:0 14px;font-size:11px;font-weight:800;line-height:32px;}',
            '.' + SHUFFLE_BUTTON_CLASS + ':hover,.ntgo-shuffle-mode-button:hover,.' + SHUFFLE_TOGGLE_CLASS + ':hover{filter:brightness(1.06);}',
            '.' + SHUFFLE_BUTTON_CLASS + ':active,.ntgo-shuffle-mode-button:active,.' + SHUFFLE_TOGGLE_CLASS + ':active{transform:translateY(1px);filter:brightness(.96);}',
            '.' + SHUFFLE_TOGGLE_CLASS + '{grid-column:3;grid-row:1;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;width:50px;padding:0;background:#2d3348;color:#dfe5f4;line-height:1;overflow:visible;}',
            '.' + SHUFFLE_TOGGLE_CLASS + ' .ntgo-toggle-label{display:block;font-size:8px;font-weight:800;line-height:9px;opacity:.82;pointer-events:none;}',
            '.' + SHUFFLE_TOGGLE_CLASS + ' .ntgo-toggle-state{display:block;font-size:12px;font-weight:900;line-height:14px;pointer-events:none;}',
            '.' + SHUFFLE_TOGGLE_CLASS + '.is-active{background:#d62f3a;color:#fff;}',
            '.ntgo-shuffle-toolbar-filter{position:relative;flex:1 1 180px;min-width:140px;max-width:none;}',
            '.ntgo-shuffle-toolbar-filter .ntgo-shuffle-pool-filter-input{box-sizing:border-box;width:100%!important;height:32px!important;border-radius:5px!important;border:1px solid rgba(135,145,184,.5)!important;background:#1f2331!important;color:#fff!important;padding:0 30px 0 10px!important;font:500 12px/32px Montserrat,Arial,sans-serif!important;outline:none!important;}',
            '.ntgo-shuffle-toolbar-filter .ntgo-shuffle-pool-filter-input:focus{border-color:#8f99bd!important;box-shadow:0 0 0 2px rgba(143,153,189,.18)!important;}',
            '.ntgo-shuffle-pool-filter-clear{position:absolute;right:7px;top:50%;width:18px;height:18px;transform:translateY(-50%);border:0;border-radius:50%;background:#3d445d;color:#b6bed6;font:800 13px/18px Montserrat,Arial,sans-serif;text-align:center;cursor:pointer;padding:0;}',
            '.ntgo-shuffle-pool-filter-clear:hover{background:#515a78;color:#fff;}',
            '.ntgo-shuffle-toolbar-sort,.ntgo-shuffle-toolbar-cycle{display:flex;align-items:center;gap:7px;flex:0 0 auto;}',
            '.ntgo-shuffle-toolbar-sort .customizer--item-selector-controls--sort-label,.ntgo-shuffle-toolbar-cycle .customizer--item-selector-controls--sort-label{color:#b9c0d7;font:700 12px/1 Montserrat,Arial,sans-serif;white-space:nowrap;}',
            '.ntgo-shuffle-toolbar-sort .ntgo-shuffle-pool-sort-select,.ntgo-shuffle-toolbar-cycle .ntgo-shuffle-pool-cycle-select{box-sizing:border-box;height:32px!important;border-radius:5px!important;border:1px solid rgba(135,145,184,.5)!important;background:#1f2331!important;color:#fff!important;padding:0 24px 0 10px!important;font:500 12px/32px Montserrat,Arial,sans-serif!important;outline:none!important;}',
            '.ntgo-shuffle-toolbar-sort .ntgo-shuffle-pool-sort-select:disabled{opacity:.72;cursor:not-allowed;}',
            '.ntgo-shuffle-toolbar-sort .ntgo-shuffle-pool-sort-select{width:142px;}',
            '.ntgo-shuffle-toolbar-cycle .ntgo-shuffle-pool-cycle-select{width:142px;}',
            'body:not(.' + SHUFFLE_POOL_MODE_CLASS + ') .customizer.no-preview .customizer--previewer,body:not(.' + SHUFFLE_POOL_MODE_CLASS + ') .customizer.no-preview .customizer--previewer *{pointer-events:none!important;}',
            '.customizer.section-titles.' + SHUFFLE_CONTROLS_HOST_CLASS + ' .title-preview--card{transform:translateY(86px);}',
            'body.' + SHUFFLE_POOL_MODE_CLASS + ' .customizer--preview.vehicle-preview{z-index:0!important;pointer-events:none!important;}',
            'body.' + SHUFFLE_POOL_MODE_CLASS + ' .customizer--previewer{position:absolute!important;left:var(--ntgo-pool-left,10px)!important;top:var(--ntgo-pool-top,90px)!important;z-index:50!important;box-sizing:border-box;width:var(--ntgo-pool-width,559px)!important;height:var(--ntgo-pool-height,500px)!important;overflow:visible!important;opacity:1!important;visibility:visible!important;pointer-events:auto!important;}',
            'body.' + SHUFFLE_POOL_MODE_CLASS + ' .customizer--preview [class^="customizer--"][class*="-selection"],body.' + SHUFFLE_POOL_MODE_CLASS + ' .customizer--vehicle-selection{display:none!important;}',
            'body.' + SHUFFLE_POOL_MODE_CLASS + ' .customizer--preview.title-preview{visibility:hidden!important;opacity:0!important;pointer-events:none!important;}',
            'body.' + SHUFFLE_POOL_MODE_CLASS + ' .customizer--previewer> :not(.' + SHUFFLE_POOL_PREVIEW_CLASS + '){display:none!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_CLASS + '.customizer--item-selector{position:relative!important;left:0!important;top:0!important;z-index:50!important;box-sizing:border-box;width:100%!important;height:100%!important;display:block!important;min-width:0;min-height:0;padding:0!important;color:#eef2ff;font-family:Montserrat,Arial,sans-serif;background:#474d67;border:1px solid #747da0;border-radius:0 0 var(--ntgo-pool-radius-bottom-right,6px) var(--ntgo-pool-radius-bottom-left,6px);box-shadow:none;overflow:visible!important;pointer-events:auto!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_CLASS + '.is-pool-ignored .ntgo-shuffle-pool-preview-scroller{filter:grayscale(1)!important;opacity:.34!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_CLASS + '.is-pool-ignored::after{content:"Pool ignored";position:absolute;left:50%;top:50%;z-index:90;box-sizing:border-box;min-width:150px;transform:translate(-50%,-50%);border:1px solid rgba(174,186,219,.48);border-radius:6px;background:rgba(20,25,39,.78);color:#e7ecfb;padding:10px 16px;font:900 13px/1 Montserrat,Arial,sans-serif;text-align:center;text-transform:uppercase;letter-spacing:0;text-shadow:0 2px 5px rgba(0,0,0,.45);box-shadow:0 10px 28px rgba(0,0,0,.28);pointer-events:none;}',
            '.ntgo-shuffle-pool-preview-content{position:relative!important;box-sizing:border-box;width:100%!important;height:100%!important;}',
            '.ntgo-shuffle-pool-preview-container{position:absolute!important;left:0!important;right:0!important;top:84px!important;bottom:0!important;width:auto!important;height:auto!important;overflow:hidden!important;}',
            '.ntgo-shuffle-pool-preview-scroller{position:absolute;inset:0 10px 0 0;overflow:hidden auto;padding-right:20px;margin-right:-21px;}',
            '.' + SHUFFLE_POOL_PREVIEW_GRID_CLASS + '{box-sizing:border-box;width:auto!important;height:auto!important;min-height:100%;overflow:visible!important;display:grid!important;grid-template-columns:repeat(auto-fill,128px)!important;grid-auto-rows:80px!important;gap:10px!important;align-content:start!important;justify-content:center!important;margin:10px!important;padding:0!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_CLASS + '[data-ntgo-pool-type="title"] .' + SHUFFLE_POOL_PREVIEW_GRID_CLASS + '{grid-template-columns:repeat(auto-fill,197px)!important;}',
            '.ntgo-shuffle-pool-preview-scroller::-webkit-scrollbar{width:10px;}',
            '.ntgo-shuffle-pool-preview-scroller::-webkit-scrollbar-thumb{border-radius:8px;background:rgba(174,186,219,.38);}',
            '.ntgo-shuffle-pool-preview-scroller::-webkit-scrollbar-track{background:rgba(11,15,27,.18);}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '{width:128px!important;height:80px!important;position:relative;cursor:pointer;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '[draggable="true"]{cursor:grab;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '.is-order-dragging{opacity:.55;cursor:grabbing;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '.is-order-drop-before{box-shadow:inset 5px 0 0 #62c4ff,0 0 0 4px rgba(244,182,63,.95),0 0 18px rgba(98,196,255,.42)!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '.is-order-drop-after{box-shadow:inset -5px 0 0 #62c4ff,0 0 0 4px rgba(244,182,63,.95),0 0 18px rgba(98,196,255,.42)!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_CLASS + '[data-ntgo-pool-type="title"] .' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '{width:197px!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_CLASS + '[data-ntgo-pool-type="title"] .' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + ' .customizer--item-selector-item--name{max-width:calc(100% - 22px);margin:0 auto;color:#fff;text-align:center;text-shadow:0 2px 4px rgba(0,0,0,.42);font:700 12px/1.2 Montserrat,Arial,sans-serif;white-space:normal;overflow-wrap:anywhere;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + ':hover{filter:brightness(1.07);}',
            '.customizer--item-selector-item:hover{position:relative!important;z-index:80!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '.' + SHUFFLE_POOL_SELECTED_CLASS + '{box-shadow:none!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '.is-unavailable .customizer--item-selector-item--content{filter:grayscale(1)!important;opacity:.42!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '.is-unavailable::before{content:"Not owned";position:absolute;inset:0;z-index:18;display:flex;align-items:center;justify-content:center;border-radius:6px;background:rgba(17,22,34,.58);color:#eef2ff;font:900 10px/1 Montserrat,Arial,sans-serif;text-align:center;text-transform:uppercase;text-shadow:0 2px 5px rgba(0,0,0,.55);pointer-events:none;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + ' .customizer--tooltip{display:block!important;position:absolute!important;left:50%!important;right:auto!important;top:calc(100% - 12px)!important;bottom:auto!important;z-index:100030!important;box-sizing:border-box!important;width:calc(100% - 14px)!important;min-width:0!important;max-width:none!important;margin:0!important;padding:5px 8px 6px!important;border:0!important;border-radius:4px!important;background:#1c99f4!important;color:#fff!important;box-shadow:0 5px 12px rgba(0,0,0,.18)!important;font:400 13px/1.2 Montserrat,Arial,sans-serif!important;text-align:center!important;text-transform:none!important;letter-spacing:0!important;white-space:normal!important;overflow-wrap:break-word!important;pointer-events:none!important;opacity:0!important;visibility:hidden!important;transform:translateX(-50%)!important;filter:none!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + ':hover .customizer--tooltip{opacity:.96!important;visibility:visible!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + ' .customizer--tooltip::before{content:""!important;position:absolute!important;left:50%!important;top:-9px!important;bottom:auto!important;transform:translateX(-50%)!important;width:0!important;height:0!important;border-left:9px solid transparent!important;border-right:9px solid transparent!important;border-bottom:9px solid #1c99f4!important;border-top:0!important;background:transparent!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + ' .customizer--tooltip::after{display:none!important;}',
            '.customizer .customizer--tooltip{z-index:120!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_ITEM_CLASS + '.' + SHUFFLE_POOL_SELECTED_CLASS + '::after{display:none!important;}',
            '.' + SHUFFLE_POOL_PREVIEW_REMOVE_CLASS + '{position:absolute;right:5px;top:5px;z-index:30;width:20px;height:20px;border:1px solid rgba(255,111,121,.78);border-radius:50%;background:#d62f3a;color:#fff;box-shadow:inset 0 -2px 0 rgba(0,0,0,.22),0 2px 8px rgba(0,0,0,.34);font:900 12px/18px Montserrat,Arial,sans-serif;text-align:center;text-transform:uppercase;pointer-events:none;text-shadow:0 1px 1px rgba(0,0,0,.28);}',
            '.ntgo-shuffle-pool-order-badge{position:absolute;left:5px;top:5px;z-index:31;min-width:18px;height:18px;border-radius:9px;background:#1c99f4;color:#fff;box-shadow:0 2px 8px rgba(0,0,0,.34);font:900 10px/18px Montserrat,Arial,sans-serif;text-align:center;padding:0 4px;pointer-events:none;}',
            '.' + SHUFFLE_POOL_PREVIEW_EMPTY_CLASS + '{grid-column:1/-1;align-self:center;justify-self:center;margin-top:150px;max-width:330px;border:1px solid rgba(116,125,160,.72);border-radius:6px;background:rgba(58,64,89,.88);color:#d7def1;padding:13px 18px;font:800 12px/1 Montserrat,Arial,sans-serif;text-align:center;text-transform:uppercase;}',
            '.ntgo-shuffle-pool-preview-empty-title{color:#eef2ff;font:800 13px/1 Montserrat,Arial,sans-serif;text-transform:uppercase;}',
            '.ntgo-shuffle-pool-preview-empty-text{margin-top:7px;color:#c8d0ea;font:600 11px/1.35 Montserrat,Arial,sans-serif;text-transform:none;}',
            '.ntgo-info-tooltip{position:absolute;bottom:calc(100% + 10px);left:50%;z-index:100023;width:260px;padding:10px 12px;border:1px solid rgba(93,104,139,.58);border-radius:8px;background:rgba(23,27,42,.97);box-shadow:0 8px 24px rgba(0,0,0,.45);color:#cbd3ec;font:500 11.5px/1.45 Montserrat,Arial,sans-serif;pointer-events:none;opacity:0;transform:translateX(-50%) translateY(4px);transition:opacity .15s,transform .15s;white-space:normal;text-align:left;text-transform:none;}',
            '.' + SHUFFLE_TOGGLE_CLASS + ':hover .ntgo-info-tooltip{opacity:1;transform:translateX(-50%) translateY(0);pointer-events:auto;}',
            '.ntgo-info-tooltip::after{content:"";position:absolute;top:100%;left:50%;margin-left:-6px;border:6px solid transparent;border-top-color:rgba(93,104,139,.58);}',
            '.ntgo-info-tooltip strong{display:block;margin-bottom:5px;color:#eef2ff;font-weight:800;}',
            '.ntgo-info-tooltip-line{display:block;margin-top:4px;}',
            '.ntgo-info-tooltip-line b{color:#eef2ff;font-weight:800;}',
            '.ntgo-info-tooltip-subtext{display:block;margin-top:7px;color:#aeb8d3;font:500 10.5px/1.35 Montserrat,Arial,sans-serif;}',
            '.' + SHUFFLE_POOL_SELECTED_CLASS + '{position:relative;box-shadow:0 0 0 4px rgba(244,182,63,.95),0 0 18px rgba(244,182,63,.45)!important;}',
            '.' + SHUFFLE_POOL_SELECTED_CLASS + '::after{content:"Pool";position:absolute;right:6px;top:6px;z-index:20;border-radius:5px;background:#f4b63f;color:#101522;padding:3px 6px;font:900 10px/1 Montserrat,Arial,sans-serif;text-transform:uppercase;box-shadow:0 3px 8px rgba(0,0,0,.28);pointer-events:none;}',
            '.' + EXPORT_BUTTON_CLASS + '{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;margin-left:8px;border:0;border-radius:6px;background:#d62f3a;color:#fff;box-shadow:inset 0 -2px 0 rgba(0,0,0,.24),0 2px 8px rgba(0,0,0,.28);cursor:pointer;vertical-align:middle;}',
            '.split-cell > .' + EXPORT_BUTTON_CLASS + '{margin-left:auto;flex:0 0 auto;}',
            '.' + EXPORT_BUTTON_CLASS + ':hover{filter:brightness(1.06);}',
            '.' + EXPORT_BUTTON_CLASS + ' svg{width:22px;height:22px;display:block;fill:currentColor;}',
            '.' + INSERT_MARKER_CLASS + '{position:fixed;z-index:100022;display:none;pointer-events:none;width:3px;height:0;border-radius:3px;background:#f4b63f;box-shadow:0 0 0 1px rgba(255,233,157,.9),0 0 16px rgba(244,182,63,.75);}',
            '.' + INSERT_MARKER_CLASS + '.is-visible{display:block;}',
            '.' + INSERT_MARKER_CLASS + '::after{content:"Insert here";position:absolute;left:9px;top:8px;white-space:nowrap;border:1px solid rgba(255,218,110,.72);border-radius:5px;background:rgba(16,21,35,.95);box-shadow:0 8px 20px rgba(0,0,0,.36);color:#ffd76c;padding:4px 7px;font:700 11px/1.2 Montserrat,Arial,sans-serif;}',
            '.' + INSERT_MARKER_CLASS + '.is-flipped::after{left:auto;right:9px;}',
            '.garage-spot.' + PULSE_CLASS + '{animation:ntgo-pulse 1.1s ease-out 1;}',
            '@keyframes ntgo-pulse{0%{box-shadow:0 0 0 0 rgba(244,182,63,.85);}70%{box-shadow:0 0 0 18px rgba(244,182,63,0);}100%{box-shadow:0 0 0 0 rgba(244,182,63,0);}}',
            '.' + TOOLBAR_CLASS + '{position:fixed;z-index:100020;box-sizing:border-box;padding:7px 9px;border:1px solid rgba(93,104,139,.58);border-radius:8px;background:url(/dist/site/images/backgrounds/bg-noise.png) top left repeat,linear-gradient(180deg,rgba(34,38,55,.98),rgba(22,26,39,.98));box-shadow:0 12px 32px rgba(0,0,0,.42);color:#eef2ff;font-family:Montserrat,Arial,sans-serif;}',
            '.' + TOOLBAR_CLASS + '.is-docking{outline:2px solid rgba(98,196,255,.86);outline-offset:3px;box-shadow:0 14px 36px rgba(0,0,0,.48),0 0 0 4px rgba(28,153,244,.18);}',
            '.' + TOOLBAR_CLASS + '--bottom{left:50%;right:auto;top:auto;bottom:12px;transform:translateX(-50%);width:min(1320px,calc(100vw - 20px));max-height:calc(100vh - 24px);overflow:visible;}',
            '.' + TOOLBAR_CLASS + '--top{left:50%;right:auto;top:12px;bottom:auto;transform:translateX(-50%);width:min(1320px,calc(100vw - 20px));max-height:calc(100vh - 24px);overflow:visible;}',
            '.' + TOOLBAR_CLASS + '--left,.' + TOOLBAR_CLASS + '--right{--ntgo-side-rail-width:116px;top:12px;bottom:12px;transform:none;width:var(--ntgo-side-rail-width);max-height:none;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:rgba(135,145,184,.58) rgba(12,16,27,.24);}',
            '.' + TOOLBAR_CLASS + '--left::-webkit-scrollbar,.' + TOOLBAR_CLASS + '--right::-webkit-scrollbar{width:6px;}',
            '.' + TOOLBAR_CLASS + '--left::-webkit-scrollbar-thumb,.' + TOOLBAR_CLASS + '--right::-webkit-scrollbar-thumb{border-radius:6px;background:rgba(135,145,184,.58);}',
            '.' + TOOLBAR_CLASS + '--left{left:12px;right:auto;}',
            '.' + TOOLBAR_CLASS + '--right{left:auto;right:12px;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-head,.' + TOOLBAR_CLASS + '--right .ntgo-head{align-items:stretch;flex-direction:column;gap:6px;margin-bottom:6px;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-row,.' + TOOLBAR_CLASS + '--right .ntgo-row{align-items:stretch;flex-direction:column;gap:6px;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-brand,.' + TOOLBAR_CLASS + '--right .ntgo-brand{margin-right:0;text-align:center;font-size:12px;line-height:1.1;white-space:normal;overflow-wrap:anywhere;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-dock-handle,.' + TOOLBAR_CLASS + '--right .ntgo-dock-handle,.' + TOOLBAR_CLASS + '--left .ntgo-btn,.' + TOOLBAR_CLASS + '--right .ntgo-btn{width:100%;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-btn,.' + TOOLBAR_CLASS + '--right .ntgo-btn{box-sizing:border-box;display:flex;align-items:center;justify-content:center;min-height:38px;height:auto;padding:6px 7px;font-size:10px;line-height:1.12;text-align:center;white-space:normal;overflow-wrap:anywhere;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-field,.' + TOOLBAR_CLASS + '--right .ntgo-field{display:flex;flex-direction:column;align-items:stretch;gap:3px;width:100%;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-field input[type="search"],.' + TOOLBAR_CLASS + '--right .ntgo-field input[type="search"],.' + TOOLBAR_CLASS + '--left .ntgo-field input[type="text"],.' + TOOLBAR_CLASS + '--right .ntgo-field input[type="text"],.' + TOOLBAR_CLASS + '--left .ntgo-field input[type="number"],.' + TOOLBAR_CLASS + '--right .ntgo-field input[type="number"],.' + TOOLBAR_CLASS + '--left .ntgo-field select,.' + TOOLBAR_CLASS + '--right .ntgo-field select{width:100%;min-width:0;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-selection,.' + TOOLBAR_CLASS + '--right .ntgo-selection{min-width:0;width:100%;text-align:center;font-size:11px;line-height:1.2;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-status,.' + TOOLBAR_CLASS + '--right .ntgo-status{width:100%;order:4;margin-right:0;font-size:10px;line-height:1.25;text-align:center;overflow-wrap:anywhere;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-search-wrap,.' + TOOLBAR_CLASS + '--right .ntgo-search-wrap{width:100%;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-mode-tabs,.' + TOOLBAR_CLASS + '--right .ntgo-mode-tabs{align-items:stretch;flex-direction:column;width:100%;box-sizing:border-box;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-grid,.' + TOOLBAR_CLASS + '--right .ntgo-grid{gap:6px;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-panel,.' + TOOLBAR_CLASS + '--right .ntgo-panel{align-items:stretch;flex-direction:column;gap:6px;padding:6px;box-sizing:border-box;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-check,.' + TOOLBAR_CLASS + '--right .ntgo-check{width:100%;align-items:flex-start;font-size:10px;line-height:1.25;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-divider,.' + TOOLBAR_CLASS + '--right .ntgo-divider{width:100%;height:1px;margin:1px 0;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-drop-zone,.' + TOOLBAR_CLASS + '--right .ntgo-drop-zone{box-sizing:border-box;min-width:0;width:100%;padding:6px;font-size:10px;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-more-copy,.' + TOOLBAR_CLASS + '--right .ntgo-more-copy{max-width:none;font-size:10px;line-height:1.3;text-align:center;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-preview,.' + TOOLBAR_CLASS + '--right .ntgo-preview{font-size:10px;padding:6px;overflow-wrap:anywhere;}',
            '.ntgo-row{display:flex;align-items:center;gap:6px;flex-wrap:wrap;}',
            '.ntgo-head{position:relative;display:flex;align-items:center;gap:8px;flex-wrap:nowrap;margin-bottom:5px;}',
            '.ntgo-head-left,.ntgo-head-right{display:flex;align-items:center;gap:6px;min-width:0;flex-wrap:nowrap;}',
            '.ntgo-head-left{position:relative;flex:0 1 calc(50% - 10px);max-width:calc(50% - 10px);}',
            '.ntgo-head-right{flex:1 1 auto;justify-content:flex-end;padding-left:20px;}',
            '.ntgo-status-wrap{position:relative;display:flex;align-items:center;flex:1 1 auto;min-width:80px;min-height:24px;}',
            '.ntgo-head-left .ntgo-status{display:block;width:100%;min-width:0;margin-right:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}',
            '.ntgo-head-right .ntgo-status{margin-right:0;}',
            '.ntgo-status-tooltip{display:none;position:absolute;left:0;bottom:calc(100% + 7px);z-index:100024;box-sizing:border-box;max-width:min(560px,calc(100vw - 32px));padding:7px 9px;border:1px solid rgba(93,104,139,.7);border-radius:6px;background:rgba(23,27,42,.98);box-shadow:0 10px 26px rgba(0,0,0,.42);color:#eef7ff;font:600 11px/1.35 Montserrat,Arial,sans-serif;white-space:normal;text-align:left;pointer-events:none;}',
            '.ntgo-status.has-tooltip:hover + .ntgo-status-tooltip{display:block;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-head,.' + TOOLBAR_CLASS + '--right .ntgo-head{display:flex;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-head-left,.' + TOOLBAR_CLASS + '--right .ntgo-head-left,.' + TOOLBAR_CLASS + '--left .ntgo-head-right,.' + TOOLBAR_CLASS + '--right .ntgo-head-right{display:flex;align-items:stretch;flex:0 0 auto;flex-direction:column;justify-content:flex-start;gap:6px;width:100%;max-width:none;padding-left:0;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-status-wrap,.' + TOOLBAR_CLASS + '--right .ntgo-status-wrap{width:100%;min-width:0;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-head-left .ntgo-status,.' + TOOLBAR_CLASS + '--right .ntgo-head-left .ntgo-status{min-width:0;overflow:visible;text-overflow:clip;white-space:normal;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-status.has-tooltip:hover + .ntgo-status-tooltip,.' + TOOLBAR_CLASS + '--right .ntgo-status.has-tooltip:hover + .ntgo-status-tooltip{display:none;}',
            '.ntgo-grid{display:grid;grid-template-columns:1fr;gap:6px;align-items:stretch;}',
            '.ntgo-panel{display:flex;align-items:center;gap:5px;flex-wrap:wrap;min-width:0;padding:5px 6px;border:1px solid rgba(93,104,139,.34);border-radius:7px;background:rgba(12,16,27,.36);}',
            '.ntgo-panel-title{margin-right:2px;color:#62c4ff;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;}',
            '.ntgo-mode-tabs{display:flex;align-items:center;gap:3px;padding:2px;border:1px solid rgba(93,104,139,.34);border-radius:6px;background:rgba(12,16,27,.32);}',
            '.ntgo-mode-tabs .ntgo-btn{height:22px;line-height:22px;padding:0 10px;background:transparent;color:#b9c0d7;box-shadow:none;}',
            '.ntgo-mode-tabs .ntgo-btn.is-active{background:#1c99f4;color:#fff;box-shadow:inset 0 -2px 0 rgba(0,0,0,.24);}',
            '.ntgo-panel[hidden]{display:none;}',
            '.ntgo-divider{width:1px;height:22px;background:rgba(93,104,139,.42);margin:0 3px;}',
            '.ntgo-brand{flex:0 0 auto;font-size:14px;font-weight:800;margin-right:4px;color:#fff;white-space:nowrap;}',
            '.ntgo-status{font-size:12px;color:#aeb6d4;margin-right:auto;}',
            '.ntgo-status.is-good{color:#63f39c;}.ntgo-status.is-warn{color:#f4c75f;}.ntgo-status.is-bad{color:#ff737d;}',
            '.ntgo-field{display:flex;align-items:center;gap:5px;font-size:11px;color:#b9c0d7;}',
            '.ntgo-field input[type="search"],.ntgo-field input[type="text"],.ntgo-field input[type="number"],.ntgo-field select{box-sizing:border-box;height:24px;border-radius:5px;border:1px solid rgba(135,145,184,.45);background:#111827;color:#fff;padding:3px 7px;font:500 11px/1.2 Montserrat,Arial,sans-serif;outline:none;}',
            '.ntgo-field input[type="search"]{width:174px;}.ntgo-field input[type="text"]{width:82px;}.ntgo-field input[type="number"]{width:58px;text-align:center;}',
            '.ntgo-field select{width:145px;}',
            '.ntgo-dock-handle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:#dce4f6;cursor:grab;touch-action:none;user-select:none;}',
            '.ntgo-dock-handle svg{display:block;width:15px;height:15px;stroke:currentColor;}',
            '.ntgo-dock-handle:hover{color:#fff;}',
            '.ntgo-dock-handle:active,.' + TOOLBAR_CLASS + '.is-docking .ntgo-dock-handle{cursor:grabbing;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-dock-handle,.' + TOOLBAR_CLASS + '--right .ntgo-dock-handle{position:static;left:auto;top:auto;transform:none;width:100%;}',
            '.ntgo-field input:focus,.ntgo-field select:focus{border-color:#1c99f4;box-shadow:0 0 0 2px rgba(28,153,244,.2);}',
            '.ntgo-check{display:flex;align-items:center;gap:5px;font-size:11px;color:#b9c0d7;user-select:none;}',
            '.ntgo-btn{height:24px;border:0;border-radius:5px;padding:0 9px;background:#1c99f4;color:#fff;font:700 10px/24px Montserrat,Arial,sans-serif;cursor:pointer;box-shadow:inset 0 -2px 0 rgba(0,0,0,.24);}',
            '.ntgo-btn:hover{filter:brightness(1.06);}.ntgo-btn:disabled{background:#343a50;color:#8d96b4;opacity:1;cursor:not-allowed;filter:none;box-shadow:none;}',
            '.ntgo-btn.ntgo-primary{background:#1c99f4;color:#fff;box-shadow:inset 0 -2px 0 rgba(0,0,0,.24),0 0 0 1px rgba(97,196,255,.32);}',
            '.ntgo-btn.ntgo-muted{background:#343a50;color:#d7dcef;}.ntgo-btn.ntgo-danger{background:#d62f3a;}',
            '.ntgo-selection{font-size:12px;color:#63f39c;min-width:88px;text-align:left;font-weight:800;}',
            '.ntgo-search-wrap{position:relative;}',
            '.ntgo-drop-zone{display:flex;align-items:center;justify-content:center;min-height:34px;min-width:260px;border:1px dashed rgba(135,145,184,.62);border-radius:6px;background:rgba(17,24,39,.55);color:#b9c0d7;padding:5px 10px;font:600 11px/1.35 Montserrat,Arial,sans-serif;text-align:center;}',
            '.ntgo-drop-zone.is-dragging{border-color:#62c4ff;background:rgba(28,153,244,.16);color:#eef7ff;}',
            '.ntgo-more-copy{color:rgba(230,234,246,.66);font-size:11px;line-height:1.35;max-width:360px;}',
            '.ntgo-results{position:absolute;left:0;right:auto;bottom:34px;z-index:100021;width:360px;max-height:280px;overflow:auto;border:1px solid rgba(93,104,139,.7);border-radius:7px;background:#171b2a;box-shadow:0 10px 28px rgba(0,0,0,.45);padding:5px;}',
            '.' + TOOLBAR_CLASS + '--top .ntgo-results{top:34px;bottom:auto;}',
            '.' + TOOLBAR_CLASS + '--left .ntgo-results{left:calc(100% + 8px);right:auto;top:0;bottom:auto;width:260px;}',
            '.' + TOOLBAR_CLASS + '--right .ntgo-results{left:auto;right:calc(100% + 8px);top:0;bottom:auto;width:260px;}',
            '.ntgo-results[hidden]{display:none;}',
            '.' + RESULT_CLASS + '{display:block;width:100%;border:0;border-radius:5px;background:transparent;color:#edf2ff;text-align:left;padding:7px 8px;font:500 12px/1.3 Montserrat,Arial,sans-serif;cursor:pointer;}',
            '.' + RESULT_CLASS + ':hover{background:rgba(28,153,244,.18);}',
            '.ntgo-result-inner{display:grid;grid-template-columns:74px minmax(0,1fr) 72px;align-items:baseline;gap:8px;}',
            '.ntgo-result-slot{color:#62c4ff;font-weight:700;}',
            '.ntgo-result-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}',
            '.ntgo-result-id{color:rgba(230,234,246,.58);font-size:11px;font-weight:500;text-align:right;white-space:nowrap;}',
            '.ntgo-preview{display:none;margin-top:6px;padding:7px 9px;border-radius:6px;background:rgba(0,0,0,.25);font-size:11px;line-height:1.35;color:#cbd3ec;}',
            '.ntgo-preview.is-visible{display:block;}',
            '.ntgo-preview strong{color:#fff;}',
            '.ntgo-muted-text{color:rgba(230,234,246,.58);}',
            '@media (max-width:1040px){.ntgo-grid{grid-template-columns:1fr}.ntgo-panel{align-items:center}}',
            '@media (max-width:760px){.' + TOOLBAR_CLASS + '{padding:8px}.' + TOOLBAR_CLASS + '--bottom{bottom:8px;width:calc(100vw - 16px)}.' + TOOLBAR_CLASS + '--top{top:8px;width:calc(100vw - 16px)}.' + TOOLBAR_CLASS + '--left,.' + TOOLBAR_CLASS + '--right{top:8px;bottom:8px;--ntgo-side-rail-width:108px;width:var(--ntgo-side-rail-width)}.' + TOOLBAR_CLASS + '--left{left:8px}.' + TOOLBAR_CLASS + '--right{right:8px}.ntgo-status{width:100%;order:4}.ntgo-field input[type="search"]{width:150px}.ntgo-results{width:260px}}'
        ].join('\n');

        if (isNewStyle) pageDocument.head.appendChild(style);
    }

    function syncStatusTooltip() {
        var node = state.statusNode;
        var tooltip = state.statusTooltipNode;
        var text;
        var isSideDock;
        var isClipped;
        if (!node || !tooltip) return;
        text = node.textContent || '';
        tooltip.textContent = text;
        isSideDock = state.toolbarOrientation === 'left' || state.toolbarOrientation === 'right';
        isClipped = !isSideDock && !!text && node.scrollWidth > node.clientWidth + 1;
        node.classList.toggle('has-tooltip', isClipped);
        if (isClipped) {
            node.setAttribute('aria-label', text);
        } else {
            node.removeAttribute('aria-label');
        }
    }

    function scheduleStatusTooltipSync() {
        if (pageWindow.requestAnimationFrame) {
            pageWindow.requestAnimationFrame(syncStatusTooltip);
            return;
        }
        pageWindow.setTimeout(syncStatusTooltip, 0);
    }

    function setStatus(message, tone) {
        if (!state.statusNode) return;
        state.statusNode.classList.remove('is-good', 'is-warn', 'is-bad');
        if (tone) state.statusNode.classList.add('is-' + tone);
        state.statusNode.textContent = message;
        scheduleStatusTooltipSync();
    }

    function getToolbarOrientationFromPoint(clientX, clientY) {
        var width = pageWindow.innerWidth || pageDocument.documentElement.clientWidth || 0;
        var height = pageWindow.innerHeight || pageDocument.documentElement.clientHeight || 0;
        var x = Math.max(0, Math.min(width, Number(clientX) || 0));
        var y = Math.max(0, Math.min(height, Number(clientY) || 0));
        var distances = {
            top: y,
            right: width - x,
            bottom: height - y,
            left: x
        };
        var best = 'bottom';
        var bestDistance = distances.bottom;
        TOOLBAR_DOCK_ORIENTATIONS.forEach(function (orientation) {
            if (distances[orientation] < bestDistance) {
                best = orientation;
                bestDistance = distances[orientation];
            }
        });
        return best;
    }

    function stopToolbarDockDrag(commit) {
        var drag = state.toolbarDockDrag;
        if (!drag) return;
        pageDocument.removeEventListener('pointermove', handleToolbarDockPointerMove, true);
        pageDocument.removeEventListener('pointerup', handleToolbarDockPointerUp, true);
        pageDocument.removeEventListener('pointercancel', handleToolbarDockPointerCancel, true);
        if (state.toolbar) state.toolbar.classList.remove('is-docking');
        state.toolbarDockDrag = null;
        if (commit && drag.moved) {
            setToolbarOrientation(drag.previewOrientation || drag.originalOrientation, { persist: true });
            setStatus('Toolbar docked ' + getToolbarOrientationLabel(state.toolbarOrientation) + '.', 'good');
            return;
        }
        setToolbarOrientation(drag.originalOrientation, { persist: false });
    }

    function handleToolbarDockPointerMove(event) {
        var drag = state.toolbarDockDrag;
        var distance;
        var orientation;
        if (!drag) return;
        distance = Math.abs((Number(event.clientX) || 0) - drag.startX) + Math.abs((Number(event.clientY) || 0) - drag.startY);
        if (!drag.moved && distance < TOOLBAR_DOCK_DRAG_THRESHOLD_PX) return;
        drag.moved = true;
        orientation = getToolbarOrientationFromPoint(event.clientX, event.clientY);
        if (orientation !== drag.previewOrientation) {
            drag.previewOrientation = orientation;
            setToolbarOrientation(orientation, { persist: false });
            setStatus('Dock preview: ' + getToolbarOrientationLabel(orientation) + '.', 'warn');
        }
        event.preventDefault();
    }

    function handleToolbarDockPointerUp(event) {
        if (event) event.preventDefault();
        stopToolbarDockDrag(true);
    }

    function handleToolbarDockPointerCancel() {
        stopToolbarDockDrag(false);
    }

    function beginToolbarDockDrag(event) {
        var target = event && event.currentTarget;
        if (!state.toolbar || state.toolbarDockDrag || (event.button != null && event.button !== 0)) return;
        event.preventDefault();
        event.stopPropagation();
        state.toolbarDockDrag = {
            startX: Number(event.clientX) || 0,
            startY: Number(event.clientY) || 0,
            originalOrientation: state.toolbarOrientation,
            previewOrientation: state.toolbarOrientation,
            moved: false
        };
        state.toolbar.classList.add('is-docking');
        try {
            if (target && typeof target.setPointerCapture === 'function') target.setPointerCapture(event.pointerId);
        } catch (e) { }
        pageDocument.addEventListener('pointermove', handleToolbarDockPointerMove, true);
        pageDocument.addEventListener('pointerup', handleToolbarDockPointerUp, true);
        pageDocument.addEventListener('pointercancel', handleToolbarDockPointerCancel, true);
    }

    function bindToolbarDockDrag(toolbar) {
        var targets = [];
        var handle = toolbar && toolbar.querySelector('[data-ntgo-dock-handle]');
        var brand = toolbar && toolbar.querySelector('.ntgo-brand');
        if (handle) targets.push(handle);
        if (brand && brand !== handle) targets.push(brand);
        targets.forEach(function (target) {
            target.addEventListener('pointerdown', beginToolbarDockDrag);
        });
    }

    function setToolbarMode(mode) {
        var nextMode = mode === 'arrange' || mode === 'more' ? mode : 'select';
        if (!state.toolbar) {
            state.toolbarMode = nextMode;
            return;
        }
        state.toolbarMode = nextMode;
        state.toolbar.querySelectorAll('[data-ntgo-mode]').forEach(function (button) {
            var isActive = button.getAttribute('data-ntgo-mode') === nextMode;
            button.classList.toggle('is-active', isActive);
            button.setAttribute('aria-selected', isActive ? 'true' : 'false');
        });
        state.toolbar.querySelectorAll('[data-ntgo-panel]').forEach(function (panel) {
            panel.hidden = panel.getAttribute('data-ntgo-panel') !== nextMode;
        });
    }

    function ensureToolbar() {
        if (state.toolbar && state.toolbar.isConnected) return state.toolbar;

        var toolbar = pageDocument.createElement('div');
        toolbar.className = TOOLBAR_CLASS;
        toolbar.setAttribute('data-ntgo-toolbar', '1');
        toolbar.innerHTML = [
            '<div class="ntgo-row ntgo-head">',
            '<div class="ntgo-head-left">',
            '<div class="ntgo-brand">Garage Organizer</div>',
            '<div class="ntgo-selection" data-ntgo-selection>0 selected</div>',
            '<div class="ntgo-status-wrap">',
            '<div class="ntgo-status">Rearrange mode active.</div>',
            '<div class="ntgo-status-tooltip" data-ntgo-status-tooltip></div>',
            '</div>',
            '</div>',
            '<span class="ntgo-dock-handle" data-ntgo-dock-handle title="Drag toolbar to another edge" aria-label="Drag toolbar to another edge"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6 8h12M6 12h12M6 16h12" fill="none" stroke-width="2.4" stroke-linecap="round"/></svg></span>',
            '<div class="ntgo-head-right">',
            '<div class="ntgo-search-wrap">',
            '<label class="ntgo-field">Search <input type="search" data-ntgo-search placeholder="Name, car ID, or slot"></label>',
            '<div class="ntgo-results" data-ntgo-results hidden></div>',
            '</div>',
            '<button class="ntgo-btn ntgo-muted" type="button" data-ntgo-undo hidden>Undo</button>',
            '<button class="ntgo-btn ntgo-danger" type="button" data-ntgo-clear>Clear</button>',
            '</div>',
            // '<button class="ntgo-btn ntgo-primary" type="button" data-ntgo-apply hidden>Apply</button>',
            '</div>',
            '<div class="ntgo-row ntgo-mode-tabs" role="tablist" aria-label="Garage Organizer mode">',
            '<button class="ntgo-btn is-active" type="button" data-ntgo-mode="select">Select</button>',
            '<button class="ntgo-btn" type="button" data-ntgo-mode="arrange">Arrange</button>',
            '<button class="ntgo-btn" type="button" data-ntgo-mode="more">More</button>',
            '</div>',
            '<div class="ntgo-grid">',
            '<div class="ntgo-panel" data-ntgo-panel="select">',
            '<label class="ntgo-field">Range <input type="text" data-ntgo-range placeholder="1-30"></label>',
            '<label class="ntgo-field">Select Section <input type="number" data-ntgo-section min="1" step="1"></label>',
            '<button class="ntgo-btn ntgo-muted" type="button" data-ntgo-section-go>Go</button>',
            '<button class="ntgo-btn ntgo-muted" type="button" data-ntgo-select-action>Select</button>',
            '<span class="ntgo-divider" aria-hidden="true"></span>',
            '<label class="ntgo-field">To Section <input type="number" data-ntgo-move-section min="1" step="1"></label>',
            '<label class="ntgo-field">To Slot <input type="number" data-ntgo-move-section-slot min="1" step="1"></label>',
            '<button class="ntgo-btn ntgo-primary" type="button" data-ntgo-move-action>Move</button>',
            '<button class="ntgo-btn ntgo-muted" type="button" data-ntgo-next-empty>Next Empty</button>',
            '</div>',
            '<div class="ntgo-panel" data-ntgo-panel="arrange" hidden>',
            '<label class="ntgo-field">Sort <select data-ntgo-sort><option value="">Choose...</option><option value="id-asc">ID low-high</option><option value="id-desc">ID high-low</option><option value="name-asc">Name A-Z</option><option value="name-desc">Name Z-A</option><option value="category">Category sections</option><option value="rarity-desc">Rarity legendary-first</option><option value="rarity-asc">Rarity common-first</option></select></label>',
            '<label class="ntgo-check"><input type="checkbox" data-ntgo-sort-gaps> Leave ID gaps</label>',
            '<button class="ntgo-btn ntgo-primary" type="button" data-ntgo-sort-action>Apply Sort</button>',
            '<button class="ntgo-btn ntgo-muted" type="button" data-ntgo-compact>Compact Gaps</button>',
            '</div>',
            '<div class="ntgo-panel" data-ntgo-panel="more" hidden>',
            '<div class="ntgo-more-copy">Import or export an exact garage layout. Import requires enough sections to match the file; cars you do not own are skipped without compacting the layout.</div>',
            '<div class="ntgo-drop-zone" data-ntgo-drop-zone>Drop layout JSON here</div>',
            '<button class="ntgo-btn ntgo-muted" type="button" data-ntgo-import>Choose JSON</button>',
            '<button class="ntgo-btn ntgo-muted" type="button" data-ntgo-export>Export Layout</button>',
            '<input type="file" data-ntgo-import-file accept="application/json,.json" hidden>',
            '</div>',
            '</div>',
            '<div class="ntgo-preview" data-ntgo-preview-panel></div>'
        ].join('');

        state.toolbar = toolbar;
        state.statusNode = toolbar.querySelector('.ntgo-status');
        state.searchInput = toolbar.querySelector('[data-ntgo-search]');
        state.searchResults = toolbar.querySelector('[data-ntgo-results]');
        state.moveInput = toolbar.querySelector('[data-ntgo-move]');
        state.moveSectionInput = toolbar.querySelector('[data-ntgo-move-section]');
        state.moveSectionSlotInput = toolbar.querySelector('[data-ntgo-move-section-slot]');
        state.insertInput = toolbar.querySelector('[data-ntgo-insert]');
        state.sortSelect = toolbar.querySelector('[data-ntgo-sort]');
        state.sortGapsInput = toolbar.querySelector('[data-ntgo-sort-gaps]');
        state.rangeInput = toolbar.querySelector('[data-ntgo-range]');
        state.sectionInput = toolbar.querySelector('[data-ntgo-section]');
        state.applyButton = toolbar.querySelector('[data-ntgo-apply]');
        state.clearButton = toolbar.querySelector('[data-ntgo-clear]');
        state.undoButton = toolbar.querySelector('[data-ntgo-undo]');
        state.previewNode = toolbar.querySelector('[data-ntgo-preview-panel]');
        state.selectionNode = toolbar.querySelector('[data-ntgo-selection]');
        state.importFileInput = toolbar.querySelector('[data-ntgo-import-file]');
        state.statusTooltipNode = toolbar.querySelector('[data-ntgo-status-tooltip]');

        toolbar.querySelector('[data-ntgo-move-action]').addEventListener('click', function () { buildAndApply(buildMovePreview); });
        toolbar.querySelector('[data-ntgo-next-empty]').addEventListener('click', function () { buildAndApply(buildNextEmptyPreview); });
        toolbar.querySelector('[data-ntgo-sort-action]').addEventListener('click', function () { buildAndApply(buildSortPreview); });
        toolbar.querySelector('[data-ntgo-compact]').addEventListener('click', function () { buildAndApply(buildCompactPreview); });
        // toolbar.querySelector('[data-ntgo-apply]').addEventListener('click', applyCurrentPreview);
        state.undoButton.addEventListener('click', undoLastAction);
        state.clearButton.addEventListener('click', clearSelection);
        toolbar.querySelectorAll('[data-ntgo-mode]').forEach(function (button) {
            button.addEventListener('click', function () { setToolbarMode(button.getAttribute('data-ntgo-mode')); });
        });
        toolbar.querySelector('[data-ntgo-select-action]').addEventListener('click', selectFromInputs);
        toolbar.querySelector('[data-ntgo-section-go]').addEventListener('click', jumpToSectionInput);
        toolbar.querySelector('[data-ntgo-export]').addEventListener('click', function () {
            exportLayout();
        });
        toolbar.querySelector('[data-ntgo-import]').addEventListener('click', function () {
            importLayoutFile();
        });
        state.importFileInput.addEventListener('change', handleImportFileChange);
        bindImportDropZone(toolbar.querySelector('[data-ntgo-drop-zone]'));
        state.searchInput.addEventListener('input', updateSearchResults);
        state.searchInput.addEventListener('focus', updateSearchResults);
        state.searchInput.addEventListener('keydown', function (event) {
            if (event.key === 'Escape') {
                closeSearchResults();
                state.searchInput.value = '';
            }
            if (event.key === 'Enter') {
                var first = state.searchResults.querySelector('.' + RESULT_CLASS);
                if (first) first.click();
            }
        });
        state.searchInput.addEventListener('blur', function () {
            pageWindow.setTimeout(function () {
                var activeElement = pageDocument.activeElement;
                if (!state.searchResults || !state.searchInput || activeElement === state.searchInput) return;
                if (activeElement && activeElement.closest && activeElement.closest('.ntgo-results')) return;
                closeSearchResults();
            }, 120);
        });
        toolbar.addEventListener('scroll', positionSearchResults, { passive: true });
        pageWindow.addEventListener('resize', positionSearchResults);
        pageWindow.addEventListener('resize', scheduleStatusTooltipSync);
        [state.moveInput, state.moveSectionInput, state.moveSectionSlotInput].forEach(function (input) {
            if (!input) return;
            input.addEventListener('keydown', function (event) {
                if (event.key === 'Enter') buildAndApply(buildMovePreview);
            });
        });
        state.rangeInput.addEventListener('keydown', function (event) {
            if (event.key === 'Enter') selectFromInputs();
        });
        state.sectionInput.addEventListener('keydown', function (event) {
            if (event.key === 'Enter') selectFromInputs();
        });
        state.sortSelect.addEventListener('change', function () {
            state.preview = null;
            syncPreviewPanel('');
        });
        state.sortGapsInput.addEventListener('change', function () {
            state.preview = null;
            syncPreviewPanel('');
        });
        bindToolbarDockDrag(toolbar);

        setToolbarOrientation(readToolbarOrientation(), { persist: false });
        pageDocument.body.appendChild(toolbar);
        setToolbarMode(state.toolbarMode || 'select');
        scheduleStatusTooltipSync();
        return toolbar;
    }

    function syncSelectionSummary() {
        var count = getSelectedInfos().length;
        if (state.selectionNode) {
            state.selectionNode.textContent = count ? count + ' selected' : 'No selection';
        }
        if (!count && state.preview && state.preview.type !== 'sort') {
            state.preview = null;
            syncPreviewPanel('');
        }
    }

    function syncApplyButtonState() {
        if (!state.applying) {
            state.operationUndoCaptured = false;
            state.currentActionLabel = '';
        }
        if (state.applyButton) {
            state.applyButton.disabled = !state.preview || state.applying;
            state.applyButton.hidden = !state.preview || state.directApplying;
            state.applyButton.setAttribute('aria-disabled', state.applyButton.disabled ? 'true' : 'false');
        }
        if (state.clearButton) {
            state.clearButton.textContent = state.applying ? 'Cancel' : 'Clear';
            state.clearButton.setAttribute('aria-label', state.applying ? 'Cancel current operation' : 'Clear selection');
        }
        if (state.undoButton) {
            state.undoButton.hidden = !state.undoHistory.length;
            state.undoButton.disabled = state.applying || !state.undoHistory.length;
            state.undoButton.setAttribute('aria-disabled', state.undoButton.disabled ? 'true' : 'false');
            if (state.undoHistory.length) {
                state.undoButton.title = 'Restore the layout from before ' + state.undoHistory[state.undoHistory.length - 1].label + '. ' + state.undoHistory.length + ' undo action' + (state.undoHistory.length === 1 ? '' : 's') + ' available.';
            } else {
                state.undoButton.removeAttribute('title');
            }
        }
    }

    function syncPreviewPanel(html) {
        if (!state.previewNode) return;
        if (!html) {
            state.previewNode.classList.remove('is-visible');
            state.previewNode.textContent = '';
            syncApplyButtonState();
            return;
        }
        state.previewNode.innerHTML = html;
        state.previewNode.classList.add('is-visible');
        syncApplyButtonState();
    }

    function buildAndApply(buildPreview) {
        if (state.applying || typeof buildPreview !== 'function') return;
        buildPreview();
        if (!state.preview || state.applying) return;
        state.directApplying = true;
        syncPreviewPanel('');
        Promise.resolve(applyCurrentPreview()).finally(function () {
            state.directApplying = false;
            syncApplyButtonState();
        });
    }

    function requestCancelOperation() {
        if (!state.applying) return false;
        state.cancelRequested = true;
        setStatus('Cancelling after the current move finishes...', 'warn');
        syncApplyButtonState();
        return true;
    }

    function getCurrentLayoutKeys() {
        return getSlots().map(function (slot) {
            var info = getCarInfo(slot);
            return info && info.key ? info.key : '';
        });
    }

    function captureUndoSnapshot(label) {
        var keys;
        if (state.restoringUndo) return;
        keys = getCurrentLayoutKeys();
        if (!keys.length) return;
        if (state.undoHistory.length && areLayoutKeysEqual(state.undoHistory[state.undoHistory.length - 1].keys, keys)) return;
        state.undoHistory.push({
            keys: keys,
            label: label || 'the last action'
        });
        while (state.undoHistory.length > MAX_UNDO_HISTORY) {
            state.undoHistory.shift();
        }
        syncApplyButtonState();
    }

    function captureOperationUndo(label) {
        if (state.operationUndoCaptured) return;
        captureUndoSnapshot(label || state.currentActionLabel || 'the last action');
        state.operationUndoCaptured = true;
    }

    function areLayoutKeysEqual(a, b) {
        var i;
        if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
        for (i = 0; i < a.length; i += 1) {
            if ((a[i] || '') !== (b[i] || '')) return false;
        }
        return true;
    }

    async function undoLastAction() {
        var snapshot = state.undoHistory[state.undoHistory.length - 1];
        var plan;
        if (!snapshot || state.applying) return;

        plan = buildLayoutPlanFromDesiredKeys(snapshot.keys, 'Undo last action', 'restore the previous garage order');
        if (!plan.ok) {
            setStatus('Undo unavailable: ' + plan.reason, 'warn');
            return;
        }

        state.restoringUndo = true;
        state.currentActionLabel = 'undo';
        state.preview = {
            type: 'layout',
            plan: plan
        };
        syncPreviewPanel('');
        try {
            await applyLayoutPreview(state.preview);
            if (areLayoutKeysEqual(getCurrentLayoutKeys(), snapshot.keys)) {
                state.undoHistory.pop();
                setStatus('Undo applied. Use Nitro Type Save Garage to persist the restored layout.', 'good');
            } else {
                setStatus('Undo stopped before the previous layout was fully restored. Click Undo again to keep trying.', 'warn');
            }
        } catch (error) {
            setStatus('Undo stopped: ' + (error && error.message ? error.message : String(error)), 'bad');
            logWarn('Undo crashed', error);
        } finally {
            state.restoringUndo = false;
            state.currentActionLabel = '';
            syncApplyButtonState();
        }
    }

    function setSvgText(svg, value, width, height, fontSize) {
        var textNode = svg.querySelector('text');
        svg.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
        svg.setAttribute('width', String(width));
        svg.setAttribute('height', String(height));
        if (!textNode) {
            textNode = pageDocument.createElementNS(SVG_NS, 'text');
            textNode.setAttribute('x', String(width / 2));
            textNode.setAttribute('y', String(Math.round(height / 2 + fontSize / 3)));
            textNode.setAttribute('text-anchor', 'middle');
            svg.appendChild(textNode);
        }
        textNode.textContent = String(value);
    }

    function createSvgLabel(className, value, width, height, fontSize) {
        var svg = pageDocument.createElementNS(SVG_NS, 'svg');
        svg.setAttribute('class', className);
        svg.setAttribute('aria-hidden', 'true');
        setSvgText(svg, value, width, height, fontSize);
        return svg;
    }

    function annotateSectionLabels(slots) {
        var garage = state.garage || getGarageRoot();
        var sectionCount;
        var sectionIndex;
        var liveLabels = {};

        if (!garage || !slots || !slots.length) return;

        sectionCount = Math.ceil(slots.length / SLOTS_PER_SECTION);
        for (sectionIndex = 0; sectionIndex < sectionCount; sectionIndex += 1) {
            var start = sectionIndex * SLOTS_PER_SECTION;
            var end = Math.min(slots.length, start + SLOTS_PER_SECTION);
            var sectionSlots = slots.slice(start, end).filter(function (slot) {
                return slot.offsetWidth && slot.offsetHeight;
            });
            var left;
            var right;
            var top;
            var bottom;
            var label;
            var labelKey = String(sectionIndex + 1);

            if (!sectionSlots.length) continue;
            left = Math.min.apply(null, sectionSlots.map(function (slot) { return slot.offsetLeft; }));
            right = Math.max.apply(null, sectionSlots.map(function (slot) { return slot.offsetLeft + slot.offsetWidth; }));
            top = Math.min.apply(null, sectionSlots.map(function (slot) { return slot.offsetTop; }));
            bottom = Math.max.apply(null, sectionSlots.map(function (slot) { return slot.offsetTop + slot.offsetHeight; }));

            label = garage.querySelector(':scope > .' + SECTION_LABEL_CLASS + '[data-ntgo-section-label="' + labelKey + '"]');
            if (!label) {
                label = createSvgLabel(SECTION_LABEL_CLASS, 'SECTION ' + labelKey, 260, 52, 34);
                label.setAttribute('data-ntgo-section-label', labelKey);
                garage.appendChild(label);
            }
            liveLabels[labelKey] = true;
            label.classList.toggle('is-active', state.focusedSection === sectionIndex);
            label.style.left = Math.round(left + (right - left) / 2 - 130) + 'px';
            label.style.top = Math.round(top + (bottom - top) / 2 - 26) + 'px';
        }

        garage.querySelectorAll(':scope > .' + SECTION_LABEL_CLASS).forEach(function (node) {
            if (!liveLabels[node.getAttribute('data-ntgo-section-label')]) node.remove();
        });
    }

    function annotateSlots() {
        var slots = getSlots();
        var selectedLiveKeys = {};

        slots.forEach(function (slot, index) {
            var info;
            var numberNode;
            var selectButton;

            slot.classList.add(SLOT_CLASS);
            slot.setAttribute('data-ntgo-slot-index', String(index));
            slot.setAttribute('data-ntgo-slot-number', String(index + 1));

            numberNode = slot.querySelector(':scope > .' + SLOT_NUMBER_CLASS);
            if (numberNode && numberNode.namespaceURI !== SVG_NS) {
                numberNode.remove();
                numberNode = null;
            }
            if (!numberNode) {
                numberNode = createSvgLabel(SLOT_NUMBER_CLASS, index + 1, 58, 18, 13);
                slot.appendChild(numberNode);
            }
            numberNode.classList.toggle(SLOT_NUMBER_CLASS + '--top', index % SLOTS_PER_SECTION < SLOTS_PER_SECTION / 2);
            numberNode.classList.toggle(SLOT_NUMBER_CLASS + '--bottom', index % SLOTS_PER_SECTION >= SLOTS_PER_SECTION / 2);
            setSvgText(numberNode, index + 1, 58, 18, 13);

            info = getCarInfo(slot);
            if (info.key) {
                selectedLiveKeys[info.key] = true;
            }

            selectButton = slot.querySelector(':scope > .' + SELECT_BUTTON_CLASS);
            if (info.isEmpty) {
                if (selectButton) selectButton.remove();
                slot.classList.remove(SELECTED_CLASS);
                return;
            }

            if (!state.selectedKeys[info.key]) {
                if (selectButton) selectButton.remove();
                slot.classList.remove(SELECTED_CLASS);
                return;
            }

            if (!selectButton) {
                selectButton = pageDocument.createElement('button');
                selectButton.type = 'button';
                selectButton.className = SELECT_BUTTON_CLASS;
                selectButton.addEventListener('click', function (event) {
                    event.preventDefault();
                    event.stopPropagation();
                    toggleSelection(getCarInfo(slot));
                });
                slot.appendChild(selectButton);
            }

            selectButton.textContent = '✓';
            selectButton.title = 'Remove from selection';
            slot.classList.add(SELECTED_CLASS);
        });

        Object.keys(state.selectedKeys).forEach(function (key) {
            if (!selectedLiveKeys[key]) {
                delete state.selectedKeys[key];
            }
        });

        syncSelectionSummary();
        annotateSectionLabels(slots);
    }

    function cleanupSlotHelpers() {
        pageDocument.querySelectorAll('.' + SLOT_NUMBER_CLASS + ', .' + SELECT_BUTTON_CLASS + ', .' + SECTION_LABEL_CLASS).forEach(function (node) {
            node.remove();
        });
        pageDocument.querySelectorAll('.' + SLOT_CLASS).forEach(function (slot) {
            slot.classList.remove(SLOT_CLASS, SELECTED_CLASS, SOURCE_CLASS, TARGET_CLASS, EMPTY_TARGET_CLASS, PULSE_CLASS);
            slot.removeAttribute('data-ntgo-slot-index');
            slot.removeAttribute('data-ntgo-slot-number');
        });
    }

    function toggleSelection(info) {
        if (!info || info.isEmpty || !info.key) return;
        if (state.selectedKeys[info.key]) {
            delete state.selectedKeys[info.key];
        } else {
            state.selectedKeys[info.key] = true;
        }
        state.preview = null;
        syncPreviewPanel('');
        annotateSlots();
        setStatus('Selection updated.', 'good');
    }

    function clearSelection() {
        if (requestCancelOperation()) return;
        state.selectedKeys = {};
        state.focusedSection = null;
        state.preview = null;
        syncPreviewPanel('');
        annotateSlots();
        setStatus('Selection cleared.', 'good');
    }

    function setFocusedSection(sectionIndex) {
        sectionIndex = parseInt(sectionIndex, 10);
        state.focusedSection = isNaN(sectionIndex) || sectionIndex < 0 ? null : sectionIndex;
        annotateSectionLabels(getSlots());
    }

    function setSourceSlot(slot) {
        if (state.sourceSlot && state.sourceSlot !== slot) {
            state.sourceSlot.classList.remove(SOURCE_CLASS);
        }
        state.sourceSlot = slot || null;
        if (state.sourceSlot) {
            state.sourceSlot.classList.add(SOURCE_CLASS);
        }
    }

    function setTargetSlot(slot) {
        if (state.targetSlot && state.targetSlot !== slot) {
            state.targetSlot.classList.remove(TARGET_CLASS, EMPTY_TARGET_CLASS);
        }
        state.targetSlot = slot || null;
        if (state.targetSlot) {
            state.targetSlot.classList.add(TARGET_CLASS);
            state.targetSlot.classList.toggle(EMPTY_TARGET_CLASS, getCarInfo(state.targetSlot).isEmpty);
        }
    }

    function clearDragMarks() {
        if (state.sourceSlot) {
            state.sourceSlot.classList.remove(SOURCE_CLASS);
            state.sourceSlot = null;
        }
        if (state.targetSlot) {
            state.targetSlot.classList.remove(TARGET_CLASS, EMPTY_TARGET_CLASS);
            state.targetSlot = null;
        }
        clearInsertTarget();
    }

    function ensureInsertMarker() {
        var marker;
        if (state.insertMarker && state.insertMarker.isConnected) return state.insertMarker;

        marker = pageDocument.createElement('div');
        marker.className = INSERT_MARKER_CLASS;
        marker.setAttribute('aria-hidden', 'true');
        pageDocument.body.appendChild(marker);
        state.insertMarker = marker;
        return marker;
    }

    function clearInsertTarget() {
        state.insertTarget = null;
        if (state.insertMarker) {
            state.insertMarker.classList.remove('is-visible', 'is-flipped');
            state.insertMarker.style.left = '';
            state.insertMarker.style.top = '';
            state.insertMarker.style.height = '';
        }
    }

    function updateInsertTargetFromPoint(target, clientX) {
        var slot;
        var slots;
        var index;
        var rect;
        var boundaryIndex;
        var boundaryX;
        var marker;
        var previousIndex;

        if (!state.blockDrag || typeof clientX !== 'number' || !isFinite(clientX)) {
            clearInsertTarget();
            return;
        }

        slot = target && target.closest ? target.closest('.garage-spot') : null;
        if (!slot) {
            clearInsertTarget();
            return;
        }

        slots = getSlots();
        index = getSlotIndex(slot);
        if (index < 0 || index >= slots.length) {
            clearInsertTarget();
            return;
        }

        rect = slot.getBoundingClientRect();
        if (clientX < rect.left - INSERT_EDGE_PX || clientX > rect.right + INSERT_EDGE_PX) {
            clearInsertTarget();
            return;
        }
        if (clientX <= rect.left + INSERT_EDGE_PX) {
            boundaryIndex = index;
            boundaryX = rect.left;
        } else if (clientX >= rect.right - INSERT_EDGE_PX) {
            boundaryIndex = index + 1;
            boundaryX = rect.right;
        } else {
            clearInsertTarget();
            return;
        }

        if (boundaryIndex < 0 || boundaryIndex >= slots.length) {
            clearInsertTarget();
            return;
        }

        previousIndex = state.insertTarget && state.insertTarget.index;
        state.insertTarget = {
            index: boundaryIndex,
            number: boundaryIndex + 1,
            slot: slot
        };

        marker = ensureInsertMarker();
        marker.style.left = Math.round(boundaryX - 1) + 'px';
        marker.style.top = Math.round(rect.top) + 'px';
        marker.style.height = Math.max(28, Math.round(rect.height)) + 'px';
        marker.classList.add('is-visible');
        marker.classList.toggle('is-flipped', boundaryX > pageWindow.innerWidth - 140);

        if (previousIndex !== boundaryIndex) {
            setStatus('Insert here: drop to pack selected cars starting at slot #' + (boundaryIndex + 1) + '.', 'warn');
        }
    }

    function pulseSlot(slot) {
        if (!slot) return;
        slot.classList.remove(PULSE_CLASS);
        // Force reflow so the animation replays.
        try { void slot.offsetWidth; } catch (e) { }
        slot.classList.add(PULSE_CLASS);
        pageWindow.setTimeout(function () {
            if (slot.isConnected) slot.classList.remove(PULSE_CLASS);
        }, 1200);
    }

    function scrollToSlot(slot) {
        if (!slot) return;
        try {
            slot.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
        } catch (e) {
            slot.scrollIntoView();
        }
        setTargetSlot(slot);
        pulseSlot(slot);
        pageWindow.setTimeout(function () {
            if (state.targetSlot === slot) {
                slot.classList.remove(TARGET_CLASS, EMPTY_TARGET_CLASS);
                state.targetSlot = null;
            }
        }, 1800);
    }

    function scrollToSlotQuiet(slot) {
        if (!slot) return;
        try {
            slot.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' });
        } catch (e) {
            slot.scrollIntoView();
        }
    }

    function getSlotByNumber(number) {
        var index = parseInt(number, 10) - 1;
        var slots = getSlots();
        if (isNaN(index) || index < 0 || index >= slots.length) return null;
        return slots[index];
    }

    function getMoveTargetSlot() {
        var sectionValue = state.moveSectionInput && state.moveSectionInput.value;
        var sectionSlotValue = state.moveSectionSlotInput && state.moveSectionSlotInput.value;
        var sectionNumber;
        var sectionSlotNumber;
        var absoluteSlotNumber;
        var sectionStartSlot;
        var sectionEndSlot;
        var localSlotNumber;
        var slot;

        if (sectionValue || sectionSlotValue) {
            sectionNumber = parseInt(sectionValue, 10);
            if (isNaN(sectionNumber) || sectionNumber < 1) {
                setStatus('Enter a valid destination section.', 'bad');
                return null;
            }
            sectionSlotNumber = normalizeText(sectionSlotValue) ? parseInt(sectionSlotValue, 10) : 1;
            if (isNaN(sectionSlotNumber) || sectionSlotNumber < 1) {
                setStatus('Enter a valid destination slot.', 'bad');
                return null;
            }

            sectionStartSlot = ((sectionNumber - 1) * SLOTS_PER_SECTION) + 1;
            sectionEndSlot = sectionNumber * SLOTS_PER_SECTION;
            if (sectionSlotNumber > SLOTS_PER_SECTION) {
                absoluteSlotNumber = sectionSlotNumber;
                if (absoluteSlotNumber < sectionStartSlot || absoluteSlotNumber > sectionEndSlot) {
                    setStatus('Garage slot #' + absoluteSlotNumber + ' is not in section #' + sectionNumber + ' (slots #' + sectionStartSlot + '-' + sectionEndSlot + ').', 'bad');
                    return null;
                }
            } else {
                localSlotNumber = sectionSlotNumber;
                absoluteSlotNumber = sectionStartSlot + localSlotNumber - 1;
            }

            slot = getSlotByNumber(absoluteSlotNumber);
            if (!slot) {
                setStatus('Destination garage slot #' + absoluteSlotNumber + ' is outside this garage.', 'bad');
            }
            return slot;
        }

        return getSlotByNumber(state.moveInput && state.moveInput.value);
    }

    function formatSlotLocation(index) {
        var sectionNumber = Math.floor(index / SLOTS_PER_SECTION) + 1;
        var sectionSlotNumber = (index % SLOTS_PER_SECTION) + 1;
        return 'section <strong>#' + sectionNumber + '</strong>, slot <strong>#' + sectionSlotNumber +
            '</strong> <span class="ntgo-muted-text">(garage slot #' + (index + 1) + ')</span>';
    }

    function getSearchScore(info, query) {
        var carID = String(info.carID || '').toLowerCase();
        var slotNumber = String(info.number || '').toLowerCase();
        var name = String(info.name || '').toLowerCase();
        var isNumeric = /^\d+$/.test(query);

        if (isNumeric && carID === query) return 0;
        if (isNumeric && slotNumber === query) return 1;
        if (isNumeric && carID.indexOf(query) === 0) return 2;
        if (isNumeric && slotNumber.indexOf(query) === 0) return 3;
        if (isNumeric) return Infinity;
        if (name.indexOf(query) !== -1) return 4;
        return Infinity;
    }

    function updateSearchResults() {
        var query = normalizeText(state.searchInput && state.searchInput.value).toLowerCase();
        var results = state.searchResults;
        var matches;

        if (!results) return;
        results.innerHTML = '';

        matches = getSlots()
            .map(getCarInfo)
            .map(function (info) {
                return {
                    info: info,
                    score: query ? getSearchScore(info, query) : 10
                };
            })
            .filter(function (result) { return result.score !== Infinity; })
            .sort(function (a, b) {
                return a.score - b.score || a.info.number - b.info.number;
            })
            .slice(0, MAX_SEARCH_RESULTS);

        state.searchMatches = matches.map(function (match) { return match.info; });

        if (!matches.length) {
            results.innerHTML = '<button type="button" class="' + RESULT_CLASS + '">No cars found</button>';
            results.hidden = false;
            positionSearchResults();
            return;
        }

        matches.forEach(function (match) {
            var info = match.info;
            var button = pageDocument.createElement('button');
            var idMarkup = info.carID ? 'ID: ' + escapeHtml(info.carID) : 'ID: N/A';
            button.type = 'button';
            button.className = RESULT_CLASS;
            button.innerHTML = '<span class="ntgo-result-inner"><span class="ntgo-result-slot">Slot ' + info.number + '</span><span class="ntgo-result-name">' + escapeHtml(info.name) + '</span><span class="ntgo-result-id">' + idMarkup + '</span></span>';
            button.addEventListener('click', function () {
                closeSearchResults();
                scrollToSlot(info.slot);
                if (!info.isEmpty && info.key) {
                    setStatus('Found "' + info.name + '" in slot #' + info.number + '.', 'good');
                } else {
                    setStatus('Found empty slot #' + info.number + '.', 'good');
                }
            });
            results.appendChild(button);
        });

        results.hidden = false;
        positionSearchResults();
    }

    function resetSearchResultsPosition() {
        var results = state.searchResults;
        if (!results) return;
        results.style.position = '';
        results.style.left = '';
        results.style.right = '';
        results.style.top = '';
        results.style.bottom = '';
        results.style.width = '';
        results.style.maxHeight = '';
    }

    function positionSearchResults() {
        var results = state.searchResults;
        var input = state.searchInput;
        var toolbar = state.toolbar;
        var orientation = state.toolbarOrientation;
        var viewportWidth;
        var viewportHeight;
        var toolbarRect;
        var inputRect;
        var preferredWidth = 260;
        var width;
        var left;
        var top;
        var maxTop;

        if (!results || results.hidden || !input || !toolbar || (orientation !== 'left' && orientation !== 'right')) {
            resetSearchResultsPosition();
            return;
        }

        viewportWidth = pageWindow.innerWidth || pageDocument.documentElement.clientWidth || 0;
        viewportHeight = pageWindow.innerHeight || pageDocument.documentElement.clientHeight || 0;
        toolbarRect = toolbar.getBoundingClientRect();
        inputRect = input.getBoundingClientRect();
        width = Math.min(preferredWidth, Math.max(180, viewportWidth - toolbarRect.width - 32));
        top = inputRect.bottom + 6;
        maxTop = Math.max(8, viewportHeight - 288);
        top = Math.max(8, Math.min(top, maxTop));

        if (orientation === 'right') {
            left = Math.max(8, toolbarRect.left - width - 8);
        } else {
            left = Math.min(toolbarRect.right + 8, viewportWidth - width - 8);
        }

        results.style.position = 'fixed';
        results.style.left = Math.max(8, left) + 'px';
        results.style.right = 'auto';
        results.style.top = top + 'px';
        results.style.bottom = 'auto';
        results.style.width = width + 'px';
        results.style.maxHeight = Math.max(120, Math.min(280, viewportHeight - top - 8)) + 'px';
    }

    function closeSearchResults() {
        if (state.searchResults) state.searchResults.hidden = true;
        resetSearchResultsPosition();
    }

    function selectInfos(infos, message) {
        var selectedCount = 0;
        (infos || []).forEach(function (info) {
            if (!info || info.isEmpty || !info.key) return;
            state.selectedKeys[info.key] = true;
            selectedCount += 1;
        });
        state.preview = null;
        syncPreviewPanel('');
        annotateSlots();
        setStatus(message || ('Selected ' + selectedCount + ' cars.'), selectedCount ? 'good' : 'warn');
    }

    function parseSlotRange(value) {
        var text = normalizeText(value);
        var match;
        var start;
        var end;
        if (!text) return null;
        match = text.match(/^(\d+)\s*(?:-|to|:|\.\.)\s*(\d+)$/i);
        if (match) {
            start = parseInt(match[1], 10);
            end = parseInt(match[2], 10);
        } else if (/^\d+$/.test(text)) {
            start = parseInt(text, 10);
            end = start;
        } else {
            return null;
        }
        if (isNaN(start) || isNaN(end)) return null;
        if (end < start) {
            var swap = start;
            start = end;
            end = swap;
        }
        return { start: start, end: end };
    }

    function selectRangeInput() {
        var range = parseSlotRange(state.rangeInput && state.rangeInput.value);
        var slots = getSlots();
        var infos = [];
        var i;
        if (!range) {
            setStatus('Enter a slot range like 151-163.', 'warn');
            return;
        }
        if (range.start < 1 || range.end > slots.length) {
            setStatus('Range must stay between slot #1 and #' + slots.length + '.', 'warn');
            return;
        }
        for (i = range.start - 1; i <= range.end - 1; i += 1) {
            infos.push(getCarInfo(slots[i]));
        }
        selectInfos(infos, 'Selected cars in slots #' + range.start + '-' + range.end + '.');
    }

    function getCurrentSectionIndex() {
        var slots = getSlots();
        var viewportMid = pageWindow.innerHeight / 2;
        var bestIndex = 0;
        var bestDistance = Infinity;
        slots.forEach(function (slot, index) {
            var rect = slot.getBoundingClientRect();
            var distance;
            if (rect.bottom < 0 || rect.top > pageWindow.innerHeight) return;
            distance = Math.abs((rect.top + rect.bottom) / 2 - viewportMid);
            if (distance < bestDistance) {
                bestDistance = distance;
                bestIndex = index;
            }
        });
        return Math.floor(bestIndex / SLOTS_PER_SECTION);
    }

    function getSectionStartIndex(sectionIndex) {
        sectionIndex = parseInt(sectionIndex, 10);
        if (isNaN(sectionIndex) || sectionIndex < 0) sectionIndex = 0;
        return sectionIndex * SLOTS_PER_SECTION;
    }

    function getSectionInfos(sectionIndex) {
        var slots = getSlots();
        var startIndex = getSectionStartIndex(sectionIndex);
        var endIndex = Math.min(slots.length, startIndex + SLOTS_PER_SECTION);
        var infos = [];
        var i;
        for (i = startIndex; i < endIndex; i += 1) {
            infos.push(getCarInfo(slots[i]));
        }
        return infos;
    }

    function selectVisibleSection() {
        var sectionIndex = state.sectionInput && state.sectionInput.value
            ? parseInt(state.sectionInput.value, 10) - 1
            : getCurrentSectionIndex();
        var infos = getSectionInfos(sectionIndex);
        if (!infos.length) {
            setStatus('That section is outside the garage.', 'warn');
            return;
        }
        if (state.sectionInput) state.sectionInput.value = String(sectionIndex + 1);
        setFocusedSection(sectionIndex);
        selectInfos(infos, 'Selected cars in section #' + (sectionIndex + 1) + '.');
    }

    function selectFromInputs() {
        var hasRange = !!normalizeText(state.rangeInput && state.rangeInput.value);
        var hasSection = !!normalizeText(state.sectionInput && state.sectionInput.value);
        if (hasRange) {
            selectRangeInput();
            return;
        }
        selectVisibleSection();
        if (!hasSection) {
            setStatus('Selected cars in the current section.', 'good');
        }
    }

    function jumpToSectionInput() {
        var sectionNumber = parseInt(state.sectionInput && state.sectionInput.value, 10);
        var startIndex;
        var slot;
        if (isNaN(sectionNumber) || sectionNumber < 1) {
            sectionNumber = getCurrentSectionIndex() + 1;
            if (state.sectionInput) state.sectionInput.value = String(sectionNumber);
        }
        startIndex = getSectionStartIndex(sectionNumber - 1);
        slot = getSlots()[startIndex];
        if (!slot) {
            setStatus('Section #' + sectionNumber + ' is outside the garage.', 'warn');
            return;
        }
        setFocusedSection(sectionNumber - 1);
        scrollToSlotQuiet(slot);
        setStatus('Jumped to section #' + sectionNumber + '.', 'good');
    }

    function onDocumentPointerDown(event) {
        if (!state.active) return;
        if (state.searchResults && !state.searchResults.hidden) {
            if (!(event.target && event.target.closest && event.target.closest('.ntgo-search-wrap'))) {
                closeSearchResults();
            }
        }
    }

    function escapeHtml(value) {
        return String(value || '').replace(/[&<>"']/g, function (char) {
            return ({
                '&': '&amp;',
                '<': '&lt;',
                '>': '&gt;',
                '"': '&quot;',
                "'": '&#39;'
            })[char] || char;
        });
    }

    function getLayoutSnapshot(garage) {
        var previousGarage = state.garage;
        var slots;
        if (garage) state.garage = garage;
        slots = getSlots();
        if (garage) state.garage = previousGarage;
        return {
            script: 'Nitro Type Toolkit Garage Organizer',
            version: '3.0.0',
            exportedAt: new Date().toISOString(),
            sourcePath: pageWindow.location.pathname || '',
            slotsPerSection: SLOTS_PER_SECTION,
            slots: slots.map(function (slot) {
                var info = getCarInfo(slot);
                return {
                    slot: info.number,
                    empty: info.isEmpty,
                    name: info.isEmpty ? '' : info.name,
                    carID: info.carID || '',
                    rarity: info.rarity || '',
                    category: info.category || '',
                    src: info.src || '',
                    key: info.key || ''
                };
            })
        };
    }

    function sanitizeFileName(value) {
        var name = normalizeText(value).replace(/[\\/:*?"<>|]+/g, '-').replace(/\s+/g, '-');
        if (!name) name = 'nitro-type-garage-layout';
        if (!/\.json$/i.test(name)) name += '.json';
        return name;
    }

    function exportLayout(garage, defaultNamePrefix, useExactDefaultName) {
        var snapshot = getLayoutSnapshot(garage);
        var json = JSON.stringify(snapshot, null, 2);
        var defaultName = useExactDefaultName
            ? (defaultNamePrefix || 'nitro-type-garage-layout')
            : (defaultNamePrefix || 'nitro-type-garage-layout') + '-' + new Date().toISOString().slice(0, 10);
        var fileName;
        var blob;
        var url;
        var link;

        try {
            fileName = useExactDefaultName
                ? sanitizeFileName(defaultName)
                : sanitizeFileName(pageWindow.prompt('Export layout file name', defaultName) || defaultName);
        } catch (e) {
            fileName = sanitizeFileName(defaultName);
        }

        try {
            blob = new Blob([json], { type: 'application/json' });
            url = URL.createObjectURL(blob);
            link = pageDocument.createElement('a');
            link.href = url;
            link.download = fileName;
            pageDocument.body.appendChild(link);
            link.click();
            link.remove();
            pageWindow.setTimeout(function () {
                URL.revokeObjectURL(url);
            }, 1000);
            setStatus('Exported garage layout as ' + fileName + '.', 'good');
        } catch (error) {
            setStatus('Export download failed. Copy the layout from the popup.', 'warn');
            try {
                pageWindow.prompt('Garage layout JSON', json);
            } catch (e) { }
        }
    }

    function buildDesiredKeysFromImportedLayout(payload) {
        var slots = getSlots();
        var currentInfos = getOccupiedCarInfos();
        var byKey = {};
        var byID = {};
        var usedKeys = {};
        var desiredKeys;
        var unknownCount = 0;
        var importedSlots = Array.isArray(payload && payload.slots) ? payload.slots : [];
        var importedSlotCount = importedSlots.length;
        var importedSections = Math.ceil(importedSlotCount / SLOTS_PER_SECTION);
        var currentSections = Math.ceil(slots.length / SLOTS_PER_SECTION);
        var additionalSections;
        var emptyIndex;
        var i;

        if (!importedSlotCount) {
            return { ok: false, reason: 'Imported layout has no slots.' };
        }

        if (importedSlotCount !== slots.length) {
            additionalSections = Math.max(0, importedSections - currentSections);
            if (importedSlotCount < slots.length) {
                return {
                    ok: false,
                    kind: 'garage-sections-mismatch',
                    reason: 'Imported layout has ' + importedSections + ' garage sections (' + importedSlotCount + ' slots), but this garage has ' + currentSections + ' sections (' + slots.length + ' slots). Use a layout file with the same section count.'
                };
            }
            return {
                ok: false,
                kind: 'garage-sections-needed',
                reason: 'Imported layout needs ' + importedSections + ' garage sections (' + importedSlotCount + ' slots). You currently have ' + currentSections + '. Add ' + additionalSections + ' more section' + (additionalSections === 1 ? '' : 's') + ' before importing.'
            };
        }

        desiredKeys = Array(slots.length).fill('');

        currentInfos.forEach(function (info) {
            byKey[info.key] = info;
            if (info.carID && !byID[String(info.carID)]) {
                byID[String(info.carID)] = info;
            }
        });

        importedSlots.forEach(function (entry, index) {
            var targetIndex = parseInt(entry && entry.slot, 10) - 1;
            var match = null;
            if (isNaN(targetIndex)) targetIndex = index;
            if (targetIndex < 0 || targetIndex >= desiredKeys.length || !entry || entry.empty) return;

            if (entry.key && byKey[entry.key] && !usedKeys[entry.key]) {
                match = byKey[entry.key];
            } else if (entry.carID && byID[String(entry.carID)] && !usedKeys[byID[String(entry.carID)].key]) {
                match = byID[String(entry.carID)];
            }

            if (!match) {
                unknownCount += 1;
                return;
            }

            if (desiredKeys[targetIndex]) {
                unknownCount += 1;
                return;
            }
            desiredKeys[targetIndex] = match.key;
            usedKeys[match.key] = true;
        });

        for (i = 0; i < currentInfos.length; i += 1) {
            if (usedKeys[currentInfos[i].key]) continue;
            emptyIndex = desiredKeys.indexOf('');
            if (emptyIndex === -1) {
                return {
                    ok: false,
                    reason: 'Imported layout has no empty slots for owned cars that are not in the file.'
                };
            }
            desiredKeys[emptyIndex] = currentInfos[i].key;
            usedKeys[currentInfos[i].key] = true;
        }

        return {
            ok: true,
            desiredKeys: desiredKeys,
            unknownCount: unknownCount,
            importedSlotCount: importedSlotCount,
            importedSections: importedSections
        };
    }

    function applyImportedLayout(raw, sourceName) {
        var payload;
        var desired;
        var plan;

        try {
            payload = JSON.parse(raw);
        } catch (error) {
            setStatus('Import stopped: that is not valid JSON.', 'bad');
            return;
        }

        desired = buildDesiredKeysFromImportedLayout(payload);
        if (!desired.ok) {
            syncPreviewPanel(desired.kind === 'garage-sections-needed' || desired.kind === 'garage-sections-mismatch'
                ? '<strong>Import stopped:</strong> ' + escapeHtml(desired.reason)
                : '');
            setStatus(desired.reason, 'bad');
            return;
        }

        plan = buildLayoutPlanFromDesiredKeys(
            desired.desiredKeys,
            sourceName || 'Imported layout',
            (desired.unknownCount ? desired.unknownCount + ' imported cars were not found in this garage and were skipped. ' : '') +
            'Imported cars keep exact slot positions; extra owned cars fill empty imported slots in current order.'
        );
        state.preview = null;
        state.applying = false;
        syncPreviewPanel('');

        if (!plan.ok) {
            setStatus(plan.reason, 'warn');
            return;
        }

        state.preview = {
            type: 'layout',
            plan: plan
        };
        if (desired.unknownCount) {
            syncPreviewPanel('<span class="ntgo-muted-text">' + desired.unknownCount + ' imported cars were not found here and were skipped; matching cars keep exact imported slot positions.</span>');
        }
        setStatus('Applying imported layout...', 'warn');
        applyLayoutPreview(state.preview);
    }

    function importLayoutPrompt() {
        var raw;

        try {
            raw = pageWindow.prompt('Paste Garage Organizer layout JSON');
        } catch (e) {
            raw = '';
        }
        if (!raw) {
            setStatus('Import cancelled.', 'warn');
            return;
        }

        applyImportedLayout(raw, 'Pasted layout');
    }

    function importLayoutFile() {
        var Reader = pageWindow.FileReader || (typeof FileReader !== 'undefined' ? FileReader : null);
        if (!state.importFileInput || !Reader) {
            importLayoutPrompt();
            return;
        }
        state.importFileInput.value = '';
        state.importFileInput.click();
    }

    function importLayoutFileObject(file) {
        var Reader = pageWindow.FileReader || (typeof FileReader !== 'undefined' ? FileReader : null);
        var reader;
        if (!file) {
            setStatus('Import cancelled.', 'warn');
            return;
        }
        if (!Reader) {
            setStatus('Import stopped: file reading is not available in this browser.', 'bad');
            return;
        }
        if (!/\.json$/i.test(file.name)) {
            setStatus('Import stopped: choose a .json layout file.', 'bad');
            return;
        }
        reader = new Reader();
        reader.onload = function () {
            applyImportedLayout(String(reader.result || ''), file.name);
        };
        reader.onerror = function () {
            setStatus('Import stopped: could not read that file.', 'bad');
        };
        reader.readAsText(file);
    }

    function handleImportFileChange() {
        importLayoutFileObject(state.importFileInput && state.importFileInput.files && state.importFileInput.files[0]);
    }

    function bindImportDropZone(dropZone) {
        if (!dropZone) return;
        ['dragenter', 'dragover'].forEach(function (eventName) {
            dropZone.addEventListener(eventName, function (event) {
                event.preventDefault();
                event.stopPropagation();
                dropZone.classList.add('is-dragging');
            });
        });
        ['dragleave', 'drop'].forEach(function (eventName) {
            dropZone.addEventListener(eventName, function (event) {
                event.preventDefault();
                event.stopPropagation();
                dropZone.classList.remove('is-dragging');
            });
        });
        dropZone.addEventListener('drop', function (event) {
            var file = event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files[0];
            importLayoutFileObject(file);
        });
    }

    function getOccupiedCarInfos() {
        return getSlots()
            .map(getCarInfo)
            .filter(function (info) { return info && !info.isEmpty && info.key; });
    }

    function compareCarID(a, b) {
        var aID = Number(a.carID);
        var bID = Number(b.carID);
        if (isFinite(aID) && isFinite(bID) && aID !== bID) return aID - bID;
        return String(a.carID || '').localeCompare(String(b.carID || ''), undefined, { numeric: true });
    }

    function compareName(a, b) {
        return String(a.name || '').localeCompare(String(b.name || ''), undefined, { numeric: true, sensitivity: 'base' });
    }

    function getCategoryLabel(info) {
        return normalizeCategory(info && info.category) || 'Uncategorized';
    }

    function compareCategoryLabel(a, b) {
        var aMissing = !normalizeCategory(a && a.category);
        var bMissing = !normalizeCategory(b && b.category);
        if (aMissing !== bMissing) return aMissing ? 1 : -1;
        return getCategoryLabel(a).localeCompare(getCategoryLabel(b), undefined, { numeric: true, sensitivity: 'base' });
    }

    function compareRarity(a, b, rareFirst) {
        var aRank = a.rarityRank || 0;
        var bRank = b.rarityRank || 0;
        if (aRank !== bRank) {
            if (rareFirst) return (bRank || -1) - (aRank || -1);
            return (aRank || 999) - (bRank || 999);
        }
        return compareCarID(a, b) || compareName(a, b);
    }

    function getSortLabel(mode) {
        return ({
            'id-asc': 'Car ID low to high',
            'id-desc': 'Car ID high to low',
            'name-asc': 'Name A-Z',
            'name-desc': 'Name Z-A',
            'category': 'Category sections',
            'rarity-desc': 'Rarity legendary first',
            'rarity-asc': 'Rarity common first'
        })[mode] || '';
    }

    function getSortComparator(mode) {
        if (mode === 'id-asc') {
            return function (a, b) { return compareCarID(a, b) || compareName(a, b); };
        }
        if (mode === 'id-desc') {
            return function (a, b) { return compareCarID(b, a) || compareName(a, b); };
        }
        if (mode === 'name-asc') {
            return function (a, b) { return compareName(a, b) || compareCarID(a, b); };
        }
        if (mode === 'name-desc') {
            return function (a, b) { return compareName(b, a) || compareCarID(a, b); };
        }
        if (mode === 'category') {
            return function (a, b) { return compareCategoryLabel(a, b) || compareCarID(a, b) || compareName(a, b); };
        }
        if (mode === 'rarity-desc') {
            return function (a, b) { return compareRarity(a, b, true); };
        }
        if (mode === 'rarity-asc') {
            return function (a, b) { return compareRarity(a, b, false); };
        }
        return null;
    }

    function buildLayoutPlanFromDesiredKeys(desiredKeys, label, detail) {
        var slots = getSlots();
        var currentKeys = slots.map(function (slot) { return getCarInfo(slot).key || ''; });
        var currentCounts = {};
        var desiredCounts = {};
        var changedCount = 0;
        var previewNames = [];
        var i;

        if (!Array.isArray(desiredKeys) || desiredKeys.length !== slots.length) {
            return { ok: false, reason: 'Layout plan does not match the current garage size.' };
        }

        currentKeys.forEach(function (key) {
            if (!key) return;
            currentCounts[key] = (currentCounts[key] || 0) + 1;
        });
        desiredKeys.forEach(function (key) {
            if (!key) return;
            desiredCounts[key] = (desiredCounts[key] || 0) + 1;
        });

        if (Object.keys(currentCounts).length !== Object.keys(desiredCounts).length) {
            return { ok: false, reason: 'Layout plan must contain the same owned cars that are currently in the garage.' };
        }

        for (i = 0; i < Object.keys(currentCounts).length; i += 1) {
            var key = Object.keys(currentCounts)[i];
            if (currentCounts[key] !== desiredCounts[key]) {
                return { ok: false, reason: 'Layout plan has duplicate or missing cars.' };
            }
        }

        for (i = 0; i < currentKeys.length; i += 1) {
            if (currentKeys[i] !== desiredKeys[i]) changedCount += 1;
            if (desiredKeys[i] && previewNames.length < 5) {
                var slot = findSlotByKey(desiredKeys[i]);
                var info = slot ? getCarInfo(slot) : null;
                previewNames.push('#' + (i + 1) + ' ' + escapeHtml(info ? info.name : 'Unknown Car'));
            }
        }

        if (!changedCount) {
            return { ok: false, reason: 'That layout already matches the current garage.' };
        }

        return {
            ok: true,
            type: 'layout',
            label: label || 'Custom layout',
            detail: detail || '',
            desiredKeys: desiredKeys,
            changedCount: changedCount,
            previewNames: previewNames
        };
    }

    function buildCompactPreview() {
        var slots = getSlots();
        var occupiedKeys = getOccupiedCarInfos().map(function (info) { return info.key; });
        var desiredKeys = occupiedKeys.concat(Array(Math.max(0, slots.length - occupiedKeys.length)).fill(''));
        var plan = buildLayoutPlanFromDesiredKeys(desiredKeys, 'Compact empty gaps', 'pack all owned cars together while preserving current order');

        state.preview = null;
        state.applying = false;
        syncPreviewPanel('');

        if (!plan.ok) {
            setStatus(plan.reason, 'warn');
            return;
        }

        state.preview = {
            type: 'layout',
            plan: plan
        };
        syncPreviewPanel(
            '<strong>Compact preview:</strong> this will move <strong>' + plan.changedCount +
            '</strong> slot positions and pack empty slots after your owned cars.<br>' +
            '<strong>First after compact:</strong> ' + plan.previewNames.join(', ') + '<br>' +
            'Use Nitro Type <strong>Save Garage</strong> after Apply if the result looks right.'
        );
        setStatus('Compact preview ready.', 'warn');
    }

    function findEmptyRange(startIndex, count) {
        var slots = getSlots();
        var start;
        var offset;
        var info;
        if (count < 1) return null;

        for (start = Math.max(0, startIndex || 0); start + count <= slots.length; start += 1) {
            for (offset = 0; offset < count; offset += 1) {
                info = getCarInfo(slots[start + offset]);
                if (!info.isEmpty) break;
            }
            if (offset === count) return start;
        }
        return null;
    }

    function buildNextEmptyPreview() {
        var selected = getSelectedInfos();
        var selectedKeys;
        var count;
        var firstStart;
        var fallbackStart;

        state.preview = null;
        state.applying = false;
        syncPreviewPanel('');

        if (!selected.length) {
            setStatus('Select at least one car first.', 'warn');
            return;
        }

        selectedKeys = selected.map(function (info) { return info.key; });
        count = selectedKeys.length;
        firstStart = findEmptyRange(selected[selected.length - 1].index + 1, count);
        fallbackStart = firstStart == null ? findEmptyRange(0, count) : firstStart;

        if (fallbackStart == null) {
            setStatus('No empty range large enough for ' + count + ' selected car' + (count === 1 ? '' : 's') + '.', 'warn');
            return;
        }

        state.preview = {
            type: 'move',
            targetIndex: fallbackStart,
            selectedKeys: selectedKeys
        };
        syncPreviewPanel(
            '<strong>Next Empty preview:</strong> ' + count + ' selected car' + (count === 1 ? '' : 's') +
            ' will move to the empty range starting at slot <strong>#' + (fallbackStart + 1) + '</strong>.<br>' +
            'Use Nitro Type <strong>Save Garage</strong> after Apply if the result looks right.'
        );
        setStatus('Next Empty preview ready.', 'warn');
    }

    function getSectionLabel(count) {
        return count + ' garage section' + (count === 1 ? '' : 's');
    }

    function buildCategorySectionTargetIndexes(sorted, totalSlots) {
        var groups = [];
        var groupByLabel = {};
        var uncategorizedGroup = null;
        var cursor = 0;
        var targetIndexes = [];
        var requiredSections = 0;
        var currentSections = Math.ceil(totalSlots / SLOTS_PER_SECTION);
        var groupIndex;
        var itemIndex;
        var groupSectionCount;

        sorted.forEach(function (info) {
            var hasCategory = !!normalizeCategory(info.category);
            var label = getCategoryLabel(info);
            var group;
            if (!hasCategory) {
                if (!uncategorizedGroup) {
                    uncategorizedGroup = { label: 'Uncategorized', infos: [] };
                }
                uncategorizedGroup.infos.push(info);
                return;
            }
            group = groupByLabel[label];
            if (!group) {
                group = { label: label, infos: [] };
                groupByLabel[label] = group;
                groups.push(group);
            }
            group.infos.push(info);
        });

        groups.sort(function (a, b) {
            return a.label.localeCompare(b.label, undefined, { numeric: true, sensitivity: 'base' });
        });
        if (uncategorizedGroup) groups.push(uncategorizedGroup);

        groups.forEach(function (group) {
            requiredSections += Math.max(1, Math.ceil(group.infos.length / SLOTS_PER_SECTION));
        });

        if (requiredSections > currentSections) {
            return {
                ok: false,
                groups: groups,
                labels: groups.map(function (group) { return group.label; }),
                currentSlots: totalSlots,
                currentSections: currentSections,
                requiredSlots: requiredSections * SLOTS_PER_SECTION,
                requiredSections: requiredSections,
                additionalSections: requiredSections - currentSections
            };
        }

        for (groupIndex = 0; groupIndex < groups.length; groupIndex += 1) {
            groupSectionCount = Math.max(1, Math.ceil(groups[groupIndex].infos.length / SLOTS_PER_SECTION));
            for (itemIndex = 0; itemIndex < groups[groupIndex].infos.length; itemIndex += 1) {
                targetIndexes.push(cursor + itemIndex);
            }
            cursor += groupSectionCount * SLOTS_PER_SECTION;
        }

        return {
            ok: true,
            indexes: targetIndexes,
            groups: groups,
            labels: groups.map(function (group) { return group.label; })
        };
    }

    function buildSortPlan(mode) {
        var comparator = getSortComparator(mode);
        var occupied = getOccupiedCarInfos();
        var selected = getSelectedInfos();
        var sortItems = selected.length ? selected : occupied;
        var selectedOnly = selected.length > 0;
        var leaveIDGaps = !!(state.sortGapsInput && state.sortGapsInput.checked && /^id-/.test(mode || ''));
        var targetIndexes;
        var sorted;
        var changedCount = 0;
        var maxCarID = 0;
        var currentSlots = getSlots().length;
        var currentSections = Math.ceil(currentSlots / SLOTS_PER_SECTION);
        var targetStartIndex = 0;
        var requiredSections;
        var carID;
        var categoryTargets;
        var categoryLabelPreview;
        var detail = '';
        var sectionSeparated = false;
        var i;

        if (!comparator) {
            return { ok: false, reason: 'Choose a sort mode first.' };
        }
        if (occupied.length < 2) {
            return { ok: false, reason: 'Need at least two cars to sort.' };
        }
        if (sortItems.length < 2) {
            return { ok: false, reason: 'Need at least two selected cars to sort.' };
        }

        if (selectedOnly) {
            if (state.focusedSection != null) {
                targetStartIndex = getSectionStartIndex(state.focusedSection);
            } else {
                targetStartIndex = Math.min.apply(null, selected.map(function (info) { return info.index; }));
            }
            if (targetStartIndex + sortItems.length > currentSlots) {
                return { ok: false, reason: 'Selected sort needs enough slots after the target section start.' };
            }
            if (leaveIDGaps) {
                return { ok: false, reason: 'Leave ID gaps only supports sorting the full garage.' };
            }
        }

        sorted = sortItems.slice().sort(comparator);
        if (mode === 'category') {
            categoryTargets = buildCategorySectionTargetIndexes(sorted, currentSlots - targetStartIndex);
            if (!categoryTargets.ok) {
                return {
                    ok: false,
                    kind: 'category-sections-needed',
                    reason: 'Category sections need enough garage sections to keep groups separated.',
                    labels: categoryTargets.labels,
                    currentSlots: categoryTargets.currentSlots,
                    currentSections: categoryTargets.currentSections,
                    requiredSlots: categoryTargets.requiredSlots,
                    requiredSections: categoryTargets.requiredSections,
                    additionalSections: categoryTargets.additionalSections
                };
            }
            targetIndexes = categoryTargets.indexes.map(function (index) { return index + targetStartIndex; });
            sectionSeparated = true;
            categoryLabelPreview = categoryTargets.labels.slice(0, 8).join(', ');
            if (categoryTargets.labels.length > 8) {
                categoryLabelPreview += ', +' + (categoryTargets.labels.length - 8) + ' more';
            }
            detail = 'Each category starts on a fresh garage section; unused slots at the end of a category section are left blank. Groups: ' + categoryLabelPreview + '.';
        } else if (leaveIDGaps) {
            occupied.forEach(function (info) {
                carID = parseInt(info.carID, 10);
                if (!isNaN(carID) && carID > maxCarID) maxCarID = carID;
            });
            if (!maxCarID || maxCarID > currentSlots) {
                requiredSections = maxCarID ? Math.ceil(maxCarID / SLOTS_PER_SECTION) : 0;
                return {
                    ok: false,
                    kind: 'garage-sections-needed',
                    reason: 'Leave ID gaps needs enough garage slots for the highest owned car ID.',
                    highestCarID: maxCarID || null,
                    currentSlots: currentSlots,
                    currentSections: currentSections,
                    requiredSlots: maxCarID || null,
                    requiredSections: requiredSections,
                    additionalSections: Math.max(0, requiredSections - currentSections)
                };
            }
            targetIndexes = sorted.map(function (info) {
                carID = parseInt(info.carID, 10);
                return isNaN(carID) ? -1 : carID - 1;
            });
            if (targetIndexes.indexOf(-1) !== -1) {
                return { ok: false, reason: 'Leave ID gaps needs real car IDs for every owned car.' };
            }
        } else {
            targetIndexes = getSlots().slice(targetStartIndex, targetStartIndex + sortItems.length).map(function (slot) {
                return getSlotIndex(slot);
            });
        }

        for (i = 0; i < sorted.length; i += 1) {
            if (sorted[i].index !== targetIndexes[i]) changedCount += 1;
        }
        if (!changedCount) {
            return { ok: false, reason: 'Garage is already sorted by ' + getSortLabel(mode) + '.' };
        }

        return {
            ok: true,
            mode: mode,
            label: selectedOnly ? getSortLabel(mode) + ' selection' : getSortLabel(mode),
            count: sortItems.length,
            changedCount: changedCount,
            leaveIDGaps: leaveIDGaps,
            detail: selectedOnly
                ? ((state.focusedSection != null ? 'Selected cars will start at section #' + (state.focusedSection + 1) + ', slot #1. ' : 'Selected cars will sort from their first selected slot. ') + detail)
                : detail,
            sectionSeparated: sectionSeparated,
            slotIndexes: targetIndexes,
            orderedKeys: sorted.map(function (info) { return info.key; }),
            previewNames: sorted.slice(0, 5).map(function (info) {
                return '#' + info.number + ' ' + escapeHtml(info.name) +
                    (info.carID ? ' <span class="ntgo-muted-text">ID: ' + escapeHtml(info.carID) + '</span>' : '') +
                    (info.rarity ? ' <span class="ntgo-muted-text">' + escapeHtml(info.rarity) + '</span>' : '') +
                    (mode === 'category' ? ' <span class="ntgo-muted-text">' + escapeHtml(getCategoryLabel(info)) + '</span>' : '');
            })
        };
    }

    function buildSortPreview() {
        var mode = state.sortSelect && state.sortSelect.value;
        var plan = buildSortPlan(mode);
        var sortBehavior;

        state.preview = null;
        state.applying = false;
        syncPreviewPanel('');

        if (!plan.ok) {
            if (plan.kind === 'garage-sections-needed') {
                syncPreviewPanel(
                    '<strong>Leave ID gaps needs more garage slots.</strong><br>' +
                    'Your highest owned car ID is <strong>' + escapeHtml(plan.highestCarID || 'unknown') + '</strong>, so this sort needs slot <strong>#' +
                    escapeHtml(plan.requiredSlots || 'unknown') + '</strong>. You currently have <strong>' + plan.currentSlots + '</strong> slots (' +
                    getSectionLabel(plan.currentSections) + ').<br>' +
                    'Set your garage to at least <strong>' + getSectionLabel(plan.requiredSections) + '</strong> with Toolkit\'s <strong>Garage Expansion</strong> (' +
                    getSectionLabel(plan.additionalSections) + ' more), then come back and run the sort again. ' +
                    'Toolkit logs you out after applying so the new sections can take effect.'
                );
                setStatus('Leave ID gaps needs more garage sections before it can sort.', 'warn');
                return;
            }
            if (plan.kind === 'category-sections-needed') {
                syncPreviewPanel(
                    '<strong>Category sections need more garage slots.</strong><br>' +
                    'This sort keeps every category on its own section block, including blank remainder slots. You currently have <strong>' +
                    plan.currentSlots + '</strong> slots (' + getSectionLabel(plan.currentSections) + '), but these categories need <strong>' +
                    getSectionLabel(plan.requiredSections) + '</strong>.<br>' +
                    'Add <strong>' + getSectionLabel(plan.additionalSections) + '</strong> with Toolkit\'s <strong>Garage Expansion</strong>, then run category sorting again.<br>' +
                    '<span class="ntgo-muted-text">Groups found: ' + escapeHtml(plan.labels.slice(0, 10).join(', ')) +
                    (plan.labels.length > 10 ? ', +' + (plan.labels.length - 10) + ' more' : '') + '</span>'
                );
                setStatus('Category sorting needs more garage sections before it can preserve blank section space.', 'warn');
                return;
            }
            setStatus(plan.reason, 'warn');
            return;
        }

        state.preview = {
            type: 'sort',
            plan: plan
        };
        sortBehavior = plan.leaveIDGaps
            ? 'leave blank spaces for missing car IDs.'
            : plan.sectionSeparated
                ? 'start category groups on garage section boundaries.'
                : 'pack empty slots after the sorted cars.';
        syncPreviewPanel(
            '<strong>Sort preview:</strong> ' + plan.label + ' will reorder <strong>' + plan.changedCount +
            '</strong> of <strong>' + plan.count + '</strong> cars and ' + sortBehavior + '<br>' +
            (plan.detail ? '<span class="ntgo-muted-text">' + escapeHtml(plan.detail) + '</span><br>' : '') +
            '<strong>First after sort:</strong> ' + plan.previewNames.join(', ') + '<br>' +
            'Use Nitro Type <strong>Save Garage</strong> after Apply if the result looks right.'
        );
        setStatus('Sort preview ready. Apply will use repeated Nitro Type swaps.', 'warn');
    }

    function buildMovePreview() {
        var selected = getSelectedInfos();
        var targetSlot = getMoveTargetSlot();
        var insertMode = !!(state.insertInput && state.insertInput.checked);
        var targetInfo;
        var names;
        var selectedKeys;
        var insertPlan;

        state.preview = null;
        state.applying = false;
        syncPreviewPanel('');

        if (!selected.length) {
            setStatus('Select at least one car first.', 'bad');
            return;
        }
        if (!targetSlot) {
            setStatus('Enter a valid target slot.', 'bad');
            return;
        }

        targetInfo = getCarInfo(targetSlot);
        names = selected.map(function (info) { return '#' + info.number + ' ' + escapeHtml(info.name); }).join(', ');
        selectedKeys = selected.map(function (info) { return info.key; });

        if (insertMode) {
            insertPlan = buildInsertZoneLayoutPlan(targetInfo.index, selectedKeys);
            if (!insertPlan.ok) {
                syncPreviewPanel(
                    '<strong>Insert preview:</strong> ' + insertPlan.reason + '<br>' +
                    '<strong>Selected:</strong> ' + names
                );
                setStatus(insertPlan.reason, 'warn');
                return;
            }

            state.preview = {
                type: 'insert-zone',
                plan: insertPlan
            };

            syncPreviewPanel(
                '<strong>Insert preview:</strong> ' + insertPlan.selectedKeys.length + ' selected car' + (insertPlan.selectedKeys.length === 1 ? '' : 's') +
                ' will start at ' + formatSlotLocation(insertPlan.targetIndex) + '. Existing cars at and after that slot will shift right in cell order until a gap absorbs the move.<br>' +
                '<strong>Selected:</strong> ' + names + '<br>' +
                'Use Nitro Type <strong>Save Garage</strong> after Apply if the result looks right.'
            );
            setStatus('Insert preview ready. Apply will reflow the selected cars into that slot.', 'warn');
            return;
        }

        state.preview = {
            type: 'move',
            targetIndex: targetInfo.index,
            selectedKeys: selectedKeys
        };
        syncPreviewPanel(
            '<strong>Move preview:</strong> ' + selected.length + ' selected car' + (selected.length === 1 ? '' : 's') +
            ' will be moved with synthetic drag/drop starting at ' + formatSlotLocation(targetInfo.index) + '. Nitro Type still controls the final rearrange behavior.<br>' +
            '<strong>Selected:</strong> ' + names
        );
        setStatus('Preview ready. Apply will test Nitro Type drag/drop.', 'warn');
    }

    function createDataTransferShim() {
        var data = {};
        try {
            if (typeof pageWindow.DataTransfer === 'function') {
                return new pageWindow.DataTransfer();
            }
        } catch (e) { }
        return {
            dropEffect: 'move',
            effectAllowed: 'all',
            files: [],
            items: [],
            types: [],
            setData: function (type, value) {
                data[type] = String(value);
                if (this.types.indexOf(type) === -1) this.types.push(type);
            },
            getData: function (type) {
                return data[type] || '';
            },
            clearData: function (type) {
                if (type) {
                    delete data[type];
                    this.types = this.types.filter(function (entry) { return entry !== type; });
                } else {
                    data = {};
                    this.types = [];
                }
            },
            setDragImage: function () { }
        };
    }

    function dispatchDragEvent(target, type, dataTransfer) {
        var event;
        var init = {
            bubbles: true,
            cancelable: true,
            composed: true,
            dataTransfer: dataTransfer,
            clientX: 0,
            clientY: 0
        };

        try {
            event = new pageWindow.DragEvent(type, init);
        } catch (e) {
            event = pageDocument.createEvent('CustomEvent');
            event.initCustomEvent(type, true, true, null);
            try {
                Object.defineProperty(event, 'dataTransfer', {
                    value: dataTransfer,
                    configurable: true
                });
            } catch (err) {
                event.dataTransfer = dataTransfer;
            }
        }

        return target.dispatchEvent(event);
    }

    function simulateDragDrop(sourceSlot, targetSlot) {
        return new Promise(function (resolve) {
            var sourceInfo = getCarInfo(sourceSlot);
            var targetInfo = getCarInfo(targetSlot);
            var sourceVehicle = sourceInfo.vehicle || sourceSlot;
            var dropTarget = (targetInfo.vehicle || targetSlot);
            var dataTransfer = createDataTransferShim();
            var beforeSourceKey = sourceInfo.key;
            var beforeTargetKey = targetInfo.key;

            if (!sourceSlot || !targetSlot || sourceSlot === targetSlot || sourceInfo.isEmpty) {
                resolve({ ok: false, reason: 'Invalid source or target slot.' });
                return;
            }

            captureOperationUndo(state.currentActionLabel || 'the last action');

            try {
                dataTransfer.effectAllowed = 'move';
                dataTransfer.dropEffect = 'move';
                dataTransfer.setData('travis_rules', beforeSourceKey || String(sourceInfo.index));
                dataTransfer.setData('text/plain', beforeSourceKey || String(sourceInfo.index));
            } catch (e) { }

            setSourceSlot(sourceSlot);
            setTargetSlot(targetSlot);

            try {
                state.syntheticDragDepth += 1;
                dispatchDragEvent(sourceVehicle, 'dragstart', dataTransfer);
                dispatchDragEvent(dropTarget, 'dragenter', dataTransfer);
                dispatchDragEvent(dropTarget, 'dragover', dataTransfer);
                dispatchDragEvent(dropTarget, 'drop', dataTransfer);
                dispatchDragEvent(sourceVehicle, 'dragend', dataTransfer);
            } catch (error) {
                clearDragMarks();
                resolve({ ok: false, reason: error && error.message ? error.message : String(error) });
                return;
            } finally {
                state.syntheticDragDepth = Math.max(0, state.syntheticDragDepth - 1);
            }

            pageWindow.setTimeout(function () {
                var afterTargetKey = getCarInfo(targetSlot).key;
                var afterSourceKey = getCarInfo(sourceSlot).key;
                var movedToTarget = afterTargetKey === beforeSourceKey;
                var sourceChanged = afterSourceKey !== beforeSourceKey;
                clearDragMarks();
                scheduleRefresh();
                resolve({
                    ok: movedToTarget || sourceChanged,
                    movedToTarget: movedToTarget,
                    sourceChanged: sourceChanged,
                    beforeSourceKey: beforeSourceKey,
                    beforeTargetKey: beforeTargetKey,
                    afterSourceKey: afterSourceKey,
                    afterTargetKey: afterTargetKey
                });
            }, 360);
        });
    }

    async function applyInsertPreview(preview) {
        var plan = preview && preview.plan;
        var currentSource;
        var currentTarget;
        var bufferSlot;
        var bufferInfo;
        var result;
        var gapInfo;

        if (!plan) return;

        state.currentActionLabel = 'insert';
        state.applying = true;
        syncApplyButtonState();

        if (plan.kind === 'empty-target') {
            setStatus('Moving selected car into empty slot...', 'warn');
            currentSource = findSlotByKey(plan.selectedKey);
            currentTarget = getSlots()[plan.targetIndex];
            if (!currentSource || !currentTarget) {
                setStatus('Insert stopped: source or target slot disappeared.', 'bad');
            } else {
                result = await simulateDragDrop(currentSource, currentTarget);
                if (result.ok) {
                    state.dirty = true;
                    setStatus('Moved into empty slot. Use Nitro Type Save Garage to persist.', 'good');
                } else {
                    setStatus('Insert move did not take. Nitro Type may reject synthetic drag/drop here.', 'bad');
                    logWarn('Empty-target insert failed', result);
                }
            }

            state.applying = false;
            state.preview = null;
            syncPreviewPanel('');
            annotateSlots();
            return;
        }

        if (plan.kind !== 'insert-one-earlier') {
            state.applying = false;
            setStatus('Unsupported insert plan.', 'bad');
            return;
        }

        setStatus('Moving selected car to temporary buffer...', 'warn');
        currentSource = findSlotByKey(plan.selectedKey);
        bufferSlot = getSlots()[plan.bufferIndex];
        bufferInfo = bufferSlot ? getCarInfo(bufferSlot) : null;
        if (!currentSource || !bufferSlot || !bufferInfo || !bufferInfo.isEmpty) {
            state.applying = false;
            state.preview = null;
            syncPreviewPanel('');
            annotateSlots();
            setStatus('Insert stopped: the buffer slot is no longer empty.', 'bad');
            return;
        }

        result = await simulateDragDrop(currentSource, bufferSlot);
        if (!result.ok) {
            state.applying = false;
            state.preview = null;
            syncPreviewPanel('');
            annotateSlots();
            setStatus('Insert stopped: selected car could not move to the buffer slot.', 'bad');
            logWarn('Insert buffer move failed', result);
            return;
        }
        await waitForGarageSettled();

        gapInfo = findLastEmptyInfoBetween(plan.targetIndex, plan.sourceIndex);
        if (!gapInfo) {
            state.applying = false;
            state.preview = null;
            syncPreviewPanel('');
            annotateSlots();
            setStatus('Insert stopped: moving to the buffer did not create an empty shift gap.', 'bad');
            logWarn('Insert buffer move did not create a shift gap', {
                plan: plan,
                result: result
            });
            return;
        }

        while (gapInfo.index > plan.targetIndex) {
            var slots = getSlots();
            var fromSlot = slots[gapInfo.index - 1];
            var toSlot = slots[gapInfo.index];
            var fromInfo = fromSlot ? getCarInfo(fromSlot) : null;
            var toInfo = toSlot ? getCarInfo(toSlot) : null;

            if (!fromSlot || !toSlot || !fromInfo || !toInfo || !toInfo.isEmpty) {
                state.applying = false;
                state.preview = null;
                syncPreviewPanel('');
                annotateSlots();
                setStatus('Insert stopped: the shift path changed while applying.', 'bad');
                logWarn('Insert shift path changed', {
                    gapIndex: gapInfo.index,
                    fromIndex: gapInfo.index - 1,
                    toIndex: gapInfo.index,
                    fromInfo: fromInfo,
                    toInfo: toInfo
                });
                return;
            }

            if (fromInfo.isEmpty) {
                gapInfo = fromInfo;
                setStatus('Skipping empty slot #' + fromInfo.number + ' in the insert path...', 'warn');
                continue;
            }

            setStatus('Shifting slot #' + fromInfo.number + ' forward...', 'warn');
            result = await simulateDragDrop(fromSlot, toSlot);
            if (!result.ok) {
                state.applying = false;
                state.preview = null;
                syncPreviewPanel('');
                annotateSlots();
                setStatus('Insert stopped: Nitro Type rejected a shift move.', 'bad');
                logWarn('Insert shift failed', result);
                return;
            }

            await waitForGarageSettled();
            gapInfo = findLastEmptyInfoBetween(plan.targetIndex, gapInfo.index - 1);
            if (!gapInfo) {
                state.applying = false;
                state.preview = null;
                syncPreviewPanel('');
                annotateSlots();
                setStatus('Insert stopped: the empty shift gap disappeared.', 'bad');
                logWarn('Insert shift gap disappeared', {
                    plan: plan,
                    lastResult: result
                });
                return;
            }
        }

        setStatus('Placing selected car into the target slot...', 'warn');
        currentSource = findSlotByKey(plan.selectedKey);
        currentTarget = gapInfo.slot || getSlots()[plan.targetIndex];
        if (!currentSource || !currentTarget || gapInfo.index !== plan.targetIndex || !getCarInfo(currentTarget).isEmpty) {
            state.applying = false;
            state.preview = null;
            syncPreviewPanel('');
            annotateSlots();
            setStatus('Insert stopped: target slot is not available.', 'bad');
            return;
        }

        result = await simulateDragDrop(currentSource, currentTarget);
        state.applying = false;
        state.preview = null;
        syncPreviewPanel('');
        annotateSlots();

        if (result.ok) {
            state.dirty = true;
            setStatus('Insert applied in the DOM. Use Nitro Type Save Garage to persist.', 'good');
        } else {
            setStatus('Insert stopped: selected car could not move into the target slot.', 'bad');
            logWarn('Insert final move failed', result);
        }
    }

    async function applySortPreview(preview) {
        var plan = preview && preview.plan;
        var i;
        var currentSource;
        var currentTarget;
        var sourceInfo;
        var targetInfo;
        var result;
        var applied = 0;

        if (!plan) return;

        state.currentActionLabel = 'sort';
        state.applying = true;
        state.cancelRequested = false;
        syncApplyButtonState();
        setStatus('Applying sort with repeated swaps...', 'warn');

        for (i = 0; i < plan.orderedKeys.length; i += 1) {
            if (state.cancelRequested) {
                state.applying = false;
                state.cancelRequested = false;
                state.preview = null;
                state.dirty = applied > 0;
                syncPreviewPanel('');
                annotateSlots();
                setStatus('Sort cancelled after ' + applied + ' swap' + (applied === 1 ? '' : 's') + '. Use Nitro Type Save Garage only if you want to keep the partial result.', 'warn');
                return;
            }

            currentSource = findSlotByKey(plan.orderedKeys[i]);
            currentTarget = getSlots()[plan.slotIndexes[i]];
            sourceInfo = currentSource ? getCarInfo(currentSource) : null;
            targetInfo = currentTarget ? getCarInfo(currentTarget) : null;

            if (!currentSource || !currentTarget || !sourceInfo || sourceInfo.isEmpty || !targetInfo) {
                state.applying = false;
                state.cancelRequested = false;
                syncApplyButtonState();
                annotateSlots();
                setStatus('Sort stopped: source or target slot changed.', 'bad');
                logWarn('Sort path changed', {
                    plan: plan,
                    index: i,
                    sourceInfo: sourceInfo,
                    targetInfo: targetInfo
                });
                return;
            }

            if (sourceInfo.index === targetInfo.index) continue;

            setStatus('Sorting: moving ' + sourceInfo.name + ' to slot #' + targetInfo.number + '...', 'warn');
            result = await simulateDragDrop(currentSource, currentTarget);
            if (!result.ok) {
                state.applying = false;
                state.cancelRequested = false;
                syncApplyButtonState();
                annotateSlots();
                setStatus('Sort stopped: Nitro Type rejected a swap.', 'bad');
                logWarn('Sort swap failed', {
                    plan: plan,
                    index: i,
                    sourceInfo: sourceInfo,
                    targetInfo: targetInfo,
                    result: result
                });
                return;
            }
            applied += 1;
            await waitForGarageSettled();
        }

        state.applying = false;
        state.cancelRequested = false;
        state.preview = null;
        state.dirty = true;
        syncPreviewPanel('');
        annotateSlots();
        setStatus('Sort applied with ' + applied + ' swaps. Use Nitro Type Save Garage to persist.', 'good');
    }

    async function applyLayoutPreview(preview) {
        var plan = preview && preview.plan;
        var i;
        var desiredKey;
        var currentSource;
        var currentTarget;
        var sourceInfo;
        var targetInfo;
        var result;
        var applied = 0;

        if (!plan) return;

        state.currentActionLabel = (plan.label || 'layout change').toLowerCase();
        state.applying = true;
        state.cancelRequested = false;
        syncApplyButtonState();
        setStatus('Applying ' + plan.label + ' with repeated swaps...', 'warn');
        await waitForGarageSettled();

        for (i = 0; i < plan.desiredKeys.length; i += 1) {
            if (state.cancelRequested) {
                state.applying = false;
                state.cancelRequested = false;
                state.preview = null;
                state.dirty = applied > 0;
                syncPreviewPanel('');
                annotateSlots();
                setStatus(plan.label + ' cancelled after ' + applied + ' swap' + (applied === 1 ? '' : 's') + '. Use Nitro Type Save Garage only if you want to keep the partial result.', 'warn');
                return;
            }

            desiredKey = plan.desiredKeys[i];
            if (!desiredKey) continue;

            currentSource = findSlotByKey(desiredKey);
            currentTarget = getSlots()[i];
            sourceInfo = currentSource ? getCarInfo(currentSource) : null;
            targetInfo = currentTarget ? getCarInfo(currentTarget) : null;

            if (!currentSource || !currentTarget || !sourceInfo || sourceInfo.isEmpty || !targetInfo) {
                state.applying = false;
                state.cancelRequested = false;
                syncApplyButtonState();
                annotateSlots();
                setStatus('Layout stopped: source or target slot changed.', 'bad');
                logWarn('Layout path changed', {
                    plan: plan,
                    index: i,
                    sourceInfo: sourceInfo,
                    targetInfo: targetInfo
                });
                return;
            }

            if (sourceInfo.index === targetInfo.index) continue;

            setStatus(plan.label + ': moving ' + sourceInfo.name + ' to slot #' + targetInfo.number + '...', 'warn');
            result = await simulateDragDrop(currentSource, currentTarget);
            if (!result.ok) {
                state.applying = false;
                state.cancelRequested = false;
                syncApplyButtonState();
                annotateSlots();
                setStatus('Layout stopped: Nitro Type rejected a swap.', 'bad');
                logWarn('Layout swap failed', {
                    plan: plan,
                    index: i,
                    sourceInfo: sourceInfo,
                    targetInfo: targetInfo,
                    result: result
                });
                return;
            }
            applied += 1;
            await waitForGarageSettled();
        }

        state.applying = false;
        state.cancelRequested = false;
        state.preview = null;
        state.dirty = true;
        syncPreviewPanel('');
        annotateSlots();
        setStatus(plan.label + ' applied with ' + applied + ' swaps. Use Nitro Type Save Garage to persist.', 'good');
    }

    async function applyBufferedBlockInsert(plan) {
        var i;
        var currentSource;
        var currentTarget;
        var sourceInfo;
        var targetInfo;
        var result;
        var targetIndex;

        setStatus('Moving selected block to temporary buffer slots...', 'warn');
        for (i = 0; i < plan.selectedKeys.length; i += 1) {
            currentSource = findSlotByKey(plan.selectedKeys[i]);
            currentTarget = getSlots()[plan.bufferIndexes[i]];
            targetInfo = currentTarget ? getCarInfo(currentTarget) : null;

            if (!currentSource || !currentTarget || !targetInfo || !targetInfo.isEmpty) {
                state.applying = false;
                annotateSlots();
                setStatus('Block insert stopped: a buffer slot is no longer empty.', 'bad');
                logWarn('Block insert buffer changed', {
                    plan: plan,
                    bufferIndex: plan.bufferIndexes[i],
                    targetInfo: targetInfo
                });
                return;
            }

            result = await simulateDragDrop(currentSource, currentTarget);
            if (!result.ok) {
                state.applying = false;
                annotateSlots();
                setStatus('Block insert stopped: selected car could not move to a buffer slot.', 'bad');
                logWarn('Block insert buffer move failed', {
                    plan: plan,
                    selectedKey: plan.selectedKeys[i],
                    result: result
                });
                return;
            }
            await waitForGarageSettled();
        }

        if (plan.direction === 'left') {
            for (i = plan.affectedEndIndex; i >= plan.affectedStartIndex; i -= 1) {
                sourceInfo = getSlotInfoAtIndex(i);
                if (!sourceInfo || sourceInfo.isEmpty) continue;

                targetIndex = i + plan.count;
                currentSource = sourceInfo.slot;
                currentTarget = getSlots()[targetIndex];
                targetInfo = currentTarget ? getCarInfo(currentTarget) : null;
                if (!currentTarget || !targetInfo || !targetInfo.isEmpty) {
                    state.applying = false;
                    annotateSlots();
                    setStatus('Block insert stopped: shifted target slot is not empty.', 'bad');
                    logWarn('Block insert right-shift target changed', {
                        plan: plan,
                        sourceInfo: sourceInfo,
                        targetInfo: targetInfo
                    });
                    return;
                }

                setStatus('Shifting slot #' + sourceInfo.number + ' to #' + targetInfo.number + '...', 'warn');
                result = await simulateDragDrop(currentSource, currentTarget);
                if (!result.ok) {
                    state.applying = false;
                    annotateSlots();
                    setStatus('Block insert stopped: Nitro Type rejected a shift move.', 'bad');
                    logWarn('Block insert right-shift failed', {
                        plan: plan,
                        sourceInfo: sourceInfo,
                        result: result
                    });
                    return;
                }
                await waitForGarageSettled();
            }
        } else {
            for (i = plan.affectedStartIndex; i <= plan.affectedEndIndex; i += 1) {
                sourceInfo = getSlotInfoAtIndex(i);
                if (!sourceInfo || sourceInfo.isEmpty) continue;

                targetIndex = i - plan.count;
                currentSource = sourceInfo.slot;
                currentTarget = getSlots()[targetIndex];
                targetInfo = currentTarget ? getCarInfo(currentTarget) : null;
                if (!currentTarget || !targetInfo || !targetInfo.isEmpty) {
                    state.applying = false;
                    annotateSlots();
                    setStatus('Block insert stopped: shifted target slot is not empty.', 'bad');
                    logWarn('Block insert left-shift target changed', {
                        plan: plan,
                        sourceInfo: sourceInfo,
                        targetInfo: targetInfo
                    });
                    return;
                }

                setStatus('Shifting slot #' + sourceInfo.number + ' to #' + targetInfo.number + '...', 'warn');
                result = await simulateDragDrop(currentSource, currentTarget);
                if (!result.ok) {
                    state.applying = false;
                    annotateSlots();
                    setStatus('Block insert stopped: Nitro Type rejected a shift move.', 'bad');
                    logWarn('Block insert left-shift failed', {
                        plan: plan,
                        sourceInfo: sourceInfo,
                        result: result
                    });
                    return;
                }
                await waitForGarageSettled();
            }
        }

        setStatus('Placing selected block into its new slots...', 'warn');
        for (i = 0; i < plan.selectedKeys.length; i += 1) {
            currentSource = findSlotByKey(plan.selectedKeys[i]);
            currentTarget = getSlots()[plan.finalStartIndex + i];
            targetInfo = currentTarget ? getCarInfo(currentTarget) : null;

            if (!currentSource || !currentTarget || !targetInfo || !targetInfo.isEmpty) {
                state.applying = false;
                annotateSlots();
                setStatus('Block insert stopped: final target slot is not empty.', 'bad');
                logWarn('Block insert final target changed', {
                    plan: plan,
                    selectedKey: plan.selectedKeys[i],
                    targetInfo: targetInfo
                });
                return;
            }

            result = await simulateDragDrop(currentSource, currentTarget);
            if (!result.ok) {
                state.applying = false;
                annotateSlots();
                setStatus('Block insert stopped: selected car could not move into final slot.', 'bad');
                logWarn('Block insert final move failed', {
                    plan: plan,
                    selectedKey: plan.selectedKeys[i],
                    result: result
                });
                return;
            }
            await waitForGarageSettled();
        }

        state.applying = false;
        state.preview = null;
        state.dirty = true;
        syncPreviewPanel('');
        annotateSlots();
        setStatus('Selected block inserted. Use Nitro Type Save Garage to persist.', 'good');
    }

    async function applyDirectEmptyBlockMove(plan) {
        var i;
        var currentSource;
        var currentTarget;
        var targetInfo;
        var result;

        setStatus('Moving selected block directly into empty slots...', 'warn');

        for (i = 0; i < plan.selectedKeys.length; i += 1) {
            currentSource = findSlotByKey(plan.selectedKeys[i]);
            currentTarget = getSlots()[plan.finalStartIndex + i];
            targetInfo = currentTarget ? getCarInfo(currentTarget) : null;

            if (!currentSource || !currentTarget || !targetInfo || !targetInfo.isEmpty) {
                state.applying = false;
                annotateSlots();
                setStatus('Direct block move stopped: target slot is no longer empty.', 'bad');
                logWarn('Direct block target changed', {
                    plan: plan,
                    selectedKey: plan.selectedKeys[i],
                    targetInfo: targetInfo
                });
                return;
            }

            setStatus('Moving selected car to slot #' + targetInfo.number + '...', 'warn');
            result = await simulateDragDrop(currentSource, currentTarget);
            if (!result.ok) {
                state.applying = false;
                annotateSlots();
                setStatus('Direct block move stopped: Nitro Type rejected a move.', 'bad');
                logWarn('Direct block move failed', {
                    plan: plan,
                    selectedKey: plan.selectedKeys[i],
                    targetInfo: targetInfo,
                    result: result
                });
                return;
            }
            await waitForGarageSettled();
        }

        state.applying = false;
        state.preview = null;
        state.dirty = true;
        syncPreviewPanel('');
        annotateSlots();
        setStatus('Selected block moved into empty slots. Use Nitro Type Save Garage to persist.', 'good');
    }

    async function applyRangeSwapBlockMove(plan) {
        var i;
        var currentSource;
        var currentTarget;
        var sourceInfo;
        var targetInfo;
        var result;

        setStatus('Swapping selected block with destination range...', 'warn');

        for (i = 0; i < plan.selectedKeys.length; i += 1) {
            currentSource = findSlotByKey(plan.selectedKeys[i]);
            currentTarget = getSlots()[plan.targetIndexes[i]];
            sourceInfo = currentSource ? getCarInfo(currentSource) : null;
            targetInfo = currentTarget ? getCarInfo(currentTarget) : null;

            if (!currentSource || !currentTarget || !sourceInfo || sourceInfo.isEmpty || !targetInfo) {
                state.applying = false;
                annotateSlots();
                setStatus('Range swap stopped: source or destination slot changed.', 'bad');
                logWarn('Range swap path changed', {
                    plan: plan,
                    selectedKey: plan.selectedKeys[i],
                    sourceInfo: sourceInfo,
                    targetInfo: targetInfo
                });
                return;
            }

            setStatus('Swapping slot #' + sourceInfo.number + ' with #' + targetInfo.number + '...', 'warn');
            result = await simulateDragDrop(currentSource, currentTarget);
            if (!result.ok) {
                state.applying = false;
                annotateSlots();
                setStatus('Range swap stopped: Nitro Type rejected a swap.', 'bad');
                logWarn('Range swap move failed', {
                    plan: plan,
                    selectedKey: plan.selectedKeys[i],
                    sourceInfo: sourceInfo,
                    targetInfo: targetInfo,
                    result: result
                });
                return;
            }
            await waitForGarageSettled();
        }

        state.applying = false;
        state.preview = null;
        state.dirty = true;
        syncPreviewPanel('');
        annotateSlots();
        setStatus('Selected block swapped with destination range. Use Nitro Type Save Garage to persist.', 'good');
    }

    async function applyOverlapBlockMove(plan) {
        var i;
        var currentSource;
        var currentTarget;
        var sourceInfo;
        var targetInfo;
        var result;
        var start;
        var end;
        var step;

        setStatus('Sliding selected block to slot #' + plan.targetNumber + '...', 'warn');

        if (plan.direction === 'right') {
            start = plan.selectedKeys.length - 1;
            end = -1;
            step = -1;
        } else {
            start = 0;
            end = plan.selectedKeys.length;
            step = 1;
        }

        for (i = start; i !== end; i += step) {
            currentSource = findSlotByKey(plan.selectedKeys[i]);
            currentTarget = getSlots()[plan.finalStartIndex + i];
            sourceInfo = currentSource ? getCarInfo(currentSource) : null;
            targetInfo = currentTarget ? getCarInfo(currentTarget) : null;

            if (!currentSource || !currentTarget || !sourceInfo || sourceInfo.isEmpty || !targetInfo) {
                state.applying = false;
                annotateSlots();
                setStatus('Block slide stopped: source or destination slot changed.', 'bad');
                logWarn('Block slide path changed', {
                    plan: plan,
                    selectedKey: plan.selectedKeys[i],
                    sourceInfo: sourceInfo,
                    targetInfo: targetInfo
                });
                return;
            }

            if (sourceInfo.index === targetInfo.index) continue;

            setStatus('Sliding slot #' + sourceInfo.number + ' to #' + targetInfo.number + '...', 'warn');
            result = await simulateDragDrop(currentSource, currentTarget);
            if (!result.ok) {
                state.applying = false;
                annotateSlots();
                setStatus('Block slide stopped: Nitro Type rejected a move.', 'bad');
                logWarn('Block slide move failed', {
                    plan: plan,
                    selectedKey: plan.selectedKeys[i],
                    sourceInfo: sourceInfo,
                    targetInfo: targetInfo,
                    result: result
                });
                return;
            }
            await waitForGarageSettled();
        }

        state.applying = false;
        state.preview = null;
        state.dirty = true;
        syncPreviewPanel('');
        annotateSlots();
        setStatus('Selected block moved to start at slot #' + plan.targetNumber + '. Use Nitro Type Save Garage to persist.', 'good');
    }

    async function applyPackedSelectionMove(targetSlot, selectedKeys) {
        var targetInfo = getCarInfo(targetSlot);
        var targetStartIndex = targetInfo ? targetInfo.index : -1;
        var slots = getSlots();
        var i;
        var currentSource;
        var currentTarget;
        var sourceInfo;
        var targetSlotInfo;
        var result;
        var moved = 0;

        if (!targetInfo || targetStartIndex < 0) {
            setStatus('Packed move stopped: no target slot found.', 'bad');
            return;
        }
        if (targetStartIndex + selectedKeys.length > slots.length) {
            setStatus('Packed move needs enough slots after the drop target for all selected cars.', 'warn');
            return;
        }

        state.currentActionLabel = 'packed move';
        state.applying = true;
        syncApplyButtonState();
        setStatus('Packing ' + selectedKeys.length + ' selected cars starting at slot #' + targetInfo.number + '...', 'warn');
        await waitForGarageSettled();

        for (i = 0; i < selectedKeys.length; i += 1) {
            currentSource = findSlotByKey(selectedKeys[i]);
            currentTarget = getSlots()[targetStartIndex + i];
            sourceInfo = currentSource ? getCarInfo(currentSource) : null;
            targetSlotInfo = currentTarget ? getCarInfo(currentTarget) : null;

            if (!currentSource || !currentTarget || !sourceInfo || sourceInfo.isEmpty || !targetSlotInfo) {
                state.applying = false;
                annotateSlots();
                setStatus('Packed move stopped: source or destination slot changed.', 'bad');
                logWarn('Packed selection path changed', {
                    selectedKey: selectedKeys[i],
                    sourceInfo: sourceInfo,
                    targetInfo: targetSlotInfo
                });
                return;
            }

            if (sourceInfo.index === targetSlotInfo.index) continue;

            setStatus('Packing slot #' + sourceInfo.number + ' into #' + targetSlotInfo.number + '...', 'warn');
            result = await simulateDragDrop(currentSource, currentTarget);
            if (!result.ok) {
                state.applying = false;
                annotateSlots();
                setStatus('Packed move stopped: Nitro Type rejected a move.', 'bad');
                logWarn('Packed selection move failed', {
                    selectedKey: selectedKeys[i],
                    sourceInfo: sourceInfo,
                    targetInfo: targetSlotInfo,
                    result: result
                });
                return;
            }
            moved += 1;
            await waitForGarageSettled();
        }

        state.applying = false;
        state.preview = null;
        state.dirty = true;
        syncPreviewPanel('');
        annotateSlots();
        setStatus('Selected cars packed together starting at slot #' + targetInfo.number + '. Use Nitro Type Save Garage to persist.', 'good');
    }

    function buildInsertZoneLayoutPlan(targetIndex, selectedKeys) {
        var slots = getSlots();
        var infos = slots.map(getCarInfo);
        var currentKeys = infos.map(function (info) { return info.key || ''; });
        var existingKeys = {};
        var selectedKeyMap = {};
        var selectedOrderedKeys = [];
        var desiredKeys = currentKeys.slice();
        var changedCount = 0;
        var i;
        var insertOffset;

        function buildDenseInsertFallback() {
            var occupiedIndexes = [];
            var reorderedKeys = [];
            var insertAt = 0;
            var fallbackKeys = Array(currentKeys.length).fill('');
            var slotPosition;

            currentKeys.forEach(function (key, index) {
                if (!key) return;
                occupiedIndexes.push(index);
                if (!selectedKeyMap[key]) {
                    if (index < targetIndex) insertAt += 1;
                    reorderedKeys.push(key);
                }
            });

            reorderedKeys.splice.apply(reorderedKeys, [insertAt, 0].concat(selectedOrderedKeys));
            for (slotPosition = 0; slotPosition < occupiedIndexes.length; slotPosition += 1) {
                fallbackKeys[occupiedIndexes[slotPosition]] = reorderedKeys[slotPosition] || '';
            }
            return fallbackKeys;
        }

        currentKeys.forEach(function (key) {
            if (key) existingKeys[key] = true;
        });

        (selectedKeys || []).forEach(function (key) {
            if (!key || !existingKeys[key] || selectedKeyMap[key]) return;
            selectedKeyMap[key] = true;
            selectedOrderedKeys.push(key);
        });

        targetIndex = parseInt(targetIndex, 10);
        if (isNaN(targetIndex) || targetIndex < 0) targetIndex = 0;

        if (!selectedOrderedKeys.length) {
            return { ok: false, reason: 'Insert stopped: no selected cars were found in the garage.' };
        }

        for (i = 0; i < desiredKeys.length; i += 1) {
            if (desiredKeys[i] && selectedKeyMap[desiredKeys[i]]) {
                desiredKeys[i] = '';
            }
        }

        for (insertOffset = selectedOrderedKeys.length - 1; insertOffset >= 0; insertOffset -= 1) {
            var emptyIndex = -1;
            for (i = targetIndex; i < desiredKeys.length; i += 1) {
                if (!desiredKeys[i]) {
                    emptyIndex = i;
                    break;
                }
            }
            if (emptyIndex === -1) {
                desiredKeys = buildDenseInsertFallback();
                break;
            }
            for (i = emptyIndex; i > targetIndex; i -= 1) {
                desiredKeys[i] = desiredKeys[i - 1];
            }
            desiredKeys[targetIndex] = selectedOrderedKeys[insertOffset];
        }

        for (i = 0; i < currentKeys.length; i += 1) {
            if (currentKeys[i] !== desiredKeys[i]) changedCount += 1;
        }

        if (!changedCount) {
            return { ok: false, reason: 'The selected cars are already inserted at that divider.' };
        }

        return {
            ok: true,
            targetIndex: targetIndex,
            targetNumber: targetIndex + 1,
            selectedKeys: selectedOrderedKeys,
            desiredKeys: desiredKeys,
            changedCount: changedCount
        };
    }

    async function applyInsertZoneMove(targetIndex, selectedKeys) {
        var plan = buildInsertZoneLayoutPlan(targetIndex, selectedKeys);
        var i;
        var desiredKey;
        var currentSource;
        var currentTarget;
        var sourceInfo;
        var targetInfo;
        var result;
        var applied = 0;

        if (!plan.ok) {
            setStatus(plan.reason, 'warn');
            return;
        }

        state.currentActionLabel = 'insert';
        state.applying = true;
        state.cancelRequested = false;
        syncApplyButtonState();
        setStatus('Inserting ' + plan.selectedKeys.length + ' selected cars starting at slot #' + plan.targetNumber + '...', 'warn');
        await waitForGarageSettled();

        for (i = 0; i < plan.desiredKeys.length; i += 1) {
            if (state.cancelRequested) {
                state.applying = false;
                state.cancelRequested = false;
                state.preview = null;
                state.dirty = applied > 0;
                syncPreviewPanel('');
                annotateSlots();
                setStatus('Insert cancelled after ' + applied + ' reflow swap' + (applied === 1 ? '' : 's') + '. Use Nitro Type Save Garage only if you want to keep the partial result.', 'warn');
                return;
            }

            desiredKey = plan.desiredKeys[i];
            if (!desiredKey) continue;

            currentSource = findSlotByKey(desiredKey);
            currentTarget = getSlots()[i];
            sourceInfo = currentSource ? getCarInfo(currentSource) : null;
            targetInfo = currentTarget ? getCarInfo(currentTarget) : null;

            if (!currentSource || !currentTarget || !sourceInfo || sourceInfo.isEmpty || !targetInfo) {
                state.applying = false;
                state.cancelRequested = false;
                syncApplyButtonState();
                annotateSlots();
                setStatus('Insert stopped: source or destination slot changed.', 'bad');
                logWarn('Insert-zone path changed', {
                    plan: plan,
                    index: i,
                    sourceInfo: sourceInfo,
                    targetInfo: targetInfo
                });
                return;
            }

            if (sourceInfo.index === targetInfo.index) continue;

            setStatus('Insert reflow: moving ' + sourceInfo.name + ' to slot #' + targetInfo.number + '...', 'warn');
            result = await simulateDragDrop(currentSource, currentTarget);
            if (!result.ok) {
                state.applying = false;
                state.cancelRequested = false;
                syncApplyButtonState();
                annotateSlots();
                setStatus('Insert stopped: Nitro Type rejected a reflow move.', 'bad');
                logWarn('Insert-zone move failed', {
                    plan: plan,
                    index: i,
                    sourceInfo: sourceInfo,
                    targetInfo: targetInfo,
                    result: result
                });
                return;
            }
            applied += 1;
            await waitForGarageSettled();
        }

        state.applying = false;
        state.cancelRequested = false;
        state.preview = null;
        state.dirty = true;
        syncPreviewPanel('');
        annotateSlots();
        setStatus('Inserted selected cars with ' + applied + ' reflow swaps. Use Nitro Type Save Garage to persist.', 'good');
    }

    function buildInsertZonePreview(targetIndex, selectedKeys) {
        var plan = buildInsertZoneLayoutPlan(targetIndex, selectedKeys);
        var names;

        state.preview = null;
        state.applying = false;
        syncPreviewPanel('');

        if (!plan.ok) {
            setStatus(plan.reason, 'warn');
            return;
        }

        names = plan.selectedKeys.map(function (key) {
            var slot = findSlotByKey(key);
            var info = slot ? getCarInfo(slot) : null;
            return info ? '#' + info.number + ' ' + escapeHtml(info.name) : 'Unknown Car';
        }).join(', ');

        state.preview = {
            type: 'insert-zone',
            plan: plan
        };
        syncPreviewPanel(
            '<strong>Insert preview:</strong> ' + plan.selectedKeys.length + ' selected car' + (plan.selectedKeys.length === 1 ? '' : 's') +
            ' will be packed into the divider at ' + formatSlotLocation(plan.targetIndex) + '. ' +
            'Following cars shift forward and empty slots absorb the movement.<br>' +
            '<strong>Selected:</strong> ' + names + '<br>' +
            'Use Nitro Type <strong>Save Garage</strong> after Apply if the result looks right.'
        );
        setStatus('Insert preview ready. Apply will reflow the selected cars into that divider.', 'warn');
    }

    async function applyAdjacentBlockDrag(targetSlot, sourceKey, allowInsert) {
        var plan = buildAdjacentBlockDragPlan(targetSlot, sourceKey, allowInsert);
        var currentSource;
        var currentTarget;
        var gapInfo;
        var fromIndex;
        var selectedKeyMap = {};
        var fromInfo;
        var targetInfo;
        var result;

        if (!plan.ok) {
            setStatus(plan.reason, 'warn');
            return;
        }

        state.currentActionLabel = allowInsert ? 'block insert' : 'block move';
        state.applying = true;
        syncApplyButtonState();
        setStatus('Moving selected block ' + plan.direction + '...', 'warn');
        await waitForGarageSettled();

        if (plan.mode === 'overlap-move') {
            await applyOverlapBlockMove(plan);
            return;
        }

        if (plan.mode === 'range-swap') {
            await applyRangeSwapBlockMove(plan);
            return;
        }

        if (plan.mode === 'buffered-insert') {
            await applyBufferedBlockInsert(plan);
            return;
        }

        if (plan.mode === 'direct-empty') {
            await applyDirectEmptyBlockMove(plan);
            return;
        }

        plan.selectedKeys.forEach(function (key) {
            selectedKeyMap[key] = true;
        });

        gapInfo = getCarInfo(targetSlot);
        if (!gapInfo || !gapInfo.isEmpty) {
            state.applying = false;
            annotateSlots();
            setStatus('Block move stopped: the drop slot is no longer empty.', 'bad');
            logWarn('Block drag target changed', {
                plan: plan,
                gapInfo: gapInfo
            });
            return;
        }

        while (
            (plan.direction === 'left' && gapInfo.index < plan.lastIndex) ||
            (plan.direction === 'right' && gapInfo.index > plan.firstIndex)
        ) {
            fromIndex = plan.direction === 'left' ? gapInfo.index + 1 : gapInfo.index - 1;
            currentSource = getSlots()[fromIndex];
            currentTarget = gapInfo.slot || getSlots()[gapInfo.index];
            fromInfo = currentSource ? getCarInfo(currentSource) : null;
            targetInfo = currentTarget ? getCarInfo(currentTarget) : null;

            if (!currentSource || !currentTarget || !fromInfo || !targetInfo || !targetInfo.isEmpty || !selectedKeyMap[fromInfo.key]) {
                state.applying = false;
                annotateSlots();
                setStatus('Block move stopped: the selected block path changed while applying.', 'bad');
                logWarn('Block drag path changed', {
                    plan: plan,
                    gapInfo: gapInfo,
                    fromInfo: fromInfo,
                    targetInfo: targetInfo
                });
                return;
            }

            setStatus('Moving slot #' + fromInfo.number + ' to #' + targetInfo.number + '...', 'warn');
            result = await simulateDragDrop(currentSource, currentTarget);
            if (!result.ok) {
                state.applying = false;
                annotateSlots();
                setStatus('Block move stopped: Nitro Type rejected a shift move.', 'bad');
                logWarn('Block drag move failed', {
                    plan: plan,
                    gapInfo: gapInfo,
                    fromInfo: fromInfo,
                    result: result
                });
                return;
            }

            await waitForGarageSettled();
            gapInfo = getSlotInfoAtIndex(fromInfo.index);
            if (!gapInfo || !gapInfo.isEmpty) {
                state.applying = false;
                annotateSlots();
                setStatus('Block move stopped: the empty gap did not advance.', 'bad');
                logWarn('Block drag gap did not advance', {
                    plan: plan,
                    fromInfo: fromInfo,
                    gapInfo: gapInfo,
                    result: result
                });
                return;
            }
        }

        state.applying = false;
        state.preview = null;
        state.dirty = true;
        syncPreviewPanel('');
        annotateSlots();
        setStatus('Selected block moved one slot ' + plan.direction + '. Use Nitro Type Save Garage to persist.', 'good');
    }

    async function applyCurrentPreview() {
        var preview = state.preview;
        var selectedKeys;
        var targetIndex;
        var successCount = 0;
        var moveCancelled = false;
        var i;

        if (!preview || state.applying) return;
        if (preview.type === 'sort') {
            syncApplyButtonState();
            try {
                await applySortPreview(preview);
            } catch (error) {
                state.applying = false;
                state.preview = null;
                syncPreviewPanel('');
                annotateSlots();
                setStatus('Sort stopped: ' + (error && error.message ? error.message : String(error)), 'bad');
                logWarn('Sort apply crashed', error);
            }
            return;
        }
        if (preview.type === 'layout') {
            syncApplyButtonState();
            try {
                await applyLayoutPreview(preview);
            } catch (error) {
                state.applying = false;
                state.preview = null;
                syncPreviewPanel('');
                annotateSlots();
                setStatus('Layout stopped: ' + (error && error.message ? error.message : String(error)), 'bad');
                logWarn('Layout apply crashed', error);
            }
            return;
        }
        if (preview.type === 'insert-zone') {
            syncApplyButtonState();
            try {
                await applyInsertZoneMove(preview.plan.targetIndex, preview.plan.selectedKeys);
            } catch (error) {
                state.applying = false;
                state.preview = null;
                syncPreviewPanel('');
                annotateSlots();
                setStatus('Insert stopped: ' + (error && error.message ? error.message : String(error)), 'bad');
                logWarn('Insert-zone apply crashed', error);
            }
            return;
        }
        if (preview.type === 'insert') {
            syncApplyButtonState();
            try {
                await applyInsertPreview(preview);
            } catch (error) {
                state.applying = false;
                state.preview = null;
                syncPreviewPanel('');
                annotateSlots();
                setStatus('Insert stopped: ' + (error && error.message ? error.message : String(error)), 'bad');
                logWarn('Insert apply crashed', error);
            }
            return;
        }
        if (preview.type === 'block-insert') {
            syncApplyButtonState();
            try {
                await applyAdjacentBlockDrag(getSlots()[preview.targetIndex], preview.sourceKey, preview.allowInsert);
            } catch (error) {
                state.applying = false;
                state.preview = null;
                syncPreviewPanel('');
                annotateSlots();
                setStatus('Block Insert stopped: ' + (error && error.message ? error.message : String(error)), 'bad');
                logWarn('Block insert apply crashed', error);
            }
            return;
        }
        if (preview.type !== 'move') {
            setStatus('Only normal Move To is enabled in this prototype.', 'warn');
            return;
        }

        selectedKeys = preview.selectedKeys.slice();
        targetIndex = preview.targetIndex;
        state.currentActionLabel = 'move';
        state.applying = true;
        state.cancelRequested = false;
        syncApplyButtonState();
        setStatus('Testing synthetic drag/drop...', 'warn');

        for (i = 0; i < selectedKeys.length; i += 1) {
            var currentSource = findSlotByKey(selectedKeys[i]);
            var currentTarget = getSlots()[targetIndex + i];
            var result;

            if (state.cancelRequested) {
                moveCancelled = true;
                setStatus('Move cancelled after ' + successCount + ' move' + (successCount === 1 ? '' : 's') + '. Use Nitro Type Save Garage only if you want to keep the partial result.', 'warn');
                break;
            }

            if (!currentSource || !currentTarget) {
                setStatus('Move stopped: source or target slot disappeared.', 'bad');
                break;
            }

            result = await simulateDragDrop(currentSource, currentTarget);
            if (!result.ok) {
                setStatus('Move did not take. Nitro Type may reject synthetic drag/drop here.', 'bad');
                logWarn('Synthetic move failed', result);
                break;
            }
            successCount += 1;
        }

        state.applying = false;
        state.cancelRequested = false;
        state.preview = null;
        syncPreviewPanel('');
        annotateSlots();

        if (successCount === selectedKeys.length) {
            state.dirty = true;
            setStatus('Move applied in the DOM. Use Nitro Type Save Garage to persist.', 'good');
        } else if (moveCancelled && successCount > 0) {
            state.dirty = true;
        }
    }

    function onDragStart(event) {
        var vehicle = event.target && event.target.closest ? event.target.closest('.garage-vehicle') : null;
        var slot = vehicle && vehicle.closest ? vehicle.closest('.garage-spot') : null;
        var info;
        var selected;
        var selectedRun;
        if (handleCustomizerPoolDragStart(event)) return;
        if (!state.active || state.syntheticDragDepth || state.applying || !slot) return;

        captureUndoSnapshot('manual drag');
        info = getCarInfo(slot);
        selected = getSelectedInfos();
        selectedRun = getSelectedRunForKey(info.key);
        if (info.key && state.selectedKeys[info.key] && selected.length > 1 && !isContiguousInfos(selected)) {
            state.blockDrag = {
                mode: 'packed-selection',
                sourceKey: info.key,
                selectedKeys: selected.map(function (selectedInfo) { return selectedInfo.key; }),
                count: selected.length
            };
            setSourceSlot(slot);
            setStatus('Dragging ' + selected.length + ' selected cars as a packed group. Drop where the line should start.', 'warn');
            return;
        }

        if (info.key && state.selectedKeys[info.key] && selectedRun.length > 1) {
            state.blockDrag = {
                mode: 'selected-run',
                sourceKey: info.key,
                selectedKeys: selectedRun.map(function (selectedInfo) { return selectedInfo.key; }),
                count: selectedRun.length
            };
            setSourceSlot(slot);
            setStatus('Dragging ' + selectedRun.length + ' selected cars as a block. Drop where you want the run inserted.', 'warn');
            return;
        }

        state.blockDrag = info.key ? {
            mode: 'single-insert',
            sourceKey: info.key,
            selectedKeys: [info.key],
            count: 1
        } : null;
        setSourceSlot(slot);
        setStatus('Dragging slot #' + (getSlotIndex(slot) + 1) + '. Drop normally to swap, or use a divider to insert.', 'warn');
    }

    function onDragTarget(event) {
        var eventTarget = event.target;
        var clientX = event.clientX;
        if (handleCustomizerPoolDragTarget(event)) return;
        if (!state.active || state.syntheticDragDepth || state.applying) return;
        if (state.blockDrag) {
            updateInsertTargetFromPoint(eventTarget, clientX);
        } else {
            clearInsertTarget();
        }
        if (state.targetTimer) return;
        state.targetTimer = pageWindow.setTimeout(function () {
            var slot = eventTarget && eventTarget.closest ? eventTarget.closest('.garage-spot') : null;
            state.targetTimer = 0;
            if (slot) {
                setTargetSlot(slot);
            }
        }, 60);
    }

    function onDrop(event) {
        var slot = event.target && event.target.closest ? event.target.closest('.garage-spot') : null;
        var blockDrag;
        var insertTarget;
        var selectedKeys;
        if (handleCustomizerPoolDrop(event)) return;
        if (!state.active || state.syntheticDragDepth) return;

        if (state.blockDrag) {
            blockDrag = state.blockDrag;
            insertTarget = state.insertTarget;
            selectedKeys = blockDrag.selectedKeys || [];
            if (insertTarget && selectedKeys.length) {
                event.preventDefault();
                event.stopPropagation();
                if (typeof event.stopImmediatePropagation === 'function') {
                    event.stopImmediatePropagation();
                }
                state.blockDrag = null;
                clearInsertTarget();
                pageWindow.setTimeout(function () {
                    applyInsertZoneMove(insertTarget.index, selectedKeys).catch(function (error) {
                        state.applying = false;
                        state.cancelRequested = false;
                        syncApplyButtonState();
                        annotateSlots();
                        setStatus('Insert stopped: ' + (error && error.message ? error.message : String(error)), 'bad');
                        logWarn('Insert-zone drag crashed', error);
                    });
                }, 80);
                return;
            }
            if (blockDrag.mode === 'single-insert') {
                state.blockDrag = null;
                clearInsertTarget();
            } else {
                event.preventDefault();
                event.stopPropagation();
                if (typeof event.stopImmediatePropagation === 'function') {
                    event.stopImmediatePropagation();
                }
                state.blockDrag = null;
                clearInsertTarget();
                if (slot) {
                    setTargetSlot(slot);
                    pageWindow.setTimeout(function () {
                        var movePromise = blockDrag.mode === 'packed-selection'
                            ? applyPackedSelectionMove(slot, blockDrag.selectedKeys || [])
                            : applyAdjacentBlockDrag(slot, blockDrag.sourceKey);
                        movePromise.catch(function (error) {
                            state.applying = false;
                            annotateSlots();
                            setStatus('Block move stopped: ' + (error && error.message ? error.message : String(error)), 'bad');
                            logWarn('Block drag crashed', error);
                        });
                    }, 80);
                } else {
                    setStatus('Block move stopped: no target slot found.', 'bad');
                }
                return;
            }
        }

        if (slot) setTargetSlot(slot);
        state.dirty = true;
        setStatus('Dropped. Use Nitro Type Save Garage to persist.', 'good');
        pageWindow.setTimeout(function () {
            clearDragMarks();
            scheduleRefresh();
        }, 300);
    }

    function onDragEnd(event) {
        if (handleCustomizerPoolDragEnd(event)) return;
        if (!state.active || state.syntheticDragDepth) return;
        pageWindow.setTimeout(function () {
            state.blockDrag = null;
            clearInsertTarget();
            clearDragMarks();
            scheduleRefresh();
        }, 200);
    }

    function isCustomizerModal(modal) {
        if (!modal) return false;
        var body = modal.querySelector('#modal-sendcash, .modal-body');
        var text = normalizeText(body && body.textContent).toLowerCase();
        return text.indexOf('customize your car') !== -1 || text.indexOf('nitro type customizer') !== -1;
    }

    function closeCustomizerModal(message) {
        Array.prototype.slice.call(pageDocument.querySelectorAll('.modal.is-active')).forEach(function (modal) {
            if (!isCustomizerModal(modal)) return;
            var closeButton = modal.querySelector('.modal-close');
            if (closeButton) {
                closeButton.click();
            } else {
                modal.remove();
            }
            if (state.active) setStatus(message || 'Customizer popup blocked while rearranging.', 'good');
        });
    }

    function closeRearrangeCustomizerModal() {
        if (!state.active) return;
        closeCustomizerModal('Customizer popup blocked while rearranging.');
    }

    function onGarageClick(event) {
        var vehicle;
        var garage;
        var slot;
        var info;
        var count;
        if (!isToolkitGarageRearrangeEnabled()) return;
        if (event.target && event.target.closest && event.target.closest('.' + SELECT_BUTTON_CLASS + ', .' + TOOLBAR_CLASS)) return;

        vehicle = event.target && event.target.closest ? event.target.closest('.garage-vehicle') : null;
        if (!vehicle) return;
        garage = vehicle.closest ? vehicle.closest('.garage') : null;
        slot = vehicle.closest ? vehicle.closest('.garage-spot') : null;
        if (!garage || !slot) return;

        if (!state.active) {
            if (!isGaragePage() || isRearranging()) return;
            event.preventDefault();
            event.stopPropagation();
            if (typeof event.stopImmediatePropagation === 'function') {
                event.stopImmediatePropagation();
            }
            closeCustomizerModal();
            pageWindow.setTimeout(function () { closeCustomizerModal(); }, 80);
            equipGarageCarFromSlot(slot);
            return;
        }

        if (!garage.classList.contains('is-rearranging')) return;

        event.preventDefault();
        event.stopPropagation();
        if (typeof event.stopImmediatePropagation === 'function') {
            event.stopImmediatePropagation();
        }
        info = getCarInfo(slot);
        if (!info.isEmpty) {
            toggleSelection(info);
            count = getSelectedInfos().length;
            if (count > 1) {
                setStatus(count + ' cars selected. Drag one selected car or choose Move/Arrange.', 'good');
            } else {
                setStatus((state.selectedKeys[info.key] ? 'Selected ' : 'Unselected ') + info.name + '.', 'good');
            }
        } else {
            setStatus('Customizer popup blocked while rearranging.', 'good');
        }
    }

    function bindEvents() {
        pageDocument.addEventListener('pointerdown', onDocumentPointerDown, true);
        pageDocument.addEventListener('pointerdown', handleCustomizerPoolPointerDown, true);
        pageDocument.addEventListener('mousedown', handleCustomizerPoolPointerDown, true);
        pageDocument.addEventListener('click', onGarageClick, true);
        pageDocument.addEventListener('click', handleCustomizerPoolItemEvent, true);
        pageDocument.addEventListener('click', onCustomizerTabClick, true);
        pageDocument.addEventListener('dragstart', onDragStart, true);
        pageDocument.addEventListener('dragenter', onDragTarget, true);
        pageDocument.addEventListener('dragover', onDragTarget, true);
        pageDocument.addEventListener('drop', onDrop, true);
        pageDocument.addEventListener('dragend', onDragEnd, true);
    }

    function unbindEvents() {
        pageDocument.removeEventListener('pointerdown', onDocumentPointerDown, true);
        pageDocument.removeEventListener('pointerdown', handleCustomizerPoolPointerDown, true);
        pageDocument.removeEventListener('mousedown', handleCustomizerPoolPointerDown, true);
        pageDocument.removeEventListener('click', onGarageClick, true);
        pageDocument.removeEventListener('click', handleCustomizerPoolItemEvent, true);
        pageDocument.removeEventListener('click', onCustomizerTabClick, true);
        pageDocument.removeEventListener('dragstart', onDragStart, true);
        pageDocument.removeEventListener('dragenter', onDragTarget, true);
        pageDocument.removeEventListener('dragover', onDragTarget, true);
        pageDocument.removeEventListener('drop', onDrop, true);
        pageDocument.removeEventListener('dragend', onDragEnd, true);
    }

    function getRacerSlugForExport() {
        var match = String(pageWindow.location.pathname || '').match(/^\/racer\/([^/]+)/);
        return match && match[1] ? match[1].replace(/[^a-z0-9_-]+/gi, '-') : 'garage-layout';
    }

    function findGarageActionAnchor() {
        var controls = Array.prototype.slice.call(pageDocument.querySelectorAll('a,button'));
        var rearrange = controls.find(function (node) {
            return normalizeText(node.textContent).toLowerCase().indexOf('rearrange') !== -1;
        });
        if (rearrange) return rearrange;
        return null;
    }

    function findCarsHeaderCell() {
        return Array.prototype.slice.call(pageDocument.querySelectorAll('.split-cell')).find(function (cell) {
            var heading = cell.querySelector('h1,h2,h3');
            return /^(?:My\s+)?Cars(?:\s*\|\s*\d+)?$/i.test(normalizeText(heading && heading.textContent));
        }) || null;
    }

    function ensureProfileExportButton(garage) {
        var existing = pageDocument.querySelector('.' + EXPORT_BUTTON_CLASS);
        var anchor;
        var headerCell;
        var button;
        if (!garage) {
            if (existing) existing.remove();
            return;
        }
        if (existing && existing.isConnected) return;

        headerCell = findCarsHeaderCell();
        anchor = findGarageActionAnchor();
        button = pageDocument.createElement('button');
        button.type = 'button';
        button.className = EXPORT_BUTTON_CLASS;
        button.title = 'Export visible garage layout';
        button.setAttribute('aria-label', 'Export visible garage layout');
        button.innerHTML = '<svg width="296" height="298" viewBox="0 0 296 298" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M122.94 67.8906C125.687 80.7934 131.287 90.9781 139.312 99.0844C149.684 109.561 163.054 115.395 174.89 120.029C177.209 120.938 179.494 121.814 181.74 122.677L181.742 122.677L181.749 122.68C203.696 131.103 222.001 138.128 233.456 159.298L234.766 168.903L185.238 218.432L78.8184 112.012L122.94 67.8906ZM71.7473 119.083L42.0488 148.782C38.1436 152.687 38.1436 159.018 42.0488 162.924L66.7976 187.672L8.99159 245.478C-2.82176 257.292 -2.82177 276.445 8.99159 288.258C20.805 300.072 39.9582 300.072 51.7716 288.258L109.578 230.452L134.326 255.201C138.232 259.106 144.563 259.106 148.468 255.201L178.167 225.503L71.7473 119.083ZM19.775 277.829C26.6091 284.663 37.6895 284.663 44.5237 277.829C51.3579 270.994 51.3579 259.914 44.5237 253.08C37.6895 246.246 26.6091 246.246 19.775 253.08C12.9408 259.914 12.9408 270.994 19.775 277.829Z"></path><path d="M176.206 5.20904L137.797 45.0956C136.002 46.959 134.976 49.5184 135.082 52.1031C137.946 122.171 214.991 94.7163 246.062 153.181C246.687 154.356 247.092 155.673 247.272 156.992L251.312 186.622C252.279 193.713 258.336 199 265.492 199C272.213 199 278.028 194.324 279.47 187.761L294.699 118.468C296.136 111.929 294.207 105.105 289.558 100.287L197.805 5.19812C191.903 -0.918788 182.102 -0.913825 176.206 5.20904Z"></path><circle cx="265" cy="226" r="14"></circle></svg>';
        button.addEventListener('click', function (event) {
            event.preventDefault();
            event.stopPropagation();
            exportLayout(garage, getRacerSlugForExport() + '-garage', true);
        });
        if (headerCell) {
            headerCell.style.display = 'flex';
            headerCell.style.alignItems = 'center';
            button.style.marginLeft = 'auto';
            headerCell.appendChild(button);
        } else if (anchor && anchor.parentNode) {
            anchor.parentNode.insertBefore(button, anchor.nextSibling);
        } else {
            garage.parentNode.insertBefore(button, garage);
        }
    }

    function activate(garage) {
        if (!isToolkitGarageRearrangeEnabled()) return;
        if (state.active && state.garage === garage) {
            if (pageDocument.body) pageDocument.body.classList.add(GARAGE_REARRANGING_BODY_CLASS);
            annotateSlots();
            return;
        }

        state.active = true;
        state.garage = garage;
        if (pageDocument.body) pageDocument.body.classList.add(GARAGE_REARRANGING_BODY_CLASS);
        ensureStyles();
        ensureToolbar();
        annotateSlots();
        setStatus('Rearrange mode active. Select cars or drag normally.', 'good');
        logInfo('Activated garage rearrange helpers.');
    }

    function deactivate() {
        if (!state.active) return;
        state.active = false;
        state.garage = null;
        state.sourceSlot = null;
        state.targetSlot = null;
        state.insertTarget = null;
        state.selectedKeys = {};
        state.focusedSection = null;
        state.blockDrag = null;
        state.preview = null;
        state.dirty = false;
        state.undoHistory = [];
        state.operationUndoCaptured = false;
        state.restoringUndo = false;
        state.currentActionLabel = '';
        stopToolbarDockDrag(false);
        pageWindow.removeEventListener('resize', positionSearchResults);
        pageWindow.removeEventListener('resize', scheduleStatusTooltipSync);
        if (pageDocument.body) pageDocument.body.classList.remove(GARAGE_REARRANGING_BODY_CLASS);
        cleanupSlotHelpers();
        if (state.insertMarker) {
            state.insertMarker.remove();
            state.insertMarker = null;
        }
        if (state.toolbar) {
            state.toolbar.remove();
            state.toolbar = null;
            state.statusNode = null;
            state.searchInput = null;
            state.searchResults = null;
            state.searchMatches = [];
            state.moveInput = null;
            state.moveSectionInput = null;
            state.moveSectionSlotInput = null;
            state.insertInput = null;
            state.sortSelect = null;
            state.sortGapsInput = null;
            state.rangeInput = null;
            state.sectionInput = null;
            state.importFileInput = null;
            state.applyButton = null;
            state.clearButton = null;
            state.undoButton = null;
            state.previewNode = null;
            state.selectionNode = null;
            state.statusTooltipNode = null;
        }
        logInfo('Deactivated garage rearrange helpers.');
    }

    function refresh() {
        var garage;
        state.refreshTimer = 0;

        if (!isGaragePage()) {
            deactivate();
            if (isToolkitCustomizerShuffleEnabled()) {
                ensureCustomizerShuffleControls();
            } else {
                removeCustomizerPoolPreview();
                removeCustomizerShuffleControls();
                if (pageDocument.body) pageDocument.body.classList.remove(SHUFFLE_POOL_MODE_CLASS);
            }
            if (isToolkitGarageRearrangeEnabled() && isRacerProfilePage()) {
                garage = getGarageRoot();
                ensureStyles();
                ensureProfileExportButton(garage);
            } else {
                ensureProfileExportButton(null);
            }
            return;
        }

        garage = getGarageRoot();
        ensureStyles();
        if (isToolkitCustomizerShuffleEnabled()) {
            ensureCustomizerShuffleControls();
        } else {
            removeCustomizerPoolPreview();
            removeCustomizerShuffleControls();
            if (pageDocument.body) pageDocument.body.classList.remove(SHUFFLE_POOL_MODE_CLASS);
        }
        ensureProfileExportButton(isToolkitGarageRearrangeEnabled() && isRacerProfilePage() ? garage : null);
        if (isToolkitGarageRearrangeEnabled() && garage && garage.classList.contains('is-rearranging')) {
            activate(garage);
            closeRearrangeCustomizerModal();
        } else {
            deactivate();
        }
    }

    function scheduleRefresh() {
        if (state.refreshTimer) return;
        state.refreshTimer = pageWindow.setTimeout(refresh, isCustomizerPage() ? 60 : 80);
    }

    function startObserver() {
        if (state.observer || !pageDocument.body) return;
        function isHelperNode(node) {
            return !!(node && node.nodeType === 1 && node.classList && (
                node.classList.contains(SLOT_NUMBER_CLASS) ||
                node.classList.contains(SECTION_LABEL_CLASS) ||
                node.classList.contains(SELECT_BUTTON_CLASS) ||
                node.classList.contains(INSERT_MARKER_CLASS) ||
                node.classList.contains(TOOLBAR_CLASS) ||
                node.classList.contains(SHUFFLE_CONTROLS_CLASS) ||
                node.classList.contains(SHUFFLE_BUTTON_CLASS) ||
                node.classList.contains(SHUFFLE_POOL_BUTTON_CLASS) ||
                node.classList.contains(SHUFFLE_TOGGLE_CLASS) ||
                String(node.className || '').indexOf('ntgo-shuffle') !== -1 ||
                String(node.className || '').indexOf('ntgo-shuffle-pool-preview') !== -1 ||
                node.classList.contains(SHUFFLE_POOL_PREVIEW_CLASS) ||
                node.classList.contains(SHUFFLE_POOL_PREVIEW_GRID_CLASS) ||
                node.classList.contains(SHUFFLE_POOL_PREVIEW_ITEM_CLASS) ||
                node.classList.contains(SHUFFLE_POOL_PREVIEW_EMPTY_CLASS) ||
                node.classList.contains(SHUFFLE_POOL_PREVIEW_REMOVE_CLASS)
            ));
        }
        function isCustomizerRefreshNode(node) {
            if (!node || node.nodeType !== 1 || !node.classList) return false;
            if (isHelperNode(node)) return false;
            if (node.classList.contains('customizer--tooltip')) return false;
            if (
                node.classList.contains('customizer') ||
                node.classList.contains('customizer--tabs') ||
                node.classList.contains('customizer--preview') ||
                node.classList.contains('customizer--previewer') ||
                node.classList.contains('customizer--item-selector') ||
                node.classList.contains('customizer--item-selector-content') ||
                node.classList.contains('customizer--item-selector-container') ||
                node.classList.contains('customizer--item-selector-controls') ||
                node.classList.contains('customizer--item-selector-item') ||
                node.classList.contains('customizer--tab')
            ) {
                return true;
            }
            return !!(node.querySelector && node.querySelector(
                '.customizer,.customizer--tabs,.customizer--preview,.customizer--previewer,.customizer--item-selector,.customizer--item-selector-item'
            ));
        }
        function shouldRefreshForCustomizerMutation(mutation) {
            var target = mutation.target;
            var changed;
            if (mutation.type === 'attributes') {
                if (target && target.closest && target.closest('.customizer--item-selector-item')) return false;
                return isCustomizerRefreshNode(target);
            }
            if (mutation.type !== 'childList') return false;
            changed = Array.prototype.slice.call(mutation.addedNodes || []).concat(Array.prototype.slice.call(mutation.removedNodes || []));
            if (changed.length && changed.every(isHelperNode)) return false;
            if (changed.some(isCustomizerRefreshNode)) return true;
            return isCustomizerRefreshNode(target) && !(target.closest && target.closest('.customizer--item-selector-item'));
        }
        state.observer = new MutationObserver(function (mutations) {
            var shouldRefresh = false;

            mutations.forEach(function (mutation) {
                var target = mutation.target;
                if (shouldRefresh) return;
                if (isCustomizerPage()) {
                    shouldRefresh = shouldRefreshForCustomizerMutation(mutation);
                    return;
                }
                if (mutation.type === 'childList') {
                    var added = Array.prototype.slice.call(mutation.addedNodes || []);
                    var removed = Array.prototype.slice.call(mutation.removedNodes || []);
                    if ((added.length || removed.length) && added.concat(removed).every(isHelperNode)) {
                        return;
                    }
                    shouldRefresh = true;
                    return;
                }
                if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                    if (isHelperNode(target)) return;
                    if (target && target.closest && target.closest('.customizer--item-selector-item')) return;
                    if (target && target.classList && (target.classList.contains('garage') || target.classList.contains('garage-spot') || target.classList.contains('garage-vehicle'))) {
                        shouldRefresh = true;
                    }
                }
            });

            if (shouldRefresh) scheduleRefresh();
        });
        state.observer.observe(pageDocument.body, {
            childList: true,
            subtree: true,
            attributes: true,
            attributeFilter: ['class']
        });
    }

    function stop() {
        state.started = false;
        state.lastSyncPath = '';
        deactivate();
        unbindEvents();
        if (state.observer) {
            state.observer.disconnect();
            state.observer = null;
        }
        if (state.refreshTimer) {
            pageWindow.clearTimeout(state.refreshTimer);
            state.refreshTimer = 0;
        }
        if (state.targetTimer) {
            pageWindow.clearTimeout(state.targetTimer);
            state.targetTimer = 0;
        }
        removeCustomizerShuffleControls();
        if (state.customizerTabSwitchTimer) {
            pageWindow.clearTimeout(state.customizerTabSwitchTimer);
            state.customizerTabSwitchTimer = 0;
        }
        removeCustomizerPoolPreview();
        if (pageDocument.body) pageDocument.body.classList.remove(SHUFFLE_POOL_MODE_CLASS);
        state.customizerPoolMode = false;
        state.customizerPoolType = null;
        stopAutoShuffleSessionWatcher();
    }

    function isToolkitGarageRearrangeEnabled() {
        return typeof readSetting !== 'function' || readSetting('ENABLE_GARAGE_REARRANGE_TOOLS') !== false;
    }

    function isToolkitCustomizerShuffleEnabled() {
        return typeof readSetting !== 'function' || readSetting('ENABLE_CUSTOMIZER_SHUFFLE') !== false;
    }

    function shouldRunToolkitGarageTools() {
        if (isRacePage() || isCustomizerPage()) return isToolkitCustomizerShuffleEnabled();
        if (isRacerProfilePage()) return isToolkitGarageRearrangeEnabled();
        if (isGaragePage()) return isToolkitGarageRearrangeEnabled() || isToolkitCustomizerShuffleEnabled();
        return false;
    }

    function syncDisabledToolkitFeatures() {
        if (!isToolkitCustomizerShuffleEnabled()) {
            state.customizerPoolMode = false;
            state.customizerPoolType = null;
            removeCustomizerPoolPreview();
            removeCustomizerShuffleControls();
            if (pageDocument.body) pageDocument.body.classList.remove(SHUFFLE_POOL_MODE_CLASS);
            stopAutoShuffleSessionWatcher();
        } else {
            syncAutoShuffleSessionWatcher();
        }
        if (!isToolkitGarageRearrangeEnabled()) {
            deactivate();
            ensureProfileExportButton(null);
        }
    }

    function start() {
        var pathKey;
        if (!shouldRunToolkitGarageTools()) {
            stop();
            return false;
        }
        pathKey = getGarageToolsPathKey();
        if (!state.started) {
            state.started = true;
            installDebugVisualHook();
            bindEvents();
            logInfo('Toolkit garage/customizer helpers loaded.');
        }
        state.lastSyncPath = pathKey;
        if (!isRacePage()) startObserver();
        syncDisabledToolkitFeatures();
        refresh();
        return true;
    }

    function sync() {
        var pathKey;
        if (!shouldRunToolkitGarageTools()) {
            stop();
            return false;
        }
        pathKey = getGarageToolsPathKey();
        if (!state.started) return start();
        if (state.lastSyncPath !== pathKey) return start();
        syncDisabledToolkitFeatures();
        if (!isRacePage()) startObserver();
        return true;
    }

    pageWindow[API_KEY] = {
        toolkitOwned: true,
        refresh: refresh,
        start: start,
        sync: sync,
        listSlots: function () {
            return getSlots().map(function (slot) {
                var info = getCarInfo(slot);
                return {
                    slot: info.number,
                    name: info.name,
                    carID: info.carID,
                    carSlug: info.carSlug,
                    empty: info.isEmpty,
                    selected: !!state.selectedKeys[info.key]
                };
            });
        },
        clearSelection: clearSelection,
        getToolbarOrientation: function () {
            return state.toolbarOrientation || readToolbarOrientation();
        },
        setToolbarOrientation: function (orientation) {
            setToolbarOrientation(orientation, { persist: true });
            return state.toolbarOrientation;
        },
        toolbarOrientationStorageKey: TOOLBAR_ORIENTATION_STORAGE_KEY,
        stop: stop
    };

    return pageWindow[API_KEY];

    }());

    function syncGarageToolsFeature() {
        if (!garageToolsModule || typeof garageToolsModule.sync !== 'function') return false;
        try { return garageToolsModule.sync(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'Garage tools error:', e); return false; }
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 7: Car Profile Icon (Global)
    // ─────────────────────────────────────────────────────────────────────────────
    const CAR_ICON_ATTR = 'data-toolkit-car-icon';
    const CAR_DATA_MAP_KEY = 'ntCarDataMap';
    let originalCarIconMarkup = null;

    function cleanupCarIcon() {
        document.querySelectorAll('img[' + CAR_ICON_ATTR + ']').forEach((img) => {
            if (!originalCarIconMarkup) {
                img.removeAttribute(CAR_ICON_ATTR);
                return;
            }
            const template = document.createElement('template');
            template.innerHTML = originalCarIconMarkup.trim();
            const restored = template.content.firstElementChild;
            if (restored) {
                img.replaceWith(restored);
            } else {
                img.removeAttribute(CAR_ICON_ATTR);
            }
        });
    }

    function readCarDataMap() {
        try {
            const cars = pageWindow.NTGLOBALS?.CARS || window.NTGLOBALS?.CARS;
            if (Array.isArray(cars) && cars.length > 0) {
                const fromGlobals = {};
                cars.forEach((car) => {
                    if (car?.carID && car?.options?.smallSrc) {
                        fromGlobals[car.carID] = car.options.smallSrc;
                    }
                });
                if (Object.keys(fromGlobals).length > 0) {
                    localStorage.setItem(CAR_DATA_MAP_KEY, JSON.stringify(fromGlobals));
                    return fromGlobals;
                }
            }
        } catch { /* ignore */ }

        try {
            const raw = localStorage.getItem(CAR_DATA_MAP_KEY);
            if (raw) {
                const parsed = JSON.parse(raw);
                if (parsed && typeof parsed === 'object') {
                    return parsed;
                }
            }
        } catch { /* ignore */ }

        try {
            const bootstrapSrc = document.querySelector('script[src*="/bootstrap.js"]')?.src;
            if (!bootstrapSrc) return null;

            const xhr = new XMLHttpRequest();
            xhr.open('GET', bootstrapSrc, false);
            xhr.send(null);
            if (xhr.status < 200 || xhr.status >= 300 || !xhr.responseText) {
                return null;
            }

            const parsed = {};
            const regex = /"carID":(\d+)[\s\S]{0,700}?"smallSrc":"([^"]+)"/g;
            let match = null;
            while ((match = regex.exec(xhr.responseText)) !== null) {
                parsed[match[1]] = match[2];
            }
            if (Object.keys(parsed).length > 0) {
                localStorage.setItem(CAR_DATA_MAP_KEY, JSON.stringify(parsed));
                return parsed;
            }
        } catch (e) {
            console.warn(TOOLKIT_LOG_PREFIX, 'Car data bootstrap fallback failed:', e?.message || e);
        }

        return null;
    }

    function handleCarIcon() {
        if (!readSetting('ENABLE_CAR_ICON')) return;

        try {
            const persistRaw = localStorage.getItem('persist:nt');
            if (!persistRaw) return;
            const persist = JSON.parse(persistRaw);
            const user = JSON.parse(persist.user);
            const { carID, carHueAngle } = user;
            if (!carID) return;

            const carDataMap = readCarDataMap();
            const smallSrc = carDataMap?.[carID] || carDataMap?.[String(carID)];
            if (!smallSrc) return;

            const carIconUrl = 'https://www.nitrotype.com/cars/' + smallSrc;
            const existingImg = document.querySelector('img[' + CAR_ICON_ATTR + ']');
            if (existingImg) {
                existingImg.src = carIconUrl;
                existingImg.style.filter = 'hue-rotate(' + (carHueAngle || 0) + 'deg)';
                return;
            }

            const icon = document.querySelector('svg.dropdown-accountIcon, .dropdown--account svg.icon-user-s, svg.icon-user-s.dropdown-accountIcon, svg.icon-user-s');
            if (!icon) return;

            originalCarIconMarkup = originalCarIconMarkup || icon.outerHTML;

            const img = document.createElement('img');
            img.src = carIconUrl;
            img.style.height = '18px';
            img.style.width = '18px';
            img.style.filter = 'hue-rotate(' + (carHueAngle || 0) + 'deg)';
            img.style.objectFit = 'contain';
            img.style.verticalAlign = 'middle';
            img.className = icon.getAttribute('class') || '';
            img.setAttribute(CAR_ICON_ATTR, '1');
            icon.replaceWith(img);
        } catch (e) {
            console.error(TOOLKIT_LOG_PREFIX, 'CarIcon error:', e);
        }
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 9: Shop Tomorrow Preview (/shop)
    // ─────────────────────────────────────────────────────────────────────────────
    const SHOP_PREVIEW_ATTR = 'data-toolkit-shop-preview';
    const SHOP_PREVIEW_ROTATION_KEY_ATTR = 'data-toolkit-preview-rotation-key';
    let shopPreviewActive = false;
    let activeShopPreviewCleanup = null;
    let shopPreviewRefreshTimers = [];
    let shopPreviewRepairWaveTimers = [];
    let shopPreviewRolloverTimer = null;
    let shopPreviewSwitchListenerBound = false;
    let shopPreviewReactCtx = null;
    let shopPreviewReactReadyLogged = false;
    let shopPreviewCatalogCache = {
        SHOP: null,
        CARS: null,
        LOOT: null,
        CAR_URL: null
    };

    function getSelectedDealershipKey() {
        const selected = document.querySelector('.page-shop--dealership-option.is-selected');
        if (!selected) return null;
        const extraClass = Array.from(selected.classList).find((cls) => cls !== 'page-shop--dealership-option' && cls !== 'is-selected');
        return extraClass || 'default';
    }

    function getDealershipKeyFromOption(option) {
        if (!option) return null;
        const extraClass = Array.from(option.classList).find((cls) => cls !== 'page-shop--dealership-option' && cls !== 'is-selected');
        return extraClass || 'default';
    }

    function updateShopPreviewCatalogCache(pw) {
        const globals = pw?.NTGLOBALS;
        if (!globals) return;

        if (Array.isArray(globals.SHOP) && globals.SHOP.length) {
            shopPreviewCatalogCache.SHOP = globals.SHOP;
        }
        if (Array.isArray(globals.CARS) && globals.CARS.length) {
            shopPreviewCatalogCache.CARS = globals.CARS;
        }
        if (Array.isArray(globals.LOOT) && globals.LOOT.length) {
            shopPreviewCatalogCache.LOOT = globals.LOOT;
        }
        if (typeof globals.CAR_URL === 'string' && globals.CAR_URL.trim()) {
            shopPreviewCatalogCache.CAR_URL = globals.CAR_URL;
        }
    }

    function cleanupShopPreview() {
        clearShopPreviewRolloverTimer();
        try {
            if (typeof activeShopPreviewCleanup === 'function') {
                activeShopPreviewCleanup();
                activeShopPreviewCleanup = null;
            }
        } catch (e) {
            console.warn(TOOLKIT_LOG_PREFIX, 'Shop preview cleanup error:', e?.message || e);
        }
        shopPreviewActive = false;
        document.querySelectorAll('[' + SHOP_PREVIEW_ATTR + '="items"], [' + SHOP_PREVIEW_ATTR + '="toggle"]').forEach((node) => node.remove());
        document.querySelectorAll('.page-shop--product-list').forEach((list) => {
            list.style.display = '';
        });
        document.querySelectorAll('.page-shop--time-remaining[data-toolkit-original-time-html]').forEach((node) => {
            node.innerHTML = node.dataset.toolkitOriginalTimeHtml || '';
            delete node.dataset.toolkitOriginalTimeHtml;
        });
        document.querySelectorAll('.page-shop--category[data-toolkit-preview-layout="1"]').forEach((node) => {
            node.style.display = '';
            node.style.alignItems = '';
            node.style.flexWrap = '';
            delete node.dataset.toolkitPreviewLayout;
        });
    }

    function clearShopPreviewRefreshTimers() {
        shopPreviewRefreshTimers.forEach((timer) => clearTimeout(timer));
        shopPreviewRefreshTimers = [];
    }

    function clearShopPreviewRepairWaveTimers() {
        shopPreviewRepairWaveTimers.forEach((timer) => clearTimeout(timer));
        shopPreviewRepairWaveTimers = [];
    }

    function clearShopPreviewRolloverTimer() {
        if (!shopPreviewRolloverTimer) return;
        clearTimeout(shopPreviewRolloverTimer);
        shopPreviewRolloverTimer = null;
    }

    function buildShopPreviewRotationKey(nextFeatured, nextDaily) {
        return [
            Number(nextFeatured?.startStamp || 0),
            Number(nextDaily?.startStamp || 0)
        ].join(':');
    }

    function scheduleShopPreviewRolloverRefresh(nextFeatured, nextDaily) {
        clearShopPreviewRolloverTimer();

        const now = Math.floor(Date.now() / 1000);
        const nextStartStamp = [nextFeatured?.startStamp, nextDaily?.startStamp]
            .map((stamp) => Number(stamp || 0))
            .filter((stamp) => Number.isFinite(stamp) && stamp > now)
            .sort((a, b) => a - b)[0];

        if (!nextStartStamp) return;

        const delayMs = Math.max(1000, ((nextStartStamp - now) * 1000) + 1500);
        shopPreviewRolloverTimer = setTimeout(() => {
            shopPreviewRolloverTimer = null;
            if (normalizePath(window.location.pathname) !== '/shop') return;
            if (!isFeatureEnabled('ENABLE_SHOP_LEAKS')) return;

            try {
                cleanupShopPreview();
                scheduleShopPreviewRefresh();
            } catch (e) {
                console.warn(TOOLKIT_LOG_PREFIX, 'Shop preview rollover refresh error:', e?.message || e);
            }

            const reloadFallbackTimer = setTimeout(() => {
                if (normalizePath(window.location.pathname) !== '/shop') return;
                if (!isFeatureEnabled('ENABLE_SHOP_LEAKS')) return;
                if (document.querySelector('[' + SHOP_PREVIEW_ATTR + '="toggle"]')) return;
                window.location.reload();
            }, 1500);
            shopPreviewRefreshTimers.push(reloadFallbackTimer);
        }, delayMs);
    }

    function scheduleShopPreviewRefresh(expectedDealershipKey = null) {
        clearShopPreviewRefreshTimers();
        let attempts = 0;
        const maxAttempts = 24;
        const runRefresh = () => {
            attempts++;
            try {
                cleanupShopPreview();
                handleShopPreview();
            } catch (e) {
                console.warn(TOOLKIT_LOG_PREFIX, 'Shop preview refresh error:', e?.message || e);
            }

            const selectedDealership = getSelectedDealershipKey();
            const hasFeaturedSection = !!document.querySelector('.page-shop--featured-products');
            const hasToggle = !!document.querySelector('[' + SHOP_PREVIEW_ATTR + '="toggle"]');
            let refreshComplete = attempts >= maxAttempts;
            if (!refreshComplete && expectedDealershipKey === 'default') {
                refreshComplete = selectedDealership === 'default' && hasFeaturedSection && hasToggle;
            } else if (!refreshComplete && expectedDealershipKey && expectedDealershipKey !== 'default') {
                refreshComplete = selectedDealership === expectedDealershipKey;
            } else if (!refreshComplete) {
                refreshComplete = (
                    (selectedDealership !== null && selectedDealership !== 'default')
                    || (selectedDealership === 'default' && hasFeaturedSection && hasToggle)
                );
            }
            if (refreshComplete) {
                clearShopPreviewRepairWaveTimers();
                return;
            }

            const timer = setTimeout(runRefresh, 45);
            shopPreviewRefreshTimers.push(timer);
        };

        runRefresh();
    }

    function scheduleShopPreviewRepairWave(expectedDealershipKey = null) {
        clearShopPreviewRepairWaveTimers();
        const delays = expectedDealershipKey === 'default'
            ? [60, 220, 500, 900, 1500]
            : [60, 220];

        delays.forEach((delay) => {
            const timer = setTimeout(() => {
                if (normalizePath(window.location.pathname) !== '/shop') return;
                if (!isFeatureEnabled('ENABLE_SHOP_LEAKS')) return;
                scheduleShopPreviewRefresh(expectedDealershipKey);
            }, delay);
            shopPreviewRepairWaveTimers.push(timer);
        });
    }

    function bindShopPreviewSwitchListener() {
        if (shopPreviewSwitchListenerBound) return;
        shopPreviewSwitchListenerBound = true;
        document.addEventListener('click', (e) => {
            const option = e.target?.closest?.('.page-shop--dealership-option');
            if (!option) return;
            if (normalizePath(window.location.pathname) !== '/shop') return;
            if (!isFeatureEnabled('ENABLE_SHOP_LEAKS')) return;
            const expectedDealershipKey = getDealershipKeyFromOption(option);
            scheduleShopPreviewRepairWave(expectedDealershipKey);
        }, true);
    }

    /**
     * Extract React internals from Nitro Type's bundled code for animated previews.
     * Returns { React, ReactDOM, CarComponent, TrailComponent, getCarUrl, getCarMetaData, getLootMetaData, playerCar }
     * or null if extraction fails.
     */
    function extractReactInternals(pw) {
        // 1. React & ReactDOM from webpack
        let React = null, ReactDOM = null;
        try {
            const moduleId = '__ntk_react_' + Date.now();
            pw.webpackJsonp.push([[moduleId], {
                [moduleId]: function (m, e, req) {
                    for (const id of Object.keys(req.m)) {
                        try {
                            const mod = req(id);
                            if (mod?.createElement && mod?.Component && !React) React = mod;
                            if (mod?.render && mod?.createPortal && !ReactDOM) ReactDOM = mod;
                        } catch (ex) { /* skip */ }
                    }
                }
            }, [[moduleId]]]);
        } catch (e) {
            console.warn(TOOLKIT_LOG_PREFIX, 'webpackJsonp extraction failed:', e.message);
            return null;
        }
        if (!React || !ReactDOM) return null;

        // 2. Walk React fiber to find components and helper functions
        let CarComponent = null, TrailComponent = null;
        let getCarUrl = null, getCarMetaData = null, getLootMetaData = null;

        function getComponentFromSelector(selector) {
            const canvas = document.querySelector(selector);
            if (!canvas) return null;
            const container = canvas.closest('.animated-car-preview') || canvas.closest('.animated-asset-preview') || canvas.parentElement;
            if (!container) return null;
            const fk = Object.keys(container).find(k => k.startsWith('__reactFiber'));
            if (!fk) return null;
            let node = container[fk];
            while (node && !(node.type && typeof node.type === 'function')) node = node.return;
            return node;
        }

        // Extract CarComponent
        const carNode = getComponentFromSelector('.animated-car-preview canvas');
        if (carNode) {
            CarComponent = carNode.type;
            // Walk up to find shop-level helper props
            let sn = carNode;
            while (sn) {
                if (sn.memoizedProps?.getCarMetaData) {
                    getCarMetaData = sn.memoizedProps.getCarMetaData;
                    getLootMetaData = sn.memoizedProps.getLootMetaData;
                    if (sn.memoizedProps.getCarUrl) getCarUrl = sn.memoizedProps.getCarUrl;
                    break;
                }
                if (sn.memoizedProps?.getCarUrl && !getCarUrl) getCarUrl = sn.memoizedProps.getCarUrl;
                sn = sn.return;
            }
        }

        // Extract TrailComponent
        const trailNode = getComponentFromSelector('.animated-asset-preview canvas');
        if (trailNode) {
            TrailComponent = trailNode.type;
            if (!getCarUrl && trailNode.memoizedProps?.getCarUrl) getCarUrl = trailNode.memoizedProps.getCarUrl;
        }

        if (!getCarUrl || !getCarMetaData) return null;

        // 3. Build playerCar data for trail previews (user's currently equipped car)
        let playerCar = null;
        try {
            const persist = JSON.parse(localStorage.getItem('persist:nt'));
            const user = JSON.parse(persist.user);
            const carID = user.carID;
            const hue = user.carHueAngle || 0;
            const meta = getCarMetaData(carID);
            if (meta) {
                playerCar = {
                    id: carID, hue,
                    rarity: meta.rarity,
                    largeSrc: meta.largeSrc,
                    smallSrc: meta.smallSrc,
                    assetKey: meta.assetKey,
                    goldOnly: meta.goldOnly || false
                };
            }
        } catch { /* ignore */ }

        // 4. Inject CSS for animated preview containers
        if (!document.getElementById('ntk-anim-preview-css')) {
            const style = document.createElement('style');
            style.id = 'ntk-anim-preview-css';
            style.textContent = `.ntk-anim-mount .animated-car-preview, .ntk-anim-mount .animated-asset-preview { width: 100%; height: 100%; }`;
            document.head.appendChild(style);
        }

        if (!shopPreviewReactReadyLogged) {
            console.info(TOOLKIT_LOG_PREFIX, 'Animated previews ready:', { car: !!CarComponent, trail: !!TrailComponent });
            shopPreviewReactReadyLogged = true;
        }
        return { React, ReactDOM, CarComponent, TrailComponent, getCarUrl, getCarMetaData, getLootMetaData, playerCar };
    }

    function getShopPreviewReactContext(pw) {
        if (shopPreviewReactCtx) return shopPreviewReactCtx;
        const ctx = extractReactInternals(pw);
        if (ctx) shopPreviewReactCtx = ctx;
        return ctx;
    }

    function handleShopPreview() {
        if (!isFeatureEnabled('ENABLE_SHOP_LEAKS')) return;
        if (normalizePath(window.location.pathname) !== '/shop') return;

        bindShopPreviewSwitchListener();

        const selectedDealership = getSelectedDealershipKey();
        const isDailyDealership = selectedDealership === 'default';
        const featuredSection = document.querySelector('.page-shop--featured-products');
        const selectedDealershipContainer = document.querySelector('.page-shop--selected-dealership');

        if (!isDailyDealership || !featuredSection || !selectedDealershipContainer) {
            clearShopPreviewRolloverTimer();
            if (document.querySelector('[' + SHOP_PREVIEW_ATTR + ']') || activeShopPreviewCleanup) {
                cleanupShopPreview();
            }
            return;
        }

        const pw = (typeof unsafeWindow !== 'undefined' && unsafeWindow) ? unsafeWindow : window;
        updateShopPreviewCatalogCache(pw);
        const SHOP = (Array.isArray(pw.NTGLOBALS?.SHOP) && pw.NTGLOBALS.SHOP.length ? pw.NTGLOBALS.SHOP : shopPreviewCatalogCache.SHOP);
        const CARS = (Array.isArray(pw.NTGLOBALS?.CARS) && pw.NTGLOBALS.CARS.length ? pw.NTGLOBALS.CARS : shopPreviewCatalogCache.CARS);
        const LOOT = (Array.isArray(pw.NTGLOBALS?.LOOT) && pw.NTGLOBALS.LOOT.length ? pw.NTGLOBALS.LOOT : shopPreviewCatalogCache.LOOT);
        const CAR_URL = pw.NTGLOBALS?.CAR_URL || shopPreviewCatalogCache.CAR_URL || '/cars/';
        if (!SHOP || !CARS || !LOOT) return;

        const now = Math.floor(Date.now() / 1000);

        // Find next rotations (startStamp in the future)
        const nextFeatured = SHOP.find(r => r.category === 'featured' && r.startStamp > now);
        const nextDaily = SHOP.find(r => r.category === 'daily1' && r.startStamp > now);
        if (!nextFeatured && !nextDaily) {
            clearShopPreviewRolloverTimer();
            return;
        }

        const currentRotationKey = buildShopPreviewRotationKey(nextFeatured, nextDaily);
        scheduleShopPreviewRolloverRefresh(nextFeatured, nextDaily);

        const existingToggle = document.querySelector('[' + SHOP_PREVIEW_ATTR + '="toggle"]');
        const existingPreview = document.querySelector('[' + SHOP_PREVIEW_ATTR + '="items"]');
        const toggleBelongsToCurrentDailyView = !!(existingToggle && selectedDealershipContainer.contains(existingToggle));
        const previewBelongsToCurrentDailyView = !!(existingPreview && selectedDealershipContainer.contains(existingPreview));
        const toggleRotationKeyMatches = !!(existingToggle && existingToggle.getAttribute(SHOP_PREVIEW_ROTATION_KEY_ATTR) === currentRotationKey);

        if ((existingToggle && !toggleBelongsToCurrentDailyView) || (existingPreview && !previewBelongsToCurrentDailyView)) {
            cleanupShopPreview();
        } else if (toggleBelongsToCurrentDailyView && toggleRotationKeyMatches) {
            return;
        }
        if (toggleBelongsToCurrentDailyView && !toggleRotationKeyMatches) {
            cleanupShopPreview();
        }

        // Animated preview helpers are resolved lazily when the preview is opened.
        let reactCtx = null;

        // Track mounted React roots for cleanup
        const mountedRoots = [];

        // User inventory for ownership badges
        let ownedCarIDs = new Set();
        let ownedLootIDs = new Set();
        try {
            const persist = JSON.parse(localStorage.getItem('persist:nt'));
            const user = JSON.parse(persist.user);
            if (user.cars) user.cars.forEach(c => ownedCarIDs.add(c[0]));
            if (user.loot) user.loot.forEach(l => ownedLootIDs.add(l.lootID));
        } catch { /* ignore */ }

        // Resolve item metadata from NTGLOBALS
        function resolveItem(shopItem) {
            const { type, id, price } = shopItem;
            if (type === 'car') {
                const car = CARS.find(c => c.carID === id);
                if (!car) return null;
                return {
                    type: 'car',
                    typeName: car.name,
                    name: car.name,
                    price: price ?? car.price ?? null,
                    rarity: car.options?.rarity || 'common',
                    imgSrc: CAR_URL + car.options?.largeSrc,
                    isAnimated: !!car.options?.isAnimated,
                    assetKey: car.options?.assetKey,
                    carID: id,
                    owned: ownedCarIDs.has(id)
                };
            }
            const loot = LOOT.find(l => l.lootID === id);
            if (!loot) return null;
            const lootType = loot.type || 'loot';
            // Animated loot types: trail, nametag, nitro — assetKey is top-level on the loot object
            const isAnimatedLoot = (lootType === 'trail' || lootType === 'nametag' || lootType === 'nitro') && !!loot.assetKey;
            return {
                type: lootType,
                typeName: lootType.toUpperCase(),
                name: loot.name,
                price: price ?? loot.price ?? null,
                rarity: loot.options?.rarity || 'common',
                imgSrc: loot.options?.src || null,
                animationPath: isAnimatedLoot ? loot.assetKey : null,
                animMode: lootType === 'trail' ? 'trail-preview' : lootType === 'nametag' ? 'nametag-preview' : lootType === 'nitro' ? 'nitro-preview' : null,
                lootID: id,
                owned: ownedLootIDs.has(id)
            };
        }

        // Format price with commas
        function formatPrice(price) {
            if (price == null) return null;
            return '$' + Number(price).toLocaleString();
        }

        // Build a single item card matching NT's DOM structure
        function buildItemCard(item, isFeatured) {
            const card = document.createElement('div');
            card.className = `page-shop--product type--${item.type}${isFeatured ? ' is-featured' : ''}${item.owned ? ' is-owned' : ''}`;

            let previewHtml = '';
            const useAnimCar = item.type === 'car' && item.isAnimated && reactCtx;
            const useAnimLoot = item.animationPath && item.animMode && reactCtx;

            if (item.type === 'title') {
                previewHtml = `
                    <div class="page-shop--product--preview">
                        <div class="title-wrapper">
                            <div class="title-label">
                                <div style="height: 38px;">
                                    <div class="page-shop--product--name" style="white-space: nowrap; position: absolute; transform: translate(-50%, 0px) scale(1, 1); left: 50%;">
                                        <span class="quote">"</span>${item.name}<span class="quote">"</span>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>`;
            } else if (useAnimCar) {
                // Animated car — mount point for React component
                previewHtml = `
                    <div class="page-shop--product--preview">
                        <div class="ntk-anim-mount" data-ntk-anim="car" data-ntk-car-id="${item.carID}" style="width:100%; height:180px;"></div>
                    </div>`;
            } else if (useAnimLoot) {
                // Animated loot (trail, nametag, nitro) — mount point for React component
                previewHtml = `
                    <div class="page-shop--product--preview">
                        <div class="ntk-anim-mount" data-ntk-anim="loot" data-ntk-path="${item.animationPath}" data-ntk-mode="${item.animMode}" style="width:100%; height:180px;"></div>
                    </div>`;
            } else if (item.type === 'car' && item.imgSrc) {
                previewHtml = `
                    <div class="page-shop--product--preview">
                        <div class="vehicle-wrapper">
                            <img src="${item.imgSrc}" style="max-width:100%; max-height:200px; object-fit:contain;" alt="${item.name}" loading="lazy">
                        </div>
                    </div>`;
            } else if (item.imgSrc) {
                previewHtml = `
                    <div class="page-shop--product--preview">
                        <div style="display:flex; align-items:center; justify-content:center; width:100%; min-height:140px; padding:12px;">
                            <img src="${item.imgSrc}" style="max-width:100%; max-height:200px; object-fit:contain;" alt="${item.name}" loading="lazy">
                        </div>
                    </div>`;
            }

            const priceHtml = formatPrice(item.price)
                ? `<div class="page-shop--product--price"><span class="as-nitro-cash--prefix">${formatPrice(item.price)}</span></div>`
                : `<div class="page-shop--product--price" style="opacity:0.5; font-style:italic; font-size:12px;">Price TBD</div>`;

            card.innerHTML = `
                <div class="page-shop--product--content">
                    <div class="rarity-frame rarity-frame--${item.rarity}">
                        <div class="rarity-frame--extra"></div>
                        <div class="rarity-frame--content">
                            <div class="page-shop--product--container">
                                ${item.owned ? '<div class="page-shop--owned">Owned</div>' : ''}
                                ${previewHtml}
                                <div class="page-shop--product--details">
                                    <div class="page-shop--product--type">${item.name}</div>
                                    ${priceHtml}
                                </div>
                            </div>
                        </div>
                    </div>
                </div>`;
            return card;
        }

        // Mount animated previews into DOM-attached mount points
        function mountAnimations(listEl) {
            if (!reactCtx) return;
            const { React, ReactDOM, CarComponent, TrailComponent, getCarUrl, getCarMetaData, playerCar } = reactCtx;

            listEl.querySelectorAll('.ntk-anim-mount').forEach(mount => {
                const animType = mount.dataset.ntkAnim;
                try {
                    if (animType === 'car' && CarComponent) {
                        const carID = parseInt(mount.dataset.ntkCarId);
                        const meta = getCarMetaData(carID);
                        if (!meta) return;
                        ReactDOM.render(
                            React.createElement(CarComponent, {
                                carID, hue: 0,
                                getCarUrl, getCarMetaData, metaData: meta,
                                animate: true, scale: 0.85,
                                transparent: true, backgroundColor: 0,
                                useWebGL: true, offsetX: 0, offsetY: 0
                            }),
                            mount
                        );
                        mountedRoots.push(mount);
                    } else if (animType === 'loot' && TrailComponent) {
                        const path = mount.dataset.ntkPath;
                        const mode = mount.dataset.ntkMode;
                        if (!path || !mode) return;
                        ReactDOM.render(
                            React.createElement(TrailComponent, {
                                mode, path, scale: 1.33,
                                getCarUrl, playerCar,
                                transparent: true, useWebGL: false,
                                options: { hideBackground: true },
                                backgroundColor: 0, animate: true
                            }),
                            mount
                        );
                        mountedRoots.push(mount);
                    }
                } catch (e) {
                    console.warn(TOOLKIT_LOG_PREFIX, 'Anim mount failed:', animType, e.message);
                }
            });
        }

        // Unmount all animated React roots
        function unmountAnimations() {
            if (!reactCtx) return;
            mountedRoots.forEach(mount => {
                try { reactCtx.ReactDOM.unmountComponentAtNode(mount); } catch (e) { /* ignore */ }
            });
            mountedRoots.length = 0;
        }

        // Build a product list container with item cards
        function buildProductList(rotation, isFeatured) {
            const list = document.createElement('div');
            list.className = 'page-shop--product-list';
            list.setAttribute(SHOP_PREVIEW_ATTR, 'items');
            if (!rotation || !rotation.items.length) {
                list.innerHTML = '<div style="color:#8a8ea0; text-align:center; padding:24px; font-size:14px;">No items available for preview.</div>';
                return list;
            }
            rotation.items.forEach(shopItem => {
                const item = resolveItem(shopItem);
                if (item) list.appendChild(buildItemCard(item, isFeatured));
            });
            return list;
        }

        // Format a countdown string from seconds
        function formatCountdown(seconds) {
            if (seconds <= 0) return 'now';
            const h = Math.floor(seconds / 3600);
            const m = Math.floor((seconds % 3600) / 60);
            const s = seconds % 60;
            const parts = [];
            if (h > 0) parts.push(h + (h === 1 ? ' hour' : ' hours'));
            if (m > 0) parts.push(m + (m === 1 ? ' minute' : ' minutes'));
            if (s > 0 || parts.length === 0) parts.push(s + (s === 1 ? ' second' : ' seconds'));
            return parts.join(', ');
        }

        // Find the product sections by their header text (search all shop sections, not just one container)
        const productSections = document.querySelectorAll('.page-shop--products');
        const sections = [];

        productSections.forEach(sec => {
            const nameEl = sec.querySelector('.page-shop--category--name');
            const productList = sec.querySelector('.page-shop--product-list');
            const timeEl = sec.querySelector('.page-shop--time-remaining');
            if (!nameEl || !productList) return;

            const name = nameEl.textContent.trim();
            const isFeatured = name.includes('Featured');
            const nextRotation = isFeatured ? nextFeatured : nextDaily;

            sections.push({
                container: sec,
                nameEl,
                productList,
                timeEl,
                isFeatured,
                nextRotation,
                originalName: name
            });
        });

        if (sections.length === 0) return;

        // Create toggle button
        const btn = document.createElement('button');
        btn.setAttribute(SHOP_PREVIEW_ATTR, 'toggle');
        btn.setAttribute(SHOP_PREVIEW_ROTATION_KEY_ATTR, currentRotationKey);
        btn.textContent = 'Show Tomorrow';
        btn.style.cssText = `
            background: #2D8050;
            color: #fff;
            border: none;
            border-radius: 4px;
            padding: 8px 16px;
            font-size: 14px;
            font-weight: 600;
            font-family: "Montserrat", sans-serif;
            cursor: pointer;
            margin-left: auto;
            transition: all 0.25s ease-in-out;
            white-space: nowrap;
            line-height: 1;
            box-shadow: 0 2px 0 #1e5c38, 0 3px 6px rgba(0,0,0,0.3);
        `;
        btn.addEventListener('mouseenter', () => { btn.style.opacity = '0.85'; });
        btn.addEventListener('mouseleave', () => { btn.style.opacity = '1'; });
        btn.addEventListener('mousedown', () => { btn.style.transform = 'scale(0.97)'; });
        btn.addEventListener('mouseup', () => { btn.style.transform = 'scale(1)'; });

        // Insert button into the first section's category header
        const firstCategory = sections[0].container.querySelector('.page-shop--category');
        if (firstCategory) {
            firstCategory.dataset.toolkitPreviewLayout = '1';
            firstCategory.style.display = 'flex';
            firstCategory.style.alignItems = 'center';
            firstCategory.style.flexWrap = 'wrap';
            firstCategory.appendChild(btn);
        }

        activeShopPreviewCleanup = () => {
            unmountAnimations();
            shopPreviewActive = false;
            sections.forEach((sec) => {
                sec.productList.style.display = '';
                const preview = sec.container.querySelector('[' + SHOP_PREVIEW_ATTR + '="items"]');
                if (preview) preview.remove();
                if (sec.timeEl && sec._originalTimeHtml) {
                    sec.timeEl.innerHTML = sec._originalTimeHtml;
                }
            });
            if (firstCategory) {
                firstCategory.style.display = '';
                firstCategory.style.alignItems = '';
                firstCategory.style.flexWrap = '';
                delete firstCategory.dataset.toolkitPreviewLayout;
            }
            btn.remove();
        };

        // Toggle handler
        btn.addEventListener('click', () => {
            clearShopPreviewRepairWaveTimers();
            clearShopPreviewRefreshTimers();
            shopPreviewActive = !shopPreviewActive;

            if (shopPreviewActive && !reactCtx) {
                try {
                    reactCtx = getShopPreviewReactContext(pw);
                } catch (e) {
                    console.warn(TOOLKIT_LOG_PREFIX, 'Animated previews unavailable:', e.message);
                }
            }

            sections.forEach(sec => {
                if (shopPreviewActive) {
                    // Hide original, show tomorrow's items
                    sec.productList.style.display = 'none';
                    const existing = sec.container.querySelector('[' + SHOP_PREVIEW_ATTR + '="items"]');
                    if (existing) existing.remove();
                    const tomorrowList = buildProductList(sec.nextRotation, sec.isFeatured);
                    sec.productList.parentNode.insertBefore(tomorrowList, sec.productList.nextSibling);

                    // Mount animated previews now that list is in the DOM
                    mountAnimations(tomorrowList);

                    // Update countdown to show when tomorrow's items go live
                    if (sec.timeEl && sec.nextRotation) {
                        sec._originalTimeHtml = sec.timeEl.innerHTML;
                        const secsUntil = sec.nextRotation.startStamp - Math.floor(Date.now() / 1000);
                        sec.timeEl.innerHTML = `<svg class="icon icon-time"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/site/images/icons/icons.css.svg#icon-time"></use></svg>Goes live in ${formatCountdown(Math.max(0, secsUntil))}`;
                    }
                } else {
                    // Unmount animated previews before removing DOM
                    unmountAnimations();

                    // Restore original
                    sec.productList.style.display = '';
                    const preview = sec.container.querySelector('[' + SHOP_PREVIEW_ATTR + '="items"]');
                    if (preview) preview.remove();

                    if (sec.timeEl && sec._originalTimeHtml) {
                        sec.timeEl.innerHTML = sec._originalTimeHtml;
                    }
                }
            });

            btn.textContent = shopPreviewActive ? 'Show Today' : 'Show Tomorrow';
            btn.style.background = shopPreviewActive ? '#e67e22' : '#2D8050';
            btn.style.boxShadow = shopPreviewActive
                ? '0 2px 0 #b35a10, 0 3px 6px rgba(0,0,0,0.3)'
                : '0 2px 0 #1e5c38, 0 3px 6px rgba(0,0,0,0.3)';
        });
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 11: Garage Expansion (/garage)
    // ─────────────────────────────────────────────────────────────────────────────
    const GARAGE_EXPANSION_ATTR = 'data-ntk-garage-expansion';
    let garageExpansionRetryTimer = null;
    let garageExpansionRetryAttempts = 0;

    function cleanupGarageExpansion() {
        stopGarageExpansionRetry();
        document.querySelectorAll('[' + GARAGE_EXPANSION_ATTR + '], [data-ntk-garage-organizer]').forEach((node) => node.remove());
    }

    function stopGarageExpansionRetry() {
        if (!garageExpansionRetryTimer) return;
        clearInterval(garageExpansionRetryTimer);
        garageExpansionRetryTimer = null;
        garageExpansionRetryAttempts = 0;
    }

    /** Show a custom NT-styled modal with an input field. Returns a Promise that resolves with the value or null. */
    function showGarageExpansionModal(currentSections, totalCars) {
        return new Promise((resolve) => {
            // Overlay
            const overlay = document.createElement('div');
            overlay.style.cssText = 'position:fixed;inset:0;z-index:99999;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0.7);';

            // Modal container
            const modal = document.createElement('div');
            modal.style.cssText = 'width:580px;max-width:92vw;border-radius:8px;overflow:hidden;box-shadow:0 8px 32px rgba(0,0,0,0.5);font-family:Montserrat,sans-serif;';

            // Header bar (blue, like mod menu)
            const header = document.createElement('div');
            header.style.cssText = 'background:url(/dist/site/images/backgrounds/bg-noise.png) top left repeat, linear-gradient(90deg,#1c99f4 0%,#167ac3 42%,#0f4f86 100%);padding:18px 28px;display:flex;align-items:center;justify-content:space-between;';
            const title = document.createElement('span');
            title.style.cssText = 'color:#fff;font-size:28px;font-weight:600;line-height:1.2;text-shadow:0 2px 2px rgba(2,2,2,0.25);font-family:Montserrat,sans-serif;';
            title.textContent = 'Garage Expansion';
            header.appendChild(title);

            const closeX = document.createElement('button');
            closeX.style.cssText = 'background:none;border:none;cursor:pointer;padding:0;line-height:1;display:inline-flex;';
            closeX.innerHTML = '<svg viewBox="0 0 24 24" style="width:28px;height:28px;display:block;"><rect x="1" y="1" width="22" height="22" rx="4" fill="#d62f3a"/><path d="M8 8l8 8M16 8l-8 8" stroke="rgba(255,255,255,0.85)" stroke-width="1.5" stroke-linecap="round"/></svg>';
            closeX.addEventListener('click', () => { overlay.remove(); resolve(null); });
            header.appendChild(closeX);

            // Body
            const body = document.createElement('div');
            body.style.cssText = 'background:url(/dist/site/images/backgrounds/bg-noise.png) top left repeat, linear-gradient(180deg,#2a2d3d 0%,#232636 100%);padding:28px;';

            const desc = document.createElement('div');
            desc.style.cssText = 'color:#d0d3e0;font-size:15px;line-height:1.7;margin-bottom:18px;';
            desc.innerHTML = 'Set the number of visible garage sections. Each section holds 30 car slots.<br><span style="color:#d0d3e0;font-size:13px;">Note: You will be logged out after applying so changes can take effect.</span>';

            const emptySlots = Math.max(0, currentSections * 30 - totalCars);
            const currentInfo = document.createElement('div');
            currentInfo.style.cssText = 'color:#8a8ea0;font-size:14px;line-height:1.8;margin-bottom:22px;padding:14px 16px;background:rgba(0,0,0,0.25);border-radius:4px;border-left:3px solid #1c99f4;';
            currentInfo.innerHTML =
                `<span style="color:#d0d3e0;">Cars:</span> <span style="color:#fff;font-weight:600;">${totalCars}</span>` +
                `<span style="margin:0 10px;color:#3a4553;">|</span>` +
                `<span style="color:#d0d3e0;">Sections:</span> <span style="color:#fff;font-weight:600;">${currentSections}</span>` +
                `<span style="margin:0 10px;color:#3a4553;">|</span>` +
                `<span style="color:#d0d3e0;">Slots:</span> <span style="color:#fff;font-weight:600;">${currentSections * 30}</span>` +
                `<span style="margin:0 10px;color:#3a4553;">|</span>` +
                `<span style="color:#d0d3e0;">Empty:</span> <span style="color:#fff;font-weight:600;">${emptySlots}</span>`;

            const inputRow = document.createElement('div');
            inputRow.style.cssText = 'display:flex;align-items:center;gap:12px;';

            const inputLabel = document.createElement('span');
            inputLabel.style.cssText = 'color:#d0d3e0;font-size:16px;white-space:nowrap;font-weight:600;';
            inputLabel.textContent = 'Sections:';

            const input = document.createElement('input');
            input.type = 'text';
            input.inputMode = 'numeric';
            input.pattern = '[0-9]*';
            input.value = String(currentSections);
            input.placeholder = '1-30';
            input.style.cssText = 'width:85px;padding:12px 14px;border-radius:4px;border:2px solid #2a5a8a;background:#1e2a3a;color:#fff;font-size:16px;font-family:Montserrat,sans-serif;text-align:center;outline:none;cursor:text;-moz-appearance:textfield;';
            input.addEventListener('focus', () => { input.style.borderColor = '#2196f3'; });
            input.addEventListener('blur', () => { input.style.borderColor = '#2a5a8a'; });
            input.addEventListener('input', () => {
                const v = parseInt(input.value, 10);
                if (v > 30) input.value = '30';
                if (v < 1 && input.value !== '') input.value = '1';
            });

            const maxLabel = document.createElement('span');
            maxLabel.style.cssText = 'color:#d0d3e0;font-size:13px;';
            maxLabel.textContent = 'Max: 30';

            inputRow.appendChild(inputLabel);
            inputRow.appendChild(input);
            inputRow.appendChild(maxLabel);

            const errorMsg = document.createElement('div');
            errorMsg.style.cssText = 'color:#d62f3a;font-size:13px;margin-top:10px;min-height:18px;';

            // Status message area (replaces browser alert)
            const statusMsg = document.createElement('div');
            statusMsg.style.cssText = 'margin-top:10px;min-height:20px;font-size:14px;';

            body.appendChild(desc);
            body.appendChild(currentInfo);
            body.appendChild(inputRow);
            body.appendChild(errorMsg);
            body.appendChild(statusMsg);

            // Footer
            const footer = document.createElement('div');
            footer.style.cssText = 'background:url(/dist/site/images/backgrounds/bg-noise.png) top left repeat, linear-gradient(180deg,#2a2d3d 0%,#232636 100%);padding:20px 28px;display:flex;justify-content:center;gap:14px;';

            const cancelBtn = document.createElement('button');
            cancelBtn.style.cssText = 'padding:12px 32px;border-radius:4px;border:1px solid #4a4e63;background:transparent;color:#d0d3e0;font-size:15px;font-weight:600;cursor:pointer;font-family:Montserrat,sans-serif;';
            cancelBtn.textContent = 'Cancel';
            cancelBtn.addEventListener('click', () => { overlay.remove(); resolve(null); });

            const applyBtn = document.createElement('button');
            applyBtn.style.cssText = 'padding:12px 32px;border-radius:4px;border:none;background:#d62f3a;color:#fff;font-size:15px;font-weight:600;cursor:pointer;font-family:Montserrat,sans-serif;';
            applyBtn.textContent = 'Apply';

            applyBtn.addEventListener('click', async () => {
                const val = parseInt(input.value, 10);
                if (isNaN(val) || val < 1 || val > 30) {
                    errorMsg.textContent = 'Please enter a number between 1 and 30.';
                    input.style.borderColor = '#d62f3a';
                    return;
                }
                errorMsg.textContent = '';
                // Disable controls during request
                applyBtn.disabled = true;
                applyBtn.style.opacity = '0.5';
                cancelBtn.disabled = true;
                cancelBtn.style.opacity = '0.5';
                input.disabled = true;
                statusMsg.style.color = '#a6aac1';
                statusMsg.textContent = 'Updating garage...';

                try {
                    const persist = JSON.parse(localStorage.getItem('persist:nt'));
                    const user = JSON.parse(persist.user);
                    const garage = user.garage;
                    if (!Array.isArray(garage)) {
                        statusMsg.style.color = '#d62f3a';
                        statusMsg.textContent = 'Could not read garage data.';
                        applyBtn.disabled = false; applyBtn.style.opacity = '1';
                        cancelBtn.disabled = false; cancelBtn.style.opacity = '1';
                        input.disabled = false;
                        return;
                    }

                    const totalSlots = val * 30;
                    let reqBody = '';
                    for (let i = 0; i < totalSlots; i++) {
                        reqBody += `garage%5B${i}%5D=${garage[i] || ''}&`;
                    }

                    const token = getLiveTokenOuter();
                    if (!token) {
                        statusMsg.style.color = '#d62f3a';
                        statusMsg.textContent = 'Session expired or token invalid. Please log in again.';
                        applyBtn.disabled = false; applyBtn.style.opacity = '1';
                        cancelBtn.disabled = false; cancelBtn.style.opacity = '1';
                        input.disabled = false;
                        return;
                    }

                    await fetch('/api/v2/loot/arrange-cars', {
                        headers: {
                            'Authorization': 'Bearer ' + token,
                            'Content-Type': 'application/x-www-form-urlencoded'
                        },
                        body: reqBody,
                        method: 'POST',
                        mode: 'cors'
                    });

                    statusMsg.style.color = '#4caf50';
                    statusMsg.innerHTML = 'Garage updated! Logging you out so changes take effect...';
                    // Brief delay so user can read the message
                    setTimeout(() => {
                        overlay.remove();
                        resolve(val);
                        const logoutLink = document.querySelector('a.dropdown-link[href="/"]');
                        if (logoutLink) logoutLink.click();
                        else window.location.href = '/';
                    }, 1500);
                } catch (e) {
                    console.error(TOOLKIT_LOG_PREFIX, 'Garage expansion error:', e);
                    statusMsg.style.color = '#d62f3a';
                    statusMsg.textContent = 'Something went wrong. Check console for details.';
                    applyBtn.disabled = false; applyBtn.style.opacity = '1';
                    cancelBtn.disabled = false; cancelBtn.style.opacity = '1';
                    input.disabled = false;
                }
            });

            // Enter key submits
            input.addEventListener('keydown', (e) => {
                if (e.key === 'Enter') applyBtn.click();
                if (e.key === 'Escape') { overlay.remove(); resolve(null); }
            });

            footer.appendChild(cancelBtn);
            footer.appendChild(applyBtn);

            modal.appendChild(header);
            modal.appendChild(body);
            modal.appendChild(footer);
            overlay.appendChild(modal);

            // Close on overlay click (outside modal)
            overlay.addEventListener('click', (e) => {
                if (e.target === overlay) { overlay.remove(); resolve(null); }
            });

            document.body.appendChild(overlay);
            input.focus();
            input.select();
        });
    }

    function getGarageExpansionMount() {
        const garageRoot = document.querySelector('.garage');
        const garageCard = document.querySelector('section.is-player-garage') || garageRoot?.closest('section') || null;
        const cardCap = garageCard?.querySelector(':scope > .card-cap') || garageCard?.querySelector('.card-cap') || null;
        const headerSplit = cardCap?.querySelector('.split') || null;
        let actionCell = null;
        let rearrangeBtn = null;

        if (headerSplit) {
            actionCell = Array.from(headerSplit.children || []).find((cell) => /rearrange/i.test(cell.textContent || '')) || headerSplit.lastElementChild;
        }
        rearrangeBtn = actionCell
            ? Array.from(actionCell.querySelectorAll('a.btn,button.btn,a,button')).find((el) => /rearrange/i.test(el.textContent || ''))
            : null;
        if (!rearrangeBtn) {
            rearrangeBtn = Array.from(document.querySelectorAll('section.is-player-garage a.btn,section.is-player-garage button.btn')).find(
                (el) => /rearrange/i.test(el.textContent || '')
            );
        }
        if (!actionCell && rearrangeBtn) actionCell = rearrangeBtn.parentElement;

        return {
            actionCell,
            cardCap,
            garageRoot,
            rearrangeBtn,
            fallbackMount: actionCell || cardCap || garageRoot?.parentElement || null
        };
    }

    function handleGarageExpansion() {
        if (!isFeatureEnabled('ENABLE_GARAGE_EXPANSION')) return;
        let mount;
        let btn;

        const path = window.location.pathname.replace(/\/+$/, '') || '/';
        if (path !== '/garage') {
            stopGarageExpansionRetry();
            return;
        }

        // Already injected?
        if (document.querySelector(`[${GARAGE_EXPANSION_ATTR}], [data-ntk-garage-organizer]`)) {
            stopGarageExpansionRetry();
            return;
        }

        mount = getGarageExpansionMount();
        if (!mount.fallbackMount) return;

        btn = document.createElement('button');
        btn.setAttribute(GARAGE_EXPANSION_ATTR, '');
        btn.type = 'button';
        btn.style.cssText = 'margin-right:8px;cursor:pointer;background:none;border:none;padding:0;display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;flex:0 0 auto;';
        btn.title = 'Open Garage Expansion';
        btn.setAttribute('aria-label', 'Open Garage Expansion');
        btn.innerHTML = '<svg viewBox="0 0 24 24" style="width:28px;height:28px;display:block;"><rect x="1" y="1" width="22" height="22" rx="4" fill="#d62f3a"/><path d="M12 6v12M6 12h12" stroke="rgba(255,255,255,0.85)" stroke-width="1.5" stroke-linecap="round"/></svg>';

        btn.addEventListener('click', async () => {
            try {
                const persist = JSON.parse(localStorage.getItem('persist:nt'));
                const user = JSON.parse(persist.user);
                const garage = user.garage;
                if (!Array.isArray(garage)) return;

                const totalCars = user.totalCars || user.carsOwned || 0;
                const currentSections = Math.ceil(garage.length / 30);
                await showGarageExpansionModal(currentSections, totalCars);
            } catch (e) {
                console.error(TOOLKIT_LOG_PREFIX, 'Garage expansion error:', e);
            }
        });

        if (mount.actionCell) {
            mount.actionCell.style.display = 'flex';
            mount.actionCell.style.alignItems = 'center';
            mount.actionCell.style.justifyContent = 'flex-end';
            if (mount.rearrangeBtn && mount.rearrangeBtn.parentElement === mount.actionCell) {
                mount.actionCell.insertBefore(btn, mount.rearrangeBtn);
            } else {
                mount.actionCell.insertBefore(btn, mount.actionCell.firstChild);
            }
        } else if (mount.cardCap) {
            btn.style.marginLeft = 'auto';
            mount.cardCap.appendChild(btn);
        } else {
            btn.style.margin = '0 0 8px 0';
            mount.fallbackMount.insertBefore(btn, mount.garageRoot || mount.fallbackMount.firstChild);
        }
        stopGarageExpansionRetry();
    }

    function syncGarageExpansionImmediate() {
        try { handleGarageExpansion(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'GarageExpansion error:', e); }
        if (typeof requestAnimationFrame === 'function') {
            requestAnimationFrame(() => {
                try { handleGarageExpansion(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'GarageExpansion error:', e); }
            });
        }
        setTimeout(() => {
            try { handleGarageExpansion(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'GarageExpansion error:', e); }
        }, 60);
        if (garageExpansionRetryTimer || !isFeatureEnabled('ENABLE_GARAGE_EXPANSION')) return;
        garageExpansionRetryAttempts = 0;
        garageExpansionRetryTimer = setInterval(() => {
            garageExpansionRetryAttempts += 1;
            try { handleGarageExpansion(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'GarageExpansion error:', e); }
            if (garageExpansionRetryAttempts >= 30 || document.querySelector(`[${GARAGE_EXPANSION_ATTR}], [data-ntk-garage-organizer]`) || (window.location.pathname.replace(/\/+$/, '') || '/') !== '/garage') {
                stopGarageExpansionRetry();
            }
        }, 150);
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 10: Keyboard Shortcuts (Global)
    // ─────────────────────────────────────────────────────────────────────────────
    /** Check if exactly the chosen modifier(s) are active (and no others). */
    const isModifierMatch = (e, modifier, modifier2) => {
        const required = new Set([modifier]);
        if (modifier2 && modifier2 !== 'none') required.add(modifier2);
        const active = new Set();
        if (e.altKey) active.add('alt');
        if (e.ctrlKey) active.add('ctrl');
        if (e.shiftKey) active.add('shift');
        if (e.metaKey) active.add('meta');
        if (required.size !== active.size) return false;
        for (const m of required) { if (!active.has(m)) return false; }
        return true;
    };

    function initKeyboardShortcuts() {
        document.addEventListener('keydown', (e) => {
            if (!isFeatureEnabled('ENABLE_KEYBOARD_SHORTCUTS')) return;

            // Skip on the race page — NT locks down keyboard input
            if (document.getElementById('raceContainer')) return;

            // Don't fire if a modal is open
            if (document.querySelector('.modal')) return;

            // Don't fire during input/textarea focus
            const active = document.activeElement;
            if (active) {
                const tag = active.tagName;
                if (tag === 'INPUT' || tag === 'TEXTAREA' || active.contentEditable === 'true') return;
            }

            // Read shortcut map from settings (fall back to defaults)
            const shortcuts = (() => {
                const raw = readSetting('KEYBOARD_SHORTCUT_MAP');
                const source = Array.isArray(raw) && raw.length > 0 ? raw : DEFAULT_SHORTCUTS;
                return source.map((shortcut) => normalizeShortcutBinding(shortcut));
            })();

            const pressedCode = normalizeShortcutCodeValue(e.code, e.key);
            const pressedKey = normalizeShortcutStoredKey(e.key, pressedCode);
            const match = shortcuts.find(s => {
                const bindingMatches = s.code ? s.code === pressedCode : (!!s.key && s.key === pressedKey);
                if (!bindingMatches) return false;
                const mod1 = s.mod1 || 'alt';
                const mod2 = s.mod2 || 'none';
                return isModifierMatch(e, mod1, mod2);
            });
            if (!match || !match.path) return;

            e.preventDefault();
            e.stopPropagation();

            // Handle toggle actions
            if ((match.action === 'toggle') && match.path.startsWith('toggle:')) {
                const parts = match.path.split(':');
                // format: toggle:scriptId:settingKey
                if (parts.length >= 3) {
                    const scriptId = parts[1];
                    const settingKey = parts.slice(2).join(':');
                    const storageKey = `ntcfg:${scriptId}:${settingKey}`;
                    try {
                        const current = JSON.parse(localStorage.getItem(storageKey) ?? 'null');
                        const newVal = !current;
                        localStorage.setItem(storageKey, JSON.stringify(newVal));
                        // Dispatch change event so scripts react immediately
                        document.dispatchEvent(new CustomEvent('ntcfg:change', {
                            detail: { script: scriptId, key: settingKey, value: newVal }
                        }));
                    } catch { /* ignore */ }
                }
                return;
            }

            if ((match.action === 'trigger') && match.path.startsWith('action:')) {
                const parts = match.path.split(':');
                if (parts.length >= 3) {
                    const scriptId = parts[1];
                    const actionKey = parts.slice(2).join(':');
                    try {
                        document.dispatchEvent(new CustomEvent('ntcfg:action', {
                            detail: { script: scriptId, key: actionKey, source: 'shortcut' }
                        }));
                    } catch { /* ignore */ }
                }
                return;
            }

            // Navigate action
            let path = match.path;
            if (path === '/profile') {
                const user = getCurrentUser();
                path = user?.username ? '/racer/' + user.username : null;
            }

            if (path) {
                window.open(window.location.origin + path, '_self');
            }
        }, true);
    }

    // ─── Register keyboard shortcuts immediately at document-start ─────────────
    // Must happen before NT's bundle loads and registers its own capture listeners.
    initKeyboardShortcuts();

    function shouldRetryToolkitCarIcon() {
        return readSetting('ENABLE_CAR_ICON') && !document.querySelector('[' + CAR_ICON_ATTR + ']');
    }

    function shouldRetryToolkitSmartNotify() {
        if (!readSetting('SMART_SHOP_NOTIFY')) return false;
        if (readSetting('HIDE_NOTIFY_ALL') || readSetting('HIDE_NOTIFY_SHOP')) return false;
        return !document.querySelector('[' + SMART_NOTIFY_ATTR + ']');
    }

    function stopToolkitGlobalUiRetryPoll() {
        if (toolkitGlobalUiRetryPollTimer) {
            clearInterval(toolkitGlobalUiRetryPollTimer);
            toolkitGlobalUiRetryPollTimer = null;
        }
        toolkitGlobalUiRetryAttempts = 0;
    }

    function startToolkitGlobalUiRetryPoll() {
        if (toolkitGlobalUiRetryPollTimer) return;
        toolkitGlobalUiRetryAttempts = 0;
        toolkitGlobalUiRetryPollTimer = setInterval(() => {
            toolkitGlobalUiRetryAttempts++;
            const carDone = !shouldRetryToolkitCarIcon();
            const smartNotifyDone = !shouldRetryToolkitSmartNotify();

            try { handleCarIcon(); } catch { /* ignore */ }
            if (!smartNotifyDone) {
                try { applySmartShopNotify(); } catch { /* ignore */ }
            }

            if ((carDone && smartNotifyDone) || toolkitGlobalUiRetryAttempts >= 50) {
                stopToolkitGlobalUiRetryPoll();
            }
        }, 200);
    }

    function syncToolkitGlobalUiFallbacks() {
        if (shouldRetryToolkitCarIcon() || shouldRetryToolkitSmartNotify()) {
            startToolkitGlobalUiRetryPoll();
        } else {
            stopToolkitGlobalUiRetryPoll();
        }
    }

    function runToolkitGlobalUiFastSync() {
        try { handleCarIcon(); } catch { /* ignore */ }
        if (shouldRetryToolkitSmartNotify()) {
            try { applySmartShopNotify(); } catch { /* ignore */ }
        }
    }

    function syncToolkitGlobalUiImmediate() {
        runToolkitGlobalUiFastSync();
        if (typeof requestAnimationFrame === 'function') {
            requestAnimationFrame(runToolkitGlobalUiFastSync);
        }
        if (toolkitGlobalUiFastSyncTimer) clearTimeout(toolkitGlobalUiFastSyncTimer);
        toolkitGlobalUiFastSyncTimer = setTimeout(() => {
            toolkitGlobalUiFastSyncTimer = null;
            runToolkitGlobalUiFastSync();
            setTimeout(runToolkitGlobalUiFastSync, 70);
            syncToolkitGlobalUiFallbacks();
        }, 45);
    }

    function stopToolkitBodyWaitObserver() {
        if (!toolkitBodyWaitObserver) return;
        try { toolkitBodyWaitObserver.disconnect(); } catch { /* ignore */ }
        toolkitBodyWaitObserver = null;
    }

    // ─── Main Initialization ──────────────────────────────────────────────────────
    function startToolkit() {
        initObserverManager();
        initCashMaskObserver();
        initCashGiftObserver();

        applyAllLiveSettingSideEffects();

        // NT renders some global chrome after the observer manager starts, so keep
        // this retry loop narrowly focused on the two late-mount global widgets.
        syncToolkitGlobalUiImmediate();
        syncGarageToolsFeature();

        // Register observer callback that dispatches to feature handlers
        window.NTObserverManager.register('toolkit', () => {
            const path = normalizePath(window.location.pathname);
            syncToolkitGlobalUiImmediate();
            syncBannedLabelsRetryPoll();
            syncGarageToolsFeature();

            // Global features (run on every page)
            try { handleCarIcon(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'CarIcon error:', e); }
            try { markCashMaskTargets(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'CashMask error:', e); }
            try { syncCashGiftModals(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'CashGift error:', e); }

            // Team and friends page features
            if ((path.startsWith('/team/') || path === '/friends') && document.querySelector('.table-row')) {
                try { handleBannedLabels(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'BannedLabels error:', e); }
            }
            if (path.startsWith('/team/') && document.querySelector('.table-row')) {
                try { handleMOTDFilter(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'MOTDFilter error:', e); }
            }

            // Garage page features
            if (path === '/garage') {
                try { syncGarageExpansionImmediate(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'GarageExpansion error:', e); }
            }

            try { syncClearNotificationsButton(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'Notifications error:', e); }

            // Shop page features
            if (path === '/shop') {
                try { handleShopPreview(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'ShopPreview error:', e); }
            }

            handleModalFeatures(path);
        });

        document.addEventListener('click', () => {
            scheduleModalFeatureRefresh();
        }, true);

        if (normalizePath(window.location.pathname) === '/shop' && readSetting('ENABLE_SHOP_LEAKS')) {
            try { scheduleShopPreviewRefresh(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'Initial ShopPreview error:', e); }
        }

    }

    // Wait for document.body to exist before starting
    if (document.body) {
        startToolkit();
    } else {
        toolkitBodyWaitObserver = new MutationObserver(() => {
            if (document.body) {
                stopToolkitBodyWaitObserver();
                startToolkit();
            }
        });
        toolkitBodyWaitObserver.observe(document.documentElement, { childList: true });
    }

})();