Nitro Type - Race Options

Auto Refresh, Themes, Stats Overlay and more!

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==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