Nitro Type Toolkit

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

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

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

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

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

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

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

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

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

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

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

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

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

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

})();