BEST Cheat for Chess.com (Stockfish 18.0.0, 17.1.0 & 10.0.2, No Anti-Ban)

An extremely advanced Chess.com cheat menu with two powerful Stockfish models, one backup model, and countless customization options.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

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

(I already have a user script manager, let me install it!)

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

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

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

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

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

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

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name          BEST Cheat for Chess.com (Stockfish 18.0.0, 17.1.0 & 10.0.2, No Anti-Ban)
// @namespace     http://tampermonkey.net/
// @version       8.3.6
// @description   An extremely advanced Chess.com cheat menu with two powerful Stockfish models, one backup model, and countless customization options.
// @author        Ech0
// @copyright     2025, Ech0
// @license       MIT
// @match         https://www.chess.com/play/*
// @match         https://www.chess.com/game/*
// @match         https://www.chess.com/puzzles/*
// @match         https://www.chess.com/daily
// @connect       chess-api.com
// @connect       stockfish.online
// @grant         GM_getResourceText
// @grant         GM_getValue
// @grant         GM_setValue
// @grant         GM_xmlhttpRequest
// @resource      stockfish.js https://cdnjs.cloudflare.com/ajax/libs/stockfish.js/10.0.2/stockfish.js
// @run-at        document-idle
// ==/UserScript==

(function () {
    "use strict";

    // --- CONFIGURATION ---
    const CONFIG = {
        BOARD_SEL: "chess-board, wc-chess-board",
        LOOP_MS: 50,
        API: { MAX_DEPTH: 18, MAX_TIME: 2000 }
    };

    const PIECE_IMGS = {
        p: "https://upload.wikimedia.org/wikipedia/commons/c/c7/Chess_pdt45.svg",
        r: "https://upload.wikimedia.org/wikipedia/commons/f/ff/Chess_rdt45.svg",
        n: "https://upload.wikimedia.org/wikipedia/commons/e/ef/Chess_ndt45.svg",
        b: "https://upload.wikimedia.org/wikipedia/commons/9/98/Chess_bdt45.svg",
        q: "https://upload.wikimedia.org/wikipedia/commons/4/47/Chess_qdt45.svg",
        k: "https://upload.wikimedia.org/wikipedia/commons/f/f0/Chess_kdt45.svg",
        P: "https://upload.wikimedia.org/wikipedia/commons/4/45/Chess_plt45.svg",
        R: "https://upload.wikimedia.org/wikipedia/commons/7/72/Chess_rlt45.svg",
        N: "https://upload.wikimedia.org/wikipedia/commons/7/70/Chess_nlt45.svg",
        B: "https://upload.wikimedia.org/wikipedia/commons/b/b1/Chess_blt45.svg",
        Q: "https://upload.wikimedia.org/wikipedia/commons/1/15/Chess_qlt45.svg",
        K: "https://upload.wikimedia.org/wikipedia/commons/4/42/Chess_klt45.svg",
    };

    const STOCKFISH_ICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEGklEQVR4nO2ZW2gcVRjH/9+Z3ewm22xMNtVGU9RIxNqmFxF8sC0iFhF8UF980QcFL1jwaRELXnwQBC94UfBBEQtK0Yqi1LwgaL0k0DQm2zapm2az2d1kd2bO8f/M7Gw22U12052lB34wzMzO+Z/vO+d85ztnlkQIIYQQQgghhBBCSKtQSt1BCHmOEDKplLqD53n7x8fH9xBCfC2U0r2EkNcIIY/xPG9rIR4F8CGl9EEA+wghG5s9+yGl9F0A+9sKEEJ8B+A5AMcIIb6W/v8B4BCl9AkA+1oK8Ty/m1L6LID9hJCNzb75hFL6IoD9bQcopc8SQp4ghExt9mw/pfR5APtbcwH1C68W/l8B3wO463+xAOu5gH2EkG2EENSX8F4A+wkhG7mA+l3gVwD3tBCAUvoYIeQpQkh/s2f7KaVPAthfFw/4HsA+QsjGZt/sJ5Q+01oArvN9Qkh/s2f7KaWPE0L2112Au8D3AO4jhGxs9u0+SulTAPbXFfA9gP2EkI3NvttPKX0KwP66Ar4HsJ8QsrHZd/sppU8C2F9XwPcA7ieEbGz23X5K6RMA9tcV8D2A+wkhG5t9t59S+iSA/XUFfA9gPyFkY7Pv9lNKTwLYX1fA9wD2E0I2Nvt2H6X0KQD76wr4HsB9hJCNzb7bTyl9CsD+ugK+B7CfELKx2Xf7KaUPE0L2112Au8D3AO4jhGxs9u0+SulTAPbXFfA9gP2EkI3NvttPKX0KwP66Ar4HsJ8QsrHZd/sppU8B2F9XwPcA9hNCNjb7bj+l9CkA++sK+B7AfYSQjc2+208pfQrA/rYClNI9hJCnCCHTmz3bTyl9CsD+tgOU0mcIIU8RQqY3e7afUvo0gP1tBSilz1BKnwGwv60A/H8uQAh5DsB+QsjGZt98Qil9DsD+1gKU0ucIIc8QQqY2e7afUvo8gP2tBail0N8A7iOEbGz23X5K6fMA9tcV8D2A+wkhG5t9t59S+iSA/XUFfA9gPyFkY7Pv9lNKTwLYX1fA9wDuI4RsbPbd/v8U4H/fA0II8Ty/mxDiA7C/Lh7wPID9hJCNzb7dTyl9EcD+ungA8Ty/mxDiA7C/pQCldC+l9EUA+1sK8Ty/hxDya0rpCwD2txTg/7kAIeR5APtbut8ghBBC2pZ/ALy683b5qZ2oAAAAAElFTkSuQmCC";

    // --- STATE MANAGEMENT ---
    const state = {
        board: null,
        isThinking: !1,
        ui: {},
        lastRawFEN: "N/A",
        lastSentFEN: "",
        lastSanitizedBoardFEN: "",
        lastMoveResult: "Waiting for analysis...",
        lastLiveResult: "Depth | Evaluation: Best move will appear here.",
        lastPayload: "N/A",
        lastResponse: "N/A",
        moveTargetTime: 0,
        calculatedDelay: 0,
        localEngine: null,
        localConfigSent: !1,
        currentCloudRequest: null,
        currentBestMove: null,
        currentPV: [],
        analysisStartTime: 0,
        h: 180, s: 100, l: 50,
        newGameObserver: null,
        queueTimeout: null,
        localEval: null,
        localMate: null,
        localPV: null,
        localDepth: null,
        history: [],
        hasSavedCurrentGameResult: !1,
        lastSeenFEN: "",
        playingAs: null,
        visualTab: "move",

        // Visual Manager State
        visuals: [], // { id, type('analysis'|'history'), move, interval, isFading }
    };

    const DEFAULT_SETTINGS = {
        engineMode: "cloud",
        depth: 18,
        maxThinkingTime: 0,
        contempt: 100,
        searchMoves: "",
        autoRun: !0,
        autoMove: !0,
        autoQueue: !1,
        hideAfterMove: false,
        showPVArrows: !1,
        pvDepth: 5,
        pvShowNumbers: !1,
        pvCustomGradient: !1,
        pvStartColor: "#FFFF00",
        pvEndColor: "#FF0000",
        minDelay: 0,
        maxDelay: 0,
        highlightColor: "#00eeff",
        visualType: "outline",
        innerOpacity: 0.6,
        outerOpacity: 0.2,
        gradientBias: 0,
        arrowOpacity: 0.8,
        arrowWidth: 15,
        visualOutlineWidth: 5,
        visualOutlineOpacity: 0.5,
        visualOutlineGlow: !0,
        visualOutlineGlowRadius: 50,
        visualDuration: 0.6,
        visualFadeOut: !0,
        themeBg: "#222222",
        themeText: "#eeeeee",
        themeBorder: "#444444",
        themePrimary: "#81b64c",
        menuOpacity: 0.9,
        debugLogs: !1,
        enableHistory: !0,
        menuPosition: "top-right",
    };

    const settings = { ...DEFAULT_SETTINGS };

    // --- COLOR HELPERS ---
    const hexToRgb = (hex) => {
        const r = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return r ? { r: parseInt(r[1], 16), g: parseInt(r[2], 16), b: parseInt(r[3], 16) } : { r: 0, g: 0, b: 0 };
    };
    const rgbToHex = (r, g, b) => "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
    const rgbToHsl = (r, g, b) => {
        r /= 255; g /= 255; b /= 255;
        const max = Math.max(r, g, b), min = Math.min(r, g, b);
        let h, s, l = (max + min) / 2;
        if (max === min) h = s = 0;
        else {
            const d = max - min;
            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
            switch (max) {
                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
                case g: h = (b - r) / d + 2; break;
                case b: h = (r - g) / d + 4; break;
            }
            h /= 6;
        }
        return { h: h * 360, s: s * 100, l: l * 100 };
    };
    const hslToRgb = (h, s, l) => {
        let r, g, b;
        h /= 360; s /= 100; l /= 100;
        if (s === 0) r = g = b = l;
        else {
            const hue2rgb = (p, q, t) => {
                if (t < 0) t += 1;
                if (t > 1) t -= 1;
                if (t < 1 / 6) return p + (q - p) * 6 * t;
                if (t < 1 / 2) return q;
                if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
                return p;
            };
            const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
            const p = 2 * l - q;
            r = hue2rgb(p, q, h + 1 / 3);
            g = hue2rgb(p, q, h);
            b = hue2rgb(p, q, h - 1 / 3);
        }
        return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) };
    };

    // --- SAVE/LOAD HELPERS ---
    function saveSetting(key, val) {
        settings[key] = val;
        GM_setValue(`bot_${key}`, val);
    }

    function loadSettings() {
        Object.keys(DEFAULT_SETTINGS).forEach((k) => {
            const saved = GM_getValue(`bot_${k}`);
            if (saved !== undefined) settings[k] = saved;
        });
        state.history = GM_getValue("bot_history", []);
    }

    // --- BOARD FEN LOGIC ---
    function getRawBoardFEN() {
        if (!state.board?.game) return null;
        try {
            if (typeof state.board.game.getFEN === "function") return state.board.game.getFEN();
            if (typeof state.board.game.fen === "string") return state.board.game.fen;
            if (state.board.game.getPosition) return state.board.game.getPosition();
        } catch (e) {}
        return null;
    }
    function sanitizeFEN(rawFEN) {
        if (!rawFEN) return "";
        let parts = rawFEN.replace(/\s+/g, " ").trim().split(" ");
        if (parts.length < 6) {
            const def = ["w", "-", "-", "0", "1"];
            for (let i = parts.length; i < 6; i++) parts.push(def[i - 1]);
        }
        if (parts[3] && parts[3] !== "-") parts[3] = parts[3].toLowerCase();
        return parts.join(" ");
    }

    // --- VISUAL MANAGER ---
    const Visuals = {
        add: (move, type) => {
            if (!move) return;

            // FIX 1: Prevent Layer Stacking (The "Dimming" Cause)
            // If we are adding a HISTORY visual (finalized move), we MUST remove any existing ANALYSIS visuals.
            // Otherwise, the Analysis box sits underneath the History box. When History fades, Analysis remains (looking "dim").
            if (type === 'history') {
                Visuals.removeByType('history');
                Visuals.removeByType('analysis');
            } else if (type === 'analysis') {
                // If adding new analysis, clear old analysis so we don't clutter.
                Visuals.removeByType('analysis');
            }

            // FIX 2: Deterministic IDs
            // We use the move string in the ID. This guarantees we can't accidentally stack two boxes for "e2e4".
            const id = `vis-${type}-${move}`;

            // Check if this specific visual exists and remove it to reset the timer/animation
            const existingIdx = state.visuals.findIndex(v => v.id === id);
            if (existingIdx !== -1) {
                Visuals.remove(id);
            }

            // Draw immediately
            Visuals.draw(id, move);

            // FIX 3: Robust Persistence Loop
            // Checks every 50ms to ensure the visual stays on the board even if Chess.com refreshes the DOM.
            const interval = setInterval(() => {
                const vis = state.visuals.find(v => v.id === id);
                // Stop if the visual was removed or is currently fading out
                if (!vis || vis.isFading) {
                    clearInterval(interval);
                    return;
                }
                Visuals.draw(id, move);
            }, 50);

            const visualObj = {
                id,
                move,
                type,
                interval,
                isFading: false
            };

            state.visuals.push(visualObj);

            // Handle Timer for History moves
            if (type === 'history') {
                if (settings.visualDuration === -1) {
                    Visuals.remove(id);
                    return;
                }
                if (settings.visualDuration > 0) {
                    const ms = settings.visualDuration * 1000;
                    if (settings.visualFadeOut) {
                        setTimeout(() => Visuals.fadeOut(id), ms);
                    } else {
                        setTimeout(() => Visuals.remove(id), ms);
                    }
                }
            }
        },

        draw: (id, move) => {
            state.board = document.querySelector(CONFIG.BOARD_SEL);
            if (!state.board) return;

            // CHECK: Does the element already exist?
            const existing = document.querySelector(`.${id}`);
            if (existing) {
                // FIX 4: "Live Board" Check
                // If the element exists but is on a DETACHED board (old DOM from before opponent move),
                // remove it so we can redraw it on the new LIVE board.
                if (!state.board.contains(existing)) {
                    existing.remove();
                } else {
                    return; // Exists and is valid. Do nothing.
                }
            }

            const { r, g, b } = hexToRgb(settings.highlightColor);
            const col = (a) => `rgba(${r}, ${g}, ${b}, ${a})`;
            const from = move.substring(0, 2);
            const to = move.substring(2, 4);

            const drawBox = () => {
                [from, to].forEach((alg) => {
                    const sqId = `${alg.charCodeAt(0) - 96}${alg.charAt(1)}`;
                    const div = document.createElement("div");
                    div.className = `square-${sqId} bot-highlight ${id}`;
                    let baseStyle = `position: absolute; pointer-events: none !important; z-index: 1000000 !important; width: 12.5%; height: 12.5%; box-sizing: border-box; transition: none !important; `;

                    if (settings.visualType === "outline") {
                         let glow = settings.visualOutlineGlow ? `box-shadow: 0 0 ${settings.visualOutlineGlowRadius}px ${col(1)}, inset 0 0 ${settings.visualOutlineGlowRadius/2}px ${col(0.5)} !important;` : "";
                         div.style.cssText = baseStyle + `border: ${settings.visualOutlineWidth}px solid ${col(settings.visualOutlineOpacity)} !important; ${glow}`;
                    } else {
                        const bias = settings.gradientBias + "%";
                        div.style.cssText = baseStyle + `background: radial-gradient(closest-side, ${col(settings.innerOpacity)} ${bias}, ${col(settings.outerOpacity)} 100%) !important;`;
                    }
                    state.board.appendChild(div);
                });
            };

            if (settings.visualType === "arrow") {
                drawArrow(move, id);
            } else {
                drawBox();
            }
        },

        fadeOut: (id) => {
            const vis = state.visuals.find(v => v.id === id);
            if (!vis) return;

            // Stop the persistence interval so it doesn't fight the fade
            vis.isFading = true;
            clearInterval(vis.interval);

            const els = document.querySelectorAll(`.${id}`);
            els.forEach(el => {
                // Force CSS transition with !important to ensure it overrides any other styles
                el.style.setProperty("transition", `opacity ${settings.visualDuration}s linear`, "important");
                el.style.setProperty("opacity", "0", "important");
            });

            setTimeout(() => Visuals.remove(id), settings.visualDuration * 1000);
        },

        remove: (id) => {
            const idx = state.visuals.findIndex(v => v.id === id);
            if (idx !== -1) {
                clearInterval(state.visuals[idx].interval);
                state.visuals.splice(idx, 1);
            }
            // Remove ALL instances (cleans up any detached/ghost nodes)
            document.querySelectorAll(`.${id}`).forEach(el => el.remove());
        },

        removeByType: (type) => {
            const toRemove = state.visuals.filter(v => v.type === type);
            toRemove.forEach(v => Visuals.remove(v.id));
        }
    };
    // --- PV MANAGER (Fixes missing arrows) ---
    const PV = {
        interval: null,
        lastMoves: [],

        update: (pvMoves) => {
            PV.lastMoves = pvMoves || [];
            if (!settings.showPVArrows) {
                PV.clear();
                return;
            }
            PV.draw();
            // Persistence loop (checks every 100ms)
            if (!PV.interval) PV.interval = setInterval(PV.draw, 100);
        },

        clear: () => {
            document.querySelectorAll('.pv-arrow').forEach(el => el.remove());
        },

        draw: () => {
            state.board = document.querySelector(CONFIG.BOARD_SEL);
            if (!state.board) return;

            if (!settings.showPVArrows || !PV.lastMoves.length) {
                PV.clear();
                return;
            }

            // Cleanup detached nodes (board refresh check)
            const existing = document.querySelector('.pv-arrow');
            if (existing && !state.board.contains(existing)) {
                PV.clear();
            }

            const limit = Math.min(PV.lastMoves.length, settings.pvDepth);

            for (let i = 0; i < limit; i++) {
                const move = PV.lastMoves[i];
                const id = `pv-arrow-${i}`;

                // If arrow exists on live board with same move, skip redraw
                const el = document.querySelector(`.${id}`);
                if (el && state.board.contains(el)) {
                    if (el.dataset.move === move) continue;
                    el.remove(); // Move changed, redraw
                } else if (el) {
                    el.remove(); // Detached
                }

                // Calculate Color
                let color = settings.highlightColor;
                if (settings.pvCustomGradient) {
                    const start = hexToRgb(settings.pvStartColor);
                    const end = hexToRgb(settings.pvEndColor);
                    // Gradient calculation
                    const factor = limit === 1 ? 0 : i / (limit - 1);
                    const r = Math.round(start.r + factor * (end.r - start.r));
                    const g = Math.round(start.g + factor * (end.g - start.g));
                    const b = Math.round(start.b + factor * (end.b - start.b));
                    color = `rgb(${r},${g},${b})`;
                }

                drawPVArrow(move, id, color, i + 1);
            }

            // Remove excess arrows if PV got shorter
            let i = limit;
            while (document.querySelector(`.pv-arrow-${i}`)) {
                document.querySelectorAll(`.pv-arrow-${i}`).forEach(e => e.remove());
                i++;
            }
        }
    };

    function drawPVArrow(move, id, color, index) {
        if (!state.board) return;

        let isFlipped = state.board.classList.contains("flipped");
        // Fallback check for flipped board
        if (!isFlipped && state.board.game && state.board.game.getPlayingAs && state.board.game.getPlayingAs() === "b") isFlipped = true;

        const from = move.substring(0, 2);
        const to = move.substring(2, 4);

        const getCoords = (sq) => {
            const file = sq.charCodeAt(0) - 97;
            const rank = parseInt(sq[1]) - 1;
            let x, y;
            if (isFlipped) {
                x = (7 - file) * 12.5 + 6.25;
                y = rank * 12.5 + 6.25;
            } else {
                x = file * 12.5 + 6.25;
                y = (7 - rank) * 12.5 + 6.25;
            }
            return { x, y };
        };

        const start = getCoords(from);
        const end = getCoords(to);

        // Offset start/end slightly so arrows connect nicely in a chain
        // (Optional refinement: purely visual)

        const dx = end.x - start.x;
        const dy = end.y - start.y;
        const len = Math.sqrt(dx * dx + dy * dy);

        // Width based on settings or default
        const width = settings.arrowWidth || 15;
        const scale = width / 15; // normalize

        const headLen = 4 * scale;
        const headWidth = 3 * scale;
        const lineWidth = 1.0 * scale;

        if (len === 0) return;

        // SVG Creation
        const ns = "http://www.w3.org/2000/svg";
        const svg = document.createElementNS(ns, "svg");
        svg.setAttribute("class", `pv-arrow ${id}`);
        svg.dataset.move = move;
        svg.style.cssText = "position:absolute; top:0; left:0; width:100%; height:100%; pointer-events:none; z-index:900;"; // z-index lower than main move
        svg.setAttribute("viewBox", "0 0 100 100");

        // Arrow Math
        const ux = dx / len;
        const uy = dy / len;
        const endLineX = end.x - ux * headLen;
        const endLineY = end.y - uy * headLen;
        const px = -uy;
        const py = ux;

        const c1X = endLineX + px * (headWidth / 2);
        const c1Y = endLineY + py * (headWidth / 2);
        const c2X = endLineX - px * (headWidth / 2);
        const c2Y = endLineY - py * (headWidth / 2);

        const line = document.createElementNS(ns, "line");
        line.setAttribute("x1", start.x); line.setAttribute("y1", start.y);
        line.setAttribute("x2", endLineX); line.setAttribute("y2", endLineY);
        line.setAttribute("stroke", color);
        line.setAttribute("stroke-width", lineWidth);
        line.setAttribute("stroke-opacity", settings.arrowOpacity || 0.8);
        line.setAttribute("stroke-linecap", "round");

        const poly = document.createElementNS(ns, "polygon");
        poly.setAttribute("points", `${end.x},${end.y} ${c1X},${c1Y} ${c2X},${c2Y}`);
        poly.setAttribute("fill", color);
        poly.setAttribute("fill-opacity", settings.arrowOpacity || 0.8);

        svg.appendChild(line);
        svg.appendChild(poly);

        // Optional: Draw Number
        if (settings.pvShowNumbers) {
            const midX = (start.x + end.x) / 2;
            const midY = (start.y + end.y) / 2;
            const text = document.createElementNS(ns, "text");
            text.setAttribute("x", midX);
            text.setAttribute("y", midY);
            text.setAttribute("dy", "0.3em"); // vertical align
            text.setAttribute("text-anchor", "middle");
            text.setAttribute("fill", "#fff");
            text.setAttribute("font-size", "2.5");
            text.setAttribute("font-weight", "bold");
            text.setAttribute("stroke", "#000");
            text.setAttribute("stroke-width", "0.1");
            text.textContent = index;
            svg.appendChild(text);
        }

        state.board.appendChild(svg);
    }
    function drawArrow(move, id) {
        const { r, g, b } = hexToRgb(settings.highlightColor);
        const color = settings.highlightColor;
        const opacity = settings.arrowOpacity;
        const width = settings.arrowWidth;

        let isFlipped = !1;
        if (state.board.classList.contains("flipped")) isFlipped = !0;
        else if (state.board.game && state.board.game.getPlayingAs && state.board.game.getPlayingAs() === "b") isFlipped = !0;

        const from = move.substring(0, 2);
        const to = move.substring(2, 4);
        const getCoords = (sq) => {
            const file = sq.charCodeAt(0) - 97;
            const rank = parseInt(sq[1]) - 1;
            let x, y;
            if (isFlipped) {
                x = (7 - file) * 12.5 + 6.25;
                y = rank * 12.5 + 6.25;
            } else {
                x = file * 12.5 + 6.25;
                y = (7 - rank) * 12.5 + 6.25;
            }
            return { x, y };
        };
        const start = getCoords(from);
        const end = getCoords(to);
        const dx = end.x - start.x;
        const dy = end.y - start.y;
        const len = Math.sqrt(dx * dx + dy * dy);
        const scale = width / 15;
        const headLen = 4 * scale;
        const headWidth = 3 * scale;
        const lineWidth = 1.2 * scale;
        if (len === 0) return;
        const ux = dx / len;
        const uy = dy / len;
        const endLineX = end.x - ux * headLen;
        const endLineY = end.y - uy * headLen;
        const px = -uy;
        const py = ux;
        const corner1X = endLineX + px * (headWidth / 2);
        const corner1Y = endLineY + py * (headWidth / 2);
        const corner2X = endLineX - px * (headWidth / 2);
        const corner2Y = endLineY - py * (headWidth / 2);
        const ns = "http://www.w3.org/2000/svg";
        const svg = document.createElementNS(ns, "svg");

        svg.setAttribute("class", `bot-highlight ${id}`);
        svg.style.cssText = "position:absolute; top:0; left:0; width:100%; height:100%; pointer-events:none; z-index:200;";
        svg.setAttribute("viewBox", "0 0 100 100");

        const line = document.createElementNS(ns, "line");
        line.setAttribute("x1", start.x); line.setAttribute("y1", start.y);
        line.setAttribute("x2", endLineX); line.setAttribute("y2", endLineY);
        line.setAttribute("stroke", color); line.setAttribute("stroke-width", lineWidth);
        line.setAttribute("stroke-opacity", opacity);

        const polygon = document.createElementNS(ns, "polygon");
        polygon.setAttribute("points", `${end.x},${end.y} ${corner1X},${corner1Y} ${corner2X},${corner2Y}`);
        polygon.setAttribute("fill", color); polygon.setAttribute("fill-opacity", opacity);

        svg.appendChild(line);
        svg.appendChild(polygon);
        state.board.appendChild(svg);
    }

    // --- EVAL STATUS LOGIC ---
    function getEvalStatusData(val, isMate) {
        const pa = state.playingAs || 1;
        let relativeScore = (pa === 2) ? -val : val;

        if (isMate) {
            if (relativeScore > 0) return { text: "Significant Advantage (Mate)", color: "#00ff00" };
            return { text: "Significant Disadvantage (Mate)", color: "#ff0000" };
        }

        // Positive Thresholds (Advantage)
        if (relativeScore > 3) return { text: "Significant Advantage", color: "#00ff00" };
        if (relativeScore > 1.5) return { text: "Clear Advantage", color: "#55ff55" };
        if (relativeScore > 0.5) return { text: "Decisive Advantage", color: "#81b64c" };
        if (relativeScore > 0.25) return { text: "Slight Advantage", color: "#aaffaa" };

        // Neutral Threshold
        if (relativeScore >= -0.25) return { text: "Equal", color: "#aaaaaa" };

        // Negative Thresholds (Disadvantage)
        if (relativeScore >= -0.5) return { text: "Slight Disadvantage", color: "#ffaaaa" };
        if (relativeScore >= -1.5) return { text: "Decisive Disadvantage", color: "#ff7777" };
        if (relativeScore >= -3) return { text: "Clear Disadvantage", color: "#ff4444" };

        // Else (Less than -3)
        return { text: "Significant Disadvantage", color: "#ff0000" };
    }

    // --- ENGINE CORE ---
    function loadLocalEngine() {
        if (state.localEngine) return;
        try {
            const scriptContent = GM_getResourceText("stockfish.js");
            if (!scriptContent) throw new Error("Stockfish resource not found.");
            const blob = new Blob([scriptContent], { type: "application/javascript" });
            state.localEngine = new Worker(URL.createObjectURL(blob));
            state.localEngine.onmessage = handleLocalMessage;
            state.localEngine.onerror = (e) => handleError("Local Engine Error", e);
            [
                "ucinewgame",
                "isready",
                "setoption name MultiPV value 1",
                `setoption name Contempt value ${settings.contempt}`,
            ].forEach((c) => state.localEngine.postMessage(c));
            console.log("Stockfish 10 Local Loaded.");
        } catch (e) {
            handleError("Engine Load Fail", e);
        }
    }

    function triggerFallback() {
        if (settings.engineMode === 'local') return;
        console.warn("API Error detected. Switching to Local Stockfish 10 at Depth 12.");
        settings.engineMode = 'local';
        settings.depth = 12;
        saveSetting('engineMode', 'local');
        saveSetting('depth', 12);

        if(state.ui.selMode) state.ui.selMode.value = 'local';
        if(state.ui.inpDepth) state.ui.inpDepth.value = 12;
        state.lastMoveResult = "⚠️ API Error. Switched to Local.";

        loadLocalEngine();
        if(state.lastSanitizedBoardFEN) {
            analyzeLocal(state.lastSanitizedBoardFEN, 12);
        }
        updateUI();
    }

    function analyze(depth = settings.depth, fenOverride = null, isRetry = !1) {
        if (state.isThinking && !fenOverride && !isRetry) return;
        let finalFEN = fenOverride || sanitizeFEN(getRawBoardFEN());
        if (!finalFEN) return;
        state.lastRawFEN = finalFEN;
        state.lastSentFEN = finalFEN;
        if (!fenOverride) state.lastSanitizedBoardFEN = finalFEN;
        state.isThinking = !0;
        state.analysisStartTime = performance.now();
        const minMs = settings.minDelay * 1000;
        const maxMs = settings.maxDelay * 1000;
        const delay = Math.random() * (maxMs - minMs) + minMs;
        state.moveTargetTime = performance.now() + delay;
        state.calculatedDelay = (delay / 1000).toFixed(2);
        updateUI();
        if (settings.engineMode === "cloud") {
            analyzeCloud(finalFEN, depth, isRetry);
        } else if (settings.engineMode === "sfonline") {
            analyzeSF16(finalFEN, depth);
        } else {
            analyzeLocal(finalFEN, depth);
        }
    }

    function analyzeCloud(finalFEN, depth, isRetry) {
        const actualDepth = Math.min(depth, 18);
        const payload = {
            fen: finalFEN,
            depth: actualDepth,
            maxThinkingTime: Math.min(settings.maxThinkingTime, CONFIG.API.MAX_TIME),
            taskId: Math.random().toString(36).substring(7),
        };
        if (settings.searchMoves.trim()) payload.searchmoves = settings.searchMoves.trim();
        state.lastPayload = `POST https://chess-api.com/v1\n${JSON.stringify(payload, null, 2)}`;
        if (state.ui.liveOutput) state.ui.liveOutput.innerHTML = isRetry ? "♻️ Retrying Safe FEN..." : "☁️ SF17 Analysis...";
        updateUI();
        state.currentCloudRequest = GM_xmlhttpRequest({
            method: "POST",
            url: "https://chess-api.com/v1",
            headers: { "Content-Type": "application/json" },
            data: JSON.stringify(payload),
            timeout: 15000,
            onload: (res) => handleCloudResponse(res, finalFEN, actualDepth, isRetry),
            onerror: (err) => { handleError("Network Error", err); triggerFallback(); },
            ontimeout: () => { handleError("Timeout (15s)"); triggerFallback(); },
        });
    }
    function analyzeSF16(finalFEN, depth) {
        const actualDepth = Math.min(depth, 15);
        const encodedFEN = encodeURIComponent(finalFEN);
        const url = `https://stockfish.online/api/s/v2.php?fen=${encodedFEN}&depth=${actualDepth}&mode=bestmove`;
        state.lastPayload = `GET ${url}`;
        if (state.ui.liveOutput) state.ui.liveOutput.innerHTML = "☁️ SF17.1.0 Analysis...";
        updateUI();
        state.currentCloudRequest = GM_xmlhttpRequest({
            method: "GET",
            url: url,
            timeout: 20000,
            onload: (res) => handleSF16Response(res),
            onerror: (err) => { handleError("Network Error (SF16)", err); triggerFallback(); },
            ontimeout: () => { handleError("Timeout (SF16 20s)"); triggerFallback(); },
        });
    }
    function handleSF16Response(response) {
        state.isThinking = !1;
        state.lastResponse = response.responseText;
        try {
            if (response.status !== 200) throw new Error(`HTTP ${response.status}`);
            const data = JSON.parse(response.responseText);
            if (!data.success || !data.bestmove) { triggerFallback(); return; }
            const bestMove = data.bestmove.split(" ")[1] || data.bestmove;
            const duration = ((performance.now() - state.analysisStartTime) / 1000).toFixed(2);
            processBestMove(bestMove, data.evaluation, data.mate, data.continuation ? data.continuation.split(" ") : null, null, duration, true);
        } catch (e) { triggerFallback(); }
        updateUI();
    }
    function handleCloudResponse(response, sentFEN, depth, isRetry) {
        state.isThinking = !1;
        state.lastResponse = response.responseText;
        if (response.responseText.includes("HIGH_USAGE") || response.status === 429) { triggerFallback(); return; }
        try {
            if (response.status !== 200) throw new Error(`HTTP ${response.status}`);
            const rawData = JSON.parse(response.responseText);
            const result = Array.isArray(rawData) ? rawData[0] : rawData;
            if (!result || result.error || result.status === "error") {
                const errText = result?.error || result?.message || "Unknown Error";
                if (errText.includes("HIGH_USAGE")) { triggerFallback(); return; }
                if ((errText.includes("FEN") || errText.includes("VALIDATION")) && !isRetry) {
                    const parts = sentFEN.split(" ");
                    if (parts.length >= 4 && parts[3] !== "-") {
                        parts[3] = "-";
                        analyze(depth, parts.join(" "), !0);
                        return;
                    }
                }
                triggerFallback();
                return;
            }
            if (result.move || result.bestmove) {
                const duration = ((performance.now() - state.analysisStartTime) / 1000).toFixed(2);
                processBestMove(result.move || result.bestmove, result.eval, result.mate, result.continuationArr, result.winChance, duration, true);
            } else { triggerFallback(); }
        } catch (e) { triggerFallback(); }
        updateUI();
    }
    function analyzeLocal(fen, depth) {
        if (!state.localEngine) loadLocalEngine();
        if (!state.localEngine) return;
        if (!state.localConfigSent) {
            state.localEngine.postMessage(`setoption name Contempt value ${settings.contempt}`);
            state.localConfigSent = !0;
        }
        state.localEval = null; state.localMate = null; state.localPV = null; state.localDepth = null;
        const actualDepth = Math.min(depth, 23);
        const cmds = [`position fen ${fen}`, `go depth ${actualDepth}`];
        state.lastPayload = `Worker CMDs:\n${cmds.join("\n")}`;
        state.ui.liveOutput.innerHTML = "⚡ Local Analysis...";
        updateUI();
        cmds.forEach((cmd) => state.localEngine.postMessage(cmd));
    }
    function handleLocalMessage(e) {
        const msg = e.data;
        if (typeof msg !== "string") return;
        state.lastResponse = (state.lastResponse.length > 500 ? "..." + state.lastResponse.slice(-500) : state.lastResponse) + "\n" + msg;
        if (msg.startsWith("info") && msg.includes("depth") && msg.includes("score")) {
            const depthMatch = msg.match(/depth (\d+)/);
            const scoreMatch = msg.match(/score (cp|mate) (-?\d+)/);
            const pvMatch = msg.match(/ pv (.*)/);
            if (depthMatch && scoreMatch) {
                const depth = depthMatch[1];
                let val = parseInt(scoreMatch[2]);
                const type = scoreMatch[1];
                const fenParts = state.lastSentFEN ? state.lastSentFEN.split(" ") : [];
                const sideToMove = fenParts.length > 1 ? fenParts[1] : "w";
                if (sideToMove === "b") val = -val;
                const pv = pvMatch ? pvMatch[1] : "";
                if (type === "mate") { state.localMate = val; state.localEval = null; }
                else { state.localMate = null; state.localEval = (val / 100).toFixed(2); }
                state.localPV = pv; state.localDepth = depth;
                if (pv) state.currentPV = pv.split(" ");

                let scoreTxt;
                if (type === "mate") { scoreTxt = "M" + Math.abs(val); if (val < 0) scoreTxt = "-" + scoreTxt; }
                else { scoreTxt = (val > 0 ? "+" : "") + (val / 100).toFixed(2); }
                const evalVal = type === "mate" ? val : parseFloat(state.localEval);
                const statusData = getEvalStatusData(evalVal, type === "mate");
                const duration = ((performance.now() - state.analysisStartTime) / 1000).toFixed(2);
                if (pv) {
                    const best = pv.split(" ")[0];
                    Visuals.add(best, 'analysis');
                    // --- TRIGGER PV UPDATE ---
                    PV.update(state.currentPV);
                    // -------------------------
                    state.lastMoveResult = `⏳ D${depth}: <span style="font-weight:bold; color:var(--bot-primary);">${best}</span>`;
                }
                state.lastLiveResult = `
                    <div style="display:flex; justify-content:space-between; align-items:center; font-weight:bold;">
                        <div style="display:flex; align-items:center; gap: 8px;">
                            <span style="color:var(--bot-primary); font-size:1.1em;">${scoreTxt}</span>
                            <span style="font-size:0.85em; color:${statusData.color}; font-weight:bold;">${statusData.text}</span>
                        </div>
                        <span style="font-size:0.7em; color:#aaa; font-weight:normal;">(${duration}s)</span>
                    </div>
                 `;
                updateUI();
            }
        }
        if (msg.startsWith("bestmove")) {
            state.isThinking = !1;
            const parts = msg.split(" ");
            const bestMove = parts[1];
            if (bestMove && bestMove !== "(none)") {
                const duration = ((performance.now() - state.analysisStartTime) / 1000).toFixed(2);
                processBestMove(bestMove, state.localEval, state.localMate, state.localPV ? state.localPV.split(" ") : null, null, duration, state.localDepth, true);
            } else state.lastMoveResult = "⚠️ No move found";
            updateUI();
        }
    }

    function processBestMove(bestMove, evalScore, mate, continuationArr, winChance, duration, depth = null, isFinal = false) {
        state.currentBestMove = bestMove;
        state.currentPV = continuationArr || (bestMove ? [bestMove] : []);

        if (isFinal || !state.isThinking) {
             Visuals.add(bestMove, 'history');
             // Clear PV when move is final (optional, but cleaner)
             PV.clear();
        } else {
             Visuals.add(bestMove, 'analysis');
             // --- UPDATE PV DISPLAY ---
             PV.update(state.currentPV);
             // ------------------------
        }

        let scoreTxt = "";
        let pvStr = "N/A";
        let numericValForStatus = 0;
        let isMate = false;
        if (evalScore !== undefined || mate !== undefined) {
            if (mate) {
                isMate = true;
                numericValForStatus = mate;
                scoreTxt = `M${Math.abs(mate)}`;
                if (mate < 0) scoreTxt = "-" + scoreTxt;
            } else {
                const sc = parseFloat(evalScore);
                numericValForStatus = sc;
                scoreTxt = (sc > 0 ? "+" : "") + sc;
            }
            if (continuationArr) pvStr = continuationArr.join(" ");
        }
        const statusData = getEvalStatusData(numericValForStatus, isMate);
        const durHtml = duration
            ? `<span style="font-size:0.7em; color:#aaa; font-weight:normal;">(${duration}s)</span>`
            : "";
        state.lastMoveResult = `✅ Best: <span style="font-weight:bold; color:var(--bot-primary);">${bestMove}</span>`;
        let wcHtml = "";
        if (winChance) wcHtml = `<span style="color:#aaa; font-size:0.8em;">(${Math.round(winChance)}%)</span>`;
        else if (depth) wcHtml = `<span style="font-size:0.8em; color:#aaa;">(D${depth})</span>`;
        state.lastLiveResult = `
            <div style="display:flex; justify-content:space-between; align-items:center; font-weight:bold;">
                <div style="display:flex; align-items:center; gap: 8px;">
                    <span style="color:var(--bot-primary); font-size:1.1em;">${scoreTxt}</span>
                    <span style="font-size:0.85em; color:${statusData.color}; font-weight:bold;">${statusData.text}</span>
                </div>
                <div>${wcHtml} ${durHtml}</div>
            </div>
            <div style="margin-top:5px; font-size:0.85em; color:#bbb; width:100%; max-width:100%; box-sizing:border-box; word-wrap:break-word; overflow-wrap:anywhere; white-space:normal;">
                <span style="color:#888;">PV:</span> ${pvStr}
            </div>
        `;
        if (settings.autoMove) triggerAutoMove();
    }

    function triggerAutoMove() {
        if (!state.currentBestMove || !state.board?.game) return;
        const turn = state.board.game.getTurn();
        const playingAs = state.board.game.getPlayingAs();
        if (turn !== playingAs) return;
        const wait = Math.max(0, state.moveTargetTime - performance.now());
        setTimeout(() => playMove(state.currentBestMove), wait);
    }
    function handleError(type, err) {
        state.isThinking = !1;
        console.error(type, err);
        state.lastResponse = `${type}: ${err.message || err}`;
        state.lastMoveResult = `❌ ${type}`;
        updateUI();
    }
    function playMove(move) {
        if (!state.board?.game) return;
        const from = move.substring(0, 2);
        const to = move.substring(2, 4);
        const currentRaw = getRawBoardFEN();
        if (currentRaw && sanitizeFEN(currentRaw).split(" ")[0] !== state.lastSentFEN.split(" ")[0]) return;
        for (const m of state.board.game.getLegalMoves()) {
            if (m.from === from && m.to === to) {
                const promotion = move.length > 4 ? move.substring(4, 5) : "q";
                state.board.game.move({ ...m, promotion, animate: !0, userGenerated: !0 });
                return;
            }
        }
    }

    function toggleAutoQueue() {
        if (state.newGameObserver) {
            state.newGameObserver.disconnect();
            state.newGameObserver = null;
        }
        if (state.queueTimeout) {
            clearTimeout(state.queueTimeout);
            state.queueTimeout = null;
        }
        if (settings.autoQueue) {
            state.newGameObserver = new MutationObserver((mutations) => {
                const btns = Array.from(document.querySelectorAll("button"));
                const newGameBtn = btns.find((b) => {
                    const txt = b.innerText.toLowerCase();
                    return txt.includes("new") && !txt.includes("rematch") && b.offsetParent !== null;
                });
                if (newGameBtn) {
                    if (!state.queueTimeout) {
                        state.queueTimeout = setTimeout(() => {
                            newGameBtn.click();
                            state.queueTimeout = null;
                        }, 100);
                    }
                }
            });
            state.newGameObserver.observe(document.body, { childList: !0, subtree: !0 });
        }
    }
    function resetSettings() {
        const currentModel = settings.engineMode;
        Object.assign(settings, DEFAULT_SETTINGS);
        settings.engineMode = currentModel;
        Object.keys(DEFAULT_SETTINGS).forEach((k) => {
            if (k !== "engineMode") saveSetting(k, DEFAULT_SETTINGS[k]);
        });
        saveSetting("engineMode", currentModel);
        const hsl = rgbToHsl(...Object.values(hexToRgb(settings.highlightColor)));
        state.h = hsl.h;
        state.s = hsl.s;
        state.l = hsl.l;
        toggleAutoQueue();
        createUI();
        applyMenuPosition();
    }
    function syncColor() {
        const rgb = hslToRgb(state.h, state.s, state.l);
        const hex = rgbToHex(rgb.r, rgb.g, rgb.b);
        settings.highlightColor = hex;
        saveSetting("highlightColor", hex);
        if (state.ui.inpR) {
            state.ui.inpR.value = rgb.r;
            state.ui.inpG.value = rgb.g;
            state.ui.inpB.value = rgb.b;
            state.ui.inpHex.value = hex;
            state.ui.colorPreview.style.background = hex;
            state.ui.sliderH.value = state.h;
            state.ui.sliderS.value = state.s;
            state.ui.sliderL.value = state.l;
            if(state.ui.sliderHNum) state.ui.sliderHNum.value = Math.round(state.h);
            if(state.ui.sliderSNum) state.ui.sliderSNum.value = Math.round(state.s);
            if(state.ui.sliderLNum) state.ui.sliderLNum.value = Math.round(state.l);
        }
        // Force redraw of current history visuals to update color
        Visuals.removeByType('history'); // Clear old colors
        if(state.currentBestMove) Visuals.add(state.currentBestMove, 'history');
    }
    function applyTheme() {
        const modals = [state.ui.panel, state.ui.modal, state.ui.histModal];

        modals.forEach(m => {
            if (!m) return;
            m.style.setProperty("--bot-bg", settings.themeBg);
            m.style.setProperty("--bot-t", settings.themeText);
            m.style.setProperty("--bot-b", settings.themeBorder);
            m.style.setProperty("--bot-p", settings.themePrimary);

            // This forces the "Recording Enabled" label and category text to update
            m.style.color = settings.themeText;

            // Apply menu opacity to the background only, keeping text sharp
            if (m === state.ui.panel) {
                m.style.opacity = settings.menuOpacity;
            } else {
                // For the pop-up modals
                const overlayId = m.id === "modal" ? "modalOv" : "histModalOv";
                const overlay = document.getElementById(overlayId);
                if (overlay) overlay.style.opacity = "1";
                m.style.opacity = settings.menuOpacity;
            }
        });
    }

    // --- POSITION LOGIC ---
    function applyMenuPosition() {
        const p = state.ui.panel;
        if(!p) return;
        const margin = "10px";
        p.style.transform = "none";
        // Important: Clear conflicting properties
        p.style.top = ""; p.style.bottom = ""; p.style.left = ""; p.style.right = "";

        if (settings.menuPosition === "custom") {
            const savedX = GM_getValue("bot_pX", "auto");
            const savedY = GM_getValue("bot_pY", "0");
            if (savedX === "auto") {
                p.style.right = "0px";
                p.style.left = "auto";
            } else {
                p.style.left = savedX + "px";
            }
            p.style.top = savedY + "px";

            // Bounds check to ensure it's not off-screen
            const rect = p.getBoundingClientRect();
            if(rect.left < 0) p.style.left = "0px";
            if(rect.top < 0) p.style.top = "0px";
            if(rect.right > window.innerWidth) p.style.left = (window.innerWidth - rect.width) + "px";
            if(rect.bottom > window.innerHeight) p.style.top = (window.innerHeight - rect.height) + "px";

        } else {
            switch (settings.menuPosition) {
                case "top-left": p.style.top = margin; p.style.left = margin; break;
                case "top-right": p.style.top = margin; p.style.right = margin; break;
                case "bottom-left": p.style.bottom = margin; p.style.left = margin; break;
                case "bottom-right": p.style.bottom = margin; p.style.right = margin; break;
            }
        }
    }
    function createUI() {
        if (document.getElementById("enginePanel")) document.getElementById("enginePanel").remove();
        if (document.getElementById("modalOv")) document.getElementById("modalOv").remove();
        if (document.getElementById("histModalOv")) document.getElementById("histModalOv").remove();
        if (document.getElementById("fenTooltip")) document.getElementById("fenTooltip").remove();

        loadSettings();

        const initHsl = rgbToHsl(...Object.values(hexToRgb(settings.highlightColor)));
        state.h = initHsl.h; state.s = initHsl.s; state.l = initHsl.l;
        const savedW = GM_getValue("bot_panelW", "25vw");
        const savedH = GM_getValue("bot_panelH", "50vh");
        const isMini = GM_getValue("bot_isMini", false);

        const style = `
            :root { --bot-bg:${settings.themeBg}; --bot-b:${settings.themeBorder}; --bot-p:${settings.themePrimary}; --bot-t:${settings.themeText}; --bot-inp:#333; }
            #enginePanel * { box-sizing: border-box; }
            #enginePanel {
                position:fixed; width:${savedW}; height:${savedH};
                min-width:300px; min-height:300px;
                background:var(--bot-bg); border:1px solid var(--bot-b);
                color:var(--bot-t); z-index:9999; font-family:sans-serif;
                box-shadow:-4px 0 15px rgba(0,0,0,0.5); font-size:14px;
                display:flex; flex-direction:column; resize:both; overflow:hidden;
                opacity: ${settings.menuOpacity};
            }
            #enginePanel.minified {
                width: 34px !important; height: 34px !important;
                resize: none; min-height: 0 !important; min-width: 0 !important;
                overflow: hidden !important; border: 1px solid var(--bot-b);
                background: var(--bot-p); padding: 0; display: flex !important;
                align-items: center !important; justify-content: center !important;
                cursor: pointer; left: auto !important; top: 0 !important; right: 0 !important;
                border-radius: 4px;
            }
            #enginePanel.minified #panelContent,
            #enginePanel.minified #panelHeader > *:not(#minBtn) { display: none !important; }
            #enginePanel.minified #minBtn {
                width: 100% !important; height: 100% !important;
                display: flex !important; justify-content: center !important; align-items: center !important;
                padding: 0 !important; margin: 0 !important;
            }
            #enginePanel.minified #minBtn img {
                width: 28px !important; height: 28px !important; display: block;
            }
            #panelHeader {
                background:var(--bot-p); color:#000; padding:10px; font-weight:bold;
                display:flex; justify-content:space-between; align-items:center;
                cursor:move; flex:none; user-select:none; height:38px;
            }
            #panelContent { padding:15px; display:flex; flex-direction:column; gap:10px; overflow-y:auto; flex:1; min-height: 0; }
            .sect { border-top:1px solid #333; padding-top:10px; display:flex; flex-direction:column; gap:8px; }
            .sect-title { font-size:0.85em; color:#aaa; font-weight:bold; text-transform:uppercase; margin-bottom:4px; }
            .row { display:flex; justify-content:space-between; align-items:center; gap: 10px; margin-bottom: 6px; }

            input, select { background:rgba(0,0,0,0.2); color:var(--bot-t); border:1px solid var(--bot-b); padding:4px; border-radius:4px; }
            input[type="number"] { width: 60px; }
            select { width: 120px; }
            input[type="text"] { flex:1; }

            /* --- UPDATED SLIDER STYLING --- */
            input[type=range] {
                -webkit-appearance: none;
                width: 100%;
                background: transparent;
                padding: 0;
                margin: 0;
                border: none;
            }
            input[type=range]:focus { outline: none; }
            input[type=range]::-webkit-slider-runnable-track {
                width: 100%;
                height: 6px;
                cursor: pointer;
                background: var(--bot-b); /* Track matches border color */
                border-radius: 3px;
            }
            input[type=range]::-webkit-slider-thumb {
                height: 16px;
                width: 16px;
                border-radius: 50%;
                background: var(--bot-t); /* Thumb matches Text Color (White in Dark mode, Black in Light) */
                cursor: pointer;
                -webkit-appearance: none;
                margin-top: -5px;
                border: 1px solid rgba(0,0,0,0.3);
                box-shadow: 0 1px 3px rgba(0,0,0,0.3);
            }
            /* Rainbow Hue Slider Override */
            #sliderH {
                background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00) !important;
            }
            #sliderH::-webkit-slider-thumb {
                background: #fff !important;
                border: 1px solid #000 !important;
            }
            /* --------------------------- */

            button { background:var(--bot-p); border:none; padding:10px; color:#000; font-weight:bold; cursor:pointer; border-radius:4px; }
            button:disabled { opacity:0.6; cursor:not-allowed; }
            #custBtn { background:#00bcd4; margin-top:5px; }
            #histBtn { background:#8e44ad; margin-top:5px; color: white; }
            .log-box {
                background:rgba(0,0,0,0.5); padding:8px; font-family:monospace; font-size:0.75em; border-radius:4px;
                overflow-y:auto; word-break:break-all; white-space:pre-wrap; border:1px solid var(--bot-b); height:100px; resize:vertical;
                user-select: text !important; -webkit-user-select: text !important; cursor: text;
            }
            #statusBox { background:rgba(0,0,0,0.2); padding:8px; border:1px solid #00bcd4; border-radius:4px; font-size:0.9em; min-height:40px; width: 100%; flex-shrink: 0; display: flex; flex-direction: column; gap: 5px; }
            #modalOv, #histModalOv { position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.8); z-index:10000; display:none; justify-content:center; align-items:center; }
            #modal, #histModal { background:var(--bot-bg); padding:0; border-radius:8px; width:420px; border:1px solid var(--bot-b); display:flex; flex-direction:column; max-height:90vh; opacity: ${settings.menuOpacity}; }
            #histModal { width: 600px; height: 600px; }
            #modal * { color:var(--bot-t); }
            #modal label, #histModal label { opacity: 1 !important; font-weight: 600; font-size:0.9em; }
            #modal input[type="color"] { height: 24px; padding: 0; width: 40px; cursor:pointer; border: none; }
            #modal select { height: 24px; padding: 0 4px; font-size: 0.9em; }
            .show-cloud { display: none; } .show-local { display: none; }
            body.mode-cloud .show-cloud { display: flex; }
            body.mode-local .show-local { display: flex; }
            .rgb-inputs { display: flex; gap: 5px; flex: 1; justify-content: flex-end; }
            .rgb-inputs input { width: 45px; text-align: center; }

            #histTableContainer { flex: 1; overflow-y: auto; border: 1px solid #444; border-radius: 4px; margin-top: 10px; }
            #histTable { width:100%; border-collapse: collapse; font-size:0.85em; }
            /* Replace the #histTable th and td sections with this: */
            #histTable th { background: var(--bot-b); color: var(--bot-p); position: sticky; top: 0; z-index: 1; }
            #histTable th, #histTable td { border-bottom: 1px solid var(--bot-b); padding: 6px; text-align: left; color: var(--bot-t); /* This ensures text swaps with theme */}
            #histTable tr:hover { background: var(--bot-b); filter: brightness(1.2); }
            .hist-win { color: #81b64c; font-weight: bold; }
            .hist-loss { color: #ff5555; font-weight: bold; }
            .hist-draw { color: #aaaaaa; font-weight: bold; }
            .hist-fen { max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; color: #888; text-decoration: underline dotted; }
            .btn-del { background: #ff5555; color: white; padding: 2px 6px; border-radius: 3px; font-size: 0.7em; cursor: pointer; border: none; }
            .hist-controls { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; }
            #histEmpty { padding: 20px; text-align: center; color: #888; }
            #fenTooltip {
                position: fixed; border: 3px solid #333; background: #222;
                z-index: 10001; display: none; pointer-events: none;
                box-shadow: 0 4px 15px rgba(0,0,0,0.5);
            }
            .fen-board { display: grid; grid-template-columns: repeat(8, 1fr); width: 240px; height: 240px; border: 2px solid #555; }
            .fen-sq { width: 30px; height: 30px; display: flex; justify-content: center; align-items: center; background-size: 100%; background-repeat: no-repeat; }
            .fen-sq.light { background-color: #eeeed2; }
            .fen-sq.dark { background-color: #769656; }
            /* Visual Modal Specifics */
            .modal-header { display:flex; justify-content:space-between; align-items:center; padding:15px; border-bottom:1px solid var(--bot-b); }
            .modal-tabs { display:flex; border-bottom:1px solid var(--bot-b); }
            .tab-btn { flex:1; background:transparent; border:none; padding:10px; color:var(--bot-t); cursor:pointer; opacity:0.7; border-bottom:2px solid transparent; }
            .tab-btn.active { opacity:1; border-bottom:2px solid var(--bot-p); font-weight:bold; }
            .modal-content { padding:15px; overflow-y:auto; flex:1; }
            .slider-group { display: flex; align-items: center; gap: 8px; flex: 1; justify-content: flex-end; }
            .slider-group input[type=range] { flex: 1; }
            .slider-group input[type=number] { width: 45px; text-align:center; }
            .adv-toggle { cursor: pointer; font-size: 0.8em; color: var(--bot-p); text-decoration: underline; margin-top: 5px; display: inline-block; }
            .modal-content .row { display: flex; align-items: center; margin-bottom: 12px; }
            .modal-content .row label { flex: 0 0 120px; text-align:left; font-weight: 600; }
            .modal-content .row > input[type="text"], .modal-content .row > input[type="color"], .modal-content .row > select { flex: 1; }
            .adv-sect { display: none; margin-top: 10px; padding-left: 10px; border-left: 2px solid var(--bot-b); display:flex; flex-direction:column; gap:8px; display:none; }
            .theme-presets { display:flex; gap:10px; margin-bottom:10px; }
            .theme-btn { flex:1; padding:5px; border:1px solid var(--bot-b); cursor:pointer; background:rgba(0,0,0,0.2); color:var(--bot-t); }
        `;
        const fullHTML = `<style>${style}</style>` + `
            <div id="enginePanel" class="${isMini ? "minified" : ""}">
                <div id="panelHeader">
                    <div style="display:flex; align-items:center; gap:5px;">
                        <span>Menu</span>
                        <span id="minBtn" style="cursor:pointer; display:flex; align-items:center; justify-content:center; width:100%; height:100%;">${isMini ? `<img src="${STOCKFISH_ICON}">` : "▼"}</span>                    </div>
                    <button id="btnReset" style="padding:2px 8px; font-size:0.8em; background:#0002; color:#000; cursor:pointer;">Reset Defaults</button>
                </div>
                <div id="panelContent">
                    <div id="statusBox">${state.lastLiveResult}</div>
                    <div id="moveResult" style="background:rgba(0,0,0,0.2); padding:5px; border-radius:4px; text-align:center;">${state.lastMoveResult}</div>
                    <div class="sect">
                        <div class="sect-title">Engine Config</div>
                        <div class="row">
                            <label>Model</label>
                            <select id="selMode" style="width:240px;">
                                <option value="cloud">SF 18.0.0(cloud 0.25-0.48s)</option>
                                <option value="sfonline">SF 17.1.0(cloud 0.15-11.0s)</option>
                                <option value="local">SF 10.0.2(local 0.00-75.0s)</option>
                            </select>
                        </div>
                        <div class="row"><label>Depth (Max <span id="lblMaxDepth">18</span>)</label><input type="number" id="inpDepth" min="1" max="18" value="${settings.depth}"></div>
                        <div class="row show-cloud"><label>Max Time (ms)</label><input type="number" id="inpTime" value="${settings.maxThinkingTime}"></div>
                        <div class="row show-local"><label>Contempt (-100→100)</label><input type="number" id="inpContempt" min="-100" max="100" value="${settings.contempt}"></div>
                        <div class="row show-cloud"><label>Search</label><input type="text" id="inpSearch" value="${settings.searchMoves}"></div>
                    </div>
                    <div class="sect">
                        <div class="sect-title" style="display:flex; justify-content:space-between; align-items:center;">
                            PV Display
                            <input type="checkbox" id="chkPV" ${settings.showPVArrows ? "checked" : ""}>
                        </div>
                        <div id="pvSettings" style="display:none;">
                            <div class="row"><label>Depth (1-45)</label><div class="slider-group"><input type="range" id="inpPVDepth" min="1" max="45" step="1" value="${settings.pvDepth}"><input type="number" id="inpPVDepthNum" min="1" max="45" value="${settings.pvDepth}"></div></div>
                            <div class="row" style="padding-top:3px;"><label>Show Numbers</label><input type="checkbox" id="chkPVNums" ${settings.pvShowNumbers ? "checked" : ""}></div>
                            <div class="row" style="padding-top:5px;"><label>Custom Gradient</label><input type="checkbox" id="chkPVGrad" ${settings.pvCustomGradient ? "checked" : ""}></div>
                            <div id="pvGradSettings" style="display:none; padding-left:10px; border-left:2px solid #333; margin-top:5px;">
                                <div class="row"><label>Start Color</label><input type="color" id="inpPVStart" value="${settings.pvStartColor}"></div>
                                <div class="row"><label>End Color</label><input type="color" id="inpPVEnd" value="${settings.pvEndColor}"></div>
                            </div>
                        </div>
                    </div>
                    <div class="sect">
                        <div class="sect-title">Automation</div>
                        <div class="row">
                            <label><input type="checkbox" id="chkRun" ${settings.autoRun ? "checked" : ""}> Auto-Analyze</label>
                            <label><input type="checkbox" id="chkMove" ${settings.autoMove ? "checked" : ""}> Auto-Move</label>
                            <label><input type="checkbox" id="chkQueue" ${settings.autoQueue ? "checked" : ""}> Auto-Queue</label>
                        </div>
                        <div class="row"><label>Randomized Delay (s)</label><div style="display:flex; gap:5px;"><input type="number" id="inpMin" style="width:50px" value="${settings.minDelay}"><span>-</span><input type="number" id="inpMax" style="width:50px" value="${settings.maxDelay}"></div></div>
                        <div style="font-size:0.7em; color:#888; text-align:right;" id="delayDisplay">Next: N/A</div>
                    </div>
                    <button id="btnAnalyze">Analyze</button>
                    <button id="custBtn">Visuals & Theme</button>
                    <button id="histBtn">Game History</button>
                    <div class="sect">
                         <div class="row"><label style="cursor:pointer"><input type="checkbox" id="chkDebug" ${settings.debugLogs ? "checked" : ""}> Show Debug Logs</label></div>
                         <div id="debugArea" style="display:${settings.debugLogs ? "block" : "none"}">
                             <div class="log-box" id="sentCommandOutput"></div>
                             <div class="log-box" id="receivedMessageOutput"></div>
                         </div>
                    </div>
                </div>
            </div>
            <div id="modalOv">
                <div id="modal">
                    <div class="modal-header">
                        <h3 style="margin:0; color:var(--bot-p);">Settings</h3>
                        <button id="modalClose" style="padding:2px 8px; font-weight:bold; cursor:pointer;">×</button>
                    </div>
                    <div class="modal-tabs">
                        <button class="tab-btn active" id="tabMove">Move Display</button>
                        <button class="tab-btn" id="tabTheme">Menu Theme</button>
                    </div>
                    <div class="modal-content" id="tabContentMove">
                         <div class="sect" style="border:none; padding:0;">
                             <div class="row" style="margin-bottom: 20px;"><label>Visual Type</label><select id="visType" style="width:120px; height:24px;"><option value="boxes">Boxes</option><option value="arrow">Arrow</option><option value="outline">Outline</option></select></div>
                             <div class="row" style="margin-bottom: 12px;">
                                 <label>Display Duration</label>
                                 <div class="slider-group">
                                     <input type="range" id="visDuration" min="0" max="100" step="1" value="100">
                                     <span id="visDurationText" style="width:70px; text-align:right; font-size:0.9em; font-family:monospace;">Forever</span>
                                 </div>
                             </div>
                             <div class="row" id="rowFadeOut" style="display:none; margin-bottom: 12px;">
                                 <label>Fade Out</label>
                                 <div style="flex:1; display:flex; align-items:center;">
                                     <input type="checkbox" id="chkFadeOut" style="width: 18px; height: 18px;">
                                 </div>
                             </div>
                             <div class="row" style="margin-bottom: 12px;">
                                 <label>Hide After Move</label>
                                 <div style="flex:1; display:flex; align-items:center;">
                                     <input type="checkbox" id="chkHideAfterMove" style="width: 18px; height: 18px;" ${settings.hideAfterMove ? "checked" : ""}>
                                 </div>
                             </div>
                         </div>
                         <div class="sect">
                            <div class="sect-title">Basic Settings</div>
                            <div style="display:flex; flex-direction:column; gap:10px;">
                                <div class="row" style="width:100%; margin-bottom: 10px;">
                                    <div id="colorPreview" style="width:30px; height:30px; border-radius:50%; border:2px solid #555; background:${settings.highlightColor}; flex:0 0 30px;"></div>
                                    <div class="rgb-inputs">
                                       <input type="number" id="inpR" min="0" max="255" placeholder="R">
                                       <input type="number" id="inpG" min="0" max="255" placeholder="G">
                                       <input type="number" id="inpB" min="0" max="255" placeholder="B">
                                    </div>
                                </div>
                                <div class="row"><label>Hue</label><div class="slider-group"><input type="range" id="sliderH" min="0" max="360" value="${state.h}"><input type="number" id="sliderHNum" min="0" max="360" value="${Math.round(state.h)}"></div></div>
                                <div class="row"><label>Saturation</label><div class="slider-group"><input type="range" id="sliderS" min="0" max="100" value="${state.s}"><input type="number" id="sliderSNum" min="0" max="100" value="${Math.round(state.s)}"><span>%</span></div></div>
                                <div class="row"><label>Brightness</label><div class="slider-group"><input type="range" id="sliderL" min="0" max="100" value="${state.l}"><input type="number" id="sliderLNum" min="0" max="100" value="${Math.round(state.l)}"><span>%</span></div></div>
                                <div class="row" style="width:100%; margin-top:5px; margin-bottom: 20px;"><label>Hex</label><input type="text" id="inpHex" style="text-transform:uppercase; text-align:center;"></div>
                            </div>
                         </div>
                         <div class="sect">
                             <div class="adv-toggle" id="advToggle">▼ Advanced Visual Settings</div>
                             <div class="adv-sect" id="advSect" style="display:none;">
                                 <!-- BOXES -->
                                 <div id="visBoxSettings">
                                     <div class="row"><label>Inner Opacity</label><div class="slider-group"><input type="range" id="visInnerOp" min="0" max="1" step="0.01" value="${settings.innerOpacity}"><input type="number" id="visInnerOpNum" min="0" max="100" value="${Math.round(settings.innerOpacity*100)}"><span>%</span></div></div>
                                     <div class="row"><label>Outer Opacity</label><div class="slider-group"><input type="range" id="visOuterOp" min="0" max="1" step="0.01" value="${settings.outerOpacity}"><input type="number" id="visOuterOpNum" min="0" max="100" value="${Math.round(settings.outerOpacity*100)}"><span>%</span></div></div>
                                     <div class="row"><label>Gradient Bias</label><div class="slider-group"><input type="range" id="visBias" min="0" max="100" step="1" value="${settings.gradientBias}"><input type="number" id="visBiasNum" min="0" max="100" value="${settings.gradientBias}"><span>%</span></div></div>
                                 </div>
                                 <!-- ARROWS -->
                                 <div id="visArrowSettings" style="display:none;">
                                     <div class="row"><label>Arrow Opacity</label><div class="slider-group"><input type="range" id="visArrowOp" min="0" max="1" step="0.01" value="${settings.arrowOpacity}"><input type="number" id="visArrowOpNum" min="0" max="100" value="${Math.round(settings.arrowOpacity*100)}"><span>%</span></div></div>
                                     <div class="row"><label>Arrow Width</label><div class="slider-group"><input type="range" id="visArrowWidth" min="5" max="50" step="1" value="${settings.arrowWidth}"><input type="number" id="visArrowWidthNum" min="5" max="50" value="${settings.arrowWidth}"><span>px</span></div></div>
                                 </div>
                                 <!-- OUTLINE -->
                                 <div id="visOutlineSettings" style="display:none;">
                                     <div class="row"><label>Line Opacity</label><div class="slider-group"><input type="range" id="visOutOp" min="0" max="1" step="0.01" value="${settings.visualOutlineOpacity}"><input type="number" id="visOutOpNum" min="0" max="100" value="${Math.round(settings.visualOutlineOpacity*100)}"><span>%</span></div></div>
                                     <div class="row"><label>Line Width</label><div class="slider-group"><input type="range" id="visOutWidth" min="1" max="10" step="1" value="${settings.visualOutlineWidth}"><input type="number" id="visOutWidthNum" min="1" max="10" value="${settings.visualOutlineWidth}"><span>px</span></div></div>
                                     <div class="row"><label>Glow Effect</label><input type="checkbox" id="visOutGlow" ${settings.visualOutlineGlow ? "checked" : ""}></div>
                                     <div class="row"><label>Glow Radius</label><div class="slider-group"><input type="range" id="visOutGlowRad" min="1" max="50" step="1" value="${settings.visualOutlineGlowRadius}"><input type="number" id="visOutGlowRadNum" min="1" max="50" value="${settings.visualOutlineGlowRadius}"><span>px</span></div></div>
                                 </div>
                             </div>
                         </div>
                    </div>
                    <div class="modal-content" id="tabContentTheme" style="display:none;">
                        <div class="theme-presets">
                            <button class="theme-btn" id="btnThemeDark">Dark Mode</button>
                            <button class="theme-btn" id="btnThemeLight">Light Mode</button>
                        </div>
                        <div class="sect">
                            <div class="sect-title">Menu Position</div>
                            <div class="row">
                                <label>Panel Position</label>
                                <select id="selMenuPos">
                                    <option value="custom">Custom (Drag)</option>
                                    <option value="top-left">Top Left</option>
                                    <option value="top-right">Top Right</option>
                                    <option value="bottom-left">Bottom Left</option>
                                    <option value="bottom-right">Bottom Right</option>
                                </select>
                            </div>
                        </div>
                        <div class="sect">
                            <div class="row" style="margin-bottom: 20px;"><label>Menu Opacity</label><div class="slider-group"><input type="range" id="inpMenuOp" min="0.1" max="1" step="0.01" value="${settings.menuOpacity}"><input type="number" id="inpMenuOpNum" min="10" max="100" value="${Math.round(settings.menuOpacity*100)}"><span>%</span></div></div>
                        </div>
                        <div class="sect">
                            <div class="sect-title">Custom Colors</div>
                            <div class="row"><label>Background</label><input type="color" id="colBg" value="${settings.themeBg}"></div>
                            <div class="row"><label>Text Color</label><input type="color" id="colTxt" value="${settings.themeText}"></div>
                            <div class="row"><label>Border Color</label><input type="color" id="colBorder" value="${settings.themeBorder}"></div>
                            <div class="row"><label>Primary/Accent</label><input type="color" id="colPrim" value="${settings.themePrimary}"></div>
                        </div>
                    </div>
                </div>
            </div>
            <div id="histModalOv">
                <div id="histModal">
                    <div class="modal-header">
                        <h3 style="margin:0; color:#8e44ad;">Game History</h3>
                        <button id="histModalClose" style="padding:2px 8px; font-weight:bold; cursor:pointer;">×</button>
                    </div>
                    <div id="histTableContainer" style="padding:0 15px;">
                        <table id="histTable">
                            <thead>
                                <tr>
                                    <th>Date</th>
                                    <th>Color</th>
                                    <th>Result</th>
                                    <th>Clock</th>
                                    <th>FEN</th>
                                    <th></th>
                                </tr>
                            </thead>
                            <tbody id="histBody"></tbody>
                        </table>
                    </div>
                    <div class="hist-controls" style="padding:15px;">
                        <label><input type="checkbox" id="chkHistory" ${settings.enableHistory ? "checked" : ""}> Recording Enabled</label>
                        <button id="btnClearHist" style="background:#ff5555; padding:5px 10px; color:white; font-size:0.8em;">Delete All</button>
                    </div>
                </div>
            </div>
            <div id="fenTooltip"></div>
        `;
        document.body.insertAdjacentHTML("beforeend", fullHTML);

        const panel = document.getElementById("enginePanel");
        const computed = window.getComputedStyle(panel);
        panel.style.width = computed.width;
        if (!isMini) panel.style.height = computed.height;

        state.ui = {
            panel: panel,
            header: document.getElementById("panelHeader"),
            minBtn: document.getElementById("minBtn"),
            moveResult: document.getElementById("moveResult"),
            liveOutput: document.getElementById("statusBox"),
            logSent: document.getElementById("sentCommandOutput"),
            logRec: document.getElementById("receivedMessageOutput"),
            delayDisplay: document.getElementById("delayDisplay"),
            btnAnalyze: document.getElementById("btnAnalyze"),
            selMode: document.getElementById("selMode"),
            inpDepth: document.getElementById("inpDepth"),
            inpTime: document.getElementById("inpTime"),
            inpContempt: document.getElementById("inpContempt"),
            inpSearch: document.getElementById("inpSearch"),
            chkRun: document.getElementById("chkRun"),
            chkMove: document.getElementById("chkMove"),
            chkQueue: document.getElementById("chkQueue"),
            chkHideAfterMove: document.getElementById("chkHideAfterMove"),
            chkPV: document.getElementById("chkPV"),
            inpPVDepth: document.getElementById("inpPVDepth"),
            inpPVDepthNum: document.getElementById("inpPVDepthNum"),
            chkPVNums: document.getElementById("chkPVNums"),
            chkPVGrad: document.getElementById("chkPVGrad"),
            inpPVStart: document.getElementById("inpPVStart"),
            inpPVEnd: document.getElementById("inpPVEnd"),
            pvSettings: document.getElementById("pvSettings"),
            pvGradSettings: document.getElementById("pvGradSettings"),
            inpMin: document.getElementById("inpMin"),
            inpMax: document.getElementById("inpMax"),
            chkDebug: document.getElementById("chkDebug"),
            debugArea: document.getElementById("debugArea"),
            btnReset: document.getElementById("btnReset"),
            lblMaxDepth: document.getElementById("lblMaxDepth"),
            custBtn: document.getElementById("custBtn"),
            histBtn: document.getElementById("histBtn"),
            modal: document.getElementById("modalOv"),
            modalClose: document.getElementById("modalClose"),
            histModal: document.getElementById("histModalOv"),
            histModalClose: document.getElementById("histModalClose"),
            histBody: document.getElementById("histBody"),
            btnClearHist: document.getElementById("btnClearHist"),
            chkHistory: document.getElementById("chkHistory"),
            visType: document.getElementById("visType"),
            visBoxSettings: document.getElementById("visBoxSettings"),
            visArrowSettings: document.getElementById("visArrowSettings"),
            visOutlineSettings: document.getElementById("visOutlineSettings"),
            sliderH: document.getElementById("sliderH"),
            sliderHNum: document.getElementById("sliderHNum"),
            sliderS: document.getElementById("sliderS"),
            sliderSNum: document.getElementById("sliderSNum"),
            sliderL: document.getElementById("sliderL"),
            sliderLNum: document.getElementById("sliderLNum"),
            colorPreview: document.getElementById("colorPreview"),
            inpR: document.getElementById("inpR"),
            inpG: document.getElementById("inpG"),
            inpB: document.getElementById("inpB"),
            inpHex: document.getElementById("inpHex"),
            fenTooltip: document.getElementById("fenTooltip"),
            tabMove: document.getElementById("tabMove"),
            tabTheme: document.getElementById("tabTheme"),
            tabContentMove: document.getElementById("tabContentMove"),
            tabContentTheme: document.getElementById("tabContentTheme"),
            advToggle: document.getElementById("advToggle"),
            advSect: document.getElementById("advSect"),
            visInnerOp: document.getElementById("visInnerOp"),
            visInnerOpNum: document.getElementById("visInnerOpNum"),
            visOuterOp: document.getElementById("visOuterOp"),
            visOuterOpNum: document.getElementById("visOuterOpNum"),
            visBias: document.getElementById("visBias"),
            visBiasNum: document.getElementById("visBiasNum"),
            visArrowOp: document.getElementById("visArrowOp"),
            visArrowOpNum: document.getElementById("visArrowOpNum"),
            visArrowWidth: document.getElementById("visArrowWidth"),
            visArrowWidthNum: document.getElementById("visArrowWidthNum"),
            visOutOp: document.getElementById("visOutOp"),
            visOutOpNum: document.getElementById("visOutOpNum"),
            visOutWidth: document.getElementById("visOutWidth"),
            visOutWidthNum: document.getElementById("visOutWidthNum"),
            visOutGlow: document.getElementById("visOutGlow"),
            visOutGlowRad: document.getElementById("visOutGlowRad"),
            visOutGlowRadNum: document.getElementById("visOutGlowRadNum"),
            btnThemeDark: document.getElementById("btnThemeDark"),
            btnThemeLight: document.getElementById("btnThemeLight"),
            inpMenuOp: document.getElementById("inpMenuOp"),
            inpMenuOpNum: document.getElementById("inpMenuOpNum"),
            colBg: document.getElementById("colBg"),
            colTxt: document.getElementById("colTxt"),
            colBorder: document.getElementById("colBorder"),
            colPrim: document.getElementById("colPrim"),
            selMenuPos: document.getElementById("selMenuPos")
        };

        applyMenuPosition();

        // Bindings
        state.ui.selMode.value = settings.engineMode;
        state.ui.selMenuPos.value = settings.menuPosition;
        state.ui.btnAnalyze.onclick = () => analyze();
        state.ui.btnReset.onclick = resetSettings;
        state.ui.custBtn.onclick = () => (state.ui.modal.style.display = "flex");
        state.ui.modalClose.onclick = () => (state.ui.modal.style.display = "none");
        state.ui.histBtn.onclick = () => { renderHistory(); state.ui.histModal.style.display = "flex"; };
        state.ui.histModalClose.onclick = () => (state.ui.histModal.style.display = "none");
        state.ui.btnClearHist.onclick = () => { if (confirm("Delete all history?")) { state.history = []; GM_setValue("bot_history", []); renderHistory(); } };

        const toggleMin = () => {
            const isMini = state.ui.panel.classList.toggle("minified");
            saveSetting("isMini", isMini);
            state.ui.minBtn.innerHTML = isMini ? `<img src="${STOCKFISH_ICON}">` : "▼";
        };
        state.ui.minBtn.onclick = (e) => { e.stopPropagation(); toggleMin(); };
        state.ui.panel.onclick = (e) => { if (state.ui.panel.classList.contains("minified")) toggleMin(); };
        if (isMini) state.ui.minBtn.innerHTML = `<img src="${STOCKFISH_ICON}">`;

        const bind = (el, key, type = "val") => {
            if (!el) return;
            el.addEventListener(type === "chk" ? "change" : "input", (e) => {
                const val = type === "chk" ? e.target.checked : type === "num" ? parseFloat(e.target.value) : e.target.value;
                saveSetting(key, val);
                if (key === "autoMove" && val === !0) triggerAutoMove();
                if (key === "autoQueue") toggleAutoQueue();
                if (key === "hideAfterMove" && val === !0) {
                    Visuals.removeByType('history');
                    Visuals.removeByType('analysis');
                    PV.clear();
                }
                if (
                    ["innerOpacity", "outerOpacity", "gradientBias", "arrowOpacity", "arrowWidth",
                     "visualOutlineWidth", "visualOutlineOpacity", "visualOutlineGlow", "visualOutlineGlowRadius"
                    ].includes(key) && state.currentBestMove
                ) {
                     // Force refresh for history visuals if they exist
                     Visuals.removeByType('history');
                     Visuals.add(state.currentBestMove, 'history');
                }
                if(["themeBg", "themeText", "themeBorder", "themePrimary", "menuOpacity"].includes(key)) applyTheme();
                updateUI();
            });
        };

        const bindSlider = (rangeEl, numEl, key, isPct = false) => {
            if(!rangeEl || !numEl) return;
            rangeEl.oninput = () => {
                let val = parseFloat(rangeEl.value);
                saveSetting(key, val);
                numEl.value = isPct ? Math.round(val * 100) : val;
                if(key === "menuOpacity") applyTheme();
                if (state.currentBestMove) {
                    Visuals.removeByType('history');
                    Visuals.add(state.currentBestMove, 'history');
                }
            };
            numEl.oninput = () => {
                let val = parseFloat(numEl.value);
                if (isPct) val /= 100;
                saveSetting(key, val);
                rangeEl.value = val;
                if(key === "menuOpacity") applyTheme();
                if (state.currentBestMove) {
                    Visuals.removeByType('history');
                    Visuals.add(state.currentBestMove, 'history');
                }
            };
        };

        state.ui.selMenuPos.onchange = (e) => {
            saveSetting("menuPosition", e.target.value);
            applyMenuPosition();
        };

        state.ui.header.onmousedown = (e) => {
            if (e.target.id === "minBtn" || e.target.id === "btnReset") return;
            if (state.ui.panel.classList.contains("minified")) return;

            // Force custom mode on drag start
            if(settings.menuPosition !== 'custom') {
                saveSetting("menuPosition", 'custom');
                state.ui.selMenuPos.value = 'custom';
            }

            e.preventDefault();
            const startX = e.clientX - state.ui.panel.offsetLeft;
            const startY = e.clientY - state.ui.panel.offsetTop;

            const onMove = (mv) => {
                let x = mv.clientX - startX;
                let y = mv.clientY - startY;

                // Bounds
                x = Math.max(0, Math.min(x, window.innerWidth - state.ui.panel.offsetWidth));
                y = Math.max(0, Math.min(y, window.innerHeight - state.ui.panel.offsetHeight));

                state.ui.panel.style.left = x + "px";
                state.ui.panel.style.top = y + "px";
                state.ui.panel.style.right = "auto";
                state.ui.panel.style.bottom = "auto";

                saveSetting("pX", x);
                saveSetting("pY", y);
            };
            document.addEventListener("mousemove", onMove);
            document.onmouseup = () => document.removeEventListener("mousemove", onMove);
        };

        new ResizeObserver(() => {
            if (!state.ui.panel.classList.contains("minified")) {
                saveSetting("panelW", state.ui.panel.style.width);
                saveSetting("panelH", state.ui.panel.style.height);
            }
        }).observe(state.ui.panel);

        state.ui.selMode.onchange = (e) => { saveSetting("engineMode", e.target.value); state.isThinking = !1; if (settings.engineMode === "local") loadLocalEngine(); updateUI(); };
        state.ui.chkDebug.onchange = (e) => { saveSetting("debugLogs", e.target.checked); updateUI(); };

        // Duration Slider Logic
        const durSlider = document.getElementById("visDuration");
        const durText = document.getElementById("visDurationText");
        const rowFade = document.getElementById("rowFadeOut");
        const chkFade = document.getElementById("chkFadeOut");

        const sliderToSeconds = (val) => {
            if (val <= 0) return -1;
            if (val >= 100) return 0;
            let secs = 59.9 * Math.pow((val - 1) / 98, 2) + 0.1;
            return Math.round(secs * 10) / 10;
        };
        const secondsToSlider = (secs) => {
            if (secs === -1) return 0;
            if (secs === 0) return 100;
            return Math.round(Math.sqrt((secs - 0.1) / 59.9) * 98) + 1;
        };

        durSlider.value = secondsToSlider(settings.visualDuration);
        chkFade.checked = settings.visualFadeOut;

        const updateDurUI = () => {
            const val = parseInt(durSlider.value);
            if (val >= 100) {
                durText.innerText = "Forever";
                rowFade.style.display = "none";
                saveSetting("visualDuration", 0);
            } else if (val <= 0) {
                durText.innerText = "Disabled";
                rowFade.style.display = "none";
                saveSetting("visualDuration", -1);
            } else {
                const secs = sliderToSeconds(val);
                durText.innerText = secs.toFixed(1) + "s";
                rowFade.style.display = "flex";
                saveSetting("visualDuration", secs);
            }
        };
        durSlider.oninput = updateDurUI;
        chkFade.onchange = (e) => saveSetting("visualFadeOut", e.target.checked);
        updateDurUI();

        state.ui.visType.onchange = (e) => { saveSetting("visualType", e.target.value); toggleVisualInputs(); Visuals.removeByType('history'); if(state.currentBestMove) Visuals.add(state.currentBestMove, 'history'); };
        function toggleVisualInputs() {
            state.ui.visBoxSettings.style.display = "none";
            state.ui.visArrowSettings.style.display = "none";
            state.ui.visOutlineSettings.style.display = "none";
            if (settings.visualType === "arrow") state.ui.visArrowSettings.style.display = "block";
            else if (settings.visualType === "outline") state.ui.visOutlineSettings.style.display = "block";
            else state.ui.visBoxSettings.style.display = "block";
        }
        state.ui.visType.value = settings.visualType;
        toggleVisualInputs();

        // Tab & Colors
        state.ui.tabMove.onclick = () => { state.ui.tabMove.classList.add("active"); state.ui.tabTheme.classList.remove("active"); state.ui.tabContentMove.style.display = "block"; state.ui.tabContentTheme.style.display = "none"; };
        state.ui.tabTheme.onclick = () => { state.ui.tabTheme.classList.add("active"); state.ui.tabMove.classList.remove("active"); state.ui.tabContentTheme.style.display = "block"; state.ui.tabContentMove.style.display = "none"; };
        state.ui.advToggle.onclick = () => { const isH = state.ui.advSect.style.display==="none"; state.ui.advSect.style.display = isH?"block":"none"; state.ui.advToggle.innerText = isH?"▲ Advanced Visual Settings":"▼ Advanced Visual Settings"; };

        state.ui.btnThemeDark.onclick = () => {
            state.ui.colBg.value = "#222222"; state.ui.colTxt.value = "#eeeeee"; state.ui.colBorder.value = "#444444"; state.ui.colPrim.value = "#81b64c";
            ["themeBg", "themeText", "themeBorder", "themePrimary"].forEach(k => saveSetting(k, k==="themeBg"?"#222222":k==="themeText"?"#eeeeee":k==="themeBorder"?"#444444":"#81b64c"));
            applyTheme();
        };
        state.ui.btnThemeLight.onclick = () => {
            state.ui.colBg.value = "#f0f0f0"; state.ui.colTxt.value = "#222222"; state.ui.colBorder.value = "#cccccc"; state.ui.colPrim.value = "#81b64c";
            ["themeBg", "themeText", "themeBorder", "themePrimary"].forEach(k => saveSetting(k, k==="themeBg"?"#f0f0f0":k==="themeText"?"#222222":k==="themeBorder"?"#cccccc":"#81b64c"));
            applyTheme();
        };

        // Standard Bindings
        bind(state.ui.inpDepth, "depth", "num");
        bind(state.ui.inpTime, "maxThinkingTime", "num");
        bind(state.ui.inpContempt, "contempt", "num");
        bind(state.ui.inpSearch, "searchMoves");
        bind(state.ui.chkRun, "autoRun", "chk");
        bind(state.ui.chkMove, "autoMove", "chk");
        bind(state.ui.chkQueue, "autoQueue", "chk");
        bind(state.ui.chkHideAfterMove, "hideAfterMove", "chk");
        bind(state.ui.chkPV, "showPVArrows", "chk");
        bindSlider(state.ui.inpPVDepth, state.ui.inpPVDepthNum, "pvDepth", false);
        bind(state.ui.chkPVNums, "pvShowNumbers", "chk");
        bind(state.ui.chkPVGrad, "pvCustomGradient", "chk");
        bind(state.ui.inpPVStart, "pvStartColor");
        bind(state.ui.inpPVEnd, "pvEndColor");
        bind(state.ui.inpMin, "minDelay", "num");
        bind(state.ui.inpMax, "maxDelay", "num");
        bindSlider(state.ui.visInnerOp, state.ui.visInnerOpNum, "innerOpacity", true);
        bindSlider(state.ui.visOuterOp, state.ui.visOuterOpNum, "outerOpacity", true);
        bindSlider(state.ui.visBias, state.ui.visBiasNum, "gradientBias", false);
        bindSlider(state.ui.visArrowOp, state.ui.visArrowOpNum, "arrowOpacity", true);
        bindSlider(state.ui.visArrowWidth, state.ui.visArrowWidthNum, "arrowWidth", false);
        bindSlider(state.ui.visOutOp, state.ui.visOutOpNum, "visualOutlineOpacity", true);
        bindSlider(state.ui.visOutWidth, state.ui.visOutWidthNum, "visualOutlineWidth", false);
        bind(state.ui.visOutGlow, "visualOutlineGlow", "chk");
        bindSlider(state.ui.visOutGlowRad, state.ui.visOutGlowRadNum, "visualOutlineGlowRadius", false);
        bindSlider(state.ui.inpMenuOp, state.ui.inpMenuOpNum, "menuOpacity", true);
        bind(state.ui.colBg, "themeBg"); bind(state.ui.colTxt, "themeText"); bind(state.ui.colBorder, "themeBorder"); bind(state.ui.colPrim, "themePrimary");

        // Color Sliders
        [state.ui.sliderH, state.ui.sliderS, state.ui.sliderL].forEach(el => { el.oninput = () => { state.h=parseFloat(state.ui.sliderH.value); state.s=parseFloat(state.ui.sliderS.value); state.l=parseFloat(state.ui.sliderL.value); syncColor(); }});
        state.ui.inpHex.onchange = (e) => { if(/^#[0-9A-F]{6}$/i.test(e.target.value)) { const rgb=hexToRgb(e.target.value); const hsl=rgbToHsl(rgb.r,rgb.g,rgb.b); state.h=hsl.h; state.s=hsl.s; state.l=hsl.l; syncColor(); }};
    }

    function drawFenBoard(fen) {
        let rows = fen.split(" ")[0].split("/");
        let board = [];
        for (let r of rows) {
            let rowArr = [];
            for (let char of r) {
                if (!isNaN(char)) {
                    let empties = parseInt(char);
                    for (let k = 0; k < empties; k++) rowArr.push("");
                } else {
                    rowArr.push(char);
                }
            }
            board.push(rowArr);
        }
        let html = '<div class="fen-board">';
        for (let r = 0; r < 8; r++) {
            for (let c = 0; c < 8; c++) {
                const piece = board[r][c];
                const isDark = (r + c) % 2 === 1;
                const bg = piece ? `style="background-image: url('${PIECE_IMGS[piece]}');"` : "";
                html += `<div class="fen-sq ${isDark ? "dark" : "light"}" ${bg}></div>`;
            }
        }
        html += "</div>";
        return html;
    }
    function renderHistory() {
        if (!state.ui.histBody) return;
        state.ui.histBody.innerHTML = "";
        if (state.history.length === 0) {
            state.ui.histBody.innerHTML = '<tr><td colspan="5" id="histEmpty">No history yet.</td></tr>';
            return;
        }
        const sorted = [...state.history].reverse();
        sorted.forEach((item, index) => {
            const tr = document.createElement("tr");
            let resClass = "hist-draw";
            if (item.result === "Win") resClass = "hist-win";
            else if (item.result === "Loss") resClass = "hist-loss";
            tr.innerHTML = `
                <td>${item.date}</td>
                <td style="font-weight:bold; color:${item.color === "White" ? "#ffffff" : "#888888"};">${item.color || "N/A"}</td>
                <td class="${resClass}">${item.result}</td>
                <td>${item.myTime} / ${item.oppTime}</td>
                <td class="hist-fen" data-fen="${item.fen}">${item.fen}</td>
                <td><button class="btn-del" data-idx="${state.history.length - 1 - index}">Delete</button></td>
            `;
            state.ui.histBody.appendChild(tr);
        });
        document.querySelectorAll(".btn-del").forEach((btn) => {
            btn.onclick = (e) => {
                const idx = parseInt(e.target.dataset.idx);
                state.history.splice(idx, 1);
                GM_setValue("bot_history", state.history);
                renderHistory();
            };
        });
        document.querySelectorAll(".hist-fen").forEach((el) => {
            el.onmouseenter = (e) => {
                const fen = e.target.getAttribute("data-fen");
                if (fen && state.ui.fenTooltip) {
                    state.ui.fenTooltip.innerHTML = drawFenBoard(fen);
                    state.ui.fenTooltip.style.display = "block";
                    const rect = e.target.getBoundingClientRect();
                    let left = rect.left + 20;
                    let top = rect.bottom + 5;
                    if (left + 250 > window.innerWidth) left = window.innerWidth - 260;
                    if (top + 250 > window.innerHeight) top = rect.top - 260;
                    state.ui.fenTooltip.style.left = left + "px";
                    state.ui.fenTooltip.style.top = top + "px";
                }
            };
            el.onmouseleave = () => {
                if (state.ui.fenTooltip) state.ui.fenTooltip.style.display = "none";
            };
        });
    }
    function checkForGameOver() {
        if (!settings.enableHistory) return;
        const resultEl = document.querySelector(
            ".game-result-component, .game-over-modal-content, .daily-game-footer-game-over"
        );
        if (resultEl) {
            if (state.hasSavedCurrentGameResult) return;
            let fen = sanitizeFEN(getRawBoardFEN());
            let playingAsCode = state.playingAs;
            if (!playingAsCode && state.board?.game?.getPlayingAs) {
                try {
                    playingAsCode = state.board.game.getPlayingAs();
                } catch (e) {}
            }
            if (playingAsCode !== 1 && playingAsCode !== 2) playingAsCode = 0;
            const playerColor = playingAsCode === 2 ? "Black" : "White";
            if (playingAsCode === 2) {
                let parts = fen.split(" ");
                if (parts.length > 0) {
                    parts[0] = parts[0]
                        .split("/")
                        .reverse()
                        .map((row) => {
                            return row.split("").reverse().join("");
                        })
                        .join("/");
                    fen = parts.join(" ");
                }
            }
            let myTime = "N/A";
            let oppTime = "N/A";
            const clockBot = document.querySelector(".clock-bottom .clock-time-monospace, .clock-bottom");
            const clockTop = document.querySelector(".clock-top .clock-time-monospace, .clock-top");
            if (clockBot) myTime = clockBot.innerText;
            if (clockTop) oppTime = clockTop.innerText;
            let resultTxt = "Ended";
            let simpleRes = "Draw";
            const mainMsg = resultEl.querySelector(".game-result-main-message, .game-over-header-title");
            if (mainMsg) resultTxt = mainMsg.innerText.trim();
            else resultTxt = resultEl.innerText.split("\n")[0].trim();
            const subMsgEl = resultEl.querySelector(".game-result-sub-message, .game-over-header-subtitle");
            let subMsg = subMsgEl ? subMsgEl.innerText.trim() : "";
            const fullText = (resultTxt + " " + subMsg).toLowerCase();
            if (resultEl.classList.contains("game-result-win")) {
                simpleRes = "Win";
            } else if (resultEl.classList.contains("game-result-loss")) {
                simpleRes = "Loss";
            } else if (resultEl.classList.contains("game-result-draw")) {
                simpleRes = "Draw";
            } else if (fullText.includes("you won")) {
                simpleRes = "Win";
            } else if (fullText.includes("you lost")) {
                simpleRes = "Loss";
            } else if (playingAsCode === 1 && fullText.includes("white won")) {
                simpleRes = "Win";
            } else if (playingAsCode === 1 && fullText.includes("black won")) {
                simpleRes = "Loss";
            } else if (playingAsCode === 2 && fullText.includes("black won")) {
                simpleRes = "Win";
            } else if (playingAsCode === 2 && fullText.includes("white won")) {
                simpleRes = "Loss";
            }
            const gameObj = {
                date: new Date().toLocaleString(),
                color: playerColor,
                result: simpleRes,
                fen: fen,
                myTime: myTime,
                oppTime: oppTime,
                id: Date.now(),
            };
            state.history.push(gameObj);
            if (state.history.length > 200) state.history.shift();
            GM_setValue("bot_history", state.history);
            state.hasSavedCurrentGameResult = !0;
            if (state.ui.histModal && state.ui.histModal.style.display !== "none") renderHistory();
        } else {
            state.hasSavedCurrentGameResult = !1;
        }
    }
    function enforceBounds() {
        if (state.ui.panel) {
            const rect = state.ui.panel.getBoundingClientRect();
            const winW = window.innerWidth;
            const winH = window.innerHeight;
            if (rect.right > winW) state.ui.panel.style.width = winW - rect.left + "px";
            if (rect.bottom > winH) state.ui.panel.style.height = winH - rect.top + "px";
            if (rect.left < 0) state.ui.panel.style.left = "0px";
            if (rect.top < 0) state.ui.panel.style.top = "0px";
        }
        requestAnimationFrame(enforceBounds);
    }
    requestAnimationFrame(enforceBounds);
    function updateUI() {
        if (!state.ui.panel) return;
        document.body.classList.remove("mode-cloud", "mode-local", "mode-sfonline");
        document.body.classList.add(`mode-${settings.engineMode}`);
        if (state.ui.debugArea) state.ui.debugArea.style.display = settings.debugLogs ? "block" : "none";
        let maxD = 18;
        if (settings.engineMode === "local") maxD = 23;
        else if (settings.engineMode === "sfonline") maxD = 15;
        if (state.ui.lblMaxDepth) state.ui.lblMaxDepth.innerText = maxD;
        if (state.ui.inpDepth) state.ui.inpDepth.max = maxD;
        if (state.ui.inpPVDepth) {
            state.ui.inpPVDepth.max = 45;
        }
        if (state.ui.pvSettings) {
            state.ui.pvSettings.style.display = settings.showPVArrows ? "block" : "none";
        }
        if (state.ui.pvGradSettings) {
            state.ui.pvGradSettings.style.display = settings.pvCustomGradient ? "block" : "none";
        }
        if (state.ui.btnAnalyze) state.ui.btnAnalyze.disabled = state.isThinking;
        if (state.ui.moveResult) state.ui.moveResult.innerHTML = state.lastMoveResult;
        if (state.ui.liveOutput) state.ui.liveOutput.innerHTML = state.lastLiveResult;
        if (state.ui.delayDisplay) state.ui.delayDisplay.innerText = `Randomized Delay: ${state.calculatedDelay}s`;
        if (state.ui.logSent) state.ui.logSent.innerText = state.lastPayload;
        if (state.ui.logRec) state.ui.logRec.innerText = state.lastResponse;
        if (document.activeElement !== state.ui.inpDepth) state.ui.inpDepth.value = settings.depth;
    }
    function mainLoop() {
        if (state.board?.game && settings.autoRun) {
            const raw = getRawBoardFEN();
            if (raw) {
                const clean = sanitizeFEN(raw);

                // ── NEW: Hard-shutoff all visuals the instant any move is played ──
                if (settings.hideAfterMove && state.lastSeenFEN && clean !== state.lastSeenFEN) {
                    Visuals.removeByType('history');
                    Visuals.removeByType('analysis');
                    PV.clear();
                }
                state.lastSeenFEN = clean;
                // ─────────────────────────────────────────────────────────────────

                const isTurn = state.board.game.getTurn() === state.board.game.getPlayingAs();
                if (isTurn && clean !== state.lastSanitizedBoardFEN) {
                    analyze(settings.depth);
                }
            }
        }
        state.board = document.querySelector(CONFIG.BOARD_SEL);
        if (!state.ui.panel) createUI();
        if (state.board?.game?.getPlayingAs) {
            try {
                const pa = state.board.game.getPlayingAs();
                if (pa === 1 || pa === 2) state.playingAs = pa;
            } catch (e) {}
        }
        if (state.board?.game && settings.autoRun) {
            const raw = getRawBoardFEN();
            if (raw) {
                const clean = sanitizeFEN(raw);
                const isTurn = state.board.game.getTurn() === state.board.game.getPlayingAs();
                if (isTurn && clean !== state.lastSanitizedBoardFEN) {
                    analyze(settings.depth);
                }
            }
        }
        checkForGameOver();
        updateUI();
    }
    setInterval(mainLoop, CONFIG.LOOP_MS);
})();