FlatMMO UI Tweaks

Adds a modern skills panel, custom themes, and a portrait mode layout.

// ==UserScript==
// @name         FlatMMO UI Tweaks
// @namespace    com.pizza1337.flatmmo.uitweaks
// @version      1.1.3
// @description  Adds a modern skills panel, custom themes, and a portrait mode layout.
// @author       Pizza1337
// @match        *://flatmmo.com/play.php*
// @grant        none
// @require      https://update.greasyfork.org/scripts/544062/FlatMMOPlus.js
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    class UITweaksPlugin extends FlatMMOPlusPlugin {
        constructor() {
            super("ui-tweaks", {
                about: {
                    name: GM_info.script.name,
                    version: GM_info.script.version,
                    author: GM_info.script.author,
                    description: GM_info.script.description
                },
                config: [
                    {
                        id: "showSkillsPanel",
                        label: "Modern Skills Panel",
                        type: "boolean",
                        default: true
                    },
                    {
                        id: "portraitMode",
                        label: "Portrait Mode (F5 Required)",
                        type: "boolean",
                        default: false
                    },
                    {
                        id: "theme",
                        label: "UI Theme",
                        type: "select",
                        options: [
                            { value: "default", label: "Default" },
                            { value: "dark", label: "Dark Mode" },
                            { value: "pumpkin", label: "Pumpkin Spice" },
                            { value: "sea", label: "Deep Sea" },
                            { value: "mystic", label: "Mystic Vale" },
                            { value: "omboko", label: "Omboko" }
                        ],
                        default: "default"
                    }
                ]
            });

            this.skillUI = { elements: {}, total: {} };
            this.isGridCreated = false;
            this.initialized = false;

            this.injectStyles();
        }

        onLogin() {
            if (this.initialized) return;
            this.initialized = true;

            this.applyTheme(this.getConfig('theme'));

            if (this.getConfig('portraitMode')) {
                const layoutObserver = new MutationObserver((mutations, observer) => {
                    if (document.querySelector('#game table canvas')) {
                        this.moveUiBelowCanvas();
                        observer.disconnect();
                    }
                });
                layoutObserver.observe(document.body, { childList: true, subtree: true });
            }
        }

        onPanelChanged(panelBefore, panelAfter) {
            if (panelAfter === 'skills') {
                this.createSkillsGrid();
            }
        }

        onConfigsChanged() {
            this.applyTheme(this.getConfig('theme'));

            if (this.getConfig('showSkillsPanel')) {
                if (document.querySelector("#ui-panel-skills")?.style.display !== "none") {
                    this.createSkillsGrid();
                }
            } else {
                this.destroySkillsGrid();
            }
        }

        injectStyles() {
             const styles = `
                /* --- General UI Fixes --- */
                .settings-ui td:first-child {
                    padding-left: 10px;
                }
                .tm-settings-row td {
                    padding-top: 5px;
                    padding-bottom: 5px;
                }

                /* --- Shared readability rules for dark themes --- */
                body.theme-dark a, body.theme-pumpkin a, body.theme-sea a, body.theme-omboko a, body.theme-mystic a { color: #8ab4f8 !important; }
                body.theme-dark a:hover, body.theme-pumpkin a:hover, body.theme-sea a:hover, body.theme-omboko a:hover, body.theme-mystic a:hover { color: #c3dafa !important; }

                /* --- Dark Mode Theme --- */
                body.theme-dark .ui-panel, body.theme-dark .modal-content,
                body.theme-dark .ach-sub-menu-btn-td, body.theme-dark .donor-shop-entry, body.theme-dark .ui-donor-chat-tags-info,
                body.theme-dark .npc-chat-options-modal-title, body.theme-dark .npc-chat-options-modal-options div {
                    background-color: #2c2f33; color: #f1f1f1; box-shadow: 1px 1px 5px #121212;
                }
                body.theme-dark table.settings-ui tr:nth-child(odd), body.theme-dark .quests-ui tr:nth-child(odd),
                body.theme-dark .monster-log-ui-table tr:nth-child(odd) { background-color: #3c4045; }
                body.theme-dark table.settings-ui tr:nth-child(even), body.theme-dark .quests-ui tr:nth-child(even),
                body.theme-dark .monster-log-ui-table tr:nth-child(even) { background-color: #32353b; }
                body.theme-dark .achievements-ui tr { background-color: #323b33; border-color: #455a46; }
                body.theme-dark .total-level-div { background-color: #23272a !important; }
                body.theme-dark .hint, body.theme-dark .color-grey, body.theme-dark .modal-content h3[style*="color: grey"] { color: #b0b0b0 !important; }
                body.theme-dark .right-click-item-modal-table { background-color: #32353b; }
                body.theme-dark .right-click-item-modal-table span[style*="color:grey"] { color: #b0b0b0 !important; }
                body.theme-dark .equipement-stats-ui-table, body.theme-dark .right-click-item-modal-table-stats,
                body.theme-dark .monster-log-modal-drops, body.theme-dark .npc-chat-message-modal-message,
                body.theme-dark .player-sell-booth-entry td, body.theme-dark .player-lookup-modal-quests,
                body.theme-dark .player-lookup-modal-achievements { background-color: rgba(0, 0, 0, 0.2); }
                body.theme-dark div[style*="color:green"], body.theme-dark .color-green { color: #6fbf73 !important; }
                body.theme-dark .color-red { color: #ff8a80 !important; }
                body.theme-dark .ach-sub-menu-btn-td:hover, body.theme-dark .npc-chat-options-modal-options div:hover { background-color: #4a4e53; }
                body.theme-dark .hover-continue-npc-chat-message-modal:hover { color: #ff8a80 !important; }
                body.theme-dark button { background-color: #4a4e53; color: #f1f1f1; border: 1px solid #6a6e73; }
                body.theme-dark button:hover { background-color: #5a5e63; }
                body.theme-dark button:disabled { background-color: #2a2e33; color: #6a6e73; border-color: #4a4e53; }
                body.theme-dark .player-lookup-modal-table-skills td { background-color: #3c4045 !important; }
                body.theme-dark .player-lookup-modal-quest-entry { background-color: #32353b; }

                /* --- Pumpkin Spice Theme --- */
                body.theme-pumpkin .ui-panel, body.theme-pumpkin .modal-content,
                body.theme-pumpkin .ach-sub-menu-btn-td, body.theme-pumpkin .donor-shop-entry, body.theme-pumpkin .ui-donor-chat-tags-info,
                body.theme-pumpkin .npc-chat-options-modal-title, body.theme-pumpkin .npc-chat-options-modal-options div {
                    background-color: #2a2421; color: #f5e4d9; box-shadow: 1px 1px 5px #1a1411; border: 1px solid #4a3421;
                }
                body.theme-pumpkin .ui-panel-title { color: #e67e22; }
                body.theme-pumpkin table.settings-ui tr:nth-child(odd), body.theme-pumpkin .quests-ui tr:nth-child(odd),
                body.theme-pumpkin .monster-log-ui-table tr:nth-child(odd) { background-color: #3b312c; }
                body.theme-pumpkin table.settings-ui tr:nth-child(even), body.theme-pumpkin .quests-ui tr:nth-child(even),
                body.theme-pumpkin .monster-log-ui-table tr:nth-child(even) { background-color: #312925; }
                body.theme-pumpkin .achievements-ui tr { background-color: #3b2e25; border-color: #5a4431; }
                body.theme-pumpkin .skill-cell-bar-fill { background-color: #d35400 !important; }
                body.theme-pumpkin .total-level-div { background-color: #1c1815 !important; }
                body.theme-pumpkin .hint, body.theme-pumpkin .color-grey, body.theme-pumpkin .modal-content h3[style*="color: grey"] { color: #c9bca2 !important; }
                body.theme-pumpkin .right-click-item-modal-table { background-color: #312925; }
                body.theme-pumpkin .right-click-item-modal-table span[style*="color:grey"] { color: #c9bca2 !important; }
                body.theme-pumpkin .equipement-stats-ui-table, body.theme-pumpkin .right-click-item-modal-table-stats,
                body.theme-pumpkin .monster-log-modal-drops, body.theme-pumpkin .npc-chat-message-modal-message,
                body.theme-pumpkin .player-sell-booth-entry td, body.theme-pumpkin .player-lookup-modal-quests,
                body.theme-pumpkin .player-lookup-modal-achievements { background-color: rgba(40, 26, 13, 0.2); }
                body.theme-pumpkin div[style*="color:green"], body.theme-pumpkin .color-green { color: #e67e22 !important; }
                body.theme-pumpkin .color-red { color: #e84c3d !important; }
                body.theme-pumpkin a { color: #f39c12 !important; }
                body.theme-pumpkin .ach-sub-menu-btn-td:hover, body.theme-pumpkin .npc-chat-options-modal-options div:hover { background-color: #4a3c35; }
                body.theme-pumpkin .hover-continue-npc-chat-message-modal:hover { color: #ffab70 !important; }
                body.theme-pumpkin button { background-color: #4a3c35; color: #f5e4d9; border: 1px solid #6a5c55; }
                body.theme-pumpkin button:hover { background-color: #5a4c45; }
                body.theme-pumpkin button:disabled { background-color: #2a2421; color: #6a5c55; border-color: #4a3421; }
                body.theme-pumpkin .player-lookup-modal-table-skills td { background-color: #3b312c !important; }
                body.theme-pumpkin .player-lookup-modal-quest-entry { background-color: #312925; }

                /* --- Deep Sea Theme --- */
                body.theme-sea .ui-panel, body.theme-sea .modal-content,
                body.theme-sea .ach-sub-menu-btn-td, body.theme-sea .donor-shop-entry, body.theme-sea .ui-donor-chat-tags-info,
                body.theme-sea .npc-chat-options-modal-title, body.theme-sea .npc-chat-options-modal-options div {
                    background-color: #0d253f; color: #e1f5fe; box-shadow: 1px 1px 5px #051525; border: 1px solid #01b4e4;
                }
                body.theme-sea .ui-panel-title { color: #90cea1; }
                body.theme-sea table.settings-ui tr:nth-child(odd), body.theme-sea .quests-ui tr:nth-child(odd),
                body.theme-sea .monster-log-ui-table tr:nth-child(odd) { background-color: #0a1d31; }
                body.theme-sea table.settings-ui tr:nth-child(even), body.theme-sea .quests-ui tr:nth-child(even),
                body.theme-sea .monster-log-ui-table tr:nth-child(even) { background-color: #102a45; }
                body.theme-sea .achievements-ui tr { background-color: #103a45; border-color: #1a5a65; }
                body.theme-sea .skill-cell-bar-fill { background-color: #01b4e4 !important; }
                body.theme-sea .total-level-div { background-color: #071726 !important; }
                body.theme-sea .hint, body.theme-sea .color-grey, body.theme-sea .modal-content h3[style*="color: grey"] { color: #a4c8d1 !important; }
                body.theme-sea .right-click-item-modal-table { background-color: #102a45; }
                body.theme-sea .right-click-item-modal-table span[style*="color:grey"] { color: #a4c8d1 !important; }
                body.theme-sea .equipement-stats-ui-table, body.theme-sea .right-click-item-modal-table-stats,
                body.theme-sea .monster-log-modal-drops, body.theme-sea .npc-chat-message-modal-message,
                body.theme-sea .player-sell-booth-entry td, body.theme-sea .player-lookup-modal-quests,
                body.theme-sea .player-lookup-modal-achievements { background-color: rgba(1, 180, 228, 0.1); }
                body.theme-sea div[style*="color:green"], body.theme-sea .color-green { color: #90cea1 !important; }
                body.theme-sea .color-red { color: #5eb5b9 !important; }
                body.theme-sea a { color: #01b4e4 !important; }
                body.theme-sea .ach-sub-menu-btn-td:hover, body.theme-sea .npc-chat-options-modal-options div:hover { background-color: #133a5f; }
                body.theme-sea .hover-continue-npc-chat-message-modal:hover { color: #66d9ff !important; }
                body.theme-sea button { background-color: #133a5f; color: #e1f5fe; border: 1px solid #235a7f; }
                body.theme-sea button:hover { background-color: #234a6f; }
                body.theme-sea button:disabled { background-color: #0d253f; color: #235a7f; border-color: #133a5f; }
                body.theme-sea .player-lookup-modal-table-skills td { background-color: #0a1d31 !important; }
                body.theme-sea .player-lookup-modal-quest-entry { background-color: #102a45; }

                /* --- Mystic Vale Theme (Darker) --- */
                body.theme-mystic .ui-panel, body.theme-mystic .modal-content,
                body.theme-mystic .ach-sub-menu-btn-td, body.theme-mystic .donor-shop-entry, body.theme-mystic .ui-donor-chat-tags-info,
                body.theme-mystic .npc-chat-options-modal-title, body.theme-mystic .npc-chat-options-modal-options div {
                    background-color: #6A6E94; color: #f0f0f0; box-shadow: 1px 1px 5px #4a4c6a;
                }
                body.theme-mystic .ui-panel-title { color: #d1d3e0; }
                body.theme-mystic table.settings-ui tr:nth-child(odd), body.theme-mystic .quests-ui tr:nth-child(odd),
                body.theme-mystic .monster-log-ui-table tr:nth-child(odd) { background-color: #7A7EA1; }
                body.theme-mystic table.settings-ui tr:nth-child(even), body.theme-mystic .quests-ui tr:nth-child(even),
                body.theme-mystic .monster-log-ui-table tr:nth-child(even) { background-color: #868AAD; }
                body.theme-mystic .achievements-ui tr { background-color: #7a8aa1; border-color: #9598b9; }
                body.theme-mystic .skill-cell-bar-fill { background-color: #9598B9 !important; }
                body.theme-mystic .skill-cell { background-color: #5f6284 !important; }
                body.theme-mystic .total-level-div { background-color: #5f6284 !important; color: #f0f0f0 !important; }
                body.theme-mystic .hint, body.theme-mystic .color-grey, body.theme-mystic .modal-content h3[style*="color: grey"] { color: #d1d3e0 !important; }
                body.theme-mystic .right-click-item-modal-table { background-color: #868AAD; }
                body.theme-mystic .right-click-item-modal-table span[style*="color:grey"] { color: #d1d3e0 !important; }
                body.theme-mystic .equipement-stats-ui-table, body.theme-mystic .right-click-item-modal-table-stats,
                body.theme-mystic .monster-log-modal-drops, body.theme-mystic .npc-chat-message-modal-message,
                body.theme-mystic .player-sell-booth-entry td, body.theme-mystic .player-lookup-modal-quests,
                body.theme-mystic .player-lookup-modal-achievements { background-color: rgba(60, 62, 84, 0.2); }
                body.theme-mystic div[style*="color:green"], body.theme-mystic .green-hover:hover, body.theme-mystic .color-green { color: #b2fab4 !important; }
                body.theme-mystic .color-red { color: #f5c0c0 !important; }
                body.theme-mystic .color-blue { color: #a6cfff !important; }
                body.theme-mystic a { color: #d1d3e0 !important; }
                body.theme-mystic .ach-sub-menu-btn-td:hover, body.theme-mystic .npc-chat-options-modal-options div:hover { background-color: #7A7EA1; }
                body.theme-mystic .hover-continue-npc-chat-message-modal:hover { color: #f5c0c0 !important; }
                body.theme-mystic button { background-color: #7A7EA1; color: #f0f0f0; border: 1px solid #9598B9; }
                body.theme-mystic button:hover { background-color: #868AAD; }
                body.theme-mystic button:disabled { background-color: #6A6E94; color: #9598B9; border-color: #5f6284; }
                body.theme-mystic .player-lookup-modal-table-skills td { background-color: #7A7EA1 !important; }
                body.theme-mystic .player-lookup-modal-quest-entry { background-color: #868AAD; }

                /* --- Omboko Theme --- */
                body.theme-omboko .ui-panel, body.theme-omboko .modal-content,
                body.theme-omboko .ach-sub-menu-btn-td, body.theme-omboko .donor-shop-entry, body.theme-omboko .ui-donor-chat-tags-info,
                body.theme-omboko .npc-chat-options-modal-title, body.theme-omboko .npc-chat-options-modal-options div {
                    background-color: #1D2319; color: #d1dcc6; box-shadow: 1px 1px 5px #000; border: 1px solid #4B682E;
                }
                body.theme-omboko .ui-panel-title { color: #9eb883; }
                body.theme-omboko table.settings-ui tr:nth-child(odd), body.theme-omboko .quests-ui tr:nth-child(odd),
                body.theme-omboko .monster-log-ui-table tr:nth-child(odd) { background-color: #25311B; }
                body.theme-omboko table.settings-ui tr:nth-child(even), body.theme-omboko .quests-ui tr:nth-child(even),
                body.theme-omboko .monster-log-ui-table tr:nth-child(even) { background-color: #30411F; }
                body.theme-omboko .achievements-ui tr { background-color: #30411F; border-color: #4B682E; }
                body.theme-omboko .skill-cell-bar-fill { background-color: #4B682E !important; }
                body.theme-omboko .skill-cell { background-color: #30411F !important; }
                body.theme-omboko .total-level-div { background-color: #11150f !important; }
                body.theme-omboko .hint, body.theme-omboko .color-grey, body.theme-omboko .modal-content h3[style*="color: grey"] { color: #8f9984 !important; }
                body.theme-omboko .right-click-item-modal-table { background-color: #30411F; }
                body.theme-omboko .right-click-item-modal-table span[style*="color:grey"] { color: #8f9984 !important; }
                body.theme-omboko .equipement-stats-ui-table, body.theme-omboko .right-click-item-modal-table-stats,
                body.theme-omboko .monster-log-modal-drops, body.theme-omboko .npc-chat-message-modal-message,
                body.theme-omboko .player-sell-booth-entry td, body.theme-omboko .player-lookup-modal-quests,
                body.theme-omboko .player-lookup-modal-achievements { background-color: rgba(75, 104, 46, 0.1); }
                body.theme-omboko div[style*="color:green"], body.theme-omboko .color-green { color: #9eb883 !important; }
                body.theme-omboko .color-red { color: #e57373 !important; }
                body.theme-omboko a { color: #9eb883 !important; }
                body.theme-omboko .ach-sub-menu-btn-td:hover, body.theme-omboko .npc-chat-options-modal-options div:hover { background-color: #3D5426; }
                body.theme-omboko .hover-continue-npc-chat-message-modal:hover { color: #c4d6b1 !important; }
                body.theme-omboko button { background-color: #3D5426; color: #d1dcc6; border: 1px solid #4B682E; }
                body.theme-omboko button:hover { background-color: #4B682E; }
                body.theme-omboko button:disabled { background-color: #1D2319; color: #4B682E; border-color: #25311B; }
                body.theme-omboko .player-lookup-modal-table-skills td { background-color: #25311B !important; }
                body.theme-omboko .player-lookup-modal-quest-entry { background-color: #30411F; }
            `;
            const styleSheet = document.createElement("style");
            styleSheet.type = "text/css";
            styleSheet.innerText = styles;
            document.head.appendChild(styleSheet);
        }

        applyTheme(themeName) {
            document.body.className = document.body.className.replace(/theme-\w+/g, '');
            if (themeName && themeName !== 'default') {
                document.body.classList.add(`theme-${themeName}`);
            }
        }

        get_xp_for_level(level) {
            if (level <= 1) return 0;
            return parseInt(Math.pow(level, 3 + (level / 200)));
        }

        recalculateAndDisplayTotal() {
            if (!this.skillUI.total.textSpan || !this.skillUI.total.tooltip) return;
            let totalLevel = 0;
            let totalXp = 0;
            for (const skillName in this.skillUI.elements) {
                totalLevel += this.skillUI.elements[skillName].level || 0;
                totalXp += this.skillUI.elements[skillName].xp || 0;
            }
            this.skillUI.total.textSpan.innerText = `TOTAL ${totalLevel}`;
            this.skillUI.total.tooltip.textContent = `${totalXp.toLocaleString('en-US')} XP`;
        }

        updateSkillCell(skillName) {
            const component = this.skillUI.elements[skillName];
            if (!component || !component.originalLevelEl) return;

            const levelText = component.originalLevelEl.innerText;
            const xpTooltipText = component.originalXpEl.innerHTML;
            const xpDataText = xpTooltipText.split('<br>').pop().trim();

            const currentLevel = parseInt(levelText);
            const [currentStr, maxStr] = xpDataText.replace(" XP", "").split("/");
            const currentXP = parseInt(currentStr.replace(/,/g, "")) || 0;
            const nextLevelXP = parseInt(maxStr.replace(/,/g, "")) || 0;

            component.level = currentLevel;
            component.xp = currentXP;

            const previousLevelXP = this.get_xp_for_level(currentLevel);
            const xpGainedThisLevel = Math.max(0, currentXP - previousLevelXP);
            const xpNeededForThisLevel = nextLevelXP - previousLevelXP;

            let progress = 0;
            if (xpNeededForThisLevel > 0) {
                progress = Math.min((xpGainedThisLevel / xpNeededForThisLevel) * 100, 100);
            }

            component.label.innerText = currentLevel;
            component.tooltip.textContent = xpDataText;
            component.barFill.style.width = `${progress}%`;

            this.recalculateAndDisplayTotal();
        }

        moveUiBelowCanvas() {
            const table = document.querySelector('#game table');
            if (!table) return;

            const canvas = table.querySelector('canvas');
            const canvasTd = canvas?.closest('td');
            const uiTd = table.querySelector('.td-ui');

            if (canvas && canvasTd && uiTd) {
                const newTbody = document.createElement('tbody');
                const canvasRow = document.createElement('tr');
                const uiRow = document.createElement('tr');

                canvasRow.appendChild(canvasTd);
                uiRow.appendChild(uiTd);
                newTbody.append(canvasRow, uiRow);
                table.innerHTML = '';
                table.appendChild(newTbody);

                uiTd.style.cssText = 'padding: 0; margin: 0; overflow: hidden; position: relative;';
                const uiWrapper = document.createElement('div');
                uiWrapper.style.transformOrigin = 'top left';
                uiWrapper.style.display = 'inline-block';

                while (uiTd.firstChild) {
                    uiWrapper.appendChild(uiTd.firstChild);
                }
                uiTd.appendChild(uiWrapper);

                const applyZoomAndWidthFix = () => {
                    const canvasWidth = canvas.offsetWidth;
                    const ratio = window.devicePixelRatio || 1;
                    const scale = 1 / ratio;

                    uiWrapper.style.transform = `scale(${scale})`;
                    uiWrapper.style.width = `${canvasWidth * ratio}px`;

                    requestAnimationFrame(() => {
                        const realHeight = uiWrapper.getBoundingClientRect().height;
                        uiTd.style.height = `${realHeight}px`;
                    });
                };

                applyZoomAndWidthFix();
                window.addEventListener('resize', applyZoomAndWidthFix);
            }
        }

        createSkillsGrid() {
            if (this.isGridCreated || !this.getConfig('showSkillsPanel')) {
                if (this.isGridCreated && !this.getConfig('showSkillsPanel')) {
                    this.destroySkillsGrid();
                }
                return;
            }

            const skillPanel = document.querySelector("#ui-panel-skills");
            const skillContainer = skillPanel?.querySelector("center");

            if (skillPanel && skillContainer) {
                const skillDivs = Array.from(skillContainer.querySelectorAll("div.skills-ui-new"));
                if (skillDivs.length > 0) {
                    this.isGridCreated = true;

                    const grid = document.createElement("div");
                    grid.style.cssText = "display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 20px 0;";
                    grid.id = "tm-skills-grid";

                    skillDivs.slice(0, -1).forEach(skillDiv => {
                        const levelEl = skillDiv.querySelector("span[id$='-level']");
                        if (!levelEl) return;
                        const skillName = levelEl.id.replace('-level', '');
                        const iconEl = skillDiv.querySelector("img");
                        const xpEl = skillDiv.querySelector("span[id$='-xp']");
                        const onclickAttr = skillDiv.getAttribute("onclick");

                        const cell = document.createElement("div");
                        cell.style.cssText = `display: flex; flex-direction: column; align-items: center; justify-content: space-between; background: #222; color: #fff; padding: 10px; border-radius: 8px; cursor: pointer;`;
                        cell.classList.add('skill-cell');
                        if (onclickAttr) cell.onclick = () => eval(onclickAttr);

                        const img = document.createElement("img");
                        img.src = iconEl.src;
                        img.style.cssText = "width: 32px; height: 32px; margin-bottom: 5px;";

                        const label = document.createElement("div");
                        label.style.fontSize = '16pt';
                        label.style.fontWeight = 'bold';

                        const spacer = document.createElement("div");
                        spacer.style.flexGrow = "1";

                        const barContainer = document.createElement("div");
                        barContainer.style.cssText = `width: 100%; height: 6px; background: #444; border-radius: 4px; margin-top: 6px; overflow: hidden;`;
                        const barFill = document.createElement("div");
                        barFill.style.cssText = "height: 100%; background: #00cc66; border-radius: 4px 0 0 4px;";
                        barFill.classList.add('skill-cell-bar-fill');
                        barContainer.appendChild(barFill);

                        const tooltip = document.createElement("div");
                        let tooltipStyle = `position: fixed; padding: 6px 10px; background: #333; color: #fff; border-radius: 6px; font-size: 14px; box-shadow: 0 2px 6px rgba(0,0,0,0.4); pointer-events: none; z-index: 9999; white-space: nowrap; display: none;`;

                        if (this.getConfig('portraitMode')) {
                            const ratio = window.devicePixelRatio || 1;
                            const scale = 1 / ratio;
                            tooltipStyle += `transform: scale(${scale}); transform-origin: left top;`;
                        }
                        tooltip.style.cssText = tooltipStyle;
                        document.body.appendChild(tooltip);

                        cell.addEventListener("mousemove", e => {
                            tooltip.style.left = `${e.pageX + 15}px`;
                            tooltip.style.top = `${e.pageY + 10}px`;
                        });
                        cell.addEventListener("mouseenter", () => { tooltip.style.display = "block"; });
                        cell.addEventListener("mouseleave", () => { tooltip.style.display = "none"; });

                        cell.append(img, label, spacer, barContainer);
                        grid.appendChild(cell);

                        this.skillUI.elements[skillName] = { label, barFill, tooltip, originalLevelEl: levelEl, originalXpEl: xpEl };
                        this.updateSkillCell(skillName);
                    });

                    const totalDiv = document.createElement("div");
                    totalDiv.style.cssText = `display: flex; align-items: center; justify-content: center; text-align: center; margin-top: 10px; padding: 10px; background: #444; color: #fff; font-weight: bold; border-radius: 8px; font-size: 16pt;`;
                    totalDiv.classList.add('total-level-div');
                    totalDiv.id = "tm-total-level-div";

                    const totalIcon = document.createElement("img");
                    totalIcon.src = "images/icons/skills_large.png";
                    totalIcon.style.cssText = "width: 24px; height: 24px; margin-right: 10px;";

                    const totalTextSpan = document.createElement("span");
                    totalDiv.append(totalIcon, totalTextSpan);

                    this.skillUI.total.textSpan = totalTextSpan;

                    const totalTooltip = document.createElement("div");
                    let tooltipStyle = `position: fixed; padding: 6px 10px; background: #333; color: #fff; border-radius: 6px; font-size: 14px; box-shadow: 0 2px 6px rgba(0,0,0,0.4); pointer-events: none; z-index: 9999; white-space: nowrap; display: none;`;
                     if (this.getConfig('portraitMode')) {
                        const ratio = window.devicePixelRatio || 1;
                        const scale = 1 / ratio;
                        tooltipStyle += `transform: scale(${scale}); transform-origin: left top;`;
                    }
                    totalTooltip.style.cssText = tooltipStyle;
                    document.body.appendChild(totalTooltip);
                    this.skillUI.total.tooltip = totalTooltip;

                    totalDiv.addEventListener("mousemove", e => {
                        totalTooltip.style.left = `${e.pageX + 15}px`;
                        totalTooltip.style.top = `${e.pageY + 10}px`;
                    });
                    totalDiv.addEventListener("mouseenter", () => { totalTooltip.style.display = "block"; });
                    totalDiv.addEventListener("mouseleave", () => { totalTooltip.style.display = "none"; });

                    this.recalculateAndDisplayTotal();

                    skillContainer.style.display = "none";
                    skillPanel.append(grid, totalDiv);

                    const skillObserver = new MutationObserver(() => {
                        Object.keys(this.skillUI.elements).forEach(skillName => this.updateSkillCell(skillName));
                    });
                    skillObserver.observe(skillContainer, { childList: true, subtree: true, characterData: true });
                }
            }
        }

        destroySkillsGrid() {
            if (!this.isGridCreated) return;

            const skillPanel = document.querySelector("#ui-panel-skills");
            const skillContainer = skillPanel?.querySelector("center");
            const grid = document.getElementById('tm-skills-grid');
            const totalDiv = document.getElementById('tm-total-level-div');

            if (grid) grid.remove();
            if (totalDiv) totalDiv.remove();
            if (this.skillUI.total.tooltip) this.skillUI.total.tooltip.remove();
            if (skillContainer) skillContainer.style.display = "";

            this.isGridCreated = false;
        }
    }

    const plugin = new UITweaksPlugin();
    FlatMMOPlus.registerPlugin(plugin);

})();