JanitorAI Character Card Scraper

Extract character card with "T" key (WHILE IN CHAT PAGE) and save as .txt, .png, or .json (proxy required)

// ==UserScript==
// @name         JanitorAI Character Card Scraper
// @version      3.0
// @description  Extract character card with "T" key (WHILE IN CHAT PAGE) and save as .txt, .png, or .json (proxy required)
// @match        https://janitorai.com/*
// @icon         https://images.dwncdn.net/images/t_app-icon-l/p/46413ec0-e1d8-4eab-a0bc-67eadabb2604/3920235030/janitor-ai-logo
// @grant        none
// @namespace    https://sleazyfork.org/en/scripts/537206-janitorai-character-card-scraper
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(() => {
    "use strict";

    /* ============================
       ==      VARIABLES        ==
       ============================ */
    let hasInitialized = false;
    let viewActive = false;
    let shouldInterceptNext = false;
    let networkInterceptActive = false;
    let exportFormat = null;
    let chatData = null;
    let currentTab = sessionStorage.getItem("lastActiveTab") || "export";
    let useChatNameForName =
        localStorage.getItem("useChatNameForName") === "true" || false;
    let applyCharToken = localStorage.getItem("applyCharToken") !== "false";
    let filenameTemplate =
        localStorage.getItem("filenameTemplateDraft") ||
        localStorage.getItem("filenameTemplate") ||
        "{name}";
    // Migration: Update old default for existing users
    const storedSavePath = localStorage.getItem("savePathTemplate");
    if (storedSavePath === "images/{creator}") {
        localStorage.setItem("savePathTemplate", "cards/{creator}");
    }

    // Simple boolean: false = show prefill, true = user has applied changes
    // Default to false for fresh installs, only true if user explicitly applied changes
    let userChangedSavePath =
        localStorage.getItem("userChangedSavePath") === "true";

    let savePathTemplate = userChangedSavePath ?
        localStorage.getItem("savePathTemplate") || "" :
        "cards/{creator}";
    let animationTimeouts = [];
    let currentActiveTab = "export"; // Track current tab state
    let restorationInProgress = false; // Prevent multiple simultaneous restorations
    let guiElement = null;
    sessionStorage.removeItem("char_export_scroll");
    sessionStorage.removeItem("char_settings_scroll");
    const ANIMATION_DURATION = 150; // Animation duration for modal open/close in ms
    const TAB_ANIMATION_DURATION = 300; // Animation duration for tab switching in ms
    const TAB_BUTTON_DURATION = 250; // Animation duration for tab button effects
    const BUTTON_ANIMATION = 200; // Animation duration for format buttons
    const TOGGLE_ANIMATION = 350; // Animation duration for toggle switch
    const ACTIVE_TAB_COLOR = "#0080ff"; // Color for active tab indicator
    const INACTIVE_TAB_COLOR = "transparent"; // Color for inactive tab indicator
    const BUTTON_COLOR = "#3a3a3a"; // Base color for buttons
    const BUTTON_HOVER_COLOR = "#4a4a4a"; // Hover color for buttons
    const BUTTON_ACTIVE_COLOR = "#0070dd"; // Active color for buttons when clicked
    const TOOLTIP_SLIDE_FROM_RIGHT = true; // true = slide towards right (default). Set false for slide-left variant.
    const TOOLTIP_SLIDE_OFFSET = 10; // px the tooltip travels during slide animation

    const blankMeta = {
        creatorUrl: "",
        characterVersion: "",
        characterCardUrl: "",
        name: "",
        creatorNotes: "",
        personality: "",
        scenario: "",
        firstMessage: "",
        exampleDialogs: "",
        definitionExposed: false,
    };

    const characterMetaCache = {
        id: null,
        useChatNameForName: false,
        ...blankMeta,
    };

    interceptNetwork();

    /* ============================
       ==      UTILITIES        ==
       ============================ */
    function makeElement(tag, attrs = {}, styles = {}) {
        const el = document.createElement(tag);
        Object.entries(attrs).forEach(([key, value]) => (el[key] = value));

        if (styles) {
            Object.entries(styles).forEach(([key, value]) => (el.style[key] = value));
        }
        return el;
    }

    /**
     * Extract creator profile URL from fetched character page document.
     * Looks for the profile anchor used across pages.
     * @param {Document} doc – HTML document parsed from character page.
     * @returns {string} Absolute URL or empty string.
     */
    function getCreatorUrlFromDoc(doc) {
        const link = doc.querySelector("a.chakra-link.css-15sl5jl");
        if (link) {
            const href = link.getAttribute("href");
            if (href) return `https://janitorai.com${href}`;
        }
        return "";
    }

    async function saveFile(filename, blob) {
        const useFileSystemAPI =
            localStorage.getItem("useFileSystemAccess") === "true";

        if (useFileSystemAPI && "showDirectoryPicker" in window) {
            try {
                // Get the selected directory handle from global storage
                const directoryHandle = window.selectedDirectoryHandle;

                if (directoryHandle) {
                    // Get save path template - use empty string if user changed it and set to empty
                    const userChangedSavePath =
                        localStorage.getItem("userChangedSavePath") === "true";
                    const savePathTemplate = userChangedSavePath ?
                        localStorage.getItem("savePathTemplate") || "" :
                        "cards/{creator}";

                    // Simple path building - replace tokens using same data as filename system
                    let savePath = savePathTemplate;

                    console.log("[DEBUG] Original save path template:", savePathTemplate);
                    console.log("[DEBUG] Available chatData:", chatData);

                    // Get character metadata for token replacement
                    const meta = await getCharacterMeta();
                    const tokens = await getFilenameTokens(meta);

                    console.log("[DEBUG] Available tokens:", tokens);

                    // Replace tokens using the same system as filename templates
                    Object.entries(tokens).forEach(([tokenKey, tokenValue]) => {
                        if (tokenValue && String(tokenValue).trim() !== "") {
                            const regex = new RegExp(`\\{${escapeRegExp(tokenKey)}\\}`, "g");
                            const oldSavePath = savePath;
                            savePath = savePath.replace(regex, String(tokenValue));
                            if (oldSavePath !== savePath) {
                                console.log(`[DEBUG] Replaced {${tokenKey}} with:`, tokenValue);
                            }
                        }
                    });

                    console.log("[DEBUG] Final save path:", savePath);

                    // Clean up the path and split into segments
                    savePath = savePath.replace(/^\/+|\/+$/g, ""); // Remove leading/trailing slashes
                    const pathSegments = savePath ?
                        savePath.split("/").filter((segment) => segment.length > 0) : [];

                    // Navigate/create directory structure
                    let currentDir = directoryHandle;
                    for (const segment of pathSegments) {
                        try {
                            currentDir = await currentDir.getDirectoryHandle(segment, {
                                create: true,
                            });
                        } catch (error) {
                            console.error(
                                `Failed to create/access directory ${segment}:`,
                                error,
                            );
                            // Fall back to regular download if directory creation fails
                            regularDownload(filename, blob);
                            return;
                        }
                    }

                    // Create unique filename if file already exists
                    let finalFilename = filename;
                    let counter = 1;
                    let fileHandle;

                    while (true) {
                        try {
                            // Try to get existing file
                            await currentDir.getFileHandle(finalFilename);
                            // File exists, increment counter and try again
                            const lastDot = filename.lastIndexOf(".");
                            if (lastDot === -1) {
                                finalFilename = `${filename} (${counter})`;
                            } else {
                                const nameWithoutExt = filename.substring(0, lastDot);
                                const extension = filename.substring(lastDot);
                                finalFilename = `${nameWithoutExt} (${counter})${extension}`;
                            }
                            counter++;
                        } catch (error) {
                            // File doesn't exist, we can use this filename
                            break;
                        }
                    }

                    // Create and write the file with unique name
                    fileHandle = await currentDir.getFileHandle(finalFilename, {
                        create: true,
                    });
                    const writable = await fileHandle.createWritable();
                    await writable.write(blob);
                    await writable.close();

                    // Visual feedback for successful save
                    const successMessage = `Saved to: ${pathSegments.length > 0 ? pathSegments.join("/") + "/" : ""}${finalFilename}`;
                    console.log(successMessage);

                    // Show temporary success notification
                    const notification = document.createElement("div");
                    notification.style.cssText = `
              position: fixed;
              top: 20px;
              right: 20px;
              background: #4CAF50;
              color: white;
              padding: 12px 20px;
              border-radius: 6px;
              z-index: 10001;
              box-shadow: 0 4px 12px rgba(0,0,0,0.3);
              font-size: 14px;
              font-weight: bold;
              opacity: 0;
              transform: translateX(100%);
              transition: all 300ms ease;
            `;
                    notification.textContent = `✓ ${successMessage}`;
                    document.body.appendChild(notification);

                    requestAnimationFrame(() => {
                        notification.style.opacity = "1";
                        notification.style.transform = "translateX(0)";
                    });

                    setTimeout(() => {
                        notification.style.opacity = "0";
                        notification.style.transform = "translateX(100%)";
                        setTimeout(() => notification.remove(), 300);
                    }, 3000);

                    return;
                }
            } catch (error) {
                console.error("FileSystemAccess API failed:", error);
                // Show error notification
                const errorNotification = document.createElement("div");
                errorNotification.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: #f44336;
            color: white;
            padding: 12px 20px;
            border-radius: 6px;
            z-index: 10001;
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
            font-size: 14px;
            font-weight: bold;
            opacity: 0;
            transform: translateX(100%);
            transition: all 300ms ease;
          `;
                errorNotification.textContent = `⚠ FileSystem save failed, using download instead`;
                document.body.appendChild(errorNotification);

                requestAnimationFrame(() => {
                    errorNotification.style.opacity = "1";
                    errorNotification.style.transform = "translateX(0)";
                });

                setTimeout(() => {
                    errorNotification.style.opacity = "0";
                    errorNotification.style.transform = "translateX(100%)";
                    setTimeout(() => errorNotification.remove(), 300);
                }, 3000);
                // Fall back to regular download
            }
        }

        // Regular download fallback
        regularDownload(filename, blob);
    }

    function regularDownload(filename, blob) {
        const url = URL.createObjectURL(blob);
        const a = makeElement("a", {
            href: url,
            download: filename,
        });
        a.addEventListener("click", (e) => {
            e.stopPropagation();
        });
        document.body.appendChild(a);
        a.click();
        a.remove();
        URL.revokeObjectURL(url);
    }

    function getCharacterCardUrl(id) {
        return `https://janitorai.com/characters/${id}`;
    }

    function escapeRegExp(s) {
        return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
    }

    function extractTagContent(sys, charName) {
        if (!charName || !sys) return "";
        const variants = [];
        const trimmed = charName.trim();
        variants.push(trimmed);
        const collapsed = trimmed.replace(/\s+/g, " ");
        if (collapsed !== trimmed) variants.push(collapsed);
        if (trimmed.includes(" ")) variants.push(trimmed.replace(/\s+/g, "_"));

        for (const name of variants) {
            const escName = escapeRegExp(name);
            const regex = new RegExp(
                `<${escName}(?:\\s[^>]*)?\\s*>([\\s\\S]*?)<\\/${escName}\\s*>`,
                "i",
            );
            const m = sys.match(regex);
            if (m && m[1] != null) {
                return m[1].trim();
            }
            const openTagRx = new RegExp(`<${escName}(?:\\s[^>]*)?\\s*>`, "i");
            const closeTagRx = new RegExp(`<\\/${escName}\\s*>`, "i");
            const openMatch = openTagRx.exec(sys);
            const closeMatch = closeTagRx.exec(sys);
            if (openMatch && closeMatch && closeMatch.index > openMatch.index) {
                const start = openMatch.index + openMatch[0].length;
                const end = closeMatch.index;
                return sys.substring(start, end).trim();
            }
            try {
                const parser = new DOMParser();
                const doc = parser.parseFromString(
                    `<root>${sys}</root>`,
                    "application/xml",
                );
                const elems = doc.getElementsByTagName(name);
                if (elems.length) {
                    return elems[0].textContent.trim();
                }
            } catch (_) {}
        }
        return "";
    }

    function stripWatermark(text) {
        if (!text) return "";
        const lines = text.split(/\r?\n/);
        const filtered = lines.filter((l) => {
            const t = l.trim();
            return !(/^created/i.test(t) && /janitorai\.com"?$/i.test(t));
        });
        return filtered.join("\n").trim();
    }

    // === Early Chat Data Prefetch ===
    function findChatId() {
        // Try URL first
        const direct = window.location.href.match(/\/chats\/(\d+)/);
        if (direct) return direct[1];
        // Fallback: parse window._storeState_ script tag
        const scripts = document.querySelectorAll("script");
        for (const s of scripts) {
            const txt = s.textContent;
            if (!txt || !txt.includes("window._storeState_")) continue;
            const m = txt.match(/JSON\.parse\("([\s\S]*?)"\)/);
            if (m && m[1]) {
                try {
                    const decoded = JSON.parse(`"${m[1]}"`); // unescape
                    const obj = JSON.parse(decoded);
                    let cid = null;
                    const walk = (o) => {
                        if (!o || typeof o !== "object" || cid) return;
                        if (
                            Object.prototype.hasOwnProperty.call(o, "chatId") &&
                            typeof o.chatId === "number"
                        ) {
                            cid = o.chatId;
                            return;
                        }
                        for (const k in o) walk(o[k]);
                    };
                    walk(obj);
                    if (cid) return cid;
                } catch (_) {}
            }
        }
        return null;
    }

    function getAuthHeader() {
        // Look for any sb-auth-auth-token.* cookie variants
        const matches = document.cookie.match(/sb-auth-auth-token\.[^=]+=([^;]+)/g);
        if (matches && matches.length) {
            for (const seg of matches) {
                const rawVal = seg.substring(seg.indexOf("=") + 1);
                const hdr = extractBearer(rawVal);
                if (hdr) return hdr;
            }
        }
        return null;

        function extractBearer(val) {
            let raw = decodeURIComponent(val);
            if (raw.startsWith("base64-")) raw = raw.slice(7);
            // Raw JWT
            if (/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/.test(raw)) {
                console.log("[getAuthHeader] using raw JWT");
                return `Bearer ${raw}`;
            }
            // Try base64 JSON with access_token field
            try {
                const json = JSON.parse(atob(raw));
                if (json && json.access_token) {
                    console.log("[getAuthHeader] using access_token from JSON");
                    return `Bearer ${json.access_token}`;
                }
            } catch (err) {
                /* ignore */
            }
            return null;
        }
        // Extract Bearer token from sb-auth-auth-token cookie (value is URL-encoded base64-JSON)
        const m = document.cookie.match(/sb-auth-auth-token\.\d+=([^;]+)/);
        if (!m) return null;
        let raw = decodeURIComponent(m[1]);
        if (raw.startsWith("base64-")) raw = raw.slice(7);
        try {
            const json = JSON.parse(atob(raw));
            if (json.access_token) return `Bearer ${json.access_token}`;
        } catch (err) {
            // Fallback: some builds store the token directly, detect JWT shape (three dot-separated parts)
            if (/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/.test(raw)) {
                return `Bearer ${raw}`;
            }
        }
        return null;
    }

    function getAppVersion() {
        // Extract version from any script src query param like '?v=2025-06-24.<hash>'
        const scr = [...document.querySelectorAll("script[src]")].find((s) =>
            /\bv=([\w.-]+)/.test(s.src),
        );
        if (scr) {
            const m = scr.src.match(/\bv=([\w.-]+)/);
            if (m) return m[1];
        }
        // Fallback to hard-coded value seen in Headers (may need update if site version changes)
        return "2025-06-24.81a918c33";
    }

    async function prefetchChatData() {
        if (chatData) return;
        const chatId = findChatId();
        if (!chatId) return;
        const endpoint = `https://janitorai.com/hampter/chats/${chatId}`;
        const appVer = getAppVersion();
        const auth = getAuthHeader();
        console.log("[prefetchChatData] auth:", auth);
        const baseHeaders = {
            "x-app-version": appVer,
            accept: "application/json, text/plain, */*",
        };
        if (auth) baseHeaders["Authorization"] = auth;
        console.log("[prefetchChatData] request headers", baseHeaders);
        // First try with cookies + headers
        try {
            let res = await fetch(endpoint, {
                method: "GET",
                credentials: "include",
                headers: baseHeaders,
            });
            if (res.status === 401) {
                // Retry with Authorization header if available
                const auth = getAuthHeader();
                if (auth) {
                    res = await fetch(endpoint, {
                        method: "GET",
                        credentials: "include",
                        headers: {
                            ...baseHeaders,
                            Authorization: auth,
                        },
                    });
                }
            }
            if (res.ok) {
                const json = await res.json();
                if (json && json.character) {
                    chatData = json;
                    console.log("[prefetchChatData] chatData pre-fetched");
                }
            }
        } catch (err) {
            console.warn("[prefetchChatData] failed:", err);
        }
    }

    function tokenizeNames(text, charName, userName) {
        if (!text) return text;
        const parts = text.split("\n\n");
        const [cRx, uRx] = [charName, userName].map((n) =>
            n ? escapeRegExp(n) : "",
        );

        for (let i = 0, l = parts.length; i < l; ++i) {
            if (
                !/^==== (Name|Chat Name|Initial Message|Character Card|Creator) ====/.test(
                    parts[i],
                )
            ) {
                if (applyCharToken) {
                    if (cRx)
                        parts[i] = parts[i].replace(
                            new RegExp(`(?<!\\w)${cRx}(?!\\w)`, "g"),
                            "{{char}}",
                        );
                    if (uRx)
                        parts[i] = parts[i].replace(
                            new RegExp(`(?<!\\w)${uRx}(?!\\w)`, "g"),
                            "{{user}}",
                        );
                } else if (charName) {
                    parts[i] = parts[i].replace(/\{\{char\}\}/gi, charName);
                }
            }
        }
        return parts.join("\n\n");
    }

    function tokenizeField(text, charName, userName) {
        if (!text) return text;
        const esc = (n) => escapeRegExp(n);
        const rules = [];
        if (applyCharToken && charName) {
            rules.push([
                new RegExp(`\\b${esc(charName)}('s)?\\b`, "gi"),
                (_, sfx) => `{{char}}${sfx || ""}`,
            ]);
        }
        if (userName) {
            rules.push([
                new RegExp(`\\b${esc(userName)}('s)?\\b`, "gi"),
                (_, sfx) => `{{user}}${sfx || ""}`,
            ]);
        }
        let out = rules.reduce((t, [rx, repl]) => t.replace(rx, repl), text);
        if (!applyCharToken && charName) {
            out = out.replace(/\{\{char\}\}/gi, charName);
        }
        return out;
    }

    /**
     * Adds a token value to the filename template input field
     * @param {string} token - Token to add (e.g., "id", "name", etc.)
     * @param {HTMLInputElement} inputField - The template input field
     */
    function addTokenToTemplate(token, inputField) {
        if (!inputField || !token) return;

        const currentValue = inputField.value || "";
        const cursorPos = inputField.selectionStart || currentValue.length;

        // Add space before token if there's content and no trailing space or slash
        const needsSpace =
            currentValue &&
            !currentValue.endsWith(" ") &&
            !currentValue.endsWith("/") &&
            cursorPos === currentValue.length;
        const tokenToAdd = needsSpace ? ` {${token}}` : `{${token}}`;

        const newValue =
            currentValue.slice(0, cursorPos) +
            tokenToAdd +
            currentValue.slice(cursorPos);
        inputField.value = newValue;

        // Update cursor position
        const newCursorPos = cursorPos + tokenToAdd.length;
        inputField.setSelectionRange(newCursorPos, newCursorPos);
        inputField.focus();

        // Trigger change event
        inputField.dispatchEvent(new Event("input", {
            bubbles: true
        }));
    }

    /**
     * Creates a token button for the filename template UI
     * @param {string} token - Token name
     * @param {string} label - Display label for the button
     * @param {HTMLInputElement} inputField - Template input field
     * @returns {HTMLElement} - Button element
     */
    function createTokenButton(token, label, inputElement, isSavePath = false) {
        const button = makeElement(
            "button", {
                textContent: label,
                type: "button",
            }, {
                background: "#3a3a3a",
                border: "1px solid #555",
                color: "#fff",
                padding: "4px 8px",
                borderRadius: "4px",
                cursor: "pointer",
                fontSize: "11px",
                transition: "all 150ms ease",
                margin: "2px",
            },
        );

        button.addEventListener("mouseover", () => {
            button.style.background = "#4a4a4a";
            button.style.borderColor = "#666";
        });

        button.addEventListener("mouseout", () => {
            button.style.background = "#3a3a3a";
            button.style.borderColor = "#555";
        });

        button.addEventListener("mousedown", (e) => {
            // Only trigger on left mouse button
            if (e.button !== 0) return;

            e.preventDefault();
            addTokenToTemplate(token, inputElement);

            // Green flash and pulse animation for left click
            button.style.background = "#4CAF50";
            button.style.borderColor = "#66BB6A";
            button.style.transform = "scale(1.1)";
            button.style.boxShadow = "0 0 10px rgba(76, 175, 80, 0.6)";

            setTimeout(() => {
                button.style.background = "#3a3a3a";
                button.style.borderColor = "#555";
                button.style.transform = "scale(1)";
                button.style.boxShadow = "none";
            }, 100);
        });

        // Right mousedown for immediate removal
        button.addEventListener("mousedown", (e) => {
            // Only trigger on right mouse button
            if (e.button !== 2) return;

            e.preventDefault();
            e.stopPropagation();

            const currentValue = inputElement.value;
            const tokenPattern = `{${token}}`;

            if (currentValue.includes(tokenPattern)) {
                // Find the first occurrence and remove only one instance with intelligent spacing
                let newValue = currentValue;
                const tokenRegex = new RegExp(`\\{${token}\\}`, "");

                // Check if token has a space before it
                const tokenWithSpaceRegex = new RegExp(` \\{${token}\\}`, "");

                if (tokenWithSpaceRegex.test(newValue)) {
                    // Remove token with preceding space
                    newValue = newValue.replace(tokenWithSpaceRegex, "");
                } else {
                    // Remove just the token
                    newValue = newValue.replace(tokenRegex, "");
                }

                // Clean up any double spaces that might result
                newValue = newValue.replace(/\s+/g, " ").trim();

                inputElement.value = newValue;

                // Trigger input event to update state
                if (isSavePath) {
                    savePathTemplate = newValue;
                } else {
                    filenameTemplate = newValue;
                    localStorage.setItem("filenameTemplateDraft", filenameTemplate);
                }

                inputElement.dispatchEvent(new Event("input", {
                    bubbles: true
                }));

                // Immediate red flash and pulse animation
                button.style.background = "#f44336";
                button.style.borderColor = "#ff6666";
                button.style.transform = "scale(1.1)";
                button.style.boxShadow = "0 0 10px rgba(244, 67, 54, 0.6)";

                setTimeout(() => {
                    button.style.background = "#3a3a3a";
                    button.style.borderColor = "#555";
                    button.style.transform = "scale(1)";
                    button.style.boxShadow = "none";
                }, 100);
            } else {
                // Budge animation when token not found
                button.style.transform = "translateX(-3px)";
                setTimeout(() => {
                    button.style.transform = "translateX(3px)";
                    setTimeout(() => {
                        button.style.transform = "translateX(0)";
                    }, 100);
                }, 100);
            }
        });

        // Prevent context menu from appearing
        button.addEventListener("contextmenu", (e) => {
            e.preventDefault();
            e.stopPropagation();
        });

        return button;
    }

    /**
     * Creates a standardized toggle component
     * @param {string} key - localStorage key
     * @param {string} label - Display label
     * @param {string} tooltip - Tooltip text
     * @param {boolean} defaultValue - Default checked state
     * @returns {Object} - Object containing container and input elements
     */
    function createToggle(key, label, tooltip, defaultValue = false) {
        const container = makeElement(
            "div", {}, {
                display: "flex",
                alignItems: "center",
                marginBottom: "8px",
                marginTop: "10px",
                padding: "15px",
                background: "#2a2a2a",
                borderRadius: "10px",
                gap: "12px",
                boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
                isolation: "isolate",
                contain: "layout style paint",
                border: "1px solid #444",
                background: "linear-gradient(135deg, #2a2a2a 0%, #2e2e2e 100%)",
                transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
                cursor: "pointer",
            },
        );

        const wrapper = makeElement(
            "div", {
                className: "toggle-wrapper",
            }, {
                display: "flex",
                alignItems: "center",
                justifyContent: "space-between",
                width: "100%",
                cursor: "pointer",
                position: "relative",
                isolation: "isolate",
                transition: "all 0.2s ease",
            },
        );

        const labelElement = makeElement(
            "span", {
                textContent: label,
            }, {
                fontSize: "13px",
                color: "#fff",
                order: "2",
                textAlign: "left",
                flex: "1",
                paddingLeft: "10px",
                wordBreak: "break-word",
                lineHeight: "1.4",
            },
        );

        const toggle = makeElement(
            "label", {
                className: "switch",
            }, {
                position: "relative",
                display: "inline-block",
                width: "40px",
                height: "24px",
                order: "1",
                margin: "0",
                flexShrink: "0",
                borderRadius: "24px",
                boxShadow: "0 1px 3px rgba(0,0,0,0.2) inset",
                transition: `all ${TOGGLE_ANIMATION}ms cubic-bezier(0.4, 0, 0.2, 1)`,
                cursor: "pointer",
            },
        );

        const slider = makeElement(
            "span", {
                className: "slider round",
            }, {
                position: "absolute",
                cursor: "pointer",
                top: "0",
                left: "0",
                right: "0",
                bottom: "0",
                backgroundColor: defaultValue ? ACTIVE_TAB_COLOR : "#ccc",
                transition: `all ${TOGGLE_ANIMATION}ms cubic-bezier(0.34, 1.56, 0.64, 1)`,
                borderRadius: "24px",
                overflow: "hidden",
                boxShadow: defaultValue ? "0 0 8px rgba(0, 128, 255, 0.3)" : "none",
            },
        );

        const sliderShine = makeElement(
            "div", {}, {
                position: "absolute",
                top: "0",
                left: "0",
                width: "100%",
                height: "100%",
                background: "linear-gradient(135deg, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0) 50%)",
                opacity: "0.5",
                transition: `opacity ${TOGGLE_ANIMATION}ms ease`,
            },
        );
        slider.appendChild(sliderShine);

        const sliderBefore = makeElement(
            "span", {
                className: "slider-before",
            }, {
                position: "absolute",
                content: '""',
                height: "16px",
                width: "16px",
                left: "4px",
                bottom: "4px",
                backgroundColor: "white",
                transition: `transform ${TOGGLE_ANIMATION}ms cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow ${TOGGLE_ANIMATION}ms ease`,
                borderRadius: "50%",
                transform: defaultValue ? "translateX(16px)" : "translateX(0)",
                boxShadow: defaultValue ?
                    "0 0 2px rgba(0,0,0,0.2), 0 0 5px rgba(0,128,255,0.3)" : "0 0 2px rgba(0,0,0,0.2)",
            },
        );

        const input = makeElement(
            "input", {
                type: "checkbox",
                checked: defaultValue,
            }, {
                opacity: "0",
                width: "0",
                height: "0",
                position: "absolute",
            },
        );

        input.addEventListener("change", (e) => {
            const isChecked = e.target.checked;
            localStorage.setItem(key, isChecked);

            // Enhanced animations
            slider.style.backgroundColor = isChecked ? ACTIVE_TAB_COLOR : "#ccc";
            slider.style.boxShadow = isChecked ?
                "0 0 8px rgba(0, 128, 255, 0.3)" :
                "none";
            sliderBefore.style.transform = isChecked ?
                "translateX(16px)" :
                "translateX(0)";
            sliderBefore.style.boxShadow = isChecked ?
                "0 0 2px rgba(0,0,0,0.2), 0 0 8px rgba(0,128,255,0.5)" :
                "0 0 2px rgba(0,0,0,0.2)";

            wrapper.classList.toggle("active", isChecked);

            // Enhanced container animation
            container.style.transform = "scale(1.02)";
            container.style.borderColor = isChecked ?
                "rgba(0, 128, 255, 0.4)" :
                "#444";
            container.style.boxShadow = isChecked ?
                "0 4px 12px rgba(0, 128, 255, 0.15)" :
                "0 2px 4px rgba(0,0,0,0.1)";

            setTimeout(() => {
                container.style.transform = "scale(1)";
            }, 150);
        });

        slider.appendChild(sliderBefore);
        toggle.appendChild(input);
        toggle.appendChild(slider);

        // Enhanced hover effects for container
        container.addEventListener("mouseenter", () => {
            if (!container.style.transform.includes("scale")) {
                container.style.transform = "translateY(-1px) scale(1.005)";
                container.style.boxShadow = "0 6px 16px rgba(0,0,0,0.15)";
            }
        });

        container.addEventListener("mouseleave", () => {
            if (!container.style.transform.includes("1.02")) {
                container.style.transform = "translateY(0) scale(1)";
                const isActive = input.checked;
                container.style.boxShadow = isActive ?
                    "0 4px 12px rgba(0, 128, 255, 0.15)" :
                    "0 2px 4px rgba(0,0,0,0.1)";
            }
        });

        wrapper.addEventListener("click", (e) => {
            e.preventDefault();
            input.checked = !input.checked;
            const event = new Event("change");
            input.dispatchEvent(event);
            document.body.focus();
        });

        wrapper.appendChild(labelElement);
        labelElement.setAttribute("data-tooltip", tooltip);
        wrapper.appendChild(toggle);
        container.appendChild(wrapper);

        return {
            container,
            input,
            wrapper
        };
    }

    /* ============================
       ==          UI           ==
       ============================ */
    function createUI() {
        if (guiElement && document.body.contains(guiElement)) {
            return;
        }

        animationTimeouts.forEach((timeoutId) => clearTimeout(timeoutId));
        animationTimeouts = [];

        viewActive = true;

        const gui = makeElement(
            "div", {
                id: "char-export-gui",
            }, {
                position: "fixed",
                top: "50%",
                left: "50%",
                transform: "translate(-50%, -50%) scale(0.95)",
                background: "#222",
                color: "white",
                padding: "15px 20px 7px",
                borderRadius: "8px",
                boxShadow: "0 0 20px rgba(0,0,0,0.5)",
                zIndex: "10000",
                textAlign: "center",
                width: "min(480px, 90vw)",
                minHeight: "400px",
                maxHeight: "85vh",
                overflow: "hidden",
                display: "flex",
                flexDirection: "column",
                boxSizing: "border-box",
                opacity: "0",
                transition: `opacity ${ANIMATION_DURATION}ms cubic-bezier(0.4, 0, 0.2, 1), transform ${ANIMATION_DURATION}ms cubic-bezier(0.4, 0, 0.2, 1)`,
            },
        );

        guiElement = gui;
        const unselectStyle = document.createElement("style");
        unselectStyle.textContent = `#char-export-gui, #char-export-gui * {
    user-select: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none;
  }
  #char-export-gui {
    backdrop-filter: blur(6px);
    background: rgba(34,34,34,0.92);
    border: none;
    border-radius: 8px;
  }
  #char-export-overlay {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    background: rgba(0,0,0,0.5); z-index: 9998;
  }
  #char-export-gui #char-export-tooltip {
    font-size: 12px; background: #222; color: #fff;
    padding: 6px 10px; border-radius: 4px; pointer-events: none;
  }
  #char-export-gui button {
    background: #333; color: #fff; border: none;
    border-radius: 4px; padding: 8px 12px;
    transition: background 200ms ease, transform 200ms ease;
  }
  #char-export-gui button:hover:not(:disabled) {
    background: #444; transform: translateY(-1px);
  }
  #char-export-gui button:disabled {
    opacity: 0.6; cursor: not-allowed;
  }
  #char-export-gui button:focus {
    outline: none;
  }

  /* Enhanced input field styling */
  #char-export-gui input[type="text"] {
    transition: border-color 300ms cubic-bezier(0.4, 0, 0.2, 1) !important;
    border-radius: 6px !important;
  }

  #char-export-gui input[type="text"]:not(.applying-changes):hover {
    border-color: #777 !important;
  }

  #char-export-gui input[type="text"]:not(.applying-changes):focus {
    border-color: #888 !important;
  }

  /* Ensure apply animation takes priority */
  #char-export-gui input.applying-changes {
    border-color: #4CAF50 !important;
  }

  /* Disable all browser tooltips */
  #char-export-gui input,
  #char-export-gui input:hover,
  #char-export-gui input:focus,
  #char-export-gui textarea,
  #char-export-gui textarea:hover,
  #char-export-gui textarea:focus {
    title: "" !important;
  }

  #char-export-gui input[title],
  #char-export-gui textarea[title] {
    title: "" !important;
  }

/* Enhanced toggle container styling */
.toggle-wrapper {
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
  border-radius: 8px !important;
}

.toggle-wrapper:hover {
  transform: translateY(-1px) scale(1.005) !important;
  box-shadow: 0 6px 16px rgba(0,0,0,0.15) !important;
  background: linear-gradient(135deg, rgba(128, 128, 128, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%) !important;
}

.toggle-wrapper.active {
  border-color: rgba(0, 128, 255, 0.4) !important;
  box-shadow: 0 4px 12px rgba(0, 128, 255, 0.15) !important;
}

  /* Token button styling */
  #char-export-gui button[type="button"] {
    transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1) !important;
  }

  #char-export-gui button[type="button"]:hover {
    transform: translateY(-2px) scale(1.05) !important;
    box-shadow: 0 4px 12px rgba(0,0,0,0.2) !important;
  }

  /* Directory button styling */
  .directory-button {
    transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1) !important;
  }

  .directory-button:hover {
    box-shadow: 0 0 8px rgba(74, 144, 226, 0.4) !important;
    background: #4a90e2 !important;
  }

  .directory-button:active {
    transform: scale(0.98) !important;
  }

  /* Custom overlay scrollbar - hide native scrollbar completely */
  #settings-tab {
    scrollbar-width: none; /* Firefox */
    -ms-overflow-style: none; /* IE/Edge */
    margin-right: -20px;
    padding-right: 20px;
  }

  #settings-tab::-webkit-scrollbar {
    display: none; /* Chrome/Safari */
  }

  /* Custom scrollbar overlay container */
  .custom-scrollbar-container {
    position: relative;
  }

  .custom-scrollbar-track {
    position: absolute;
    top: 0;
    right: -6px;
    width: 4px;
    height: 100%;
    background: rgba(68, 68, 68, 0.1);
    border-radius: 2px;
    opacity: 0.6;
    visibility: visible;
    transition: opacity 50ms ease, box-shadow 100ms ease;
    z-index: 1000;
    pointer-events: auto;
  }

  .custom-scrollbar-track.visible {
    opacity: 0.6;
    visibility: visible;
  }

  .custom-scrollbar-track:hover {
    opacity: 1;
    background: rgba(68, 68, 68, 0.2);
    box-shadow: 0 0 2px rgba(136, 136, 136, 0.2);
  }

  .custom-scrollbar-track.expanded {
    opacity: 1;
    background: rgba(68, 68, 68, 0.2);
    box-shadow: 0 0 4px rgba(136, 136, 136, 0.3);
  }

  .custom-scrollbar-thumb {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    background: rgba(136, 136, 136, 0.7);
    border-radius: 2px;
    border: none;
    transition: background 50ms ease;
    cursor: pointer;
    min-height: 20px;
  }

  .custom-scrollbar-thumb:hover {
    background: rgba(170, 170, 170, 0.8);
  }

  .custom-scrollbar-thumb:active,
  .custom-scrollbar-thumb.dragging {
    background: rgba(200, 200, 200, 0.9);
  }
  }`;
        document.head.appendChild(unselectStyle);

        const tabContainer = makeElement(
            "div", {}, {
                display: "flex",
                justifyContent: "center",
                marginBottom: "20px",
                borderBottom: "1px solid #444",
                paddingBottom: "12px",
                width: "100%",
            },
        );

        const tabsWrapper = makeElement(
            "div", {}, {
                display: "flex",
                justifyContent: "center",
                width: "100%",
                maxWidth: "min(400px, 100%)",
                margin: "0 auto",
            },
        );

        const createTabButton = (text, isActive) => {
            const button = makeElement(
                "button", {
                    textContent: text,
                }, {
                    background: "transparent",
                    border: "none",
                    color: "#fff",
                    padding: "8px 20px",
                    cursor: "pointer",
                    margin: "0 5px",
                    fontWeight: "bold",
                    flex: "1",
                    textAlign: "center",
                    position: "relative",
                    overflow: "hidden",
                    transition: `opacity ${TAB_BUTTON_DURATION}ms ease, transform ${TAB_BUTTON_DURATION}ms ease, color ${TAB_BUTTON_DURATION}ms ease`,
                },
            );

            const indicator = makeElement(
                "div", {}, {
                    position: "absolute",
                    bottom: "0",
                    left: "0",
                    width: "100%",
                    height: "2px",
                    background: isActive ? ACTIVE_TAB_COLOR : INACTIVE_TAB_COLOR,
                    transition: `transform ${TAB_BUTTON_DURATION}ms ease, background-color ${TAB_BUTTON_DURATION}ms ease`,
                },
            );

            if (!isActive) {
                button.style.opacity = "0.7";
                indicator.style.transform = "scaleX(0.5)";
            }

            button.appendChild(indicator);
            return {
                button,
                indicator,
            };
        };

        const {
            button: exportTab,
            indicator: exportIndicator
        } = createTabButton(
            "Export",
            true,
        );
        const {
            button: settingsTab,
            indicator: settingsIndicator
        } =
        createTabButton("Settings", false);

        exportTab.onmouseover = () => {
            if (currentTab !== "export") {
                exportTab.style.opacity = "1";
                exportTab.style.transform = "translateY(-2px)";
                exportIndicator.style.transform = "scaleX(0.8)";
            }
        };
        exportTab.onmouseout = () => {
            if (currentTab !== "export") {
                exportTab.style.opacity = "0.7";
                exportTab.style.transform = "";
                exportIndicator.style.transform = "scaleX(0.5)";
            }
        };

        settingsTab.onmouseover = () => {
            if (currentTab !== "settings") {
                settingsTab.style.opacity = "1";
                settingsTab.style.transform = "translateY(-2px)";
                settingsIndicator.style.transform = "scaleX(0.8)";
            }
        };
        settingsTab.onmouseout = () => {
            if (currentTab !== "settings") {
                settingsTab.style.opacity = "0.7";
                settingsTab.style.transform = "";
                settingsIndicator.style.transform = "scaleX(0.5)";
            }
        };

        tabsWrapper.appendChild(exportTab);
        tabsWrapper.appendChild(settingsTab);
        tabContainer.appendChild(tabsWrapper);
        gui.appendChild(tabContainer);
        /* ========= Dynamic Tooltip ========= */
        (() => {
            let tEl;
            const show = (target) => {
                const msg = target.getAttribute("data-tooltip");
                if (!msg) return;
                if (!tEl) {
                    tEl = document.createElement("div");
                    tEl.id = "char-export-tooltip";
                    tEl.id = "char-export-tooltip";
                    tEl.style.cssText =
                        "position:fixed;padding:6px 10px;font-size:12px;background:#222;color:#fff;border-radius:4px;white-space:nowrap;pointer-events:none;box-shadow:0 4px 12px rgba(0,0,0,0.4);opacity:0;transition:opacity 200ms ease,transform 200ms ease;z-index:10002;";
                    const offset = TOOLTIP_SLIDE_FROM_RIGHT ?
                        -TOOLTIP_SLIDE_OFFSET :
                        TOOLTIP_SLIDE_OFFSET;
                    tEl.style.transform = `translateX(${offset}px)`;
                    document.body.appendChild(tEl);
                }
                tEl.textContent = msg;
                const guiRect = gui.getBoundingClientRect();
                const tgtRect = target.getBoundingClientRect();
                tEl.style.top =
                    tgtRect.top + tgtRect.height / 2 - tEl.offsetHeight / 2 + "px";
                tEl.style.left = guiRect.right + 10 + "px";
                requestAnimationFrame(() => {
                    tEl.style.opacity = "1";
                    tEl.style.transform = "translateX(0)";
                });
            };
            const hide = () => {
                if (!tEl) return;
                tEl.style.opacity = "0";
                const offsetHide = TOOLTIP_SLIDE_FROM_RIGHT ?
                    -TOOLTIP_SLIDE_OFFSET :
                    TOOLTIP_SLIDE_OFFSET;
                tEl.style.transform = `translateX(${offsetHide}px)`;
            };
            gui.addEventListener("mouseover", (e) => {
                const tgt = e.target.closest("[data-tooltip]");
                if (tgt) show(tgt);
            });
            gui.addEventListener("mouseout", (e) => {
                const tgt = e.target.closest("[data-tooltip]");
                if (tgt) hide();
            });
            window.addEventListener("keydown", (ev) => {
                hide();
                if ((ev.key === "t" || ev.key === "T") && tEl) {
                    tEl.style.opacity = "0";
                    const offsetHide = TOOLTIP_SLIDE_FROM_RIGHT ?
                        -TOOLTIP_SLIDE_OFFSET :
                        TOOLTIP_SLIDE_OFFSET;
                    tEl.style.transform = `translateX(${offsetHide}px)`;
                }
            });
        })();

        const exportContent = makeElement(
            "div", {
                id: "export-tab",
            }, {
                maxHeight: "60vh",
                overflowY: "auto",
                padding: "0 5px 10px 0",
                display: "flex",
                flexDirection: "column",
                justifyContent: "center",
            },
        );

        const title = makeElement(
            "h1", {
                textContent: "Export Character Card",
            }, {
                margin: "-10px 0 25px 0",
                fontSize: "24px",
                paddingTop: "0px",
                textAlign: "center",
                fontWeight: "bold",
                color: "#fff",
                borderBottom: "2px solid #444",
                paddingBottom: "8px",
            },
        );
        exportContent.appendChild(title);

        const buttonContainer = makeElement(
            "div", {}, {
                display: "flex",
                gap: "12px",
                justifyContent: "center",
                marginBottom: "8px",
                marginTop: "12px",
            },
        );

        ["TXT", "PNG", "JSON"].forEach((format) => {
            const type = format.toLowerCase();

            const button = makeElement(
                "button", {
                    textContent: format,
                }, {
                    background: BUTTON_COLOR,
                    border: "none",
                    color: "white",
                    padding: "12px 24px",
                    borderRadius: "8px",
                    cursor: "pointer",
                    fontWeight: "bold",
                    position: "relative",
                    overflow: "hidden",
                    flex: "1",
                    maxWidth: "min(120px, 30%)",
                    transition: `all ${BUTTON_ANIMATION}ms ease`,
                    boxShadow: "0 3px 6px rgba(0,0,0,0.15)",
                    transform: "translateY(0)",
                    fontSize: "14px",
                },
            );

            const shine = makeElement(
                "div", {}, {
                    position: "absolute",
                    top: "0",
                    left: "0",
                    width: "100%",
                    height: "100%",
                    background: "linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0) 60%)",
                    transform: "translateX(-100%)",
                    transition: `transform ${BUTTON_ANIMATION * 1.5}ms ease-out`,
                    pointerEvents: "none",
                },
            );
            button.appendChild(shine);

            button.onmouseover = () => {
                button.style.background = BUTTON_HOVER_COLOR;
                button.style.transform = "translateY(-3px) scale(1.02)";
                button.style.boxShadow = "0 6px 20px rgba(0,0,0,0.25)";
                button.style.filter = "brightness(1.1)";
                shine.style.transform = "translateX(100%)";
            };

            button.onmouseout = () => {
                button.style.background = BUTTON_COLOR;
                button.style.transform = "translateY(0) scale(1)";
                button.style.boxShadow = "0 3px 6px rgba(0,0,0,0.15)";
                button.style.filter = "brightness(1)";
                shine.style.transform = "translateX(-100%)";
            };

            button.onmousedown = () => {
                button.style.transform = "translateY(0) scale(0.98)";
                button.style.boxShadow = "0 2px 4px rgba(0,0,0,0.3)";
                button.style.background = BUTTON_ACTIVE_COLOR;
                button.style.filter = "brightness(1.2)";
            };

            button.onmouseup = () => {
                button.style.transform = "translateY(-3px) scale(1.02)";
                button.style.boxShadow = "0 6px 20px rgba(0,0,0,0.25)";
                button.style.background = BUTTON_HOVER_COLOR;
                button.style.filter = "brightness(1.1)";
            };

            button.onclick = (e) => {
                const rect = button.getBoundingClientRect();
                const x = e.clientX - rect.left;
                const y = e.clientY - rect.top;

                const ripple = makeElement(
                    "div", {}, {
                        position: "absolute",
                        borderRadius: "50%",
                        backgroundColor: "rgba(255,255,255,0.4)",
                        width: "5px",
                        height: "5px",
                        transform: "scale(1)",
                        opacity: "1",
                        animation: "ripple 600ms linear",
                        pointerEvents: "none",
                        top: `${y}px`,
                        left: `${x}px`,
                        marginLeft: "-2.5px",
                        marginTop: "-2.5px",
                    },
                );

                button.appendChild(ripple);

                exportFormat = type;
                closeV();
                extraction();

                setTimeout(() => ripple.remove(), 600);
            };

            buttonContainer.appendChild(button);
        });

        if (!document.getElementById("char-export-style")) {
            const style = document.createElement("style");
            style.id = "char-export-style";
            style.textContent = `
            @keyframes ripple {
              to {
                transform: scale(30);
                opacity: 0; pointer-events: none;
              }
            }
          `;
            document.head.appendChild(style);
        }

        // Add responsive design styles
        if (!document.getElementById("char-export-responsive")) {
            const responsiveStyle = document.createElement("style");
            responsiveStyle.id = "char-export-responsive";
            responsiveStyle.textContent = `
      @media (max-width: 600px) {
        #char-export-gui {
          width: 95vw !important;
          height: 90vh !important;
          max-height: 90vh !important;
          padding: 10px 15px 5px !important;
        }

        #content-wrapper {
          min-height: 280px !important;
        }

        #export-tab, #settings-tab {
          padding: 10px !important;
        }

        .toggle-wrapper {
          flex-direction: column;
          align-items: flex-start !important;
          gap: 8px !important;
        }

        .toggle-wrapper span {
          order: 1 !important;
          padding-left: 0 !important;
          text-align: left !important;
        }

        .toggle-wrapper label {
          order: 2 !important;
          align-self: flex-end;
        }
      }

      @media (max-height: 600px) {
        #char-export-gui {
          max-height: 95vh !important;
        }
      }
        `;
            document.head.appendChild(responsiveStyle);
        }

        // Add scrollbar styling for settings
        if (!document.getElementById("char-export-settings-scroll")) {
            const settingsScrollStyle = document.createElement("style");
            settingsScrollStyle.id = "char-export-settings-scroll";
            settingsScrollStyle.textContent = `
      #settings-tab {
        scrollbar-width: thin;
        scrollbar-color: #555 #2a2a2a;
      }
      #settings-tab::-webkit-scrollbar {
        width: 6px;
      }
      #settings-tab::-webkit-scrollbar-track {
        background: #2a2a2a;
        border-radius: 3px;
      }
      #settings-tab::-webkit-scrollbar-thumb {
        background: #555;
        border-radius: 3px;
      }
      #settings-tab::-webkit-scrollbar-thumb:hover {
        background: #666;
      }

      /* Enhanced hover effects */
      .toggle-wrapper {
        transition: background 200ms ease;
      }
      .toggle-wrapper:hover {
        background: rgba(255, 255, 255, 0.02);
      }

      /* Enhanced section hover effects */
      #settings-tab > div {
        transition: box-shadow 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94),
                    border 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94),
                    transform 300ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
        border: 1px solid transparent;
        background: #2a2a2a;
      }
      #settings-tab > div:hover {
        box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2),
                    0 4px 12px rgba(0,0,0,0.15);
        border: 1px solid rgba(128, 128, 128, 0.3);
        transform: translateY(-2px) scale(1.01);
        background: linear-gradient(135deg, #2a2a2a 0%, #323232 100%);
      }

      /* Enhanced toggle hover effects */
      .toggle-wrapper {
        transition: background 250ms cubic-bezier(0.25, 0.46, 0.45, 0.94),
                    box-shadow 250ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
        border-radius: 8px;
        contain: layout style;
        isolation: isolate;
      }
      .toggle-wrapper:hover {
        background: linear-gradient(135deg, rgba(128, 128, 128, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
        box-shadow: inset 0 0 0 1px rgba(128, 128, 128, 0.2);
      }

      /* Disable all tooltips inside UI */
      #char-export-gui [data-tooltip]:hover::before,
      #char-export-gui [data-tooltip]:hover::after,
      #char-export-gui input:hover::before,
      #char-export-gui input:hover::after,
      #char-export-gui input[data-tooltip-disabled]:hover::before,
      #char-export-gui input[data-tooltip-disabled]:hover::after {
        display: none !important;
        opacity: 0 !important;
      }

      /* Slot machine animation overflow clipping */
      .template-input-container {
        overflow: hidden !important;
        position: relative !important;
      }

      .template-apply-btn {
        will-change: transform, opacity, filter;
      }

      /* Applied text animation clipping */
      .template-input-container span {
        will-change: transform, opacity, filter;
        user-select: none;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
      }

      /* Disable browser tooltips on input */
      #char-export-gui input[data-tooltip-disabled] {
        pointer-events: auto !important;
      }
      #char-export-gui input[data-tooltip-disabled]:hover::before,
      #char-export-gui input[data-tooltip-disabled]:hover::after {
        display: none !important;
      }
    `;
            document.head.appendChild(settingsScrollStyle);
        }

        if (!document.getElementById("char-export-tooltip-style")) {
            const tooltipStyle = document.createElement("style");
            tooltipStyle.id = "char-export-tooltip-style";
            tooltipStyle.textContent = `
  [data-tooltip] {
    position: relative;
  }
  [data-tooltip]::before {
    content: '';
    position: absolute;
    left: calc(100% + 4px);
    top: 50%;
    transform: translateY(-50%) scaleY(0.5);
    border: solid transparent;
    border-width: 6px 6px 6px 0;
    border-left-color: #333;
    opacity: 0; pointer-events: none;
    transition: opacity 150ms ease;
    z-index: 10001;
  }
  [data-tooltip]::after {
    content: attr(data-tooltip);
    position: absolute;
    left: calc(100% + 10px);
    top: 50%;
    transform: translateY(-50%) scale(0.8);
    background: #333;
    color: #fff;
    padding: 6px 10px;
    border-radius: 4px;
    white-space: nowrap;
    opacity: 0; pointer-events: none;
    transition: opacity 150ms ease, transform 150ms ease;
    z-index: 10001;
  }
  [data-tooltip]:hover::before,
  [data-tooltip]:hover::after {
    opacity: 1;
    transform: translateY(-50%) scale(1);
  }

  .toggle-wrapper {
    border-radius: 8px;
    transition: background 0.2s ease, box-shadow 0.2s ease;
  }
  .toggle-wrapper.active {
    background: transparent;
    box-shadow: none;
  }
              `;
            document.head.appendChild(tooltipStyle);
            if (!document.getElementById("char-export-scrollbar-style")) {
                const scrollStyle = document.createElement("style");
                scrollStyle.id = "char-export-scrollbar-style";
                scrollStyle.textContent = `
  #content-wrapper { overflow: visible; }
  #settings-tab { overflow-y: auto; scrollbar-width: none; -ms-overflow-style: none; }
  #settings-tab::-webkit-scrollbar { width: 0; height: 0; }
  `;
                document.head.appendChild(scrollStyle);
                if (!document.getElementById("char-export-tooltip-override-style")) {
                    const overrideStyle = document.createElement("style");
                    overrideStyle.id = "char-export-tooltip-override-style";
                    overrideStyle.textContent = `
  [data-tooltip]::before { transform: translateY(-50%) translateX(-6px); transition: transform 200ms ease, opacity 200ms ease; }
  [data-tooltip]::after { transform: translateY(-50%) translateX(-10px); transition: transform 200ms ease, opacity 200ms ease; }
  [data-tooltip]:hover::before { transform: translateY(-50%) translateX(0); opacity:1; }
  [data-tooltip]:hover::after { transform: translateY(-50%) translateX(0); opacity:1; }

[data-tooltip]::before,[data-tooltip]::after{display:none !important;}
@keyframes toggle-pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } }
.toggle-wrapper.pulse { animation: toggle-pulse 300ms ease; }

.switch .slider-before { transition: transform 200ms ease, box-shadow 200ms ease; }
.toggle-wrapper.active .slider-before { box-shadow: 0 0 2px rgba(0,0,0,0.2), 0 0 8px rgba(0,128,255,0.5); }
.toggle-wrapper.active .slider { background-color: #0080ff; }
              `;
                    document.head.appendChild(overrideStyle);
                }
            }
        }

        exportContent.appendChild(buttonContainer);

        const contentWrapper = makeElement(
            "div", {
                id: "content-wrapper",
            }, {
                minHeight: "320px",
                width: "100%",
                overflow: "visible",
                display: "flex",
                flexDirection: "column",
                justifyContent: "flex-start",
                position: "relative",
                flex: "1",
            },
        );
        gui.appendChild(contentWrapper);

        const tabContentStyles = {
            height: "100%",
            width: "100%",
            overflowY: "auto",
            overflowX: "hidden",
            padding: "15px",
            paddingTop: "10px",
            position: "absolute",
            top: "0",
            left: "0",
            opacity: "1",
            transform: "scale(1)",
            transition: `opacity ${TAB_ANIMATION_DURATION}ms ease, transform ${TAB_ANIMATION_DURATION}ms ease`,
            boxSizing: "border-box",
        };

        Object.assign(exportContent.style, tabContentStyles);
        exportContent.style.overflowY = "visible";
        exportContent.style.overflowX = "hidden";
        exportContent.style.display = "flex";
        exportContent.style.flexDirection = "column";
        exportContent.style.alignItems = "center";

        const settingsContent = makeElement(
            "div", {
                id: "settings-tab",
                style: "display: none;",
            },
            tabContentStyles,
        );

        contentWrapper.appendChild(exportContent);
        contentWrapper.appendChild(settingsContent);
        const savedExportScroll = parseInt(
            sessionStorage.getItem("char_export_scroll") || "0",
            10,
        );
        exportContent.scrollTop = savedExportScroll;
        const savedSettingsScroll = parseInt(
            sessionStorage.getItem("char_settings_scroll") || "0",
            10,
        );
        settingsContent.scrollTop = savedSettingsScroll;
        settingsContent.addEventListener("scroll", () =>
            sessionStorage.setItem("char_settings_scroll", settingsContent.scrollTop),
        );

        requestAnimationFrame(() => {
            exportContent.scrollTop = savedExportScroll;
            settingsContent.scrollTop = savedSettingsScroll;
        });

        const settingsTitle = makeElement(
            "h1", {
                textContent: "Export Settings",
            }, {
                margin: "-10px 0 25px 0",
                fontSize: "24px",
                paddingTop: "0px",
                textAlign: "center",
                fontWeight: "bold",
                color: "#fff",
                borderBottom: "2px solid #444",
                paddingBottom: "12px",
            },
        );
        settingsContent.appendChild(settingsTitle);

        /**
         * Custom overlay scrollbar implementation
         * Creates a fully custom scrollbar that overlays the content
         * @param {HTMLElement} element - Target scrollable element
         */
        const createCustomScrollbar = (element) => {
            let track, thumb;
            let isDragging = false;
            let startY = 0;
            let startScrollTop = 0;
            let isVisible = false;
            let hideTimeout;

            const createScrollbarElements = () => {
                // Create track
                track = makeElement("div", {
                    className: "custom-scrollbar-track"
                }, {});

                // Create thumb
                thumb = makeElement("div", {
                    className: "custom-scrollbar-thumb"
                }, {});

                track.appendChild(thumb);

                // Add to container
                const container = element.parentElement;
                if (container) {
                    container.classList.add("custom-scrollbar-container");
                    container.style.position = "relative";
                    container.appendChild(track);
                }

                // Ensure completely clean state on creation
                track.classList.remove("expanded", "visible");
                thumb.classList.remove("dragging", "scrolling");
                track.style.opacity = "0.6";
                thumb.style.transition = "background 50ms ease";
            };

            const updateThumbSize = () => {
                if (!track || !thumb) return;

                const containerHeight = element.clientHeight;
                const contentHeight = element.scrollHeight;
                const scrollRatio = containerHeight / contentHeight;

                if (scrollRatio >= 1 || contentHeight <= containerHeight) {
                    track.classList.remove("visible");
                    track.style.visibility = "hidden";
                    isVisible = false;
                    return;
                }

                track.classList.add("visible");
                track.style.visibility = "visible";
                isVisible = true;

                const thumbHeight = Math.max(20, containerHeight * scrollRatio);
                thumb.style.height = `${thumbHeight}px`;

                updateThumbPosition();
            };

            const updateThumbPosition = () => {
                if (!thumb || !isVisible) return;

                const containerHeight = element.clientHeight;
                const contentHeight = element.scrollHeight;
                const trackHeight = track.clientHeight;
                const thumbHeight = thumb.clientHeight;
                const maxThumbTop = trackHeight - thumbHeight;
                const scrollRatio =
                    element.scrollTop / (contentHeight - containerHeight);
                const thumbTop = scrollRatio * maxThumbTop;

                thumb.style.transition = "none";
                thumb.style.transform = `translateY(${thumbTop}px)`;
                requestAnimationFrame(() => {
                    thumb.style.transition = "background 50ms ease";
                });
            };

            const onThumbMouseDown = (e) => {
                e.preventDefault();
                e.stopPropagation();

                isDragging = true;
                startY = e.clientY;
                startScrollTop = element.scrollTop;

                thumb.classList.add("dragging");
                track.classList.add("expanded");
                document.addEventListener("mousemove", onMouseMove);
                document.addEventListener("mouseup", onMouseUp);
                document.body.style.userSelect = "none";
            };

            const onMouseMove = (e) => {
                if (!isDragging) return;

                const deltaY = e.clientY - startY;
                const trackHeight = track.clientHeight;
                const thumbHeight = thumb.clientHeight;
                const contentHeight = element.scrollHeight;
                const containerHeight = element.clientHeight;

                const scrollRange = contentHeight - containerHeight;
                const thumbRange = trackHeight - thumbHeight;
                const scrollRatio = deltaY / thumbRange;
                const scrollDelta = scrollRatio * scrollRange;

                element.scrollTop = Math.max(
                    0,
                    Math.min(startScrollTop + scrollDelta, scrollRange),
                );
            };

            const onMouseUp = () => {
                isDragging = false;
                thumb.classList.remove("dragging");
                track.classList.remove("expanded");
                document.removeEventListener("mousemove", onMouseMove);
                document.removeEventListener("mouseup", onMouseUp);
                document.body.style.userSelect = "";
            };

            const onTrackClick = (e) => {
                if (e.target === thumb) return;

                const trackRect = track.getBoundingClientRect();
                const clickY = e.clientY - trackRect.top;
                const trackHeight = track.clientHeight;
                const thumbHeight = thumb.clientHeight;
                const containerHeight = element.clientHeight;
                const contentHeight = element.scrollHeight;

                const scrollRatio =
                    (clickY - thumbHeight / 2) / (trackHeight - thumbHeight);
                const scrollTop = scrollRatio * (contentHeight - containerHeight);

                element.scrollTop = Math.max(
                    0,
                    Math.min(scrollTop, contentHeight - containerHeight),
                );
            };

            const onScroll = () => {
                updateThumbPosition();
            };

            const onResize = () => {
                updateThumbSize();
            };

            const init = () => {
                createScrollbarElements();

                // Mouse wheel support - just update position
                const onWheel = () => {
                    updateThumbPosition();
                };

                // No special hover events needed - CSS handles it

                // Event listeners
                element.addEventListener("scroll", onScroll);
                element.addEventListener("wheel", onWheel, {
                    passive: true
                });
                thumb.addEventListener("mousedown", onThumbMouseDown);
                track.addEventListener("click", onTrackClick);

                // Resize observer for content changes
                const resizeObserver = new ResizeObserver(onResize);
                resizeObserver.observe(element);

                // No scroll position restoration

                // Force clean initial state with proper timing
                setTimeout(() => {
                    track.classList.remove("expanded", "visible");
                    thumb.classList.remove("dragging", "scrolling");
                    track.style.opacity = "0.6";
                    thumb.style.transition = "background 50ms ease";
                }, 0);

                // Initial setup - immediate and delayed for reliability
                updateThumbSize();
                requestAnimationFrame(() => {
                    updateThumbSize();
                    // Additional state reset after first frame
                    track.classList.remove("expanded");
                });
                setTimeout(() => {
                    updateThumbSize();
                    // Final state cleanup
                    track.classList.remove("expanded");
                }, 50);

                return {
                    destroy: () => {
                        element.removeEventListener("scroll", onScroll);
                        element.removeEventListener("wheel", onWheel);
                        if (thumb) thumb.removeEventListener("mousedown", onThumbMouseDown);
                        if (track) {
                            track.removeEventListener("click", onTrackClick);
                            track.remove();
                        }
                        resizeObserver.disconnect();
                        clearTimeout(element.scrollTimeout);
                    },
                };
            };

            return {
                init
            };
        };

        // Initialize custom scrollbar
        const settingsScrollbar = createCustomScrollbar(settingsContent);

        // Ensure scrollbar appears on first open
        setTimeout(() => {
            settingsScrollbar.init();
        }, 10);

        // Filename Template Section
        const templateSection = makeElement(
            "div", {}, {
                marginTop: "20px",
                marginBottom: "15px",
                padding: "15px",
                background: "#2a2a2a",
                borderRadius: "10px",
                boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
                transition: "all 200ms ease",
                cursor: "default",
            },
        );

        const templateTitle = makeElement(
            "h3", {
                textContent: "Filename",
            }, {
                margin: "0 0 15px 0",
                fontSize: "16px",
                color: "#fff",
                fontWeight: "bold",
                textAlign: "center",
            },
        );
        templateSection.appendChild(templateTitle);

        const templateInputContainer = makeElement(
            "div", {
                className: "template-input-container",
            }, {
                marginBottom: "12px",
                position: "relative",
                overflow: "hidden",
            },
        );

        const templateInput = makeElement(
            "input", {
                type: "text",
                value: filenameTemplate,
                placeholder: "Enter filename template",
            }, {
                width: "100%",
                padding: "10px 55px 10px 12px",
                border: "1px solid #555",
                borderRadius: "6px",
                background: "#1a1a1a",
                color: "#fff",
                fontSize: "13px",
                boxSizing: "border-box",
                transition: "border-color 200ms ease, box-shadow 200ms ease",
                outline: "none",
            },
        );

        // Disable tooltips completely
        templateInput.setAttribute("title", "");
        templateInput.setAttribute("data-tooltip-disabled", "true");
        templateInput.removeAttribute("title");
        templateInput.addEventListener("mouseenter", (e) => {
            e.target.removeAttribute("title");
            e.target.title = "";
        });

        // Override browser tooltip styles
        templateInput.style.setProperty("pointer-events", "auto", "important");
        templateInput.addEventListener("mouseover", (e) => {
            e.preventDefault();
            e.stopPropagation();
        });

        let hasChanges =
            filenameTemplate !== "" &&
            filenameTemplate !==
            (localStorage.getItem("filenameTemplate") || "{name}");
        let originalTemplate = localStorage.getItem("filenameTemplate") || "{name}";

        // Auto-restore functionality
        const restoreTemplate = () => {
            const savedDraft = localStorage.getItem("filenameTemplateDraft");
            if (savedDraft && savedDraft !== templateInput.value) {
                templateInput.value = savedDraft;
                filenameTemplate = savedDraft;
                hasChanges =
                    filenameTemplate !== "" &&
                    filenameTemplate !==
                    (localStorage.getItem("filenameTemplate") || "{name}");

                // Update apply button state
                const applyBtn = templateSection.querySelector(".template-apply-btn");
                if (applyBtn && hasChanges) {
                    applyBtn.style.opacity = "1";
                    applyBtn.style.color = "#4CAF50";
                    applyBtn.style.filter = "drop-shadow(0 0 4px rgba(76, 175, 80, 0.6))";
                }
            }
        };

        templateInput.addEventListener("input", (e) => {
            filenameTemplate = e.target.value;
            localStorage.setItem("filenameTemplateDraft", filenameTemplate);
            hasChanges =
                filenameTemplate !== "" &&
                filenameTemplate !==
                (localStorage.getItem("filenameTemplate") || "{name}");

            // Update apply button state with smooth animation
            const applyBtn = templateSection.querySelector(".template-apply-btn");
            if (applyBtn && !isAnimating) {
                applyBtn.style.transition = "all 200ms ease";
                if (hasChanges) {
                    applyBtn.style.opacity = "1";
                    applyBtn.style.color = "#4CAF50";
                    applyBtn.style.filter = "drop-shadow(0 0 4px rgba(76, 175, 80, 0.6))";
                } else {
                    applyBtn.style.opacity = "0.5";
                    applyBtn.style.color = "#666";
                    applyBtn.style.filter = "none";
                }
            }
        });

        // Restore on tab switch and UI open
        restoreTemplate();

        let isEnterHeld = false;
        let isMouseHeld = false;

        templateInput.addEventListener("keydown", (e) => {
            if (e.key === "Enter" && !isEnterHeld) {
                isEnterHeld = true;
                e.preventDefault();
                if (hasChanges && !isAnimating) {
                    performApplyAction();
                } else if (!hasChanges && !isAnimating) {
                    startGrayHold();
                }
            }
        });

        templateInput.addEventListener("keyup", (e) => {
            if (e.key === "Enter") {
                isEnterHeld = false;
                if (!hasChanges && !isAnimating) {
                    endGrayHold();
                }
            }
        });

        templateInput.addEventListener("mouseover", () => {
            if (
                !isAnimating &&
                document.activeElement !== templateInput &&
                templateInput.style.borderColor !== "rgb(76, 175, 80)"
            ) {
                templateInput.style.borderColor = "#777";
            }
        });

        templateInput.addEventListener("mouseout", () => {
            if (
                !isAnimating &&
                document.activeElement !== templateInput &&
                templateInput.style.borderColor !== "rgb(76, 175, 80)"
            ) {
                templateInput.style.borderColor = "#555";
            }
        });

        templateInput.addEventListener("focus", () => {
            if (
                !isAnimating &&
                templateInput.style.borderColor !== "rgb(76, 175, 80)"
            ) {
                templateInput.style.borderColor = "#888";
            }
        });

        templateInput.addEventListener("blur", () => {
            if (
                !isAnimating &&
                templateInput.style.borderColor !== "rgb(76, 175, 80)"
            ) {
                templateInput.style.borderColor = "#555";
            }
        });

        templateInputContainer.appendChild(templateInput);

        const applyButton = makeElement(
            "button", {
                textContent: "✓",
                className: "template-apply-btn",
            }, {
                position: "absolute",
                right: "8px",
                top: "50%",
                transform: "translateY(-50%)",
                background: "transparent",
                border: "none",
                color: "#666",
                fontSize: "14px",
                cursor: "pointer",
                padding: "4px",
                borderRadius: "3px",
                opacity: "0.5",
                transition: "all 200ms ease",
            },
        );

        let isAnimating = false;

        const performApplyAction = () => {
            if (!hasChanges || isAnimating) return;
            isAnimating = true;

            // Green glow for input box (slightly thicker but subtle)
            templateInput.classList.add("applying-changes");
            templateInput.style.borderColor = "#4CAF50";
            templateInput.style.boxShadow = "0 0 8px rgba(76, 175, 80, 0.5)";

            // Show bright green glow before animation
            applyButton.style.color = "#2ecc71";
            applyButton.style.filter = "drop-shadow(0 0 8px rgba(46, 204, 113, 0.8))";
            applyButton.style.textShadow = "0 0 12px rgba(46, 204, 113, 0.9)";

            setTimeout(() => {
                // Save current template
                localStorage.setItem("filenameTemplate", filenameTemplate);
                originalTemplate = filenameTemplate;
                hasChanges = false;

                // Slot machine animation sequence with proper overflow clipping

                // Phase 1: Checkmark slides up with fast acceleration (like slot reel)
                applyButton.style.transition =
                    "all 180ms cubic-bezier(0.25, 0.46, 0.45, 0.94)";
                applyButton.style.transform = "translateY(-50%) translateY(-30px)";
                applyButton.style.filter = "blur(4px)";
                applyButton.style.opacity = "0";

                setTimeout(() => {
                    // Phase 2: Applied! slides up from bottom (like slot winning symbol)
                    const appliedText = makeElement(
                        "span", {
                            textContent: "Applied!",
                        }, {
                            position: "absolute",
                            right: "8px",
                            top: "50%",
                            transform: "translateY(-50%) translateY(25px)",
                            color: "#4CAF50",
                            fontSize: "11px",
                            fontWeight: "bold",
                            opacity: "0",
                            transition: "all 150ms cubic-bezier(0.25, 0.46, 0.45, 0.94)",
                            pointerEvents: "none",
                            whiteSpace: "nowrap",
                        },
                    );

                    templateInputContainer.appendChild(appliedText);

                    // Applied! slides into view with deceleration
                    requestAnimationFrame(() => {
                        appliedText.style.opacity = "1";
                        appliedText.style.transform = "translateY(-50%) translateY(0px)";
                        appliedText.style.filter = "blur(0px)";
                    });

                    // Phase 3: Applied! slides up and disappears (faster stay time)
                    setTimeout(() => {
                        appliedText.style.transition =
                            "all 120ms cubic-bezier(0.25, 0.46, 0.45, 0.94)";
                        appliedText.style.transform = "translateY(-50%) translateY(-25px)";
                        appliedText.style.filter = "blur(3px)";
                        appliedText.style.opacity = "0";

                        // Phase 4: New checkmark slides up from bottom with glow
                        setTimeout(() => {
                            // Position new checkmark below input box ready to slide up
                            applyButton.style.transition = "none";
                            applyButton.style.transform = "translateY(-50%) translateY(25px)";
                            applyButton.style.opacity = "0";
                            applyButton.style.color = "#aaa";
                            applyButton.style.filter = "blur(1px)";

                            requestAnimationFrame(() => {
                                // Slide up with glow effect and color mixing
                                applyButton.style.transition =
                                    "all 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275)";
                                applyButton.style.transform =
                                    "translateY(-50%) translateY(-2px)";
                                applyButton.style.opacity = "0.9";
                                applyButton.style.color = "#999";
                                applyButton.style.filter =
                                    "blur(0px) drop-shadow(0 0 6px rgba(153, 153, 153, 0.8)) hue-rotate(20deg)";
                                applyButton.style.textShadow =
                                    "0 0 10px rgba(200, 200, 200, 0.9)";

                                // Phase 5: Settle with subtle bounce and color normalization
                                setTimeout(() => {
                                    // Check if user made changes during animation
                                    const currentChanges =
                                        filenameTemplate !== "" &&
                                        filenameTemplate !==
                                        (localStorage.getItem("filenameTemplate") || "{name}");

                                    applyButton.style.transition = "all 150ms ease-out";
                                    applyButton.style.transform =
                                        "translateY(-50%) translateY(0px)";

                                    if (currentChanges) {
                                        // Show green if changes exist
                                        applyButton.style.opacity = "1";
                                        applyButton.style.color = "#4CAF50";
                                        applyButton.style.filter =
                                            "drop-shadow(0 0 4px rgba(76, 175, 80, 0.6))";
                                    } else {
                                        // Show gray if no changes
                                        applyButton.style.opacity = "0.5";
                                        applyButton.style.color = "#666";
                                        applyButton.style.filter = "none";
                                    }
                                    applyButton.style.textShadow = "none";

                                    // Reset input box border after delay
                                    setTimeout(() => {
                                        templateInput.classList.remove("applying-changes");
                                        if (document.activeElement === templateInput) {
                                            templateInput.style.borderColor = "#888";
                                            templateInput.style.boxShadow =
                                                "inset 0 0 0 1px rgba(136, 136, 136, 0.3)";
                                        } else {
                                            templateInput.style.borderColor = "#555";
                                            templateInput.style.boxShadow = "none";
                                        }
                                    }, 100);

                                    // Clean up Applied! text
                                    appliedText.remove();
                                    isAnimating = false;
                                }, 250);
                            });
                        }, 100);
                    }, 500); // Shorter stay time for snappier feel
                }, 120);
            }, 50);
        };

        const startGrayHold = () => {
            if (!hasChanges && !isAnimating) {
                // Hold down effect for gray checkmark
                applyButton.style.transition = "all 100ms ease";
                applyButton.style.transform = "translateY(-50%) scale(0.9)";
                applyButton.style.opacity = "0.3";
            }
        };

        const endGrayHold = () => {
            if (!hasChanges && !isAnimating) {
                // Release effect for gray checkmark
                applyButton.style.transition = "all 100ms ease";
                applyButton.style.transform = "translateY(-50%) scale(1)";
                applyButton.style.opacity = "0.5";
            }
        };

        const handleGrayClick = () => {
            if (!hasChanges && !isAnimating) {
                startGrayHold();
                setTimeout(() => endGrayHold(), 100);
            }
        };

        applyButton.addEventListener("mousedown", () => {
            if (hasChanges && !isAnimating) {
                // Green glow for input box on click too (slightly thicker but subtle)
                templateInput.classList.add("applying-changes");
                templateInput.style.borderColor = "#4CAF50";
                templateInput.style.boxShadow = "0 0 8px rgba(76, 175, 80, 0.5)";
                performApplyAction();
            } else if (!hasChanges && !isAnimating) {
                isMouseHeld = true;
                startGrayHold();
            }
        });

        applyButton.addEventListener("mouseup", () => {
            if (isMouseHeld) {
                isMouseHeld = false;
                endGrayHold();
            }
        });

        applyButton.addEventListener("mouseleave", () => {
            if (isMouseHeld) {
                isMouseHeld = false;
                endGrayHold();
            }
        });

        // Set initial apply button state
        if (hasChanges) {
            applyButton.style.opacity = "1";
            applyButton.style.color = "#4CAF50";
        }

        templateInputContainer.appendChild(applyButton);
        templateSection.appendChild(templateInputContainer);

        const tokenButtonsContainer = makeElement(
            "div", {}, {
                display: "flex",
                flexWrap: "wrap",
                gap: "4px",
                marginBottom: "8px",
                alignItems: "center",
            },
        );

        // Create token buttons
        const tokens = [{
                token: "id",
                label: "ID"
            },
            {
                token: "creator",
                label: "Creator"
            },
            {
                token: "name",
                label: "Name"
            },
            {
                token: "chat_name",
                label: "Chat Name"
            },
            {
                token: "created",
                label: "Created"
            },
            {
                token: "updated",
                label: "Updated"
            },
            {
                token: "tags",
                label: "Tags"
            },
        ];

        tokens.forEach(({
            token,
            label
        }) => {
            const button = createTokenButton(token, label, templateInput, false);
            tokenButtonsContainer.appendChild(button);
        });

        templateSection.appendChild(tokenButtonsContainer);

        // Save Path Section
        const savePathSection = makeElement(
            "div", {}, {
                marginTop: "20px",
                marginBottom: "15px",
                padding: "15px",
                background: "#2a2a2a",
                borderRadius: "10px",
                boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
                transition: "all 200ms ease",
                cursor: "default",
            },
        );

        const savePathTitle = makeElement(
            "h3", {
                textContent: "Save Path",
            }, {
                margin: "0 0 15px 0",
                fontSize: "16px",
                color: "#fff",
                fontWeight: "bold",
                textAlign: "center",
            },
        );
        savePathSection.appendChild(savePathTitle);

        const savePathInputContainer = makeElement(
            "div", {
                className: "savepath-input-container",
            }, {
                marginBottom: "12px",
                position: "relative",
                overflow: "hidden",
            },
        );

        // Update userChangedSavePath to current state
        userChangedSavePath =
            localStorage.getItem("userChangedSavePath") === "true";

        // Always use default prefill if user hasn't applied changes yet
        let savePathTemplate = userChangedSavePath ?
            localStorage.getItem("savePathTemplate") || "" :
            "cards/{creator}";
        const savePathInput = makeElement(
            "input", {
                type: "text",
                value: savePathTemplate,
                placeholder: "Leave empty to save to the root directory",
            }, {
                width: "100%",
                padding: "10px 55px 10px 12px",
                border: "1px solid #555",
                borderRadius: "6px",
                background: "#1a1a1a",
                color: "#fff",
                fontSize: "13px",
                boxSizing: "border-box",
                transition: "border-color 200ms ease, box-shadow 200ms ease",
                outline: "none",
            },
        );

        // Disable tooltips
        savePathInput.setAttribute("title", "");
        savePathInput.setAttribute("data-tooltip-disabled", "true");
        savePathInput.removeAttribute("title");
        savePathInput.addEventListener("mouseenter", (e) => {
            e.target.removeAttribute("title");
            e.target.title = "";
        });

        // Override browser tooltip styles
        savePathInput.style.setProperty("pointer-events", "auto", "important");
        savePathInput.addEventListener("mouseover", (e) => {
            e.preventDefault();
            e.stopPropagation();
        });

        let originalSavePathTemplate = userChangedSavePath ?
            localStorage.getItem("savePathTemplate") || "" :
            "cards/{creator}";
        let savePathHasChanges = savePathTemplate !== originalSavePathTemplate;

        // Auto-restore functionality removed for Save Path

        savePathInput.addEventListener("input", (e) => {
            savePathTemplate = e.target.value;
            // Update userChangedSavePath state
            userChangedSavePath =
                localStorage.getItem("userChangedSavePath") === "true";
            const currentOriginal = userChangedSavePath ?
                localStorage.getItem("savePathTemplate") || "" :
                "cards/{creator}";
            savePathHasChanges = savePathTemplate !== currentOriginal;

            // Update apply button state
            const applyBtn = savePathSection.querySelector(".savepath-apply-btn");
            if (applyBtn && !savePathIsAnimating) {
                applyBtn.style.transition = "all 200ms ease";
                if (savePathHasChanges) {
                    applyBtn.style.opacity = "1";
                    applyBtn.style.color = "#4CAF50";
                    applyBtn.style.filter = "drop-shadow(0 0 4px rgba(76, 175, 80, 0.6))";
                } else {
                    applyBtn.style.opacity = "0.5";
                    applyBtn.style.color = "#666";
                    applyBtn.style.filter = "none";
                }
            }
        });

        // restoreSavePath(); // Removed auto-restore for Save Path

        let savePathIsEnterHeld = false;
        let savePathIsMouseHeld = false;
        let savePathIsAnimating = false;

        savePathInput.addEventListener("keydown", (e) => {
            if (e.key === "Enter" && !savePathIsEnterHeld) {
                savePathIsEnterHeld = true;
                e.preventDefault();
                if (savePathHasChanges && !savePathIsAnimating) {
                    performSavePathApplyAction();
                } else if (!savePathHasChanges && !savePathIsAnimating) {
                    startSavePathGrayHold();
                }
            }
        });

        savePathInput.addEventListener("keyup", (e) => {
            if (e.key === "Enter") {
                savePathIsEnterHeld = false;
                if (!savePathHasChanges && !savePathIsAnimating) {
                    endSavePathGrayHold();
                }
            }
        });

        savePathInput.addEventListener("mouseover", () => {
            if (
                !savePathIsAnimating &&
                document.activeElement !== savePathInput &&
                savePathInput.style.borderColor !== "rgb(76, 175, 80)"
            ) {
                savePathInput.style.borderColor = "#777";
            }
        });

        savePathInput.addEventListener("mouseout", () => {
            if (
                !savePathIsAnimating &&
                document.activeElement !== savePathInput &&
                savePathInput.style.borderColor !== "rgb(76, 175, 80)"
            ) {
                savePathInput.style.borderColor = "#555";
            }
        });

        savePathInput.addEventListener("focus", () => {
            if (
                !savePathIsAnimating &&
                savePathInput.style.borderColor !== "rgb(76, 175, 80)"
            ) {
                savePathInput.style.borderColor = "#888";
            }
        });

        savePathInput.addEventListener("blur", () => {
            if (
                !savePathIsAnimating &&
                savePathInput.style.borderColor !== "rgb(76, 175, 80)"
            ) {
                savePathInput.style.borderColor = "#555";
            }
        });

        savePathInputContainer.appendChild(savePathInput);

        const savePathApplyButton = makeElement(
            "button", {
                textContent: "✓",
                className: "savepath-apply-btn",
            }, {
                position: "absolute",
                right: "8px",
                top: "50%",
                transform: "translateY(-50%)",
                background: "transparent",
                border: "none",
                color: "#666",
                fontSize: "14px",
                cursor: "pointer",
                padding: "4px",
                borderRadius: "3px",
                opacity: "0.5",
                transition: "all 200ms ease",
            },
        );

        const performSavePathApplyAction = () => {
            if (!savePathHasChanges || savePathIsAnimating) return;
            savePathIsAnimating = true;

            savePathInput.classList.add("applying-changes");
            savePathInput.style.borderColor = "#4CAF50";
            savePathInput.style.boxShadow = "0 0 8px rgba(76, 175, 80, 0.5)";

            savePathApplyButton.style.color = "#2ecc71";
            savePathApplyButton.style.filter =
                "drop-shadow(0 0 8px rgba(46, 204, 113, 0.8))";
            savePathApplyButton.style.textShadow = "0 0 12px rgba(46, 204, 113, 0.9)";

            setTimeout(() => {
                localStorage.setItem("savePathTemplate", savePathTemplate);
                // Set boolean to true when user applies any changes to save path
                localStorage.setItem("userChangedSavePath", "true");
                userChangedSavePath = true; // Update the variable immediately
                originalSavePathTemplate = savePathTemplate;
                savePathHasChanges = false;

                savePathApplyButton.style.transition =
                    "all 180ms cubic-bezier(0.25, 0.46, 0.45, 0.94)";
                savePathApplyButton.style.transform =
                    "translateY(-50%) translateY(-30px)";
                savePathApplyButton.style.filter = "blur(4px)";
                savePathApplyButton.style.opacity = "0";

                setTimeout(() => {
                    const appliedText = makeElement(
                        "span", {
                            textContent: "Applied!",
                        }, {
                            position: "absolute",
                            right: "8px",
                            top: "50%",
                            transform: "translateY(-50%) translateY(25px)",
                            color: "#4CAF50",
                            fontSize: "11px",
                            fontWeight: "bold",
                            opacity: "0",
                            transition: "all 150ms cubic-bezier(0.25, 0.46, 0.45, 0.94)",
                            pointerEvents: "none",
                            whiteSpace: "nowrap",
                        },
                    );

                    savePathInputContainer.appendChild(appliedText);

                    requestAnimationFrame(() => {
                        appliedText.style.opacity = "1";
                        appliedText.style.transform = "translateY(-50%) translateY(0px)";
                        appliedText.style.filter = "blur(0px)";
                    });

                    setTimeout(() => {
                        appliedText.style.transition =
                            "all 120ms cubic-bezier(0.25, 0.46, 0.45, 0.94)";
                        appliedText.style.transform = "translateY(-50%) translateY(-25px)";
                        appliedText.style.filter = "blur(3px)";
                        appliedText.style.opacity = "0";

                        setTimeout(() => {
                            savePathApplyButton.style.transition = "none";
                            savePathApplyButton.style.transform =
                                "translateY(-50%) translateY(25px)";
                            savePathApplyButton.style.opacity = "0";
                            savePathApplyButton.style.color = "#aaa";
                            savePathApplyButton.style.filter = "blur(1px)";

                            requestAnimationFrame(() => {
                                savePathApplyButton.style.transition =
                                    "all 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275)";
                                savePathApplyButton.style.transform =
                                    "translateY(-50%) translateY(-2px)";
                                savePathApplyButton.style.opacity = "0.9";
                                savePathApplyButton.style.color = "#999";
                                savePathApplyButton.style.filter =
                                    "blur(0px) drop-shadow(0 0 6px rgba(153, 153, 153, 0.8)) hue-rotate(20deg)";
                                savePathApplyButton.style.textShadow =
                                    "0 0 10px rgba(200, 200, 200, 0.9)";

                                setTimeout(() => {
                                    // Always set to gray state after applying since changes are now saved
                                    savePathApplyButton.style.transition = "all 150ms ease-out";
                                    savePathApplyButton.style.transform =
                                        "translateY(-50%) translateY(0px)";
                                    savePathApplyButton.style.opacity = "0.5";
                                    savePathApplyButton.style.color = "#666";
                                    savePathApplyButton.style.filter = "none";
                                    savePathApplyButton.style.textShadow = "none";

                                    setTimeout(() => {
                                        savePathInput.classList.remove("applying-changes");
                                        if (document.activeElement === savePathInput) {
                                            savePathInput.style.borderColor = "#888";
                                            savePathInput.style.boxShadow =
                                                "inset 0 0 0 1px rgba(136, 136, 136, 0.3)";
                                        } else {
                                            savePathInput.style.borderColor = "#555";
                                            savePathInput.style.boxShadow = "none";
                                        }
                                    }, 100);

                                    appliedText.remove();
                                    savePathIsAnimating = false;
                                }, 250);
                            });
                        }, 100);
                    }, 500);
                }, 120);
            }, 50);
        };

        const startSavePathGrayHold = () => {
            if (!savePathHasChanges && !savePathIsAnimating) {
                savePathApplyButton.style.transition = "all 100ms ease";
                savePathApplyButton.style.transform = "translateY(-50%) scale(0.9)";
                savePathApplyButton.style.opacity = "0.3";
            }
        };

        const endSavePathGrayHold = () => {
            if (!savePathHasChanges && !savePathIsAnimating) {
                savePathApplyButton.style.transition = "all 100ms ease";
                savePathApplyButton.style.transform = "translateY(-50%) scale(1)";
                savePathApplyButton.style.opacity = "0.5";
            }
        };

        savePathApplyButton.addEventListener("mousedown", () => {
            if (savePathHasChanges && !savePathIsAnimating) {
                savePathInput.classList.add("applying-changes");
                savePathInput.style.borderColor = "#4CAF50";
                savePathInput.style.boxShadow = "0 0 8px rgba(76, 175, 80, 0.5)";
                performSavePathApplyAction();
            } else if (!savePathHasChanges && !savePathIsAnimating) {
                savePathIsMouseHeld = true;
                startSavePathGrayHold();
            }
        });

        savePathApplyButton.addEventListener("mouseup", () => {
            if (savePathIsMouseHeld) {
                savePathIsMouseHeld = false;
                endSavePathGrayHold();
            }
        });

        savePathApplyButton.addEventListener("mouseleave", () => {
            if (savePathIsMouseHeld) {
                savePathIsMouseHeld = false;
                endSavePathGrayHold();
            }
        });

        if (savePathHasChanges) {
            savePathApplyButton.style.opacity = "1";
            savePathApplyButton.style.color = "#4CAF50";
        }

        savePathInputContainer.appendChild(savePathApplyButton);
        savePathSection.appendChild(savePathInputContainer);

        const savePathTokenButtonsContainer = makeElement(
            "div", {}, {
                display: "flex",
                flexWrap: "wrap",
                gap: "4px",
                marginBottom: "8px",
                alignItems: "center",
            },
        );

        tokens.forEach(({
            token,
            label
        }) => {
            const button = createTokenButton(token, label, savePathInput, true);
            savePathTokenButtonsContainer.appendChild(button);
        });

        savePathSection.appendChild(savePathTokenButtonsContainer);

        // FileSystemAccess API Toggle
        const useFileSystemToggle = createToggle(
            "useFileSystemAccess",
            "Use FileSystemAccess API",
            "Enable to use save path with directory picker. Disable for regular downloads.",
            localStorage.getItem("useFileSystemAccess") === "true",
        );

        useFileSystemToggle.input.addEventListener("change", (e) => {
            const isEnabled = e.target.checked;
            localStorage.setItem("useFileSystemAccess", isEnabled);

            // Smooth animation with resume logic
            directorySection.style.transition =
                "all 400ms cubic-bezier(0.4, 0, 0.2, 1)";

            if (isEnabled) {
                // Slide down animation
                directorySection.style.maxHeight = "35px";
                directorySection.style.opacity = "1";
                directorySection.style.paddingTop = "5px";
                directorySection.style.paddingBottom = "5px";
                directorySection.style.marginBottom = "5px";
                directorySection.style.transform = "translateY(0)";
            } else {
                // Slide up animation
                directorySection.style.maxHeight = "0";
                directorySection.style.opacity = "0";
                directorySection.style.paddingTop = "0";
                directorySection.style.paddingBottom = "0";
                directorySection.style.marginBottom = "0";
                directorySection.style.transform = "translateY(-10px)";
            }
        });

        savePathSection.appendChild(useFileSystemToggle.container);

        // Directory Picker with smooth animation support
        const directorySection = makeElement(
            "div", {}, {
                marginTop: "5px",
                display: "flex",
                alignItems: "center",
                justifyContent: "space-between",
                width: "100%",
                overflow: "hidden",
                transition: "all 400ms cubic-bezier(0.4, 0, 0.2, 1)",
                maxHeight: localStorage.getItem("useFileSystemAccess") === "true" ? "35px" : "0",
                opacity: localStorage.getItem("useFileSystemAccess") === "true" ? "1" : "0",
                paddingTop: localStorage.getItem("useFileSystemAccess") === "true" ? "5px" : "0",
                paddingBottom: localStorage.getItem("useFileSystemAccess") === "true" ? "5px" : "0",
                marginBottom: localStorage.getItem("useFileSystemAccess") === "true" ? "5px" : "0",
            },
        );

        const directoryLabel = makeElement(
            "span", {
                textContent: "Directory",
            }, {
                fontSize: "13px",
                color: "#fff",
                fontWeight: "bold",
            },
        );

        const directoryRightSection = makeElement(
            "div", {}, {
                display: "flex",
                alignItems: "center",
                gap: "10px",
            },
        );

        const directoryName = makeElement(
            "span", {
                textContent: "Not selected",
            }, {
                fontSize: "12px",
                color: "#aaa",
                fontStyle: "italic",
            },
        );

        const directoryButton = makeElement(
            "button", {
                textContent: "Browse",
                className: "directory-button",
            }, {
                background: "#333",
                color: "#fff",
                border: "none",
                borderRadius: "6px",
                padding: "8px 16px",
                cursor: "pointer",
                fontSize: "12px",
                transition: "all 200ms ease",
            },
        );

        let selectedDirectory = null;

        // IndexedDB functions for directory handle persistence
        const DB_NAME = "DirectoryHandles";
        const DB_VERSION = 1;
        const STORE_NAME = "handles";

        async function storeDirectoryHandle(handle) {
            return new Promise((resolve, reject) => {
                const request = indexedDB.open(DB_NAME, DB_VERSION);

                request.onupgradeneeded = (e) => {
                    const db = e.target.result;
                    if (!db.objectStoreNames.contains(STORE_NAME)) {
                        db.createObjectStore(STORE_NAME);
                    }
                };

                request.onsuccess = (e) => {
                    const db = e.target.result;
                    const transaction = db.transaction([STORE_NAME], "readwrite");
                    const store = transaction.objectStore(STORE_NAME);

                    const putRequest = store.put(handle, "selectedDirectory");
                    putRequest.onsuccess = () => resolve();
                    putRequest.onerror = () => reject(putRequest.error);
                };

                request.onerror = () => reject(request.error);
            });
        }

        async function getDirectoryHandle() {
            return new Promise((resolve, reject) => {
                const request = indexedDB.open(DB_NAME, DB_VERSION);

                request.onupgradeneeded = (e) => {
                    const db = e.target.result;
                    if (!db.objectStoreNames.contains(STORE_NAME)) {
                        db.createObjectStore(STORE_NAME);
                    }
                };

                request.onsuccess = (e) => {
                    const db = e.target.result;
                    const transaction = db.transaction([STORE_NAME], "readonly");
                    const store = transaction.objectStore(STORE_NAME);

                    const getRequest = store.get("selectedDirectory");
                    getRequest.onsuccess = () => resolve(getRequest.result);
                    getRequest.onerror = () => reject(getRequest.error);
                };

                request.onerror = () => reject(request.error);
            });
        }

        // Restore directory selection on page load
        directoryName.textContent = "Not selected";
        directoryName.style.color = "#aaa";
        directoryName.style.fontStyle = "italic";

        // Async function to restore directory handle
        (async () => {
            try {
                const storedHandle = await getDirectoryHandle();
                if (storedHandle) {
                    // Test if the handle is still valid
                    try {
                        const permission = await storedHandle.queryPermission({
                            mode: "readwrite",
                        });
                        if (permission === "granted" || permission === "prompt") {
                            selectedDirectory = storedHandle;
                            window.selectedDirectoryHandle = storedHandle;
                            directoryName.textContent = storedHandle.name;
                            directoryName.style.color = "#4CAF50";
                            directoryName.style.fontStyle = "normal";
                            console.log(
                                "[Directory] Restored from IndexedDB:",
                                storedHandle.name,
                            );
                        } else {
                            console.log("[Directory] Handle exists but permission denied");
                        }
                    } catch (error) {
                        console.log("[Directory] Handle invalid, removing from storage");
                        // Handle is invalid, remove it
                        const request = indexedDB.open(DB_NAME, DB_VERSION);
                        request.onsuccess = (e) => {
                            const db = e.target.result;
                            const transaction = db.transaction([STORE_NAME], "readwrite");
                            const store = transaction.objectStore(STORE_NAME);
                            store.delete("selectedDirectory");
                        };
                    }
                }
            } catch (error) {
                console.log("[Directory] Error restoring from IndexedDB:", error);
            }
        })();

        directoryButton.addEventListener("click", async () => {
            if ("showDirectoryPicker" in window) {
                try {
                    selectedDirectory = await window.showDirectoryPicker();
                    window.selectedDirectoryHandle = selectedDirectory; // Store globally for save function
                    directoryName.textContent = selectedDirectory.name;
                    directoryName.style.color = "#4CAF50";
                    directoryName.style.fontStyle = "normal";

                    // Persist directory handle in IndexedDB
                    storeDirectoryHandle(selectedDirectory)
                        .then(() => {
                            console.log(
                                "[Directory] Stored in IndexedDB:",
                                selectedDirectory.name,
                            );
                        })
                        .catch((error) => {
                            console.log("[Directory] Failed to store in IndexedDB:", error);
                        });
                } catch (err) {
                    console.log("Directory picker was cancelled or failed:", err);
                }
            } else {
                alert("FileSystemAccess API is not supported in this browser.");
            }
        });

        directoryRightSection.appendChild(directoryName);
        directoryRightSection.appendChild(directoryButton);
        directorySection.appendChild(directoryLabel);
        directorySection.appendChild(directoryRightSection);
        savePathSection.appendChild(directorySection);

        settingsContent.appendChild(savePathSection);
        settingsContent.appendChild(templateSection);

        // Export Options Section
        const exportOptionsSection = makeElement(
            "div", {}, {
                marginTop: "20px",
                marginBottom: "15px",
                padding: "15px",
                background: "#2a2a2a",
                borderRadius: "10px",
                boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
                transition: "all 200ms ease",
                cursor: "default",
            },
        );

        const exportOptionsTitle = makeElement(
            "h3", {
                textContent: "Export Options",
            }, {
                margin: "0 0 15px 0",
                fontSize: "16px",
                color: "#fff",
                fontWeight: "bold",
            },
        );
        exportOptionsSection.appendChild(exportOptionsTitle);

        // Use character's chat name toggle
        const chatNameToggle = createToggle(
            "useChatNameForName",
            "Use character's chat name",
            "Uses chat name for the character name instead of label name.",
            useChatNameForName,
        );
        chatNameToggle.input.addEventListener("change", (e) => {
            useChatNameForName = e.target.checked;
        });
        exportOptionsSection.appendChild(chatNameToggle.container);

        // Apply {{char}} tokenization toggle
        const charTokenToggle = createToggle(
            "applyCharToken",
            "Apply {{char}} tokenization",
            "Toggle replacement of character names with {{char}} placeholder.",
            applyCharToken,
        );
        charTokenToggle.input.addEventListener("change", (e) => {
            applyCharToken = e.target.checked;
        });
        exportOptionsSection.appendChild(charTokenToggle.container);

        // Include Creator Notes toggle
        const creatorNotesToggle = createToggle(
            "includeCreatorNotes",
            "Include creator notes",
            "Include creator notes in exported files",
            localStorage.getItem("includeCreatorNotes") !== "false",
        );
        exportOptionsSection.appendChild(creatorNotesToggle.container);

        settingsContent.appendChild(exportOptionsSection);

        // Advanced Section
        const advancedSection = makeElement(
            "div", {}, {
                marginTop: "20px",
                marginBottom: "15px",
                padding: "15px",
                background: "#2a2a2a",
                borderRadius: "10px",
                boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
                transition: "all 200ms ease",
                cursor: "default",
            },
        );

        const advancedTitle = makeElement(
            "h3", {
                textContent: "Advanced",
            }, {
                margin: "0 0 15px 0",
                fontSize: "16px",
                color: "#fff",
                fontWeight: "bold",
            },
        );
        advancedSection.appendChild(advancedTitle);

        // Show Debug Logs toggle
        const debugLogsToggle = createToggle(
            "showDebugLogs",
            "Debug logs",
            "Show verbose console logging for debugging",
            localStorage.getItem("showDebugLogs") === "true",
        );
        advancedSection.appendChild(debugLogsToggle.container);

        settingsContent.appendChild(advancedSection);

        const tabs = {
            export: {
                content: exportContent,
                tab: exportTab,
                active: true,
            },
            settings: {
                content: settingsContent,
                tab: settingsTab,
                active: false,
            },
        };

        function switchTab(tabKey) {
            const previousTab = currentActiveTab;
            currentActiveTab = tabKey;

            // Save filename draft and clean up toggle states when switching AWAY from settings
            if (previousTab === "settings" && tabKey !== "settings") {
                const templateInput = document.querySelector(
                    'input[placeholder="Enter filename template"]',
                );
                if (templateInput && templateInput.value) {
                    localStorage.setItem("filenameTemplateDraft", templateInput.value);
                }
            }

            // Too many flaws, will fix the toggle state visual restoration later
            // The commented code below is the original (flawed version) logic for restoring toggle states

            //   // Clean up any lingering toggle visual states
            //   document.querySelectorAll(".toggle-wrapper").forEach((wrapper) => {
            //     const container = wrapper.closest("div");
            //     if (container) {
            //       // Reset any stuck styles and classes
            //       container.style.transform = "";
            //       container.style.borderColor = "";
            //       container.style.boxShadow = "";
            //       container.className = container.className.replace(
            //         /toggle-container-(active|inactive)/g,
            //         "",
            //       );
            //     }
            //   });
            // }

            // Only restore when switching TO settings (not from settings)
            if (tabKey === "settings" && previousTab !== "settings") {
                // Immediate restoration before settings tab loads
                inputStateManager.restoreAll(false);

                // Re-initialize scrollbar when switching to settings with proper cleanup
                requestAnimationFrame(() => {
                    // Clean up any existing scrollbar state
                    const existingTrack = settingsContent.parentElement?.querySelector(
                        ".custom-scrollbar-track",
                    );
                    if (existingTrack) {
                        existingTrack.remove();
                    }

                    const newScrollbar = createCustomScrollbar(settingsContent);
                    newScrollbar.init();

                    // Restore complete toggle visual states
                    document.querySelectorAll(".toggle-wrapper").forEach((wrapper) => {
                        const input = wrapper.querySelector('input[type="checkbox"]');
                        const container = wrapper.closest("div");
                        const slider = wrapper.querySelector(".slider");
                        const sliderBefore = wrapper.querySelector(".slider-before");

                        if (input && container && slider && sliderBefore) {
                            const isChecked = input.checked;

                            // // Clear any existing state classes and inline styles
                            // container.style.borderColor = "";
                            // container.style.boxShadow = "";
                            // container.style.transform = "";
                            // container.className = container.className.replace(
                            //   /toggle-container-(active|inactive)/g,
                            //   "",
                            // );

                            // // Apply correct state class
                            // container.classList.add(
                            //   isChecked
                            //     ? "toggle-container-active"
                            //     : "toggle-container-inactive",
                            // );

                            // Restore slider styles
                            slider.style.backgroundColor = isChecked ? "#0080ff" : "#ccc";
                            slider.style.boxShadow = isChecked ?
                                "0 0 8px rgba(0, 128, 255, 0.3)" :
                                "none";

                            // Restore slider before styles
                            sliderBefore.style.transform = isChecked ?
                                "translateX(16px)" :
                                "translateX(0)";
                            sliderBefore.style.boxShadow = isChecked ?
                                "0 0 2px rgba(0,0,0,0.2), 0 0 8px rgba(0,128,255,0.5)" :
                                "0 0 2px rgba(0,0,0,0.2)";

                            // Restore wrapper class
                            // wrapper.classList.toggle("active", isChecked);
                        }
                    });
                });

                // Use requestAnimationFrame to ensure DOM is ready for draft restoration
                requestAnimationFrame(() => {
                    const templateInput = document.querySelector(
                        'input[placeholder="Enter filename template"]',
                    );
                    if (templateInput) {
                        const savedDraft = localStorage.getItem("filenameTemplateDraft");
                        if (savedDraft && savedDraft !== templateInput.value) {
                            templateInput.value = savedDraft;
                            filenameTemplate = savedDraft;
                            templateInput.dispatchEvent(
                                new Event("input", {
                                    bubbles: true
                                }),
                            );
                        }
                    }

                    // Auto-restore removed for Save Path input
                });
            }
            animationTimeouts.forEach((timeoutId) => clearTimeout(timeoutId));
            animationTimeouts = [];

            Object.entries(tabs).forEach(([key, {
                content,
                tab
            }]) => {
                const isActive = key === tabKey;

                tab.style.opacity = isActive ? "1" : "0.7";
                tab.style.transform = isActive ? "translateY(-2px)" : "";

                const indicator = tab.lastChild;
                if (indicator) {
                    if (isActive) {
                        indicator.style.background = ACTIVE_TAB_COLOR;
                        indicator.style.transform = "scaleX(1)";
                    } else {
                        indicator.style.background = INACTIVE_TAB_COLOR;
                        indicator.style.transform = "scaleX(0.5)";
                    }
                }

                content.style.display = "block";
                content.style.pointerEvents = isActive ? "auto" : "none";

                if (isActive) {
                    content.style.opacity = "0";
                    content.style.transform = "scale(0.95)";

                    void content.offsetWidth;

                    requestAnimationFrame(() => {
                        content.style.opacity = "1";
                        content.style.transform = "scale(1)";
                    });
                } else {
                    requestAnimationFrame(() => {
                        content.style.opacity = "0";
                        content.style.transform = "scale(0.95)";
                    });

                    const hideTimeout = setTimeout(() => {
                        if (!tabs[key].active) {
                            content.style.display = "none";
                            // Clean up scrollbar when hiding settings tab
                            if (key === "settings") {
                                const existingTrack = content.parentElement?.querySelector(
                                    ".custom-scrollbar-track",
                                );
                                if (existingTrack) {
                                    existingTrack.remove();
                                }
                            }
                        }
                    }, TAB_ANIMATION_DURATION);
                    animationTimeouts.push(hideTimeout);
                }

                tabs[key].active = isActive;
            });

            currentTab = tabKey;
            try {
                sessionStorage.setItem("lastActiveTab", tabKey);
            } catch (e) {
                console.warn("Failed to save tab state to sessionStorage", e);
            }
        }

        const handleTabClick = (e) => {
            const tt = document.getElementById("char-export-tooltip");
            if (tt) {
                tt.style.opacity = "0";
                const offsetHide = TOOLTIP_SLIDE_FROM_RIGHT ?
                    -TOOLTIP_SLIDE_OFFSET :
                    TOOLTIP_SLIDE_OFFSET;
                tt.style.transform = `translateX(${offsetHide}px)`;
            }
            const tabKey = e.target === exportTab ? "export" : "settings";
            if (!tabs[tabKey].active) {
                switchTab(tabKey);
            }
        };

        exportTab.onclick = handleTabClick;
        settingsTab.onclick = handleTabClick;

        Object.entries(tabs).forEach(([key, {
            content
        }]) => {
            const isActive = key === currentTab;

            content.style.display = isActive ? "block" : "none";
            content.style.opacity = isActive ? "1" : "0";
            content.style.transform = isActive ? "scale(1)" : "scale(0.95)";
        });

        switchTab(currentTab);
        document.body.appendChild(gui);

        // Add backdrop with smooth linear animation
        const backdrop = makeElement(
            "div", {
                id: "char-export-backdrop",
            }, {
                position: "fixed",
                top: "0",
                left: "0",
                width: "100%",
                height: "100%",
                background: "rgba(0, 0, 0, 0)",
                backdropFilter: "blur(0px)",
                zIndex: "9999",
                opacity: "0",
                transition: "all 150ms ease-out",
            },
        );

        document.body.insertBefore(backdrop, gui);

        // Set initial modal state
        gui.style.opacity = "0";
        gui.style.transform = "translate(-50%, -50%) scale(0.95)";
        gui.style.filter = "blur(3px)";
        gui.style.transition = "all 150ms ease-out";

        // Start backdrop animation smoothly - no instant fill
        requestAnimationFrame(() => {
            backdrop.style.opacity = "1";
            backdrop.style.background = "rgba(0, 0, 0, 0.4)";
            backdrop.style.backdropFilter = "blur(3px)";

            gui.style.opacity = "1";
            gui.style.transform = "translate(-50%, -50%) scale(1)";
            gui.style.filter = "blur(0px) drop-shadow(0 15px 35px rgba(0,0,0,0.3))";
        });

        document.addEventListener("mousedown", handleDialogOutsideClick);
        document.addEventListener("mouseup", handleDialogOutsideClick);
    }

    function toggleUIState() {
        // Clear any existing animations
        animationTimeouts.forEach((timeoutId) => clearTimeout(timeoutId));
        animationTimeouts = [];

        if (guiElement && document.body.contains(guiElement)) {
            if (viewActive) {
                // If reopening while closing, get current state and resume
                const backdrop = document.getElementById("char-export-backdrop");
                const currentGuiOpacity =
                    parseFloat(getComputedStyle(guiElement).opacity) || 0;
                const currentBackdropOpacity = backdrop ?
                    parseFloat(getComputedStyle(backdrop).opacity) || 0 :
                    0;

                // Resume opening animation from current state - ensure smooth animation
                guiElement.style.display = "flex";

                // Force a reflow to ensure display change is applied
                void guiElement.offsetHeight;

                requestAnimationFrame(() => {
                    guiElement.style.transition = "all 150ms ease-out";
                    guiElement.style.opacity = "1";
                    guiElement.style.transform = "translate(-50%, -50%) scale(1)";
                    guiElement.style.filter =
                        "blur(0px) drop-shadow(0 15px 35px rgba(0,0,0,0.3))";

                    if (backdrop) {
                        backdrop.style.transition = "all 150ms ease-out";
                        backdrop.style.opacity = "1";
                        backdrop.style.background = "rgba(0, 0, 0, 0.4)";
                        backdrop.style.backdropFilter = "blur(3px)";
                    }
                });
            } else {
                const backdrop = document.getElementById("char-export-backdrop");

                // Get current animation state to resume from
                const currentGuiOpacity =
                    parseFloat(getComputedStyle(guiElement).opacity) || 1;
                const currentBackdropOpacity = backdrop ?
                    parseFloat(getComputedStyle(backdrop).opacity) || 1 :
                    0;

                // Calculate current scale from transform
                const transformMatrix = getComputedStyle(guiElement).transform;
                let currentScale = 1;
                if (transformMatrix !== "none") {
                    const values = transformMatrix.match(/-?\d+\.?\d*/g);
                    if (values && values.length >= 6) {
                        currentScale = parseFloat(values[0]); // Get scale from matrix
                    }
                }

                // Apply smooth exit transition with proper timing
                requestAnimationFrame(() => {
                    guiElement.style.transition = "all 120ms ease-in";
                    guiElement.style.opacity = "0";
                    guiElement.style.transform = "translate(-50%, -50%) scale(0.9)";
                    guiElement.style.filter = "blur(4px)";

                    if (backdrop) {
                        backdrop.style.transition = "all 120ms ease-in";
                        backdrop.style.opacity = "0";
                        backdrop.style.background = "rgba(0, 0, 0, 0)";
                        backdrop.style.backdropFilter = "blur(0px)";
                    }
                });

                const removeTimeout = setTimeout(() => {
                    if (!viewActive && guiElement && document.body.contains(guiElement)) {
                        document.body.removeChild(guiElement);
                        const backdrop = document.getElementById("char-export-backdrop");
                        if (backdrop) backdrop.remove();
                        document.removeEventListener("mousedown", handleDialogOutsideClick);
                        document.removeEventListener("mouseup", handleDialogOutsideClick);
                        guiElement = null;
                    }
                }, 140);
                animationTimeouts.push(removeTimeout);
            }
        } else if (viewActive) {
            createUI();
        }
    }

    /**
     * Centralized input state manager with immediate restoration
     * Handles DOM queries, variable sync, and immediate updates with retry logic
     * @param {boolean} force - Force restoration regardless of current value
     * @param {number} retryCount - Internal retry counter for DOM queries
     */
    function createInputStateManager() {
        const SELECTORS = {
            filename: 'input[placeholder="Enter filename template"]',
        };

        const DEFAULTS = {
            filename: "{name}",
        };

        const STATE_KEYS = {
            filename: "filenameTemplate",
        };

        function restoreInput(type, force = false, retryCount = 0) {
            const input = document.querySelector(SELECTORS[type]);

            if (!input) {
                // Retry with RAF if element not found (during tab transitions)
                if (retryCount < 5) {
                    requestAnimationFrame(() =>
                        restoreInput(type, force, retryCount + 1),
                    );
                }
                return;
            }

            const savedValue =
                localStorage.getItem(STATE_KEYS[type]) || DEFAULTS[type];
            const needsRestore = force || input.value.trim() === "";

            if (needsRestore) {
                input.value = savedValue;
                // Sync global variables immediately
                if (type === "filename") {
                    window.filenameTemplate = savedValue;
                    filenameTemplate = savedValue;
                }

                // Trigger input event for UI updates
                input.dispatchEvent(new Event("input", {
                    bubbles: true
                }));
            }
        }

        return {
            restoreAll: (force = false) => {
                if (restorationInProgress) return;
                restorationInProgress = true;

                restoreInput("filename", force);

                // Reset flag after completion
                setTimeout(() => {
                    restorationInProgress = false;
                }, 50);
            },
            restoreFilename: (force = false) => restoreInput("filename", force),
        };
    }

    const inputStateManager = createInputStateManager();

    function closeV() {
        if (!viewActive) return;

        // Save filename template draft before closing
        const templateInput = document.querySelector(
            'input[placeholder="Enter filename template"]',
        );
        if (templateInput && templateInput.value) {
            localStorage.setItem("filenameTemplateDraft", templateInput.value);
        }

        // Restore IMMEDIATELY before any close logic or animations
        inputStateManager.restoreAll(false);

        // Use RAF to ensure restoration completes before UI animations
        requestAnimationFrame(() => {
            viewActive = false;
            toggleUIState();
        });
    }

    let isMouseDownInside = false;

    function handleDialogOutsideClick(e) {
        const gui = document.getElementById("char-export-gui");
        const backdrop = document.getElementById("char-export-backdrop");

        if (e.type === "mousedown") {
            isMouseDownInside = gui && gui.contains(e.target);
        } else if (e.type === "mouseup") {
            const isMouseUpOutside = !gui || !gui.contains(e.target);
            if (!isMouseDownInside && isMouseUpOutside) {
                closeV();
            }
            isMouseDownInside = false;
        }
    }

    /* ============================
       ==      INTERCEPTORS     ==
       ============================ */
    function interceptNetwork() {
        if (networkInterceptActive) return;
        networkInterceptActive = true;

        const origXHR = XMLHttpRequest.prototype.open;
        XMLHttpRequest.prototype.open = function(method, url) {
            this.addEventListener("load", () => {
                if (url.includes("generateAlpha")) modifyResponse(this.responseText);
                if (url.includes("/hampter/chats/"))
                    modifyChatResponse(this.responseText);
            });
            return origXHR.apply(this, arguments);
        };

        const origFetch = window.fetch;
        window.fetch = function(input, init) {
            const url = typeof input === "string" ? input : input?.url;

            if (url && (url.includes("skibidi.com") || url.includes("proxy"))) {
                if (shouldInterceptNext && exportFormat) {
                    setTimeout(() => modifyResponse("{}"), 300);
                    return Promise.resolve(new Response("{}"));
                }
                return Promise.resolve(
                    new Response(
                        JSON.stringify({
                            error: "Service unavailable",
                        }),
                    ),
                );
            }

            try {
                return origFetch.apply(this, arguments).then((res) => {
                    if (res.url?.includes("generateAlpha"))
                        res.clone().text().then(modifyResponse);
                    if (res.url?.includes("/hampter/chats/"))
                        res.clone().text().then(modifyChatResponse);
                    return res;
                });
            } catch (e) {
                return Promise.resolve(new Response("{}"));
            }
        };
    }

    function modifyResponse(text) {
        if (!shouldInterceptNext) return;
        shouldInterceptNext = false;
        try {
            const json = JSON.parse(text);
            const sys = json.messages.find((m) => m.role === "system")?.content || "";
            let initMsg = "";
            if (chatData?.chatMessages?.length) {
                const msgs = chatData.chatMessages;
                initMsg = msgs[msgs.length - 1].message;
            }
            const header = document.querySelector("p.chakra-text.css-1nj33dt");
            const headerName = header?.textContent
                .match(/Chat with\s+(.*)$/)?.[1]
                ?.trim();
            const fullName = (
                chatData?.character?.chat_name ||
                chatData?.character?.name ||
                ""
            ).trim();
            const nameFirst = (chatData?.character?.name || "")
                .trim()
                .split(/\s+/)[0];
            const charName = fullName || nameFirst || headerName || "char";
            let charBlock = extractTagContent(sys, fullName);
            if (!charBlock) {
                charBlock = extractTagContent(sys, nameFirst || charName);
            }
            const scen = extractTagContent(sys, "scenario");
            const rawExs = extractTagContent(sys, "example_dialogs");
            const exs = rawExs.replace(
                /^\s*Example conversations between[^:]*:\s*/,
                "",
            );
            const userName =
                document.documentElement.innerHTML.match(
                    /\\"name\\":\\"([^\\"]+)\\"/,
                )?.[1] || "";
            switch (exportFormat) {
                case "txt": {
                    saveAsTxt(charBlock, scen, initMsg, exs, charName, userName);
                    break;
                }
                case "png": {
                    saveAsPng(charName, charBlock, scen, initMsg, exs, userName);
                    break;
                }
                case "json": {
                    saveAsJson(charName, charBlock, scen, initMsg, exs, userName);
                    break;
                }
            }
            exportFormat = null;
        } catch (err) {
            console.error("Error processing response:", err);
        }
    }

    function modifyChatResponse(text) {
        try {
            if (!text || typeof text !== "string" || !text.trim()) return;

            const data = JSON.parse(text);
            if (data && data.character) {
                chatData = data;
            }
        } catch (err) {
            // ignore parsing errors
        }
    }

    /* ============================
       ==      CORE LOGIC       ==
       ============================ */
    async function getCharacterMeta() {
        // ---------- BEGIN Method 1 helpers ----------
        const findCharacter = (obj) => {
            if (!obj || typeof obj !== "object") return null;
            if ("showdefinition" in obj && "name" in obj && "id" in obj) return obj;
            for (const key of Object.keys(obj)) {
                const res = findCharacter(obj[key]);
                if (res) return res;
            }
            return null;
        };

        const extractFromJson = (json) => {
            if (!json) return null;
            const charObj = findCharacter(json);
            if (!charObj) {
                if (localStorage.getItem("showDebugLogs") === "true") {
                    console.log("[getCharacterMeta] Method 1: no character object found");
                }
                return null;
            }
            if (localStorage.getItem("showDebugLogs") === "true") {
                console.log(
                    "[getCharacterMeta] Method 1: character object located, showdefinition=",
                    charObj.showdefinition,
                );
            }

            const {
                name: rawName = "",
                chat_name: chatName = "",
                description: creatorNotesRaw = "",
                creator = {},
                personality: personalityRaw = "",
                scenario: scenarioRaw = "",
                first_message: firstMsgRaw = "",
                example_dialogs: exDialogsRaw = "",
                showdefinition = false,
                id = "",
            } = charObj;

            if (!showdefinition) return null;

            const name = (
                chatName && !useChatNameForName ? rawName : chatName || rawName
            ).trim();

            let characterVersion = getCharacterCardUrl(id);
            if (chatName && !useChatNameForName) {
                characterVersion += `\nChat Name: ${chatName.trim()}`;
            }

            // Verbose logging for Method 1 (JSON.parse when showdefinition=true)
            if (localStorage.getItem("showDebugLogs") === "true") {
                const src = "JSON.parse (showdefinition=true)";
                console.log("[getCharacterMeta] name", name, `<= ${src}`);
                console.log(
                    "[getCharacterMeta] personality",
                    personalityRaw,
                    `<= ${src}`,
                );
                console.log("[getCharacterMeta] scenario", scenarioRaw, `<= ${src}`);
                console.log(
                    "[getCharacterMeta] first_message",
                    firstMsgRaw,
                    `<= ${src}`,
                );
                console.log(
                    "[getCharacterMeta] example_dialogs",
                    exDialogsRaw,
                    `<= ${src}`,
                );
                console.log(
                    "[getCharacterMeta] creator_notes",
                    creatorNotesRaw,
                    `<= ${src}`,
                );
            }
            return {
                characterVersion,
                characterCardUrl: getCharacterCardUrl(id),
                name,
                creatorNotes: creatorNotesRaw,
                personality: stripWatermark(personalityRaw),
                scenario: stripWatermark(scenarioRaw),
                firstMessage: stripWatermark(firstMsgRaw),
                exampleDialogs: stripWatermark(exDialogsRaw),
                definitionExposed: true,
            };
        };
        // ---------- END Method 1 helpers ----------
        // ---------- BEGIN Method 2 helpers (chatData fallback) ----------
        // Method 2 (showdefinition false) reads directly from chatData for character information.
        // No additional helper functions are required for this path.
        // ---------- END Method 2 helpers ----------
        const charId = chatData?.character?.id;
        if (!charId)
            return {
                creatorUrl: "",
                characterVersion: "",
                characterCardUrl: "",
                name: "",
                creatorNotes: "",
                personality: "",
                scenario: "",
                firstMessage: "",
                exampleDialogs: "",
                definitionExposed: false,
            };

        // Check cache first - return cached values unless debug logging is enabled
        const skipCache = localStorage.getItem("showDebugLogs") === "true";
        if (
            !skipCache &&
            characterMetaCache.id === charId &&
            characterMetaCache.useChatNameForName === useChatNameForName
        ) {
            if (localStorage.getItem("showDebugLogs") === "true") {
                console.log(
                    "[getCharacterMeta] Returning cached result for character:",
                    charId,
                );
            }
            return {
                creatorUrl: characterMetaCache.creatorUrl || "",
                characterVersion: characterMetaCache.characterVersion || "",
                characterCardUrl: characterMetaCache.characterCardUrl || "",
                name: characterMetaCache.name || "",
                creatorNotes: characterMetaCache.creatorNotes || "",
                personality: characterMetaCache.personality || "",
                scenario: characterMetaCache.scenario || "",
                firstMessage: characterMetaCache.firstMessage || "",
                exampleDialogs: characterMetaCache.exampleDialogs || "",
                definitionExposed: characterMetaCache.definitionExposed || false,
            };
        }

        const characterCardUrl = getCharacterCardUrl(charId);
        let meta = {
            ...blankMeta,
            characterVersion: characterCardUrl,
            characterCardUrl,
        };
        try {
            const response = await fetch(characterCardUrl);
            const html = await response.text();
            const doc = new DOMParser().parseFromString(html, "text/html");
            // ---------- BEGIN Method 1 execution ----------
            let metaFromJson = null;
            try {
                if (localStorage.getItem("showDebugLogs") === "true") {
                    console.log("[getCharacterMeta] Method 1: scanning <script> tags");
                }
                const scripts = Array.from(doc.querySelectorAll("script"));
                for (const s of scripts) {
                    const txt = s.textContent || "";
                    if (!txt.includes("window.mbxM.push(JSON.parse(")) continue;

                    const m = txt.match(/JSON\.parse\(\s*("([\s\S]*?)")\s*\)/);
                    if (!m || !m[1]) continue;

                    let innerStr;
                    try {
                        innerStr = JSON.parse(m[1]);
                    } catch (_) {
                        continue;
                    }

                    let obj;
                    try {
                        obj =
                            typeof innerStr === "string" ? JSON.parse(innerStr) : innerStr;
                    } catch (_) {
                        continue;
                    }

                    metaFromJson = extractFromJson(obj);
                    if (metaFromJson) break;
                }
            } catch (parseErr) {
                console.error(
                    "[getCharacterMeta] JSON parse error (Method 1):",
                    parseErr,
                );
            }
            // ---------- END Method 1 execution ----------

            Object.assign(meta, metaFromJson || {}, {
                creatorUrl: getCreatorUrlFromDoc(doc),
                creatorNotes: chatData?.character?.description || "",
            });
        } catch (_) {}

        // Debug logging before cache assignment (shows every time when enabled)
        if (localStorage.getItem("showDebugLogs") === "true") {
            console.log(
                "[getCharacterMeta] creator_url",
                meta.creatorUrl,
                "<= getCreatorUrlFromDoc",
            );

            if (!meta.definitionExposed) {
                const src = "generateAlpha/chatData (showdefinition=false)";
                console.log(
                    "[getCharacterMeta] name",
                    meta.name ||
                    chatData?.character?.name ||
                    chatData?.character?.chat_name,
                    `<= ${src}`,
                );
                console.log(
                    "[getCharacterMeta] personality",
                    chatData?.character?.personality || "extracted from generateAlpha",
                    `<= ${src}`,
                );
                console.log(
                    "[getCharacterMeta] scenario",
                    chatData?.character?.scenario || "extracted from generateAlpha",
                    `<= ${src}`,
                );
                console.log(
                    "[getCharacterMeta] first_message",
                    chatData?.character?.first_message || "extracted from generateAlpha",
                    `<= ${src}`,
                );
                console.log(
                    "[getCharacterMeta] example_dialogs",
                    chatData?.character?.example_dialogs ||
                    "extracted from generateAlpha",
                    `<= ${src}`,
                );
                console.log(
                    "[getCharacterMeta] creator_notes",
                    chatData?.character?.description,
                    `<= ${src}`,
                );
            }
        }

        Object.assign(characterMetaCache, {
            id: charId,
            useChatNameForName,
            ...meta,
        });

        return meta;
    }

    async function buildTemplate(charBlock, scen, initMsg, exs) {
        const sections = [];
        const {
            creatorUrl,
            characterCardUrl,
            creatorNotes
        } =
        await getCharacterMeta();
        const includeCreatorNotes =
            localStorage.getItem("includeCreatorNotes") !== "false";

        const realName = chatData.character.name.trim();
        sections.push(`==== Name ====\n${realName}`);
        const chatName = (chatData.character.chat_name || realName).trim();
        sections.push(`==== Chat Name ====\n${chatName}`);
        if (charBlock) sections.push(`==== Description ====\n${charBlock.trim()}`);
        if (scen) sections.push(`==== Scenario ====\n${scen.trim()}`);
        if (initMsg) sections.push(`==== Initial Message ====\n${initMsg.trim()}`);
        if (exs) sections.push(`==== Example Dialogs ====\n${exs.trim()}`);
        sections.push(`==== Character Card ====\n${characterCardUrl}`);
        sections.push(`==== Creator ====\n${creatorUrl}`);
        if (includeCreatorNotes && creatorNotes)
            sections.push(`==== Creator Notes ====\n${creatorNotes}`);
        return sections.join("\n\n");
    }

    /**
     * Extracts the updated date from character page HTML
     * @param {Document} doc - Parsed HTML document from character page
     * @returns {string} - Date in format MM/DD/YYYY or empty string if not found
     */
    function extractUpdatedDate(doc) {
        try {
            const dateElement = doc.querySelector(".chakra-text.css-722v25");
            if (dateElement && dateElement.textContent) {
                return dateElement.textContent.trim();
            }
        } catch (err) {
            console.warn("[extractUpdatedDate] Failed to extract date:", err);
        }
        return "";
    }

    /**
     * Builds filename from template using available tokens
     * @param {string} template - Template string with tokens like {id}, {name}, etc.
     * @param {Object} tokens - Available token values
     * @returns {string} - Processed filename
     */
    function buildFilenameFromTemplate(template, tokens = {}) {
        if (!template || typeof template !== "string") {
            return tokens.name || tokens.chat_name || "card";
        }

        if (!template || template.trim() === "") {
            return "";
        }

        let result = template;

        // Step 1: Create unique placeholders for double brackets to prevent interference
        const placeholders = {};
        Object.entries(tokens).forEach(([key, value]) => {
            if (
                value !== undefined &&
                value !== null &&
                String(value).trim() !== ""
            ) {
                const placeholder = `__TEMP_DOUBLE_${key}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}__`;
                placeholders[placeholder] = `{${String(value)}}`;
                const doubleBracketRegex = new RegExp(
                    `\\{\\{${escapeRegExp(key)}\\}\\}`,
                    "g",
                );
                result = result.replace(doubleBracketRegex, placeholder);
            }
        });

        // Step 2: Handle single brackets normally
        Object.entries(tokens).forEach(([key, value]) => {
            if (
                value !== undefined &&
                value !== null &&
                String(value).trim() !== ""
            ) {
                const singleBracketRegex = new RegExp(
                    `\\{${escapeRegExp(key)}\\}`,
                    "g",
                );
                result = result.replace(singleBracketRegex, String(value));
            }
        });

        // Step 3: Replace placeholders with final double bracket values
        Object.entries(placeholders).forEach(([placeholder, finalValue]) => {
            result = result.replace(
                new RegExp(escapeRegExp(placeholder), "g"),
                finalValue,
            );
        });

        // Clean up any remaining unreplaced tokens only if they don't have values
        result = result.replace(/\{\{[^}]+\}\}/g, "");
        result = result.replace(/\{[^}]+\}/g, "");

        // Clean up multiple spaces and trim
        result = result.replace(/\s+/g, " ").trim();

        // Return actual result or fallback to "export" only if completely empty
        return result || "export";
    }

    /**
     * Gets all available tokens for filename template
     * @param {Object} meta - Character metadata from getCharacterMeta
     * @returns {Object} - Object with all available tokens
     */
    async function getFilenameTokens(meta) {
        const charId = chatData?.character?.id || "";
        let creatorName = meta?.creatorUrl ?
            meta.creatorUrl.split("/").pop() || "" :
            "";

        // Extract data from character JSON
        let updatedDate = "";
        let createdDate = "";

        // Extract all data from character JSON
        let tagsString = "";
        try {
            if (meta?.characterCardUrl) {
                const response = await fetch(meta.characterCardUrl);
                const html = await response.text();
                const doc = new DOMParser().parseFromString(html, "text/html");

                const scripts = Array.from(doc.querySelectorAll("script"));
                for (const script of scripts) {
                    const text = script.textContent || "";
                    if (text.includes("window.mbxM.push(JSON.parse(")) {
                        const match = text.match(/JSON\.parse\(\s*("([\s\S]*?)")\s*\)/);
                        if (match && match[1]) {
                            try {
                                let innerStr = JSON.parse(match[1]);
                                let obj =
                                    typeof innerStr === "string" ?
                                    JSON.parse(innerStr) :
                                    innerStr;

                                const debugEnabled =
                                    localStorage.getItem("showDebugLogs") === "true";
                                if (debugEnabled) {
                                    console.log("[getFilenameTokens] Found JSON object:", obj);
                                }

                                // Find the character store (nested structure)
                                let characterData = null;
                                for (const key in obj) {
                                    if (key.includes("characterStore") && obj[key]?.character) {
                                        characterData = obj[key].character;
                                        break;
                                    }
                                }

                                if (!characterData) {
                                    if (debugEnabled) {
                                        console.log(
                                            "[getFilenameTokens] No character data found in nested structure",
                                        );
                                    }
                                    continue;
                                }

                                if (debugEnabled) {
                                    console.log(
                                        "[getFilenameTokens] Found character data:",
                                        characterData,
                                    );
                                }

                                // Extract tags from character section only (including custom_tags)
                                const allTags = [];

                                if (characterData?.tags) {
                                    const regularTags = characterData.tags
                                        .filter((tag) => typeof tag.id === "number" && tag.id >= 2)
                                        .map((tag) => tag.name);
                                    allTags.push(...regularTags);
                                }

                                if (characterData?.custom_tags) {
                                    allTags.push(...characterData.custom_tags);
                                }

                                // Remove duplicates, filter out unwanted emojis, and format properly
                                const uniqueTags = allTags
                                    .filter((name, index, arr) => arr.indexOf(name) === index)
                                    .map((tag) => {
                                        // Remove unwanted emojis and clean up
                                        let cleanTag = tag
                                            .replace(/🦰/g, "")
                                            .replace(/_{2,}/g, "_")
                                            .replace(/\s{2,}/g, " ")
                                            .trim();

                                        // Handle emoji + text format
                                        if (/^[\p{Emoji}]/u.test(cleanTag)) {
                                            // Handle complex emojis like "❤️ 🔥 Smut" -> "❤️🔥_Smut"
                                            // First, combine consecutive emojis without spaces between them
                                            cleanTag = cleanTag.replace(
                                                /([\p{Emoji}\uFE0F]+)\s+([\p{Emoji}\uFE0F]+)/gu,
                                                "$1$2",
                                            );
                                            // Then replace the space after emoji group with underscore
                                            cleanTag = cleanTag.replace(
                                                /([\p{Emoji}\uFE0F]+)\s+/u,
                                                "$1_",
                                            );
                                            // Remove any remaining spaces
                                            cleanTag = cleanTag.replace(/\s/g, "");
                                        } else {
                                            // For non-emoji tags, just remove spaces
                                            cleanTag = cleanTag.replace(/\s/g, "");
                                        }

                                        return cleanTag;
                                    })
                                    .filter((tag) => tag.length > 0);
                                tagsString = uniqueTags.join(" ");

                                if (debugEnabled) {
                                    console.log(
                                        "[getFilenameTokens] Extracted tags:",
                                        tagsString,
                                    );
                                }

                                // Extract dates and creator from character JSON
                                if (characterData?.created_at) {
                                    const dateStr = characterData.created_at.split("T")[0];
                                    const [year, month, day] = dateStr.split("-");
                                    createdDate = `${parseInt(month)}-${parseInt(day)}-${year}`;
                                    if (debugEnabled) {
                                        console.log(
                                            "[getFilenameTokens] Extracted created date:",
                                            createdDate,
                                        );
                                    }
                                }

                                if (characterData?.updated_at) {
                                    const dateStr = characterData.updated_at.split("T")[0];
                                    const [year, month, day] = dateStr.split("-");
                                    updatedDate = `${parseInt(month)}-${parseInt(day)}-${year}`;
                                    if (debugEnabled) {
                                        console.log(
                                            "[getFilenameTokens] Extracted updated date:",
                                            updatedDate,
                                        );
                                    }
                                }

                                if (characterData?.creator_name) {
                                    creatorName = characterData.creator_name;
                                    if (debugEnabled) {
                                        console.log(
                                            "[getFilenameTokens] Extracted creator name:",
                                            creatorName,
                                        );
                                    }
                                }

                                break;
                            } catch (parseError) {
                                console.warn(
                                    "[getFilenameTokens] JSON parse error:",
                                    parseError,
                                );
                                continue;
                            }
                        }
                    }
                }
            }
        } catch (err) {
            console.warn("[getFilenameTokens] Failed to extract from JSON:", err);
        }

        return {
            id: charId,
            creator: creatorName,
            name: meta?.name || chatData?.character?.name || "",
            chat_name: chatData?.character?.chat_name || "",
            created: createdDate,
            updated: updatedDate,
            tags: tagsString,
        };
    }

    async function saveAsTxt(charBlock, scen, initMsg, exs, charName, userName) {
        const template = await buildTemplate(charBlock, scen, initMsg, exs);
        const tokenized = tokenizeNames(template, charName, userName);

        // Use filename template system
        const meta = await getCharacterMeta();
        const tokens = await getFilenameTokens(meta);
        const currentTemplate =
            localStorage.getItem("filenameTemplate") || "{name}";
        const fileName =
            buildFilenameFromTemplate(currentTemplate, tokens) || "export";

        saveFile(
            `${fileName}.txt`,
            new Blob([tokenized], {
                type: "text/plain",
            }),
        );
    }

    function tokenizeField(text, charName, userName) {
        if (!text) return text;
        const esc = (n) => escapeRegExp(n);
        const rules = [];
        if (applyCharToken && charName) {
            rules.push([
                new RegExp(`\\b${esc(charName)}('s)?\\b`, "gi"),
                (_, sfx) => `{{char}}${sfx || ""}`,
            ]);
        }
        if (userName) {
            rules.push([
                new RegExp(`\\b${esc(userName)}('s)?\\b`, "gi"),
                (_, sfx) => `{{user}}${sfx || ""}`,
            ]);
        }
        let out = rules.reduce((t, [rx, repl]) => t.replace(rx, repl), text);
        if (!applyCharToken && charName) {
            out = out.replace(/\{\{char\}\}/gi, charName);
        }
        return out;
    }

    /* ============================
       ==      INTERCEPTORS     ==
       ============================ */
    function extraction() {
        if (!exportFormat) return;
        if (
            !document.querySelector("span.css-yhlqn1") &&
            !document.querySelector("span.css-154nobl")
        )
            return;

        (async () => {
            const meta = await getCharacterMeta();

            // Method 1
            if (meta.definitionExposed) {
                const charName = meta.name;
                const userName =
                    document.documentElement.innerHTML.match(
                        /\\"name\\":\\"([^\\"]+)\\"/,
                    )?.[1] || "";
                switch (exportFormat) {
                    case "txt":
                        saveAsTxt(
                            meta.personality,
                            meta.scenario,
                            meta.firstMessage,
                            meta.exampleDialogs,
                            charName,
                            userName,
                        );
                        break;
                    case "png":
                        saveAsPng(
                            charName,
                            meta.personality,
                            meta.scenario,
                            meta.firstMessage,
                            meta.exampleDialogs,
                            userName,
                        );
                        break;
                    case "json":
                        saveAsJson(
                            charName,
                            meta.personality,
                            meta.scenario,
                            meta.firstMessage,
                            meta.exampleDialogs,
                            userName,
                        );
                        break;
                }
                exportFormat = null;
                return;
            }

            shouldInterceptNext = true;
            interceptNetwork();
            callApi();
        })();
    }

    function callApi() {
        try {
            const textarea = document.querySelector("textarea");
            if (!textarea) return;

            Object.getOwnPropertyDescriptor(
                HTMLTextAreaElement.prototype,
                "value",
            ).set.call(textarea, "extract-char");
            textarea.dispatchEvent(
                new Event("input", {
                    bubbles: true,
                }),
            );

            ["keydown", "keyup"].forEach((type) =>
                textarea.dispatchEvent(
                    new KeyboardEvent(type, {
                        key: "Enter",
                        code: "Enter",
                        bubbles: true,
                    }),
                ),
            );
        } catch (err) {
            // ignore errors
        }
    }

    /* ============================
       ==    CHARA CARD V2      ==
       ============================ */
    async function buildCharaCardV2(
        charName,
        charBlock,
        scen,
        initMsg,
        exs,
        userName,
    ) {
        const {
            creatorUrl,
            characterVersion,
            name: metaName,
            creatorNotes,
        } = await getCharacterMeta();

        // Tokenize relevant fields
        const tokenizedDesc = tokenizeField(charBlock, charName, userName);
        const tokenizedScen = tokenizeField(scen, charName, userName);
        const tokenizedExs = tokenizeField(exs, charName, userName);

        /* ----------------------
                 Resolve display name
              ---------------------- */
        let displayName;
        if (useChatNameForName) {
            // Prefer chat_name when toggle is enabled
            displayName = (
                chatData?.character?.chat_name ||
                metaName ||
                chatData?.character?.name ||
                ""
            ).trim();
        } else {
            // Prefer canonical name first
            displayName = (
                metaName ||
                chatData?.character?.name ||
                chatData?.character?.chat_name ||
                ""
            ).trim();
        }
        if (!displayName) displayName = "Unknown";

        /* --------------------
                 Build version text
              -------------------- */
        let versionText = characterVersion;
        if (useChatNameForName) {
            const canonicalName = (
                metaName ||
                chatData?.character?.name ||
                ""
            ).trim();
            if (canonicalName && canonicalName !== displayName) {
                versionText = `${characterVersion}\nName: ${canonicalName}`;
            }
        }

        const includeCreatorNotes =
            localStorage.getItem("includeCreatorNotes") !== "false";

        return {
            spec: "chara_card_v2",
            spec_version: "2.0",
            data: {
                name: displayName,
                description: tokenizedDesc.trim(),
                personality: "",
                scenario: tokenizedScen.trim(),
                first_mes: initMsg.trim(),
                mes_example: tokenizedExs.trim(),
                creator_notes: includeCreatorNotes ? creatorNotes : "",
                system_prompt: "",
                post_history_instructions: "",
                alternate_greetings: [],
                character_book: null,
                tags: [],
                creator: creatorUrl,
                character_version: versionText,
                extensions: {},
            },
        };
    }

    /* ============================
       ==       EXPORTERS       ==
       ============================ */
    async function saveAsJson(charName, charBlock, scen, initMsg, exs, userName) {
        const jsonData = await buildCharaCardV2(
            charName,
            charBlock,
            scen,
            initMsg,
            exs,
            userName,
        );

        // Use filename template system
        const meta = await getCharacterMeta();
        const tokens = await getFilenameTokens(meta);
        const currentTemplate =
            localStorage.getItem("filenameTemplate") || "{name}";
        const fileName =
            buildFilenameFromTemplate(currentTemplate, tokens) || "export";

        saveFile(
            `${fileName}.json`,
            new Blob([JSON.stringify(jsonData, null, 2)], {
                type: "application/json",
            }),
        );
    }

    async function saveAsPng(charName, charBlock, scen, initMsg, exs, userName) {
        try {
            const avatarImg = document.querySelector('img[src*="/bot-avatars/"]');
            if (!avatarImg) {
                alert("Character avatar not found.");
                return;
            }

            const cardData = await buildCharaCardV2(
                charName,
                charBlock,
                scen,
                initMsg,
                exs,
                userName,
            );

            const avatarResponse = await fetch(avatarImg.src);
            const avatarBlob = await avatarResponse.blob();

            const img = new Image();
            img.onload = () => {
                const canvas = document.createElement("canvas");
                canvas.width = img.width;
                canvas.height = img.height;

                const ctx = canvas.getContext("2d");
                ctx.drawImage(img, 0, 0);

                canvas.toBlob(async (blob) => {
                    try {
                        const arrayBuffer = await blob.arrayBuffer();
                        const pngData = new Uint8Array(arrayBuffer);

                        const jsonString = JSON.stringify(cardData);

                        const base64Data = btoa(unescape(encodeURIComponent(jsonString)));

                        const keyword = "chara";
                        const keywordBytes = new TextEncoder().encode(keyword);
                        const nullByte = new Uint8Array([0]);
                        const textBytes = new TextEncoder().encode(base64Data);

                        const chunkType = new Uint8Array([116, 69, 88, 116]); // "tEXt" in ASCII
                        const dataLength =
                            keywordBytes.length + nullByte.length + textBytes.length;

                        const lengthBytes = new Uint8Array(4);
                        lengthBytes[0] = (dataLength >>> 24) & 0xff;
                        lengthBytes[1] = (dataLength >>> 16) & 0xff;
                        lengthBytes[2] = (dataLength >>> 8) & 0xff;
                        lengthBytes[3] = dataLength & 0xff;

                        const crcData = new Uint8Array(
                            chunkType.length +
                            keywordBytes.length +
                            nullByte.length +
                            textBytes.length,
                        );
                        crcData.set(chunkType, 0);
                        crcData.set(keywordBytes, chunkType.length);
                        crcData.set(nullByte, chunkType.length + keywordBytes.length);
                        crcData.set(
                            textBytes,
                            chunkType.length + keywordBytes.length + nullByte.length,
                        );

                        const crc = computeCrc32(crcData, 0, crcData.length);
                        const crcBytes = new Uint8Array(4);
                        crcBytes[0] = (crc >>> 24) & 0xff;
                        crcBytes[1] = (crc >>> 16) & 0xff;
                        crcBytes[2] = (crc >>> 8) & 0xff;
                        crcBytes[3] = crc & 0xff;

                        let pos = 8; // Skip PNG signature
                        while (pos < pngData.length - 12) {
                            const length =
                                (pngData[pos] << 24) |
                                (pngData[pos + 1] << 16) |
                                (pngData[pos + 2] << 8) |
                                pngData[pos + 3];

                            const type = String.fromCharCode(
                                pngData[pos + 4],
                                pngData[pos + 5],
                                pngData[pos + 6],
                                pngData[pos + 7],
                            );

                            if (type === "IEND") break;
                            pos += 12 + length; // 4 (length) + 4 (type) + length + 4 (CRC)
                        }

                        const finalSize =
                            pngData.length +
                            lengthBytes.length +
                            chunkType.length +
                            dataLength +
                            crcBytes.length;
                        const finalPNG = new Uint8Array(finalSize);

                        finalPNG.set(pngData.subarray(0, pos));
                        let writePos = pos;

                        finalPNG.set(lengthBytes, writePos);
                        writePos += lengthBytes.length;
                        finalPNG.set(chunkType, writePos);
                        writePos += chunkType.length;
                        finalPNG.set(keywordBytes, writePos);
                        writePos += keywordBytes.length;
                        finalPNG.set(nullByte, writePos);
                        writePos += nullByte.length;
                        finalPNG.set(textBytes, writePos);
                        writePos += textBytes.length;
                        finalPNG.set(crcBytes, writePos);
                        writePos += crcBytes.length;

                        finalPNG.set(pngData.subarray(pos), writePos);

                        // Use filename template system
                        const meta = await getCharacterMeta();
                        const tokens = await getFilenameTokens(meta);
                        const currentTemplate =
                            localStorage.getItem("filenameTemplate") || "{name}";
                        const fileName =
                            buildFilenameFromTemplate(currentTemplate, tokens) || "export";

                        saveFile(
                            `${fileName}.png`,
                            new Blob([finalPNG], {
                                type: "image/png",
                            }),
                        );

                        console.log("Character card created successfully!");
                    } catch (err) {
                        console.error("Error creating PNG:", err);
                        alert("Failed to create PNG: " + err.message);
                    }
                }, "image/png");
            };

            img.src = URL.createObjectURL(avatarBlob);
        } catch (err) {
            console.error("Error creating PNG:", err);
            alert("Failed to create PNG: " + err.message);
        }
    }

    function computeCrc32(data, start, length) {
        let crc = 0xffffffff;

        for (let i = 0; i < length; i++) {
            const byte = data[start + i];
            crc = (crc >>> 8) ^ crc32Table[(crc ^ byte) & 0xff];
        }

        return ~crc >>> 0; // Invert and cast to unsigned 32-bit
    }

    const crc32Table = (() => {
        const table = new Uint32Array(256);

        for (let i = 0; i < 256; i++) {
            let crc = i;
            for (let j = 0; j < 8; j++) {
                crc = crc & 1 ? 0xedb88320 ^ (crc >>> 1) : crc >>> 1;
            }
            table[i] = crc;
        }

        return table;
    })();

    /* ============================
       ==       ROUTING         ==
       ============================ */
    function inChats() {
        const isInChat = /^\/chats\/\d+/.test(window.location.pathname);
        return isInChat;
    }

    function initialize() {
        if (hasInitialized || !inChats()) return;
        hasInitialized = true;
        shouldInterceptNext = false;
        networkInterceptActive = false;
        exportFormat = null;
        chatData = null;
        // Attempt to prefetch chat data before UI makes its own request (disabled)
        // prefetchChatData();

        document.removeEventListener("keydown", handleKeyDown);
        document.addEventListener("keydown", handleKeyDown);

        interceptNetwork();
    }

    function handleKeyDown(e) {
        if (!inChats()) return;
        if (
            e.key.toLowerCase() !== "t" ||
            e.ctrlKey ||
            e.metaKey ||
            e.altKey ||
            e.shiftKey
        )
            return;
        if (
            ["INPUT", "TEXTAREA"].includes(document.activeElement.tagName) ||
            document.activeElement.isContentEditable
        )
            return;

        if (!chatData || !chatData.character || !chatData.character.allow_proxy) {
            if (chatData && chatData.character) {
                alert("Proxy disabled — extraction aborted.");
            }
            return;
        }

        viewActive = !viewActive;
        toggleUIState();
    }

    function cleanup() {
        hasInitialized = false;
        const gui = document.getElementById("char-export-gui");
        if (gui) gui.remove();
        document.removeEventListener("keydown", handleKeyDown);
        viewActive = false;
        animationTimeouts.forEach((timeoutId) => clearTimeout(timeoutId));
        animationTimeouts = [];
    }

    function handleRoute() {
        if (inChats()) {
            initialize();
        } else {
            cleanup();
        }
    }

    /* ============================
       ==    EVENT LISTENERS    ==
       ============================ */

    // Initialize unified auto-restore system
    function initializeAutoRestore() {
        // Debounced restoration for window events to prevent conflicts
        const debouncedRestore = () => {
            if (!restorationInProgress) {
                inputStateManager.restoreAll(false);
            }
        };

        // Multiple event listeners for comprehensive coverage
        ["beforeunload", "pagehide"].forEach((event) => {
            window.addEventListener(event, debouncedRestore);
        });

        // Separate handler for visibility changes
        window.addEventListener("visibilitychange", () => {
            if (document.visibilityState === "hidden") {
                debouncedRestore();
            }
        });
    }

    // Initialize the auto-restore system
    initializeAutoRestore();

    // Enhanced tooltip prevention
    document.addEventListener("DOMContentLoaded", () => {
        const style = document.createElement("style");
        style.textContent = `
        /* Disable all browser tooltips inside the UI */
        #char-export-gui input,
        #char-export-gui input:hover,
        #char-export-gui input:focus,
        #char-export-gui textarea,
        #char-export-gui textarea:hover,
        #char-export-gui textarea:focus {
          title: "" !important;
        }

        #char-export-gui input[title],
        #char-export-gui textarea[title] {
          title: "" !important;
        }

        /* Enhanced toggle animations */
        .toggle-wrapper {
          transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
        }

        .toggle-wrapper:hover {
          transform: translateY(-1px) scale(1.005) !important;
          box-shadow: 0 6px 16px rgba(0,0,0,0.15) !important;
        }

        .toggle-wrapper.active {
          border-color: rgba(0, 128, 255, 0.4) !important;
          box-shadow: 0 4px 12px rgba(0, 128, 255, 0.15) !important;
        }
      `;
        document.head.appendChild(style);
    });

    /* ============================
       ==      ENTRYPOINT       ==
       ============================ */
    window.addEventListener(
        "load",
        () => {
            handleRoute();
        }, {
            once: true,
        },
    );
    window.addEventListener("popstate", () => {
        handleRoute();
    });

    ["pushState", "replaceState"].forEach((fn) => {
        const orig = history[fn];
        history[fn] = function(...args) {
            const res = orig.apply(this, args);
            setTimeout(handleRoute, 50);
            return res;
        };
    });
    handleRoute();
})();