IdlePixel Mobile UI

Restyles Idle Pixel into a mobile-first UI: bottom tab navigation, skill/more drawers, glanceable chat peek strip, compact headers. Auto-activates on touch devices.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

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

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Advertisement:

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

Advertisement:

// ==UserScript==
// @name         IdlePixel Mobile UI
// @namespace    com.eisa.idlepixel
// @version      0.8.4
// @description  Restyles Idle Pixel into a mobile-first UI: bottom tab navigation, skill/more drawers, glanceable chat peek strip, compact headers. Auto-activates on touch devices.
// @author       Eisa (StoneSinew)
// @license      MIT
// @match        *://idle-pixel.com/login/play*
// @grant        none
// @icon         https://cdn.idle-pixel.com/images/skills.png
// @require      https://greasyfork.org/scripts/441206-idlepixel/code/IdlePixel+.js?anticache=20220905
// ==/UserScript==
(function () {
    'use strict';

    const ACTIVE_CLASS = "mobile-ui";
    const NARROW_PX = 820;

    const COMBAT_STYLES = { "panel-melee": 1, "panel-archery": 1, "panel-magic": 1 };

    const SHEET_GROUPS = {
        skills: ["mining", "crafting", "gathering", "farming", "brewing", "woodcutting", "cooking", "fishing", "breeding", "invention", "melee", "archery", "magic"],
        shops: ["shop", "donor-shop", "criptoe-market"],
        other: ["teams", "keyitems", "quests", "achievements", "collection-log", "history", "friends", "database"]
    };

    const TAB_PANEL_MAP = { "panel-main": 0, "panel-combat": 2, "panel-combat-canvas": 2, "panel-player-market": 3 };

    const BREW_FAVS_KEY = "mob_brewing_favs";

    const MARKET_CATEGORIES = ["gems", "ores", "bars", "bones", "seeds", "logs", "raw_fish", "cooked_fish", "brewing", "weapons", "armour", "other_equipment", "breeding", "donor", "sigils"];
    const MARKET_CATEGORY_COLORS = {
        gems: "#b3ffff", ores: "#dddddd", bars: "#c2c2a3", bones: "#ffffff", seeds: "#ccffcc",
        logs: "#99ffcc", brewing: "#ffccff", weapons: "#ffcccc", armour: "#ffcccc", other_equipment: "#ffcccc",
        breeding: "#d8b38a", raw_fish: "#b3e6ff", cooked_fish: "#ffb366", donor: "#ccccff", sigils: "#f2f2f2"
    };

    const COMBAT_SPELLS = [
        { slug: "heal", label: "HEAL" },
        { slug: "fire", label: "FIRE" },
        { slug: "reflect", label: "REFLECT" },
        { slug: "invisibility", label: "INVIS" }
    ];

    const COMBAT_ACTION_AREAS = [
        "combat-presets-area",
        "combat-potions-area",
        "combat-cannon-area",
        "combat-faradox-crystals-area",
        "combat-faradox-crystals-area-2"
    ];

    const SHEET_MODAL_IDS = [
        "modal-market-configure-item-to-sell",
        "modal-market-select-item",
        "modal-market-purchase-item",
        "modal-closet",
        "modal-gatherer-menu",
        "modal-monster-lookup",
        "modal-loot"
    ];

    let viewportMeta = null;
    let colorSchemeMeta = null;
    function setMobileViewport(on) {
        const root = document.head || document.documentElement;
        if (on && !viewportMeta) {
            viewportMeta = document.createElement("meta");
            viewportMeta.name = "viewport";
            viewportMeta.content = "width=device-width, initial-scale=1, viewport-fit=cover";
            root.appendChild(viewportMeta);
            colorSchemeMeta = document.createElement("meta");
            colorSchemeMeta.name = "color-scheme";
            colorSchemeMeta.content = "light";
            root.appendChild(colorSchemeMeta);
        } else if (!on && viewportMeta) {
            viewportMeta.remove();
            viewportMeta = null;
            if (colorSchemeMeta) { colorSchemeMeta.remove(); colorSchemeMeta = null; }
        }
    }

    function looksMobile() {
        const coarse = window.matchMedia && window.matchMedia("(pointer: coarse)").matches;
        const layoutW = document.documentElement.clientWidth || window.innerWidth;
        return coarse || layoutW <= NARROW_PX;
    }

    const CSS = `

.mob-shell { display: none; }

html:has(body.${ACTIVE_CLASS}) {
    height: 100%;
    overflow: hidden;
}
body.${ACTIVE_CLASS} {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
}
body.${ACTIVE_CLASS} #not-credits,
body.${ACTIVE_CLASS} #content {
    display: block;
    height: 100%;
}

body.${ACTIVE_CLASS} .panels img {
    max-width: 100%;
    height: auto;
}
body.${ACTIVE_CLASS} .panel-logo-xp-area {
    max-width: 100%;
    box-sizing: border-box;
}
body.${ACTIVE_CLASS} .panels .progress-bar {
    max-width: 100%;
}

body.${ACTIVE_CLASS} #activity-log-area {
    margin: 0 !important;
    height: 64px !important;
    font-size: 11px;
    line-height: 1.35;
    padding: 5px 10px;
    overflow-y: auto;
    resize: none;
    background: rgba(0, 52, 45, 0.05);
    border-top: 1px solid #b9dcd6;
    border-bottom: 1px solid #b9dcd6;
    box-sizing: border-box;
}

body.${ACTIVE_CLASS} #menu-bar,
body.${ACTIVE_CLASS} .menu-bar { display: none !important; }

body.${ACTIVE_CLASS} .game-screen {
    display: flex !important;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}
body.${ACTIVE_CLASS} .game-top-bar {
    flex: 0 0 auto;
}

body.${ACTIVE_CLASS} .panels {
    flex: 1 1 auto;
    min-height: 0;
    width: 100% !important;
    overflow-y: auto;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: calc(122px + env(safe-area-inset-bottom));
    box-sizing: border-box;
}
body.${ACTIVE_CLASS} #top-menu-bar-labels {
    position: sticky;
    top: 0;
    z-index: 5;
}
body.${ACTIVE_CLASS}.mob-peek-off .panels {
    padding-bottom: calc(90px + env(safe-area-inset-bottom));
}

body.${ACTIVE_CLASS} .game-top-bar-upper {
    display: flex;
    align-items: center;
    gap: 8px;
    overflow-x: auto;
    white-space: nowrap;
    padding: 6px 10px;
    font-size: 12px;
    scrollbar-width: none;
}
body.${ACTIVE_CLASS} #top-menu-bar-labels {
    align-items: center;
    gap: 14px;
    overflow-x: auto;
    white-space: nowrap;
    padding: 5px 10px;
    background: #00342d;
    color: silver;
    border-bottom: 1px solid #00504d;
    font-size: 12px;
    scrollbar-width: none;
}
body.${ACTIVE_CLASS} #top-menu-bar-labels:not([style*="none"]) { display: flex; }
body.${ACTIVE_CLASS} #top-menu-bar-labels .top-bar-entry { margin: 0; padding: 0; flex: 0 0 auto; }
body.${ACTIVE_CLASS} #top-menu-bar-labels img { width: 16px; height: 16px; vertical-align: -3px; }

body.${ACTIVE_CLASS} .game-top-bar {
    position: relative;
    z-index: 6;
}
body.${ACTIVE_CLASS} .game-top-bar-upper:has(.dropdown-menu.show),
body.${ACTIVE_CLASS} .game-top-bar-upper:focus-within {
    overflow: visible;
}
body.${ACTIVE_CLASS} .game-top-bar .dropdown-menu {
    max-height: calc(100dvh - 110px);
    overflow-y: auto;
}

body.${ACTIVE_CLASS} .mob-tabbar {
    display: flex;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 1040;
    background: #00342d;
    border-top: 2px solid #0a6e5c;
    padding-bottom: env(safe-area-inset-bottom);
    box-shadow: 0 -2px 10px rgba(0,0,0,0.45);
}
body.${ACTIVE_CLASS} .mob-tab {
    flex: 1 1 0;
    min-height: 56px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    color: #b8d8d0;
    background: none;
    border: none;
    font-size: 10px;
    letter-spacing: 0.4px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
body.${ACTIVE_CLASS} .mob-tab img { width: 24px; height: 24px; image-rendering: pixelated; }
body.${ACTIVE_CLASS} .mob-tab .mob-glyph { font-size: 22px; line-height: 24px; }
body.${ACTIVE_CLASS} .mob-tab.active {
    color: #fff;
    background: #005247;
    box-shadow: inset 0 3px 0 #2bd9a9;
}

body.${ACTIVE_CLASS} .mob-backdrop {
    position: fixed; inset: 0;
    z-index: 1042;
    background: rgba(0,0,0,0.55);
    display: none;
}
body.${ACTIVE_CLASS} .mob-backdrop.open { display: block; }
body.${ACTIVE_CLASS} .mob-sheet {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 1043;
    background: #00342d;
    color: #e8f4f0;
    border-top: 2px solid #0a6e5c;
    border-radius: 14px 14px 0 0;
    max-height: 72vh;
    max-height: 72dvh;
    display: none;
    flex-direction: column;
    box-shadow: 0 -4px 24px rgba(0,0,0,0.6);
}
body.${ACTIVE_CLASS} .mob-sheet.open { display: flex; }
body.${ACTIVE_CLASS} .mob-sheet-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px 8px;
    font-size: 14px;
    letter-spacing: 1px;
}
body.${ACTIVE_CLASS} .mob-sheet-close {
    background: none;
    border: 1px solid #0a6e5c;
    border-radius: 8px;
    color: #b8d8d0;
    font-size: 14px;
    padding: 4px 12px;
    cursor: pointer;
}
body.${ACTIVE_CLASS} .mob-sheet-body {
    overflow-y: auto;
    padding: 4px 12px calc(16px + env(safe-area-inset-bottom));
}
body.${ACTIVE_CLASS} .mob-section-title {
    font-size: 11px;
    letter-spacing: 1.5px;
    color: #6fbfae;
    margin: 14px 4px 8px;
}
body.${ACTIVE_CLASS} .mob-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 8px;
}
body.${ACTIVE_CLASS} .mob-item {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    min-height: 72px;
    background: #005247;
    border: 1px solid #0a6e5c;
    border-radius: 10px;
    color: #e8f4f0;
    font-size: 9.5px;
    letter-spacing: 0.3px;
    text-align: center;
    cursor: pointer;
    padding: 8px 2px;
    -webkit-tap-highlight-color: transparent;
}
body.${ACTIVE_CLASS} .mob-item img { width: 26px; height: 26px; image-rendering: pixelated; }
body.${ACTIVE_CLASS} .mob-item .mob-glyph { font-size: 22px; line-height: 26px; }
body.${ACTIVE_CLASS} .mob-item .mob-level {
    position: absolute;
    top: 4px; right: 5px;
    background: #022b25;
    border: 1px solid #2bd9a9;
    color: #2bd9a9;
    border-radius: 8px;
    font-size: 9px;
    padding: 0 5px;
    line-height: 13px;
}

body.${ACTIVE_CLASS} .mob-chatpeek {
    position: fixed;
    left: 0; right: 0;
    bottom: calc(58px + env(safe-area-inset-bottom));
    z-index: 1040;
    display: flex;
    align-items: center;
    gap: 8px;
    height: 28px;
    padding: 0 10px;
    background: #022b25;
    border-top: 1px solid #0a6e5c;
    color: #cfe9e2;
    font-size: 11px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
body.${ACTIVE_CLASS}.mob-peek-off .mob-chatpeek { display: none; }
body.${ACTIVE_CLASS} .mob-chatpeek .mob-peek-msg {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: #9fd2c6;
}
body.${ACTIVE_CLASS} .mob-chatpeek .mob-peek-chevron { flex: 0 0 auto; color: #6fbfae; font-size: 12px; }

body.${ACTIVE_CLASS}:not(.mob-chat-open) #game-chat {
    position: absolute;
    width: 100%;
    height: 0 !important;
    min-height: 0 !important;
    max-height: 0 !important;
    overflow: hidden;
    margin: 0 !important;
    padding: 0 !important;
    border: 0;
}
body.${ACTIVE_CLASS}.mob-chat-open #game-chat {
    display: block !important;
    position: fixed;
    left: 0; right: 0;
    bottom: calc(86px + env(safe-area-inset-bottom));
    height: 52vh;
    height: 52dvh;
    z-index: 1039;
    margin: 0 !important;
    background: #022b25;
    border-top: 2px solid #0a6e5c;
    box-shadow: 0 -4px 24px rgba(0,0,0,0.5);
    overflow-y: auto;
    padding: 10px;
    box-sizing: border-box;
}

body.${ACTIVE_CLASS} .modal-dialog {
    max-width: calc(100vw - 20px);
    margin: 12px auto;
    display: flex;
    align-items: center;
    min-height: calc(100% - 24px);
}
body.${ACTIVE_CLASS} .modal-dialog .modal-content {
    width: 100%;
}
body.${ACTIVE_CLASS} .modal-body {
    overflow-x: auto;
    max-height: calc(100dvh - 210px);
}
body.${ACTIVE_CLASS} .modal-body img {
    max-width: 100%;
    height: auto;
}
body.${ACTIVE_CLASS} .modal-content .btn {
    min-height: 44px;
}
body.${ACTIVE_CLASS} .modal-content .btn-close {
    padding: 14px;
}
body.${ACTIVE_CLASS} .modal-content input,
body.${ACTIVE_CLASS} .modal-content select,
body.${ACTIVE_CLASS} .modal-content textarea {
    font-size: 16px;
    min-height: 40px;
}
body.${ACTIVE_CLASS} .modal-dialog.modal-xl,
body.${ACTIVE_CLASS} .modal-dialog.modal-lg,
body.${ACTIVE_CLASS} .modal-xxl,
body.${ACTIVE_CLASS} .modal-xxxl {
    min-width: 0 !important;
    max-width: calc(100vw - 20px) !important;
}

body.${ACTIVE_CLASS} .modal.mob-sheet-modal .modal-dialog {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    margin: 0;
    width: 100vw;
    max-width: 100vw !important;
    min-height: 0;
    display: block;
    transform: none !important;
}
body.${ACTIVE_CLASS} .modal.mob-sheet-modal .modal-content {
    border-radius: 14px 14px 0 0;
    border: 0;
    border-top: 2px solid #0a6e5c;
    max-height: 88dvh;
    display: flex;
    flex-direction: column;
    padding-bottom: env(safe-area-inset-bottom);
}
body.${ACTIVE_CLASS} .modal.mob-sheet-modal .modal-body {
    flex: 1 1 auto;
    max-height: none;
    overflow-y: auto;
}

body.${ACTIVE_CLASS} #crafting-table,
body.${ACTIVE_CLASS} #brewing-table,
body.${ACTIVE_CLASS} #invention-table {
    display: block;
    width: 100%;
    border: 0 !important;
    background: none !important;
    box-shadow: none;
}
body.${ACTIVE_CLASS} #crafting-table tbody,
body.${ACTIVE_CLASS} #brewing-table tbody,
body.${ACTIVE_CLASS} #invention-table tbody {
    display: block;
}
body.${ACTIVE_CLASS} #crafting-table tr:has(th),
body.${ACTIVE_CLASS} #brewing-table tr:has(th),
body.${ACTIVE_CLASS} #invention-table tr:has(th) {
    display: none;
}
body.${ACTIVE_CLASS} #crafting-table tr,
body.${ACTIVE_CLASS} #brewing-table tr,
body.${ACTIVE_CLASS} #invention-table tr {
    display: block;
    position: relative;
    margin: 6px 0;
    border: 1px solid #9ccac2 !important;
    border-radius: 10px;
    background-color: #eafdfb;
    padding: 6px 10px;
    text-align: left !important;
}
body.${ACTIVE_CLASS} #crafting-table td,
body.${ACTIVE_CLASS} #brewing-table td,
body.${ACTIVE_CLASS} #invention-table td {
    display: block;

    width: auto !important;
    min-width: 0 !important;
    max-width: none !important;
    border: 0 !important;
    padding: 0;
    font-size: 13px;
    line-height: 1.5;
    text-align: left;
}

body.${ACTIVE_CLASS} #crafting-table td br,
body.${ACTIVE_CLASS} #brewing-table td br,
body.${ACTIVE_CLASS} #invention-table td br {
    display: none;
}
body.${ACTIVE_CLASS} #crafting-table td img,
body.${ACTIVE_CLASS} #brewing-table td img,
body.${ACTIVE_CLASS} #invention-table td img {
    max-height: 20px;
    width: auto;
    vertical-align: middle;
    image-rendering: pixelated;
    margin-left: 10px;
    margin-right: 3px;
}
body.${ACTIVE_CLASS} #crafting-table td:first-child,
body.${ACTIVE_CLASS} #brewing-table td:first-child,
body.${ACTIVE_CLASS} #invention-table td:first-child {
    font-size: 15px;
    font-weight: 600;
    padding-bottom: 4px;
}
body.${ACTIVE_CLASS} #crafting-table td:first-child,
body.${ACTIVE_CLASS} #brewing-table td:first-child,
body.${ACTIVE_CLASS} #invention-table td:first-child {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
body.${ACTIVE_CLASS} #crafting-table td:first-child img,
body.${ACTIVE_CLASS} #brewing-table td:first-child img,
body.${ACTIVE_CLASS} #invention-table td:first-child img {
    max-height: 26px;
    margin-left: 0;
    margin-right: 6px;
}

body.${ACTIVE_CLASS} #crafting-table td:nth-child(4),
body.${ACTIVE_CLASS} #brewing-table td:nth-child(4),
body.${ACTIVE_CLASS} #invention-table td:nth-child(5) {
    color: #5a7d78;
    font-size: 12px;
    line-height: 1.35;
    margin: 2px 0;
}

body.${ACTIVE_CLASS} #crafting-table td::before,
body.${ACTIVE_CLASS} #brewing-table td::before,
body.${ACTIVE_CLASS} #invention-table td::before {
    color: #2e6e63;
    font-size: 10.5px;
    letter-spacing: 0.6px;
    margin-right: 5px;
}
body.${ACTIVE_CLASS} #crafting-table td:nth-child(2)::before { content: "LEVEL"; }
body.${ACTIVE_CLASS} #crafting-table td:nth-child(3)::before { content: "MATERIALS"; }
body.${ACTIVE_CLASS} #crafting-table td:nth-child(6)::before { content: "USED WITH"; }
body.${ACTIVE_CLASS} #brewing-table td:nth-child(2)::before { content: "LEVEL"; }
body.${ACTIVE_CLASS} #brewing-table td:nth-child(3)::before { content: "MATERIALS"; }
body.${ACTIVE_CLASS} #brewing-table td:nth-child(5)::before { content: "DURATION"; }
body.${ACTIVE_CLASS} #brewing-table td:nth-child(7)::before { content: "BREWED"; }
body.${ACTIVE_CLASS} #brewing-table td:nth-child(8)::before { content: "USED WITH"; }
body.${ACTIVE_CLASS} #invention-table td:nth-child(2)::before { content: "LEVEL"; }
body.${ACTIVE_CLASS} #invention-table td:nth-child(3)::before { content: "TABLETTE"; }
body.${ACTIVE_CLASS} #invention-table td:nth-child(4)::before { content: "COMPONENTS"; }

body.${ACTIVE_CLASS} .gathering-box {
    width: auto !important;
    max-width: 100%;
    box-sizing: border-box;
    margin: 8px 4px;
}

body.${ACTIVE_CLASS} .panels [class*="game-shop-table-entry"] {
    width: auto !important;
    min-width: 0 !important;
    max-width: 100% !important;
    box-sizing: border-box;
}
body.${ACTIVE_CLASS} .panels [class*="game-shop-table-entry"] table {
    width: 100%;
    max-width: 100%;
}

body.${ACTIVE_CLASS} .panels table {
    max-width: 100%;
}

body.${ACTIVE_CLASS} .panel-logo-xp-area {
    display: block;
    padding: 8px 12px !important;
    margin-bottom: 6px;
    border-radius: 8px;
}
body.${ACTIVE_CLASS} .panel-logo-xp-area br { display: none; }

body.${ACTIVE_CLASS} .panel-logo-xp-area > img,
body.${ACTIVE_CLASS} .panel-logo-xp-area > a img {
    max-height: 40px;
    width: auto;
    display: block;
    margin: 0 0 6px;
    image-rendering: pixelated;
}
body.${ACTIVE_CLASS} .panel-logo-xp-area > div { margin-left: 0 !important; }
body.${ACTIVE_CLASS} .panel-logo-xp-area .font-large { font-size: 15px !important; }
body.${ACTIVE_CLASS} .panel-logo-xp-area > div > a { font-size: 12px; }
body.${ACTIVE_CLASS} .panel-logo-xp-area .progress-bar {
    display: block;
    height: 8px !important;
    border-radius: 4px;
    overflow: hidden;
    margin: 4px 0 2px;
    box-shadow: none !important;
}
body.${ACTIVE_CLASS} .panel-logo-xp-area .progress-bar-inner {
    display: block;
    height: 100% !important;
}
body.${ACTIVE_CLASS} .panel-logo-xp-area .font-small { font-size: 11px; }
body.${ACTIVE_CLASS} .panel-logo-xp-area .warning-message { display: block; }

body.${ACTIVE_CLASS} #panel-gathering .panel-logo-xp-area {
    display: flex !important;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 8px;
    padding: 7px 10px !important;
}
body.${ACTIVE_CLASS} #panel-gathering .panel-logo-xp-area > img,
body.${ACTIVE_CLASS} #panel-gathering .panel-logo-xp-area > a img {
    max-height: 16px;
    margin: 0;
}
body.${ACTIVE_CLASS} #panel-gathering .panel-logo-xp-area > img,
body.${ACTIVE_CLASS} #panel-gathering .panel-logo-xp-area > a {
    flex: 0 0 auto;
    order: 0;
}
body.${ACTIVE_CLASS} #panel-gathering .panel-logo-xp-area > div { display: contents; }
body.${ACTIVE_CLASS} #panel-gathering .panel-logo-xp-area .font-large {
    font-size: 13px !important;
    order: 1;
    margin-left: auto;
    white-space: nowrap;
}
body.${ACTIVE_CLASS} #panel-gathering .panel-logo-xp-area > div > a {
    order: 2;
    flex: 0 0 auto;
    font-size: 11px;
    white-space: nowrap;
}
body.${ACTIVE_CLASS} #panel-gathering .panel-logo-xp-area .progress-bar {
    order: 3;
    flex: 1 1 100%;
    height: 6px !important;
    margin: 5px 0 1px;
}
body.${ACTIVE_CLASS} #panel-gathering .panel-logo-xp-area .font-small {
    order: 4;
    flex: 1 1 100%;
    font-size: 10px;
    text-align: right;
    line-height: 1.2;
}
body.${ACTIVE_CLASS} #panel-gathering .panel-logo-xp-area .warning-message {
    order: 5;
    flex: 1 1 100%;
}

body.${ACTIVE_CLASS}:not(.mob-on-home) #notifications-area { display: none !important; }

body.${ACTIVE_CLASS}:not(.mob-on-home) #activity-log-area { display: none !important; }

body.${ACTIVE_CLASS}:not(.mob-on-home) #top-menu-bar-optional-labels { display: none !important; }
body.${ACTIVE_CLASS}.mob-on-home #top-menu-bar-optional-labels {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 14px;
    padding: 8px 10px;
    background: #00342d;
    color: silver;
    border-bottom: 1px solid #00504d;
    font-size: 12px;
}
body.${ACTIVE_CLASS}.mob-on-home #top-menu-bar-optional-labels .top-bar-entry {
    margin: 0;
    padding: 0;
    flex: 0 0 auto;
}
body.${ACTIVE_CLASS}.mob-on-home #top-menu-bar-optional-labels img {
    max-height: 16px;
    width: auto;
    vertical-align: -3px;
}
body.${ACTIVE_CLASS} #notifications-area {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 8px 2px;
}
body.${ACTIVE_CLASS} #notifications-area > * {
    border-radius: 10px;
    padding: 8px 10px;
    font-size: 13px;
    text-align: left;
    min-height: 40px;
}
body.${ACTIVE_CLASS} #notifications-area img {
    max-height: 22px;
    width: auto;
    vertical-align: middle;
    image-rendering: pixelated;
}
body.${ACTIVE_CLASS} .mob-tab { position: relative; }
body.${ACTIVE_CLASS} .mob-tab-badge {
    display: none;
    position: absolute;
    top: 5px;
    right: 16%;
    min-width: 16px;
    height: 16px;
    border-radius: 8px;
    background: #f0b00a;
    color: #022b25;
    font-size: 10px;
    line-height: 16px;
    padding: 0 4px;
    text-align: center;
}
body.${ACTIVE_CLASS} .mob-tab-badge.on { display: block; }

body.${ACTIVE_CLASS} #panel-gathering > br { display: none; }

body.${ACTIVE_CLASS} #panel-gathering .itembox-div.box-shortcut-potion { display: none !important; }

body.${ACTIVE_CLASS} #mob-gather-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 2px 0 8px;
}
body.${ACTIVE_CLASS} #mob-gather-chips itembox:not([style*="display: none"]):not([style*="display:none"]) {
    display: flex !important;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    width: 52px !important;
    height: 52px !important;
    min-width: 0 !important;
    min-height: 0 !important;
    margin: 0 !important;
    padding: 4px !important;
    border-radius: 10px;
    box-sizing: border-box;
    overflow: hidden;
    font-size: 10px;
}
body.${ACTIVE_CLASS} #mob-gather-chips itembox div {
    margin: 0 !important;
    line-height: 1.1;
}
body.${ACTIVE_CLASS} #mob-gather-chips itembox img {
    max-width: 26px;
    max-height: 26px;
    image-rendering: pixelated;
}

body.${ACTIVE_CLASS} #mob-gather-minis {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    margin: 0 0 8px;
}
body.${ACTIVE_CLASS} #mob-gather-minis .gathering-box {
    margin: 0 !important;
    width: auto !important;
}
body.${ACTIVE_CLASS} #mob-gather-minis .gathering-box.mob-gather-active {
    grid-column: 1 / -1;
    order: -1;
    height: auto !important;
    min-height: 0 !important;
}
body.${ACTIVE_CLASS} #mob-gather-minis .gathering-box.mob-gather-mini {
    padding: 9px 6px !important;
    height: auto !important;
    min-height: 0 !important;
    background-image: none !important;
}
body.${ACTIVE_CLASS} #mob-gather-minis .gathering-box.mob-gather-mini h2 {
    font-size: 13px;
    margin: 0;
}
body.${ACTIVE_CLASS} #mob-gather-minis .gathering-box.mob-gather-mini > :not(h2) {
    display: none;
}

body.${ACTIVE_CLASS} #mob-gather-loot {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
    margin: 4px 0 8px;
}
body.${ACTIVE_CLASS} #mob-gather-loot itembox:not([style*="display: none"]):not([style*="display:none"]) {
    display: flex !important;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    width: auto !important;
    height: auto !important;
    min-height: 64px;
    margin: 0 !important;
    padding: 6px 4px !important;
    border-radius: 10px;
    box-sizing: border-box;
    font-size: 11px;
}
body.${ACTIVE_CLASS} #mob-gather-loot itembox div { margin: 0 !important; }
body.${ACTIVE_CLASS} #mob-gather-loot itembox img {
    max-width: 30px;
    max-height: 30px;
    image-rendering: pixelated;
}

body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active {
    height: auto !important;
    min-height: 0 !important;
    padding: 10px !important;
}
body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active h2 {
    font-size: 18px;
    margin: 0 0 6px;
}
body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active img {
    display: block;
    margin: 0 auto;
    max-height: 140px;
    width: auto;
}
body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active br,
body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active hr,
body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active .font-tiny,
body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active .gathering-items-list,
body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active span.color-silver,
body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active center,
body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active .progress-bar,
body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active span:has([id*="-x-img"]),
body.${ACTIVE_CLASS} #panel-gathering .gathering-box.mob-gather-active [id*="-x-img"] {
    display: none !important;
}

body.${ACTIVE_CLASS} #panel-player-market > :not(#mob-market) { display: none !important; }

body.${ACTIVE_CLASS}.mob-mkt-loading #modal-market-select-item,
body.${ACTIVE_CLASS}.mob-mkt-loading .modal-backdrop { display: none !important; }
body.${ACTIVE_CLASS} #mob-market { display: block; }
body.${ACTIVE_CLASS} #mob-market-tabs {
    display: flex;
    gap: 6px;
    margin: 2px 0 10px;
}
body.${ACTIVE_CLASS} .mob-mkt-tab {
    flex: 1 1 0;
    min-height: 40px;
    background: #eafdfb;
    border: 1px solid #9ccac2;
    border-radius: 10px;
    color: #17564c;
    font-size: 12px;
    letter-spacing: 0.5px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
body.${ACTIVE_CLASS} .mob-mkt-tab.active {
    background: #00584a;
    border-color: #00584a;
    color: #fff;
}
body.${ACTIVE_CLASS} .mob-mkt-search {
    width: 100%;
    box-sizing: border-box;
    height: 40px;
    border: 1px solid #9ccac2;
    border-radius: 10px;
    padding: 0 12px;
    font-size: 15px;
    margin-bottom: 10px;
    background: #fff url('https://cdn.idle-pixel.com/images/search.png') no-repeat 10px center;
    background-size: 0;
}
body.${ACTIVE_CLASS} .mob-mkt-cats {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 8px;
}
body.${ACTIVE_CLASS} .mob-mkt-cat {
    min-height: 72px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    border: 1px solid rgba(0,0,0,0.15);
    border-radius: 12px;
    color: #1b1b1b;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.3px;
    text-align: center;
    padding: 6px 4px;
    cursor: pointer;
    text-transform: capitalize;
    -webkit-tap-highlight-color: transparent;
}
body.${ACTIVE_CLASS} .mob-mkt-cat small { font-weight: 400; opacity: 0.7; font-size: 9.5px; }
body.${ACTIVE_CLASS} .mob-mkt-crumb {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    font-size: 13px;
    color: #17564c;
}
body.${ACTIVE_CLASS} .mob-mkt-back {
    flex: 0 0 auto;
    min-width: 40px;
    min-height: 34px;
    border: 1px solid #9ccac2;
    border-radius: 9px;
    background: #eafdfb;
    color: #17564c;
    font-size: 16px;
    cursor: pointer;
}
body.${ACTIVE_CLASS} .mob-mkt-crumb-title { font-weight: 600; text-transform: capitalize; }
body.${ACTIVE_CLASS} .mob-mkt-allbtn {
    width: 100%;
    min-height: 40px;
    margin-bottom: 8px;
    background: #005247;
    border: 0;
    border-radius: 10px;
    color: #fff;
    font-size: 12px;
    letter-spacing: 0.4px;
    cursor: pointer;
}
body.${ACTIVE_CLASS} .mob-mkt-row {
    display: flex;
    align-items: center;
    gap: 10px;
    background: #fff;
    border: 1px solid #cfe6e1;
    border-radius: 10px;
    padding: 8px 10px;
    margin-bottom: 6px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
body.${ACTIVE_CLASS} .mob-mkt-row img.mob-mkt-icon {
    width: 34px;
    height: 34px;
    flex: 0 0 auto;
    image-rendering: pixelated;
    object-fit: contain;
}
body.${ACTIVE_CLASS} .mob-mkt-row .mob-mkt-main { flex: 1 1 auto; min-width: 0; }
body.${ACTIVE_CLASS} .mob-mkt-row .mob-mkt-name {
    font-size: 14px;
    color: #1b1b1b;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-transform: capitalize;
}
body.${ACTIVE_CLASS} .mob-mkt-row .mob-mkt-sub { font-size: 11px; color: #6a8781; margin-top: 1px; }
body.${ACTIVE_CLASS} .mob-mkt-row .mob-mkt-price {
    flex: 0 0 auto;
    text-align: right;
    font-size: 13px;
    color: #17564c;
    font-weight: 600;
    white-space: nowrap;
}
body.${ACTIVE_CLASS} .mob-mkt-row .mob-mkt-price small { display: block; font-weight: 400; font-size: 9.5px; color: #6a8781; }
body.${ACTIVE_CLASS} .mob-mkt-row.mob-mkt-cheapest { border-color: #2bd9a9; box-shadow: 0 0 0 1px #2bd9a9 inset; }
body.${ACTIVE_CLASS} .mob-mkt-row.mob-mkt-yours { background: #fffbe6; border-color: #e6d27a; }
body.${ACTIVE_CLASS} .mob-mkt-empty { text-align: center; color: #6a8781; font-size: 13px; padding: 24px 10px; }
body.${ACTIVE_CLASS} .mob-mkt-chev { flex: 0 0 auto; color: #9ccac2; font-size: 16px; }
body.${ACTIVE_CLASS} .mob-mkt-trend {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin: 2px 0 10px;
    font-size: 11px;
    color: #2e6e63;
    text-decoration: none;
}

body.${ACTIVE_CLASS} #modal-market-select-item-section > .select-item-tradables-catagory:first-child {
    display: none !important;
}
body.${ACTIVE_CLASS} .select-item-tradables-catagory {
    display: block !important;
    width: 100% !important;
    box-sizing: border-box;
    margin: 0 0 12px !important;
    padding: 0 !important;
    background: none !important;
    box-shadow: none !important;
    text-transform: capitalize;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.4px;
    color: #17564c;
    text-align: left;
}
body.${ACTIVE_CLASS} .select-item-tradables-catagory hr {
    margin: 4px 0 8px;
    border: 0;
    border-top: 1px solid #cfe6e1;
}
body.${ACTIVE_CLASS} .market-tradable-item {
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    width: 48px !important;
    height: 48px !important;
    margin: 3px !important;
    padding: 0 !important;
    border-radius: 10px;
    border: 1px solid rgba(0, 0, 0, 0.12);
    box-shadow: none !important;
    vertical-align: middle;
}
body.${ACTIVE_CLASS} .market-tradable-item img {
    width: 32px !important;
    height: 32px !important;
    image-rendering: pixelated;
}

body.${ACTIVE_CLASS} #mob-market-sell {
    display: grid;
    grid-template-columns: 1fr;
    gap: 8px;
}
body.${ACTIVE_CLASS} #mob-market-sell .player-market-slot-base:not([style*="display: none"]):not([style*="display:none"]) {
    display: block !important;
}
body.${ACTIVE_CLASS} #mob-market-sell .player-market-slot-base {
    width: auto !important;
    min-width: 0 !important;
    max-width: none !important;
    height: auto !important;
    min-height: 0 !important;
    margin: 0 !important;
    box-sizing: border-box;
    background: #fff !important;
    border: 1px solid #cfe6e1 !important;
    border-radius: 12px;
    padding: 12px !important;
    text-align: center;
}
body.${ACTIVE_CLASS} #mob-market-sell .player-market-slot-base br { display: none; }
body.${ACTIVE_CLASS} #mob-market-sell .player-market-slot-base hr { margin: 6px 0; opacity: 0.3; }
body.${ACTIVE_CLASS} #mob-market-sell [id^="player-market-slot-empty"] {
    border-style: dashed !important;
    padding: 16px 12px !important;
}
body.${ACTIVE_CLASS} #mob-market-sell [id^="player-market-slot-empty"] button {
    width: 100%;
    min-height: 46px;
    margin: 0;
    background: #005247;
    color: #fff;
    border: 0;
    border-radius: 10px;
    font-size: 14px;
    letter-spacing: 0.4px;
}
body.${ACTIVE_CLASS} #mob-market-sell .player-market-slot-base h2 { font-size: 15px; margin: 0 0 6px; }
body.${ACTIVE_CLASS} #mob-market-sell .player-market-slot-base img { image-rendering: pixelated; max-height: 42px; width: auto; }
body.${ACTIVE_CLASS} #mob-market-sell [id^="player-market-slot-occupied"] { text-align: left; font-size: 13px; }
body.${ACTIVE_CLASS} #mob-market-sell [id^="player-market-slot-occupied"] h2 { text-align: center; }
body.${ACTIVE_CLASS} #mob-market-sell [id^="player-market-slot-occupied"] img { vertical-align: middle; }
body.${ACTIVE_CLASS} #mob-market-sell [id^="player-market-slot-occupied"] button {
    min-height: 40px;
    margin: 8px 4px 0;
    padding: 0 14px;
    border-radius: 9px;
}

body.${ACTIVE_CLASS} .mob-fav-star {
    display: block;
    position: absolute;
    top: 2px;
    right: 4px;
    width: 36px;
    height: 36px;
    line-height: 36px;
    padding: 0;
    text-align: center;
    font-size: 21px;
    color: #8fb8b0;
    background: none;
    border: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    z-index: 2;
}
body.${ACTIVE_CLASS} .mob-fav-star.faved {
    color: #f0b00a;
}
body.${ACTIVE_CLASS} .mob-brew-favs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    margin: 8px 0;
}
body.${ACTIVE_CLASS} .mob-brew-favs-title {
    grid-column: 1 / -1;
    font-size: 11px;
    letter-spacing: 1.5px;
    color: #2e6e63;
    margin: 2px 2px 0;
}
body.${ACTIVE_CLASS} .mob-fav-card {
    display: flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    background: #eafdfb;
    border: 1px solid #9ccac2;
    border-radius: 10px;
    padding: 4px 8px;
    font-size: 12px;
    color: inherit;
    text-align: left;
    cursor: pointer;
    overflow: hidden;
    -webkit-tap-highlight-color: transparent;
}
body.${ACTIVE_CLASS} .mob-fav-card img {
    width: 22px;
    height: 22px;
    image-rendering: pixelated;
    flex: 0 0 auto;
}
body.${ACTIVE_CLASS} .mob-fav-card span {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

body.${ACTIVE_CLASS}.mob-combat .mob-tab { display: none; }
body.${ACTIVE_CLASS}.mob-combat .mob-chatpeek { display: none !important; }
body.${ACTIVE_CLASS} .mob-combat-bar { display: none; }
body.${ACTIVE_CLASS}.mob-combat .mob-combat-bar {
    display: flex;
    flex: 1 1 auto;
    align-items: stretch;
    gap: 5px;
    padding: 5px 6px;
}
body.${ACTIVE_CLASS} .mob-combat-back {
    flex: 0 0 50px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #005247;
    border: 1px solid #0a6e5c;
    border-radius: 10px;
    color: #e8f4f0;
    font-size: 22px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
body.${ACTIVE_CLASS} .mob-spell-btn {
    position: relative;
    flex: 1 1 0;
    min-height: 58px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    background: #0b2d54;
    border: 1px solid #2b6cb0;
    border-radius: 10px;
    color: #dbeafe;
    font-size: 9px;
    letter-spacing: 0.4px;
    cursor: pointer;
    overflow: hidden;
    -webkit-tap-highlight-color: transparent;
}
body.${ACTIVE_CLASS} .mob-spell-btn img {
    width: 26px;
    height: 26px;
    image-rendering: pixelated;
}
body.${ACTIVE_CLASS} .mob-spell-btn.mob-cooling {
    filter: grayscale(0.8) brightness(0.75);
}
body.${ACTIVE_CLASS} .mob-spell-btn .mob-spell-cd {
    display: none;
    position: absolute;
    inset: 0;
    align-items: center;
    justify-content: center;
    background: rgba(2, 15, 33, 0.55);
    color: #fff;
    font-size: 19px;
    font-weight: 600;
}
body.${ACTIVE_CLASS} .mob-spell-btn.mob-cooling .mob-spell-cd { display: flex; }
body.${ACTIVE_CLASS} .mob-spell-btn.mob-unavailable { display: none; }
body.${ACTIVE_CLASS} .mob-spell-btn.mob-nomana {
    border-color: #b91c1c;
    filter: saturate(0.6) brightness(0.8);
}
body.${ACTIVE_CLASS} .mob-spell-btn .mob-spell-note {
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    bottom: 2px;
    color: #fca5a5;
    font-size: 8px;
    text-align: center;
}
body.${ACTIVE_CLASS} .mob-spell-btn.mob-nomana .mob-spell-note { display: block; }

body.${ACTIVE_CLASS}.mob-combat [id^="fighting-spell-heal"],
body.${ACTIVE_CLASS}.mob-combat [id^="fighting-spell-fire"],
body.${ACTIVE_CLASS}.mob-combat [id^="fighting-spell-reflect"],
body.${ACTIVE_CLASS}.mob-combat [id^="fighting-spell-invisibility"] {
    display: none !important;
}

body.${ACTIVE_CLASS} #combat-canvas-hero {
    width: calc((100vw - 8px) * 0.375) !important;
    height: auto !important;
    margin: 0 !important;
}
body.${ACTIVE_CLASS} #combat-canvas-monster {
    width: calc((100vw - 8px) * 0.625) !important;
    height: auto !important;
    margin: 0 !important;
}
body.${ACTIVE_CLASS} #panel-combat-canvas table { max-width: 100%; border-spacing: 0; }
body.${ACTIVE_CLASS} #panel-combat-canvas td {
    padding: 0 !important;
    border: none !important;
}
body.${ACTIVE_CLASS} #panel-combat-canvas > button { display: none; }
body.${ACTIVE_CLASS} #panel-combat-canvas { position: relative; }

body.${ACTIVE_CLASS}.mob-combat .panels,
body.${ACTIVE_CLASS}.mob-combat .panels .panel-content {
    padding-left: 0 !important;
    padding-right: 0 !important;
}
body.${ACTIVE_CLASS} #panel-combat-canvas center { margin: 0; }

body.${ACTIVE_CLASS} #mob-combat-hud-left,
body.${ACTIVE_CLASS} #mob-combat-hud-right {
    position: absolute;
    top: 4px;
    width: 46%;
    z-index: 5;
    color: #fff;
    text-shadow: 0 1px 3px #000, 0 0 2px #000;
}
body.${ACTIVE_CLASS} #mob-combat-hud-left { left: 6px; text-align: left; }
body.${ACTIVE_CLASS} #mob-combat-hud-right { right: 6px; text-align: right; }
body.${ACTIVE_CLASS} #mob-combat-hud-left .fighting-hero-stats-area,
body.${ACTIVE_CLASS} #mob-combat-hud-right .fighting-monster-stats-area {
    background: none !important;
    border: none !important;
    box-shadow: none !important;
    padding: 0 !important;
    margin: 0 0 2px !important;
    display: block;
    font-size: 13px;
    font-weight: 600;
}
body.${ACTIVE_CLASS} #mob-combat-hud-left .hp-progress-bar,
body.${ACTIVE_CLASS} #mob-combat-hud-left .mana-progress-bar,
body.${ACTIVE_CLASS} #mob-combat-hud-right .hp-progress-bar {
    display: block;
    width: 100% !important;
    min-width: 0 !important;
    max-width: none !important;
    height: 7px !important;
    border-radius: 4px;
    overflow: hidden;
    margin: 2px 0 0;
    box-shadow: none !important;
}
body.${ACTIVE_CLASS} #mob-combat-hud-left .hp-progress-bar-inner,
body.${ACTIVE_CLASS} #mob-combat-hud-left .mana-progress-bar-inner,
body.${ACTIVE_CLASS} #mob-combat-hud-right .hp-progress-bar-inner {
    display: block;
    height: 100% !important;
}
body.${ACTIVE_CLASS} #mob-combat-hud-left .progress-bar-label,
body.${ACTIVE_CLASS} #mob-combat-hud-right .progress-bar-label {
    width: auto !important;
    min-width: 0 !important;
    font-size: 10px;
    line-height: 1.3;
    padding: 0;
    margin: 0 0 2px;
    background: none !important;
}
body.${ACTIVE_CLASS} #mob-combat-hud-left .td-combat-bottom-panel,
body.${ACTIVE_CLASS} #mob-combat-hud-right .td-combat-bottom-panel {
    background: none !important;
    border: none !important;
    box-shadow: none !important;
    padding: 0 !important;
    margin: 3px 0 0 !important;
    min-width: 0 !important;
    display: block;
}
body.${ACTIVE_CLASS} #mob-combat-hud-left .td-combat-stat-entry,
body.${ACTIVE_CLASS} #mob-combat-hud-right .td-combat-stat-entry {
    display: flex;
    align-items: center;
    gap: 3px;
    padding: 0;
    font-size: 10px;
    line-height: 1.45;
}
body.${ACTIVE_CLASS} #mob-combat-hud-right .td-combat-stat-entry { justify-content: flex-end; }
body.${ACTIVE_CLASS} #mob-combat-hud-left br,
body.${ACTIVE_CLASS} #mob-combat-hud-right br { display: none; }

body.${ACTIVE_CLASS} #mob-combat-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 8px 6px;
    align-items: flex-start;
}
body.${ACTIVE_CLASS} #mob-combat-actions .combat-presets-area {
    background: rgba(2, 43, 37, 0.9) !important;
    border: 1px solid #0a6e5c !important;
    box-shadow: none !important;
    border-radius: 10px;
    padding: 5px 8px !important;
    margin: 0 !important;
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 10px;
    min-width: 0;
    width: auto !important;
}
body.${ACTIVE_CLASS} #mob-combat-actions .combat-presets-area br { display: none; }
body.${ACTIVE_CLASS} #mob-combat-actions .combat-presets-area u {
    font-size: 9px;
    letter-spacing: 0.5px;
    text-decoration: none;
    color: #6fbfae !important;
}
body.${ACTIVE_CLASS} #mob-combat-actions .combat-presets-combat-icon {
    width: 34px !important;
    height: 34px !important;
    border-radius: 8px;
}

body.${ACTIVE_CLASS} #mob-toasts {
    display: flex;
    flex-direction: column;
    gap: 6px;
    position: fixed;
    left: 10px;
    right: 10px;
    top: calc(env(safe-area-inset-top) + 8px);
    z-index: 1045;
    pointer-events: none;
}
body.${ACTIVE_CLASS} .mob-toast {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: rgba(2, 43, 37, 0.94);
    border: 1px solid #0a6e5c;
    border-radius: 10px;
    padding: 8px 12px;
    font-size: 13px;
    color: #e8f4f0;
    text-align: center;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
    transition: opacity 0.35s, transform 0.35s;
}
body.${ACTIVE_CLASS} .mob-toast img { width: 22px; height: 22px; image-rendering: pixelated; }
body.${ACTIVE_CLASS} .mob-toast-out { opacity: 0; transform: translateY(-6px); }
body.${ACTIVE_CLASS} .scroller {
    font-size: 16pt;
    max-width: 80vw;
}
`;

    class MobileUIPlugin extends IdlePixelPlusPlugin {

        constructor() {
            const about = (typeof GM_info !== "undefined" && GM_info.script)
                ? { name: GM_info.script.name, version: GM_info.script.version, author: GM_info.script.author, description: GM_info.script.description }
                : { name: "IdlePixel Mobile UI", version: "0.1.0", author: "Eisa (StoneSinew)", description: "Mobile-first UI shell" };

            super("mobile-ui", {
                about: about,
                config: [
                    { label: "Mobile UI", type: "label" },
                    { id: "mode", label: "Activation (auto = touch device or narrow window)", type: "select", options: ["auto", "on", "off"], default: "auto" },
                    { id: "chatPeek", label: "Chat peek strip above the tab bar", type: "boolean", default: true }
                ]
            });

            this.built = false;
            this.active = false;
            this.tabs = [];
            this.sheets = [];
            this.badgeSyncs = [];
            this._origSwitchPanels = null;
            this._origScrollText = null;
            this._modalObserver = null;
            this._brewObserver = null;
            this._brewDecorateTimer = null;
            this._notifObserver = null;
            this._notifSyncTimer = null;
            this._notifBadgeEl = null;
            this._combatBuilt = false;
            this._combatTicker = null;
            this._spellBtns = {};
            this._mkt = null;
            this._mktTabBtns = {};
            this._mktCatalogRequested = false;
            this._mktModalHooked = false;
            this._mktLoading = false;
            this._mktPoll = null;
        }

        onLogin() {
            this.injectStyles();
            this.hookSwitchPanels();
            this.hookToasts();
            this.hookModals();
            this.evaluate();
            let t = null;
            window.addEventListener("resize", () => {
                clearTimeout(t);
                t = setTimeout(() => this.evaluate(), 200);
            });

            window.addEventListener("scroll", () => {
                if (!this.active) return;
                if (document.documentElement.scrollTop) document.documentElement.scrollTop = 0;
                if (document.body.scrollTop) document.body.scrollTop = 0;
            }, { passive: true });
        }

        onConfigChange() { this.evaluate(); }
        onConfigsChanged() { this.evaluate(); }

        onVariableSet(key) {
            if (key === "current_gathering_area" || key === "gathering_area") {
                this.syncGatheringActive();
            }
        }

        onMessageReceived(data) {
            try {
                if (!this._mkt) return;
                const tag = String(data).split("=")[0];
                if (this._mktLoading && /MARKET|TRADABLE/.test(tag)) {
                    console.log("[mobile-ui] market msg while loading:", tag);
                }
                if (this._mktLoading && this.mktCatalogReady()) this.mktCatalogArrived();
            } catch (e) {}
        }

        cfg(id, fallback) {
            try {
                const v = this.getConfig(id);
                return (v === undefined || v === null) ? fallback : v;
            } catch (e) {
                return fallback;
            }
        }

        shouldActivate() {
            const mode = String(this.cfg("mode", "auto"));
            if (mode === "on") return true;
            if (mode === "off") return false;
            return looksMobile();
        }

        evaluate() {
            const want = this.shouldActivate();
            if (want && !this.built) this.buildShell();
            document.body.classList.toggle(ACTIVE_CLASS, want);
            document.body.classList.toggle("mob-peek-off", !this.cfg("chatPeek", true));
            if (!want) {
                document.body.classList.remove("mob-chat-open");
                document.body.classList.remove("mob-combat");
                this.leaveCombat();
            }
            this.toggleViewport(want);
            this.active = want;
            if (want) {
                this.decorateBrewing();
                this.arrangeGathering();
                this.arrangeMarket();
                this.syncNotifBadge();
            }
        }

        toggleViewport(on) {
            setMobileViewport(on);
        }

        injectStyles() {
            if (document.getElementById("mob-ui-styles")) return;
            const style = document.createElement("style");
            style.id = "mob-ui-styles";
            style.textContent = CSS;
            document.head.appendChild(style);
        }

        parseMenu() {
            const out = {};
            document.querySelectorAll('[id^="left-panel-item_panel-"]').forEach((el) => {
                const pid = el.id.replace("left-panel-item_", "");
                if (pid.indexOf("-label") !== -1) return;
                const img = el.querySelector("img");
                const labelEl = document.getElementById(el.id + "-label");
                out[pid.replace("panel-", "")] = {
                    panel: COMBAT_STYLES[pid] ? "panel-combat" : pid,
                    icon: img ? img.src : null,
                    label: labelEl ? labelEl.textContent.trim() : pid.replace("panel-", "").replace(/-/g, " ").toUpperCase(),
                    sourceEl: el
                };
            });
            return out;
        }

        readLevel(sourceEl) {
            const lvlEl = sourceEl && sourceEl.querySelector("[data-menu-bar-levels-label]");
            const m = lvlEl ? lvlEl.textContent.match(/\d+/) : null;
            return m ? m[0] : null;
        }

        buildShell() {
            const menu = this.parseMenu();
            const pick = (keys) => keys.map(k => menu[k]).filter(Boolean);

            const skillsSheet = this.buildSheet("SKILLS", [
                { items: pick(SHEET_GROUPS.skills) }
            ]);

            const moreSheet = this.buildSheet("MORE", [
                { title: "SHOPS", items: pick(SHEET_GROUPS.shops) },

                { title: "PLUGINS & MODS", dynamic: () => this.scanPluginMenuItems() },
                { title: "OTHER", items: pick(SHEET_GROUPS.other) }
            ]);
            this.sheets = [skillsSheet, moreSheet];

            this.buildChatPeek();

            this.buildTabBar([
                { label: "HOME", icon: "https://cdn.idle-pixel.com/images/loot_bag.png", panel: "panel-main" },
                { label: "SKILLS", icon: "https://cdn.idle-pixel.com/images/skills.png", launcher: skillsSheet },
                { label: "COMBAT", icon: "https://cdn.idle-pixel.com/images/melee.png", panel: "panel-combat" },
                { label: "MARKET", icon: "https://cdn.idle-pixel.com/images/player_market.png", panel: "panel-player-market" },
                { label: "MORE", glyph: "☰", launcher: moreSheet }
            ]);

            if (this.tabs[0]) {
                const badge = document.createElement("span");
                badge.className = "mob-tab-badge";
                this.tabs[0].appendChild(badge);
                this._notifBadgeEl = badge;
            }
            this.watchNotifications();

            this.built = true;
            const current = typeof Globals !== "undefined" && Globals.currentPanel ? Globals.currentPanel : "panel-main";
            this.setActiveTab(current);
            document.body.classList.toggle("mob-on-home", current === "panel-main");
        }

        scanPluginMenuItems() {
            const items = [];
            document.querySelectorAll("#menu-bar .hover-menu-bar-item").forEach((el) => {

                if (el.closest('[id^="left-panel-item_"]')) return;
                if (el.querySelector('[id^="left-panel-item_"]')) return;
                if (el.style.display === "none") return;
                const label = (el.textContent || "").replace(/\s+/g, " ").trim().slice(0, 24).toUpperCase();
                if (!label || label === "BACK") return;
                const img = el.querySelector("img");
                items.push({
                    icon: img ? img.src : null,
                    glyph: "🔌",
                    label: label,
                    action: () => el.click()
                });
            });
            return items;
        }

        goTo(panelId) {
            this.closeSheets();
            if (typeof window.switch_panels === "function") window.switch_panels(panelId);
            window.scrollTo(0, 0);
        }

        closeSheets() {
            this.sheets.forEach(s => s.close());
        }

        makeSheetItem(it) {
            const b = document.createElement("button");
            b.className = "mob-item";
            if (it.icon) {
                const im = document.createElement("img");
                im.src = it.icon;
                im.alt = "";
                b.appendChild(im);
            } else if (it.glyph) {
                const g = document.createElement("span");
                g.className = "mob-glyph";
                g.textContent = it.glyph;
                b.appendChild(g);
            }
            const lab = document.createElement("span");
            lab.textContent = it.label;
            b.appendChild(lab);

            if (it.sourceEl) {
                const badge = document.createElement("span");
                badge.className = "mob-level";
                badge.style.display = "none";
                b.appendChild(badge);
                this.badgeSyncs.push(() => {
                    const lvl = this.readLevel(it.sourceEl);
                    badge.style.display = lvl ? "" : "none";
                    badge.textContent = lvl || "";
                });
            }

            b.addEventListener("click", () => {
                if (it.action) {
                    this.closeSheets();
                    it.action();
                    this.setActiveTab("");
                    const panels = document.querySelector(".panels");
                    if (panels) panels.scrollTop = 0;
                } else {
                    this.goTo(it.panel);
                }
            });
            return b;
        }

        buildSheet(title, sections) {
            const backdrop = document.createElement("div");
            backdrop.className = "mob-backdrop mob-shell";

            const sheet = document.createElement("div");
            sheet.className = "mob-sheet mob-shell";

            const head = document.createElement("div");
            head.className = "mob-sheet-head";
            const titleSpan = document.createElement("span");
            titleSpan.textContent = title;
            const close = document.createElement("button");
            close.className = "mob-sheet-close";
            close.textContent = "CLOSE";
            head.appendChild(titleSpan);
            head.appendChild(close);

            const body = document.createElement("div");
            body.className = "mob-sheet-body";

            const dynamics = [];
            sections.forEach((sec) => {
                let titleEl = null;
                if (sec.title) {
                    titleEl = document.createElement("div");
                    titleEl.className = "mob-section-title";
                    titleEl.textContent = sec.title;
                    body.appendChild(titleEl);
                }
                const grid = document.createElement("div");
                grid.className = "mob-grid";
                if (sec.dynamic) {
                    dynamics.push({ grid: grid, titleEl: titleEl, fn: sec.dynamic });
                } else {
                    sec.items.forEach((it) => grid.appendChild(this.makeSheetItem(it)));
                }
                body.appendChild(grid);
            });

            sheet.appendChild(head);
            sheet.appendChild(body);
            document.body.appendChild(backdrop);
            document.body.appendChild(sheet);

            const self = this;
            const api = {
                open() {
                    self.closeSheets();
                    dynamics.forEach((d) => {
                        const items = d.fn() || [];
                        d.grid.innerHTML = "";
                        items.forEach((it) => d.grid.appendChild(self.makeSheetItem(it)));
                        if (d.titleEl) d.titleEl.style.display = items.length ? "" : "none";
                        d.grid.style.display = items.length ? "" : "none";
                    });
                    self.badgeSyncs.forEach(fn => fn());
                    backdrop.classList.add("open");
                    sheet.classList.add("open");
                },
                close() {
                    backdrop.classList.remove("open");
                    sheet.classList.remove("open");
                },
                isOpen() { return sheet.classList.contains("open"); },
                toggle() { api.isOpen() ? api.close() : api.open(); }
            };
            close.addEventListener("click", api.close);
            backdrop.addEventListener("click", api.close);
            return api;
        }

        buildTabBar(slots) {
            const bar = document.createElement("div");
            bar.className = "mob-tabbar mob-shell";
            this.tabs = [];

            slots.forEach((slot) => {
                const b = document.createElement("button");
                b.className = "mob-tab";
                if (slot.icon) {
                    const im = document.createElement("img");
                    im.src = slot.icon;
                    im.alt = "";
                    b.appendChild(im);
                } else {
                    const g = document.createElement("span");
                    g.className = "mob-glyph";
                    g.textContent = slot.glyph || "?";
                    b.appendChild(g);
                }
                const lab = document.createElement("span");
                lab.textContent = slot.label;
                b.appendChild(lab);

                b.addEventListener("click", () => {
                    if (slot.launcher) {
                        slot.launcher.toggle();
                    } else if (slot.panel) {
                        this.goTo(slot.panel);
                    }
                });
                this.tabs.push(b);
                bar.appendChild(b);
            });

            document.body.appendChild(bar);
        }

        buildChatPeek() {
            const peek = document.createElement("div");
            peek.className = "mob-chatpeek mob-shell";

            const icon = document.createElement("span");
            icon.textContent = "💬";
            const msg = document.createElement("span");
            msg.className = "mob-peek-msg";
            msg.textContent = "CHAT";
            const chevron = document.createElement("span");
            chevron.className = "mob-peek-chevron";
            chevron.textContent = "▲";

            peek.appendChild(icon);
            peek.appendChild(msg);
            peek.appendChild(chevron);
            document.body.appendChild(peek);

            peek.addEventListener("click", () => {
                const open = document.body.classList.toggle("mob-chat-open");
                chevron.textContent = open ? "▼" : "▲";
                if (open) {
                    const area = document.getElementById("chat-area");
                    if (area) area.scrollTop = area.scrollHeight;
                }
            });

            const area = document.getElementById("chat-area");
            if (area) {
                const seed = area.lastElementChild;
                if (seed) msg.textContent = this.chatLineText(seed);
                new MutationObserver((muts) => {
                    for (let i = muts.length - 1; i >= 0; i--) {
                        const added = muts[i].addedNodes;
                        if (added && added.length) {
                            msg.textContent = this.chatLineText(added[added.length - 1]);
                            return;
                        }
                    }
                }).observe(area, { childList: true });
            }
        }

        chatLineText(node) {
            const text = (node.textContent || "").replace(/\s+/g, " ").trim();
            return text ? text.slice(0, 140) : "CHAT";
        }

        hookSwitchPanels() {
            if (this._origSwitchPanels || typeof window.switch_panels !== "function") return;
            const orig = window.switch_panels;
            this._origSwitchPanels = orig;
            const self = this;

            window.switch_panels = function (id) {
                orig.apply(this, arguments);
                if (!self.active) return;
                try {
                    self.closeSheets();
                    self.setActiveTab(id);
                    document.body.classList.toggle("mob-on-home", id === "panel-main");
                    const inCombat = id === "panel-combat-canvas";
                    document.body.classList.toggle("mob-combat", inCombat);
                    if (inCombat) self.enterCombat(); else self.leaveCombat();
                    const panels = document.querySelector(".panels");
                    if (panels) panels.scrollTop = 0;
                    if (id === "panel-brewing") requestAnimationFrame(() => { try { self.decorateBrewing(); } catch (e) { self.reportError("brewing", e); } });
                    if (id === "panel-gathering") requestAnimationFrame(() => { try { self.arrangeGathering(); } catch (e) { self.reportError("gathering", e); } });
                    if (id === "panel-player-market") requestAnimationFrame(() => { try { self.arrangeMarket(); } catch (e) { self.reportError("market", e); } });
                    if (inCombat) requestAnimationFrame(() => { try { self.arrangeCombat(); } catch (e) { self.reportError("combat-arrange", e); } });
                } catch (e) {
                    self.reportError("panel-switch", e);
                }
            };
        }

        reportError(where, e) {
            try {
                console.error("[mobile-ui] " + where + ":", e);
                this.showToast("none", "red", "Mobile UI error (" + where + "): " + (e && e.message ? e.message : e));
            } catch (e2) {  }
        }

        buildCombatUI() {
            if (this._combatBuilt) return;
            const tabbar = document.querySelector(".mob-tabbar");
            if (!tabbar) return;
            this._combatBuilt = true;

            const bar = document.createElement("div");
            bar.className = "mob-combat-bar";

            const back = document.createElement("button");
            back.className = "mob-combat-back";
            back.textContent = "←";
            back.setAttribute("aria-label", "leave combat");
            back.addEventListener("click", () => {
                if (typeof window.switch_panels === "function") window.switch_panels("panel-combat");
            });
            bar.appendChild(back);

            COMBAT_SPELLS.forEach((sp) => {
                const b = document.createElement("button");
                b.className = "mob-spell-btn";
                const origIcon = document.getElementById("image-" + sp.slug + "_spell_icon");
                const im = document.createElement("img");
                im.src = origIcon ? origIcon.src : "https://cdn.idle-pixel.com/images/" + sp.slug + "_spell_icon.png";
                im.alt = "";
                b.appendChild(im);
                const lab = document.createElement("span");
                lab.textContent = sp.label;
                b.appendChild(lab);
                const cd = document.createElement("span");
                cd.className = "mob-spell-cd";
                b.appendChild(cd);
                const note = document.createElement("span");
                note.className = "mob-spell-note";
                b.appendChild(note);
                b.addEventListener("click", () => {
                    const orig = document.getElementById("fighting-spell-" + sp.slug);
                    if (orig) orig.click();
                });
                this._spellBtns[sp.slug] = { btn: b, cd: cd, note: note, img: im };
                bar.appendChild(b);
            });
            tabbar.appendChild(bar);
        }

        arrangeCombat() {
            if (!this.active) return;
            const panel = document.getElementById("panel-combat-canvas");
            if (!panel || panel.dataset.mobArranged) return;
            const table = panel.querySelector("center > table");
            if (!table) return;
            panel.dataset.mobArranged = "1";

            const hudL = document.createElement("div");
            hudL.id = "mob-combat-hud-left";
            const hudR = document.createElement("div");
            hudR.id = "mob-combat-hud-right";
            const acts = document.createElement("div");
            acts.id = "mob-combat-actions";

            const heroPlate = panel.querySelector(".fighting-hero-stats-area");
            if (heroPlate) hudL.appendChild(heroPlate);
            const heroHp = document.getElementById("hero-progress-bar-hp");
            if (heroHp) {
                const barsTd = heroHp.closest("td");
                const center = barsTd ? barsTd.querySelector("center") : null;
                if (center) hudL.appendChild(center);
            }
            const heroStats = panel.querySelector("td.fight-right-border .td-combat-bottom-panel");
            if (heroStats) hudL.appendChild(heroStats);

            const monPlate = panel.querySelector(".fighting-monster-stats-area");
            if (monPlate) hudR.appendChild(monPlate);
            const monHp = document.getElementById("monster-progress-bar-hp");
            if (monHp) {
                const td = monHp.closest("td");
                const wrap = td ? (td.querySelector("center") || td.firstElementChild) : null;
                if (wrap && wrap !== td) hudR.appendChild(wrap);
                else if (td) { while (td.firstChild) hudR.appendChild(td.firstChild); }
            }
            panel.querySelectorAll("td.fight-left-border .td-combat-bottom-panel").forEach((el) => hudR.appendChild(el));

            COMBAT_ACTION_AREAS.forEach((id) => {
                const el = document.getElementById(id);
                if (el) acts.appendChild(el);
            });

            panel.appendChild(hudL);
            panel.appendChild(hudR);
            panel.appendChild(acts);
        }

        syncCombatUI() {
            COMBAT_SPELLS.forEach((sp) => {
                const entry = this._spellBtns[sp.slug];
                if (!entry) return;
                const orig = document.getElementById("fighting-spell-" + sp.slug);

                const available = !!orig && orig.style.display !== "none";
                if (entry.btn.classList.contains("mob-unavailable") === available) {
                    entry.btn.classList.toggle("mob-unavailable", !available);
                }

                const origIcon = document.getElementById("image-" + sp.slug + "_spell_icon");
                if (origIcon && entry.img.src !== origIcon.src) entry.img.src = origIcon.src;

                let cdVal = 0;
                try {
                    if (typeof Items !== "undefined" && typeof Items.getItem === "function") {
                        cdVal = parseInt(Items.getItem(sp.slug + "_cooldown"), 10) || 0;
                    }
                } catch (e) {  }
                const label = document.getElementById("fighting-spell-label-" + sp.slug);
                const labelText = label ? label.textContent.trim() : "";
                if (!cdVal && /^\d+$/.test(labelText)) cdVal = parseInt(labelText, 10) || 0;
                const cooling = cdVal > 0;
                if (entry.btn.classList.contains("mob-cooling") !== cooling) {
                    entry.btn.classList.toggle("mob-cooling", cooling);
                }
                const text = cooling ? String(cdVal) : "";
                if (entry.cd.textContent !== text) entry.cd.textContent = text;
                const blocked = labelText === "NO MANA" || labelText === "MAGIC BONUS";
                if (entry.btn.classList.contains("mob-nomana") !== blocked) {
                    entry.btn.classList.toggle("mob-nomana", blocked);
                }
                const noteText = blocked ? labelText : "";
                if (entry.note.textContent !== noteText) entry.note.textContent = noteText;
            });
        }

        enterCombat() {
            this.buildCombatUI();
            this.arrangeCombat();
            this.syncCombatUI();
            if (!this._combatTicker) {
                this._combatTicker = setInterval(() => {
                    if (!this.active || !document.body.classList.contains("mob-combat")) return;
                    this.syncCombatUI();
                }, 500);
            }
        }

        leaveCombat() {
            if (this._combatTicker) {
                clearInterval(this._combatTicker);
                this._combatTicker = null;
            }
        }

        arrangeGathering() {
            if (!this.active) return;
            const panel = document.getElementById("panel-gathering");
            if (!panel) return;
            if (!panel.dataset.mobArranged) {
                const header = panel.querySelector(".panel-logo-xp-area");
                if (header) {
                    panel.dataset.mobArranged = "1";
                    const chips = document.createElement("div");
                    chips.id = "mob-gather-chips";
                    const minis = document.createElement("div");
                    minis.id = "mob-gather-minis";
                    const loot = document.createElement("div");
                    loot.id = "mob-gather-loot";

                    const chipEls = Array.from(panel.querySelectorAll(
                        ':scope > itembox.box-shortcut-potion, :scope > itembox.tool-item-box-gathering, :scope > itembox[data-item="gathering_worker"]'
                    ));
                    const boxEls = Array.from(panel.querySelectorAll(":scope > .gathering-box"));
                    const lootEls = Array.from(panel.querySelectorAll(":scope > itembox"))
                        .filter((el) => chipEls.indexOf(el) === -1);

                    chipEls.forEach((el) => chips.appendChild(el));
                    boxEls.forEach((el) => minis.appendChild(el));
                    lootEls.forEach((el) => loot.appendChild(el));

                    header.after(chips, minis, loot);
                }
            }
            this.syncGatheringActive();
        }

        syncGatheringActive() {
            const boxes = document.querySelectorAll("#mob-gather-minis .gathering-box, #panel-gathering > .gathering-box");
            if (!boxes.length) return;

            let area = "";
            try {
                if (typeof Items !== "undefined" && typeof Items.getItemString === "function") {
                    area = String(Items.getItemString("current_gathering_area") || "");
                }
            } catch (e) {  }
            if (area === "none" || area === "0" || area === "undefined" || area === "null") area = "";

            if (!area) {
                document.querySelectorAll('#panel-gathering [id^="progress-bar-gathering-"]').forEach((el) => {
                    if (parseFloat(el.style.width || "0") > 0) {
                        area = el.id.replace("progress-bar-gathering-", "");
                    }
                });
            }

            boxes.forEach((b) => {
                const m = (b.getAttribute("onclick") || "").match(/open_gathering_dialogue\('([^']+)'/);
                const active = !!m && !!area && m[1] === area;

                const mini = !!area && !active;
                if (b.classList.contains("mob-gather-active") !== active) b.classList.toggle("mob-gather-active", active);
                if (b.classList.contains("mob-gather-mini") !== mini) b.classList.toggle("mob-gather-mini", mini);
            });
        }

        syncNotifBadge() {
            if (!this._notifBadgeEl) return;
            const area = document.getElementById("notifications-area");
            let count = 0;
            if (area) {
                Array.from(area.children).forEach((c) => {
                    if (c.style.display !== "none") count++;
                });
            }
            const text = count > 9 ? "9+" : String(count);
            if (this._notifBadgeEl.textContent !== text) this._notifBadgeEl.textContent = text;
            const on = count > 0;
            if (this._notifBadgeEl.classList.contains("on") !== on) this._notifBadgeEl.classList.toggle("on", on);
        }

        watchNotifications() {
            if (this._notifObserver) return;
            const area = document.getElementById("notifications-area");
            if (!area) return;
            this._notifObserver = new MutationObserver(() => {
                clearTimeout(this._notifSyncTimer);
                this._notifSyncTimer = setTimeout(() => this.syncNotifBadge(), 100);
            });
            this._notifObserver.observe(area, { childList: true, subtree: true, attributes: true, attributeFilter: ["style"] });
        }

        getBrewFavs() {
            try { return JSON.parse(localStorage.getItem(BREW_FAVS_KEY)) || []; } catch (e) { return []; }
        }

        setBrewFavs(list) {
            try { localStorage.setItem(BREW_FAVS_KEY, JSON.stringify(list)); } catch (e) {  }
        }

        toggleBrewFav(potion) {
            const favs = this.getBrewFavs();
            const i = favs.indexOf(potion);
            if (i === -1) favs.push(potion); else favs.splice(i, 1);
            this.setBrewFavs(favs);
            this.syncBrewStars();
            this.buildBrewFavStrip();
        }

        syncBrewStars() {
            const favs = this.getBrewFavs();
            document.querySelectorAll("#brewing-table .mob-fav-star").forEach((b) => {
                const faved = favs.indexOf(b.getAttribute("data-potion")) !== -1;
                const glyph = faved ? "★" : "☆";
                if (b.textContent !== glyph) b.textContent = glyph;
                if (b.classList.contains("faved") !== faved) b.classList.toggle("faved", faved);
            });
        }

        buildBrewFavStrip() {
            const table = document.getElementById("brewing-table");
            if (!table || !table.parentElement) return;
            let strip = document.getElementById("mob-brew-favs");
            if (!strip) {
                strip = document.createElement("div");
                strip.id = "mob-brew-favs";
                strip.className = "mob-brew-favs mob-shell";
                table.parentElement.insertBefore(strip, table);
            }
            const favs = this.getBrewFavs();
            strip.innerHTML = "";
            if (!favs.length) {
                strip.style.display = "none";
                return;
            }
            strip.style.display = "";

            const title = document.createElement("div");
            title.className = "mob-brew-favs-title";
            title.textContent = "FAVOURITES";
            strip.appendChild(title);

            favs.forEach((potion) => {
                const row = table.querySelector('tr[data-brewing-item="' + potion + '"]');
                const srcImg = row ? row.querySelector("td img") : null;
                const name = row && row.querySelector("td")
                    ? row.querySelector("td").textContent.replace(/\s+/g, " ").trim()
                    : potion.replace(/_/g, " ");

                const card = document.createElement("button");
                card.className = "mob-fav-card";
                if (srcImg) {
                    const im = document.createElement("img");
                    im.src = srcImg.src;
                    im.alt = "";
                    card.appendChild(im);
                }
                const span = document.createElement("span");
                span.textContent = name;
                card.appendChild(span);
                card.addEventListener("click", () => {
                    if (typeof Modals !== "undefined" && typeof Modals.open_brew_dialogue === "function") {
                        Modals.open_brew_dialogue(potion);
                    }
                });
                strip.appendChild(card);
            });
        }

        decorateBrewing() {
            if (!this.active) return;
            const table = document.getElementById("brewing-table");
            if (!table) return;

            const favs = this.getBrewFavs();
            table.querySelectorAll("tr[data-brewing-item]").forEach((row) => {
                if (row.querySelector(".mob-fav-star")) return;
                const potion = row.getAttribute("data-brewing-item");
                const b = document.createElement("button");
                b.className = "mob-fav-star mob-shell";
                b.setAttribute("data-potion", potion);
                b.setAttribute("aria-label", "favourite");
                b.textContent = favs.indexOf(potion) !== -1 ? "★" : "☆";
                b.classList.toggle("faved", favs.indexOf(potion) !== -1);
                b.addEventListener("click", (e) => {
                    e.stopPropagation();
                    this.toggleBrewFav(potion);
                });
                row.appendChild(b);
            });
            this.syncBrewStars();
            this.buildBrewFavStrip();

            if (!this._brewObserver) {
                this._brewObserver = new MutationObserver(() => {
                    clearTimeout(this._brewDecorateTimer);
                    this._brewDecorateTimer = setTimeout(() => this.decorateBrewing(), 150);
                });
                this._brewObserver.observe(table, { childList: true, subtree: true });
            }
        }

        mktCategories() {
            const map = {};
            const t = (typeof Market !== "undefined" && Market.tradables) || [];
            t.forEach((x) => { (map[x.category] = map[x.category] || []).push(x.item); });
            return map;
        }

        mktPretty(item) {
            try { if (typeof Items !== "undefined" && Items.get_pretty_item_name) return Items.get_pretty_item_name(item); } catch (e) {}
            return String(item).replace(/_/g, " ");
        }

        mktFmt(n) {
            try { if (typeof format_number === "function") return format_number(n); } catch (e) {}
            return String(n);
        }

        mktPrice(n) {
            try { if (typeof Market !== "undefined" && Market.get_price_after_tax) return Market.get_price_after_tax(n); } catch (e) {}
            return this.mktFmt(Math.floor(n * 1.01));
        }

        mktColor(cat) {
            try { if (typeof Market !== "undefined" && Market.get_category_background_color) { const c = Market.get_category_background_color(cat); if (c) return c; } } catch (e) {}
            return MARKET_CATEGORY_COLORS[cat] || "#eafdfb";
        }

        mktExpire(ts) {
            try { if (typeof Market !== "undefined" && Market._get_expire_time) return Market._get_expire_time(ts); } catch (e) {}
            const left = 259200000 + parseInt(ts, 10) - Date.now();
            if (left < 0) return "Expired";
            return Math.floor(left / 3600000) + "h left";
        }

        hookMarketModal() {
            if (this._mktModalHooked) return;
            if (typeof Modals === "undefined" || typeof Modals.market_select_tradable_item !== "function") return;
            this._mktModalHooked = true;
            const orig = Modals.market_select_tradable_item;
            const self = this;
            Modals.market_select_tradable_item = function (is_sell) {
                if (!is_sell && self.active) {
                    self.mktCatalogArrived();
                    return;
                }
                return orig.apply(this, arguments);
            };
        }

        mktCatalogReady() {
            return !!(typeof Market !== "undefined" && Market.tradables && Market.tradables.length);
        }

        mktCatalogArrived() {
            if (!this.mktCatalogReady()) return;
            if (this._mktPoll) { clearInterval(this._mktPoll); this._mktPoll = null; }
            this._mktCatalogRequested = false;
            document.body.classList.remove("mob-mkt-loading");
            this.dismissBrowsePicker();
            if (this._mktLoading) {
                this._mktLoading = false;
                try { this.renderMarketHome(); } catch (e) { this.reportError("market-catalog", e); }
            }
        }

        dismissBrowsePicker() {
            try {
                const m = document.getElementById("modal-market-select-item");
                if (m && m.classList.contains("show") && typeof jQuery !== "undefined") {
                    jQuery(m).modal("hide");
                }
            } catch (e) {}
        }

        loadMarketCatalog() {
            if (this.mktCatalogReady()) { this.mktCatalogArrived(); return; }
            this.hookMarketModal();
            if (this._mktPoll) return;
            document.body.classList.add("mob-mkt-loading");
            const self = this;
            let tries = 0;
            const attempt = function () {
                if (self.mktCatalogReady()) { self.mktCatalogArrived(); return; }
                if (tries % 4 === 0) {
                    self._mktCatalogRequested = true;
                    try { if (typeof websocket !== "undefined" && websocket.send) websocket.send("MARKET_BROWSE_BUTTON_CLICKED"); } catch (e) {}
                }
                tries++;
                if (tries > 24) {
                    clearInterval(self._mktPoll);
                    self._mktPoll = null;
                    document.body.classList.remove("mob-mkt-loading");
                    self.dismissBrowsePicker();
                    self.showMarketCatalogError();
                }
            };
            attempt();
            this._mktPoll = setInterval(attempt, 500);
        }

        showMarketCatalogError() {
            const body = this._mktBody;
            if (!body || !this._mktLoading) return;
            body.innerHTML = "";
            const wrap = document.createElement("div");
            wrap.className = "mob-mkt-empty";
            const msg = document.createElement("div");
            msg.textContent = "Couldn't load the market catalog.";
            wrap.appendChild(msg);
            const btn = document.createElement("button");
            btn.className = "mob-mkt-allbtn";
            btn.style.maxWidth = "220px";
            btn.style.marginTop = "10px";
            btn.textContent = "RETRY";
            const self = this;
            btn.addEventListener("click", function () { self._mktCatalogRequested = false; self.renderMarketHome(); });
            wrap.appendChild(btn);
            body.appendChild(wrap);
        }

        mktFetch(item) {
            try {
                const user = (typeof Items !== "undefined" && Items.getItemString) ? Items.getItemString("username") : "";
                return jQuery.get("../../market/browse/" + item + "/?username=" + user).then((d) => d || []);
            } catch (e) {
                return Promise.resolve([]);
            }
        }

        arrangeMarket() {
            if (!this.active) return;
            const panel = document.getElementById("panel-player-market");
            if (!panel || panel.dataset.mobArranged) return;
            panel.dataset.mobArranged = "1";
            this._mkt = { tab: "buy" };

            const shell = document.createElement("div");
            shell.id = "mob-market";
            shell.className = "mob-shell";

            const tabs = document.createElement("div");
            tabs.id = "mob-market-tabs";
            [["buy", "BUY"], ["sell", "SELL"], ["history", "HISTORY"]].forEach((def) => {
                const b = document.createElement("button");
                b.className = "mob-mkt-tab";
                b.textContent = def[1];
                b.addEventListener("click", () => this.marketTab(def[0]));
                this._mktTabBtns[def[0]] = b;
                tabs.appendChild(b);
            });
            shell.appendChild(tabs);

            const buy = document.createElement("div");
            buy.id = "mob-market-buy";
            const search = document.createElement("input");
            search.className = "mob-mkt-search";
            search.type = "search";
            search.placeholder = "Search items…";
            search.addEventListener("input", () => {
                const q = search.value.trim().toLowerCase();
                if (!q) this.renderMarketHome(); else this.renderMarketSearch(q);
            });
            buy.appendChild(search);
            this._mktSearchEl = search;
            const buyBody = document.createElement("div");
            buyBody.id = "mob-market-buy-body";
            buy.appendChild(buyBody);
            this._mktBody = buyBody;
            shell.appendChild(buy);

            const sell = document.createElement("div");
            sell.id = "mob-market-sell";
            for (let i = 1; i <= 3; i++) {
                ["empty", "occupied"].forEach((k) => {
                    const el = document.getElementById("player-market-slot-" + k + "-" + i);
                    if (el) sell.appendChild(el);
                });
            }
            shell.appendChild(sell);

            panel.insertBefore(shell, panel.firstChild);
            this.hookMarketModal();
            this.marketTab("buy");
            this.renderMarketHome();
        }

        marketTab(tab) {
            if (tab === "history") {
                if (typeof websocket !== "undefined") websocket.send("SHOW_BUY_SELL_MARKET_HISTORY");
                return;
            }
            this._mkt.tab = tab;
            Object.keys(this._mktTabBtns).forEach((k) => this._mktTabBtns[k].classList.toggle("active", k === tab));
            const buy = document.getElementById("mob-market-buy");
            const sell = document.getElementById("mob-market-sell");
            if (buy) buy.style.display = tab === "buy" ? "" : "none";
            if (sell) sell.style.display = tab === "sell" ? "" : "none";
        }

        mktCrumb(title, onBack) {
            const bar = document.createElement("div");
            bar.className = "mob-mkt-crumb";
            const back = document.createElement("button");
            back.className = "mob-mkt-back";
            back.textContent = "←";
            back.addEventListener("click", onBack);
            const t = document.createElement("span");
            t.className = "mob-mkt-crumb-title";
            t.textContent = title;
            bar.appendChild(back);
            bar.appendChild(t);
            return bar;
        }

        mktItemRow(item, onClick) {
            const row = document.createElement("div");
            row.className = "mob-mkt-row";
            const img = document.createElement("img");
            img.className = "mob-mkt-icon";
            img.src = "https://cdn.idle-pixel.com/images/" + item + ".png";
            img.alt = "";
            const main = document.createElement("div");
            main.className = "mob-mkt-main";
            const name = document.createElement("div");
            name.className = "mob-mkt-name";
            name.textContent = this.mktPretty(item);
            main.appendChild(name);
            const chev = document.createElement("span");
            chev.className = "mob-mkt-chev";
            chev.textContent = "›";
            row.appendChild(img);
            row.appendChild(main);
            row.appendChild(chev);
            row.addEventListener("click", onClick);
            return row;
        }

        mktListingRow(r, cheapest, showName) {
            const row = document.createElement("div");
            row.className = "mob-mkt-row" + (cheapest ? " mob-mkt-cheapest" : "");
            const yours = !!(typeof Items !== "undefined" && Items.getItem && String(Items.getItem("player_id")) === String(r.player_id));
            if (yours) row.className += " mob-mkt-yours";
            const img = document.createElement("img");
            img.className = "mob-mkt-icon";
            img.src = "https://cdn.idle-pixel.com/images/" + r.market_item_name + ".png";
            img.alt = "";
            const main = document.createElement("div");
            main.className = "mob-mkt-main";
            const name = document.createElement("div");
            name.className = "mob-mkt-name";
            const sub = document.createElement("div");
            sub.className = "mob-mkt-sub";
            if (showName) {
                name.textContent = this.mktPretty(r.market_item_name);
                sub.textContent = this.mktFmt(r.market_item_amount) + " available · " + this.mktExpire(r.market_item_post_timestamp);
            } else {
                name.textContent = this.mktFmt(r.market_item_amount) + " available";
                sub.textContent = (yours ? "Your offer · " : "") + this.mktExpire(r.market_item_post_timestamp);
            }
            main.appendChild(name);
            main.appendChild(sub);
            const price = document.createElement("div");
            price.className = "mob-mkt-price";
            price.innerHTML = '<img src="https://cdn.idle-pixel.com/images/coins.png" width="12" style="vertical-align:-1px"> ' + this.mktPrice(r.market_item_price_each) + " <small>each</small>";
            row.appendChild(img);
            row.appendChild(main);
            row.appendChild(price);
            row.addEventListener("click", () => {
                try {
                    if (typeof Modals !== "undefined" && Modals.market_purchase_item) {
                        Modals.market_purchase_item(r.market_id, r.market_item_name, r.market_item_amount, r.market_item_price_each);
                    }
                } catch (e) { this.reportError("market-buy", e); }
            });
            return row;
        }

        renderMarketHome() {
            const body = this._mktBody;
            if (!body) return;
            body.innerHTML = "";
            const cats = this.mktCategories();
            const grid = document.createElement("div");
            grid.className = "mob-mkt-cats";
            MARKET_CATEGORIES.forEach((cat) => {
                const items = cats[cat];
                if (!items || !items.length) return;
                const tile = document.createElement("div");
                tile.className = "mob-mkt-cat";
                tile.style.backgroundColor = this.mktColor(cat);
                const label = document.createElement("span");
                label.textContent = cat.replace(/_/g, " ");
                const cnt = document.createElement("small");
                cnt.textContent = items.length + " items";
                tile.appendChild(label);
                tile.appendChild(cnt);
                tile.addEventListener("click", () => this.openMarketCategory(cat));
                grid.appendChild(tile);
            });
            if (!grid.children.length) {
                const e = document.createElement("div");
                e.className = "mob-mkt-empty";
                e.textContent = "Loading market catalog…";
                body.appendChild(e);
                this._mktLoading = true;
                this.loadMarketCatalog();
                return;
            }
            body.appendChild(grid);
        }

        renderMarketSearch(q) {
            const body = this._mktBody;
            if (!body) return;
            body.innerHTML = "";
            const t = (typeof Market !== "undefined" && Market.tradables) || [];
            const seen = {};
            const matches = t.filter((x) => {
                if (seen[x.item]) return false;
                seen[x.item] = 1;
                return x.item.toLowerCase().indexOf(q) !== -1 || this.mktPretty(x.item).toLowerCase().indexOf(q) !== -1;
            }).slice(0, 40);
            if (!matches.length) {
                const e = document.createElement("div");
                e.className = "mob-mkt-empty";
                e.textContent = 'No items match "' + q + '"';
                body.appendChild(e);
                return;
            }
            matches.forEach((x) => body.appendChild(this.mktItemRow(x.item, () => this.openMarketItem(x.item, "search"))));
        }

        openMarketCategory(cat) {
            const body = this._mktBody;
            if (!body) return;
            body.innerHTML = "";
            body.appendChild(this.mktCrumb(cat.replace(/_/g, " "), () => this.renderMarketHome()));
            const allBtn = document.createElement("button");
            allBtn.className = "mob-mkt-allbtn";
            allBtn.textContent = "VIEW ALL LISTINGS IN " + cat.replace(/_/g, " ").toUpperCase();
            allBtn.addEventListener("click", () => this.openMarketCategoryAll(cat));
            body.appendChild(allBtn);
            const items = this.mktCategories()[cat] || [];
            items.forEach((item) => body.appendChild(this.mktItemRow(item, () => this.openMarketItem(item, "category:" + cat))));
        }

        openMarketItem(item, from) {
            const body = this._mktBody;
            if (!body) return;
            body.innerHTML = "";
            const back = (from && from.indexOf("category:") === 0)
                ? () => this.openMarketCategory(from.slice(9))
                : () => {
                    const q = this._mktSearchEl ? this._mktSearchEl.value.trim().toLowerCase() : "";
                    if (q) this.renderMarketSearch(q); else this.renderMarketHome();
                };
            body.appendChild(this.mktCrumb(this.mktPretty(item), back));
            const trend = document.createElement("a");
            trend.className = "mob-mkt-trend";
            trend.target = "_blank";
            trend.href = "https://data.idle-pixel.com/market/?item=" + item + "&range=7d";
            trend.innerHTML = '<img src="https://cdn.idle-pixel.com/images/stocks.png" width="14"> 7-day price trend';
            body.appendChild(trend);
            const loading = document.createElement("div");
            loading.className = "mob-mkt-empty";
            loading.textContent = "Loading offers…";
            body.appendChild(loading);
            const self = this;
            this.mktFetch(item).then((rows) => {
                if (loading.parentElement) loading.remove();
                rows = (rows || []).slice().sort((a, b) => a.market_item_price_each - b.market_item_price_each);
                if (!rows.length) {
                    const e = document.createElement("div");
                    e.className = "mob-mkt-empty";
                    e.textContent = "No offers for " + self.mktPretty(item) + " right now.";
                    body.appendChild(e);
                    return;
                }
                rows.forEach((r, idx) => body.appendChild(self.mktListingRow(r, idx === 0, false)));
            }).catch((e) => { if (loading.parentElement) loading.textContent = "Couldn't load offers."; self.reportError("market-fetch", e); });
        }

        openMarketCategoryAll(cat) {
            const body = this._mktBody;
            if (!body) return;
            body.innerHTML = "";
            body.appendChild(this.mktCrumb(cat.replace(/_/g, " ") + " · all listings", () => this.openMarketCategory(cat)));
            const loading = document.createElement("div");
            loading.className = "mob-mkt-empty";
            loading.textContent = "Loading listings…";
            body.appendChild(loading);
            const items = this.mktCategories()[cat] || [];
            const self = this;
            Promise.all(items.map((it) => this.mktFetch(it).catch(() => []))).then((all) => {
                if (loading.parentElement) loading.remove();
                let rows = [];
                all.forEach((a) => { rows = rows.concat(a || []); });
                rows.sort((a, b) => a.market_item_price_each - b.market_item_price_each);
                if (!rows.length) {
                    const e = document.createElement("div");
                    e.className = "mob-mkt-empty";
                    e.textContent = "No live listings in " + cat.replace(/_/g, " ") + ".";
                    body.appendChild(e);
                    return;
                }
                rows.forEach((r) => body.appendChild(self.mktListingRow(r, false, true)));
            });
        }

        hookToasts() {
            if (this._origScrollText || typeof Animations === "undefined" || typeof Animations.scrollText !== "function") return;
            const orig = Animations.scrollText;
            this._origScrollText = orig;
            const self = this;

            Animations.scrollText = function (icon, color, text) {
                if (self.active) {
                    try { self.showToast(icon, color, text); } catch (e) { console.error("[mobile-ui] toast:", e); }
                    return;
                }
                return orig.call(this, icon, color, text);
            };
        }

        hookModals() {
            if (this._modalObserver) return;

            const tagIfDeclaredBig = (m) => {
                if (m.classList.contains("mob-sheet-modal")) return;
                if (m.querySelector(".modal-dialog.modal-xl, .modal-dialog.modal-lg, .modal-xxl, .modal-xxxl")
                    || SHEET_MODAL_IDS.indexOf(m.id) !== -1) {
                    m.classList.add("mob-sheet-modal");
                }
            };
            document.querySelectorAll(".modal").forEach(tagIfDeclaredBig);

            this._modalObserver = new MutationObserver((muts) => {
                for (const mu of muts) {
                    const m = mu.target;
                    if (!m.classList || !m.classList.contains("modal")) continue;

                    if (!m.classList.contains("show")) {
                        m._mobSeen = false;
                        continue;
                    }
                    if (m._mobSeen) continue;
                    m._mobSeen = true;

                    tagIfDeclaredBig(m);
                    if (m.classList.contains("mob-sheet-modal")) continue;

                    requestAnimationFrame(() => {
                        if (!this.active || !m.classList.contains("show")) return;
                        if (m.classList.contains("mob-sheet-modal")) return;
                        try {
                            const content = m.querySelector(".modal-content");
                            if (content && content.offsetHeight > document.documentElement.clientHeight * 0.55) {
                                m.classList.add("mob-sheet-modal");
                            }
                        } catch (e) {  }
                    });
                }
            });
            this._modalObserver.observe(document.body, { subtree: true, attributes: true, attributeFilter: ["class"] });
        }

        showToast(icon, color, text) {
            let host = document.getElementById("mob-toasts");
            if (!host) {
                host = document.createElement("div");
                host.id = "mob-toasts";
                host.className = "mob-shell";
                document.body.appendChild(host);
            }
            const t = document.createElement("div");
            t.className = "mob-toast";
            if (icon && icon !== "none") {
                const im = document.createElement("img");
                im.src = "https://cdn.idle-pixel.com/" + icon;
                im.alt = "";
                t.appendChild(im);
            }
            const span = document.createElement("span");
            span.textContent = String(text == null ? "" : text).replace(/<[^>]*>/g, "");
            if (color && color !== "none") span.style.color = color;
            t.appendChild(span);
            host.appendChild(t);
            while (host.children.length > 3) host.removeChild(host.firstChild);
            setTimeout(function () {
                t.classList.add("mob-toast-out");
                setTimeout(function () { t.remove(); }, 400);
            }, 3200);
        }

        setActiveTab(panelId) {
            if (!this.tabs.length) return;
            const idx = TAB_PANEL_MAP[panelId];
            this.tabs.forEach((t, i) => t.classList.toggle("active", i === idx));
        }
    }

    if (looksMobile()) setMobileViewport(true);

    IdlePixelPlus.registerPlugin(new MobileUIPlugin());
})();