Nitro Type Toolkit

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Nitro Type Toolkit
// @namespace    https://greasyfork.org/users/1443935
// @version      1.0.1
// @description  Quality-of-life utilities: shop leaks, keyboard shortcuts & more.
// @author       Captain.Loveridge
// @match        https://www.nitrotype.com/*
// @match        *://*.nitrotype.com/settings/mods*
// @grant        none
// @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';

    // ─── 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 = 2;
    const SHORTCUTS_VERSION_KEY = `${NTCFG_VALUE_PREFIX}__shortcuts_version`;
    const DEFAULT_SHORTCUTS = [
        { key: 'R', path: '/race', mod1: 'alt', mod2: 'none' },
        { key: 'G', path: '/garage', mod1: 'alt', mod2: 'none' },
        { key: 'F', path: '/friends', mod1: 'alt', mod2: 'none' },
        { key: 'S', path: '/shop', mod1: 'alt', mod2: 'none' },
        { key: 'P', path: '/profile', mod1: 'alt', mod2: 'none' },
        { key: 'T', path: '/team', mod1: 'alt', mod2: 'none' },
        { key: 'A', path: '/achievements', mod1: 'alt', mod2: 'none' },
        { key: 'M', path: '/settings/mods', mod1: 'alt', mod2: 'none' },
        { key: 'E', path: '/season', mod1: 'alt', mod2: 'none' },
        { key: 'L', path: '/leagues', mod1: 'alt', mod2: 'none' },
        { key: 'B', path: '/leaderboards', mod1: 'alt', mod2: 'none' },
        { key: 'I', path: '/stats', mod1: 'alt', mod2: 'none' }
    ];

    const TOOLKIT_SETTINGS = {
        // ── Garage ─────────────────────────────────────────────────────────────
        ENABLE_GARAGE_ORGANIZER: {
            type: 'boolean',
            label: 'Garage Section Organizer',
            default: true,
            group: 'Garage',
            description: 'Add a button on the garage page to set the number of visible garage sections (pages of 30 cars).'
        },
        GARAGE_ORGANIZER_ACTION: {
            type: 'action',
            label: 'Open Garage Organizer',
            style: 'primary',
            group: 'Garage',
            help: 'Set the number of garage sections directly from the mod menu.',
            visibleWhen: { key: 'ENABLE_GARAGE_ORGANIZER', eq: true }
        },
        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 member lists and the team header.'
        },
        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_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_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 }
        },
        // ── 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 which shortcuts navigate to which pages. Use /profile for your own racer page.',
            visibleWhen: { key: 'ENABLE_KEYBOARD_SHORTCUTS', eq: true }
        }
    };

    // ─── Settings Read/Write Utilities ────────────────────────────────────────────
    const getStorageKey = (settingKey) => `${NTCFG_VALUE_PREFIX}${settingKey}`;

    const readSetting = (settingKey) => {
        const meta = TOOLKIT_SETTINGS[settingKey];
        if (!meta) return undefined;
        try {
            const raw = localStorage.getItem(getStorageKey(settingKey));
            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) => {
        try {
            const serialized = JSON.stringify(value);
            if (localStorage.getItem(getStorageKey(settingKey)) !== serialized) {
                localStorage.setItem(getStorageKey(settingKey), serialized);
            }
        } catch { /* ignore storage failures */ }
    };

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

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

    // ─── Donation Link Migration ────────────────────────────────────────────────
    // Migrate old boolean ENABLE_DONATION_LINK + DONATION_LINK_FULL_URL to new select DONATION_LINK_STYLE
    (() => {
        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 = parseInt(localStorage.getItem(SHORTCUTS_VERSION_KEY), 10) || 0;
            if (storedVersion >= SHORTCUTS_VERSION) return;

            const saved = readSetting('KEYBOARD_SHORTCUT_MAP');
            if (Array.isArray(saved) && saved.length > 0) {
                // Find keys the user already has mapped
                const existingKeys = new Set(saved.map(s => s.key?.toUpperCase()));
                // Add any new defaults that don't conflict with user's keys
                const additions = DEFAULT_SHORTCUTS.filter(d => !existingKeys.has(d.key.toUpperCase()));
                if (additions.length > 0) {
                    writeSetting('KEYBOARD_SHORTCUT_MAP', saved.concat(additions));
                }
            }
            localStorage.setItem(SHORTCUTS_VERSION_KEY, String(SHORTCUTS_VERSION));
        } catch { /* ignore */ }
    })();

    // ─── Manifest Registration ────────────────────────────────────────────────────
    const registerManifest = () => {
        try {
            const manifest = {
                id: NTCFG_MANIFEST_ID,
                name: 'Toolkit',
                version: NTCFG_BRIDGE_VERSION,
                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));
        });
    };

    // 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) => {
        if (event?.detail?.script !== NTCFG_MANIFEST_ID) return;
        if (event.detail.key === 'GARAGE_ORGANIZER_ACTION') {
            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);
                showGarageModal(currentSections, totalCars);
            } catch (e) {
                console.error(TOOLKIT_LOG_PREFIX, 'Garage organizer 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 */ }
    });

    registerManifest();
    syncAllSettings();

    try {
        document.dispatchEvent(new CustomEvent('ntcfg:manifest-updated', {
            detail: { script: NTCFG_MANIFEST_ID }
        }));
    } catch { /* ignore */ }

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

    /** 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;
    };

    /** 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() {
        // Features that need cleanup on route change can hook here.
        // The NTObserverManager handles re-injection on DOM mutations.
    }

    // ─── Observer Manager Integration ─────────────────────────────────────────────
    function initObserverManager() {
        window.NTObserverManager = window.NTObserverManager || {
            callbacks: {},
            observer: null,
            debounceTimer: null,
            register(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
                    });
                }
            }
        };
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 1: Banned/Warned Labels (/team/*)
    // ─────────────────────────────────────────────────────────────────────────────
    const BANNED_ATTR = 'data-toolkit-banned';

    /** 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 handleBannedLabels() {
        if (!isFeatureEnabled('ENABLE_BANNED_LABELS')) return;

        const teamTable = document.querySelector('.table.table--striped.table--selectable.table--team.table--teamOverview');
        if (!teamTable) return;

        // Try to get members data from React internals
        const members = findTeamMembers(teamTable);
        if (!members || members.length === 0) return;

        // ── Team header: captain badge ──────────────────────────────────────────
        const headerContainer = document.querySelector('.tsm.tbs');
        if (headerContainer && !headerContainer.hasAttribute(BANNED_ATTR)) {
            const captainLink = headerContainer.querySelector('a.link');
            if (captainLink) {
                // Extract username from href like "/racer/ii_zvx"
                const hrefParts = (captainLink.getAttribute('href') || '').split('/').filter(Boolean);
                const captainUsername = hrefParts[hrefParts.length - 1] || '';

                if (captainUsername) {
                    const captainMember = members.find(m =>
                        (m.username || '').toLowerCase() === captainUsername.toLowerCase()
                    );

                    if (captainMember) {
                        const captainStatus = (captainMember.status || '').toLowerCase();
                        if (captainStatus === 'banned' || captainStatus === 'warned') {
                            headerContainer.setAttribute(BANNED_ATTR, captainStatus);
                            const badge = createStatusBadge(captainStatus);
                            // Insert badge after the "Team Captain" label
                            const captainLabel = headerContainer.querySelector('.tsxs.ttu.tsi.mls');
                            if (captainLabel) {
                                captainLabel.after(badge);
                            } else {
                                captainLink.after(badge);
                            }
                        } else {
                            headerContainer.setAttribute(BANNED_ATTR, 'ok');
                        }
                    }
                }
            }
        }

        // ── Roster rows ─────────────────────────────────────────────────────────
        const rows = teamTable.querySelectorAll('.table-row');
        rows.forEach((row) => {
            if (row.hasAttribute(BANNED_ATTR)) return;

            const nameContainer = row.querySelector('.player-name--container[title]');
            if (!nameContainer) return;

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

            const displayName = nameSpan.textContent.trim();

            // Match this row to a member object
            const member = members.find(m => {
                const mName = m.displayName || m.username || '';
                return mName.trim() === displayName;
            });

            if (!member) return;

            const status = (member.status || '').toLowerCase();
            if (status !== 'banned' && status !== 'warned') {
                row.setAttribute(BANNED_ATTR, 'ok');
                return;
            }

            row.setAttribute(BANNED_ATTR, status);

            const badge = createStatusBadge(status);

            // Place the badge in the status area (where flag icons also go),
            // or after the name text and any racer badge icons
            const statusArea = nameContainer.querySelector('.tsi.tc-lemon.tsxs');
            if (statusArea) {
                if (statusArea.firstChild) {
                    statusArea.insertBefore(badge, statusArea.firstChild);
                    const sep = document.createTextNode(' ');
                    statusArea.insertBefore(sep, badge.nextSibling);
                } else {
                    statusArea.appendChild(badge);
                }
            } else {
                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);
                }
            }
        });
    }

    /** Extract team members array from React fiber tree. */
    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;

            let fiber = getReactFiber(card);
            let steps = 0;
            while (fiber && steps++ < 40) {
                const props = fiber.memoizedProps || fiber.pendingProps || {};
                if (Array.isArray(props.members)) return props.members;
                if (props.children?.props?.members) return props.children.props.members;
                const state = fiber.memoizedState;
                if (state?.memoizedState?.members) return state.memoizedState.members;
                fiber = fiber.return;
            }

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

            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 NUMERIC_REGEXP = /^[0-9]+$/;

    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';

            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';

    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.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);
        });
    }

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

    // 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';

    /**
     * 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 {
            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();

        const rules = [];

        if (readSetting('HIDE_SEASON_BANNER')) rules.push('.seasonTeaser { display: none !important; }');
        if (readSetting('HIDE_ADS')) rules.push('.ad, .profile-ad { display: none !important; }');
        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();
            }
        }

        if (readSetting('HIDE_CASH_DISPLAY')) {
            const mode = readSetting('HIDE_CASH_MODE') || 'hidden';
            // Exclude: shop item prices, shop modal prices, toolkit's own cash preview, racelog winnings
            const excludeParts = [
                '.page-shop--product--price .as-nitro-cash--prefix',
                '.page-shop--modal--price .as-nitro-cash--prefix',
                '[data-ntk-cash-preview]',
                '.table--striped .as-nitro-cash--prefix',
                '.season-reward-mini-preview--label .as-nitro-cash--prefix'
            ];
            // Only exclude Total Spent if the user hasn't opted to hide it
            if (!readSetting('HIDE_CASH_TOTAL_SPENT')) {
                excludeParts.push('.stat-box--extra .as-nitro-cash--prefix');
            }
            const excludeReset = excludeParts.join(', ');

            if (mode === 'hidden') {
                rules.push('.as-nitro-cash--prefix { visibility: hidden !important; }');
                rules.push(`${excludeReset} { visibility: visible !important; }`);
                // Hide the entire cash section on garage/profile when showing nothing
                rules.push('.profile--content--current-cash { display: none !important; }');
            } else {
                rules.push('.as-nitro-cash--prefix { font-size: 0 !important; }');
                let replacementText = '';
                if (mode === 'redacted') replacementText = 'REDACTED';
                else if (mode === 'stars') replacementText = '*******';
                else if (mode === 'custom') replacementText = (readSetting('HIDE_CASH_CUSTOM_TEXT') || '').replace(/\\/g, '\\\\').replace(/'/g, "\\'");
                rules.push(`.as-nitro-cash--prefix::after { content: '${replacementText}'; font-size: 1rem; }`);
                // Restore excluded elements to normal
                rules.push(`${excludeReset} { font-size: inherit !important; }`);
                const afterParts = excludeParts.map(s => s.replace('.as-nitro-cash--prefix', '.as-nitro-cash--prefix::after'));
                rules.push(`${afterParts.join(', ')} { content: none !important; }`);
                // Fix double replacement — nested .as-nitro-cash--prefix elements should only show one replacement
                rules.push(`.as-nitro-cash--prefix .as-nitro-cash--prefix::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);
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 7: Car Profile Icon (Global)
    // ─────────────────────────────────────────────────────────────────────────────
    const CAR_ICON_ATTR = 'data-toolkit-car-icon';

    function handleCarIcon() {
        if (!readSetting('ENABLE_CAR_ICON')) return;

        // Already replaced
        if (document.querySelector('[' + CAR_ICON_ATTR + ']')) return;

        const icon = document.querySelector('svg.icon-user-s');
        if (!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;

            const cars = window.NTGLOBALS?.CARS;
            if (!cars || !carID) return;

            const car = cars.find(c => c.carID === carID);
            if (!car?.options?.smallSrc) return;

            const img = document.createElement('img');
            img.src = 'https://www.nitrotype.com/cars/' + car.options.smallSrc;
            img.style.height = '18px';
            img.style.width = '18px';
            img.style.filter = 'hue-rotate(' + (carHueAngle || 0) + 'deg)';
            img.style.objectFit = 'contain';
            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';
    let shopPreviewActive = false;

    /**
     * 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);
        }

        console.info(TOOLKIT_LOG_PREFIX, 'Animated previews ready:', { car: !!CarComponent, trail: !!TrailComponent });
        return { React, ReactDOM, CarComponent, TrailComponent, getCarUrl, getCarMetaData, getLootMetaData, playerCar };
    }

    function handleShopPreview() {
        if (!isFeatureEnabled('ENABLE_SHOP_LEAKS')) return;
        if (window.location.pathname !== '/shop') return;
        if (document.querySelector('[' + SHOP_PREVIEW_ATTR + ']')) return;

        const featuredSection = document.querySelector('.page-shop--featured-products');
        if (!featuredSection) return;

        const pw = (typeof unsafeWindow !== 'undefined' && unsafeWindow) ? unsafeWindow : window;
        const SHOP = pw.NTGLOBALS?.SHOP;
        const CARS = pw.NTGLOBALS?.CARS;
        const LOOT = pw.NTGLOBALS?.LOOT;
        const CAR_URL = pw.NTGLOBALS?.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) return;

        // ── Extract React internals for animated previews ──
        let reactCtx = null;
        try {
            reactCtx = extractReactInternals(pw);
        } catch (e) {
            console.warn(TOOLKIT_LOG_PREFIX, 'Animated previews unavailable:', e.message);
        }

        // 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.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.style.display = 'flex';
            firstCategory.style.alignItems = 'center';
            firstCategory.style.flexWrap = 'wrap';
            firstCategory.appendChild(btn);
        }

        // Toggle handler
        btn.addEventListener('click', () => {
            shopPreviewActive = !shopPreviewActive;

            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 Section Organizer (/garage)
    // ─────────────────────────────────────────────────────────────────────────────
    const GARAGE_ORGANIZER_ATTR = 'data-ntk-garage-organizer';

    /** Show a custom NT-styled modal with an input field. Returns a Promise that resolves with the value or null. */
    function showGarageModal(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 Organizer';
            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 = localStorage.getItem('player_token');
                    if (!token) {
                        statusMsg.style.color = '#d62f3a';
                        statusMsg.textContent = 'Not logged in.';
                        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 organizer 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 handleGarageOrganizer() {
        if (!isFeatureEnabled('ENABLE_GARAGE_ORGANIZER')) return;

        const path = window.location.pathname.replace(/\/+$/, '') || '/';
        if (path !== '/garage') return;

        // Already injected?
        if (document.querySelector(`[${GARAGE_ORGANIZER_ATTR}]`)) return;

        // Find the "Rearrange Cars" button
        const rearrangeBtn = Array.from(document.querySelectorAll('a.btn')).find(
            el => el.textContent.trim().toLowerCase().includes('rearrange')
        );
        if (!rearrangeBtn) return;

        const btn = document.createElement('button');
        btn.setAttribute(GARAGE_ORGANIZER_ATTR, '');
        btn.style.cssText = 'margin-right:8px;cursor:pointer;background:none;border:none;padding:0;display:inline-flex;align-items:center;vertical-align:middle;';
        btn.title = 'Add garage sections (pages of 30 car slots)';
        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 showGarageModal(currentSections, totalCars);
            } catch (e) {
                console.error(TOOLKIT_LOG_PREFIX, 'Garage organizer error:', e);
            }
        });

        rearrangeBtn.parentElement.insertBefore(btn, rearrangeBtn);
    }

    // ─────────────────────────────────────────────────────────────────────────────
    // FEATURE 10: Keyboard Shortcuts (Global)
    // ─────────────────────────────────────────────────────────────────────────────
    /** Map e.code (e.g. "KeyR") to a single uppercase letter. */
    const codeToLetter = (code) => {
        if (code.startsWith('Key')) return code.slice(3).toUpperCase();
        if (code.startsWith('Digit')) return code.slice(5);
        return code.toUpperCase();
    };

    /** 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');
                return Array.isArray(raw) && raw.length > 0 ? raw : DEFAULT_SHORTCUTS;
            })();

            // Use e.code for reliable key detection (Alt/Option on Mac changes e.key)
            const pressed = codeToLetter(e.code);
            const match = shortcuts.find(s => {
                if (!s.key || s.key.toUpperCase() !== pressed) 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;
            }

            // 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();

    // ─── Main Initialization ──────────────────────────────────────────────────────
    function startToolkit() {
        initObserverManager();

        // Apply CSS-based appearance toggles immediately
        applyAppearanceStyles();

        // Listen for setting changes to re-apply appearance styles
        document.addEventListener('ntcfg:change', (e) => {
            const k = e.detail?.key || '';
            if (e.detail?.script === NTCFG_MANIFEST_ID && k.startsWith('HIDE_')) {
                applyAppearanceStyles();
            }
        });

        // Poll for global UI elements that may not exist yet when the observer first fires
        // (NT renders the nav shell asynchronously)
        let globalRetries = 0;
        const globalPoll = setInterval(() => {
            globalRetries++;
            const carDone = !readSetting('ENABLE_CAR_ICON') || document.querySelector('[' + CAR_ICON_ATTR + ']');
            const smartNotifyDone = !readSetting('SMART_SHOP_NOTIFY') || document.querySelector('[' + SMART_NOTIFY_ATTR + ']');

            try { handleCarIcon(); } catch { /* ignore */ }
            if (!smartNotifyDone && !readSetting('HIDE_NOTIFY_ALL') && !readSetting('HIDE_NOTIFY_SHOP')) {
                try { applySmartShopNotify(); } catch { /* ignore */ }
            }

            if ((carDone && smartNotifyDone) || globalRetries >= 50) {
                clearInterval(globalPoll);
            }
        }, 200);

        // Register observer callback that dispatches to feature handlers
        window.NTObserverManager.register('toolkit', () => {
            const path = window.location.pathname;

            // Global features (run on every page)
            try { handleCarIcon(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'CarIcon error:', e); }

            // Team page features
            if (path.startsWith('/team/') && document.querySelector('.table-row')) {
                try { handleBannedLabels(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'BannedLabels error:', e); }
                try { handleMOTDFilter(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'MOTDFilter error:', e); }
            }

            // Garage page features
            if (path === '/garage') {
                try { handleGarageOrganizer(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'GarageOrganizer error:', e); }
            }

            // Shop page features
            if (path === '/shop') {
                try { handleShopPreview(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'ShopPreview error:', e); }
            }

            // Modal-based features (can appear on any page with modals)
            if (document.querySelector('.modal')) {
                try { handleSendCashFormat(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'SendCash error:', e); }
                try { handleDonationLink(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'DonationLink error:', e); }
                // MOTD modal can also appear on team pages
                if (path.startsWith('/team/')) {
                    try { handleMOTDFilter(); } catch (e) { console.error(TOOLKIT_LOG_PREFIX, 'MOTDFilter modal error:', e); }
                }
            }
        });

    }

    // Wait for document.body to exist before starting
    if (document.body) {
        startToolkit();
    } else {
        const bodyWaiter = new MutationObserver((_, obs) => {
            if (document.body) {
                obs.disconnect();
                startToolkit();
            }
        });
        bodyWaiter.observe(document.documentElement, { childList: true });
    }

})();