Nitro Type - Race Options

Auto Refresh, Themes, Stats Overlay and more!

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         Nitro Type - Race Options
// @namespace    https://nitrotype.info
// @version      2.1.0
// @description  Auto Refresh, Themes, Stats Overlay and more!
// @author       Captain.Loveridge
// @match        *://*.nitrotype.com/race
// @match        *://*.nitrotype.com/race/*
// @match        *://*.nitrotype.com/settings/mods*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @require      https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js#sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==
// @require      https://cdnjs.cloudflare.com/ajax/libs/dexie/3.2.1/dexie.min.js#sha512-ybuxSW2YL5rQG/JjACOUKLiosgV80VUfJWs4dOpmSWZEGwdfdsy2ldvDSQ806dDXGmg9j/csNycIbqsrcqW6tQ==
// @require      https://cdnjs.cloudflare.com/ajax/libs/interact.js/1.10.27/interact.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/pixi.js/6.5.4/browser/pixi.min.js
// @license      MIT
// ==/UserScript==

/* global Dexie moment NTGLOBALS PIXI interact */

const enableStats = GM_getValue('enableStats', true);
//// GENERAL VISUAL OPTIONS ////
const hideTrack = GM_getValue('hideTrack', false);
const hideNotifications = GM_getValue('hideNotifications', true);
const AUTO_CLOSE_REWARD_POPUP = GM_getValue('AUTO_CLOSE_REWARD_POPUP', true);
const ENABLE_MINI_MAP = GM_getValue('ENABLE_MINI_MAP', false);
const MINI_MAP_POSITION = GM_getValue('MINI_MAP_POSITION', 'bottom');
const ENABLE_ALT_WPM_COUNTER = GM_getValue('ENABLE_ALT_WPM_COUNTER', true);
const ENABLE_ALT_WPM_COUNTDOWN = GM_getValue('ENABLE_ALT_WPM_COUNTDOWN', true);
const HIDE_PREPARE_FOR_RACE_ICON = GM_getValue('HIDE_PREPARE_FOR_RACE_ICON', false);
const ENABLE_PERFECT_NITROS = GM_getValue('ENABLE_PERFECT_NITROS', true);
const ENABLE_PRECISE_ACCURACY = GM_getValue('ENABLE_PRECISE_ACCURACY', false);
const PERFECT_NITRO_HIGHLIGHT_COLOR = GM_getValue('PERFECT_NITRO_HIGHLIGHT_COLOR', '#FFFFFF');
const PERFECT_NITRO_SCAN_INTERVAL_MS = GM_getValue('PERFECT_NITRO_SCAN_INTERVAL_MS', 100);
const PERFECT_NITRO_ITALIC = GM_getValue('PERFECT_NITRO_ITALIC', false);
const PERFECT_NITRO_RAINBOW = GM_getValue('PERFECT_NITRO_RAINBOW', false);
const PERFECT_NITRO_HIGHLIGHT_OPACITY = GM_getValue('PERFECT_NITRO_HIGHLIGHT_OPACITY', 0.5);
const PERFECT_NITRO_ENABLE_HIGHLIGHT = GM_getValue('PERFECT_NITRO_ENABLE_HIGHLIGHT', true);
const PERFECT_NITRO_OVERRIDE_TEXT_COLOR = GM_getValue('PERFECT_NITRO_OVERRIDE_TEXT_COLOR', false);
const PERFECT_NITRO_TEXT_COLOR = GM_getValue('PERFECT_NITRO_TEXT_COLOR', '#FFFFFF');
const HIDE_CHAT_AND_STICKERS = GM_getValue('HIDE_CHAT_AND_STICKERS', false);
const HIDE_FINISH_FLAG = GM_getValue('HIDE_FINISH_FLAG', false);
const ENABLE_RACER_BADGES_IN_RACE = GM_getValue('ENABLE_RACER_BADGES_IN_RACE', true);
const THEME_ENABLE_DARK_MODE = GM_getValue('THEME_ENABLE_DARK_MODE', false);
const THEME_DARK_MODE_SYNC_SYSTEM = GM_getValue('THEME_DARK_MODE_SYNC_SYSTEM', false);
const THEME_COLOR_FOREGROUND = GM_getValue('THEME_COLOR_FOREGROUND', '#FFFFFF');
const THEME_COLOR_FOREGROUND_ACTIVE = GM_getValue('THEME_COLOR_FOREGROUND_ACTIVE', '#000000');
const THEME_COLOR_FOREGROUND_TYPED = GM_getValue('THEME_COLOR_FOREGROUND_TYPED', '#5B5B5B');
const THEME_COLOR_BACKGROUND = GM_getValue('THEME_COLOR_BACKGROUND', '#000000');
const THEME_COLOR_BACKGROUND_ACTIVE = GM_getValue('THEME_COLOR_BACKGROUND_ACTIVE', '#FFFFFF');
const THEME_COLOR_BACKGROUND_INCORRECT = GM_getValue('THEME_COLOR_BACKGROUND_INCORRECT', '#FF0000');
const THEME_OVERRIDE_FOREGROUND = GM_getValue('THEME_OVERRIDE_FOREGROUND', false);
const THEME_OVERRIDE_FOREGROUND_ACTIVE = GM_getValue('THEME_OVERRIDE_FOREGROUND_ACTIVE', false);
const THEME_OVERRIDE_FOREGROUND_TYPED = GM_getValue('THEME_OVERRIDE_FOREGROUND_TYPED', false);
const THEME_HIDE_TYPED_TEXT = GM_getValue('THEME_HIDE_TYPED_TEXT', false);
const THEME_OVERRIDE_BACKGROUND = GM_getValue('THEME_OVERRIDE_BACKGROUND', false);
const THEME_OVERRIDE_BACKGROUND_ACTIVE = GM_getValue('THEME_OVERRIDE_BACKGROUND_ACTIVE', false);
const THEME_OVERRIDE_BACKGROUND_INCORRECT = GM_getValue('THEME_OVERRIDE_BACKGROUND_INCORRECT', false);
const THEME_FONT_FAMILY_DEFAULT_CSS = '"Roboto Mono", "Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace';
const THEME_FONT_WEIGHT_DEFAULT = 400;
const THEME_FONT_BOLD = GM_getValue('THEME_FONT_BOLD', false);
const THEME_FONT_WEIGHT = GM_getValue('THEME_FONT_WEIGHT', 700);
const THEME_FONT_ITALIC = GM_getValue('THEME_FONT_ITALIC', false);
const THEME_DARK_MODE_FOREGROUND = "#E7EEF8";
const THEME_DARK_MODE_FOREGROUND_ACTIVE = "#101623";
const THEME_DARK_MODE_FOREGROUND_TYPED = "#8FA3BA";
const THEME_DARK_MODE_BACKGROUND = "#0A121E";
const THEME_DARK_MODE_BACKGROUND_ACTIVE = "#1C99F4";
const THEME_DARK_MODE_BACKGROUND_INCORRECT = "#D62F3A";
const THEME_FONT_FAMILY_PRESET = GM_getValue('THEME_FONT_FAMILY_PRESET', "__default__");
const THEME_FONT_SIZE_PRESET = GM_getValue('THEME_FONT_SIZE_PRESET', "__default__");
const THEME_SINGLE_LINE_FONT_SIZE_PRESET = GM_getValue('THEME_SINGLE_LINE_FONT_SIZE_PRESET', "__default__");
const THEME_ENABLE_RAINBOW_TYPED_TEXT = GM_getValue('THEME_ENABLE_RAINBOW_TYPED_TEXT', false);
const THEME_RAINBOW_TYPED_TEXT_SPEED_SECONDS = GM_getValue('THEME_RAINBOW_TYPED_TEXT_SPEED_SECONDS', 10);

////// AUTO RELOAD OPTIONS /////
const greedyStatsReload = GM_getValue('greedyStatsReload', true);
const MIN_PERFECT_NITRO_SCAN_INTERVAL_MS = 100;
const COUNTDOWN_TICK_INTERVAL_MS = 50;
const greedyStatsReloadInt = GM_getValue('greedyStatsReloadInt', 50);

const reloadOnStats = GM_getValue('reloadOnStats', true);

//// BETTER STATS OPTIONS /////
const RACES_OUTSIDE_CURRENT_TEAM = GM_getValue('RACES_OUTSIDE_CURRENT_TEAM', 0);
const TEAM_RACES_BUGGED = GM_getValue('TEAM_RACES_BUGGED', 0);

const config = {
    ///// ALT WPM COUNTER CONFIG //////
    targetWPM: GM_getValue('targetWPM', 79.5),
    indicateWPMWithin: GM_getValue('indicateWPMWithin', 2),
    timerRefreshIntervalMS: GM_getValue('timerRefreshIntervalMS', 25),
    dif: GM_getValue('dif', 0.8),

    raceLatencyMS: 140,

    ///// CUSTOM MINIMAP CONFIG ////// (hardcoded)
    colors: {
        me: 0xD62F3A,
        opponentPlayer: 0x167AC3,
        opponentBot: 0xbbbbbb,
        opponentWampus: 0xFFA500,
        nitro: 0xef9e18,
        raceLane: 0x555555,
        startLine: 0x929292,
        finishLine: 0x929292
    },
    trackLocally: true,
    moveDestination: {
        enabled: true,
        alpha: 0.3,
    }
};

const THEME_FONT_FAMILY_PRESETS = [
    { value: "__default__", label: "Default", css: THEME_FONT_FAMILY_DEFAULT_CSS },
    { value: "roboto_mono", label: "Roboto Mono", css: '"Roboto Mono", "Courier New", Courier, monospace' },
    { value: "montserrat", label: "Montserrat", css: '"Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif' },
    { value: "poppins", label: "Poppins", css: '"Poppins", "Segoe UI", Tahoma, sans-serif' },
    { value: "nunito", label: "Nunito", css: '"Nunito", "Trebuchet MS", sans-serif' },
    { value: "oswald", label: "Oswald", css: '"Oswald", "Arial Narrow", sans-serif' },
    { value: "space_mono", label: "Space Mono", css: '"Space Mono", "Courier New", monospace' },
];

const THEME_FONT_SIZE_PRESETS = [
    { value: "__default__", label: "Default", px: 18 },
    { value: "8", label: "8px", px: 8 },
    { value: "10", label: "10px", px: 10 },
    { value: "12", label: "12px", px: 12 },
    { value: "14", label: "14px", px: 14 },
    { value: "16", label: "16px", px: 16 },
    { value: "18", label: "18px", px: 18 },
    { value: "20", label: "20px", px: 20 },
    { value: "24", label: "24px", px: 24 },
    { value: "28", label: "28px", px: 28 },
    { value: "32", label: "32px", px: 32 },
    { value: "36", label: "36px", px: 36 },
];

const RACER_BADGES_RACE_TOGGLE_KEY = "ntcfg_racer_badges_in_race_enabled";
const syncRacerBadgesRaceToggle = (enabled) => {
    try {
        localStorage.setItem(RACER_BADGES_RACE_TOGGLE_KEY, enabled ? "1" : "0");
    } catch {
        // ignore storage errors
    }
};

syncRacerBadgesRaceToggle(ENABLE_RACER_BADGES_IN_RACE);

const normalizeHexColorValue = (value, fallback = "#FFFFFF") => {
    const normalizedFallback = /^#[0-9A-Fa-f]{6}$/.test(String(fallback || "").trim())
        ? String(fallback).toUpperCase()
        : "#FFFFFF";
    const raw = String(value || "").trim();
    if (/^#[0-9A-Fa-f]{6}$/.test(raw)) {
        return raw.toUpperCase();
    }
    if (/^#[0-9A-Fa-f]{3}$/.test(raw)) {
        return `#${raw[1]}${raw[1]}${raw[2]}${raw[2]}${raw[3]}${raw[3]}`.toUpperCase();
    }
    return normalizedFallback;
};

const hexToRgba = (hex, alpha = 1) => {
    const h = normalizeHexColorValue(hex, "#FFFFFF");
    const r = parseInt(h.slice(1, 3), 16);
    const g = parseInt(h.slice(3, 5), 16);
    const b = parseInt(h.slice(5, 7), 16);
    return `rgba(${r}, ${g}, ${b}, ${Math.min(1, Math.max(0, alpha))})`;
};

const hexToRgbChannels = (hex) => {
    const h = normalizeHexColorValue(hex, "#FFFFFF");
    return [parseInt(h.slice(1, 3), 16), parseInt(h.slice(3, 5), 16), parseInt(h.slice(5, 7), 16)];
};

const blendedLuminance = (fgHex, bgHex, alpha) => {
    const [fr, fg, fb] = hexToRgbChannels(fgHex);
    const [br, bg, bb] = hexToRgbChannels(bgHex);
    const a = Math.min(1, Math.max(0, alpha));
    const r = (fr * a + br * (1 - a)) / 255;
    const g = (fg * a + bg * (1 - a)) / 255;
    const b = (fb * a + bb * (1 - a)) / 255;
    const linear = (ch) => (ch <= 0.03928 ? ch / 12.92 : Math.pow((ch + 0.055) / 1.055, 2.4));
    return (0.2126 * linear(r)) + (0.7152 * linear(g)) + (0.0722 * linear(b));
};

const normalizeHighlightOpacity = (value, fallback = 0.5) => {
    const parsed = Number(value);
    if (!Number.isFinite(parsed)) return Number(fallback) || 0.5;
    return Math.min(1, Math.max(0.05, Math.round(parsed * 100) / 100));
};

const normalizeRainbowSpeedSeconds = (value, fallback = 10) => {
    const normalizedFallback = Number.isFinite(Number(fallback)) ? Number(fallback) : 10;
    const parsed = Number(value);
    if (!Number.isFinite(parsed)) {
        return normalizedFallback;
    }
    return Math.min(60, Math.max(1, parsed));
};

const normalizeThemeFontSizePx = (value, fallback = 18) => {
    const normalizedFallback = Number.isFinite(Number(fallback)) ? Number(fallback) : 18;
    const parsed = Number(value);
    if (!Number.isFinite(parsed)) {
        return normalizedFallback;
    }
    return Math.min(72, Math.max(8, Math.round(parsed)));
};

const normalizeThemeFontFamilyValue = (value, fallback = THEME_FONT_FAMILY_DEFAULT_CSS) => {
    const raw = String(value ?? "").trim();
    if (!raw) {
        return String(fallback);
    }
    const cleaned = raw.replace(/[{}<>;\r\n]/g, "").trim().slice(0, 180);
    return cleaned || String(fallback);
};

const normalizeThemePresetValue = (value, presets, fallback = "__default__") => {
    const raw = String(value ?? "").trim();
    if (Array.isArray(presets) && presets.some((preset) => preset?.value === raw)) {
        return raw;
    }
    return fallback;
};

const normalizeMiniMapPositionValue = (value, fallback = "bottom") => {
    const normalizedFallback = String(fallback || "").trim().toLowerCase() === "top" ? "top" : "bottom";
    const raw = String(value || "").trim().toLowerCase();
    if (raw === "top" || raw === "bottom") {
        return raw;
    }
    return normalizedFallback;
};

const NTCFG_MOD_MENU_PATH = "/settings/mods";
const NTCFG_RACE_OPTIONS_MANIFEST_ID = "race-options";
const NTCFG_RACE_OPTIONS_MANIFEST_KEY = `ntcfg:manifest:${NTCFG_RACE_OPTIONS_MANIFEST_ID}`;
const NTCFG_RACE_OPTIONS_VALUE_PREFIX = `ntcfg:${NTCFG_RACE_OPTIONS_MANIFEST_ID}:`;
const NTCFG_RACE_OPTIONS_BRIDGE_VERSION = "1.0.0-bridge.3";
const RACE_OPTIONS_STORAGE_VERSION = 1;
const RACE_OPTIONS_STORAGE_VERSION_KEY = `${NTCFG_RACE_OPTIONS_VALUE_PREFIX}__storage_version`;
const NTCFG_RACE_OPTIONS_SETTING_SYNC_EVENT = "NTCFG_RACE_OPTIONS_SETTING_SYNC";
const isNtcfgRaceOptionsModMenuRoute = () => location.pathname === NTCFG_MOD_MENU_PATH || location.pathname.startsWith(`${NTCFG_MOD_MENU_PATH}/`);
const isNtcfgRaceOptionsRaceRoute = () => /^\/race(?:\/|$)/.test(location.pathname);
const mapPresetOptionsForManifest = (presets) => presets.map((preset) => ({
    value: preset.value,
    label: preset.label
}));

const RACE_OPTIONS_SHARED_SETTINGS = {
    hideTrack: {
        type: "boolean",
        label: "Hide Track",
        default: false,
        group: "General",
        description: "Hides the visual racetrack area to reduce on-screen clutter."
    },
    hideNotifications: {
        type: "boolean",
        label: "Hide Notifications",
        default: true,
        group: "General",
        description: "Blocks growl popups during races."
    },
    AUTO_CLOSE_REWARD_POPUP: {
        type: "boolean",
        label: "Auto close reward popup",
        default: true,
        group: "General",
        description: "Automatically dismisses reward and takeover popups if they appear."
    },
    HIDE_PREPARE_FOR_RACE_ICON: {
        type: "boolean",
        label: 'Hide "Prepare for your race" floating icon',
        default: false,
        group: "General",
        description: "Removes the floating prep icon overlay."
    },
    ENABLE_MINI_MAP: {
        type: "boolean",
        label: "Enable Mini Map",
        default: false,
        group: "General",
        description: "Shows a compact lane map on the race page."
    },
    MINI_MAP_POSITION: {
        type: "select",
        label: "Mini Map Position",
        default: "bottom",
        group: "General",
        description: "Choose where the mini map appears relative to the race track.",
        options: [
            { value: "bottom", label: "Bottom (below track)" },
            { value: "top", label: "Top (above track)" }
        ],
        visibleWhen: { key: "ENABLE_MINI_MAP", eq: true }
    },
    ENABLE_RACER_BADGES_IN_RACE: {
        type: "boolean",
        label: "Enable Racer Badges (In-Race)",
        default: true,
        group: "General",
        description: "Controls whether Racer Badges injects race nameplate badges."
    },
    HIDE_CHAT_AND_STICKERS: {
        type: "boolean",
        label: "Hide Chat and Stickers",
        default: false,
        group: "General",
        description: "Hides the in-race chat and sticker panel."
    },
    HIDE_FINISH_FLAG: {
        type: "boolean",
        label: "Hide Finish Flag",
        default: false,
        group: "General",
        description: "Hides the finish flag icon in the race text."
    },
    reloadOnStats: {
        type: "boolean",
        label: "Enable Auto Reload",
        default: true,
        group: "Auto Reload",
        description: "Reload the page after results update."
    },
    greedyStatsReload: {
        type: "boolean",
        label: "Enable FAST RELOAD",
        default: true,
        group: "Auto Reload",
        description: "Aggressively checks for result updates to reload sooner."
    },
    greedyStatsReloadInt: {
        type: "number",
        label: "FAST RELOAD - Check Interval",
        default: 50,
        group: "Auto Reload",
        description: "How often FAST RELOAD checks for updates (milliseconds). Lower is faster but heavier.",
        min: 1,
        max: 1000,
        step: 1,
        warn: { below: 50, message: "Warning: values below 50ms can cause stats to fail to save. 50ms is the fastest recommended setting." }
    },
    enableStats: {
        type: "boolean",
        label: "Enable Stats",
        default: true,
        group: "Stats",
        description: "Shows the custom Racing Stats panel."
    },
    ENABLE_PRECISE_ACCURACY: {
        type: "boolean",
        label: "Enable Precise Accuracy",
        default: false,
        group: "Stats",
        description: "Uses full-text error math for the live in-race accuracy metric."
    },
    RACES_OUTSIDE_CURRENT_TEAM: {
        type: "number",
        label: "Races Outside Current Team",
        default: 0,
        group: "Stats",
        description: "Subtract races done outside your current team from team-race math.",
        min: 0,
        max: 999999,
        step: 1
    },
    TEAM_RACES_BUGGED: {
        type: "number",
        label: "Bugged team count (0 if no)",
        default: 0,
        group: "Stats",
        description: "Manual correction added to team race totals when Nitro Type data is wrong.",
        min: 0,
        max: 999999,
        step: 1
    },
    ENABLE_ALT_WPM_COUNTER: {
        type: "boolean",
        label: "Enable Alt. WPM",
        default: true,
        group: "Alt. WPM",
        description: "Shows the draggable pace helper during the race. Countdown can be toggled separately."
    },
    ENABLE_ALT_WPM_COUNTDOWN: {
        type: "boolean",
        label: "Enable Countdown",
        default: true,
        group: "Alt. WPM",
        description: "Shows the draggable race-start countdown even if Alt. WPM is turned off."
    },
    targetWPM: {
        type: "number",
        label: "Target WPM (1 = No Sandbagging)",
        default: 79.5,
        group: "Alt. WPM",
        description: "Your pacing target. Lower values encourage slower controlled finishes.",
        visibleWhen: { key: "ENABLE_ALT_WPM_COUNTER", eq: true },
        min: 1,
        max: 300,
        step: 0.1
    },
    indicateWPMWithin: {
        type: "number",
        label: "Alt. WPM: Yellow when +X WPM",
        default: 2,
        group: "Alt. WPM",
        description: "Highlight threshold near your target WPM.",
        visibleWhen: { key: "ENABLE_ALT_WPM_COUNTER", eq: true },
        min: 0,
        max: 30,
        step: 0.1
    },
    timerRefreshIntervalMS: {
        type: "number",
        label: "Alt. WPM: Refresh int.",
        default: 25,
        group: "Alt. WPM",
        description: "How often the helper updates in milliseconds.",
        visibleWhen: { key: "ENABLE_ALT_WPM_COUNTER", eq: true },
        min: 5,
        max: 1000,
        step: 1
    },
    dif: {
        type: "number",
        label: "Alt. WPM: +X WPM Delay",
        default: 0.8,
        group: "Alt. WPM",
        description: "Small offset applied to displayed possible WPM.",
        visibleWhen: { key: "ENABLE_ALT_WPM_COUNTER", eq: true },
        min: 0,
        max: 30,
        step: 0.1
    },
    ENABLE_PERFECT_NITROS: {
        type: "boolean",
        label: "Enable Perfect Nitros",
        default: true,
        group: "Perfect Nitros",
        description: "Highlights the best long-word nitro target."
    },
    PERFECT_NITRO_ENABLE_HIGHLIGHT: {
        type: "boolean",
        label: "Highlight background",
        default: true,
        group: "Perfect Nitros",
        description: "Background color and opacity for the perfect nitro word.",
        compound: [
            { type: "color", key: "PERFECT_NITRO_HIGHLIGHT_COLOR", default: "#FFFFFF" },
            {
                type: "select", key: "PERFECT_NITRO_HIGHLIGHT_OPACITY", default: 0.5, options: [
                    { value: 0.25, label: "25%" },
                    { value: 0.5, label: "50%" },
                    { value: 0.75, label: "75%" },
                    { value: 1, label: "100%" }
                ]
            }
        ]
    },
    PERFECT_NITRO_HIGHLIGHT_COLOR: {
        type: "color",
        label: "Perfect Nitro Highlight Color",
        default: "#FFFFFF",
        group: "Perfect Nitros",
        description: "Background color for the perfect nitro word."
    },
    PERFECT_NITRO_HIGHLIGHT_OPACITY: {
        type: "select",
        label: "Perfect Nitro Highlight Opacity",
        default: 0.5,
        group: "Perfect Nitros",
        description: "Background opacity for the perfect nitro word.",
        options: [
            { value: 0.25, label: "25%" },
            { value: 0.5, label: "50%" },
            { value: 0.75, label: "75%" },
            { value: 1, label: "100%" }
        ]
    },
    PERFECT_NITRO_OVERRIDE_TEXT_COLOR: {
        type: "boolean",
        label: "Text color",
        default: false,
        group: "Perfect Nitros",
        description: "Custom text color instead of auto-contrast.",
        compound: [
            { type: "color", key: "PERFECT_NITRO_TEXT_COLOR", default: "#FFFFFF" }
        ]
    },
    PERFECT_NITRO_TEXT_COLOR: {
        type: "color",
        label: "Perfect Nitro Text Color",
        default: "#FFFFFF",
        group: "Perfect Nitros",
        description: "Custom text color for the highlighted perfect nitro word."
    },
    PERFECT_NITRO_ITALIC: {
        type: "boolean",
        label: "Italic Perfect Nitro Word",
        default: false,
        group: "Perfect Nitros",
        description: "Applies italic styling to the highlighted perfect nitro word."
    },
    PERFECT_NITRO_RAINBOW: {
        type: "boolean",
        label: "Rainbow Perfect Nitro Word",
        default: false,
        group: "Perfect Nitros",
        description: "Applies a cycling rainbow animation to the highlighted perfect nitro word."
    },
    PERFECT_NITRO_SCAN_INTERVAL_MS: {
        type: "number",
        label: "Perfect Nitro Scan Interval (ms)",
        default: 100,
        group: "Perfect Nitros",
        description: "How frequently to scan for the best nitro word.",
        min: 25,
        max: 5000,
        step: 1
    },
    THEME_ENABLE_DARK_MODE: {
        type: "boolean",
        label: "Dark mode",
        default: false,
        group: "Theme",
        description: "Uses the darker theme palette on the race page.",
        compound: [
            {
                type: "select", key: "THEME_DARK_MODE_SYNC_SYSTEM", default: "always", options: [
                    { value: "always", label: "Always" },
                    { value: "system", label: "Same as system" }
                ]
            }
        ]
    },
    THEME_DARK_MODE_SYNC_SYSTEM: {
        type: "boolean",
        label: "Sync Dark Mode with System",
        default: false,
        group: "Theme",
        description: "Automatically follows your operating system dark mode."
    },
    THEME_FONT_FAMILY_PRESET: {
        type: "select",
        label: "Font family",
        default: "__default__",
        group: "Theme",
        description: "Preview typography for the race text.",
        options: mapPresetOptionsForManifest(THEME_FONT_FAMILY_PRESETS)
    },
    THEME_FONT_SIZE_PRESET: {
        type: "select",
        label: "Font size",
        default: "__default__",
        group: "Theme",
        description: "Applies a preset font size to multi-line race text.",
        options: mapPresetOptionsForManifest(THEME_FONT_SIZE_PRESETS)
    },
    THEME_SINGLE_LINE_FONT_SIZE_PRESET: {
        type: "select",
        label: "Single-line font size",
        default: "__default__",
        group: "Theme",
        description: "Applies a preset font size when single-line mode is enabled.",
        options: mapPresetOptionsForManifest(THEME_FONT_SIZE_PRESETS)
    },
    THEME_FONT_BOLD: {
        type: "boolean",
        label: "Bold text",
        default: false,
        group: "Theme",
        description: "Applies bold styling to the race text.",
        compound: [
            {
                type: "select", key: "THEME_FONT_WEIGHT", default: 700, options: [
                    { value: 300, label: "Light" },
                    { value: 500, label: "Medium" },
                    { value: 600, label: "Semi-Bold" },
                    { value: 700, label: "Bold" },
                    { value: 800, label: "Extra-Bold" },
                    { value: 900, label: "Black" }
                ]
            }
        ]
    },
    THEME_FONT_WEIGHT: {
        type: "select",
        label: "Font weight",
        default: 700,
        group: "Theme",
        description: "Controls the weight used when bold text is enabled.",
        options: [
            { value: 300, label: "Light" },
            { value: 500, label: "Medium" },
            { value: 600, label: "Semi-Bold" },
            { value: 700, label: "Bold" },
            { value: 800, label: "Extra-Bold" },
            { value: 900, label: "Black" }
        ]
    },
    THEME_FONT_ITALIC: {
        type: "boolean",
        label: "Italic text",
        default: false,
        group: "Theme",
        description: "Applies italic styling to the race text."
    },
    THEME_OVERRIDE_BACKGROUND: {
        type: "boolean",
        label: "Background color",
        default: false,
        group: "Theme",
        description: "Enables a custom text area background.",
        compound: [
            { type: "color", key: "THEME_COLOR_BACKGROUND", default: "#000000" }
        ]
    },
    THEME_COLOR_BACKGROUND: {
        type: "color",
        label: "Background Color",
        default: "#000000",
        group: "Theme",
        description: "Main background color used for text theming."
    },
    THEME_OVERRIDE_FOREGROUND: {
        type: "boolean",
        label: "Text color",
        default: false,
        group: "Theme",
        description: "Enables a custom text color for upcoming letters.",
        compound: [
            { type: "color", key: "THEME_COLOR_FOREGROUND", default: "#FFFFFF" }
        ]
    },
    THEME_COLOR_FOREGROUND: {
        type: "color",
        label: "Foreground Color",
        default: "#FFFFFF",
        group: "Theme",
        description: "Main text color for upcoming characters."
    },
    THEME_OVERRIDE_FOREGROUND_ACTIVE: {
        type: "boolean",
        label: "Active letter color",
        default: false,
        group: "Theme",
        description: "Enables a custom foreground for the active letter.",
        compound: [
            { type: "color", key: "THEME_COLOR_FOREGROUND_ACTIVE", default: "#000000" }
        ]
    },
    THEME_COLOR_FOREGROUND_ACTIVE: {
        type: "color",
        label: "Active Foreground Color",
        default: "#000000",
        group: "Theme",
        description: "Foreground color for the active character."
    },
    THEME_OVERRIDE_BACKGROUND_ACTIVE: {
        type: "boolean",
        label: "Active letter background",
        default: false,
        group: "Theme",
        description: "Enables a custom background behind the active letter.",
        compound: [
            { type: "color", key: "THEME_COLOR_BACKGROUND_ACTIVE", default: "#FFFFFF" }
        ]
    },
    THEME_COLOR_BACKGROUND_ACTIVE: {
        type: "color",
        label: "Active Background Color",
        default: "#FFFFFF",
        group: "Theme",
        description: "Background color for the active character."
    },
    THEME_OVERRIDE_FOREGROUND_TYPED: {
        type: "boolean",
        label: "Typed letter color",
        default: false,
        group: "Theme",
        description: "Enables a custom foreground for typed text.",
        compound: [
            { type: "color", key: "THEME_COLOR_FOREGROUND_TYPED", default: "#5B5B5B" }
        ]
    },
    THEME_COLOR_FOREGROUND_TYPED: {
        type: "color",
        label: "Typed Foreground Color",
        default: "#5B5B5B",
        group: "Theme",
        description: "Foreground color for typed text."
    },
    THEME_OVERRIDE_BACKGROUND_INCORRECT: {
        type: "boolean",
        label: "Incorrect letter background",
        default: false,
        group: "Theme",
        description: "Enables a custom background for incorrect letters.",
        compound: [
            { type: "color", key: "THEME_COLOR_BACKGROUND_INCORRECT", default: "#FF0000" }
        ]
    },
    THEME_COLOR_BACKGROUND_INCORRECT: {
        type: "color",
        label: "Incorrect Background Color",
        default: "#FF0000",
        group: "Theme",
        description: "Background color for incorrect characters."
    },
    THEME_HIDE_TYPED_TEXT: {
        type: "boolean",
        label: "Hide typed letters",
        default: false,
        group: "Theme",
        description: "Makes completed text invisible while racing."
    },
    THEME_ENABLE_RAINBOW_TYPED_TEXT: {
        type: "boolean",
        label: "Rainbow typed text",
        default: false,
        group: "Theme",
        description: "Applies animated color cycling to typed text."
    },
    THEME_RAINBOW_TYPED_TEXT_SPEED_SECONDS: {
        type: "number",
        label: "Rainbow speed (seconds)",
        default: 10,
        group: "Theme",
        description: "Controls how quickly the typed text rainbow animation cycles.",
        min: 1,
        max: 60,
        step: 0.5,
        visibleWhen: { key: "THEME_ENABLE_RAINBOW_TYPED_TEXT", eq: true },
        presets: [
            { label: "Fast", value: 5 },
            { label: "Normal", value: 10 },
            { label: "Slow", value: 15 },
            { label: "Very Slow", value: 25 }
        ]
    },
    DEBUG_LOGGING: {
        type: "boolean",
        label: "Debug Logging",
        default: false,
        group: "Advanced",
        description: "Enable verbose console logging for troubleshooting."
    }
};

const getNtcfgRaceOptionsStorageKey = (settingKey) => `${NTCFG_RACE_OPTIONS_VALUE_PREFIX}${settingKey}`;

const normalizeNtcfgRaceOptionsNumber = (value, meta) => {
    const fallback = Number(meta.default);
    const parsed = Number(value);
    let normalized = Number.isFinite(parsed) ? parsed : fallback;
    const min = Number(meta.min);
    const max = Number(meta.max);
    const step = Number(meta.step);

    if (Number.isFinite(step) && step >= 1) {
        normalized = Math.round(normalized);
    }
    if (Number.isFinite(min)) {
        normalized = Math.max(min, normalized);
    }
    if (Number.isFinite(max)) {
        normalized = Math.min(max, normalized);
    }
    return normalized;
};

const coerceNtcfgRaceOptionsValue = (settingKey, value) => {
    const meta = RACE_OPTIONS_SHARED_SETTINGS[settingKey];
    if (!meta) return value;

    if (settingKey === "MINI_MAP_POSITION") {
        return normalizeMiniMapPositionValue(value, meta.default);
    }
    if (settingKey === "THEME_FONT_FAMILY_PRESET") {
        return normalizeThemePresetValue(value, THEME_FONT_FAMILY_PRESETS, meta.default);
    }
    if (settingKey === "THEME_FONT_SIZE_PRESET") {
        return normalizeThemePresetValue(value, THEME_FONT_SIZE_PRESETS, meta.default);
    }
    if (settingKey === "THEME_SINGLE_LINE_FONT_SIZE_PRESET") {
        return normalizeThemePresetValue(value, THEME_FONT_SIZE_PRESETS, meta.default);
    }
    if (settingKey === "THEME_FONT_WEIGHT") {
        return Math.min(900, Math.max(100, Math.round(normalizeNtcfgRaceOptionsNumber(value, meta) || meta.default)));
    }
    if (settingKey === "PERFECT_NITRO_HIGHLIGHT_OPACITY") {
        return normalizeHighlightOpacity(value, meta.default);
    }
    if (settingKey === "THEME_RAINBOW_TYPED_TEXT_SPEED_SECONDS") {
        return normalizeRainbowSpeedSeconds(value, meta.default);
    }

    if (meta.type === "boolean") {
        if (typeof value === "string") {
            const raw = value.trim().toLowerCase();
            if (raw === "false" || raw === "0" || raw === "off") return false;
            if (raw === "true" || raw === "1" || raw === "on") return true;
        }
        return !!value;
    }
    if (meta.type === "color") {
        return normalizeHexColorValue(value, meta.default);
    }
    if (meta.type === "number") {
        return normalizeNtcfgRaceOptionsNumber(value, meta);
    }
    if (meta.type === "select") {
        const raw = String(value ?? "").trim();
        const options = Array.isArray(meta.options) ? meta.options : [];
        return options.some((option) => String(option.value) === raw) ? raw : meta.default;
    }
    return String(value ?? meta.default);
};

const writeNtcfgRaceOptionsValue = (settingKey, value) => {
    try {
        const serialized = JSON.stringify(value);
        if (localStorage.getItem(getNtcfgRaceOptionsStorageKey(settingKey)) !== serialized) {
            localStorage.setItem(getNtcfgRaceOptionsStorageKey(settingKey), serialized);
        }
    } catch {
        // ignore storage sync failures
    }
};

const readNtcfgRaceOptionsValue = (settingKey) => {
    const meta = RACE_OPTIONS_SHARED_SETTINGS[settingKey];
    if (!meta) return undefined;

    try {
        const normalized = coerceNtcfgRaceOptionsValue(settingKey, GM_getValue(settingKey, meta.default));
        writeNtcfgRaceOptionsValue(settingKey, normalized);
        return normalized;
    } catch {
        try {
            const raw = localStorage.getItem(getNtcfgRaceOptionsStorageKey(settingKey));
            if (raw == null) return meta.default;
            return coerceNtcfgRaceOptionsValue(settingKey, JSON.parse(raw));
        } catch {
            return meta.default;
        }
    }
};

const dispatchNtcfgRaceOptionsSettingSync = (settingKey, value) => {
    try {
        window.dispatchEvent(new CustomEvent(NTCFG_RACE_OPTIONS_SETTING_SYNC_EVENT, {
            detail: {
                key: settingKey,
                value
            }
        }));
    } catch {
        // ignore sync event failures
    }
};

const syncNtcfgRaceOptionsSettingFromGM = (settingKey) => {
    const meta = RACE_OPTIONS_SHARED_SETTINGS[settingKey];
    if (!meta) return;

    const normalized = coerceNtcfgRaceOptionsValue(settingKey, GM_getValue(settingKey, meta.default));
    writeNtcfgRaceOptionsValue(settingKey, normalized);
    if (settingKey === "ENABLE_RACER_BADGES_IN_RACE") {
        syncRacerBadgesRaceToggle(normalized);
    }
};

const syncAllNtcfgRaceOptionsSettingsFromGM = () => {
    Object.keys(RACE_OPTIONS_SHARED_SETTINGS).forEach(syncNtcfgRaceOptionsSettingFromGM);
};

const registerNtcfgRaceOptionsManifest = () => {
    try {
        const manifest = {
            id: NTCFG_RACE_OPTIONS_MANIFEST_ID,
            name: "Race Options",
            version: NTCFG_RACE_OPTIONS_BRIDGE_VERSION,
            scriptVersion: typeof GM_info !== 'undefined' ? GM_info.script.version : '',
            storageVersion: RACE_OPTIONS_STORAGE_VERSION,
            supportsGlobalReset: true,
            description: "Race overlays, pacing tools, and theme controls for the race screen.",
            sections: [
                { id: 'general', title: 'General', subtitle: 'Visual behavior and quality-of-life controls.', resetButton: true },
                { id: 'auto-reload', title: 'Auto Reload', subtitle: 'Race-end refresh controls.', resetButton: true },
                { id: 'stats', title: 'Stats', subtitle: 'Adjust stat correction and offset values.', resetButton: true },
                { id: 'alt-wpm', title: 'Alt. WPM', subtitle: 'Countdown and pace helper settings.', resetButton: true },
                { id: 'perfect-nitros', title: 'Perfect Nitros', subtitle: 'Longest-word highlight settings.', resetButton: true, preview: { type: 'perfect-nitro' } },
                { id: 'theme', title: 'Theme', subtitle: 'Customize the colors on the racetrack.', resetButton: true, preview: { type: 'theme' } },
                { id: 'advanced', title: 'Advanced', subtitle: 'Debug and diagnostic controls.', resetButton: true }
            ],
            settings: RACE_OPTIONS_SHARED_SETTINGS
        };
        const serialized = JSON.stringify(manifest);
        if (localStorage.getItem(NTCFG_RACE_OPTIONS_MANIFEST_KEY) !== serialized) {
            localStorage.setItem(NTCFG_RACE_OPTIONS_MANIFEST_KEY, serialized);
        }
    } catch {
        // ignore manifest registration failures
    }
};

const setNtcfgRaceOptionsValue = (settingKey, value) => {
    const meta = RACE_OPTIONS_SHARED_SETTINGS[settingKey];
    if (!meta) {
        GM_setValue(settingKey, value);
        dispatchNtcfgRaceOptionsSettingSync(settingKey, value);
        return value;
    }

    const normalized = coerceNtcfgRaceOptionsValue(settingKey, value);
    GM_setValue(settingKey, normalized);
    if (settingKey === "ENABLE_RACER_BADGES_IN_RACE") {
        syncRacerBadgesRaceToggle(normalized);
    }
    writeNtcfgRaceOptionsValue(settingKey, normalized);
    dispatchNtcfgRaceOptionsSettingSync(settingKey, normalized);
    return normalized;
};

// Direct apply: always writes through to GM (used for same-tab ntcfg:change events from mod menu)
const applyNtcfgRaceOptionsValueDirect = (settingKey, value) => {
    const meta = RACE_OPTIONS_SHARED_SETTINGS[settingKey];
    if (!meta) return;
    const normalized = coerceNtcfgRaceOptionsValue(settingKey, value);
    setNtcfgRaceOptionsValue(settingKey, normalized);
};

// Deduped apply: compares against GM before writing (used for cross-tab storage events)
const applyNtcfgRaceOptionsValueIfChanged = (settingKey, value) => {
    const meta = RACE_OPTIONS_SHARED_SETTINGS[settingKey];
    if (!meta) return;

    const normalized = coerceNtcfgRaceOptionsValue(settingKey, value);
    const currentValue = coerceNtcfgRaceOptionsValue(settingKey, GM_getValue(settingKey, meta.default));

    if (JSON.stringify(currentValue) !== JSON.stringify(normalized)) {
        setNtcfgRaceOptionsValue(settingKey, normalized);
    }
};

const dispatchRaceOptionsActionResult = (requestId, status, error = "") => {
    if (!requestId) return;
    try {
        document.dispatchEvent(new CustomEvent("ntcfg:action-result", {
            detail: {
                requestId,
                script: NTCFG_RACE_OPTIONS_MANIFEST_ID,
                status,
                error
            }
        }));
    } catch {
        // ignore dispatch failures
    }
};

const resetRaceOptionsSettingsToDefaults = () => {
    Object.entries(RACE_OPTIONS_SHARED_SETTINGS).forEach(([settingKey, meta]) => {
        if (!meta || meta.type === 'note' || meta.type === 'action') return;
        setNtcfgRaceOptionsValue(settingKey, meta.default);
    });
    try { GM_deleteValue('savedTimestamp'); } catch { /* ignore */ }
    try { localStorage.removeItem('nt_sandbagging_tool'); } catch { /* ignore */ }
};

document.addEventListener("ntcfg:change", (event) => {
    if (event?.detail?.script !== NTCFG_RACE_OPTIONS_MANIFEST_ID) return;
    applyNtcfgRaceOptionsValueDirect(event.detail.key, event.detail.value);
});

document.addEventListener("ntcfg:action", (event) => {
    const detail = event?.detail || {};
    if (detail.script !== '*') return;
    if (detail.key !== 'clear-settings' || detail.scope !== 'prefs+caches') return;
    try {
        resetRaceOptionsSettingsToDefaults();
        GM_setValue(RACE_OPTIONS_STORAGE_VERSION_KEY, RACE_OPTIONS_STORAGE_VERSION);
        registerNtcfgRaceOptionsManifest();
        syncAllNtcfgRaceOptionsSettingsFromGM();
        document.dispatchEvent(new CustomEvent("ntcfg:manifest-updated", {
            detail: { script: NTCFG_RACE_OPTIONS_MANIFEST_ID }
        }));
        dispatchRaceOptionsActionResult(detail.requestId, 'success');
    } catch (error) {
        dispatchRaceOptionsActionResult(detail.requestId, 'error', error?.message || String(error));
    }
});

window.addEventListener("storage", (event) => {
    const storageKey = String(event?.key || "");
    if (!storageKey.startsWith(NTCFG_RACE_OPTIONS_VALUE_PREFIX) || event.newValue == null) return;

    const settingKey = storageKey.slice(NTCFG_RACE_OPTIONS_VALUE_PREFIX.length);
    if (!RACE_OPTIONS_SHARED_SETTINGS[settingKey]) return;

    try {
        applyNtcfgRaceOptionsValueIfChanged(settingKey, JSON.parse(event.newValue));
    } catch {
        // ignore invalid synced payloads
    }
});

registerNtcfgRaceOptionsManifest();
syncAllNtcfgRaceOptionsSettingsFromGM();
try { GM_setValue(RACE_OPTIONS_STORAGE_VERSION_KEY, RACE_OPTIONS_STORAGE_VERSION); } catch { /* ignore */ }

// Alive signal — write BEFORE dispatching manifest-updated so the mod menu
// sees this script as alive when it re-renders in response to the event.
try { localStorage.setItem('ntcfg:alive:' + NTCFG_RACE_OPTIONS_MANIFEST_ID, String(Date.now())); } catch { /* ignore */ }

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

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

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

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

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

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

    hostWindow.NTRouteHelper = helper;
    return helper;
}

const ntRaceOptionsRouteHelper = initNTRouteHelper(window);
let ntRaceOptionsPendingReload = false;

if (!isNtcfgRaceOptionsRaceRoute()) {
    ntRaceOptionsRouteHelper.subscribe(() => {
        if (!isNtcfgRaceOptionsRaceRoute() || ntRaceOptionsPendingReload) return;
        ntRaceOptionsPendingReload = true;
        window.location.reload();
    }, { immediate: false });
}

if (isNtcfgRaceOptionsRaceRoute()) {
    ntRaceOptionsRouteHelper.subscribe(() => {
        if (isNtcfgRaceOptionsRaceRoute() || ntRaceOptionsPendingReload) return;
        ntRaceOptionsPendingReload = true;
        window.location.reload();
    }, { immediate: false });

    const themeSystemDarkModeMediaQuery = typeof window.matchMedia === "function"
        ? window.matchMedia("(prefers-color-scheme: dark)")
        : null;

    const isThemeSystemDarkModeEnabled = () => !!themeSystemDarkModeMediaQuery?.matches;

    const getThemeEngineOptions = () => {
        const fontFamilyPreset = normalizeThemePresetValue(
            GM_getValue("THEME_FONT_FAMILY_PRESET", THEME_FONT_FAMILY_PRESET),
            THEME_FONT_FAMILY_PRESETS
        );
        const fontSizePreset = normalizeThemePresetValue(
            GM_getValue("THEME_FONT_SIZE_PRESET", THEME_FONT_SIZE_PRESET),
            THEME_FONT_SIZE_PRESETS
        );
        const singleLineFontSizePreset = normalizeThemePresetValue(
            GM_getValue("THEME_SINGLE_LINE_FONT_SIZE_PRESET", THEME_SINGLE_LINE_FONT_SIZE_PRESET),
            THEME_FONT_SIZE_PRESETS
        );
        const fontFamilyPresetOption = THEME_FONT_FAMILY_PRESETS.find((preset) => preset.value === fontFamilyPreset) || THEME_FONT_FAMILY_PRESETS[0];
        const fontSizePresetOption = THEME_FONT_SIZE_PRESETS.find((preset) => preset.value === fontSizePreset) || THEME_FONT_SIZE_PRESETS[0];
        const singleLineFontSizePresetOption = THEME_FONT_SIZE_PRESETS.find((preset) => preset.value === singleLineFontSizePreset) || THEME_FONT_SIZE_PRESETS[0];
        const darkModeEnabled = GM_getValue("THEME_ENABLE_DARK_MODE", THEME_ENABLE_DARK_MODE);
        const darkModeSyncSystem = GM_getValue("THEME_DARK_MODE_SYNC_SYSTEM", THEME_DARK_MODE_SYNC_SYSTEM);
        const darkModeEffective = darkModeSyncSystem ? isThemeSystemDarkModeEnabled() : !!darkModeEnabled;

        return {
            darkModeEnabled: !!darkModeEnabled,
            darkModeSyncSystem: !!darkModeSyncSystem,
            darkModeEffective,
            foreground: normalizeHexColorValue(GM_getValue("THEME_COLOR_FOREGROUND", THEME_COLOR_FOREGROUND), THEME_COLOR_FOREGROUND),
            foregroundActive: normalizeHexColorValue(GM_getValue("THEME_COLOR_FOREGROUND_ACTIVE", THEME_COLOR_FOREGROUND_ACTIVE), THEME_COLOR_FOREGROUND_ACTIVE),
            foregroundTyped: normalizeHexColorValue(GM_getValue("THEME_COLOR_FOREGROUND_TYPED", THEME_COLOR_FOREGROUND_TYPED), THEME_COLOR_FOREGROUND_TYPED),
            background: normalizeHexColorValue(GM_getValue("THEME_COLOR_BACKGROUND", THEME_COLOR_BACKGROUND), THEME_COLOR_BACKGROUND),
            backgroundActive: normalizeHexColorValue(GM_getValue("THEME_COLOR_BACKGROUND_ACTIVE", THEME_COLOR_BACKGROUND_ACTIVE), THEME_COLOR_BACKGROUND_ACTIVE),
            backgroundIncorrect: normalizeHexColorValue(GM_getValue("THEME_COLOR_BACKGROUND_INCORRECT", THEME_COLOR_BACKGROUND_INCORRECT), THEME_COLOR_BACKGROUND_INCORRECT),
            overrideForeground: GM_getValue("THEME_OVERRIDE_FOREGROUND", THEME_OVERRIDE_FOREGROUND),
            overrideForegroundActive: GM_getValue("THEME_OVERRIDE_FOREGROUND_ACTIVE", THEME_OVERRIDE_FOREGROUND_ACTIVE),
            overrideForegroundTyped: GM_getValue("THEME_OVERRIDE_FOREGROUND_TYPED", THEME_OVERRIDE_FOREGROUND_TYPED),
            hideTypedText: GM_getValue("THEME_HIDE_TYPED_TEXT", THEME_HIDE_TYPED_TEXT),
            overrideBackground: GM_getValue("THEME_OVERRIDE_BACKGROUND", THEME_OVERRIDE_BACKGROUND),
            overrideBackgroundActive: GM_getValue("THEME_OVERRIDE_BACKGROUND_ACTIVE", THEME_OVERRIDE_BACKGROUND_ACTIVE),
            overrideBackgroundIncorrect: GM_getValue("THEME_OVERRIDE_BACKGROUND_INCORRECT", THEME_OVERRIDE_BACKGROUND_INCORRECT),
            fontFamilyPreset,
            fontFamilyCss: fontFamilyPreset !== "__default__" && typeof fontFamilyPresetOption?.css === "string"
                ? normalizeThemeFontFamilyValue(fontFamilyPresetOption.css, THEME_FONT_FAMILY_DEFAULT_CSS)
                : null,
            fontSizePreset,
            fontSizePx: fontSizePreset !== "__default__" && Number.isFinite(Number(fontSizePresetOption?.px))
                ? normalizeThemeFontSizePx(fontSizePresetOption.px, 18)
                : null,
            singleLineFontSizePreset,
            singleLineFontSizePx: singleLineFontSizePreset !== "__default__" && Number.isFinite(Number(singleLineFontSizePresetOption?.px))
                ? normalizeThemeFontSizePx(singleLineFontSizePresetOption.px, 18)
                : null,
            fontBold: !!GM_getValue("THEME_FONT_BOLD", THEME_FONT_BOLD),
            fontItalic: !!GM_getValue("THEME_FONT_ITALIC", THEME_FONT_ITALIC),
            fontWeight: GM_getValue("THEME_FONT_BOLD", THEME_FONT_BOLD)
                ? Math.min(900, Math.max(100, Math.round(Number(GM_getValue("THEME_FONT_WEIGHT", THEME_FONT_WEIGHT)) || 700)))
                : THEME_FONT_WEIGHT_DEFAULT,
            fontStyle: GM_getValue("THEME_FONT_ITALIC", THEME_FONT_ITALIC) ? "italic" : "normal",
            enableRainbowTypedText: GM_getValue("THEME_ENABLE_RAINBOW_TYPED_TEXT", THEME_ENABLE_RAINBOW_TYPED_TEXT),
            rainbowTypedTextSpeedSeconds: normalizeRainbowSpeedSeconds(
                GM_getValue("THEME_RAINBOW_TYPED_TEXT_SPEED_SECONDS", THEME_RAINBOW_TYPED_TEXT_SPEED_SECONDS),
                THEME_RAINBOW_TYPED_TEXT_SPEED_SECONDS
            ),
        };
    };

    const THEME_ENGINE_STYLE_ID = "nt-theme-engine-style";
    const THEME_ENGINE_UPDATED_EVENT = "NT_THEME_ENGINE_UPDATED";
    const PERFECT_NITRO_UPDATED_EVENT = "NT_PERFECT_NITRO_UPDATED";

    // Capture NT's native line-height before any theme overrides are applied
    let _ntNativeLineHeight = null;
    const captureNativeLineHeight = () => {
        if (_ntNativeLineHeight !== null) return;
        const letter = document.querySelector('.dash-copy .dash-letter');
        const target = letter || document.querySelector('.dash-copy');
        if (!target) return;
        const computed = window.getComputedStyle(target);
        const raw = computed.lineHeight;
        if (raw && raw !== "normal") {
            _ntNativeLineHeight = raw;
        }
    };

    const applyRaceThemeEngine = () => {
        captureNativeLineHeight();
        const options = getThemeEngineOptions();
        const currentStyle = document.getElementById(THEME_ENGINE_STYLE_ID);
        const rules = [];
        const lineHeightRule = _ntNativeLineHeight ? `line-height: ${_ntNativeLineHeight} !important;` : "";

        if (options.darkModeEffective) {
            rules.push(`.dash-copyContainer { background: ${THEME_DARK_MODE_BACKGROUND} !important; }`);
            rules.push(`.dash-copy { color: ${THEME_DARK_MODE_FOREGROUND}; }`);
            if (!options.enableRainbowTypedText && !options.hideTypedText) {
                rules.push(`.dash-letter.is-typed { color: ${THEME_DARK_MODE_FOREGROUND_TYPED} !important; opacity: 1; }`);
            }
            rules.push(`.dash-letter.is-waiting { color: ${THEME_DARK_MODE_FOREGROUND_ACTIVE} !important; background: ${THEME_DARK_MODE_BACKGROUND_ACTIVE} !important; }`);
            rules.push(`.dash-letter.is-incorrect { color: ${THEME_DARK_MODE_FOREGROUND_ACTIVE} !important; background: ${THEME_DARK_MODE_BACKGROUND_INCORRECT} !important; }`);
        }

        if (options.overrideForeground) {
            rules.push(`.dash-copy { color: ${options.foreground}; }`);
        }
        if (options.overrideForegroundActive) {
            rules.push(`.dash-letter.is-incorrect, .dash-letter.is-waiting { color: ${options.foregroundActive} !important; }`);
        }
        if (options.overrideForegroundTyped && !options.enableRainbowTypedText && !options.hideTypedText) {
            rules.push(`.dash-letter.is-typed { color: ${options.foregroundTyped} !important; opacity: 1; }`);
        }
        if (options.overrideBackground) {
            rules.push(`.dash-copyContainer { background: ${options.background} !important; }`);
        }
        if (options.overrideBackgroundActive) {
            rules.push(`.dash-letter.is-waiting { background: ${options.backgroundActive} !important; }`);
        }
        if (options.overrideBackgroundIncorrect) {
            rules.push(`.dash-letter.is-incorrect { background: ${options.backgroundIncorrect} !important; }`);
        }
        if (options.fontFamilyCss) {
            rules.push(`.dash-copy, .dash-copy .dash-letter { font-family: ${options.fontFamilyCss} !important; }`);
        }
        const isSingleLine = !!document.querySelector('.dash-actions button:has(.icon-sololine).is-on');
        const effectiveFontSizePx = isSingleLine ? options.singleLineFontSizePx : options.fontSizePx;
        if (Number.isFinite(effectiveFontSizePx)) {
            rules.push(`.dash-copy, .dash-copy .dash-letter { font-size: ${effectiveFontSizePx}px !important; ${lineHeightRule} }`);
        }
        if (options.fontBold || options.fontFamilyCss || Number.isFinite(effectiveFontSizePx)) {
            rules.push(`.dash-copy, .dash-copy .dash-letter { font-weight: ${options.fontWeight} !important; }`);
        }
        if (options.fontItalic) {
            rules.push(`.dash-copy, .dash-copy .dash-letter { font-style: italic !important; }`);
        }
        if (options.enableRainbowTypedText && !options.hideTypedText) {
            rules.push(`
@keyframes ntcfg-race-rainbow-text {
    0% { color: blue; }
    10% { color: #ff005d; }
    20% { color: #f0f; }
    30% { color: black; }
    40% { color: #7500ff; }
    50% { color: blue; }
    60% { color: #f0f; }
    70% { color: black; }
    80% { color: black; }
    90% { color: red; }
    100% { color: red; }
}
.dash-letter.is-correct,
.dash-letter.is-typed:not(.is-incorrect):not(.is-waiting):not(.is-active):not(.is-current) {
    animation: ntcfg-race-rainbow-text ${options.rainbowTypedTextSpeedSeconds}s infinite alternate;
    -webkit-animation: ntcfg-race-rainbow-text ${options.rainbowTypedTextSpeedSeconds}s infinite alternate;
    opacity: 1;
}
`);
        }

        if (options.hideTypedText) {
            rules.push(`
.dash-letter.is-typed:not(.is-active):not(.is-current),
.dash-letter.is-correct:not(.is-active):not(.is-current) {
    color: transparent !important;
    -webkit-text-fill-color: transparent !important;
    text-shadow: none !important;
    opacity: 0 !important;
}
`);
        }

        if (rules.length === 0) {
            if (currentStyle) {
                currentStyle.remove();
            }
            return;
        }

        const style = currentStyle || document.createElement("style");
        style.id = THEME_ENGINE_STYLE_ID;
        style.textContent = rules.join("\n");
        if (!currentStyle) {
            document.head.appendChild(style);
        }
    };

    const handleThemeSystemColorSchemeChange = () => {
        if (!GM_getValue("THEME_DARK_MODE_SYNC_SYSTEM", THEME_DARK_MODE_SYNC_SYSTEM)) {
            return;
        }
        applyRaceThemeEngine();
        window.dispatchEvent(new CustomEvent(THEME_ENGINE_UPDATED_EVENT));
    };

    if (themeSystemDarkModeMediaQuery) {
        if (typeof themeSystemDarkModeMediaQuery.addEventListener === "function") {
            themeSystemDarkModeMediaQuery.addEventListener("change", handleThemeSystemColorSchemeChange);
        } else if (typeof themeSystemDarkModeMediaQuery.addListener === "function") {
            themeSystemDarkModeMediaQuery.addListener(handleThemeSystemColorSchemeChange);
        }
    }

    const maybeApplyLiveThemeSetting = (variableName) => {
        if (String(variableName).startsWith("THEME_")) {
            applyRaceThemeEngine();
            window.dispatchEvent(new CustomEvent(THEME_ENGINE_UPDATED_EVENT));
        }
        if (String(variableName).startsWith("PERFECT_NITRO_") || variableName === "ENABLE_PERFECT_NITROS") {
            window.dispatchEvent(new CustomEvent(PERFECT_NITRO_UPDATED_EVENT));
        }
    };

    applyRaceThemeEngine();

    // Observe single-line / multi-line toggle changes to re-apply font size override
    const setupSingleLineModeObserver = () => {
        let lastSingleLine = null;
        const check = () => {
            const isSingleLine = !!document.querySelector('.dash-actions button:has(.icon-sololine).is-on');
            if (lastSingleLine !== isSingleLine) {
                lastSingleLine = isSingleLine;
                applyRaceThemeEngine();
                window.dispatchEvent(new CustomEvent(THEME_ENGINE_UPDATED_EVENT));
            }
        };
        const observer = new MutationObserver(check);
        const startObserving = () => {
            const dashActions = document.querySelector('.dash-actions');
            if (dashActions) {
                observer.observe(dashActions, { attributes: true, subtree: true, attributeFilter: ['class'] });
                check();
                return true;
            }
            return false;
        };
        if (!startObserving()) {
            // dash-actions may not exist yet; watch for it
            const bodyObserver = new MutationObserver(() => {
                if (startObserving()) {
                    bodyObserver.disconnect();
                }
            });
            bodyObserver.observe(document.body, { childList: true, subtree: true });
        }
    };
    setupSingleLineModeObserver();

    const NTCFG_FOCUS_LOCK_EVENT = "NT_RACE_OPTIONS_FOCUS_LOCK";
    const NTCFG_IFRAME_CLICK_EVENT = "NT_RACE_OPTIONS_IFRAME_CLICKED";

    if (!window.__ntcfgFocusPatchInstalled) {
        window.__ntcfgFocusPatchInstalled = true;
        window.__ntcfgFocusLocked = false;

        window.addEventListener("message", (event) => {
            if (event?.data?.type === NTCFG_FOCUS_LOCK_EVENT) {
                window.__ntcfgFocusLocked = !!event.data.locked;
            }
        });

        window.addEventListener("mousedown", () => {
            if (window.__ntcfgFocusLocked) {
                window.__ntcfgFocusLocked = false;
                if (window.top && window.top !== window) {
                    window.top.postMessage({ type: NTCFG_IFRAME_CLICK_EVENT }, "*");
                }
            }
            window.focus();
        }, true);

        const ntcfgOriginalFocus = HTMLElement.prototype.focus;
        HTMLElement.prototype.focus = function () {
            if (window.__ntcfgFocusLocked) return;
            return ntcfgOriginalFocus.apply(this, arguments);
        };
    }

    // Perfect Nitro helper functions (top-level so preview can access them)
    const getEffectiveThemeBackground = () => {
        const themeOptions = getThemeEngineOptions();
        if (themeOptions.overrideBackground) return normalizeHexColorValue(themeOptions.background, "#FFFFFF");
        if (themeOptions.darkModeEffective) return THEME_DARK_MODE_BACKGROUND;
        return "#E9EAEB"; // NT default light background for .dash-copyContainer
    };

    const getPerfectNitroTextStyle = (highlightColor, opacity = 0.5) => {
        const bgHex = getEffectiveThemeBackground();
        const fgHex = normalizeHexColorValue(highlightColor, "#FFFFFF");
        const luminance = blendedLuminance(fgHex, bgHex, opacity);
        const color = luminance > 0.5 ? "#101623" : "#E7EEF8";
        return {
            color,
            shadow: color === "#101623" ? "0 1px 1px rgba(255, 255, 255, 0.25)" : "0 1px 1px rgba(0, 0, 0, 0.35)",
        };
    };

    const getPerfectNitroOptions = () => {
        const rawInterval = Number(GM_getValue("PERFECT_NITRO_SCAN_INTERVAL_MS", PERFECT_NITRO_SCAN_INTERVAL_MS));
        const intervalMs = Number.isFinite(rawInterval) && rawInterval > 0
            ? Math.max(MIN_PERFECT_NITRO_SCAN_INTERVAL_MS, Math.round(rawInterval))
            : MIN_PERFECT_NITRO_SCAN_INTERVAL_MS;
        const rawColor = String(GM_getValue("PERFECT_NITRO_HIGHLIGHT_COLOR", PERFECT_NITRO_HIGHLIGHT_COLOR) || "").trim();
        const rawTextColor = String(GM_getValue("PERFECT_NITRO_TEXT_COLOR", PERFECT_NITRO_TEXT_COLOR) || "").trim();
        return {
            enabled: GM_getValue("ENABLE_PERFECT_NITROS", ENABLE_PERFECT_NITROS),
            intervalMs,
            highlightColor: rawColor || "#FFFFFF",
            enableHighlight: !!GM_getValue("PERFECT_NITRO_ENABLE_HIGHLIGHT", PERFECT_NITRO_ENABLE_HIGHLIGHT),
            italic: !!GM_getValue("PERFECT_NITRO_ITALIC", PERFECT_NITRO_ITALIC),
            rainbow: !!GM_getValue("PERFECT_NITRO_RAINBOW", PERFECT_NITRO_RAINBOW),
            highlightOpacity: normalizeHighlightOpacity(GM_getValue("PERFECT_NITRO_HIGHLIGHT_OPACITY", PERFECT_NITRO_HIGHLIGHT_OPACITY)),
            overrideTextColor: !!GM_getValue("PERFECT_NITRO_OVERRIDE_TEXT_COLOR", PERFECT_NITRO_OVERRIDE_TEXT_COLOR),
            textColor: normalizeHexColorValue(rawTextColor || "#FFFFFF", "#FFFFFF"),
        };
    };

    // Create UI elements
    const createUI = () => {
        if (!document.getElementById("ntcfg-style")) {
            const style = document.createElement("style");
            style.id = "ntcfg-style";
            style.textContent = `
.ntcfg-overlay {
    position: fixed;
    inset: 0;
    z-index: 100000;
    display: none;
    align-items: center;
    justify-content: center;
}
.ntcfg-overlay.is-open {
    display: flex;
}
.ntcfg-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(6, 12, 18, 0.72);
    backdrop-filter: blur(2px);
}
.ntcfg-card {
    position: relative;
    width: min(980px, calc(100vw - 28px));
    max-height: calc(100vh - 28px);
    border-radius: 20px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    color: #fff;
    background-color: #20222e;
    background-image: url(/dist/site/images/backgrounds/bg-noise.png);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.45);
}
.ntcfg-header {
    padding: 18px 22px;
    background: url(/dist/site/images/backgrounds/bg-noise.png) top left repeat, linear-gradient(90deg, #1c99f4 60%, #167ac3 100%);
}
.ntcfg-title {
    margin: 0;
    font-family: "Montserrat", sans-serif;
    font-size: 30px;
    line-height: 1.1;
    font-weight: 600;
    text-shadow: 0 2px 2px rgba(2, 2, 2, 0.25);
}
.ntcfg-subtitle {
    margin: 6px 0 0;
    color: rgba(255, 255, 255, 0.92);
    font-size: 13px;
}
.ntcfg-layout {
    display: flex;
    gap: 18px;
    min-height: 0;
    padding: 18px;
}
.ntcfg-sidebar {
    width: 240px;
    max-width: 240px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.ntcfg-nav-btn {
    box-shadow: none;
    justify-content: flex-start;
    width: 100%;
    backface-visibility: hidden;
    background: #393c50;
    border: 1px solid transparent;
    color: #a6aac1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    font-family: "Montserrat", sans-serif;
    font-size: 14px;
    overflow: hidden;
    padding: 13px 14px;
    position: relative;
    text-align: left;
    transition: all 0.12s linear;
}
.ntcfg-nav-btn:first-child {
    border-radius: 5px 5px 0 0;
}
.ntcfg-nav-btn:last-child {
    border-radius: 0 0 5px 5px;
}
.ntcfg-nav-btn:hover {
    background: #585e7d;
    color: #e2e3eb;
}
.ntcfg-nav-btn.is-active {
    background: #167ac3 !important;
    color: #fff;
    text-shadow: 0 2px 2px rgba(2, 2, 2, 0.25);
}
.ntcfg-content {
    flex: 1;
    min-width: 0;
    max-height: calc(100vh - 250px);
    overflow: auto;
    border-radius: 10px;
    background: #2b2e3f;
    border: 1px solid rgba(255, 255, 255, 0.08);
    padding: 18px;
}
.ntcfg-content::-webkit-scrollbar {
    width: 8px;
}
.ntcfg-content::-webkit-scrollbar-track {
    background: rgba(0, 0, 0, 0.25);
    border-radius: 8px;
}
.ntcfg-content::-webkit-scrollbar-thumb {
    background: rgba(28, 153, 244, 0.8);
    border-radius: 8px;
}
.ntcfg-panel[hidden] {
    display: none !important;
}
.ntcfg-panel-title {
    margin: 0;
    font-size: 20px;
    font-family: "Montserrat", sans-serif;
}
.ntcfg-panel-subtitle {
    margin: 6px 0 16px;
    color: #b5bad3;
    font-size: 13px;
}
.ntcfg-fields {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.ntcfg-field {
    display: block;
}
.ntcfg-field-title {
    color: #d8dcf2;
    font-size: 13px;
    margin-bottom: 6px;
}
.ntcfg-field-help {
    margin-top: 5px;
    color: #99a4c5;
    font-size: 12px;
    line-height: 1.35;
}
.ntcfg-field-warning {
    color: #ffb8b8;
}
.ntcfg-input {
    width: 100%;
    box-sizing: border-box;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background: #1d2030;
    color: #eef3ff;
    padding: 10px;
    font-size: 13px;
}
.ntcfg-input:focus {
    outline: none;
    border-color: #1c99f4;
    box-shadow: 0 0 0 2px rgba(28, 153, 244, 0.28);
}
.ntcfg-input.ntcfg-input-warning {
    border-color: rgba(255, 90, 90, 0.85);
    box-shadow: 0 0 0 2px rgba(255, 90, 90, 0.2);
}
.ntcfg-color-row {
    display: flex;
    gap: 8px;
}
.ntcfg-color-picker {
    width: 52px;
    min-width: 52px;
    padding: 0;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: #1d2030;
    cursor: pointer;
}
.ntcfg-color-hex {
    flex: 1;
    text-transform: uppercase;
}
.ntcfg-checkbox {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: #252839;
    padding: 10px 12px;
}
.ntcfg-checkbox-label {
    color: #d8dcf2;
    font-size: 13px;
}
.ntcfg-checkbox-copy {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}
.ntcfg-checkbox-help {
    color: #99a4c5;
    font-size: 12px;
    line-height: 1.35;
}
.ntcfg-checkbox-controls {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}
.ntcfg-checkbox-controls .ntcfg-color-picker {
    width: 38px;
    min-width: 38px;
    height: 30px;
}
.ntcfg-checkbox-controls .ntcfg-input {
    width: 84px;
    padding: 6px 8px;
    font-size: 12px;
}
.ntcfg-checkbox-controls select.ntcfg-input {
    width: auto;
}
.ntcfg-switch {
    position: relative;
    width: 40px;
    height: 24px;
    flex: 0 0 auto;
    display: inline-block;
    cursor: pointer;
}
.ntcfg-switch input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
    margin: 0;
    z-index: 2;
}
.ntcfg-switch-track {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 999px;
    background: #585e7d;
    transition: background 0.15s ease;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
    pointer-events: none;
}
.ntcfg-switch-track::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #fff;
    transition: transform 0.1s ease;
}
.ntcfg-switch input:checked + .ntcfg-switch-track {
    background: #d62f3a;
    box-shadow: 0 2px 20px rgba(214, 47, 58, 0.35);
}
.ntcfg-switch input:checked + .ntcfg-switch-track::after {
    transform: translateX(16px);
}
.ntcfg-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 0 18px 18px;
}
.ntcfg-action {
    border: 0;
    border-radius: 8px;
    padding: 10px 14px;
    font-size: 13px;
    cursor: pointer;
    color: #fff;
    background: #393c50;
}
.ntcfg-action:hover {
    filter: brightness(1.1);
}
.ntcfg-action.ntcfg-primary {
    background: #167ac3;
}
.ntcfg-inline-action {
    align-self: flex-start;
}
.ntcfg-theme-preview-label {
    color: #d8dcf2;
    font-size: 13px;
    margin-bottom: 4px;
}
.ntcfg-theme-preview-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 8px;
    margin-bottom: 12px;
}
.ntcfg-theme-preview {
    width: 100%;
    box-sizing: border-box;
    padding: 12px;
    margin-bottom: 0;
    border-radius: 5px;
    background: #e9eaeb;
    color: #2e3141;
}
.ntcfg-theme-preview span {
    font-family: "Roboto Mono", "Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace;
    display: inline-block;
    padding: 2px;
    font-size: 18px;
    white-space: pre;
}
.ntcfg-theme-preview span.ntcfg-theme-char-active {
    background: #1c99f4;
    color: #fff;
}
.ntcfg-theme-preview span.ntcfg-theme-char-incorrect {
    background: #d62f3a;
    color: #fff;
}
.ntcfg-theme-preview span.ntcfg-theme-char-typed {
    color: #2e3141;
    opacity: 0.5;
}
.ntcfg-theme-preview span.ntcfg-theme-char-rainbow {
    animation: ntcfg-preview-rainbow-text 10s infinite alternate;
    -webkit-animation: ntcfg-preview-rainbow-text 10s infinite alternate;
    opacity: 1;
}
@keyframes ntcfg-preview-rainbow-text {
    0% { color: blue; }
    10% { color: #ff005d; }
    20% { color: #f0f; }
    30% { color: black; }
    40% { color: #7500ff; }
    50% { color: blue; }
    60% { color: #f0f; }
    70% { color: black; }
    80% { color: black; }
    90% { color: red; }
    100% { color: red; }
}
.ntcfg-theme-settings {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.ntcfg-theme-setting {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 8px;
    background: #252839;
    padding: 8px 10px;
}
.ntcfg-theme-setting-title {
    color: #d8dcf2;
    font-size: 13px;
}
.ntcfg-theme-setting-controls {
    display: flex;
    align-items: center;
    gap: 8px;
}
.ntcfg-theme-color-compact {
    display: flex;
    align-items: center;
    gap: 6px;
}
.ntcfg-theme-color-compact .ntcfg-color-picker {
    width: 38px;
    min-width: 38px;
    height: 30px;
}
.ntcfg-theme-color-compact .ntcfg-input {
    width: 96px;
    padding: 6px 8px;
    font-size: 12px;
}
.ntcfg-theme-input-compact {
    width: auto;
    padding: 6px 8px;
    font-size: 12px;
}
.ntcfg-theme-input-select {
    width: 180px;
}
.ntcfg-theme-input-number {
    width: 96px;
}
.ntcfg-theme-input-preset {
    width: 132px;
}
@media (min-width: 900px) {
    .ntcfg-theme-preview-grid {
        grid-template-columns: 1fr 1fr;
    }
}
.ntcfg-sticky-preview {
    position: sticky;
    top: 0;
    z-index: 10;
    background: #2b2e3f;
    padding-bottom: 12px;
    margin-bottom: 4px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.ntcfg-pn-preview {
    width: 100%;
    box-sizing: border-box;
    padding: 12px;
    border-radius: 5px;
    background: #e9eaeb;
    color: #2e3141;
    margin-bottom: 0;
    overflow: hidden;
    word-wrap: break-word;
}
.ntcfg-pn-preview span {
    font-family: "Roboto Mono", "Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace;
    display: inline-block;
    padding: 2px;
    font-size: 18px;
    white-space: pre;
}
.ntcfg-pn-preview-rainbow {
    animation: ntcfg-pn-preview-rainbow 3s linear infinite;
    -webkit-animation: ntcfg-pn-preview-rainbow 3s linear infinite;
}
@keyframes ntcfg-pn-preview-rainbow {
    0% { color: #FF0000; }
    14% { color: #FF8C00; }
    28% { color: #FFD700; }
    42% { color: #00CC00; }
    57% { color: #0066FF; }
    71% { color: #7B00FF; }
    85% { color: #FF00FF; }
    100% { color: #FF0000; }
}
.ntcfg-open-btn {
    position: fixed;
    left: 10px;
    bottom: 10px;
    z-index: 99999;
    border: 0;
    border-radius: 8px;
    padding: 7px 10px;
    cursor: pointer;
    color: #dff7ff;
    background: rgba(0, 0, 0, 0.82);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
}
.ntcfg-open-btn:hover {
    background: rgba(15, 25, 36, 0.94);
}
`;
            document.head.appendChild(style);
        }

        const overlay = document.createElement("div");
        overlay.className = "ntcfg-overlay";
        overlay.innerHTML = `
        <div class="ntcfg-backdrop"></div>
        <div class="ntcfg-card" role="dialog" aria-label="Nitro Type script configuration">
            <div class="ntcfg-header">
                <h2 class="ntcfg-title">Configuration</h2>
                <p class="ntcfg-subtitle">Changes save instantly.</p>
            </div>
            <div class="ntcfg-layout">
                <div class="ntcfg-sidebar"></div>
                <div class="ntcfg-content"></div>
            </div>
            <div class="ntcfg-footer">
                <button type="button" class="ntcfg-action ntcfg-primary ntcfg-save">Save and Reload</button>
                <button type="button" class="ntcfg-action ntcfg-close">Close</button>
            </div>
        </div>
    `;
        document.body.appendChild(overlay);

        const sidebar = overlay.querySelector(".ntcfg-sidebar");
        const content = overlay.querySelector(".ntcfg-content");
        const saveBtn = overlay.querySelector(".ntcfg-save");
        const closeBtn = overlay.querySelector(".ntcfg-close");
        const backdrop = overlay.querySelector(".ntcfg-backdrop");

        const broadcastFocusLock = (locked) => {
            window.__ntcfgFocusLocked = !!locked;
            for (let i = 0; i < window.frames.length; i++) {
                try {
                    window.frames[i].postMessage({ type: NTCFG_FOCUS_LOCK_EVENT, locked: !!locked }, "*");
                } catch {
                    // ignore
                }
            }
        };

        window.addEventListener("message", (event) => {
            if (event?.data?.type === NTCFG_IFRAME_CLICK_EVENT) {
                broadcastFocusLock(false);
            }
        });

        const sections = new Map();
        const settingInputBindings = new Map();

        const bindSettingInput = (variableName, syncFn) => {
            settingInputBindings.set(variableName, syncFn);
        };

        const syncSettingInput = (variableName, value) => {
            const syncFn = settingInputBindings.get(variableName);
            if (typeof syncFn === "function") {
                syncFn(value);
            }
        };

        window.addEventListener(NTCFG_RACE_OPTIONS_SETTING_SYNC_EVENT, (event) => {
            const variableName = event?.detail?.key;
            if (!variableName) return;
            syncSettingInput(variableName, event.detail.value);
        });

        const selectSection = (id) => {
            sections.forEach((section, key) => {
                const active = key === id;
                section.panel.hidden = !active;
                section.button.classList.toggle("is-active", active);
            });
        };

        const createSection = (id, title, subtitle) => {
            const button = document.createElement("button");
            button.type = "button";
            button.className = "ntcfg-nav-btn";
            button.textContent = title;
            sidebar.appendChild(button);

            const panel = document.createElement("section");
            panel.className = "ntcfg-panel";
            panel.hidden = true;
            panel.innerHTML = `
            <h3 class="ntcfg-panel-title">${title}</h3>
            <p class="ntcfg-panel-subtitle">${subtitle}</p>
        `;
            const fields = document.createElement("div");
            fields.className = "ntcfg-fields";
            panel.appendChild(fields);
            content.appendChild(panel);

            button.addEventListener("click", () => selectSection(id));
            sections.set(id, { button, panel, fields });
            if (sections.size === 1) {
                selectSection(id);
            }
            return fields;
        };

        const addCheckbox = (root, labelText, variableName, defaultValue, helpText = "", onChange = null) => {
            const saveSetting = (value) => {
                setNtcfgRaceOptionsValue(variableName, value);
                maybeApplyLiveThemeSetting(variableName);
            };

            const row = document.createElement("label");
            row.className = "ntcfg-checkbox";

            const title = document.createElement("span");
            title.className = "ntcfg-checkbox-label";
            title.textContent = labelText;

            const copy = document.createElement("span");
            copy.className = "ntcfg-checkbox-copy";
            copy.appendChild(title);
            if (helpText) {
                const help = document.createElement("span");
                help.className = "ntcfg-checkbox-help";
                help.textContent = helpText;
                copy.appendChild(help);
            }

            const switchRoot = document.createElement("span");
            switchRoot.className = "ntcfg-switch";

            const input = document.createElement("input");
            input.type = "checkbox";
            input.checked = GM_getValue(variableName, defaultValue);
            input.addEventListener("change", () => {
                saveSetting(input.checked);
                if (typeof onChange === "function") {
                    onChange(input.checked);
                }
            });
            bindSettingInput(variableName, (value) => {
                input.checked = !!value;
            });

            const track = document.createElement("span");
            track.className = "ntcfg-switch-track";

            switchRoot.append(input, track);
            row.append(copy, switchRoot);
            root.appendChild(row);
        };

        const addNumberInput = (root, labelText, variableName, defaultValue, helpText = "", options = {}) => {
            const { minRecommended = null, warningText = "" } = options;
            const saveSetting = (value) => {
                setNtcfgRaceOptionsValue(variableName, value);
                maybeApplyLiveThemeSetting(variableName);
            };

            const field = document.createElement("label");
            field.className = "ntcfg-field";

            const title = document.createElement("div");
            title.className = "ntcfg-field-title";
            title.textContent = labelText;

            const input = document.createElement("input");
            input.className = "ntcfg-input";
            input.type = "number";
            input.value = GM_getValue(variableName, defaultValue);

            const warning = document.createElement("div");
            warning.className = "ntcfg-field-help ntcfg-field-warning";
            warning.hidden = true;

            const updateWarningState = (value) => {
                const shouldWarn = Number.isFinite(minRecommended) && Number.isFinite(value) && value < minRecommended;
                warning.hidden = !shouldWarn;
                if (shouldWarn) {
                    warning.textContent = warningText || `Warning: values below ${minRecommended} are not recommended.`;
                    input.classList.add("ntcfg-input-warning");
                } else {
                    warning.textContent = "";
                    input.classList.remove("ntcfg-input-warning");
                }
            };

            input.addEventListener("input", () => {
                updateWarningState(parseFloat(input.value));
            });
            input.addEventListener("change", () => {
                const parsed = parseFloat(input.value);
                if (!Number.isFinite(parsed)) {
                    return;
                }
                saveSetting(parsed);
                updateWarningState(parsed);
            });
            bindSettingInput(variableName, (value) => {
                input.value = String(value ?? defaultValue);
                updateWarningState(parseFloat(input.value));
            });

            field.append(title, input);
            if (helpText) {
                const help = document.createElement("div");
                help.className = "ntcfg-field-help";
                help.textContent = helpText;
                field.appendChild(help);
            }
            if (Number.isFinite(minRecommended)) {
                field.appendChild(warning);
                updateWarningState(parseFloat(input.value));
            }
            root.appendChild(field);
        };

        const addTextInput = (root, labelText, variableName, defaultValue, helpText = "") => {
            const saveSetting = (value) => {
                setNtcfgRaceOptionsValue(variableName, value);
                maybeApplyLiveThemeSetting(variableName);
            };

            const field = document.createElement("label");
            field.className = "ntcfg-field";

            const title = document.createElement("div");
            title.className = "ntcfg-field-title";
            title.textContent = labelText;

            const input = document.createElement("input");
            input.className = "ntcfg-input";
            input.type = "text";
            input.value = GM_getValue(variableName, defaultValue);
            input.addEventListener("change", () => {
                const value = String(input.value).trim();
                saveSetting(value || defaultValue);
            });
            bindSettingInput(variableName, (value) => {
                input.value = String(value ?? defaultValue);
            });

            field.append(title, input);
            if (helpText) {
                const help = document.createElement("div");
                help.className = "ntcfg-field-help";
                help.textContent = helpText;
                field.appendChild(help);
            }
            root.appendChild(field);
        };

        const addSelectInput = (root, labelText, variableName, defaultValue, options = [], helpText = "", onChange = null) => {
            const saveSetting = (value) => {
                setNtcfgRaceOptionsValue(variableName, value);
                maybeApplyLiveThemeSetting(variableName);
            };

            const field = document.createElement("label");
            field.className = "ntcfg-field";

            const title = document.createElement("div");
            title.className = "ntcfg-field-title";
            title.textContent = labelText;

            const select = document.createElement("select");
            select.className = "ntcfg-input";

            const safeOptions = Array.isArray(options) ? options.filter((option) => option && typeof option.value !== "undefined") : [];
            safeOptions.forEach((optionDef) => {
                const option = document.createElement("option");
                option.value = String(optionDef.value);
                option.textContent = String(optionDef.label ?? optionDef.value);
                select.appendChild(option);
            });

            const normalizeSelectedValue = (value) => {
                const raw = String(value ?? "").trim();
                if (safeOptions.some((optionDef) => String(optionDef.value) === raw)) {
                    return raw;
                }
                return String(defaultValue);
            };

            select.value = normalizeSelectedValue(GM_getValue(variableName, defaultValue));
            select.addEventListener("change", () => {
                const normalized = normalizeSelectedValue(select.value);
                select.value = normalized;
                saveSetting(normalized);
                if (typeof onChange === "function") {
                    onChange(normalized);
                }
            });
            bindSettingInput(variableName, (value) => {
                const normalized = normalizeSelectedValue(value);
                select.value = normalized;
                if (typeof onChange === "function") {
                    onChange(normalized);
                }
            });

            field.append(title, select);
            if (helpText) {
                const help = document.createElement("div");
                help.className = "ntcfg-field-help";
                help.textContent = helpText;
                field.appendChild(help);
            }
            root.appendChild(field);
            return { field, select };
        };

        const normalizeHexColor = (value, fallback = "#FFFFFF") => {
            const raw = String(value || "").trim();
            if (/^#[0-9A-Fa-f]{6}$/.test(raw)) {
                return raw.toUpperCase();
            }
            if (/^#[0-9A-Fa-f]{3}$/.test(raw)) {
                return `#${raw[1]}${raw[1]}${raw[2]}${raw[2]}${raw[3]}${raw[3]}`.toUpperCase();
            }
            return fallback.toUpperCase();
        };

        const addColorInput = (root, labelText, variableName, defaultValue, helpText = "") => {
            const saveSetting = (value) => {
                setNtcfgRaceOptionsValue(variableName, value);
                maybeApplyLiveThemeSetting(variableName);
            };

            const field = document.createElement("label");
            field.className = "ntcfg-field";

            const title = document.createElement("div");
            title.className = "ntcfg-field-title";
            title.textContent = labelText;

            const row = document.createElement("div");
            row.className = "ntcfg-color-row";

            const colorInput = document.createElement("input");
            colorInput.type = "color";
            colorInput.className = "ntcfg-color-picker";

            const hexInput = document.createElement("input");
            hexInput.type = "text";
            hexInput.className = "ntcfg-input ntcfg-color-hex";
            hexInput.maxLength = 7;
            hexInput.placeholder = "#FFFFFF";

            const startingHex = normalizeHexColor(GM_getValue(variableName, defaultValue), normalizeHexColor(defaultValue));
            colorInput.value = startingHex;
            hexInput.value = startingHex;
            bindSettingInput(variableName, (value) => {
                const normalized = normalizeHexColor(value, normalizeHexColor(defaultValue));
                colorInput.value = normalized;
                hexInput.value = normalized;
            });

            colorInput.addEventListener("input", () => {
                const hex = normalizeHexColor(colorInput.value, startingHex);
                hexInput.value = hex;
                saveSetting(hex);
            });

            const commitHex = () => {
                const hex = normalizeHexColor(hexInput.value, colorInput.value || startingHex);
                hexInput.value = hex;
                colorInput.value = hex;
                saveSetting(hex);
            };

            hexInput.addEventListener("change", commitHex);
            hexInput.addEventListener("blur", commitHex);

            row.append(colorInput, hexInput);
            field.append(title, row);
            if (helpText) {
                const help = document.createElement("div");
                help.className = "ntcfg-field-help";
                help.textContent = helpText;
                field.appendChild(help);
            }
            root.appendChild(field);
        };

        const addSectionResetButton = (root, labelText, defaults, onAfterReset = null) => {
            const resetButton = document.createElement("button");
            resetButton.type = "button";
            resetButton.className = "ntcfg-action ntcfg-inline-action";
            resetButton.textContent = labelText;
            resetButton.addEventListener("click", () => {
                Object.entries(defaults).forEach(([variableName, value]) => {
                    setNtcfgRaceOptionsValue(variableName, value);
                    syncSettingInput(variableName, value);
                    maybeApplyLiveThemeSetting(variableName);
                });
                if (typeof onAfterReset === "function") {
                    onAfterReset(defaults);
                }
            });
            root.appendChild(resetButton);
        };

        const general = createSection("general", "General", "Visual behavior and quality-of-life controls.");
        addCheckbox(general, 'Hide Track', 'hideTrack', hideTrack, "Hides the visual racetrack area to reduce on-screen clutter.");
        addCheckbox(general, 'Hide Notifications', 'hideNotifications', hideNotifications, "Blocks growl popups during races.");
        addCheckbox(general, 'Auto close reward popup', 'AUTO_CLOSE_REWARD_POPUP', AUTO_CLOSE_REWARD_POPUP, "Automatically dismisses reward/takeover popups if they appear.");
        addCheckbox(general, 'Hide "Prepare for your race" floating icon', 'HIDE_PREPARE_FOR_RACE_ICON', HIDE_PREPARE_FOR_RACE_ICON, "Removes the floating prep icon overlay.");
        let miniMapPositionInput = null;
        const setMiniMapPositionVisibility = (enabled) => {
            if (miniMapPositionInput?.field) {
                miniMapPositionInput.field.hidden = !enabled;
            }
        };
        addCheckbox(
            general,
            'Enable Mini Map',
            'ENABLE_MINI_MAP',
            ENABLE_MINI_MAP,
            "Shows a compact lane map on the race page.",
            (checked) => setMiniMapPositionVisibility(checked)
        );
        miniMapPositionInput = addSelectInput(
            general,
            "Mini Map Position",
            "MINI_MAP_POSITION",
            normalizeMiniMapPositionValue(MINI_MAP_POSITION),
            [
                { value: "bottom", label: "Bottom (below track)" },
                { value: "top", label: "Top (above track)" },
            ],
            "Choose where the mini map appears relative to the race track."
        );
        setMiniMapPositionVisibility(GM_getValue("ENABLE_MINI_MAP", ENABLE_MINI_MAP));
        addCheckbox(
            general,
            'Enable Racer Badges (In-Race)',
            'ENABLE_RACER_BADGES_IN_RACE',
            ENABLE_RACER_BADGES_IN_RACE,
            "Controls whether Racer Badges injects race nameplate badges.",
            (checked) => syncRacerBadgesRaceToggle(checked)
        );
        addCheckbox(general, 'Hide Chat and Stickers', 'HIDE_CHAT_AND_STICKERS', HIDE_CHAT_AND_STICKERS, "Hides the in-race chat and sticker panel.");
        addCheckbox(general, 'Hide Finish Flag', 'HIDE_FINISH_FLAG', HIDE_FINISH_FLAG, "Hides the finish flag icon in the race text.");
        const generalDefaults = {
            hideTrack: false,
            hideNotifications: true,
            AUTO_CLOSE_REWARD_POPUP: true,
            HIDE_PREPARE_FOR_RACE_ICON: false,
            ENABLE_MINI_MAP: false,
            MINI_MAP_POSITION: "bottom",
            ENABLE_RACER_BADGES_IN_RACE: true,
            HIDE_CHAT_AND_STICKERS: false,
            HIDE_FINISH_FLAG: false,
        };
        addSectionResetButton(general, "Reset General to Defaults", generalDefaults, (defaults) => {
            setMiniMapPositionVisibility(!!defaults.ENABLE_MINI_MAP);
            syncRacerBadgesRaceToggle(!!defaults.ENABLE_RACER_BADGES_IN_RACE);
        });

        const autoReload = createSection("autoreload", "Auto Reload", "Race-end refresh controls.");
        addCheckbox(autoReload, 'Enable Auto Reload', 'reloadOnStats', reloadOnStats, "Reload the page after results update.");
        addCheckbox(autoReload, 'Enable FAST RELOAD', 'greedyStatsReload', greedyStatsReload, "Aggressively checks for result updates to reload sooner.");
        addNumberInput(
            autoReload,
            'FAST RELOAD - Check Interval',
            'greedyStatsReloadInt',
            greedyStatsReloadInt,
            "How often FAST RELOAD checks for updates (milliseconds). Lower = faster but heavier.",
            {
                minRecommended: 50,
                warningText: "Warning: values below 50ms can cause stats to fail to save. 50ms is the fastest recommended setting.",
            }
        );
        const autoReloadDefaults = {
            reloadOnStats: true,
            greedyStatsReload: true,
            greedyStatsReloadInt: 50,
        };
        addSectionResetButton(autoReload, "Reset Auto Reload to Defaults", autoReloadDefaults);

        const stats = createSection("stats", "Stats", "Adjust stat correction/offset values.");
        addCheckbox(stats, 'Enable Stats', 'enableStats', enableStats, "Shows the custom Racing Stats panel.");
        addCheckbox(stats, 'Enable Precise Accuracy', 'ENABLE_PRECISE_ACCURACY', ENABLE_PRECISE_ACCURACY, "Uses full-text error math for the live in-race accuracy metric.");
        addNumberInput(stats, 'Races Outside Current Team', 'RACES_OUTSIDE_CURRENT_TEAM', RACES_OUTSIDE_CURRENT_TEAM, "Subtract races done outside your current team from team-race math.");
        addNumberInput(stats, 'Bugged team count (0 if no)', 'TEAM_RACES_BUGGED', TEAM_RACES_BUGGED, "Manual correction added to team race totals when NT data is wrong.");
        const statsDefaults = {
            enableStats: true,
            ENABLE_PRECISE_ACCURACY: false,
            RACES_OUTSIDE_CURRENT_TEAM: 0,
            TEAM_RACES_BUGGED: 0,
        };
        addSectionResetButton(stats, "Reset Stats to Defaults", statsDefaults);

        const altWpm = createSection("altwpm", "Alt. WPM", "Countdown and pace helper settings.");
        addCheckbox(altWpm, 'Enable Alt. WPM', 'ENABLE_ALT_WPM_COUNTER', ENABLE_ALT_WPM_COUNTER, "Shows the draggable pace helper during the race.");
        addCheckbox(altWpm, 'Enable Countdown', 'ENABLE_ALT_WPM_COUNTDOWN', ENABLE_ALT_WPM_COUNTDOWN, "Shows the draggable race-start countdown even if Alt. WPM is turned off.");
        addNumberInput(altWpm, 'Target WPM (1 = No Sandbagging)', 'targetWPM', config.targetWPM, "Your pacing target. Lower values encourage slower controlled finishes.");
        addNumberInput(altWpm, 'Alt. WPM: Yellow when +X WPM', 'indicateWPMWithin', config.indicateWPMWithin, "Highlight threshold near your target WPM.");
        addNumberInput(altWpm, 'Alt. WPM: Refresh int.', 'timerRefreshIntervalMS', config.timerRefreshIntervalMS, "How often the helper updates (milliseconds).");
        addNumberInput(altWpm, 'Alt. WPM: +X WPM Delay', 'dif', config.dif, "Small offset applied to displayed possible WPM.");
        const altWpmDefaults = {
            ENABLE_ALT_WPM_COUNTER: true,
            ENABLE_ALT_WPM_COUNTDOWN: true,
            targetWPM: 79.5,
            indicateWPMWithin: 2,
            timerRefreshIntervalMS: 25,
            dif: 0.8,
        };
        addSectionResetButton(altWpm, "Reset Alt. WPM to Defaults", altWpmDefaults);

        const perfectNitro = createSection("perfectnitro", "Perfect Nitros", "Longest-word highlight settings.");

        // Perfect Nitro Preview
        const pnPreviewText = "the quick brown fox jumps";
        const pnHighlightWord = "jumps"; // the "longest" word to highlight
        const pnHighlightStart = pnPreviewText.indexOf(pnHighlightWord);
        const pnHighlightEnd = pnHighlightStart + pnHighlightWord.length;

        const createPerfectNitroPreview = () => {
            const preview = document.createElement("div");
            preview.className = "ntcfg-pn-preview";

            const render = () => {
                const options = getPerfectNitroOptions();
                const themeOptions = getThemeEngineOptions();
                preview.innerHTML = "";

                // Set background to match effective theme background
                if (themeOptions.darkModeEffective) {
                    preview.style.background = THEME_DARK_MODE_BACKGROUND;
                    preview.style.color = THEME_DARK_MODE_FOREGROUND;
                } else if (themeOptions.overrideBackground) {
                    preview.style.background = themeOptions.background;
                    preview.style.color = "";
                } else {
                    preview.style.background = "";
                    preview.style.color = "";
                }

                // Apply font family from theme
                if (themeOptions.fontFamilyCss) {
                    preview.style.fontFamily = themeOptions.fontFamilyCss;
                } else {
                    preview.style.fontFamily = "";
                }

                const bgRgba = options.enableHighlight ? hexToRgba(options.highlightColor, options.highlightOpacity) : null;
                const textStyle = options.overrideTextColor
                    ? { color: options.textColor, shadow: null }
                    : options.enableHighlight
                        ? getPerfectNitroTextStyle(options.highlightColor, options.highlightOpacity)
                        : { color: null, shadow: null };

                Array.from(pnPreviewText).forEach((char, index) => {
                    const span = document.createElement("span");
                    span.textContent = char;

                    const isHighlighted = index >= pnHighlightStart && index < pnHighlightEnd;

                    if (isHighlighted) {
                        if (bgRgba) {
                            span.style.backgroundColor = bgRgba;
                        }
                        if (textStyle.color) {
                            span.style.color = textStyle.color;
                        }
                        if (textStyle.shadow) {
                            span.style.textShadow = textStyle.shadow;
                        }
                        if (options.italic) {
                            span.style.fontStyle = "italic";
                        }
                        if (options.rainbow) {
                            span.classList.add("ntcfg-pn-preview-rainbow");
                        }
                    } else {
                        // Untyped text style
                        if (themeOptions.overrideForeground) {
                            span.style.color = themeOptions.foreground;
                        } else if (themeOptions.darkModeEffective) {
                            span.style.color = THEME_DARK_MODE_FOREGROUND;
                        }
                    }

                    preview.appendChild(span);
                });
            };

            render();
            return { preview, render };
        };

        const pnStickyWrapper = document.createElement("div");
        pnStickyWrapper.className = "ntcfg-sticky-preview";

        const pnPreviewLabel = document.createElement("div");
        pnPreviewLabel.className = "ntcfg-theme-preview-label";
        pnPreviewLabel.textContent = "Preview:";
        pnStickyWrapper.appendChild(pnPreviewLabel);

        const pnPreview = createPerfectNitroPreview();
        pnStickyWrapper.appendChild(pnPreview.preview);
        perfectNitro.appendChild(pnStickyWrapper);

        const renderPnPreview = () => { pnPreview.render(); };
        window.addEventListener(PERFECT_NITRO_UPDATED_EVENT, renderPnPreview);
        window.addEventListener(THEME_ENGINE_UPDATED_EVENT, renderPnPreview);

        addCheckbox(perfectNitro, 'Enable Perfect Nitros', 'ENABLE_PERFECT_NITROS', ENABLE_PERFECT_NITROS, "Highlights the best long-word nitro target.");
        // Highlight background toggle with inline color + opacity
        (() => {
            const row = document.createElement("div");
            row.className = "ntcfg-checkbox";

            const copy = document.createElement("span");
            copy.className = "ntcfg-checkbox-copy";
            const title = document.createElement("span");
            title.className = "ntcfg-checkbox-label";
            title.textContent = "Highlight background";
            const help = document.createElement("span");
            help.className = "ntcfg-checkbox-help";
            help.textContent = "Background color and opacity for the perfect nitro word.";
            copy.append(title, help);

            const controls = document.createElement("span");
            controls.className = "ntcfg-checkbox-controls";

            // Color picker (compact)
            const colorWrap = document.createElement("span");
            colorWrap.className = "ntcfg-checkbox-controls";
            const colorInput = document.createElement("input");
            colorInput.type = "color";
            colorInput.className = "ntcfg-color-picker";
            const hexInput = document.createElement("input");
            hexInput.type = "text";
            hexInput.className = "ntcfg-input";
            hexInput.maxLength = 7;
            hexInput.placeholder = "#FFFFFF";

            const startingHex = normalizeHexColor(GM_getValue("PERFECT_NITRO_HIGHLIGHT_COLOR", PERFECT_NITRO_HIGHLIGHT_COLOR));
            colorInput.value = startingHex;
            hexInput.value = startingHex;
            bindSettingInput("PERFECT_NITRO_HIGHLIGHT_COLOR", (value) => {
                const n = normalizeHexColor(value);
                colorInput.value = n;
                hexInput.value = n;
            });
            colorInput.addEventListener("input", () => {
                const hex = normalizeHexColor(colorInput.value, startingHex);
                hexInput.value = hex;
                setNtcfgRaceOptionsValue("PERFECT_NITRO_HIGHLIGHT_COLOR", hex);
                maybeApplyLiveThemeSetting("PERFECT_NITRO_HIGHLIGHT_COLOR");
            });
            const commitHex = () => {
                const hex = normalizeHexColor(hexInput.value, colorInput.value || startingHex);
                hexInput.value = hex;
                colorInput.value = hex;
                setNtcfgRaceOptionsValue("PERFECT_NITRO_HIGHLIGHT_COLOR", hex);
                maybeApplyLiveThemeSetting("PERFECT_NITRO_HIGHLIGHT_COLOR");
            };
            hexInput.addEventListener("change", commitHex);
            hexInput.addEventListener("blur", commitHex);
            colorWrap.append(colorInput, hexInput);

            // Opacity select
            const opacitySelect = document.createElement("select");
            opacitySelect.className = "ntcfg-input ntcfg-theme-input-compact";
            const opacityOptions = [
                { value: "0.25", label: "25%" },
                { value: "0.5", label: "50%" },
                { value: "0.75", label: "75%" },
                { value: "1", label: "100%" },
            ];
            opacityOptions.forEach((opt) => {
                const option = document.createElement("option");
                option.value = opt.value;
                option.textContent = opt.label;
                opacitySelect.appendChild(option);
            });
            const normalizeOpacitySelect = (val) => {
                const n = String(normalizeHighlightOpacity(val));
                return opacityOptions.some((o) => o.value === n) ? n : "0.5";
            };
            opacitySelect.value = normalizeOpacitySelect(GM_getValue("PERFECT_NITRO_HIGHLIGHT_OPACITY", PERFECT_NITRO_HIGHLIGHT_OPACITY));
            opacitySelect.addEventListener("change", () => {
                setNtcfgRaceOptionsValue("PERFECT_NITRO_HIGHLIGHT_OPACITY", opacitySelect.value);
                maybeApplyLiveThemeSetting("PERFECT_NITRO_HIGHLIGHT_OPACITY");
            });
            bindSettingInput("PERFECT_NITRO_HIGHLIGHT_OPACITY", (value) => {
                opacitySelect.value = normalizeOpacitySelect(value);
            });

            // Toggle
            const isOn = GM_getValue("PERFECT_NITRO_ENABLE_HIGHLIGHT", PERFECT_NITRO_ENABLE_HIGHLIGHT);
            colorWrap.hidden = !isOn;
            opacitySelect.hidden = !isOn;

            const switchRoot = document.createElement("span");
            switchRoot.className = "ntcfg-switch";
            const toggleInput = document.createElement("input");
            toggleInput.type = "checkbox";
            toggleInput.checked = isOn;
            toggleInput.addEventListener("change", () => {
                setNtcfgRaceOptionsValue("PERFECT_NITRO_ENABLE_HIGHLIGHT", toggleInput.checked);
                colorWrap.hidden = !toggleInput.checked;
                opacitySelect.hidden = !toggleInput.checked;
                maybeApplyLiveThemeSetting("PERFECT_NITRO_ENABLE_HIGHLIGHT");
            });
            bindSettingInput("PERFECT_NITRO_ENABLE_HIGHLIGHT", (value) => {
                toggleInput.checked = !!value;
                colorWrap.hidden = !value;
                opacitySelect.hidden = !value;
            });
            const track = document.createElement("span");
            track.className = "ntcfg-switch-track";
            switchRoot.append(toggleInput, track);

            controls.append(colorWrap, opacitySelect, switchRoot);
            row.append(copy, controls);
            perfectNitro.appendChild(row);
        })();
        // Text color override toggle with inline color picker
        (() => {
            const row = document.createElement("div");
            row.className = "ntcfg-checkbox";

            const copy = document.createElement("span");
            copy.className = "ntcfg-checkbox-copy";
            const title = document.createElement("span");
            title.className = "ntcfg-checkbox-label";
            title.textContent = "Text color";
            const help = document.createElement("span");
            help.className = "ntcfg-checkbox-help";
            help.textContent = "Custom text color instead of auto-contrast.";
            copy.append(title, help);

            const controls = document.createElement("span");
            controls.className = "ntcfg-checkbox-controls";

            // Color picker (compact)
            const colorWrap = document.createElement("span");
            colorWrap.className = "ntcfg-checkbox-controls";
            const colorInput = document.createElement("input");
            colorInput.type = "color";
            colorInput.className = "ntcfg-color-picker";
            const hexInput = document.createElement("input");
            hexInput.type = "text";
            hexInput.className = "ntcfg-input";
            hexInput.maxLength = 7;
            hexInput.placeholder = "#FFFFFF";

            const startingHex = normalizeHexColor(GM_getValue("PERFECT_NITRO_TEXT_COLOR", PERFECT_NITRO_TEXT_COLOR));
            colorInput.value = startingHex;
            hexInput.value = startingHex;
            bindSettingInput("PERFECT_NITRO_TEXT_COLOR", (value) => {
                const n = normalizeHexColor(value);
                colorInput.value = n;
                hexInput.value = n;
            });
            colorInput.addEventListener("input", () => {
                const hex = normalizeHexColor(colorInput.value, startingHex);
                hexInput.value = hex;
                setNtcfgRaceOptionsValue("PERFECT_NITRO_TEXT_COLOR", hex);
                maybeApplyLiveThemeSetting("PERFECT_NITRO_TEXT_COLOR");
            });
            const commitHex = () => {
                const hex = normalizeHexColor(hexInput.value, colorInput.value || startingHex);
                hexInput.value = hex;
                colorInput.value = hex;
                setNtcfgRaceOptionsValue("PERFECT_NITRO_TEXT_COLOR", hex);
                maybeApplyLiveThemeSetting("PERFECT_NITRO_TEXT_COLOR");
            };
            hexInput.addEventListener("change", commitHex);
            hexInput.addEventListener("blur", commitHex);
            colorWrap.append(colorInput, hexInput);

            // Toggle
            const isOn = GM_getValue("PERFECT_NITRO_OVERRIDE_TEXT_COLOR", PERFECT_NITRO_OVERRIDE_TEXT_COLOR);
            colorWrap.hidden = !isOn;

            const switchRoot = document.createElement("span");
            switchRoot.className = "ntcfg-switch";
            const toggleInput = document.createElement("input");
            toggleInput.type = "checkbox";
            toggleInput.checked = isOn;
            toggleInput.addEventListener("change", () => {
                setNtcfgRaceOptionsValue("PERFECT_NITRO_OVERRIDE_TEXT_COLOR", toggleInput.checked);
                colorWrap.hidden = !toggleInput.checked;
                maybeApplyLiveThemeSetting("PERFECT_NITRO_OVERRIDE_TEXT_COLOR");
            });
            bindSettingInput("PERFECT_NITRO_OVERRIDE_TEXT_COLOR", (value) => {
                toggleInput.checked = !!value;
                colorWrap.hidden = !value;
            });
            const track = document.createElement("span");
            track.className = "ntcfg-switch-track";
            switchRoot.append(toggleInput, track);

            controls.append(colorWrap, switchRoot);
            row.append(copy, controls);
            perfectNitro.appendChild(row);
        })();
        addCheckbox(perfectNitro, 'Italic Perfect Nitro Word', 'PERFECT_NITRO_ITALIC', PERFECT_NITRO_ITALIC, "Applies italic styling to the highlighted perfect nitro word.");
        addCheckbox(perfectNitro, 'Rainbow Perfect Nitro Word', 'PERFECT_NITRO_RAINBOW', PERFECT_NITRO_RAINBOW, "Applies a cycling rainbow color animation to the highlighted perfect nitro word.");
        addNumberInput(perfectNitro, 'Perfect Nitro Scan Interval (ms)', 'PERFECT_NITRO_SCAN_INTERVAL_MS', PERFECT_NITRO_SCAN_INTERVAL_MS, "How frequently to scan for the best nitro word.");
        const perfectNitroDefaults = {
            ENABLE_PERFECT_NITROS: true,
            PERFECT_NITRO_ENABLE_HIGHLIGHT: true,
            PERFECT_NITRO_HIGHLIGHT_COLOR: "#FFFFFF",
            PERFECT_NITRO_HIGHLIGHT_OPACITY: 0.5,
            PERFECT_NITRO_OVERRIDE_TEXT_COLOR: false,
            PERFECT_NITRO_TEXT_COLOR: "#FFFFFF",
            PERFECT_NITRO_ITALIC: false,
            PERFECT_NITRO_RAINBOW: false,
            PERFECT_NITRO_SCAN_INTERVAL_MS: 100,
        };
        addSectionResetButton(perfectNitro, "Reset Perfect Nitros to Defaults", perfectNitroDefaults);

        const themeEngine = createSection("themeengine", "Theme", "Customize the colors on the racetrack.");
        const themePreviewText = "The Quick Brown Fox is afraid of The Big Black";

        const createThemePreview = (cursorIndex, incorrect = false) => {
            const preview = document.createElement("div");
            preview.className = "ntcfg-theme-preview";

            const render = () => {
                const options = getThemeEngineOptions();
                preview.innerHTML = "";
                if (options.darkModeEffective) {
                    preview.style.background = THEME_DARK_MODE_BACKGROUND;
                    preview.style.color = THEME_DARK_MODE_FOREGROUND;
                } else if (options.overrideBackground) {
                    preview.style.background = options.background;
                    preview.style.color = "";
                } else {
                    preview.style.background = "";
                    preview.style.color = "";
                }
                if (options.fontFamilyCss) {
                    preview.style.fontFamily = options.fontFamilyCss;
                } else {
                    preview.style.fontFamily = "";
                }
                preview.style.fontWeight = String(options.fontWeight || THEME_FONT_WEIGHT_DEFAULT);
                preview.style.fontStyle = options.fontItalic ? "italic" : "";

                Array.from(themePreviewText).forEach((char, index) => {
                    const span = document.createElement("span");
                    if (index === cursorIndex) {
                        span.classList.add(incorrect ? "ntcfg-theme-char-incorrect" : "ntcfg-theme-char-active");
                    } else if (index < cursorIndex) {
                        span.classList.add("ntcfg-theme-char-typed");
                        if (options.enableRainbowTypedText && !options.hideTypedText) {
                            span.classList.add("ntcfg-theme-char-rainbow");
                            span.style.animationDuration = `${options.rainbowTypedTextSpeedSeconds}s`;
                            span.style.webkitAnimationDuration = `${options.rainbowTypedTextSpeedSeconds}s`;
                        }
                    }
                    span.textContent = char;

                    if (index > cursorIndex && options.overrideForeground) {
                        span.style.color = options.foreground;
                    } else if (index > cursorIndex && options.darkModeEffective) {
                        span.style.color = THEME_DARK_MODE_FOREGROUND;
                    }
                    if (index === cursorIndex && options.overrideForegroundActive) {
                        span.style.color = options.foregroundActive;
                    } else if (index === cursorIndex && options.darkModeEffective) {
                        span.style.color = THEME_DARK_MODE_FOREGROUND_ACTIVE;
                    }
                    if (index < cursorIndex && options.overrideForegroundTyped && !options.enableRainbowTypedText) {
                        span.style.color = options.foregroundTyped;
                        span.style.opacity = "1";
                    } else if (index < cursorIndex && options.darkModeEffective && !options.enableRainbowTypedText) {
                        span.style.color = THEME_DARK_MODE_FOREGROUND_TYPED;
                        span.style.opacity = "1";
                    }
                    if (index < cursorIndex && options.hideTypedText) {
                        span.style.color = "transparent";
                        span.style.webkitTextFillColor = "transparent";
                        span.style.textShadow = "none";
                        span.style.opacity = "0";
                    }
                    if (index === cursorIndex && !incorrect && options.overrideBackgroundActive) {
                        span.style.background = options.backgroundActive;
                    } else if (index === cursorIndex && !incorrect && options.darkModeEffective) {
                        span.style.background = THEME_DARK_MODE_BACKGROUND_ACTIVE;
                    }
                    if (index === cursorIndex && incorrect && options.overrideBackgroundIncorrect) {
                        span.style.background = options.backgroundIncorrect;
                    } else if (index === cursorIndex && incorrect && options.darkModeEffective) {
                        span.style.background = THEME_DARK_MODE_BACKGROUND_INCORRECT;
                    }
                    if (options.fontFamilyCss) {
                        span.style.fontFamily = options.fontFamilyCss;
                    }
                    if (Number.isFinite(options.fontSizePx)) {
                        span.style.fontSize = `${options.fontSizePx}px`;
                        if (_ntNativeLineHeight) {
                            span.style.lineHeight = _ntNativeLineHeight;
                        }
                    }
                    span.style.fontWeight = String(options.fontWeight || THEME_FONT_WEIGHT_DEFAULT);
                    if (options.fontItalic) {
                        span.style.fontStyle = "italic";
                    }
                    preview.appendChild(span);
                });
            };

            render();
            return { preview, render };
        };

        const stickyPreviewWrapper = document.createElement("div");
        stickyPreviewWrapper.className = "ntcfg-sticky-preview";

        const previewLabel = document.createElement("div");
        previewLabel.className = "ntcfg-theme-preview-label";
        previewLabel.textContent = "Preview:";
        stickyPreviewWrapper.appendChild(previewLabel);

        const normalPreview = createThemePreview(7, false);
        const incorrectPreview = createThemePreview(7, true);
        const previewGrid = document.createElement("div");
        previewGrid.className = "ntcfg-theme-preview-grid";
        previewGrid.append(normalPreview.preview, incorrectPreview.preview);
        stickyPreviewWrapper.appendChild(previewGrid);
        themeEngine.appendChild(stickyPreviewWrapper);

        const renderThemePreviews = () => {
            normalPreview.render();
            incorrectPreview.render();
        };
        window.addEventListener(THEME_ENGINE_UPDATED_EVENT, renderThemePreviews);

        const themeSettingsRoot = document.createElement("div");
        themeSettingsRoot.className = "ntcfg-theme-settings";
        themeEngine.append(themeSettingsRoot);

        const addThemeOption = (labelText, toggleName, toggleDefault, colorName, colorDefault) => {
            const row = document.createElement("div");
            row.className = "ntcfg-theme-setting";

            const title = document.createElement("div");
            title.className = "ntcfg-theme-setting-title";
            title.textContent = labelText;

            const controls = document.createElement("div");
            controls.className = "ntcfg-theme-setting-controls";

            const switchRoot = document.createElement("span");
            switchRoot.className = "ntcfg-switch";

            const toggleInput = document.createElement("input");
            toggleInput.type = "checkbox";
            toggleInput.checked = GM_getValue(toggleName, toggleDefault);
            toggleInput.addEventListener("change", () => {
                setNtcfgRaceOptionsValue(toggleName, toggleInput.checked);
                maybeApplyLiveThemeSetting(toggleName);
            });
            bindSettingInput(toggleName, (value) => {
                toggleInput.checked = !!value;
            });

            const track = document.createElement("span");
            track.className = "ntcfg-switch-track";
            switchRoot.append(toggleInput, track);

            const colorWrap = document.createElement("div");
            colorWrap.className = "ntcfg-theme-color-compact";

            const colorInput = document.createElement("input");
            colorInput.type = "color";
            colorInput.className = "ntcfg-color-picker";

            const hexInput = document.createElement("input");
            hexInput.type = "text";
            hexInput.className = "ntcfg-input ntcfg-color-hex";
            hexInput.maxLength = 7;
            hexInput.placeholder = "#FFFFFF";

            const startingHex = normalizeHexColor(GM_getValue(colorName, colorDefault), normalizeHexColor(colorDefault));
            colorInput.value = startingHex;
            hexInput.value = startingHex;
            bindSettingInput(colorName, (value) => {
                const normalized = normalizeHexColor(value, normalizeHexColor(colorDefault));
                colorInput.value = normalized;
                hexInput.value = normalized;
            });

            const saveColor = (value) => {
                const hex = normalizeHexColor(value, colorInput.value || startingHex);
                colorInput.value = hex;
                hexInput.value = hex;
                setNtcfgRaceOptionsValue(colorName, hex);
                maybeApplyLiveThemeSetting(colorName);
            };

            colorInput.addEventListener("input", () => saveColor(colorInput.value));
            hexInput.addEventListener("change", () => saveColor(hexInput.value));
            hexInput.addEventListener("blur", () => saveColor(hexInput.value));

            colorWrap.append(colorInput, hexInput);
            controls.append(colorWrap, switchRoot);
            row.append(title, controls);
            themeSettingsRoot.append(row);
        };

        const addThemeToggleOption = (labelText, toggleName, toggleDefault, onChange = null) => {
            const row = document.createElement("div");
            row.className = "ntcfg-theme-setting";

            const title = document.createElement("div");
            title.className = "ntcfg-theme-setting-title";
            title.textContent = labelText;

            const controls = document.createElement("div");
            controls.className = "ntcfg-theme-setting-controls";

            const switchRoot = document.createElement("span");
            switchRoot.className = "ntcfg-switch";

            const toggleInput = document.createElement("input");
            toggleInput.type = "checkbox";
            toggleInput.checked = GM_getValue(toggleName, toggleDefault);
            toggleInput.addEventListener("change", () => {
                setNtcfgRaceOptionsValue(toggleName, toggleInput.checked);
                maybeApplyLiveThemeSetting(toggleName);
                if (typeof onChange === "function") {
                    onChange(toggleInput.checked);
                }
            });
            bindSettingInput(toggleName, (value) => {
                toggleInput.checked = !!value;
                if (typeof onChange === "function") {
                    onChange(toggleInput.checked);
                }
            });

            const track = document.createElement("span");
            track.className = "ntcfg-switch-track";
            switchRoot.append(toggleInput, track);
            controls.append(switchRoot);

            row.append(title, controls);
            themeSettingsRoot.append(row);
            return { row, input: toggleInput };
        };

        const addThemeSelectOption = (labelText, valueName, valueDefault, options, onChange = null) => {
            const row = document.createElement("div");
            row.className = "ntcfg-theme-setting";

            const title = document.createElement("div");
            title.className = "ntcfg-theme-setting-title";
            title.textContent = labelText;

            const controls = document.createElement("div");
            controls.className = "ntcfg-theme-setting-controls";

            const select = document.createElement("select");
            select.className = "ntcfg-input ntcfg-theme-input-compact ntcfg-theme-input-select";

            const safeOptions = Array.isArray(options) ? options.filter(Boolean) : [];
            safeOptions.forEach((optionDef) => {
                const option = document.createElement("option");
                option.value = String(optionDef.value);
                option.textContent = String(optionDef.label ?? optionDef.value);
                select.appendChild(option);
            });

            const normalizeSelectedValue = (value) => {
                const raw = String(value ?? "").trim();
                if (safeOptions.some((optionDef) => String(optionDef.value) === raw)) {
                    return raw;
                }
                return String(valueDefault);
            };

            select.value = normalizeSelectedValue(GM_getValue(valueName, valueDefault));
            select.addEventListener("change", () => {
                const normalized = normalizeSelectedValue(select.value);
                select.value = normalized;
                setNtcfgRaceOptionsValue(valueName, normalized);
                maybeApplyLiveThemeSetting(valueName);
                if (typeof onChange === "function") {
                    onChange(normalized);
                }
            });

            bindSettingInput(valueName, (value) => {
                const normalized = normalizeSelectedValue(value);
                select.value = normalized;
                if (typeof onChange === "function") {
                    onChange(normalized);
                }
            });

            controls.append(select);
            row.append(title, controls);
            themeSettingsRoot.append(row);
            return { row, select };
        };

        const addThemeNumberOption = (
            labelText,
            valueName,
            valueDefault,
            {
                min = 1,
                max = 60,
                step = 1,
                presets = [],
                normalizeValue = (value, fallback) => {
                    const parsed = Number(value);
                    return Number.isFinite(parsed) ? parsed : Number(fallback);
                },
            } = {}
        ) => {
            const row = document.createElement("div");
            row.className = "ntcfg-theme-setting";

            const title = document.createElement("div");
            title.className = "ntcfg-theme-setting-title";
            title.textContent = labelText;

            const controls = document.createElement("div");
            controls.className = "ntcfg-theme-setting-controls";

            const input = document.createElement("input");
            input.type = "number";
            input.className = "ntcfg-input ntcfg-theme-input-compact ntcfg-theme-input-number";
            input.min = String(min);
            input.max = String(max);
            input.step = String(step);
            input.value = String(normalizeValue(GM_getValue(valueName, valueDefault), valueDefault));

            const presetSelect = document.createElement("select");
            presetSelect.className = "ntcfg-input ntcfg-theme-input-compact ntcfg-theme-input-preset";

            const customPresetValue = "__custom__";
            const customOption = document.createElement("option");
            customOption.value = customPresetValue;
            customOption.textContent = "Custom";
            presetSelect.appendChild(customOption);

            const normalizedPresets = Array.isArray(presets)
                ? presets
                    .map((preset) => {
                        if (!preset || typeof preset !== "object") return null;
                        const value = normalizeValue(preset.value, valueDefault);
                        const label = String(preset.label || `${value}s`).trim();
                        return { value, label };
                    })
                    .filter(Boolean)
                : [];

            normalizedPresets.forEach((preset) => {
                const option = document.createElement("option");
                option.value = String(preset.value);
                option.textContent = `${preset.label} (${preset.value}s)`;
                presetSelect.appendChild(option);
            });

            const syncPresetFromValue = (value) => {
                const matched = normalizedPresets.find((preset) => preset.value === value);
                presetSelect.value = matched ? String(matched.value) : customPresetValue;
            };

            const save = () => {
                const normalized = normalizeValue(input.value, valueDefault);
                input.value = String(normalized);
                syncPresetFromValue(normalized);
                setNtcfgRaceOptionsValue(valueName, normalized);
                maybeApplyLiveThemeSetting(valueName);
            };

            input.addEventListener("change", save);
            input.addEventListener("blur", save);

            presetSelect.addEventListener("change", () => {
                if (presetSelect.value === customPresetValue) {
                    return;
                }
                const normalized = normalizeValue(presetSelect.value, valueDefault);
                input.value = String(normalized);
                setNtcfgRaceOptionsValue(valueName, normalized);
                maybeApplyLiveThemeSetting(valueName);
            });

            bindSettingInput(valueName, (value) => {
                const normalized = normalizeValue(value, valueDefault);
                input.value = String(normalized);
                syncPresetFromValue(normalized);
            });

            controls.append(input);
            if (normalizedPresets.length > 0) {
                controls.append(presetSelect);
                syncPresetFromValue(normalizeValue(input.value, valueDefault));
            }
            row.append(title, controls);
            themeSettingsRoot.append(row);
            return { row, input, presetSelect };
        };

        // — Dark mode —
        // Dark mode toggle with inline "Always" / "Same as system" dropdown
        (() => {
            const row = document.createElement("div");
            row.className = "ntcfg-theme-setting";

            const title = document.createElement("div");
            title.className = "ntcfg-theme-setting-title";
            title.textContent = "Dark mode";

            const controls = document.createElement("div");
            controls.className = "ntcfg-theme-setting-controls";

            const modeSelect = document.createElement("select");
            modeSelect.className = "ntcfg-input ntcfg-theme-input-compact ntcfg-theme-input-select";

            const modeOptions = [
                { value: "always", label: "Always" },
                { value: "system", label: "Same as system" },
            ];
            modeOptions.forEach((opt) => {
                const option = document.createElement("option");
                option.value = opt.value;
                option.textContent = opt.label;
                modeSelect.appendChild(option);
            });

            const isSyncSystem = GM_getValue("THEME_DARK_MODE_SYNC_SYSTEM", THEME_DARK_MODE_SYNC_SYSTEM);
            modeSelect.value = isSyncSystem ? "system" : "always";

            const isDarkOn = GM_getValue("THEME_ENABLE_DARK_MODE", THEME_ENABLE_DARK_MODE);
            modeSelect.hidden = !isDarkOn;

            modeSelect.addEventListener("change", () => {
                const isSystem = modeSelect.value === "system";
                setNtcfgRaceOptionsValue("THEME_DARK_MODE_SYNC_SYSTEM", isSystem);
                maybeApplyLiveThemeSetting("THEME_DARK_MODE_SYNC_SYSTEM");
            });
            bindSettingInput("THEME_DARK_MODE_SYNC_SYSTEM", (value) => {
                modeSelect.value = value ? "system" : "always";
            });

            const switchRoot = document.createElement("span");
            switchRoot.className = "ntcfg-switch";
            const toggleInput = document.createElement("input");
            toggleInput.type = "checkbox";
            toggleInput.checked = isDarkOn;
            toggleInput.addEventListener("change", () => {
                setNtcfgRaceOptionsValue("THEME_ENABLE_DARK_MODE", toggleInput.checked);
                modeSelect.hidden = !toggleInput.checked;
                if (!toggleInput.checked) {
                    setNtcfgRaceOptionsValue("THEME_DARK_MODE_SYNC_SYSTEM", false);
                    modeSelect.value = "always";
                }
                maybeApplyLiveThemeSetting("THEME_ENABLE_DARK_MODE");
            });
            bindSettingInput("THEME_ENABLE_DARK_MODE", (value) => {
                toggleInput.checked = !!value;
                modeSelect.hidden = !value;
            });
            const track = document.createElement("span");
            track.className = "ntcfg-switch-track";
            switchRoot.append(toggleInput, track);

            controls.append(modeSelect, switchRoot);
            row.append(title, controls);
            themeSettingsRoot.append(row);
        })();

        // — Font —
        addThemeSelectOption(
            "Font family",
            "THEME_FONT_FAMILY_PRESET",
            "__default__",
            THEME_FONT_FAMILY_PRESETS.map((preset) => ({ value: preset.value, label: preset.label }))
        );
        addThemeSelectOption(
            "Font size",
            "THEME_FONT_SIZE_PRESET",
            "__default__",
            THEME_FONT_SIZE_PRESETS.map((preset) => ({ value: preset.value, label: preset.label }))
        );
        addThemeSelectOption(
            "Single-line font size",
            "THEME_SINGLE_LINE_FONT_SIZE_PRESET",
            "__default__",
            THEME_FONT_SIZE_PRESETS.map((preset) => ({ value: preset.value, label: preset.label }))
        );
        // Bold text toggle with inline weight select
        (() => {
            const row = document.createElement("div");
            row.className = "ntcfg-theme-setting";

            const title = document.createElement("div");
            title.className = "ntcfg-theme-setting-title";
            title.textContent = "Bold text";

            const controls = document.createElement("div");
            controls.className = "ntcfg-theme-setting-controls";

            const weightSelect = document.createElement("select");
            weightSelect.className = "ntcfg-input ntcfg-theme-input-compact ntcfg-theme-input-select";

            const weightOptions = [
                { value: "300", label: "Light" },
                { value: "500", label: "Medium" },
                { value: "600", label: "Semi-Bold" },
                { value: "700", label: "Bold" },
                { value: "800", label: "Extra-Bold" },
                { value: "900", label: "Black" },
            ];
            weightOptions.forEach((opt) => {
                const option = document.createElement("option");
                option.value = opt.value;
                option.textContent = opt.label;
                weightSelect.appendChild(option);
            });

            const normalizeWeight = (val) => {
                const s = String(val ?? "700").trim();
                return weightOptions.some((o) => o.value === s) ? s : "700";
            };
            weightSelect.value = normalizeWeight(GM_getValue("THEME_FONT_WEIGHT", THEME_FONT_WEIGHT));
            weightSelect.addEventListener("change", () => {
                const normalized = normalizeWeight(weightSelect.value);
                weightSelect.value = normalized;
                setNtcfgRaceOptionsValue("THEME_FONT_WEIGHT", normalized);
                maybeApplyLiveThemeSetting("THEME_FONT_WEIGHT");
            });
            bindSettingInput("THEME_FONT_WEIGHT", (value) => {
                weightSelect.value = normalizeWeight(value);
            });

            const isBoldOn = GM_getValue("THEME_FONT_BOLD", THEME_FONT_BOLD);
            weightSelect.hidden = !isBoldOn;

            const switchRoot = document.createElement("span");
            switchRoot.className = "ntcfg-switch";
            const toggleInput = document.createElement("input");
            toggleInput.type = "checkbox";
            toggleInput.checked = isBoldOn;
            toggleInput.addEventListener("change", () => {
                setNtcfgRaceOptionsValue("THEME_FONT_BOLD", toggleInput.checked);
                weightSelect.hidden = !toggleInput.checked;
                maybeApplyLiveThemeSetting("THEME_FONT_BOLD");
            });
            bindSettingInput("THEME_FONT_BOLD", (value) => {
                toggleInput.checked = !!value;
                weightSelect.hidden = !value;
            });
            const track = document.createElement("span");
            track.className = "ntcfg-switch-track";
            switchRoot.append(toggleInput, track);

            controls.append(weightSelect, switchRoot);
            row.append(title, controls);
            themeSettingsRoot.append(row);
        })();
        addThemeToggleOption("Italic text", "THEME_FONT_ITALIC", THEME_FONT_ITALIC);

        // — Colors —
        addThemeOption("Background color", "THEME_OVERRIDE_BACKGROUND", THEME_OVERRIDE_BACKGROUND, "THEME_COLOR_BACKGROUND", THEME_COLOR_BACKGROUND);
        addThemeOption("Text color", "THEME_OVERRIDE_FOREGROUND", THEME_OVERRIDE_FOREGROUND, "THEME_COLOR_FOREGROUND", THEME_COLOR_FOREGROUND);
        addThemeOption("Active letter color", "THEME_OVERRIDE_FOREGROUND_ACTIVE", THEME_OVERRIDE_FOREGROUND_ACTIVE, "THEME_COLOR_FOREGROUND_ACTIVE", THEME_COLOR_FOREGROUND_ACTIVE);
        addThemeOption("Active letter background", "THEME_OVERRIDE_BACKGROUND_ACTIVE", THEME_OVERRIDE_BACKGROUND_ACTIVE, "THEME_COLOR_BACKGROUND_ACTIVE", THEME_COLOR_BACKGROUND_ACTIVE);
        addThemeOption("Typed letter color", "THEME_OVERRIDE_FOREGROUND_TYPED", THEME_OVERRIDE_FOREGROUND_TYPED, "THEME_COLOR_FOREGROUND_TYPED", THEME_COLOR_FOREGROUND_TYPED);
        addThemeOption("Incorrect letter background", "THEME_OVERRIDE_BACKGROUND_INCORRECT", THEME_OVERRIDE_BACKGROUND_INCORRECT, "THEME_COLOR_BACKGROUND_INCORRECT", THEME_COLOR_BACKGROUND_INCORRECT);

        // — Effects —
        addThemeToggleOption("Hide typed letters", "THEME_HIDE_TYPED_TEXT", THEME_HIDE_TYPED_TEXT);

        let rainbowSpeedOption = null;
        const setRainbowOptionsVisibility = (enabled) => {
            if (rainbowSpeedOption?.row) {
                rainbowSpeedOption.row.hidden = !enabled;
            }
        };
        addThemeToggleOption(
            "Rainbow typed text",
            "THEME_ENABLE_RAINBOW_TYPED_TEXT",
            THEME_ENABLE_RAINBOW_TYPED_TEXT,
            setRainbowOptionsVisibility
        );
        rainbowSpeedOption = addThemeNumberOption(
            "Rainbow speed (seconds)",
            "THEME_RAINBOW_TYPED_TEXT_SPEED_SECONDS",
            THEME_RAINBOW_TYPED_TEXT_SPEED_SECONDS,
            {
                min: 1,
                max: 60,
                step: 0.5,
                normalizeValue: normalizeRainbowSpeedSeconds,
                presets: [
                    { label: "Fast", value: 5 },
                    { label: "Normal", value: 10 },
                    { label: "Slow", value: 15 },
                    { label: "Very Slow", value: 25 },
                ],
            }
        );
        setRainbowOptionsVisibility(GM_getValue("THEME_ENABLE_RAINBOW_TYPED_TEXT", THEME_ENABLE_RAINBOW_TYPED_TEXT));

        const themeDefaults = {
            THEME_ENABLE_DARK_MODE: false,
            THEME_DARK_MODE_SYNC_SYSTEM: false,
            THEME_OVERRIDE_BACKGROUND: false,
            THEME_OVERRIDE_FOREGROUND: false,
            THEME_OVERRIDE_FOREGROUND_ACTIVE: false,
            THEME_OVERRIDE_FOREGROUND_TYPED: false,
            THEME_HIDE_TYPED_TEXT: false,
            THEME_OVERRIDE_BACKGROUND_ACTIVE: false,
            THEME_OVERRIDE_BACKGROUND_INCORRECT: false,
            THEME_FONT_SIZE_PRESET: "__default__",
            THEME_SINGLE_LINE_FONT_SIZE_PRESET: "__default__",
            THEME_FONT_FAMILY_PRESET: "__default__",
            THEME_FONT_BOLD: false,
            THEME_FONT_WEIGHT: 700,
            THEME_FONT_ITALIC: false,
            THEME_ENABLE_RAINBOW_TYPED_TEXT: false,
            THEME_RAINBOW_TYPED_TEXT_SPEED_SECONDS: 10,
            THEME_COLOR_BACKGROUND,
            THEME_COLOR_FOREGROUND,
            THEME_COLOR_FOREGROUND_ACTIVE,
            THEME_COLOR_FOREGROUND_TYPED,
            THEME_COLOR_BACKGROUND_ACTIVE,
            THEME_COLOR_BACKGROUND_INCORRECT,
        };

        addSectionResetButton(themeEngine, "Reset Theme to Defaults", themeDefaults, () => {
            renderThemePreviews();
        });

        const openPanel = () => {
            overlay.classList.add("is-open");
            broadcastFocusLock(true);
            const firstFocusable = overlay.querySelector("input, button");
            if (firstFocusable) {
                setTimeout(() => firstFocusable.focus(), 0);
            }
        };
        const closePanel = () => {
            overlay.classList.remove("is-open");
            broadcastFocusLock(false);
        };

        saveBtn.addEventListener("click", () => location.reload());
        closeBtn.addEventListener("click", closePanel);
        backdrop.addEventListener("click", closePanel);
        const stopEvent = (e) => { e.stopPropagation(); };
        overlay.addEventListener("mousedown", (e) => { e.stopPropagation(); broadcastFocusLock(true); }, false);
        overlay.addEventListener("click", stopEvent, false);
        overlay.addEventListener("keydown", (e) => {
            stopEvent(e);
            if (e.key === "Escape") {
                closePanel();
            }
        }, true);
        overlay.addEventListener("keyup", stopEvent, true);
        overlay.addEventListener("mouseenter", () => broadcastFocusLock(true));
        overlay.addEventListener("mouseleave", () => {
            if (!overlay.contains(document.activeElement)) {
                broadcastFocusLock(false);
            }
        });
        document.addEventListener("keydown", (e) => {
            if (e.key === "Escape" && overlay.classList.contains("is-open")) {
                closePanel();
            }
        });

        const configureButton = document.createElement('button');
        configureButton.textContent = 'Configure';
        configureButton.className = "ntcfg-open-btn";
        configureButton.addEventListener("click", () => {
            if (overlay.classList.contains("is-open")) {
                closePanel();
                return;
            }
            openPanel();
        });
        document.body.appendChild(configureButton);
    };

    createUI();


    /** Finds the React Component from given dom. */
    const findReact = (dom, traverseUp = 0) => {
        const key = Object.keys(dom).find((key) => key.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
    }

    var my_race_started = false;

    const RACE_VISUAL_STYLE_ID = "ntcfg-race-visual-live-style";
    const isRaceOptionEnabledNow = (settingKey, fallback = false) => {
        const liveValue = readNtcfgRaceOptionsValue(settingKey)
        return typeof liveValue === "undefined" ? !!fallback : !!liveValue
    }
    const applyRaceVisualStyles = () => {
        const rules = [];
        if (isRaceOptionEnabledNow("hideTrack", false)) {
            rules.push(`.racev3-track { opacity: 0 !important; margin-top: -400px !important; }`);
        }
        if (isRaceOptionEnabledNow("hideNotifications", true)) {
            rules.push(`.growls { display: none !important; }`);
        }
        if (isRaceOptionEnabledNow("HIDE_CHAT_AND_STICKERS", false)) {
            rules.push(`.raceChat { display: none !important; }`);
        }
        if (isRaceOptionEnabledNow("HIDE_FINISH_FLAG", false)) {
            rules.push(`.dash-letter > img[alt="Finish"] { display: none !important; }`);
        }

        let styleNode = document.getElementById(RACE_VISUAL_STYLE_ID);
        if (rules.length === 0) {
            styleNode?.remove();
            return;
        }
        if (!styleNode) {
            styleNode = document.createElement("style");
            styleNode.id = RACE_VISUAL_STYLE_ID;
            document.head.appendChild(styleNode);
        }
        styleNode.textContent = rules.join("\n");
    }

    applyRaceVisualStyles()
    function isRaceOptionsDebugEnabled() {
        return readNtcfgRaceOptionsValue('DEBUG_LOGGING') === true;
    }

    /** Create a Console Logger with some prefixing. */
    const createLogger = (namespace) => {
        const logPrefix = (prefix = "") => {
            const formatMessage = `%c[${namespace}]${prefix ? `%c[${prefix}]` : ""}`
            let args = [console, `${formatMessage}%c`, "background-color: #D62F3A; color: #fff; font-weight: bold"]
            if (prefix) {
                args = args.concat("background-color: #4f505e; color: #fff; font-weight: bold")
            }
            return args.concat("color: unset")
        }
        const bindConsoleMethod = (methodName, prefix) => Function.prototype.bind.apply(console[methodName], logPrefix(prefix))
        const bindGatedMethod = (methodName, prefix) => (...args) => {
            if (!isRaceOptionsDebugEnabled()) return
            bindConsoleMethod(methodName, prefix)(...args)
        }
        return {
            info: (prefix) => bindGatedMethod("info", prefix),
            warn: (prefix) => bindConsoleMethod("warn", prefix),
            error: (prefix) => bindConsoleMethod("error", prefix),
            log: (prefix) => bindGatedMethod("log", prefix),
            debug: (prefix) => bindGatedMethod("debug", prefix),
        }
    }

    function logstats() {
        const raceContainer = document.getElementById("raceContainer"),
            canvasTrack = raceContainer?.querySelector("canvas"),
            raceObj = raceContainer ? findReact(raceContainer) : null;
        const currentUserID = raceObj.props.user.userID;
        const currentUserResult = raceObj.state.racers.find((r) => r.userID === currentUserID)
        if (!currentUserResult || !currentUserResult.progress || typeof currentUserResult.place === "undefined") {
            console.log("STATS LOGGER: Unable to find race results");
            return
        }

        const {
            typed,
            skipped,
            startStamp,
            completeStamp,
            errors
        } = currentUserResult.progress,
            wpm = Math.round((typed - skipped) / 5 / ((completeStamp - startStamp) / 6e4)),
            time = ((completeStamp - startStamp) / 1e3).toFixed(2),
            acc = ((1 - errors / (typed - skipped)) * 100).toFixed(2),
            points = Math.round((100 + wpm / 2) * (1 - errors / (typed - skipped))),
            place = currentUserResult.place

        console.log(`STATS LOGGER: ${place} | ${acc}% Acc | ${wpm} WPM | ${points} points | ${time} secs`)
    }
    const logging = createLogger("Nitro Type Racing Stats")

    /** Auto close reward popup takeover (optional). */
    const setupAutoCloseRewardPopup = () => {
        const getRootContainer = () => document.getElementById("root")

        const lastAttemptByNode = new WeakMap()
        const shouldAttempt = (node) => {
            const now = Date.now()
            const prev = lastAttemptByNode.get(node) || 0
            if (now - prev < 500) return false
            lastAttemptByNode.set(node, now)
            return true
        }

        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
        }

        const findCloseFn = (dom) => {
            let fiber = getReactFiber(dom)
            let steps = 0
            while (fiber && steps++ < 60) {
                const props = fiber.memoizedProps || fiber.pendingProps || null
                if (props && typeof props.close === "function") {
                    return props.close
                }
                const stateNodeProps = fiber.stateNode?.props
                if (stateNodeProps && typeof stateNodeProps.close === "function") {
                    return stateNodeProps.close
                }
                fiber = fiber.return
            }
            return null
        }

        const closeEventsRewardsPopup = (node) => {
            if (!node || !node.classList?.contains("events--rewards")) return false
            if (!node.classList.contains("is-visible")) return false
            if (!shouldAttempt(node)) return true

            const actions = node.querySelector?.(".events--rewards--actions")
            const buttons = actions ? Array.from(actions.querySelectorAll(".btn")) : []
            const byText = (t) => buttons.find((b) => (b.textContent || "").trim().toLowerCase() === t)
            const closeBtn =
                byText("close") ||
                byText("continue") ||
                actions?.querySelector?.(".btn--primary") ||
                buttons[buttons.length - 1] ||
                null

            if (closeBtn && typeof closeBtn.click === "function") {
                closeBtn.click()
                return true
            }

            const closeFn = findCloseFn(node)
            if (typeof closeFn === "function") {
                try {
                    closeFn()
                    return true
                } catch {
                    // ignore and fall through
                }
            }

            // Last resort: hide it so it can't block the UI.
            try {
                node.style.display = "none"
                node.style.pointerEvents = "none"
                node.classList.remove("is-visible")
            } catch {
                // ignore
            }
            return true
        }

        const closeTakeoverTempPopup = (node) => {
            if (!node || !node.classList?.contains("takeoverTemp")) return false
            if (!shouldAttempt(node)) return true

            const closeBtn =
                node.querySelector?.('[data-testid="close"]') ||
                node.querySelector?.('button[aria-label="Close"]') ||
                node.querySelector?.('[aria-label="Close"]') ||
                node.querySelector?.('button[title="Close"]') ||
                node.querySelector?.('button[class*="close"]') ||
                node.querySelector?.('[role="button"][aria-label="Close"]') ||
                null

            if (closeBtn && typeof closeBtn.click === "function") {
                closeBtn.click()
                return true
            }

            const closeFn = findCloseFn(node)
            if (typeof closeFn === "function") {
                try {
                    closeFn()
                    return true
                } catch {
                    // ignore and fall through
                }
            }

            // Last resort: hide it so it can't block the UI.
            try {
                node.style.display = "none"
                node.style.pointerEvents = "none"
            } catch {
                // ignore
            }
            return true
        }

        const scanAndClose = () => {
            // Allow toggling without reload.
            if (!GM_getValue("AUTO_CLOSE_REWARD_POPUP", true)) return

            const root = getRootContainer()
            if (!root) return

            root.querySelectorAll(".events--rewards.is-visible").forEach((n) => closeEventsRewardsPopup(n))
            root.querySelectorAll(".takeoverTemp").forEach((n) => closeTakeoverTempPopup(n))
        }

        // Scan immediately and then keep scanning; rewards popups often toggle visibility via class changes.
        scanAndClose()

        const observer = new MutationObserver(() => scanAndClose())
        const root = getRootContainer()
        if (root) {
            observer.observe(root, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"] })
        }

        setInterval(scanAndClose, 1000)
    }
    setupAutoCloseRewardPopup()

    /* Config storage */
    const db = new Dexie("NTRacingStats")
    db.version(1).stores({
        backupStatData: "userID",
    })
    db.open().catch(function (e) {
        logging.error("Init")("Failed to open up the racing stat cache database", e)
    })

    ////////////
    //  Init  //
    ////////////

    let raceContainer = document.getElementById("raceContainer"),
        raceObj = raceContainer ? findReact(raceContainer) : null,
        server = raceObj?.server,
        currentUser = raceObj?.props.user

    const resolveRaceBootstrap = () => {
        raceContainer = document.getElementById("raceContainer")
        raceObj = raceContainer ? findReact(raceContainer) : null
        server = raceObj?.server
        currentUser = raceObj?.props.user
        return !!(raceContainer && raceObj && server && currentUser)
    }

    if (!resolveRaceBootstrap()) {
        logging.info("Init")("Race container not ready, waiting...")
        let initAttempts = 0
        const initMaxAttempts = 100
        const initCheck = () => {
            initAttempts++
            if (resolveRaceBootstrap()) {
                logging.info("Init")("Race container found after " + initAttempts + " attempts")
                _initContinue()
                return
            }
            if (initAttempts >= initMaxAttempts) {
                logging.info("Init")("No active race on this page, stats features inactive")
                return
            }
            setTimeout(initCheck, 150)
        }
        setTimeout(initCheck, 150)
        return
    }
    _initContinue()
    return

    function _initContinue() {
        if (!currentUser?.loggedIn) {
            logging.error("Init")("Not available for Guest Racing")
            return
        }

        const getLiveRaceOptionValue = (settingKey, fallback = undefined) => {
            const liveValue = readNtcfgRaceOptionsValue(settingKey)
            return typeof liveValue === "undefined" ? fallback : liveValue
        }

        const isLiveRaceOptionEnabled = (settingKey, fallback = false) => !!getLiveRaceOptionValue(settingKey, fallback)

        const getLiveRaceOptionNumber = (settingKey, fallback = 0) => {
            const parsed = Number(getLiveRaceOptionValue(settingKey, fallback))
            return Number.isFinite(parsed) ? parsed : Number(fallback) || 0
        }

        const setupPreciseAccuracyMetric = () => {
            if (!GM_getValue("ENABLE_PRECISE_ACCURACY", ENABLE_PRECISE_ACCURACY)) {
                return
            }

            const styleId = "ntcfg-precise-accuracy-style"
            if (!document.getElementById(styleId)) {
                const style = document.createElement("style")
                style.id = styleId
                style.appendChild(
                    document.createTextNode(`
.dash-metrics .accuracy-rounded { font-size: 14px; }
`)
                )
                document.head.appendChild(style)
            }

            const state = {
                lessonLength: 0,
                skipped: 0,
                errors: 0,
                accuracyNode: null,
                roundedValueNode: null,
                active: false,
            }

            const getAccuracyNode = () => raceContainer.querySelector(".dash-metrics .list-item:nth-of-type(2) span.h4")

            const ensureRoundedValueNode = (accuracyNode) => {
                const parent = accuracyNode?.parentNode
                if (!parent) return null

                let roundedWrap = parent.querySelector(".ntcfg-accuracy-rounded-wrap")
                if (!roundedWrap) {
                    roundedWrap = document.createElement("div")
                    roundedWrap.className = "ntcfg-accuracy-rounded-wrap"
                    roundedWrap.innerHTML = `<span class="accuracy-rounded">100</span><span class="tsxs tc-ts ttu mlxxs">%</span>`
                    parent.append(roundedWrap)
                }
                return roundedWrap.querySelector(".accuracy-rounded")
            }

            const refreshAccuracy = () => {
                if (!state.active || !state.accuracyNode || state.lessonLength <= 0) {
                    return
                }
                const denominator = state.lessonLength - state.skipped
                if (denominator <= 0) {
                    return
                }

                const score = Math.max(0, Math.min(100, (1 - state.errors / denominator) * 100))
                state.accuracyNode.textContent = score.toFixed(2)
                if (state.roundedValueNode) {
                    state.roundedValueNode.textContent = String(Math.round(score))
                }
            }

            server.on("status", (e) => {
                if (e.status !== "countdown") {
                    return
                }
                if (!GM_getValue("ENABLE_PRECISE_ACCURACY", ENABLE_PRECISE_ACCURACY)) {
                    state.active = false
                    return
                }

                const lessonLength = Number(e.lessonLength)
                if (!Number.isFinite(lessonLength) || lessonLength <= 0) {
                    state.active = false
                    return
                }

                const accuracyNode = getAccuracyNode()
                if (!accuracyNode) {
                    state.active = false
                    return
                }

                state.lessonLength = lessonLength
                state.skipped = 0
                state.errors = 0
                state.accuracyNode = accuracyNode
                state.roundedValueNode = ensureRoundedValueNode(accuracyNode)
                state.active = true

                state.accuracyNode.textContent = "100.00"
                if (state.roundedValueNode) {
                    state.roundedValueNode.textContent = "100"
                }
            })

            server.on("update", () => {
                if (!state.active) {
                    return
                }
                refreshAccuracy()
            })

            if (typeof raceObj.incrementTyped === "function" && !raceObj.__ntcfgPreciseAccuracyPatched) {
                const originalIncrementTyped = raceObj.incrementTyped
                raceObj.incrementTyped = function () {
                    const result = originalIncrementTyped.apply(this, arguments)
                    const data = arguments[0]

                    state.skipped = Number(raceObj?.typedStats?.skipped || 0)
                    state.errors = Number(raceObj?.typedStats?.errors || 0)

                    let canRefresh = false
                    if (typeof data?.skipped === "number") {
                        canRefresh = state.errors > 0
                    }
                    if (typeof data?.error === "number") {
                        canRefresh = true
                    }

                    if (canRefresh) {
                        refreshAccuracy()
                    }
                    return result
                }
                raceObj.__ntcfgPreciseAccuracyPatched = true
            }
        }

        setupPreciseAccuracyMetric()

        raceContainer.addEventListener('click', (event) => {
            const hiddenInput = document.querySelector('.race-hiddenInput');
            if (hiddenInput && typeof hiddenInput.click === "function") {
                hiddenInput.click();
            }
        });
        //////////////////
        //  Components  //
        //////////////////

        /** Styles for the following components. */
        const style = document.createElement("style")
        style.appendChild(
            document.createTextNode(`

/* Race page tweaks (kept). */
.racev3-track {
    margin-top: -30px;
}

.header-bar--return-to-garage{
    display: none !important;
}

.dropdown {
    display: none !important;
}

.header-nav {
    display: none !important;
}
.logo-SVG {
    height: 50% !important;
    width: 50% !important;
}

/* Racing Stats UI theme (restored). */
#raceContainer {
    margin-bottom: 0;
}
.nt-stats-root {
    background-color: #222;
    box-sizing: border-box;
}
.nt-stats-body {
    display: flex;
    justify-content: space-between;
    padding: 8px;
}
.nt-stats-root.nt-stats-root--wide .nt-stats-body {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 24px;
    align-items: start;
}
.nt-stats-left-section, .nt-stats-right-section  {
    display: flex;
    flex-direction: column;
    row-gap: 8px;
}
.nt-stats-right-section {
    flex-grow: 1;
    margin-left: 15px;
}
.nt-stats-root.nt-stats-root--wide .nt-stats-right-section {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 28px;
    row-gap: 0;
    align-items: center;
    margin-left: 0;
}
.nt-stats-root.nt-stats-root--wide .nt-stats-info {
    justify-self: center;
    align-self: center;
    max-width: 100%;
}
.nt-stats-root.nt-stats-root--wide .nt-stats-season-progress {
    justify-self: end;
    margin: 0;
}
.nt-stats-toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-left: 8px;
    color: rgba(255, 255, 255, 0.8);
    background-color: #03111a;
    font-size: 12px;
}
.nt-stats-toolbar-status {
    display: flex;
}
.nt-stats-toolbar-status .nt-stats-toolbar-status-item {
    padding: 0 8px;
    background-color: #0a2c42;
}
.nt-stats-toolbar-status .nt-stats-toolbar-status-item-alt {
    padding: 0 8px;
    background-color: #22465c;
}
.nt-stats-daily-challenges {
    width: 350px;
}
.nt-stats-daily-challenges .daily-challenge-progress--badge {
    z-index: 0;
}
.nt-stats-season-progress {
    padding: 8px;
    margin: 0 auto;
    border-radius: 8px;
    background-color: #1b83d0;
    box-shadow: 0 28px 28px 0 rgb(2 2 2 / 5%), 0 17px 17px 0 rgb(2 2 2 / 20%), 0 8px 8px 0 rgb(2 2 2 / 15%);
}
.nt-stats-season-progress .season-progress-widget {
    width: 350px;
}
.nt-stats-season-progress .season-progress-widget--level-progress-bar {
    transition: width 0.3s ease;
}
.nt-stats-season-progress .season-progress-widget--level-progress {
    border-radius: 999px;
    overflow: hidden;
    background: rgba(0, 0, 0, 0.22);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.35);
}
.nt-stats-season-progress .season-progress-widget--level-progress-bar {
    border-radius: 999px;
    background: linear-gradient(90deg, #f7d14a 0%, #f3a81b 55%, #f07d1b 100%);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.25) inset, 0 2px 6px rgba(0, 0, 0, 0.25);
}
.nt-stats-season-progress img.season-reward-mini-previewImg {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}
.nt-stats-season-progress .season-reward-mini-preview--preview .seasonReward-cardVis--money {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
}
.nt-stats-season-progress .season-reward-mini-preview--preview .rarity-badge {
    transform: scale(0.9);
    transform-origin: center;
}
/* Cash already shows the amount; hide the corner label box to avoid a blank square. */
.nt-stats-season-progress .season-reward-mini-preview--money .season-reward-mini-preview--label {
    display: none !important;
}
.nt-stats-info {
    text-align: center;
    color: #eee;
    font-size: 14px;
}
.nt-stats-metric-row {
    margin-bottom: 4px;
}
.nt-stats-metric-separator {
    color: rgba(255, 255, 255, 0.35);
}
.nt-stats-metric-heading {
    color: rgba(255, 255, 255, 0.75);
}
.nt-stats-metric-value, .nt-stats-metric-suffix {
    font-weight: 600;
}
.nt-stats-metric-suffix {
    color: #aaa;
}
`)
        )
        document.head.appendChild(style)

        /** Populates daily challenge data merges in the given progress. */
        const mergeDailyChallengeData = (progress) => {
            const {
                CHALLENGES,
                CHALLENGE_TYPES
            } = NTGLOBALS,
                now = Math.floor(Date.now() / 1000)
            return CHALLENGES.filter((c) => c.expiration > now)
                .slice(0, 3)
                .map((c, i) => {
                    const userProgress = progress.find((p) => p.challengeID === c.challengeID),
                        challengeType = CHALLENGE_TYPES[c.type],
                        field = challengeType[1],
                        title = challengeType[0].replace(/\$\{goal\}/, c.goal).replace(/\$\{field\}/, `${challengeType[1]}${c.goal !== 1 ? "s" : ""}`)
                    return {
                        ...c,
                        title,
                        field,
                        goal: c.goal,
                        progress: userProgress?.progress || 0,
                    }
                })
        }

        /** Grab NT Racing Stats from various sources. */
        const getStats = async () => {
            //await new Promise(resolve => setTimeout(resolve, 3000));
            let backupUserStats = null
            try {
                backupUserStats = await db.backupStatData.get(currentUser.userID)
            } catch (ex) {
                logging.warn("Update")("Unable to get backup stats", ex)
            }
            try {
                const persistStorageStats = JSON.parse(JSON.parse(localStorage.getItem("persist:nt")).user),
                    user = !backupUserStats || typeof backupUserStats.lastConsecRace !== "number" || persistStorageStats.lastConsecRace >= backupUserStats.lastConsecRace ?
                        persistStorageStats :
                        backupUserStats,
                    dailyChallenges = mergeDailyChallengeData(user.challenges)
                return {
                    user,
                    dailyChallenges
                }
            } catch (ex) {
                logging.error("Update")("Unable to get stats", ex)
            }
            return Promise.reject(new Error("Unable to get stats"))
        }

        /** Grab Summary Stats. */
        const getSummaryStats = () => {
            const authToken = localStorage.getItem("player_token")
            return fetch("/api/v2/stats/summary", {
                headers: {
                    Authorization: `Bearer ${authToken}`,
                },
            })
                .then((r) => r.json())
                .then((r) => {
                    return {
                        seasonBoard: r?.results?.racingStats?.find((b) => b.board === "season"),
                        dailyBoard: r?.results?.racingStats?.find((b) => b.board === "daily"),
                    }
                })
                .catch((err) => Promise.reject(err))
        }

        /** Grab Stats from Team Data. */
        const getTeamStats = () => {
            if (!currentUser?.tag) {
                return Promise.reject(new Error("User is not in a team"))
            }
            const authToken = localStorage.getItem("player_token")
            return fetch(`/api/v2/teams/${currentUser.tag}`, {
                headers: {
                    Authorization: `Bearer ${authToken}`,
                },
            })
                .then((r) => r.json())
                .then((r) => {
                    return {
                        leaderboard: r?.results?.leaderboard,
                        motd: r?.results?.motd,
                        info: r?.results?.info,
                        stats: r?.results?.stats,
                        member: r?.results?.members?.find((u) => u.userID === currentUser.userID),
                        season: r?.results?.season?.find((u) => u.userID === currentUser.userID),
                    }
                })
                .catch((err) => Promise.reject(err))
        }

        /** Stat Manager widget (basically a footer with settings button). */
        const ToolbarWidget = ((user) => {
            const root = document.createElement("div")
            root.classList.add("nt-stats-toolbar")
            root.innerHTML = `
        <div>
            NOTE: Team Stats and Season Stats are cached.
        </div>
        <div class="nt-stats-toolbar-status">
            <div class="nt-stats-toolbar-status-item">
                <span class=" nt-cash-status as-nitro-cash--prefix">N/A</span>
            </div>
            <div class="nt-stats-toolbar-status-item-alt">
                📦 Mystery Box: <span class="mystery-box-status">N/A</span>
            </div>
        </div>`

            /** Mystery Box **/
            const rewardCountdown = user.rewardCountdown,
                mysteryBoxStatus = root.querySelector(".mystery-box-status")

            let isDisabled = Date.now() < user.rewardCountdown * 1e3,
                timer = null

            const syncCountdown = () => {
                isDisabled = Date.now() < user.rewardCountdown * 1e3
                if (!isDisabled) {
                    if (timer) {
                        clearInterval(timer)
                    }
                    mysteryBoxStatus.textContent = "Claim Now!"
                    return
                }
                mysteryBoxStatus.textContent = moment(user.rewardCountdown * 1e3).fromNow(false)
            }
            syncCountdown()
            if (isDisabled) {
                timer = setInterval(syncCountdown, 6e3)
            }

            /** NT Cash. */
            const amountNode = root.querySelector(".nt-cash-status")

            return {
                root,
                updateStats: (user) => {
                    if (typeof user?.money === "number") {
                        amountNode.textContent = `$${user.money.toLocaleString()}`
                    }
                },
            }

        })(raceObj.props.user)

        /** Daily Challenge widget. */
        const DailyChallengeWidget = (() => {
            const root = document.createElement("div")
            root.classList.add("nt-stats-daily-challenges", "profile-dailyChallenges", "card", "card--open", "card--d", "card--grit", "card--shadow-l")
            root.innerHTML = `
        <div class="daily-challenge-list--heading">
            <h4>Daily Challenges</h4>
            <div class="daily-challenge-list--arriving">
                <div class="daily-challenge-list--arriving-label">
                    <svg class="icon icon-recent-time"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/site/images/icons/icons.css.1494.svg#icon-recent-time"></use></svg>
                    New <span></span>
                </div>
            </div>
        </div>
        <div class="daily-challenge-list--challenges"></div>`

            const dailyChallengesContainer = root.querySelector(".daily-challenge-list--challenges"),
                dailyChallengesExpiry = root.querySelector(".daily-challenge-list--arriving-label span")

            const dailyChallengeItem = document.createElement("div")
            dailyChallengeItem.classList.add("raceResults--dailyChallenge")
            dailyChallengeItem.innerHTML = `
    	<div class="daily-challenge-progress">
			<div class="daily-challenge-progress--info">
				<div class="daily-challenge-progress--requirements">
					<div class="daily-challenge-progress--name">
						<div style="height: 19px;">
							<div align="left" style="white-space: nowrap; pavgSpeedosition: absolute; transform: translate(0%, 0px) scale(1, 1); left: 0px;">
							</div>
						</div>
					</div>
					<div class="daily-challenge-progress--status"></div>
				</div>
				<div class="daily-challenge-progress--progress">
					<div class="daily-challenge-progress--progress-bar-container">
						<div class="daily-challenge-progress--progress-bar" style="width: 40%"></div>
						<div class="daily-challenge-progress--progress-bar--earned" style="width: 40%"></div>
					</div>
				</div>
			</div>
			<div class="daily-challenge-progress--badge">
				<div class="daily-challenge-progress--success"></div>
				<div class="daily-challenge-progress--xp">
					<span class="daily-challenge-progress--value"></span><span class="daily-challenge-progress--divider">/</span><span class="daily-challenge-progress--target"></span>
				</div>
				<div class="daily-challenge-progress--label"></div>
			</div>
		</div>`

            const updateDailyChallengeNode = (node, challenge) => {
                let progressPercentage = challenge.goal > 0 ? (challenge.progress / challenge.goal) * 100 : 0
                if (challenge.progress === challenge.goal) {
                    progressPercentage = 100
                    node.querySelector(".daily-challenge-progress").classList.add("is-complete")
                } else {
                    node.querySelector(".daily-challenge-progress").classList.remove("is-complete")
                }
                node.querySelector(".daily-challenge-progress--name div div").textContent = challenge.title
                node.querySelector(".daily-challenge-progress--label").textContent = `${challenge.field}s`
                node.querySelector(".daily-challenge-progress--value").textContent = challenge.progress
                node.querySelector(".daily-challenge-progress--target").textContent = challenge.goal
                node.querySelector(".daily-challenge-progress--status").textContent = `Earn ${Math.floor(challenge.reward / 100) / 10}k XP`
                node.querySelectorAll(".daily-challenge-progress--progress-bar, .daily-challenge-progress--progress-bar--earned").forEach((bar) => {
                    bar.style.width = `${progressPercentage}%`
                })
            }

            let dailyChallengeNodes = null

            getStats().then(({
                dailyChallenges
            }) => {
                const dailyChallengeFragment = document.createDocumentFragment()

                dailyChallengeNodes = dailyChallenges.map((c) => {
                    const node = dailyChallengeItem.cloneNode(true)
                    updateDailyChallengeNode(node, c)

                    dailyChallengeFragment.append(node)

                    return node
                })
                dailyChallengesContainer.append(dailyChallengeFragment)
            })

            const updateStats = (data) => {
                if (!data || !dailyChallengeNodes || data.length === 0) {
                    return
                }
                if (data[0] && data[0].expiration) {
                    const t = 1000 * data[0].expiration
                    if (!isNaN(t)) {
                        dailyChallengesExpiry.textContent = moment(t).fromNow()
                    }
                }
                data.forEach((c, i) => {
                    if (dailyChallengeNodes[i]) {
                        updateDailyChallengeNode(dailyChallengeNodes[i], c)
                    }
                })
            }

            return {
                root,
                updateStats,
            }
        })()

        /** Display Season Progress and next Reward. */
        const SeasonProgressWidget = ((raceObj) => {
            const currentSeason = NTGLOBALS.ACTIVE_SEASONS.find((s) => {
                const now = Date.now()
                return now >= s.startStamp * 1e3 && now <= s.endStamp * 1e3
            })

            const seasonRewards = raceObj.props?.seasonRewards,
                user = raceObj.props?.user

            let cachedSeasonAssetKey = null
            const extractAssetKeyFromPerkImgSrc = (src) => {
                const m = String(src || "").match(/\/dist\/site\/images\/seasons\/([^/]+)\/perk\.png/i)
                return m ? m[1] : null
            }
            const resolveSeasonAssetKey = () => {
                const direct =
                    (typeof currentSeason?.assetKey === "string" && currentSeason.assetKey) ||
                    (typeof currentSeason?.asset_key === "string" && currentSeason.asset_key) ||
                    (typeof raceObj?.props?.season?.assetKey === "string" && raceObj.props.season.assetKey) ||
                    (typeof raceObj?.props?.season?.asset_key === "string" && raceObj.props.season.asset_key) ||
                    null
                if (direct) return direct

                // DOM hints (if NT has already rendered perk art anywhere).
                const perkImg =
                    document.querySelector('img.seasonReward-cardVisImg[src*="/dist/site/images/seasons/"][src*="/perk.png"]') ||
                    document.querySelector('img[src*="/dist/site/images/seasons/"][src*="/perk.png"]')
                const domSrc = perkImg?.getAttribute?.("src") || perkImg?.src || null
                const fromDom = extractAssetKeyFromPerkImgSrc(domSrc)
                if (fromDom) return fromDom

                // Bootstrap JSON embedded in inline scripts.
                const scripts = Array.from(document.scripts || [])
                for (const s of scripts) {
                    if (s.src) continue
                    const txt = s.textContent
                    if (!txt || txt.length > 2000000) continue
                    const m = txt.match(/"assetKey"\s*:\s*"([a-zA-Z0-9_-]+)"/)
                    if (m && m[1]) return m[1]
                }

                // Common JSON data containers (framework-dependent).
                const nextDataEl = document.getElementById("__NEXT_DATA__")
                if (nextDataEl && nextDataEl.textContent) {
                    try {
                        const parsed = JSON.parse(nextDataEl.textContent)
                        const key =
                            parsed?.props?.pageProps?.currentSeason?.assetKey ||
                            parsed?.props?.pageProps?.season?.assetKey ||
                            null
                        if (typeof key === "string" && key) return key
                    } catch {
                        // ignore
                    }
                }

                return null
            }
            const getSeasonAssetKey = () => {
                if (cachedSeasonAssetKey) return cachedSeasonAssetKey
                const key = resolveSeasonAssetKey()
                if (typeof key === "string" && key) {
                    cachedSeasonAssetKey = key
                    return cachedSeasonAssetKey
                }
                return null
            }

            const root = document.createElement("div")
            root.classList.add("nt-stats-season-progress", "theme--pDefault")
            root.innerHTML = `
        <div class="season-progress-widget">
            <div class="season-progress-widget--info">
                <div class="season-progress-widget--title">Season Progress${currentSeason ? "" : " (starting soon)"}</div>
                <div class="season-progress-widget--current-xp"></div>
                <div class="season-progress-widget--current-level">
                    <div class="season-progress-widget--current-level--prefix">Level</div>
                    <div class="season-progress-widget--current-level--number"></div>
                </div>
                <div class="season-progress-widget--level-progress">
                    <div class="season-progress-widget--level-progress-bar" style="width: 0%;"></div>
                </div>
            </div>
            <div class="season-progress-widget--next-reward">
                <div class="season-progress-widget--next-reward--display">
                    <div class="season-reward-mini-preview">
                        <div class="season-reward-mini-preview--locked">
                            <div class="tooltip--season tooltip--xs tooltip--c" data-ttcopy="Upgrade to Nitro Gold to Unlock!">
                                <svg class="icon icon-lock"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/dist/site/images/icons/icons.css.svg#icon-lock"></use></svg>
                            </div>
                        </div>
                        <a class="season-reward-mini-preview" href="/season">
                            <div class="season-reward-mini-preview--frame">
                                <div class="rarity-frame rarity-frame--small">
                                    <div class="rarity-frame--extra"></div>
                                    <div class="rarity-frame--content">
                                        <div class="season-reward-mini-preview--preview"></div>
                                        <div class="season-reward-mini-preview--label"></div>
                                    </div>
                                </div>
                            </div>
                        </a>
                    </div>
                </div>
            </div>
        </div>`

            const xpTextNode = root.querySelector(".season-progress-widget--current-xp"),
                xpProgressBarNode = root.querySelector(".season-progress-widget--level-progress-bar"),
                levelNode = root.querySelector(".season-progress-widget--current-level--number"),
                nextRewardRootNode = root.querySelector(".season-reward-mini-preview"),
                nextRewardTypeLabelNode = root.querySelector(".season-reward-mini-preview--label"),
                nextRewardTypeLockedNode = root.querySelector(".season-reward-mini-preview--locked"),
                nextRewardTypePreviewNode = root.querySelector(".season-reward-mini-preview--preview"),
                nextRewardTypePreviewImgNode = document.createElement("img"),
                nextRewardRarityFrameNode = root.querySelector(".rarity-frame.rarity-frame--small")

            nextRewardTypePreviewImgNode.classList.add("season-reward-mini-previewImg")
            nextRewardTypePreviewImgNode.decoding = "async"
            nextRewardTypePreviewImgNode.loading = "lazy"

            if (!currentSeason) {
                nextRewardRootNode.remove()
            }

            /** Work out how much experience required to reach specific level. */
            const getExperienceRequired = (lvl) => {
                if (lvl < 1) {
                    lvl = 1
                }
                const {
                    startingLevels,
                    experiencePerStartingLevel,
                    experiencePerAchievementLevel,
                    experiencePerExtraLevels
                } = NTGLOBALS.SEASON_LEVELS

                let totalExpRequired = 0,
                    amountExpRequired = experiencePerStartingLevel
                for (let i = 1; i < lvl; i++) {
                    if (i <= startingLevels) {
                        totalExpRequired += experiencePerStartingLevel
                    } else if (currentSeason && i > currentSeason.totalRewards) {
                        totalExpRequired += experiencePerExtraLevels
                        amountExpRequired = experiencePerExtraLevels
                    } else {
                        totalExpRequired += experiencePerAchievementLevel
                        amountExpRequired = experiencePerAchievementLevel
                    }
                }
                return [amountExpRequired, totalExpRequired]
            }

            /** Get next reward object from `seasonRewards`. */
            const getNextReward = (currentXP) => {
                currentXP = currentXP || user.experience
                if (!seasonRewards || seasonRewards.length === 0) {
                    return null
                }
                if (user.experience === 0) {
                    return seasonRewards[0] || null
                }
                let claimed = false
                let nextReward = seasonRewards.find((r, i) => {
                    if (!r.bonus && (claimed || r.experience === currentXP)) {
                        claimed = true
                        return false
                    }
                    return r.experience > currentXP || i + 1 === seasonRewards.length
                })
                if (!nextReward) {
                    nextReward = seasonRewards[seasonRewards.length - 1]
                }
                return nextReward || null
            }

            const setRewardPreviewText = (text) => {
                nextRewardTypePreviewImgNode.remove()
                nextRewardTypePreviewNode.innerHTML = ""
                nextRewardTypePreviewNode.textContent = text
            }

            const setRewardPreviewImage = (src, fallback = "?") => {
                let fallbackText = "?"
                let fallbackSrc = null
                if (typeof fallback === "string") {
                    fallbackText = fallback
                } else if (fallback && typeof fallback === "object") {
                    fallbackText = typeof fallback.fallbackText === "string" ? fallback.fallbackText : "?"
                    fallbackSrc = typeof fallback.fallbackSrc === "string" ? fallback.fallbackSrc : null
                }

                nextRewardTypePreviewImgNode.onerror = () => {
                    if (fallbackSrc && nextRewardTypePreviewImgNode.src !== fallbackSrc) {
                        nextRewardTypePreviewImgNode.onerror = () => {
                            setRewardPreviewText(fallbackText)
                        }
                        nextRewardTypePreviewImgNode.src = fallbackSrc
                        return
                    }
                    setRewardPreviewText(fallbackText)
                }
                nextRewardTypePreviewImgNode.src = src
                nextRewardTypePreviewNode.innerHTML = ""
                nextRewardTypePreviewNode.append(nextRewardTypePreviewImgNode)
            }

            return {
                root,
                refreshTeamRaceCorrections: () => {
                    syncCorrectedTeamRaces()
                },
                updateStats: (data) => {
                    // XP Progress
                    if (typeof data.experience === "number") {
                        const [amountExpRequired, totalExpRequired] = getExperienceRequired(data.level + 1),
                            progress = Math.max(5, ((amountExpRequired - (totalExpRequired - data.experience)) / amountExpRequired) * 100.0) || 5
                        xpTextNode.textContent = `${(amountExpRequired - (totalExpRequired - data.experience)).toLocaleString()} / ${amountExpRequired / 1e3}k XP`
                        xpProgressBarNode.style.width = `${progress}%`
                    }
                    levelNode.textContent = currentSeason && data.level > currentSeason.totalRewards + 1 ? `∞${data.level - currentSeason.totalRewards - 1}` : data.level || 1

                    // Next Reward
                    if (typeof data.experience !== "number") {
                        return
                    }
                    const nextReward = getNextReward(data.experience)
                    const nextRewardID =
                        nextReward?.achievementID ||
                        nextReward?.achievementId ||
                        nextReward?.achievement_id ||
                        nextReward?.id ||
                        null
                    const achievementsList =
                        Array.isArray(NTGLOBALS?.ACHIEVEMENTS?.LIST)
                            ? NTGLOBALS.ACHIEVEMENTS.LIST
                            : Array.isArray(NTGLOBALS?.ACHIEVEMENTS?.list)
                                ? NTGLOBALS.ACHIEVEMENTS.list
                                : Array.isArray(NTGLOBALS?.ACHIEVEMENTS)
                                    ? NTGLOBALS.ACHIEVEMENTS
                                    : null
                    const achievement =
                        nextRewardID && achievementsList
                            ? achievementsList.find((a) => String(a?.achievementID || a?.achievementId || a?.id || "") === String(nextRewardID))
                            : null
                    const reward = achievement?.reward || nextReward?.reward || null
                    if (!reward || typeof reward.type !== "string") {
                        // Don't hard-fail; just remove any stale preview so the widget doesn't look broken.
                        setRewardPreviewText("?")
                        nextRewardTypeLabelNode.textContent = ""
                        return
                    }
                    const { type, value } = reward
                    const rewardType = String(type).toLowerCase()
                    if (["loot", "car"].includes(rewardType)) {
                        const v = String(value)
                        const item =
                            rewardType === "loot"
                                ? NTGLOBALS.LOOT?.find((l) => String(l.lootID) === v)
                                : NTGLOBALS.CARS?.find((l) => String(l.carID) === v)
                        if (!item) {
                            logging.warn("Update")(`Unable to find next reward ${rewardType}`, reward)
                            setRewardPreviewText("?")
                            nextRewardTypeLabelNode.textContent = rewardType
                            return
                        }

                        nextRewardRootNode.className = `season-reward-mini-preview season-reward-mini-preview--${rewardType === "loot" ? item?.type : "car"}`
                        nextRewardTypeLabelNode.textContent = rewardType === "loot" ? item.type || "???" : "car"
                        nextRewardRarityFrameNode.className = `rarity-frame rarity-frame--small${item.options?.rarity ? ` rarity-frame--${item.options.rarity}` : ""}`

                        if (item?.type === "title") {
                            setRewardPreviewText(`"${item.name}"`)
                        } else {
                            const src =
                                rewardType === "loot"
                                    ? (item.options?.src || item.options?.smallSrc || item.options?.small_src || "")
                                    : item.options?.smallSrc
                                        ? `/cars/${item.options.smallSrc}`
                                        : item.options?.src || item.options?.small_src
                                            ? `/cars/${item.options.small_src}`
                                            : ""
                            if (!src) {
                                setRewardPreviewText("?")
                            } else {
                                setRewardPreviewImage(src)
                            }
                        }
                    } else if (rewardType === "money") {
                        const moneyValue = typeof value === "number" ? value : Number(value)
                        const moneyText = isNaN(moneyValue) ? String(value) : moneyValue.toLocaleString()
                        nextRewardTypeLabelNode.textContent = ""
                        nextRewardRootNode.className = "season-reward-mini-preview season-reward-mini-preview--money"
                        nextRewardRarityFrameNode.className = "rarity-frame rarity-frame--small rarity-frame--legendary"
                        nextRewardTypePreviewImgNode.remove()
                        nextRewardTypePreviewNode.innerHTML = `
		                    <div class="seasonReward-cardVis seasonReward-cardVis--money">
		                        <div class="rarity-badge as-nitro-cash rarity-badge--cash rarity-badge--cash">
		                            <div class="rarity-badge--extra"></div>
		                            <div class="rarity-badge--content">$${moneyText}</div>
		                        </div>
		                    </div>`
                    } else if (rewardType === "perk") {
                        const perkIcon = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(
                            `<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
  <defs>
    <linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0" stop-color="#2ff3ff"/>
      <stop offset="1" stop-color="#9b6bff"/>
    </linearGradient>
  </defs>
  <rect x="10" y="10" width="44" height="44" rx="10" fill="#0b2233"/>
  <path d="M28 12h8l-4 18h10L26 52l4-18H20z" fill="url(#g)"/>
</svg>`
                        )}`
                        const seasonAssetKey = getSeasonAssetKey()
                        const seasonPerkSrc = seasonAssetKey ? `/dist/site/images/seasons/${seasonAssetKey}/perk.png` : null
                        const perkID = String(value)
                        const matchPerkID = (p) => String(p?.perkID || p?.perkId || p?.perk_id || p?.id || "") === perkID
                        const findPerk = (collection) => {
                            if (!collection) return null
                            if (Array.isArray(collection)) return collection.find(matchPerkID) || null
                            if (Array.isArray(collection?.LIST)) return collection.LIST.find(matchPerkID) || null
                            if (Array.isArray(collection?.list)) return collection.list.find(matchPerkID) || null
                            if (typeof collection === "object") {
                                const direct = collection[perkID] || collection[Number(perkID)]
                                if (direct) return direct
                                try {
                                    return Object.values(collection).find(matchPerkID) || null
                                } catch {
                                    return null
                                }
                            }
                            return null
                        }
                        const perk =
                            findPerk(NTGLOBALS?.PERKS) ||
                            findPerk(NTGLOBALS?.PERK) ||
                            null
                        const perkSrc =
                            perk?.options?.src ||
                            perk?.options?.icon ||
                            perk?.options?.iconSrc ||
                            perk?.options?.icon_src ||
                            perk?.options?.smallSrc ||
                            perk?.options?.small_src ||
                            perk?.src ||
                            perk?.icon ||
                            perk?.image ||
                            null

                        nextRewardRootNode.className = "season-reward-mini-preview season-reward-mini-preview--perk"
                        nextRewardTypeLabelNode.textContent = "PERK"
                        nextRewardRarityFrameNode.className = `rarity-frame rarity-frame--small${perk?.options?.rarity ? ` rarity-frame--${perk.options.rarity}` : ""}`

                        if (seasonPerkSrc) {
                            setRewardPreviewImage(seasonPerkSrc, { fallbackSrc: perkSrc || perkIcon, fallbackText: "PERK" })
                        } else if (perkSrc) {
                            setRewardPreviewImage(perkSrc, { fallbackSrc: perkIcon, fallbackText: "PERK" })
                        } else {
                            // Perk metadata differs between Nitro Type versions; always show something.
                            setRewardPreviewImage(perkIcon, "PERK")
                            if (!perk) {
                                logging.warn("Update")("Unable to resolve PERK metadata from NTGLOBALS", reward)
                            }
                        }
                    } else {
                        logging.warn("Update")(`Unhandled next reward type ${rewardType}`, reward)
                        setRewardPreviewText("?")
                        nextRewardTypeLabelNode.textContent = rewardType
                        return
                    }

                    const isFree = typeof achievement?.free === "boolean" ? achievement.free : typeof nextReward?.free === "boolean" ? nextReward.free : true
                    if (!isFree && user.membership === "basic") {
                        nextRewardRootNode.firstElementChild.before(nextRewardTypeLockedNode)
                    } else {
                        nextRewardTypeLockedNode.remove()
                    }
                },
            }
        })(raceObj)

        /** Displays list of player stats. */
        const StatWidget = (() => {
            const root = document.createElement("div")
            root.classList.add("nt-stats-info")
            root.innerHTML = `
	        <div class="nt-stats-metric-row">
	            <span class="nt-stats-metric nt-stats-metric-total-races">
	                <span class="nt-stats-metric-heading">Races:</span>
	                <span class="nt-stats-metric-value">0</span>
	            </span>
	            ${currentUser.tag
                    ? `<span class="nt-stats-metric-separator">|</span>
	                       <span class="nt-stats-metric nt-stats-metric-team-races">
	                <span class="nt-stats-metric-heading">Team:</span>
	                <span class="nt-stats-metric-value">N/A</span>
	            </span>`
                    : ``
                }
	            <span class="nt-stats-metric-separator">|</span>
	            <span class="nt-stats-metric nt-stats-metric-rta">
	                <span class="nt-stats-metric-heading">Real time:</span>
	                <span class="nt-stats-metric-value">00:00</span>
	            </span>
	            <span class="nt-stats-metric-separator">|</span>
	            <span class="nt-stats-metric nt-stats-metric-session-races">
	                <span class="nt-stats-metric-heading">Session:</span>
	                <span class="nt-stats-metric-value">0</span>
	            </span>
	        </div>
	        <div class="nt-stats-metric-row">
	            <span class="nt-stats-metric-separator">|</span>
	            <span class="nt-stats-metric nt-stats-metric-playtime">
	                <span class="nt-stats-metric-heading">Playtime:</span>
	                <span class="nt-stats-metric-value">0</span>
	            </span>
	            <span class="nt-stats-metric-separator">|</span>
	            <span class="nt-stats-metric nt-stats-metric-season-xp">
	                <span class="nt-stats-metric-heading">Season XP:</span>
	                <span class="nt-stats-metric-value">0</span>
	            </span>
	        </div>
	        <div class="nt-stats-metric-row">
	            <span class="nt-stats-metric nt-stats-metric-avg-speed">
	            <span class="nt-stats-metric-heading">Avg:</span>
	                <span class="nt-stats-metric-value">0</span>
	                <span class="nt-stats-metric-suffix">WPM</span>
	            </span>
	            <span class="nt-stats-metric-separator">|</span>
	            <span class="nt-stats-metric nt-stats-metric-avg-accuracy">
	                <span class="nt-stats-metric-value">0</span>
	                <span class="nt-stats-metric-suffix nt-stats-metric-suffix-no-space">%</span>
	            </span>
	            <span class="nt-stats-metric-separator">|</span>
	            <span class="nt-stats-metric nt-stats-metric-avg-time">
	                <span class="nt-stats-metric-value">0</span>
	                <span class="nt-stats-metric-suffix nt-stats-metric-suffix-no-space">s</span>
	            </span>
	            <span class="nt-stats-metric-separator">|</span>
	            <span class="nt-stats-metric nt-stats-metric-last-speed">
	                <span class="nt-stats-metric-heading">Last:</span>
	                <span class="nt-stats-metric-value">N/A</span>
	                <span class="nt-stats-metric-suffix">WPM</span>
	            </span>
	            <span class="nt-stats-metric-separator">|</span>
	            <span class="nt-stats-metric nt-stats-metric-last-accuracy">
	                <span class="nt-stats-metric-value">N/A</span>
	                <span class="nt-stats-metric-suffix nt-stats-metric-suffix-no-space">%</span>
	            </span>
	            <span class="nt-stats-metric-separator">|</span>
	            <span class="nt-stats-metric nt-stats-metric-last-time">
	                <span class="nt-stats-metric-value">N/A</span>
	                <span class="nt-stats-metric-suffix nt-stats-metric-suffix-no-space">s</span>
	            </span>
	        </div>
	        `

            let currentTime = JSON.parse(JSON.parse(localStorage.getItem("persist:nt")).user).lastConsecRace;
            let greedyReloadTimerId = null;
            const isGreedyReloadEnabled = () => isLiveRaceOptionEnabled("greedyStatsReload", true);
            const shouldReloadOnStats = () => isLiveRaceOptionEnabled("reloadOnStats", true);
            const getGreedyReloadDelay = () => Math.max(10, Math.round(getLiveRaceOptionNumber("greedyStatsReloadInt", 50)));
            const clearGreedyReloadTimer = () => {
                if (greedyReloadTimerId !== null) {
                    clearTimeout(greedyReloadTimerId);
                    greedyReloadTimerId = null;
                }
            };
            const scheduleGreedyReloadCheck = (lasttime = currentTime) => {
                clearGreedyReloadTimer();
                if (!isGreedyReloadEnabled()) {
                    return;
                }
                greedyReloadTimerId = setTimeout(() => checkendgreedy(lasttime), getGreedyReloadDelay());
            };
            function checkendgreedy(lasttime) {
                if (!isGreedyReloadEnabled()) {
                    clearGreedyReloadTimer();
                    return;
                }
                if (document.querySelector('.modal--raceError')) {
                    clearGreedyReloadTimer();
                    location.reload();
                    return;
                }
                const newtime = JSON.parse(JSON.parse(localStorage.getItem("persist:nt")).user).lastConsecRace;
                if (newtime > lasttime) {
                    clearGreedyReloadTimer();
                    getStats().then(({
                        user,
                    }) => {
                        StatWidget.updateStats(user)
                        if (shouldReloadOnStats()) {
                            if (my_race_started) {
                                location.reload()
                            } else {
                                document.querySelector('.race-hiddenInput')?.click()
                                currentTime = newtime;
                                scheduleGreedyReloadCheck(currentTime);
                            }
                        }
                    })
                    return;
                }
                scheduleGreedyReloadCheck(lasttime);
            }
            scheduleGreedyReloadCheck(currentTime);


            const totalRacesNode = root.querySelector(".nt-stats-metric-total-races .nt-stats-metric-value"),
                sessionRacesNode = root.querySelector(".nt-stats-metric-session-races .nt-stats-metric-value"),
                seasonXPNode = root.querySelector(".nt-stats-metric-season-xp .nt-stats-metric-value"),
                teamRacesNode = currentUser.tag ? root.querySelector(".nt-stats-metric-team-races .nt-stats-metric-value") : null,
                avgSpeedNode = root.querySelector(".nt-stats-metric-avg-speed .nt-stats-metric-value"),
                avgAccuracyNode = root.querySelector(".nt-stats-metric-avg-accuracy .nt-stats-metric-value"),
                lastSpeedNode = root.querySelector(".nt-stats-metric-last-speed .nt-stats-metric-value"),
                lastAccuracyNode = root.querySelector(".nt-stats-metric-last-accuracy .nt-stats-metric-value"),
                lastTimeNode = root.querySelector(".nt-stats-metric-last-time .nt-stats-metric-value"),
                playtimeNode = root.querySelector(".nt-stats-metric-playtime .nt-stats-metric-value"),
                rtaNode = root.querySelector(".nt-stats-metric-rta .nt-stats-metric-value"),
                avgTimeNode = root.querySelector(".nt-stats-metric-avg-time .nt-stats-metric-value")

            let cachedRawTotalRaces = null
            let cachedRawTeamRaces = null
            let cachedTeamRaces = null
            const syncCorrectedTeamRaces = () => {
                const racesOutsideCurrentTeam = getLiveRaceOptionNumber("RACES_OUTSIDE_CURRENT_TEAM", 0)
                const buggedTeamCount = getLiveRaceOptionNumber("TEAM_RACES_BUGGED", 0)
                if (typeof cachedRawTotalRaces === "number" && racesOutsideCurrentTeam > 0) {
                    cachedTeamRaces = cachedRawTotalRaces - racesOutsideCurrentTeam + buggedTeamCount
                } else if (typeof cachedRawTeamRaces === "number") {
                    cachedTeamRaces = cachedRawTeamRaces + buggedTeamCount
                } else {
                    cachedTeamRaces = null
                }
                if (teamRacesNode) {
                    teamRacesNode.textContent = typeof cachedTeamRaces === "number" ? cachedTeamRaces.toLocaleString() : "N/A"
                }
            }


            // Function to save the current timestamp using GM_setValue
            function saveTimestamp() {
                const currentTimestamp = Date.now(); // Get current time in milliseconds since Unix epoch
                setNtcfgRaceOptionsValue("savedTimestamp", currentTimestamp.toString()); // Convert to string and save the timestamp
            }

            // Function to load the timestamp and calculate the time difference
            function loadTimeDif() {
                const savedTimestampStr = GM_getValue("savedTimestamp", null); // Load the saved timestamp as a string

                if (savedTimestampStr === null) {
                    return null;
                }

                // Convert the retrieved string back to a number
                const savedTimestamp = parseInt(savedTimestampStr, 10);

                // Validate the loaded timestamp
                if (isNaN(savedTimestamp)) {
                    return null;
                }

                const currentTimestamp = Date.now(); // Get the current timestamp
                const timeDiff = currentTimestamp - savedTimestamp; // Calculate the difference in milliseconds

                // Convert the time difference to minutes and seconds
                const minutes = Math.floor(timeDiff / 60000); // Convert to minutes
                const seconds = Math.floor((timeDiff % 60000) / 1000); // Convert remaining milliseconds to seconds

                // Format the time difference as "00:00 MM:SS"
                const formattedTimeDiff = `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;

                return formattedTimeDiff;
            }

            function formatPlayTime(seconds) {
                let hours = Math.floor(seconds / 3600);
                let minutes = Math.floor((seconds % 3600) / 60);
                let remainingSeconds = seconds % 60;

                return `${hours}h ${minutes}m ${remainingSeconds}s`;
            }

            const getRaceEntries = (data) => {
                if (!data || typeof data.lastRaces !== "string") return []
                const entries = data.lastRaces
                    .split("|")
                    .map((s) => s.trim())
                    .filter(Boolean)
                const parsed = []
                for (const entry of entries) {
                    const parts = entry.split(",").map((p) => p.trim())
                    if (parts.length < 3) continue
                    const chars = Number(parts[0])
                    const duration = Number(parts[1])
                    const errors = Number(parts[2])
                    if (!Number.isFinite(chars) || !Number.isFinite(duration) || !Number.isFinite(errors)) continue
                    if (chars <= 0 || duration <= 0) continue
                    parsed.push({ chars, duration, errors })
                }
                return parsed
            }

            const calcWpm = (chars, duration) => (chars / duration) * 12

            function getLastRaceMetrics(data) {
                const races = getRaceEntries(data)
                if (races.length === 0) return null
                const last = races[races.length - 1]
                const wpm = calcWpm(last.chars, last.duration)
                const acc = ((last.chars - last.errors) * 100) / last.chars
                return {
                    wpm: wpm.toFixed(2),
                    acc: acc.toFixed(2),
                    time: last.duration.toFixed(2),
                }
            }

            function getAverageMetrics(data) {
                const races = getRaceEntries(data)
                if (races.length === 0) return null
                let totalDuration = 0
                let totalWpm = 0
                let totalAcc = 0
                for (const r of races) {
                    totalDuration += r.duration
                    totalWpm += calcWpm(r.chars, r.duration)
                    totalAcc += ((r.chars - r.errors) * 100) / r.chars
                }
                return {
                    wpm: (totalWpm / races.length).toFixed(2),
                    acc: (totalAcc / races.length).toFixed(2),
                    time: (totalDuration / races.length).toFixed(2),
                }
            }
            function timeSinceLastLogin(data) {
                let lastLogin = data.lastLogin; // Timestamp of last login (in seconds)
                let currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
                currentTime = data.lastConsecRace;
                let elapsedTime = currentTime - lastLogin; // Time since last login in seconds
                let minutes = Math.floor(elapsedTime / 60);
                let seconds = elapsedTime % 60;

                // Format the output as "MM:SS"
                return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
            }

            function handleSessionRaces(data) {
                const sessionRaces = data.sessionRaces; // Get sessionRaces from data

                if (sessionRaces === 0) {
                    const lastSavedTimestampStr = GM_getValue("savedTimestamp", null);

                    if (lastSavedTimestampStr !== null) {
                        const lastSavedTimestamp = parseInt(lastSavedTimestampStr, 10);

                        // Check if the last saved timestamp was less than 30 minutes ago
                        // otherwise, it is not possible, because game resets session after at least 30 minutes
                        // necessary, because it might call save function multiple times for same session at the end of the race
                        // it would not fix value if page was loaded at first race and it was not succesful
                        // so value would overshoot in that case by whenever frist race attempt of the session started
                        const fifteenMinutesInMs = 30 * 60 * 1000;
                        const currentTimestamp = Date.now();

                        if (currentTimestamp - lastSavedTimestamp < fifteenMinutesInMs) {
                            return; // Exit the function to avoid saving again
                        }
                    }

                    // If no recent timestamp or no timestamp at all, save the current time
                    saveTimestamp();
                    rtaNode.textContent = "00:00";
                } else {
                    // If sessionRaces is not 0, load the time difference
                    const timeDifference = loadTimeDif();

                    if (timeDifference !== null) {
                        rtaNode.textContent = timeDifference;
                    } else {
                        // If the script starts mid-session, we can't infer session start.
                        // Start the timer "now" so we don't show a confusing N/A forever.
                        saveTimestamp();
                        rtaNode.textContent = "00:00";
                    }
                }
            }
            return {
                root,
                refreshTeamRaceCorrections: () => {
                    syncCorrectedTeamRaces()
                },
                updateStats: (data) => {
                    if (typeof data?.playTime === "number") {
                        playtimeNode.textContent = formatPlayTime(data.playTime);
                    }
                    if (typeof data?.experience === "number") {
                        seasonXPNode.textContent = data.experience.toLocaleString();
                    } else if (typeof data?.experience === "string") {
                        const value = parseInt(data.experience, 10)
                        if (!isNaN(value)) {
                            seasonXPNode.textContent = value.toLocaleString()
                        }
                    }
                    if (typeof data?.lastRaces === "string") {
                        const avg = getAverageMetrics(data)
                        if (avg) {
                            avgTimeNode.textContent = avg.time
                            avgSpeedNode.textContent = avg.wpm
                            avgAccuracyNode.textContent = avg.acc
                        }
                        const last = getLastRaceMetrics(data)
                        if (last) {
                            lastSpeedNode.textContent = last.wpm
                            lastAccuracyNode.textContent = last.acc
                            lastTimeNode.textContent = last.time
                        } else {
                            lastSpeedNode.textContent = "N/A"
                            lastAccuracyNode.textContent = "N/A"
                            lastTimeNode.textContent = "N/A"
                        }
                    }
                    if (typeof data?.racesPlayed === "number") {
                        cachedRawTotalRaces = data.racesPlayed
                        totalRacesNode.textContent = data.racesPlayed.toLocaleString();
                        syncCorrectedTeamRaces()
                    }
                    if (typeof data?.teamRaces === "number") {
                        cachedRawTeamRaces = data.teamRaces
                        syncCorrectedTeamRaces()
                    }
                    if (typeof data?.sessionRaces === "number") {
                        sessionRacesNode.textContent = data.sessionRaces.toLocaleString();
                        handleSessionRaces(data);
                    }
                    if ((typeof data?.avgAcc === "string" || typeof data?.avgAcc === "number") && avgAccuracyNode.textContent === "0") {
                        avgAccuracyNode.textContent = data.avgAcc
                    }
                    if (typeof data?.avgSpeed === "number") {
                        //avgSpeed.textContent = data.avgSpeed
                    } else if (typeof data?.avgScore === "number") {
                        //avgSpeed.textContent = data.avgScore
                    }
                },
            }
        })()

        ////////////
        //  Main  //
        ////////////

        const isStatsPanelEnabled = () => isLiveRaceOptionEnabled("enableStats", true);

        let statsPanelRoot = null;
        let statsPanelLayoutObserver = null;
        let statsPanelResizeObserver = null;
        let statsPanelLayoutFrame = null;
        const ensureStatsPanelRoot = () => {
            if (statsPanelRoot) {
                return statsPanelRoot;
            }

            const root = document.createElement("div"),
                body = document.createElement("div");
            root.classList.add("nt-stats-root");
            root.dataset.ntcfgStatsPanel = "1";
            body.classList.add("nt-stats-body");

            const leftSection = document.createElement("div");
            leftSection.classList.add("nt-stats-left-section");
            leftSection.append(DailyChallengeWidget.root);

            const rightSection = document.createElement("div");
            rightSection.classList.add("nt-stats-right-section");
            rightSection.append(StatWidget.root, SeasonProgressWidget.root);

            body.append(leftSection, rightSection);
            root.append(body, ToolbarWidget.root);

            statsPanelRoot = root;
            return statsPanelRoot;
        };

        const getMountedStatsPanelRoot = () => statsPanelRoot && statsPanelRoot.isConnected
            ? statsPanelRoot
            : document.querySelector(".nt-stats-root[data-ntcfg-stats-panel=\"1\"]");

        const resetStatsPanelLayout = (root = getMountedStatsPanelRoot()) => {
            if (!root) return;
            root.classList.remove("nt-stats-root--wide");
            root.style.removeProperty("width");
            root.style.removeProperty("max-width");
            root.style.removeProperty("margin-left");
            root.style.removeProperty("margin-right");
        };

        const syncStatsPanelLayout = () => {
            const root = getMountedStatsPanelRoot();
            const mountTarget = raceContainer?.parentElement;
            if (!root || !raceContainer || !mountTarget) {
                resetStatsPanelLayout(root);
                return;
            }

            const raceRect = raceContainer.getBoundingClientRect();
            const parentRect = mountTarget.getBoundingClientRect();
            if (!Number.isFinite(raceRect.width) || !Number.isFinite(parentRect.width) || raceRect.width <= 0 || parentRect.width <= 0) {
                resetStatsPanelLayout(root);
                return;
            }

            const widthDelta = Math.abs(raceRect.width - parentRect.width);
            const leftDelta = raceRect.left - parentRect.left;
            root.classList.toggle("nt-stats-root--wide", widthDelta >= 100);
            if (widthDelta < 1 && Math.abs(leftDelta) < 1) {
                resetStatsPanelLayout(root);
                return;
            }

            root.style.width = `${raceRect.width}px`;
            root.style.maxWidth = "none";
            root.style.marginLeft = `${leftDelta}px`;
            root.style.marginRight = "0";
        };

        const queueStatsPanelLayoutSync = () => {
            if (statsPanelLayoutFrame !== null) {
                return;
            }
            statsPanelLayoutFrame = window.requestAnimationFrame(() => {
                statsPanelLayoutFrame = null;
                syncStatsPanelLayout();
            });
        };

        const ensureStatsPanelLayoutObserver = () => {
            if (statsPanelLayoutObserver || statsPanelResizeObserver) {
                return;
            }

            const handleLayoutChange = () => queueStatsPanelLayoutSync();

            if (typeof ResizeObserver === "function") {
                statsPanelResizeObserver = new ResizeObserver(handleLayoutChange);
                if (raceContainer) {
                    statsPanelResizeObserver.observe(raceContainer);
                }
                if (raceContainer?.parentElement) {
                    statsPanelResizeObserver.observe(raceContainer.parentElement);
                }
            }

            statsPanelLayoutObserver = new MutationObserver(handleLayoutChange);
            if (raceContainer) {
                statsPanelLayoutObserver.observe(raceContainer, { attributes: true, attributeFilter: ["class", "style"] });
            }
            if (raceContainer?.parentElement) {
                statsPanelLayoutObserver.observe(raceContainer.parentElement, { attributes: true, attributeFilter: ["class", "style"] });
            }

            window.addEventListener("resize", handleLayoutChange);
        };

        const syncStatsPanelMount = () => {
            const existingRoot = getMountedStatsPanelRoot();

            if (!isStatsPanelEnabled()) {
                resetStatsPanelLayout(existingRoot);
                existingRoot?.remove();
                return;
            }

            const mountTarget = raceContainer?.parentElement;
            if (!mountTarget) {
                return;
            }

            const root = ensureStatsPanelRoot();
            if (!root.isConnected) {
                mountTarget.append(root);
            }
            ensureStatsPanelLayoutObserver();
            queueStatsPanelLayoutSync();
        };

        syncStatsPanelMount();

        /* Add stats into race page with current values */
        getStats().then(({
            user,
            dailyChallenges
        }) => {
            StatWidget.updateStats(user)
            SeasonProgressWidget.updateStats(user)
            DailyChallengeWidget.updateStats(dailyChallenges)
            ToolbarWidget.updateStats(user)
            logging.info("Update")("Start of race")
            syncStatsPanelMount()
        }).catch((error) => {
            logging.warn("Update")("Stats panel mounted without initial stats payload", error)
            syncStatsPanelMount()
        })

        getTeamStats().then(
            (data) => {
                const {
                    member,
                } = data
                StatWidget.updateStats({
                    teamRaces: member?.played,
                })
            },
            (err) => {
                if (err.message !== "User is not in a team") {
                    return Promise.reject(err)
                }
            }
        )

        /** Broadcast Channel to let other windows know that stats updated. */
        const MESSGAE_LAST_RACE_UPDATED = "last_race_updated",
            MESSAGE_DAILY_CHALLANGE_UPDATED = "stats_daily_challenge_updated",
            MESSAGE_USER_STATS_UPDATED = "stats_user_updated"

        const statChannel = new BroadcastChannel("NTRacingStats")
        statChannel.onmessage = (e) => {
            const [type, payload] = e.data
            switch (type) {
                case MESSGAE_LAST_RACE_UPDATED:
                    getStats().then(({
                        user,
                        dailyChallenges
                    }) => {
                        StatWidget.updateStats(user)
                        SeasonProgressWidget.updateStats(user)
                        DailyChallengeWidget.updateStats(dailyChallenges)
                        ToolbarWidget.updateStats(user)
                    })
                    break
                case MESSAGE_DAILY_CHALLANGE_UPDATED:
                    DailyChallengeWidget.updateStats(payload)
                    break
                case MESSAGE_USER_STATS_UPDATED:
                    StatWidget.updateStats(payload)
                    SeasonProgressWidget.updateStats(payload)
                    break
            }
        }

        /** Sync Daily Challenge data. */
        server.on("setup", (e) => {
            const dailyChallenges = mergeDailyChallengeData(e.challenges)
            DailyChallengeWidget.updateStats(dailyChallenges)
            statChannel.postMessage([MESSAGE_DAILY_CHALLANGE_UPDATED, dailyChallenges])
        })

        /** Sync some of the User Stat data. */
        server.on("joined", (e) => {
            if (e.userID !== currentUser.userID) {
                return
            }
            const payload = {
                level: e.profile?.level,
                racesPlayed: e.profile?.racesPlayed,
                sessionRaces: e.profile?.sessionRaces,
                avgSpeed: e.profile?.avgSpeed,
            }
            StatWidget.updateStats(payload)
            SeasonProgressWidget.updateStats(payload)
            statChannel.postMessage([MESSAGE_USER_STATS_UPDATED, payload])
        })

        /** Track Race Finish exact time. */
        let hasCollectedResultStats = false

        server.on("update", (e) => {
            const me = e?.racers?.find((r) => r.userID === currentUser.userID)
            if (me.progress.completeStamp > 0 && me.rewards?.current && !hasCollectedResultStats) {
                hasCollectedResultStats = true
                db.backupStatData.put({
                    ...me.rewards.current,
                    challenges: me.challenges,
                    userID: currentUser.userID
                }).then(() => {
                    statChannel.postMessage([MESSGAE_LAST_RACE_UPDATED])
                })
            }
        })

        /** Mutation observer to check if Racing Result has shown up. */
        const resultObserver = new MutationObserver(([mutation], observer) => {
            for (const node of mutation.addedNodes) {
                if (node.classList?.contains("race-results")) {
                    observer.disconnect()
                    logging.info("Update")("Race Results received")

                    //AUTO RELOAD
                    //logstats();
                    //setTimeout(() => location.reload(), autoReloadMS);
                    //AUTO RELOAD

                    getStats().then(({
                        user,
                        dailyChallenges
                    }) => {
                        StatWidget.updateStats(user)
                        SeasonProgressWidget.updateStats(user)
                        DailyChallengeWidget.updateStats(dailyChallenges)
                        ToolbarWidget.updateStats(user)
                        if (isLiveRaceOptionEnabled("reloadOnStats", true)) {
                            location.reload()
                        }
                    })
                    break
                }
            }
        })
        resultObserver.observe(raceContainer, {
            childList: true,
            subtree: true
        })


        ///MINI MAP




        PIXI.utils.skipHello()

        style.appendChild(
            document.createTextNode(`
.nt-racing-mini-map-root canvas {
    display: block;
}`))
        document.head.appendChild(style)

        const racingMiniMap = new PIXI.Application({
            width: 1024,
            height: 100,
            backgroundColor: config.colors.background,
            backgroundAlpha: 0.66
        }),
            container = document.createElement("div");

        container.className = "nt-racing-mini-map-root"

        ///////////////////////
        //  Prepare Objects  //
        ///////////////////////

        const RACER_WIDTH = 28,
            CROSSING_LINE_WIDTH = 32,
            PADDING = 2,
            racers = Array(5).fill(null),
            currentUserID = raceObj.props.user.userID

        // Draw mini racetrack
        const raceTrackBG = new PIXI.TilingSprite(PIXI.Texture.EMPTY, racingMiniMap.renderer.width, racingMiniMap.renderer.height),
            startLine = PIXI.Sprite.from(PIXI.Texture.WHITE),
            finishLine = PIXI.Sprite.from(PIXI.Texture.WHITE)

        startLine.x = CROSSING_LINE_WIDTH
        startLine.y = 0
        startLine.width = 1
        startLine.height = racingMiniMap.renderer.height
        startLine.tint = config.colors.startLine

        finishLine.x = racingMiniMap.renderer.width - CROSSING_LINE_WIDTH - 1
        finishLine.y = 0
        finishLine.width = 1
        finishLine.height = racingMiniMap.renderer.height
        finishLine.tint = config.colors.finishLine

        raceTrackBG.addChild(startLine, finishLine)

        for (let i = 1; i < 5; i++) {
            const lane = PIXI.Sprite.from(PIXI.Texture.WHITE)
            lane.x = 0
            lane.y = i * (racingMiniMap.renderer.height / 5)
            lane.width = racingMiniMap.renderer.width
            lane.height = 1
            lane.tint = config.colors.raceLane
            raceTrackBG.addChild(lane)
        }

        racingMiniMap.stage.addChild(raceTrackBG)

        /* Mini Map movement animation update. */
        function animateRacerTicker() {
            const r = this
            const lapse = Date.now() - r.lastUpdated
            if (r.sprite.x < r.toX) {
                const distance = r.toX - r.fromX
                r.sprite.x = r.fromX + Math.min(distance, distance * (lapse / r.moveMS))
                if (r.ghostSprite && r.sprite.x === r.ghostSprite.x) {
                    r.ghostSprite.renderable = false
                }
            }

            if (r.skipped > 0) {
                const nitroTargetWidth = r.nitroToX - r.nitroFromX
                if (r.nitroSprite.width < nitroTargetWidth) {
                    r.nitroSprite.width = Math.min(nitroTargetWidth, r.sprite.x - r.nitroFromX)
                } else if (r.nitroSprite.width === nitroTargetWidth && r.nitroSprite.alpha > 0 && !r.nitroDisableFade) {
                    if (r.nitroSprite.alpha === 1) {
                        r.nitroStartFadeStamp = Date.now() - 1
                    }
                    r.nitroSprite.alpha = Math.max(0, 1 - ((Date.now() - r.nitroStartFadeStamp) / 1e3))
                }
            }
            if (r.completeStamp !== null && r.sprite.x === r.toX && r.nitroSprite.alpha === 0) {
                racingMiniMap.ticker.remove(animateRacerTicker, this)
            }
        }

        /* Handle adding in players on the mini map. */
        server.on("joined", (e) => {
            //console.log(my_race_started);
            my_race_started = true;
            const {
                lane,
                userID
            } = e

            let color = config.colors.opponentBot
            if (userID === currentUserID) {
                color = config.colors.me
            } else if (!e.robot) {
                color = config.colors.opponentPlayer
            } else if (e.profile.specialRobot === "wampus") {
                color = config.colors.opponentWampus
            }

            if (racers[lane]) {
                racers[lane].ghostSprite.tint = color
                racers[lane].sprite.tint = color
                racers[lane].sprite.x = 0 - RACER_WIDTH + PADDING
                racers[lane].lastUpdated = Date.now()
                racers[lane].fromX = racers[lane].sprite.x
                racers[lane].toX = PADDING
                racers[lane].sprite.renderable = true
                return
            }

            const r = PIXI.Sprite.from(PIXI.Texture.WHITE)
            r.x = 0 - RACER_WIDTH + PADDING
            r.y = PADDING + (lane > 0 ? 1 : 0) + (lane * (racingMiniMap.renderer.height / 5))
            r.tint = color
            r.width = RACER_WIDTH
            r.height = 16 - (lane > 0 ? 1 : 0)

            const n = PIXI.Sprite.from(PIXI.Texture.WHITE)
            n.y = r.y + ((16 - (lane > 0 ? 1 : 0)) / 2) - 1
            n.renderable = false
            n.tint = config.colors.nitro
            n.width = 1
            n.height = 2

            racers[lane] = {
                lane,
                sprite: r,
                userID: userID,
                ghostSprite: null,
                nitroSprite: n,
                lastUpdated: Date.now(),
                fromX: r.x,
                toX: PADDING,
                skipped: 0,
                nitroStartFadeStamp: null,
                nitroFromX: null,
                nitroToX: null,
                nitroDisableFade: false,
                moveMS: 250,
                completeStamp: null,
            }

            if (config.moveDestination.enabled) {
                const g = PIXI.Sprite.from(PIXI.Texture.WHITE)
                g.x = PADDING
                g.y = PADDING + (lane > 0 ? 1 : 0) + (lane * (racingMiniMap.renderer.height / 5))
                g.tint = color
                g.alpha = config.moveDestination.alpha
                g.width = RACER_WIDTH
                g.height = 16 - (lane > 0 ? 1 : 0)
                g.renderable = false

                racers[lane].ghostSprite = g
                racingMiniMap.stage.addChild(g)
            }

            racingMiniMap.stage.addChild(n)
            racingMiniMap.stage.addChild(r)

            racingMiniMap.ticker.add(animateRacerTicker, racers[lane])
        })

        /* Handle any players leaving the race track. */
        server.on("left", (e) => {
            const lane = racers.findIndex((r) => r?.userID === e)
            if (racers[lane]) {
                racers[lane].sprite.renderable = false
                racers[lane].ghostSprite.renderable = false
                racers[lane].nitroSprite.renderable = false
            }
        })

        /* Handle race map progress position updates. */
        server.on("update", (e) => {
            let moveFinishMS = 100

            const payloadUpdateRacers = e.racers.slice().sort((a, b) => {
                if (a.progress.completeStamp === b.progress.completeStamp) {
                    return 0
                }
                if (a.progress.completeStamp === null) {
                    return 1
                }
                return a.progress.completeStamp > 0 && b.progress.completeStamp > 0 && a.progress.completeStamp > b.progress.completeStamp ? 1 : -1
            })

            for (let i = 0; i < payloadUpdateRacers.length; i++) {
                const r = payloadUpdateRacers[i],
                    {
                        completeStamp,
                        skipped
                    } = r.progress,
                    racerObj = racers[r.lane]
                if (!racerObj || racerObj.completeStamp > 0 || (r.userID === currentUserID && completeStamp <= 0 && config.trackLocally)) {
                    continue
                }

                if (r.disqualified) {
                    racingMiniMap.ticker.remove(animateRacerTicker, racerObj)
                    racingMiniMap.stage.removeChild(racerObj.sprite, racerObj.nitroSprite)
                    if (racerObj.ghostSprite) {
                        racingMiniMap.stage.removeChild(racerObj.ghostSprite)
                    }
                    racerObj.sprite.destroy()
                    racerObj.ghostSprite.destroy()
                    racerObj.nitroSprite.destroy()

                    racers[r.lane] = null
                    continue
                }

                racerObj.lastUpdated = Date.now()
                racerObj.fromX = racerObj.sprite.x

                if (racerObj.completeStamp === null && completeStamp > 0) {
                    racerObj.completeStamp = completeStamp
                    racerObj.toX = racingMiniMap.renderer.width - RACER_WIDTH - PADDING
                    racerObj.moveMS = moveFinishMS

                    if (racerObj.nitroDisableFade) {
                        racerObj.nitroToX = racingMiniMap.renderer.width - RACER_WIDTH - PADDING
                        racerObj.nitroDisableFade = false
                    }
                } else {
                    racerObj.moveMS = 1e3
                    racerObj.toX = r.progress.percentageFinished * (racingMiniMap.renderer.width - RACER_WIDTH - CROSSING_LINE_WIDTH - PADDING - 1)
                    racerObj.sprite.x = racerObj.fromX
                }

                if (racerObj.ghostSprite) {
                    racerObj.ghostSprite.x = racerObj.toX
                    racerObj.ghostSprite.renderable = true
                }

                if (skipped !== racerObj.skipped) {
                    if (racerObj.skipped === 0) {
                        racerObj.nitroFromX = racerObj.fromX
                        racerObj.nitroSprite.x = racerObj.fromX
                        racerObj.nitroSprite.renderable = true
                    }
                    racerObj.skipped = skipped // because infinite nitros exist? :/
                    racerObj.nitroToX = racerObj.toX
                    racerObj.nitroSprite.alpha = 1
                    if (racerObj.completeStamp !== null) {
                        racerObj.nitroToX = racingMiniMap.renderer.width - RACER_WIDTH - PADDING
                    }
                }

                if (completeStamp > 0 && i + 1 < payloadUpdateRacers.length) {
                    const nextRacer = payloadUpdateRacers[i + 1],
                        nextRacerObj = racers[nextRacer?.lane]
                    if (nextRacerObj && nextRacerObj.completeStamp === null && nextRacer.progress.completeStamp > 0 && nextRacer.progress.completeStamp > completeStamp) {
                        moveFinishMS += 100
                    }
                }
            }
        })

        if (config.trackLocally) {
            let lessonLength = 0
            server.on("status", (e) => {
                if (e.status === "countdown") {
                    lessonLength = e.lessonLength
                }
            })

            const originalSendPlayerUpdate = server.sendPlayerUpdate
            server.sendPlayerUpdate = (data) => {
                originalSendPlayerUpdate(data)
                const racerObj = racers.find((r) => r?.userID === currentUserID)
                if (!racerObj) {
                    return
                }

                const percentageFinished = (data.t / (lessonLength || 1))
                racerObj.lastUpdated = Date.now()
                racerObj.fromX = racerObj.sprite.x
                racerObj.moveMS = 100
                racerObj.toX = percentageFinished * (racingMiniMap.renderer.width - RACER_WIDTH - CROSSING_LINE_WIDTH - PADDING - 1)
                racerObj.sprite.x = racerObj.fromX

                if (racerObj.ghostSprite) {
                    racerObj.ghostSprite.x = racerObj.toX
                    racerObj.ghostSprite.renderable = true
                }

                if (data.s) {
                    if (racerObj.skipped === 0) {
                        racerObj.nitroFromX = racerObj.fromX
                        racerObj.nitroSprite.x = racerObj.fromX
                        racerObj.nitroSprite.renderable = true
                    }
                    racerObj.skipped = data.s // because infinite nitros exist? but I'm not going to test that! :/
                    racerObj.nitroToX = racerObj.toX
                    racerObj.nitroSprite.alpha = 1
                    racerObj.nitroDisableFade = percentageFinished === 1

                    if (racerObj.completeStamp !== null) {
                        racerObj.nitroToX = racingMiniMap.renderer.width - RACER_WIDTH - PADDING
                    }
                }
            }
        }

        /////////////
        //  Final  //
        /////////////

        const syncMiniMapMount = () => {
            if (!isLiveRaceOptionEnabled("ENABLE_MINI_MAP", false)) {
                container.remove()
                return
            }
            if (!container.contains(racingMiniMap.view)) {
                container.append(racingMiniMap.view)
            }
            const miniMapPosition = normalizeMiniMapPositionValue(
                getLiveRaceOptionValue("MINI_MAP_POSITION", MINI_MAP_POSITION),
                MINI_MAP_POSITION
            )
            if (miniMapPosition === "top") {
                raceContainer.before(container)
            } else {
                raceContainer.after(container)
            }
        }

        syncMiniMapMount()

        //alt wpm thingy

        /** Get Nitro Word Length. */
        const nitroWordLength = (words, i) => {
            let wordLength = words[i].length + 1
            if (i > 0 && i + 1 < words.length) {
                wordLength++
            }
            return wordLength
        }

        const normalizeDashWord = (word) => String(word || "").replace(/\s/g, "")

        const getLargestWordIndexes = (wordList) => {
            let largest = 0
            const indexes = []

            for (let i = 0; i < wordList.length; i++) {
                const normalized = normalizeDashWord(wordList[i])
                const len = normalized.length
                if (len === 0) continue
                if (len > largest) {
                    largest = len
                    indexes.length = 0
                    indexes.push(i)
                } else if (len === largest) {
                    indexes.push(i)
                }
            }
            return indexes
        }

        let perfectNitroHighlightInterval = null
        let perfectNitroHighlightAttempts = 0
        let perfectNitroUsedThisRace = false
        const PERFECT_NITRO_MAX_ATTEMPTS = 250

        const resetPerfectNitroUsageState = () => {
            perfectNitroUsedThisRace = false
        }

        const consumePerfectNitroHighlights = () => {
            if (perfectNitroUsedThisRace) {
                return
            }
            perfectNitroUsedThisRace = true
            stopPerfectNitroHighlighter()
            clearPerfectNitroHighlights()
        }

        const clearPerfectNitroHighlights = () => {
            document.querySelectorAll('.dash-word[data-nt-perfect-nitro="1"]').forEach((node) => {
                node.style.removeProperty("background-color")
                node.style.removeProperty("font-style")
                node.querySelectorAll(".dash-letter").forEach((letter) => {
                    letter.style.removeProperty("font-style")
                    letter.classList.remove("ntcfg-perfect-nitro-rainbow")
                })
                node.removeAttribute("data-nt-perfect-nitro")
            })
            const textStyle = document.getElementById("ntcfg-perfect-nitro-text-style")
            if (textStyle) textStyle.remove()
            const rainbowStyle = document.getElementById("ntcfg-perfect-nitro-rainbow-style")
            if (rainbowStyle) rainbowStyle.remove()
        }

        const ensurePerfectNitroTextStyle = (color, shadow) => {
            let style = document.getElementById("ntcfg-perfect-nitro-text-style")
            if (!style) {
                style = document.createElement("style")
                style.id = "ntcfg-perfect-nitro-text-style"
                document.head.appendChild(style)
            }
            const colorRule = color ? `color: ${color} !important;` : ""
            const shadowRule = shadow ? `text-shadow: ${shadow} !important;` : ""
            style.textContent = `.dash-word[data-nt-perfect-nitro="1"] .dash-letter:not(.is-waiting):not(.is-incorrect) { ${colorRule} ${shadowRule} }`
        }

        const ensurePerfectNitroRainbowStyle = () => {
            if (document.getElementById("ntcfg-perfect-nitro-rainbow-style")) return
            const style = document.createElement("style")
            style.id = "ntcfg-perfect-nitro-rainbow-style"
            style.textContent = `
@keyframes ntcfg-perfect-nitro-rainbow {
    0% { color: #FF0000; }
    14% { color: #FF8C00; }
    28% { color: #FFD700; }
    42% { color: #00CC00; }
    57% { color: #0066FF; }
    71% { color: #7B00FF; }
    85% { color: #FF00FF; }
    100% { color: #FF0000; }
}
.ntcfg-perfect-nitro-rainbow {
    animation: ntcfg-perfect-nitro-rainbow 3s linear infinite !important;
    -webkit-animation: ntcfg-perfect-nitro-rainbow 3s linear infinite !important;
}
`
            document.head.appendChild(style)
        }

        const stopPerfectNitroHighlighter = () => {
            if (perfectNitroHighlightInterval !== null) {
                clearInterval(perfectNitroHighlightInterval)
                perfectNitroHighlightInterval = null
            }
        }

        const applyPerfectNitroHighlight = (indexes, options) => {
            const dashWords = Array.from(document.getElementsByClassName("dash-word"))
            if (dashWords.length === 0 || indexes.length === 0) {
                return false
            }
            if (indexes.some((idx) => !dashWords[idx])) {
                return false
            }

            clearPerfectNitroHighlights()

            const { highlightColor, highlightOpacity, enableHighlight, italic, rainbow, overrideTextColor, textColor } = options
            const bgRgba = enableHighlight ? hexToRgba(highlightColor, highlightOpacity) : null
            const adaptiveTextStyle = enableHighlight
                ? getPerfectNitroTextStyle(highlightColor, highlightOpacity)
                : { color: null, shadow: null }
            const textStyle = overrideTextColor
                ? { color: textColor, shadow: null }
                : rainbow
                    ? { color: null, shadow: adaptiveTextStyle.shadow }
                    : adaptiveTextStyle

            if (rainbow) {
                ensurePerfectNitroRainbowStyle()
            }

            // Use a stylesheet rule for text color so it dynamically
            // excludes the active cursor and incorrect indicator letters
            if (textStyle.color || textStyle.shadow) {
                ensurePerfectNitroTextStyle(textStyle.color, textStyle.shadow)
            }

            let applied = 0
            indexes.forEach((idx) => {
                const node = dashWords[idx]
                if (!node) return
                node.dataset.ntPerfectNitro = "1"
                if (bgRgba) {
                    node.style.backgroundColor = bgRgba
                }
                if (italic) {
                    node.style.fontStyle = "italic"
                }
                node.querySelectorAll(".dash-letter").forEach((letter) => {
                    if (rainbow) {
                        letter.classList.add("ntcfg-perfect-nitro-rainbow")
                    }
                    if (italic) {
                        letter.style.fontStyle = "italic"
                    }
                })
                applied++
            })
            return applied > 0
        }

        const startPerfectNitroHighlighter = (lesson = "") => {
            stopPerfectNitroHighlighter()
            perfectNitroHighlightAttempts = 0

            const startupOptions = getPerfectNitroOptions()
            if (!startupOptions.enabled || perfectNitroUsedThisRace) {
                clearPerfectNitroHighlights()
                return
            }

            const lessonWords = typeof lesson === "string" ? lesson.split(" ") : []
            const lessonIndexes = getLargestWordIndexes(lessonWords)

            const tick = () => {
                const options = getPerfectNitroOptions()
                if (!options.enabled || perfectNitroUsedThisRace) {
                    stopPerfectNitroHighlighter()
                    clearPerfectNitroHighlights()
                    return
                }

                perfectNitroHighlightAttempts++

                let indexes = lessonIndexes
                if (indexes.length === 0) {
                    const currentWords = Array.from(document.getElementsByClassName("dash-word")).map((node) => node.textContent || "")
                    indexes = getLargestWordIndexes(currentWords)
                }

                if (applyPerfectNitroHighlight(indexes, options)) {
                    stopPerfectNitroHighlighter()
                    return
                }

                if (perfectNitroHighlightAttempts >= PERFECT_NITRO_MAX_ATTEMPTS) {
                    stopPerfectNitroHighlighter()
                }
            }

            tick()
            if (perfectNitroHighlightInterval === null) {
                perfectNitroHighlightInterval = setInterval(tick, startupOptions.intervalMs)
            }
        }

        /** Get Player Avg using lastRaces data. */
        const getPlayerAvg = (prefix, raceObj, lastRaces) => {
            const raceLogs = (lastRaces || raceObj.props.user.lastRaces)
                .split("|")
                .map((r) => {
                    const data = r.split(","),
                        typed = parseInt(data[0], 10),
                        time = parseFloat(data[1]),
                        errs = parseInt(data[2])
                    if (isNaN(typed) || isNaN(time) || isNaN(errs)) {
                        return false
                    }
                    return {
                        time,
                        acc: 1 - errs / typed,
                        wpm: typed / 5 / (time / 60),
                    }
                })
                .filter((r) => r !== false)

            const avgSpeed = raceLogs.reduce((prev, current) => prev + current.wpm, 0.0) / Math.max(raceLogs.length, 1)

            logging.info(prefix)("Avg Speed", avgSpeed)
            console.table(raceLogs, ["time", "acc", "wpm"])

            return avgSpeed
        }

        ///////////////
        //  Backend  //
        ///////////////

        if (config.targetWPM <= 0) {
            logging.error("Init")("Invalid target WPM value")
            return
        }

        let raceTimeLatency = null

        /** Styles for the following components. */
        const styleNew = document.createElement("style")
        styleNew.appendChild(
            document.createTextNode(`
/* Some Overrides */
.race-results {
    z-index: 6;
}

/* Sandbagging Tool */
.nt-evil-sandbagging-root {
    position: absolute;
    top: 0px;
    left: 0px;
    z-index: 5;
    color: #E7EEF8;
    touch-action: none;
}
.nt-evil-sandbagging-metric-value {
    font-weight: 600;
    font-family: "Roboto Mono", "Courier New", Courier, "Lucida Sans Typewriter", "Lucida Typewriter", monospace;
}
.nt-evil-sandbagging-metric-suffix {
    color: #8FA3BA;
}
.nt-evil-sandbagging-live {
    padding: 5px;
    border-radius: 8px;
    color: #D62F3A;
    background-color: rgba(10, 18, 30, 0.88);
    border: 1px solid rgba(22, 122, 195, 0.42);
    text-align: center;
}
.nt-evil-sandbagging-live span.live-wpm-inactive {
    opacity: 1;
}
.nt-evil-sandbagging-live > span:not(.live-wpm-inactive) .nt-evil-sandbagging-metric-value {
    color: #167AC3;
}
.nt-evil-sandbagging-best-live-wpm {
    font-size: 10px;
}
.nt-evil-sandbagging-section {
    padding: 5px;
    border-top: 1px solid rgba(255, 255, 255, 0.15);
    font-size: 10px;
    text-align: center;
}
.nt-evil-sandbagging-stats {
    background-color: rgba(10, 18, 30, 0.95);
    border-top-color: rgba(22, 122, 195, 0.45);
}
.nt-evil-sandbagging-results {
    border-bottom-left-radius: 8px;
    border-bottom-right-radius: 8px;
    background-color: rgba(17, 34, 53, 0.95);
    border-top-color: rgba(214, 47, 58, 0.45);
}`)
        )
        document.head.appendChild(styleNew);

        /** Manages and displays the race timer. */
        const RaceTimer = ((config) => {
            // Restore widget settings
            let widgetSettings = null
            try {
                const data = localStorage.getItem("nt_sandbagging_tool")
                if (typeof data === "string") {
                    widgetSettings = JSON.parse(data)
                }
            } catch {
                widgetSettings = null
            }
            if (widgetSettings === null) {
                widgetSettings = { x: 384, y: 285 }
            }

            // Setup Widget
            const root = document.createElement("div")
            root.classList.add("nt-evil-sandbagging-root", "has-live-wpm")
            root.dataset.x = widgetSettings.x
            root.dataset.y = widgetSettings.y
            root.style.transform = `translate(${parseFloat(root.dataset.x) || 0}px, ${parseFloat(root.dataset.y) || 0}px)`
            root.innerHTML = `
        <div class="nt-evil-sandbagging-live">
            <span class="nt-evil-sandbagging-current-live-wpm live-wpm-inactive">
                <small class="nt-evil-sandbagging-metric-suffix">Prepare for your race!</small><span class="nt-evil-sandbagging-live-wpm nt-evil-sandbagging-metric-value"></span>
            </span>
            <span class="nt-evil-sandbagging-best-live-wpm live-wpm-inactive">
                (<span class="nt-evil-sandbagging-metric-value">0.00</span> <small class="nt-evil-sandbagging-metric-suffix">WPM</small>)
            </span>
        </div>
        <div class="nt-evil-sandbagging-section nt-evil-sandbagging-stats">
            Timer: <span class="nt-evil-sandbagging-live-time nt-evil-sandbagging-metric-value">0.00</span> / <span class="nt-evil-sandbagging-target-time nt-evil-sandbagging-metric-value">0.00</span> <small class="nt-evil-sandbagging-metric-suffix">sec</small> |
            Target: <span class="nt-evil-sandbagging-target-wpm nt-evil-sandbagging-metric-value">${config.targetWPM}</span> <small class="nt-evil-sandbagging-metric-suffix">WPM</small> |
            Avg: <span class="nt-evil-sandbagging-current-avg-wpm nt-evil-sandbagging-metric-value">?</span> <small class="nt-evil-sandbagging-metric-suffix">WPM</small>
        </div>
        <div class="nt-evil-sandbagging-section nt-evil-sandbagging-results">
            Time: <span class="nt-evil-sandbagging-result-time nt-evil-sandbagging-metric-value">?</span> <small class="nt-evil-sandbagging-metric-suffix">secs</small> |
            Speed: <span class="nt-evil-sandbagging-result-wpm nt-evil-sandbagging-metric-value">?</span> <small class="nt-evil-sandbagging-metric-suffix">WPM</small> |
            Avg: <span class="nt-evil-sandbagging-new-avg-wpm nt-evil-sandbagging-metric-value">?</span> <small class="nt-evil-sandbagging-metric-suffix">WPM</small> |
            Latency: <span class="nt-evil-sandbagging-latency nt-evil-sandbagging-metric-value">?</span> <small class="nt-evil-sandbagging-metric-suffix">ms</small>
        </div>`

            const liveContainerNode = root.querySelector(".nt-evil-sandbagging-live"),
                liveCurrentWPMContainerNode = liveContainerNode.querySelector(".nt-evil-sandbagging-current-live-wpm"),
                liveWPMValueNode = liveCurrentWPMContainerNode.querySelector(".nt-evil-sandbagging-live-wpm"),
                liveBestWPMContainerNode = liveContainerNode.querySelector(".nt-evil-sandbagging-best-live-wpm"),
                liveBestWPMValueNode = liveBestWPMContainerNode.querySelector(".nt-evil-sandbagging-metric-value"),
                statContainerNode = root.querySelector(".nt-evil-sandbagging-stats"),
                liveTimeNode = statContainerNode.querySelector(".nt-evil-sandbagging-live-time"),
                targetTimeNode = statContainerNode.querySelector(".nt-evil-sandbagging-target-time"),
                targetWPMNode = statContainerNode.querySelector(".nt-evil-sandbagging-target-wpm"),
                currentAvgWPMNode = statContainerNode.querySelector(".nt-evil-sandbagging-current-avg-wpm"),
                resultContainerNode = root.querySelector(".nt-evil-sandbagging-results"),
                resultTimeNode = resultContainerNode.querySelector(".nt-evil-sandbagging-result-time"),
                resultWPMNode = resultContainerNode.querySelector(".nt-evil-sandbagging-result-wpm"),
                resultNewAvgWPMNode = resultContainerNode.querySelector(".nt-evil-sandbagging-new-avg-wpm"),
                resultLatencyNode = resultContainerNode.querySelector(".nt-evil-sandbagging-latency")

            resultContainerNode.remove()

            statContainerNode.style.display = 'none';
            liveBestWPMContainerNode.style.display = 'none';
            resultContainerNode.style.display = 'none';

            let timer = null,
                targetWPM = config.targetWPM || 79.49,
                startTime = null,
                finishTime = null,
                skipLength = null,
                bestSkipLength = null,
                lessonLength = null,
                onTargetTimeUpdate = null,
                onTimeUpdate = null

            /** Updates the race timer metrics. */
            const refreshCurrentTime = () => {
                if (startTime === null) {
                    logging.warn("Update")("Invalid last time, unable to update current timer")
                    return
                }
                if (finishTime !== null) {
                    return
                }

                let diff = Date.now() - startTime
                if (onTimeUpdate) {
                    onTimeUpdate(diff)
                }
                liveTimeNode.textContent = (diff / 1e3).toFixed(2);

                diff /= 6e4;
                const suffixwpm = liveCurrentWPMContainerNode.querySelector(".nt-evil-sandbagging-metric-suffix");
                const currentWPM = (lessonLength - skipLength) / 5 / diff,
                    bestWPM = (lessonLength - bestSkipLength) / 5 / diff
                if (currentWPM < (config.targetWPM + 20)) {
                    liveWPMValueNode.textContent = (currentWPM - config.dif).toFixed(1);
                    suffixwpm.style.display = 'block';
                }
                else {

                    suffixwpm.style.display = 'none';
                    liveWPMValueNode.textContent = "Just type...!"
                }
                liveBestWPMValueNode.textContent = bestWPM.toFixed(2)

                if (currentWPM - targetWPM <= config.indicateWPMWithin) {
                    liveCurrentWPMContainerNode.classList.remove("live-wpm-inactive")
                }
                if (bestWPM - targetWPM <= config.indicateWPMWithin) {
                    liveBestWPMContainerNode.classList.remove("live-wpm-inactive")
                }
                timer = setTimeout(refreshCurrentTime, config.timerRefreshIntervalMS)
            }

            /** Toggle whether to show best wpm counter or not (the small text). */
            const toggleBestLiveWPM = (show) => {
                if (show) {
                    liveContainerNode.append(liveBestWPMContainerNode)
                } else {
                    liveBestWPMContainerNode.remove()
                }
            }

            /** Save widget settings. */
            const saveSettings = () => {
                localStorage.setItem("nt_sandbagging_tool", JSON.stringify(widgetSettings))
            }
            saveSettings()

            /** Setup draggable widget. */
            interact(root).draggable({
                modifiers: [
                    interact.modifiers.restrictRect({
                        //restriction: "parent",
                        endOnly: true,
                    }),
                ],
                listeners: {
                    move: (event) => {
                        const target = event.target,
                            x = (parseFloat(target.dataset.x) || 0) + event.dx,
                            y = (parseFloat(target.dataset.y) || 0) + event.dy

                        target.style.transform = "translate(" + x + "px, " + y + "px)"

                        target.dataset.x = x
                        target.dataset.y = y

                        widgetSettings.x = x
                        widgetSettings.y = y

                        saveSettings()
                    },
                },
            })

            return {
                root,
                setTargetWPM: (wpm) => {
                    targetWPM = wpm
                    if (targetWPMNode) {
                        targetWPMNode.textContent = Number.isFinite(Number(wpm)) ? String(Number(wpm)) : String(wpm)
                    }
                    const baseSkipLength = skipLength !== null ? skipLength : bestSkipLength
                    if (lessonLength !== null && baseSkipLength !== null && Number(targetWPM) > 0) {
                        const newTime = ((lessonLength - baseSkipLength) / 5 / targetWPM) * 60
                        if (Number.isFinite(newTime)) {
                            if (onTargetTimeUpdate) {
                                onTargetTimeUpdate(newTime * 1e3)
                            }
                            targetTimeNode.textContent = newTime.toFixed(2)
                        }
                    }
                },
                setLessonLength: (l) => {
                    lessonLength = l
                },
                getLessonLength: () => lessonLength,
                setSkipLength: (l) => {
                    skipLength = l
                    toggleBestLiveWPM(false)
                    if (skipLength !== bestSkipLength) {
                        const newTime = ((lessonLength - skipLength) / 5 / targetWPM) * 60
                        if (onTargetTimeUpdate) {
                            onTargetTimeUpdate(newTime * 1e3)
                        }
                        targetTimeNode.textContent = newTime.toFixed(2)
                    }
                },
                setBestSkipLength: (l) => {
                    bestSkipLength = l
                    const newTime = ((lessonLength - bestSkipLength) / 5 / targetWPM) * 60
                    if (onTargetTimeUpdate) {
                        onTargetTimeUpdate(newTime * 1e3)
                    }
                    targetTimeNode.textContent = newTime.toFixed(2)
                },
                start: (t) => {
                    if (timer) {
                        clearTimeout(timer)
                    }
                    finishTime = null
                    const normalizedStartTime = Number(t)
                    startTime = Number.isFinite(normalizedStartTime)
                        ? Math.min(normalizedStartTime, Date.now())
                        : Date.now()
                    refreshCurrentTime()
                },
                stop: () => {
                    if (timer) {
                        finishTime = Date.now()
                        clearTimeout(timer)
                    }
                },
                setCurrentAvgSpeed: (wpm) => {
                    currentAvgWPMNode.textContent = wpm.toFixed(2)
                },
                reportFinishResults: (speed, avgSpeed, actualStartTime, actualFinishTime) => {
                    const latency = actualFinishTime - finishTime,
                        output = (latency / 1e3).toFixed(2)

                    resultTimeNode.textContent = ((actualFinishTime - actualStartTime) / 1e3).toFixed(2)
                    resultWPMNode.textContent = speed.toFixed(2)
                    liveWPMValueNode.textContent = speed.toFixed(2)
                    resultNewAvgWPMNode.textContent = avgSpeed.toFixed(2)
                    resultLatencyNode.textContent = latency
                    toggleBestLiveWPM(false)

                    root.append(resultContainerNode)

                    logging.info("Finish")(`Race Finish acknowledgement latency: ${output} secs (${latency}ms)`)
                    return output
                },
                setOnTargetTimeUpdate: (c) => {
                    onTargetTimeUpdate = c
                },
                setOnTimeUpdate: (c) => {
                    onTimeUpdate = c
                },
            }
        })(config)

        window.NTRaceTimer = RaceTimer

        let currentRaceStatus = null
        const isAltWpmCounterEnabledLive = () => isLiveRaceOptionEnabled("ENABLE_ALT_WPM_COUNTER", true)
        const isAltWpmCountdownEnabledLive = () => isLiveRaceOptionEnabled("ENABLE_ALT_WPM_COUNTDOWN", true)
        const resetRaceTimerLiveDisplay = () => {
            const liveWpmNode = RaceTimer?.root?.querySelector(".nt-evil-sandbagging-live-wpm")
            const suffixNode = RaceTimer?.root?.querySelector(".nt-evil-sandbagging-current-live-wpm .nt-evil-sandbagging-metric-suffix")
            if (!liveWpmNode || !suffixNode) {
                return
            }
            suffixNode.style.display = ""
            suffixNode.textContent = "Prepare for your race!"
            liveWpmNode.textContent = ""
        }
        const syncRaceTimerVisibility = () => {
            if (!RaceTimer?.root?.isConnected) {
                return
            }
            const shouldHideUntilCountdown = isLiveRaceOptionEnabled("HIDE_PREPARE_FOR_RACE_ICON", false)
            const altWpmEnabled = isAltWpmCounterEnabledLive()
            const countdownEnabled = isAltWpmCountdownEnabledLive()
            const showIdle = !shouldHideUntilCountdown && (altWpmEnabled || countdownEnabled) && currentRaceStatus !== "countdown" && currentRaceStatus !== "racing"
            const showCountdown = countdownEnabled && currentRaceStatus === "countdown"
            const showAltWpm = altWpmEnabled && currentRaceStatus === "racing"
            const shouldShowNow = showIdle || showCountdown || showAltWpm
            RaceTimer.root.style.display = shouldShowNow ? "" : "none"
        }

        const syncRaceTimerMount = () => {
            if (!isAltWpmCounterEnabledLive() && !isAltWpmCountdownEnabledLive()) {
                stopRaceStartCountdown()
                RaceTimer.root.remove()
                return
            }
            if (!isAltWpmCountdownEnabledLive()) {
                stopRaceStartCountdown()
            }
            if (!RaceTimer.root.isConnected) {
                raceContainer.append(RaceTimer.root)
            }
            syncRaceTimerVisibility()
        }

        /** Track Racing League for analysis. */
        server.on("setup", (e) => {
            if (e.scores && e.scores.length === 2) {
                const [from, to] = e.scores
                logging.info("Init")("Racing League", JSON.stringify({ from, to, trackLeader: e.trackLeader }))
                RaceTimer.setCurrentAvgSpeed(getPlayerAvg("Init", raceObj))
            }
        })
        let countdownTimer = null
        let countdownTargetStamp = null
        const stopRaceStartCountdown = () => {
            if (countdownTimer !== null) {
                clearTimeout(countdownTimer)
                countdownTimer = null
            }
            countdownTargetStamp = null
        }
        const updateRaceStartCountdown = () => {
            const wpmtextnode = RaceTimer.root.querySelector(".nt-evil-sandbagging-live-wpm")
            if (!wpmtextnode || !Number.isFinite(countdownTargetStamp)) {
                stopRaceStartCountdown()
                return
            }
            const remainingMs = Math.max(0, countdownTargetStamp - Date.now())
            wpmtextnode.textContent = (remainingMs / 1e3).toFixed(2)
            if (remainingMs <= 0) {
                countdownTimer = null
                return
            }
            countdownTimer = setTimeout(updateRaceStartCountdown, COUNTDOWN_TICK_INTERVAL_MS)
        }
        /** Track whether to start the timer and manage target goals. */
        server.on("status", (e) => {
            currentRaceStatus = e.status
            syncRaceTimerVisibility()
            if (e.status === "countdown") {
                resetPerfectNitroUsageState()
                startPerfectNitroHighlighter(e.lesson)
                resetRaceTimerLiveDisplay()

                const countdownEnabled = isAltWpmCountdownEnabledLive()
                const wpmtextnode = RaceTimer.root.querySelector(".nt-evil-sandbagging-live-wpm");
                const wpmsuffix = RaceTimer.root.querySelector(".nt-evil-sandbagging-current-live-wpm .nt-evil-sandbagging-metric-suffix");
                if (countdownEnabled && wpmtextnode && wpmsuffix) {
                    const nextCountdownTargetStamp = Number.isFinite(Number(e.startStamp))
                        ? Number(e.startStamp) - config.raceLatencyMS
                        : Date.now() + 4e3
                    wpmsuffix.textContent = "Race starts in... ";
                    const shouldRestartCountdown = countdownTimer === null || countdownTargetStamp !== nextCountdownTargetStamp
                    countdownTargetStamp = nextCountdownTargetStamp
                    if (shouldRestartCountdown) {
                        stopRaceStartCountdown()
                        countdownTargetStamp = nextCountdownTargetStamp
                        updateRaceStartCountdown()
                    }
                } else {
                    stopRaceStartCountdown()
                }

                RaceTimer.setLessonLength(e.lessonLength)

                const words = e.lesson.split(" ")

                let mostLetters = null,
                    nitroWordCount = 0
                words.forEach((_, i) => {
                    let wordLength = nitroWordLength(words, i)
                    if (mostLetters === null || mostLetters < wordLength) {
                        mostLetters = wordLength
                    }
                })
                RaceTimer.setBestSkipLength(mostLetters)
            } else if (e.status === "racing") {
                startPerfectNitroHighlighter()

                stopRaceStartCountdown()
                if (!isAltWpmCounterEnabledLive()) {
                    syncRaceTimerVisibility()
                    return
                }
                const wpmsuffix = RaceTimer.root.querySelector(".nt-evil-sandbagging-current-live-wpm .nt-evil-sandbagging-metric-suffix");
                wpmsuffix.textContent = "Possible WPM: ";
                RaceTimer.start(e.startStamp - config.raceLatencyMS)

                const originalSendPlayerUpdate = server.sendPlayerUpdate
                server.sendPlayerUpdate = (data) => {
                    originalSendPlayerUpdate(data)
                    if (data.t >= RaceTimer.getLessonLength()) {
                        RaceTimer.stop()
                    }
                    if (typeof data.s === "number") {
                        if (data.s > 0) {
                            consumePerfectNitroHighlights()
                        }
                        RaceTimer.setSkipLength(data.s)
                    }
                }
            }
        })

        /** Track Race Finish exact time. */
        server.on("update", (e) => {
            const me = e?.racers?.find((r) => r.userID === currentUserID)
            if (me?.progress?.skipped > 0) {
                consumePerfectNitroHighlights()
            }
            if (raceTimeLatency === null && me.progress.completeStamp > 0 && me.rewards) {
                const { typed, skipped, startStamp, completeStamp } = me.progress

                raceTimeLatency = RaceTimer.reportFinishResults(
                    (typed - skipped) / 5 / ((completeStamp - startStamp) / 6e4),
                    getPlayerAvg("Finish", raceObj, me.rewards.current.lastRaces),
                    startStamp,
                    completeStamp
                )
            }
        })

        /////////////
        //  Final  //
        /////////////
        const syncRaceOptionsRuntimeSetting = (event) => {
            const settingKey = event?.detail?.key
            if (!settingKey) {
                return
            }
            if (settingKey === "enableStats") {
                syncStatsPanelMount()
                return
            }
            if (["hideTrack", "hideNotifications", "HIDE_CHAT_AND_STICKERS", "HIDE_FINISH_FLAG"].includes(settingKey)) {
                applyRaceVisualStyles()
            }
            if (["ENABLE_MINI_MAP", "MINI_MAP_POSITION"].includes(settingKey)) {
                syncMiniMapMount()
            }
            if (["ENABLE_ALT_WPM_COUNTER", "ENABLE_ALT_WPM_COUNTDOWN", "HIDE_PREPARE_FOR_RACE_ICON"].includes(settingKey)) {
                syncRaceTimerMount()
            }
            if (["targetWPM", "indicateWPMWithin", "timerRefreshIntervalMS", "dif"].includes(settingKey)) {
                config[settingKey] = getLiveRaceOptionNumber(settingKey, config[settingKey])
                if (settingKey === "targetWPM") {
                    RaceTimer.setTargetWPM(config.targetWPM)
                }
            }
            if (["RACES_OUTSIDE_CURRENT_TEAM", "TEAM_RACES_BUGGED"].includes(settingKey)) {
                StatWidget.refreshTeamRaceCorrections()
            }
        }

        window.addEventListener(NTCFG_RACE_OPTIONS_SETTING_SYNC_EVENT, syncRaceOptionsRuntimeSetting)

        syncRaceTimerMount()
    } // end _initContinue
} // end race-only runtime