MWI Customizer

Customize Milky Way Idle

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         MWI Customizer
// @namespace    https://github.com/collaring
// @version      1.2.2
// @description  Customize Milky Way Idle
// @author       collaring <https://github.com/collaring>
// @license      MIT
// @match        https://www.milkywayidle.com/*
// @match        https://test.milkywayidle.com/*
// @match        https://www.milkywayidlecn.com/*
// @match        https://test.milkywayidlecn.com/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

// MIT License
//
// Copyright (c) 2026 ave
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

(function () {
  'use strict';

  // Configuration (user-tweakable)
  const cfg = {
    debug: false,
    // A list of DOM selectors that might represent inventory item elements.
    inventorySelectors: [
      '.inventory .slot',
      '.inv-slot',
      '.item-slot',
      '[data-item-id]',
      '.inventory-slot'
    ],
    // exposed quick-tunable options (defaults; can be overridden at runtime)
    outlineWidth: 2, // px
    glowAlpha: 0.08, // alpha for outer glow
    // smaller default spread so the outer cloud is less dominant
    glowSpread: 6, // px distance of the colored ring from the icon
    // blur amount for the outer glow (softens hard edge)
    glowBlur: 6, // px blur radius for outer glow
    innerBorderWidth: 2, // px width of the inner curved border
    // Toggle to show the inner curved border (inset) around icons
    showInnerBorder: true,
    // reduce background tint so icons aren't cloudy
    bgAlpha: 0.12, // background tint alpha
    // allow user override of quantity tiers via cfg.quantityTiers (null = disabled)
    quantityTiers: null,
    // Color mode: 'Quantity'|'Category'|'None' 窶・controls which coloring strategy is applied
    colorMode: 'Quantity',
    // 'All' mode: single color applied to all inventory/targets
    allColor: '#1d8ce0',
    allAlpha: 0.2,
    // Category-to-color mapping used when colorMode === 'Category'. Keys are category names.
    // Collection-style quantity tiers (min inclusive). These attempt to match Collection colors.
    // Edit these thresholds/colors to match your Collections UI precisely.
    collectionQuantityTiers: [
      { min: 1000000, color: '#ff44cc', alpha: 0.2 },
      { min: 100000, color: '#e3931b', alpha: 0.2 },
      { min: 10000, color: '#d0333d', alpha: 0.2 },
      { min: 1000, color: '#9368cf', alpha: 0.2 },
      { min: 100, color: '#1d8ce0', alpha: 0.2 },
      { min: 1, color: '#d0d0d0', alpha: 0.2 }
    ]
    ,
    // Sitewide colors (adjust site appearance). Empty = no override.
    siteColors: {
      header: '',
      headerAlpha: 0.2,
      panelBg: '',
      panelBgAlpha: 0.2,
      sidePanel: '',
      sidePanelAlpha: 0.2,
      navLabel: '',
      navLabelAlpha: 1,
      interactables: '',
      interactablesAlpha: 1,
      subPanel: '',
      subPanelAlpha: 0.2,
      chatBg: '',
      chatBgAlpha: 0.2,
        timestamp: '',
        timestampAlpha: 1,
        chatText: '',
        chatTextAlpha: 1,
        systemMessage: '',
        systemMessageAlpha: 1,
        inventoryLabels: '',
        inventoryLabelsAlpha: 1,
        buttonBg: '',
        buttonBgAlpha: 1,
        tabsBg: '',
        tabsBgAlpha: 1,
      skillXPBar: '',
      skillXPBarAlpha: 1,
      level: '',
      levelAlpha: 1,
      skillActions: '',
      skillActionsAlpha: 1,
      combat: '',
      combatAlpha: 1,
      progressBar: '',
      progressBarAlpha: 1,
      hitDmg: '',
      hitDmgAlpha: 1,
      hitMiss: '',
      hitMissAlpha: 1,
      barBg: '',
      barBgAlpha: 1,
      // Selected skill (active navigation link)
      selectedSkill: '',
      selectedSkillAlpha: 1,
      accent: '',
      accentAlpha: 1,
      text: ''
    }
    ,
    // Custom background image (URL). Enable to overlay a full-page background.
    backgroundEnabled: false,
    backgroundUrl: '',
    // background overlay appearance
    backgroundOpacity: 1,
    // active theme key (empty = custom/default)
    themeKey: '',
    // Hide/Organize UI state: per-element hidden flags and ordering
    hiddenElements: {},
    organizeOrder: [],
    // UI style: 'frosted' (default) or 'solid'
    uiStyle: 'frosted',
    // Settings button style: 'frosted' (default) or 'solid'
    btnStyle: 'frosted',
    // Animations
    combatAnim: true,
    usageAnim: true,
    swapPanels: false,
    chatTop: false,
    headerBottom: false,
    // Theme presets removed 窶・use siteColors and manual controls in the UI
  };

  // Reset-on-refresh flag: when true restores defaults except Dev keys
  cfg.resetOnRefresh = false;

  // Keep an immutable copy of defaults for reset
  const DEFAULT_CFG = JSON.parse(JSON.stringify(cfg));

  // Preset themes (map to `cfg.siteColors`)
  const PRESET_THEMES = [
    { key: '', label: 'Custom / Default', siteColors: {} },
    { key: 'dark', label: 'Dark', siteColors: {
        header: '#000000', headerAlpha: 1,
        panelBg: '#000000', panelBgAlpha: 1,
        sidePanel: '#000000', sidePanelAlpha: 1,
        navLabel: '', navLabelAlpha: 1,
        interactables: '#3c3c3c', interactablesAlpha: 1,
        subPanel: '#000000', subPanelAlpha: 1,
        chatBg: '#000000', chatBgAlpha: 1,
        timestamp: '#868686', timestampAlpha: 1,
        chatText: '', chatTextAlpha: 1,
        systemMessage: '', systemMessageAlpha: 1,
        inventoryLabels: '#b0b0b0', inventoryLabelsAlpha: 1,
        buttonBg: '#000000', buttonBgAlpha: 1,
        skillXPBar: '#999999', skillXPBarAlpha: 1,
        level: '', levelAlpha: 1,
        skillActions: '#1b1b1b', skillActionsAlpha: 1,
        combat: '#252525', combatAlpha: 1,
        progressBar: '', progressBarAlpha: 1,
        accent: '', accentAlpha: 1,
        text: ''
      } },
    { key: 'pink', label: 'Pink', siteColors: {
        header: '#ff80ff', headerAlpha: 0.78,
        panelBg: '#ff80ff', panelBgAlpha: 0.64,
        subPanel: '#ff80ff', subPanelAlpha: 0.47,
        sidePanel: '#ff80ff', sidePanelAlpha: 0.65,
        navLabel: '', navLabelAlpha: 1,
        interactables: '', interactablesAlpha: 1,
        chatBg: '#414141', chatBgAlpha: 0.41,
        timestamp: '', timestampAlpha: 1,
        chatText: '#ff80ff', chatTextAlpha: 1,
        systemMessage: '', systemMessageAlpha: 1,
        inventoryLabels: '#ffffff', inventoryLabelsAlpha: 1,
        buttonBg: '#000000', buttonBgAlpha: 1,
        skillXPBar: '#ff80ff', skillXPBarAlpha: 1,
        level: '', levelAlpha: 1,
        skillActions: '#460046', skillActionsAlpha: 0.79,
        combat: '#9b009b', combatAlpha: 1,
        progressBar: '#ff80ff', progressBarAlpha: 1,
        accent: '', accentAlpha: 1,
        text: ''
      } }
  ];

  // Items available for Hide/Organize (id, label, selectors)
  const ORGANIZE_ITEMS = [
    { id: 'marketplace', label: 'Marketplace', icon: { sprite: 'misc', id: 'marketplace' }, selectors: ['[class*="Marketplace"]','[id*="marketplace"]'] },
    { id: 'tasks', label: 'Tasks', icon: { sprite: 'misc', id: 'tasks' }, selectors: ['[class*="Tasks"]','[id*="tasks"]'] },
    { id: 'labyrinth', label: 'Labyrinth', icon: { sprite: 'misc', id: 'labyrinth' }, selectors: ['[class*="Labyrinth"]','[id*="labyrinth"]'] },
    { type: 'separator' },
    { id: 'milking', label: 'Milking', icon: { sprite: 'skills', id: 'milking' }, selectors: ['[class*="Milking"]','[id*="milking"]'] },
    { id: 'foraging', label: 'Foraging', icon: { sprite: 'skills', id: 'foraging' }, selectors: ['[class*="Foraging"]','[id*="foraging"]'] },
    { id: 'woodcutting', label: 'Woodcutting', icon: { sprite: 'skills', id: 'woodcutting' }, selectors: ['[class*="Woodcutting"]','[id*="woodcutting"]'] },
    { id: 'cheesesmithing', label: 'Cheesesmithing', icon: { sprite: 'skills', id: 'cheesesmithing' }, selectors: ['[class*="Cheese"]','[id*="cheese"]'] },
    { id: 'crafting', label: 'Crafting', icon: { sprite: 'skills', id: 'crafting' }, selectors: ['[class*="Craft"]','[id*="craft"]'] },
    { id: 'tailoring', label: 'Tailoring', icon: { sprite: 'skills', id: 'tailoring' }, selectors: ['[class*="Tailor"]','[id*="tailor"]'] },
    { id: 'cooking', label: 'Cooking', icon: { sprite: 'skills', id: 'cooking' }, selectors: ['[class*="Cook"]','[id*="cooking"]'] },
    { id: 'brewing', label: 'Brewing', icon: { sprite: 'skills', id: 'brewing' }, selectors: ['[class*="Brew"]','[id*="brew"]'] },
    { id: 'alchemy', label: 'Alchemy', icon: { sprite: 'skills', id: 'alchemy' }, selectors: ['[class*="Alchemy"]','[id*="alchemy"]'] },
    { id: 'enhancing', label: 'Enhancing', icon: { sprite: 'skills', id: 'enhancing' }, selectors: ['[class*="Enhance"]','[id*="enhance"]'] },
    { type: 'separator' },
    { id: 'combat', label: 'Combat', icon: { sprite: 'misc', id: 'combat' }, selectors: ['[class*="Combat"]','[id*="combat"]'] },
    { type: 'separator' },
    { id: 'shop', label: 'Shop', icon: { sprite: 'misc', id: 'shop' }, selectors: ['[class*="Shop"]','[id*="shop"]'] },
    { id: 'cowbell', label: 'Cowbell Store', icon: { sprite: 'misc', id: 'cowbell_store' }, selectors: ['[class*="Cowbell"]','[id*="cowbell"]'] },
    { id: 'loottracker', label: 'Loot Tracker', icon: { sprite: 'misc', id: 'loot_tracker' }, selectors: ['[class*="LootTracker"]','[id*="loottracker"]'] },
    { id: 'achievements', label: 'Achievements', icon: { sprite: 'misc', id: 'achievements' }, selectors: ['[class*="Achievement"]','[id*="achieve"]'] },
    { id: 'social', label: 'Social', icon: { sprite: 'misc', id: 'social' }, selectors: ['[class*="Social"]','[id*="social"]'] },
    { id: 'guild', label: 'Guild', icon: { sprite: 'misc', id: 'guild' }, selectors: ['[class*="Guild"]','[id*="guild"]'] },
    { id: 'leaderboard', label: 'Leaderboard', icon: { sprite: 'misc', id: 'leaderboard' }, selectors: ['[class*="Leader"]','[id*="leaderboard"]'] },
    { type: 'separator' },
    { id: 'settings', label: 'Settings', icon: { sprite: 'misc', id: 'settings' }, selectors: [], noHide: true },
    { id: 'links', label: 'Links', icon: { sprite: 'misc', id: 'patch_notes' }, selectors: ['[class*="minorNavigationLinks"]'] },
  ];

  const DEV_KEYS = ['debug']; // keys in cfg considered part of Dev category and preserved during auto-reset

  // Settings persistence
  const STORAGE_KEY = 'mwiCustomizerSettings_v1';

  function loadSettings() {
    try {
      const raw = localStorage.getItem(STORAGE_KEY);
      if (!raw) return;
      const obj = JSON.parse(raw);
      for (const k of Object.keys(obj)) {
        // only restore known cfg keys
        if (k in cfg) cfg[k] = obj[k];
      }
    } catch (e) { log('loadSettings error', e); }
  }

  function saveSettings() {
    try {
      // Persist all cfg keys except dev-only keys
      const keys = Object.keys(cfg).filter(k => !DEV_KEYS.includes(k));
      const out = {};
      for (const k of keys) if (cfg[k] !== undefined) out[k] = cfg[k];
      localStorage.setItem(STORAGE_KEY, JSON.stringify(out));
    } catch (e) { log('saveSettings error', e); }
  }

  function clearSettings() { try { localStorage.removeItem(STORAGE_KEY); } catch (e) { log('clearSettings error', e); } }

  // Apply stored sitewide colors
  function applySiteColors() {
    try {
      const sc = cfg.siteColors || {};
      const root = document.documentElement;
      if (sc.header) {
        const headVal = (sc.headerAlpha !== undefined && sc.headerAlpha < 1) ? colorToRGBA(sc.header, sc.headerAlpha) : sc.header;
        root.style.setProperty('--mwi-header-bg', headVal);
      } else root.style.removeProperty('--mwi-header-bg');
      if (sc.headerGrad) {
        const hgVal = (sc.headerGradAlpha !== undefined && sc.headerGradAlpha < 1) ? colorToRGBA(sc.headerGrad, sc.headerGradAlpha) : sc.headerGrad;
        root.style.setProperty('--mwi-header-grad', hgVal);
        root.classList.add('mwi-header-grad-active');
      } else { root.style.removeProperty('--mwi-header-grad'); root.classList.remove('mwi-header-grad-active'); }
      // panel bg variable still available but we also explicitly override default-colored panels
      // support alpha for panel and accent by converting to rgba when alpha < 1
      if (sc.panelBg) {
        const panelVal = (sc.panelBgAlpha !== undefined && sc.panelBgAlpha < 1) ? colorToRGBA(sc.panelBg, sc.panelBgAlpha) : sc.panelBg;
        root.style.setProperty('--mwi-panel-bg', panelVal);
      } else root.style.removeProperty('--mwi-panel-bg');
      if (sc.sidePanel) {
        const sideVal = (sc.sidePanelAlpha !== undefined && sc.sidePanelAlpha < 1) ? colorToRGBA(sc.sidePanel, sc.sidePanelAlpha) : sc.sidePanel;
        root.style.setProperty('--mwi-side-panel-bg', sideVal);
      } else root.style.removeProperty('--mwi-side-panel-bg');
      if (sc.subPanel) {
        const subVal = (sc.subPanelAlpha !== undefined && sc.subPanelAlpha < 1) ? colorToRGBA(sc.subPanel, sc.subPanelAlpha) : sc.subPanel;
        root.style.setProperty('--mwi-subpanel-bg', subVal);
      } else root.style.removeProperty('--mwi-subpanel-bg');
      if (sc.chatBg) {
        const chatVal = (sc.chatBgAlpha !== undefined && sc.chatBgAlpha < 1) ? colorToRGBA(sc.chatBg, sc.chatBgAlpha) : sc.chatBg;
        root.style.setProperty('--mwi-chat-bg', chatVal);
      } else root.style.removeProperty('--mwi-chat-bg');
      if (sc.skillActions) {
        const saVal = (sc.skillActionsAlpha !== undefined && sc.skillActionsAlpha < 1) ? colorToRGBA(sc.skillActions, sc.skillActionsAlpha) : sc.skillActions;
        root.style.setProperty('--mwi-skill-actions', saVal);
        root.classList.add('mwi-skill-actions-active');
      } else {
        root.style.removeProperty('--mwi-skill-actions');
        root.classList.remove('mwi-skill-actions-active');
      }
      if (sc.skillXPBar) {
        const xpVal = (sc.skillXPBarAlpha !== undefined && sc.skillXPBarAlpha < 1) ? colorToRGBA(sc.skillXPBar, sc.skillXPBarAlpha) : sc.skillXPBar;
        root.style.setProperty('--mwi-skill-xp', xpVal);
        root.classList.add('mwi-skill-xp-active');
      } else {
        root.style.removeProperty('--mwi-skill-xp');
        root.classList.remove('mwi-skill-xp-active');
      }
      if (sc.navLabel) {
        const nlVal = (sc.navLabelAlpha !== undefined && sc.navLabelAlpha < 1) ? colorToRGBA(sc.navLabel, sc.navLabelAlpha) : sc.navLabel;
        root.style.setProperty('--mwi-nav-label', nlVal);
        root.classList.add('mwi-nav-label-active');
      } else {
        root.style.removeProperty('--mwi-nav-label');
        root.classList.remove('mwi-nav-label-active');
      }
      // Selected skill (active nav link)
      if (sc.selectedSkill) {
        const ssVal = (sc.selectedSkillAlpha !== undefined && sc.selectedSkillAlpha < 1) ? colorToRGBA(sc.selectedSkill, sc.selectedSkillAlpha) : sc.selectedSkill;
        root.style.setProperty('--mwi-selected-skill', ssVal);
        root.classList.add('mwi-nav-selected-active');
      } else {
        root.style.removeProperty('--mwi-selected-skill');
        root.classList.remove('mwi-nav-selected-active');
      }
      if (sc.inventoryLabels) {
        const ilVal = (sc.inventoryLabelsAlpha !== undefined && sc.inventoryLabelsAlpha < 1) ? colorToRGBA(sc.inventoryLabels, sc.inventoryLabelsAlpha) : sc.inventoryLabels;
        root.style.setProperty('--mwi-inventory-labels', ilVal);
        root.classList.add('mwi-inventory-labels-active');
      } else {
        root.style.removeProperty('--mwi-inventory-labels');
        root.classList.remove('mwi-inventory-labels-active');
      }
      if (sc.level) {
        const lv = (sc.levelAlpha !== undefined && sc.levelAlpha < 1) ? colorToRGBA(sc.level, sc.levelAlpha) : sc.level;
        root.style.setProperty('--mwi-level', lv);
        root.classList.add('mwi-level-active');
      } else {
        root.style.removeProperty('--mwi-level');
        root.classList.remove('mwi-level-active');
      }
      if (sc.interactables) {
        const iaVal = (sc.interactablesAlpha !== undefined && sc.interactablesAlpha < 1) ? colorToRGBA(sc.interactables, sc.interactablesAlpha) : sc.interactables;
        root.style.setProperty('--mwi-interactables', iaVal);
        root.classList.add('mwi-interactables-active');
      } else {
        root.style.removeProperty('--mwi-interactables');
        root.classList.remove('mwi-interactables-active');
      }
      if (sc.timestamp) {
        const tVal = (sc.timestampAlpha !== undefined && sc.timestampAlpha < 1) ? colorToRGBA(sc.timestamp, sc.timestampAlpha) : sc.timestamp;
        root.style.setProperty('--mwi-timestamp', tVal);
        root.classList.add('mwi-timestamp-active');
      } else {
        root.style.removeProperty('--mwi-timestamp');
        root.classList.remove('mwi-timestamp-active');
      }
      if (sc.chatText) {
        const ctVal = (sc.chatTextAlpha !== undefined && sc.chatTextAlpha < 1) ? colorToRGBA(sc.chatText, sc.chatTextAlpha) : sc.chatText;
        root.style.setProperty('--mwi-chat-text', ctVal);
        root.classList.add('mwi-chat-text-active');
        try {
          applyChatTextToAll(); ensureChatTextObserver();
          // Chat messages may not be in the DOM yet on page load — retry a few times
          // to catch the initial batch that renders after React mounts.
          setTimeout(() => { try { applyChatTextToAll(); } catch (e) {} }, 800);
          setTimeout(() => { try { applyChatTextToAll(); } catch (e) {} }, 2500);
          setTimeout(() => { try { applyChatTextToAll(); } catch (e) {} }, 5000);
        } catch (e) { log('apply chatText error', e); }
      } else {
        root.style.removeProperty('--mwi-chat-text');
        root.classList.remove('mwi-chat-text-active');
        try { clearChatTextFromAll(); if (chatTextObserver) { chatTextObserver.disconnect(); chatTextObserver = null; } } catch (e) { log('clear chatText error', e); }
      }
      if (sc.systemMessage) {
        const sVal = (sc.systemMessageAlpha !== undefined && sc.systemMessageAlpha < 1) ? colorToRGBA(sc.systemMessage, sc.systemMessageAlpha) : sc.systemMessage;
        root.style.setProperty('--mwi-system-message', sVal);
        root.classList.add('mwi-system-message-active');
      } else {
        root.style.removeProperty('--mwi-system-message');
        root.classList.remove('mwi-system-message-active');
      }
      if (sc.progressBar) {
        const pVal = (sc.progressBarAlpha !== undefined && sc.progressBarAlpha < 1) ? colorToRGBA(sc.progressBar, sc.progressBarAlpha) : sc.progressBar;
        root.style.setProperty('--mwi-progress-bar', pVal);
        root.classList.add('mwi-progress-bar-active');
      } else {
        root.style.removeProperty('--mwi-progress-bar');
        root.classList.remove('mwi-progress-bar-active');
      }
      if (sc.combat) {
        const cVal = (sc.combatAlpha !== undefined && sc.combatAlpha < 1) ? colorToRGBA(sc.combat, sc.combatAlpha) : sc.combat;
        root.style.setProperty('--mwi-combat', cVal);
        root.classList.add('mwi-combat-active');
      } else {
        root.style.removeProperty('--mwi-combat');
        root.classList.remove('mwi-combat-active');
      }
      // HP / MP bar colors
      if (sc.hp) {
        const hpVal = (sc.hpAlpha !== undefined && sc.hpAlpha < 1) ? colorToRGBA(sc.hp, sc.hpAlpha) : sc.hp;
        root.style.setProperty('--mwi-hp', hpVal);
        root.classList.add('mwi-hp-active');
      } else {
        root.style.removeProperty('--mwi-hp');
        root.classList.remove('mwi-hp-active');
      }
      if (sc.mp) {
        const mpVal = (sc.mpAlpha !== undefined && sc.mpAlpha < 1) ? colorToRGBA(sc.mp, sc.mpAlpha) : sc.mp;
        root.style.setProperty('--mwi-mp', mpVal);
        root.classList.add('mwi-mp-active');
      } else {
        root.style.removeProperty('--mwi-mp');
        root.classList.remove('mwi-mp-active');
      }
      // Hitsplat Damage color
      if (sc.hitDmg) {
        const hitDmgVal = (sc.hitDmgAlpha !== undefined && sc.hitDmgAlpha < 1) ? colorToRGBA(sc.hitDmg, sc.hitDmgAlpha) : sc.hitDmg;
        root.style.setProperty('--mwi-hit-dmg', hitDmgVal);
        root.classList.add('mwi-hit-dmg-active');
      } else {
        root.style.removeProperty('--mwi-hit-dmg');
        root.classList.remove('mwi-hit-dmg-active');
      }
      // Hitsplat Miss color
      if (sc.hitMiss) {
        const hitMissVal = (sc.hitMissAlpha !== undefined && sc.hitMissAlpha < 1) ? colorToRGBA(sc.hitMiss, sc.hitMissAlpha) : sc.hitMiss;
        root.style.setProperty('--mwi-hit-miss', hitMissVal);
        root.classList.add('mwi-hit-miss-active');
      } else {
        root.style.removeProperty('--mwi-hit-miss');
        root.classList.remove('mwi-hit-miss-active');
      }
      // Attack bar color
      if (sc.attack) {
        const attackVal = (sc.attackAlpha !== undefined && sc.attackAlpha < 1) ? colorToRGBA(sc.attack, sc.attackAlpha) : sc.attack;
        root.style.setProperty('--mwi-attack', attackVal);
        root.classList.add('mwi-attack-active');
      } else {
        root.style.removeProperty('--mwi-attack');
        root.classList.remove('mwi-attack-active');
      }
      // Bar background color
      if (sc.barBg) {
        const barBgVal = (sc.barBgAlpha !== undefined && sc.barBgAlpha < 1) ? colorToRGBA(sc.barBg, sc.barBgAlpha) : sc.barBg;
        root.style.setProperty('--mwi-bar-bg', barBgVal);
        root.classList.add('mwi-bar-bg-active');
      } else {
        root.style.removeProperty('--mwi-bar-bg');
        root.classList.remove('mwi-bar-bg-active');
      }
      // Consumables / Abilities color
      if (sc.consumables) {
        const consVal = (sc.consumablesAlpha !== undefined && sc.consumablesAlpha < 1) ? colorToRGBA(sc.consumables, sc.consumablesAlpha) : sc.consumables;
        root.style.setProperty('--mwi-consumables', consVal);
        root.classList.add('mwi-consumables-active');
      } else {
        root.style.removeProperty('--mwi-consumables');
        root.classList.remove('mwi-consumables-active');
      }
      if (sc.buttonBg) {
        const btnVal = (sc.buttonBgAlpha !== undefined && sc.buttonBgAlpha < 1) ? colorToRGBA(sc.buttonBg, sc.buttonBgAlpha) : sc.buttonBg;
        root.style.setProperty('--mwi-button-bg', btnVal);
        root.classList.add('mwi-button-bg-active');
      } else {
        root.style.removeProperty('--mwi-button-bg');
        root.classList.remove('mwi-button-bg-active');
      }
      if (sc.tabsBg) {
        const tabsBgVal = (sc.tabsBgAlpha !== undefined && sc.tabsBgAlpha < 1) ? colorToRGBA(sc.tabsBg, sc.tabsBgAlpha) : sc.tabsBg;
        root.style.setProperty('--mwi-tabs-bg', tabsBgVal);
        root.classList.add('mwi-tabs-bg-active');
      } else {
        root.style.removeProperty('--mwi-tabs-bg');
        root.classList.remove('mwi-tabs-bg-active');
      }
      if (sc.accent) {
        const accVal = (sc.accentAlpha !== undefined && sc.accentAlpha < 1) ? colorToRGBA(sc.accent, sc.accentAlpha) : sc.accent;
        root.style.setProperty('--mwi-accent', accVal);
        root.classList.add('mwi-accent-active');
      } else {
        root.style.removeProperty('--mwi-accent');
        root.classList.remove('mwi-accent-active');
      }
      // text color falls back to accent when text is not explicitly set
      if (sc.text) root.style.setProperty('--mwi-text', sc.text);
      else if (sc.accent) root.style.setProperty('--mwi-text', sc.accent);
      else root.style.removeProperty('--mwi-text');
      // Custom background image (opt-in)
      try {
        if (cfg.backgroundUrl && String(cfg.backgroundUrl).trim()) {
          const urlVal = String(cfg.backgroundUrl).trim();
          root.style.setProperty('--mwi-bg-image', `url("${urlVal}")`);
          // set appearance vars (opacity/size/position)
          root.style.setProperty('--mwi-bg-opacity', (cfg.backgroundOpacity !== undefined ? cfg.backgroundOpacity : 1));
          // background size/position are fixed to cover/center for now
          if (cfg.backgroundEnabled) root.classList.add('mwi-bg-active'); else root.classList.remove('mwi-bg-active');
        } else {
          root.style.removeProperty('--mwi-bg-image');
          root.style.removeProperty('--mwi-bg-opacity');
          root.style.removeProperty('--mwi-bg-size');
          root.style.removeProperty('--mwi-bg-position');
          root.classList.remove('mwi-bg-active');
        }
      } catch (e) { log('apply background error', e); }
      // Use root-level CSS variables so dynamic elements inherit colors.
    try { applyHideOrganize(); } catch (e) {}
    // Apply panel swap from saved config
    try { document.documentElement.classList.toggle('mwi-swap-panels', cfg.swapPanels === true); } catch (e) {}
    try { document.documentElement.classList.toggle('mwi-chat-top', cfg.chatTop === true); } catch (e) {}
    try { document.documentElement.classList.toggle('mwi-header-bottom', cfg.headerBottom === true); } catch (e) {}
    } catch (e) { log('applySiteColors error', e); }
  }

  // Apply hide/organize settings
  function applyHideOrganize() {
    try {
      const order = Array.isArray(cfg.organizeOrder) && cfg.organizeOrder.length ? cfg.organizeOrder : ORGANIZE_ITEMS.filter(i=>i.id).map(i=>i.id);
      // ensure cfg.organizeOrder initialized
      if (!Array.isArray(cfg.organizeOrder) || !cfg.organizeOrder.length) cfg.organizeOrder = order.slice();
      // append any newly-added items not yet in the saved order (e.g. after importing an old theme)
      for (const item of ORGANIZE_ITEMS) { if (item.id && item.type !== 'separator' && !cfg.organizeOrder.includes(item.id)) cfg.organizeOrder.push(item.id); }
      for (const item of ORGANIZE_ITEMS) {
        if (!item || item.type === 'separator' || !item.id) continue;
        const hidden = cfg.hiddenElements && cfg.hiddenElements[item.id];
        const sels = Array.isArray(item.selectors) ? item.selectors : [];
        for (const s of sels) {
          try {
            const els = Array.from(document.querySelectorAll(s));
            for (const el of els) {
              try {
                if (hidden) {
                  el.style.setProperty('display','none','important');
                  try { el.dataset.mwiHidden = '1'; } catch (e) {}
                } else {
                  try {
                    if (el.dataset && el.dataset.mwiHidden) {
                      el.style.removeProperty('display');
                      delete el.dataset.mwiHidden;
                    }
                  } catch (e) {}
                }
              } catch (e) {}
            }
          } catch (e) {}
        }
        // Also support hiding navigation entries by label text
        try {
          const navs = Array.from(document.querySelectorAll('.NavigationBar_nav__3uuUl'));
          if (navs.length && item.label) {
            const want = (String(item.label||'')||'').trim().toLowerCase();
            for (const n of navs) {
              try {
                const labelSpan = n.querySelector('.NavigationBar_label__1uH-y');
                const txt = labelSpan && labelSpan.textContent ? labelSpan.textContent.trim().toLowerCase() : '';
                if (!txt) continue;
                if (txt === want) {
                  // hide the whole navigationLink wrapper if present
                  const link = n.closest('.NavigationBar_navigationLink__3eAHA') || n;
                  try {
                    if (hidden) {
                      link.style.setProperty('display','none','important');
                      try { link.dataset.mwiHidden = '1'; } catch (e) {}
                    } else {
                      try {
                        if (link.dataset && link.dataset.mwiHidden) {
                          link.style.removeProperty('display');
                          delete link.dataset.mwiHidden;
                        }
                      } catch (e) {}
                    }
                  } catch (e) {}
                }
              } catch (e) {}
            }
          }
        } catch (e) {}
      }
      // Also reorder nav elements in the DOM
      try { applyNavOrder(); } catch(e) {}
    } catch (e) { log('applyHideOrganize error', e); }
  }

  // Reorder navigation items in the game DOM to match cfg.organizeOrder
  function applyNavOrder() {
    try {
      const order = Array.isArray(cfg.organizeOrder) && cfg.organizeOrder.length ? cfg.organizeOrder : ORGANIZE_ITEMS.filter(i=>i.id).map(i=>i.id);
      // Build label 竊・id map
      const labelToId = {};
      for (const it of ORGANIZE_ITEMS) { if (it.id && it.label) labelToId[it.label.trim().toLowerCase()] = it.id; }
      // Find all nav link elements (hashed class names)
      const navLinks = Array.from(document.querySelectorAll('[class*="NavigationBar_navigationLink"]'));
      if (!navLinks.length) return;
      // Match each nav link to an id by its label text
      const idToEl = {};
      for (const link of navLinks) {
        const labelEl = link.querySelector('[class*="NavigationBar_label"]');
        const txt = labelEl ? labelEl.textContent.trim().toLowerCase() : '';
        if (txt && labelToId[txt]) idToEl[labelToId[txt]] = link;
      }
      // Also map 'links' to the minorNavigationLinks element (different element type, same container)
      const minorLinks = document.querySelector('[class*="NavigationBar_minorNavigationLinks"]');
      if (minorLinks) idToEl['links'] = minorLinks;
      // Find container (parent of first matched element)
      const firstMatched = Object.values(idToEl)[0];
      if (!firstMatched) return;
      const container = firstMatched.parentElement;
      if (!container) return;
      // Append each ordered element to end of container in sequence
      for (const id of order) {
        const el = idToEl[id];
        if (el && el.parentElement === container) container.appendChild(el);
      }
    } catch (e) { log('applyNavOrder error', e); }
  }

  // Open organize modal (hide toggles only)
  function openOrganizeModal() {
    try {
      // remove existing
      const existing = document.getElementById('mwi-organize-overlay'); if (existing) existing.remove();
      const over = document.createElement('div'); over.id = 'mwi-organize-overlay'; over.style.position = 'fixed'; over.style.inset = '0'; over.style.background = 'rgba(0,0,0,0.6)'; over.style.display = 'flex'; over.style.alignItems = 'center'; over.style.justifyContent = 'center'; over.style.zIndex = '10000030';
      const dialog = document.createElement('div'); dialog.id = 'mwi-organize-dialog'; dialog.style.position = 'relative'; dialog.style.background = '#0f1720'; dialog.style.color = '#e6eef8'; dialog.style.padding = '12px'; dialog.style.borderRadius = '8px'; dialog.style.width = '420px'; dialog.style.maxWidth = '86%'; dialog.style.maxHeight = '80vh'; dialog.style.overflow = 'hidden'; dialog.style.boxShadow = '0 8px 24px rgba(0,0,0,0.6)'; dialog.style.display = 'flex'; dialog.style.flexDirection = 'column';
      const title = document.createElement('h3'); title.textContent = 'Customize left side panel'; title.style.margin = '0 0 8px 0'; title.style.background = 'linear-gradient(90deg, #44aaff, #ff44cc)'; title.style.webkitBackgroundClip = 'text'; title.style.webkitTextFillColor = 'transparent'; title.style.backgroundClip = 'text';
      // top-right close button (matches main modal close style)
      const orgClose = document.createElement('button'); orgClose.id = 'mwi-organize-close'; orgClose.textContent = '\u2715';
      orgClose.style.position = 'absolute'; orgClose.style.top = '8px'; orgClose.style.right = '8px'; orgClose.style.background = 'transparent'; orgClose.style.border = '0'; orgClose.style.color = '#e6eef8'; orgClose.style.fontSize = '16px'; orgClose.style.cursor = 'pointer'; orgClose.style.padding = '4px';
      dialog.appendChild(orgClose);
      dialog.appendChild(title);

      const list = document.createElement('div'); list.className = 'mwi-org-list';

      // Resolve sprite URL from live DOM by matching a partial filename
      function getSpriteUrl(spriteKey) {
        try {
          const uses = document.querySelectorAll('svg use[href*="' + spriteKey + '_sprite"]');
          if (uses.length) { const href = uses[0].getAttribute('href'); return href ? href.split('#')[0] : null; }
        } catch (e) {}
        return null;
      }
      const skillsSpriteUrl = getSpriteUrl('skills');
      const miscSpriteUrl = getSpriteUrl('misc');

      let dragSrcId = null;

      function renderList() {
        list.innerHTML = '';
        const order = Array.isArray(cfg.organizeOrder) && cfg.organizeOrder.length ? cfg.organizeOrder.slice() : ORGANIZE_ITEMS.filter(i=>i.id).map(i=>i.id);
        // append newly-added items not yet in saved order (e.g. old imported theme)
        for (const it of ORGANIZE_ITEMS) { if (it.id && it.type !== 'separator' && !order.includes(it.id)) order.push(it.id); }
        const map = {};
        for (const it of ORGANIZE_ITEMS) if (it && it.id) map[it.id] = it;

        function makeRow(it) {
          const row = document.createElement('div'); row.className = 'mwi-org-row'; row.dataset.id = it.id;
          row.draggable = true;

          // Drag handle 窶・fixed width col
          const handleWrap = document.createElement('div'); handleWrap.className = 'mwi-org-row-handle';
          const handle = document.createElement('span'); handle.className = 'mwi-drag-handle'; handle.textContent = '⣿';
          handle.title = 'Drag to reorder';
          handleWrap.appendChild(handle); row.appendChild(handleWrap);

          // Icon 窶・fixed width col
          const iconWrap = document.createElement('div'); iconWrap.className = 'mwi-org-row-icon';
          if (it.icon) {
            try {
              const spriteUrl = it.icon.sprite === 'skills' ? skillsSpriteUrl : miscSpriteUrl;
              if (spriteUrl) {
                const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
                svg.setAttribute('role', 'img'); svg.setAttribute('width', '20'); svg.setAttribute('height', '20');
                svg.style.flexShrink = '0';
                const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
                use.setAttribute('href', spriteUrl + '#' + it.icon.id);
                svg.appendChild(use); iconWrap.appendChild(svg);
              }
            } catch (e) {}
          }
          row.appendChild(iconWrap);

          // Label 窶・fills remaining space
          const lbl = document.createElement('div'); lbl.className = 'mwi-org-row-label'; lbl.textContent = it.label;
          row.appendChild(lbl);

          // Right side
          const right = document.createElement('div'); right.className = 'mwi-org-row-right';
          if (it.noHide) {
            const badge = document.createElement('span'); badge.textContent = 'drag only'; badge.style.fontSize = '11px'; badge.style.opacity = '0.4'; badge.style.fontStyle = 'italic';
            right.appendChild(badge);
          } else {
            const chk = document.createElement('input'); chk.type = 'checkbox'; chk.checked = !!(cfg.hiddenElements && cfg.hiddenElements[it.id]);
            chk.addEventListener('change', () => { try { cfg.hiddenElements = cfg.hiddenElements || {}; cfg.hiddenElements[it.id] = chk.checked; saveSettings(); applyHideOrganize(); } catch (e) { log('hide toggle error', e); } });
            const chkLabel = document.createElement('label'); chkLabel.textContent = 'Hide'; chkLabel.style.marginLeft = '8px';
            right.appendChild(chk); right.appendChild(chkLabel);
            // Clicking anywhere in the row (except handle) also toggles the checkbox
            row.style.cursor = 'pointer';
            row.addEventListener('click', (ev) => { try { if (ev.target === chk || ev.target === handle) return; chk.checked = !chk.checked; chk.dispatchEvent(new Event('change')); } catch (e) {} });
          }
          row.appendChild(right);

          // Drag events
          row.addEventListener('dragstart', (ev) => {
            dragSrcId = it.id;
            row.classList.add('dragging');
            ev.dataTransfer.effectAllowed = 'move';
            ev.dataTransfer.setData('text/plain', it.id);
          });
          row.addEventListener('dragend', () => {
            row.classList.remove('dragging');
            list.querySelectorAll('.mwi-org-row').forEach(r => r.classList.remove('drag-over-top','drag-over-bottom'));
          });
          row.addEventListener('dragover', (ev) => {
            ev.preventDefault(); ev.dataTransfer.dropEffect = 'move';
            if (!dragSrcId || dragSrcId === it.id) return;
            const rect = row.getBoundingClientRect();
            const half = rect.top + rect.height / 2;
            list.querySelectorAll('.mwi-org-row').forEach(r => r.classList.remove('drag-over-top','drag-over-bottom'));
            row.classList.add(ev.clientY < half ? 'drag-over-top' : 'drag-over-bottom');
          });
          row.addEventListener('dragleave', () => row.classList.remove('drag-over-top','drag-over-bottom'));
          row.addEventListener('drop', (ev) => {
            ev.preventDefault();
            row.classList.remove('drag-over-top','drag-over-bottom');
            if (!dragSrcId || dragSrcId === it.id) return;
            const currentOrder = Array.isArray(cfg.organizeOrder) && cfg.organizeOrder.length ? cfg.organizeOrder.slice() : ORGANIZE_ITEMS.filter(i=>i.id).map(i=>i.id);
            const fromIdx = currentOrder.indexOf(dragSrcId);
            let toIdx = currentOrder.indexOf(it.id);
            if (fromIdx === -1 || toIdx === -1) return;
            const rect = row.getBoundingClientRect();
            const insertBefore = ev.clientY < rect.top + rect.height / 2;
            currentOrder.splice(fromIdx, 1);
            toIdx = currentOrder.indexOf(it.id);
            currentOrder.splice(insertBefore ? toIdx : toIdx + 1, 0, dragSrcId);
            cfg.organizeOrder = currentOrder;
            saveSettings();
            try { applyNavOrder(); } catch(e) {}
            renderList();
            dragSrcId = null;
          });

          return row;
        }

        // Render all items in current order (flat, no grouping by separator)
        const container = document.createElement('div'); container.style.display = 'flex'; container.style.flexDirection = 'column';
        for (const id of order) {
          const it = map[id]; if (!it) continue;
          container.appendChild(makeRow(it));
        }
        list.appendChild(container);
      }

      renderList(); dialog.appendChild(list);
      const row = document.createElement('div'); row.style.display = 'flex'; row.style.justifyContent = 'center'; row.style.marginTop = '8px';
      const closeBtn = document.createElement('button'); closeBtn.type = 'button'; closeBtn.textContent = 'Close';
      // style like main modal action buttons
      closeBtn.style.background = '#1f7d3d'; closeBtn.style.color = '#fff'; closeBtn.style.border = '0'; closeBtn.style.padding = '8px 12px'; closeBtn.style.borderRadius = '6px'; closeBtn.classList.add('mwi-push-btn');
      const orgResetBtn = document.createElement('button'); orgResetBtn.type = 'button'; orgResetBtn.textContent = 'Reset to defaults';
      orgResetBtn.style.background = '#7f1d1d'; orgResetBtn.style.color = '#fff'; orgResetBtn.style.border = '0'; orgResetBtn.style.padding = '8px 12px'; orgResetBtn.style.borderRadius = '6px'; orgResetBtn.style.marginLeft = '8px'; orgResetBtn.classList.add('mwi-push-btn');
      orgResetBtn.addEventListener('click', () => {
        try {
          cfg.organizeOrder = DEFAULT_CFG.organizeOrder.slice ? DEFAULT_CFG.organizeOrder.slice() : [];
          cfg.hiddenElements = {};
          saveSettings();
          try { applyHideOrganize(); } catch (e) {}
          try { applyNavOrder(); } catch (e) {}
          renderList();
        } catch (e) { log('organize reset error', e); }
      });
      row.appendChild(closeBtn); row.appendChild(orgResetBtn); dialog.appendChild(row);
      function closeOrganizeModal() {
        over.classList.remove('mwi-organize-open');
        over.classList.add('mwi-organize-closing');
        setTimeout(() => { try { over.remove(); } catch (e) {} }, 200);
      }
      orgClose.addEventListener('click', () => closeOrganizeModal());
      closeBtn.addEventListener('click', () => closeOrganizeModal());
      over.appendChild(dialog);
      // clicking outside closes organize modal only
      over.addEventListener('click', (ev) => { try { if (ev.target === over) closeOrganizeModal(); } catch (e) {} });
      document.body.appendChild(over);
      requestAnimationFrame(() => requestAnimationFrame(() => over.classList.add('mwi-organize-open')));
    } catch (e) { log('openOrganizeModal error', e); }
  }

  // Chat-text helpers: recolor message text that is white
  function applyChatTextToNode(node) {
    try {
      if (!node || !(node instanceof Element)) return;
      // If this is a chat message container, mark only its text elements (exclude username span)
      const isMsgContainer = (node.matches && (node.matches('.ChatMessage_chatMessage__2wev4') || node.matches('[class*="ChatMessage_chatMessage__"]')));
      if (isMsgContainer) {
        const descendants = Array.from(node.querySelectorAll('*'));
        const parentText = (node.textContent || '').trim();
        for (const d of descendants) {
          try {
            // Skip if this element is within a username element
            if (d.closest && d.closest('[class*="CharacterName_name__"]')) continue;
            // Only consider leaf elements (no element children) to avoid marking containers
            if (d.children && d.children.length) continue;
            const txt = (d.textContent || '').trim();
            if (!txt) continue;
            // Heuristic: if the parent message text begins with this descendant followed by ':'
            // it's very likely the username; skip it.
            if (parentText.startsWith(txt + ':')) continue;
            const cs = getComputedStyle(d);
            if (cs && cs.color && cs.color.trim() === 'rgb(231, 231, 231)') d.setAttribute('data-mwi-chat-text-applied', '1');
          } catch (e) { /* ignore per-node errors */ }
        }
        return;
      }
      // Otherwise, mark the node itself if it's text-colored white and not a username
      // Skip nodes that are the username or contained within a username element
      if (node.closest && node.closest('[class*="CharacterName_name__"]')) return;
      const cs = getComputedStyle(node);
      if (!cs) return;
      if (cs.color && cs.color.trim() === 'rgb(231, 231, 231)') {
        node.setAttribute('data-mwi-chat-text-applied', '1');
      }
    } catch (e) { /* ignore */ }
  }

  function applyChatTextToAll() {
    try {
      const sel = '.ChatMessage_chatMessage__2wev4, [class*="ChatMessage_chatMessage__"]';
      const nodes = Array.from(document.querySelectorAll(sel));
      for (const n of nodes) applyChatTextToNode(n);
    } catch (e) { /* ignore */ }
  }

  function clearChatTextFromAll() {
    try {
      const nodes = Array.from(document.querySelectorAll('[data-mwi-chat-text-applied]'));
      for (const n of nodes) n.removeAttribute('data-mwi-chat-text-applied');
    } catch (e) { /* ignore */ }
  }

  function ensureChatTextObserver() {
    try {
      if (chatTextObserver) return;
      chatTextObserver = new MutationObserver((muts) => {
        try {
          for (const m of muts) {
            for (const n of Array.from(m.addedNodes || [])) {
              if (!(n instanceof Element)) continue;
              if (n.matches && (n.matches('.ChatMessage_chatMessage__2wev4') || n.querySelector('.ChatMessage_chatMessage__2wev4'))) applyChatTextToAll();
            }
          }
        } catch (e) { }
      });
      chatTextObserver.observe(document.body, { childList: true, subtree: true });
    } catch (e) { /* ignore */ }
  }

  // load persisted settings (if any)
  loadSettings();
  // If reset-on-refresh is enabled, restore defaults on startup except Dev keys
  try {
    if (cfg.resetOnRefresh) {
      try {
        const preserved = {};
        // preserve Dev keys and the reset flag itself
        for (const k of DEV_KEYS) if (k in cfg) preserved[k] = cfg[k];
        preserved.resetOnRefresh = cfg.resetOnRefresh;
        // reset all keys to DEFAULT_CFG
        for (const k of Object.keys(DEFAULT_CFG)) cfg[k] = JSON.parse(JSON.stringify(DEFAULT_CFG[k]));
        // restore preserved
        for (const k of Object.keys(preserved)) cfg[k] = preserved[k];
        // persist the reset defaults (keep resetOnRefresh enabled)
        saveSettings();
      } catch (e) { log('resetOnRefresh handling error', e); }
    }
  } catch (e) {}
  // immediately apply persisted/site colors
  try { applySiteColors(); } catch (e) {}

  // Ensure hide/organize is applied after dynamic page content loads.
  try {
    // small delayed reapply in case elements mount after initial run
    setTimeout(() => { try { applyHideOrganize(); } catch (e) {} }, 600);
    // also wait for the navigation container and reapply + observe for changes
    waitFor(() => document.querySelector('.NavigationBar_navigationLinks__1XSSb') || document.querySelector('.NavigationBar_navigationLinks'), 10000, 200)
      .then((nav) => {
        try {
          if (nav) applyHideOrganize();
          // debounce helper
          let to = null;
          const obs = new MutationObserver((muts) => {
            try {
              if (to) clearTimeout(to);
              to = setTimeout(() => { try { applyHideOrganize(); } catch (e) {} }, 120);
            } catch (e) {}
          });
          try { obs.observe(document.body, { childList: true, subtree: true }); } catch (e) {}
        } catch (e) {}
      }).catch(() => {});
  } catch (e) {}

  function log(...args) { if (cfg.debug) console.log('[MWI-HL]', ...args); }

  function waitFor(conditionFn, timeout = 10000, interval = 200) {
    return new Promise((resolve, reject) => {
      const start = Date.now();
      (function check() {
        try {
          const v = conditionFn();
          if (v) return resolve(v);
        } catch (e) {}
        if (Date.now() - start >= timeout) return resolve(null);
        setTimeout(check, interval);
      })();
    });
  }

  // Attempt to discover a mapping of item id/name -> color by scanning globals.
  function discoverCollectionColors() {
    const hridMap = new Map();
    const nameMap = new Map();
    const hridNameMap = new Map();
    const nameToHrid = new Map();
    // Use init payload if available 窶・handle Map-like or plain object
    try {
      const util = window.localStorageUtil;
      if (util && typeof util.getInitClientData === 'function') {
        const init = util.getInitClientData();
        const idm = init && init.itemDetailMap;
        if (idm) {
          const entries = (typeof idm.forEach === 'function' && typeof idm.entries === 'function') ? Array.from(idm.entries()) : Object.entries(idm);
          for (const [k, v] of entries) {
            try {
              const key = String(k);
              if (v && v.name) {
                const name = String(v.name).toLowerCase();
                nameToHrid.set(name, key);
                hridNameMap.set(key, String(v.name));
              }
              const color = v && (v.collectionColor || v.color || v.hex);
              if (color) {
                hridMap.set(key, color);
                if (v && v.name) nameMap.set(String(v.name).toLowerCase(), color);
              }
            } catch (e) {}
          }
        }
      }
    } catch (e) { log('discover error', e); }
    return { hridMap, nameMap, hridNameMap, nameToHrid };
  }

  // Build a best-effort key extractor for inventory elements
  function elementItemKey(el) {
    if (!el) return null;
    // common attributes
    const attrs = ['data-item-id', 'data-id', 'data-item', 'data-itemid'];
    for (const a of attrs) {
      const v = el.getAttribute && el.getAttribute(a);
      if (v) return String(v);
    }
    // dataset
    for (const k of Object.keys(el.dataset || {})) {
      if (k.toLowerCase().includes('item')) return String(el.dataset[k]);
    }
    // image filename
    const img = el.querySelector && el.querySelector('img');
    if (img) {
      if (img.alt) return String(img.alt).trim();
      if (img.src) {
        const parts = img.src.split('/');
        const last = parts[parts.length - 1];
        return last.split('.')[0];
      }
    }
    // svg <use href="#sprite"> pattern (collection icons)
    try {
      const use = el.querySelector && (el.querySelector('use') || el.querySelector('svg use'));
      if (use) {
        // use.href may be an SVGAnimatedString
        const href = use.getAttribute('href') || use.getAttribute('xlink:href') || (use.href && use.href.baseVal);
        if (href) {
          const frag = String(href).split('#').slice(-1)[0];
          if (frag) return String(frag);
        }
      }
      // ancestor svg
      const an = el.closest && el.closest('svg');
      if (an) {
        const use2 = an.querySelector('use');
        if (use2) {
          const href2 = use2.getAttribute('href') || use2.getAttribute('xlink:href') || (use2.href && use2.href.baseVal);
          if (href2) {
            const frag2 = String(href2).split('#').slice(-1)[0];
            if (frag2) return String(frag2);
          }
        }
      }
    } catch (e) {}
    // title or text fallback
    if (el.title) return String(el.title).trim();
    const txt = el.textContent && el.textContent.trim();
    if (txt) return txt.split('\n')[0].trim();
    return null;
  }

  function highlightElement(el, color, itemAlpha) {
    if (!el || !color) return;
    // stronger visual: outline (higher specificity) plus inset box-shadow
    try {
      // Only style small, item-like elements to avoid tinting the whole inventory
      if (!isSmallNode(el)) return;
      // use setProperty with important to override game styles
      // thinner border like collection log, with a soft outer glow
      const outlineWidth = (cfg.outlineWidth !== undefined) ? cfg.outlineWidth : 2;
      const glowAlpha = (itemAlpha !== undefined && !isNaN(Number(itemAlpha))) ? Number(itemAlpha) : ((cfg.glowAlpha !== undefined) ? cfg.glowAlpha : 0.08);
      // inner curved border (inset) + outer glow; and subtle background tint
      const innerW = (cfg.innerBorderWidth !== undefined) ? cfg.innerBorderWidth : outlineWidth;
      const bg = colorToRGBA(color, (cfg.bgAlpha !== undefined) ? cfg.bgAlpha : 0.12);
      if (bg) el.style.setProperty('background-color', bg, 'important');
      const glow = colorToRGBA(color, glowAlpha) || 'rgba(0,0,0,0)';
      const spread = (cfg.glowSpread !== undefined) ? cfg.glowSpread : Math.max(6, outlineWidth*2);
      const blur = (cfg.glowBlur !== undefined) ? cfg.glowBlur : Math.max(4, Math.floor(spread/2));
      // compose inset inner border and a soft outer halo (blur + spread)
      const innerPart = (cfg.showInnerBorder === false) ? '' : `inset 0 0 0 ${innerW}px ${color}, `;
      const boxShadow = `${innerPart}0 0 ${blur}px ${spread}px ${glow}`;
      el.style.setProperty('box-shadow', boxShadow, 'important');
      if (!el.style.borderRadius) el.style.borderRadius = '8px';
    } catch (e) {
      // style assignment may fail on SVG or read-only nodes
    }
  }

  // Parse quantity strings like '28M', '3.2k', '410', etc.
  function parseQuantity(str) {
    if (!str) return 0;
    const s = String(str).trim().toUpperCase().replace(/,/g,'');
    const m = s.match(/^([0-9]*\.?[0-9]+)\s*([KMBT])?$/i);
    if (!m) return parseInt(s) || 0;
    let v = parseFloat(m[1]);
    const suf = m[2] || '';
    if (suf === 'K') v *= 1e3;
    if (suf === 'M') v *= 1e6;
    if (suf === 'B') v *= 1e9;
    if (suf === 'T') v *= 1e12;
    return Math.floor(v);
  }

  // Default quantity tiers (min inclusive). You can edit these in cfg if desired.
  const defaultQuantityTiers = [
    { min: 100000, color: '#9b59b6' },
    { min: 10000, color: '#d0333d' },
    { min: 1000, color: '#a272e4' },
    { min: 100, color: '#1d8ce0' },
    { min: 10, color: '#259c85' },
    { min: 1, color: '#7f8c8d' },
    { min: 0, color: '#7f8c8d' }
  ];

  function quantityToColor(q) {
    // Prefer collection-style tiers if provided, then cfg.quantityTiers, then defaults
    const tiers = cfg.collectionQuantityTiers || cfg.quantityTiers || defaultQuantityTiers;
    for (const t of tiers) {
      if (q >= t.min) {
        return { color: t.color, alpha: (t.alpha !== undefined ? t.alpha : 1) };
      }
    }
    return null;
  }

  // Convert color string (#rgb, #rrggbb, rgb(...), rgba(...)) to rgba(...) with given alpha
  function colorToRGBA(c, alpha) {
    try {
      if (!c) return null;
      c = String(c).trim();
      if (c.startsWith('rgba')) {
        // replace alpha
        const parts = c.replace(/rgba\(|\)/g, '').split(',').map(s=>s.trim());
        return `rgba(${parts[0]}, ${parts[1]}, ${parts[2]}, ${alpha})`;
      }
      if (c.startsWith('rgb')) {
        const parts = c.replace(/rgb\(|\)/g, '').split(',').map(s=>s.trim());
        return `rgba(${parts[0]}, ${parts[1]}, ${parts[2]}, ${alpha})`;
      }
      // hex
      const hex = c.replace('#','');
      if (hex.length === 3) {
        const r = parseInt(hex[0]+hex[0],16);
        const g = parseInt(hex[1]+hex[1],16);
        const b = parseInt(hex[2]+hex[2],16);
        return `rgba(${r}, ${g}, ${b}, ${alpha})`;
      }
      if (hex.length === 6) {
        const r = parseInt(hex.slice(0,2),16);
        const g = parseInt(hex.slice(2,4),16);
        const b = parseInt(hex.slice(4,6),16);
        return `rgba(${r}, ${g}, ${b}, ${alpha})`;
      }
      return null;
    } catch (e) { return null; }
  }

  // Reusable small-node check (used in multiple places)
  function isSmallNode(node) {
    try {
      if (!node || !node.getBoundingClientRect) return false;
      const r = node.getBoundingClientRect();
      if (!r || !r.width || !r.height) return false;
      return (r.width <= 240 && r.height <= 240);
    } catch (e) { return false; }
  }

  // find a sensible container to apply highlight to (avoid tiny count elements)
  function findHighlightTarget(el) {
    if (!el) return null;
    // Prefer the Item wrapper when available (e.g. Item_item__* / Item_clickable__*)
    try {
      const itemAncestor = el.closest && (el.closest('[class*="Item_item"]') || el.closest('[class*="Item_clickable"]') || el.closest('[class*="Item_"]'));
      if (itemAncestor && isSmallNode(itemAncestor)) return itemAncestor;
    } catch (e) {}
    // Prefer an explicit icon/container around the svg/img. Try several heuristics and prefer
    // small wrappers so we style only the tile/icon, not entire rows.
    try {
      // If the element itself is an icon wrapper (contains svg or img) and is small, use it
      if (el.querySelector && (el.querySelector('use') || el.querySelector('svg') || el.querySelector('img'))) {
        if (isSmallNode(el)) return el;
      }

      // look for nearest ancestor that directly wraps an svg/img
      const iconAncestor = el.closest && (el.closest('[class*="icon"]') || el.closest('[class*="Icon"]') || el.closest('[class*="IconContainer"]') || el.closest('[class*="Collection_"]'));
      if (iconAncestor && isSmallNode(iconAncestor)) return iconAncestor;

      // nearest svg ancestor
      const svgan = el.closest && el.closest('svg');
      if (svgan) {
        const parent = svgan.parentElement;
        if (parent && isSmallNode(parent)) return parent;
        if (isSmallNode(svgan)) return svgan;
      }

      // if element has a direct sibling or child img/svg, prefer that small sibling
      try {
        const p = el.parentElement;
        if (p) {
          const imgs = p.querySelectorAll && p.querySelectorAll('img, svg, use');
          for (const candidate of imgs || []) {
            const wrap = candidate.closest && candidate.closest('*') || candidate.parentElement;
            if (wrap && isSmallNode(wrap)) return wrap;
          }
        }
      } catch (e) {}

      // fallback: parent that is small enough
      if (el.parentElement && isSmallNode(el.parentElement)) return el.parentElement;
      if (isSmallNode(el)) return el;
    } catch (e) {}
    // nothing appropriate 窶・avoid styling large containers
    return null;
  }

  // Look for a nearby SVG/icon element associated with this element (useful when the visible node is just the count)
  function findAssociatedIcon(el) {
    if (!el) return null;
    try {
      // check siblings first
      const p = el.parentElement;
      if (p) {
        // look for svg/use inside parent
        const u = p.querySelector('use') || p.querySelector('svg');
        if (u) {
          // return the element wrapping the svg (small target)
          const wrap = u.closest && u.closest('.Collection_iconContainer__2cD7o') || u.closest('svg') || u.closest('*');
          if (wrap && isSmallNode(wrap)) return wrap;
        }
        // look at previous/next element siblings
        const prev = el.previousElementSibling;
        const next = el.nextElementSibling;
        for (const s of [prev, next]) {
          if (!s) continue;
          if (s.querySelector && s.querySelector('use')) return s;
          if (s.tagName && s.tagName.toLowerCase() === 'svg') return s;
        }
      }
      // search within element for use
      if (el.querySelector && el.querySelector('use')) return el;
    } catch (e) {}
    return null;
  }

  // Find the count element near an item (target the class the user reported)
  function findCountElement(el) {
    if (!el) return null;
    const cls = '.Item_count__1HVvv';
    try {
      // if the element itself is the count
      if (el.classList && el.classList.contains && el.classList.contains('Item_count__1HVvv')) return el;
      // descendant
      if (el.querySelector) {
        const d = el.querySelector(cls);
        if (d) return d;
      }
      // check up to 3 ancestor levels for a count
      let p = el.parentElement;
      for (let i = 0; i < 3 && p; i++, p = p.parentElement) {
        try {
          const found = p.querySelector && p.querySelector(cls);
          if (found) return found;
        } catch (e) {}
      }
      // check slot-like container
      const slot = el.closest && (el.closest('.slot') || el.closest('.inventory-slot') || el.closest('[class*="Item_"]') || el.closest('[class*="Inventory_"]'));
      if (slot) {
        const s = slot.querySelector && slot.querySelector(cls);
        if (s) return s;
      }
      // check siblings via parent
      const parent = el.parentElement;
      if (parent) {
        const sib = parent.querySelector && parent.querySelector(cls);
        if (sib) return sib;
      }
    } catch (e) {}
    return null;
  }

  function highlightInventory(maps) {
    const hridMap = maps && maps.hridMap ? maps.hridMap : new Map();
    const nameMap = maps && maps.nameMap ? maps.nameMap : new Map();
    const hridNameMap = maps && maps.hridNameMap ? maps.hridNameMap : new Map();
    const nameToHrid = maps && maps.nameToHrid ? maps.nameToHrid : new Map();
    // prepare name keys for substring matching (longer names first)
    const nameKeys = Array.from(nameMap.keys()).sort((a,b)=>b.length - a.length);

    // Debug: report map sizes and a small sample
    log('highlightInventory 窶・hridMap size:', hridMap.size, 'nameMap size:', nameMap.size, 'hridNameMap size:', hridNameMap.size, 'nameToHrid size:', nameToHrid.size);
    if (cfg.debug && nameMap.size) {
      const sample = Array.from(nameMap.entries()).slice(0,5).map(e => e[0] + '->' + e[1]);
      log('nameMap sample:', sample);
    }

    // Evaluate which coloring strategy to use
    if (cfg.colorMode === 'None') {
      log('highlightInventory skipped 窶・colorMode: None');
      return;
    }
    const useQuantity = cfg.colorMode === 'Quantity';
    const useAll = cfg.colorMode === 'All';

    // Collect likely item candidates. Keep set small and focused to avoid scanning the whole DOM.
    const els = new Set();
    // Restrict to inventory panels matching the game's Inventory wrapper to avoid site-wide effects
    const inventoryRoots = Array.from(document.querySelectorAll('.Inventory_inventory__17CH2'));
    if (inventoryRoots.length) {
      for (const root of inventoryRoots) {
        try {
          const selList = ['[data-item-id], [data-id], [data-item], [data-itemid]'].concat(cfg.inventorySelectors || []);
          for (const sel of selList) {
            const nl = root.querySelectorAll(sel);
            for (const n of nl) els.add(n);
          }
          const icons = root.querySelectorAll('.Collection_iconContainer__2cD7o, [class*="icon"], [class*="Icon"], [class*="Collection_"]');
          for (const n of icons) if (isSmallNode(n)) els.add(n);
          const imgs = root.querySelectorAll('img, svg');
          for (const im of imgs) {
            if (isSmallNode(im)) { els.add(im); continue; }
            const p = im.closest && im.closest('*');
            if (p && isSmallNode(p)) els.add(p);
          }
        } catch (e) { /* ignore individual root errors */ }
      }
    } else {
      const globalSel = ['[data-item-id], [data-id], [data-item], [data-itemid]'].concat(cfg.inventorySelectors || []);
      try {
        for (const sel of globalSel) {
          const nl = document.querySelectorAll(sel);
          for (const n of nl) els.add(n);
        }
        const icons = document.querySelectorAll('.Collection_iconContainer__2cD7o, [class*="icon"], [class*="Icon"], [class*="Collection_"]');
        for (const n of icons) if (isSmallNode(n)) els.add(n);
        const imgs = document.querySelectorAll('img, svg');
        for (const im of imgs) {
          if (isSmallNode(im)) { els.add(im); continue; }
          const p = im.closest && im.closest('*');
          if (p && isSmallNode(p)) els.add(p);
        }
      } catch (e) { /* ignore fallback selection errors */ }
    }

    // Cap number of elements processed to avoid long synchronous loops
    const elArray = Array.from(els).slice(0, 1200);
    if (cfg.debug) log('highlightInventory candidates:', elArray.length);
    let applied = 0;
    for (const el of elArray) {
      let colorInfo = null; // { color: '#rrggbb' , alpha: 0-1 }
      // Category mode: try to infer a category and map to configured colors
      // All mode: force single color for everything
      if (!colorInfo && useAll) {
        try {
          const col = cfg.allColor || '#ffffff';
          const a = (cfg.allAlpha !== undefined ? cfg.allAlpha : 1);
          colorInfo = { color: col, alpha: a };
        } catch (e) {}
      }

      // Quantity (or fallback) mode: existing quantity/name matching logic
      if (!colorInfo && useQuantity) {
        try {
          const countEl = findCountElement(el);
          if (countEl && countEl.textContent) {
            const q = parseQuantity(countEl.textContent);
            const qc = quantityToColor(q);
            if (qc) {
              colorInfo = { color: qc.color, alpha: (qc.alpha !== undefined ? qc.alpha : 1) };
              if (cfg.debug) log('Found count', countEl.textContent.trim(), '->', q, 'colorInfo', colorInfo);
            }
          }
        } catch (e) {}

        if (!colorInfo) {
          const key = elementItemKey(el);
          let resolvedHrid = null;
          if (key) {
            const tmp = hridMap.get(String(key)) || hridMap.get(String(parseInt(key) || '')) || nameMap.get(String(key).toLowerCase());
            if (tmp) colorInfo = { color: tmp, alpha: 1 };
            if (!colorInfo) {
              const lk = String(key).toLowerCase();
              if (nameToHrid.has(lk)) resolvedHrid = nameToHrid.get(lk);
            }
          }
          if (!colorInfo) {
            const txt = (el.textContent || '').toLowerCase();
            if (txt) {
              for (const n of nameKeys) {
                if (txt.indexOf(n) !== -1) { const tmp = nameMap.get(n); if (tmp) colorInfo = { color: tmp, alpha: 1 }; break; }
              }
            }
          }
          if (!colorInfo && !resolvedHrid) {
            const txt = (el.textContent || '').toLowerCase();
            if (txt) {
              for (const n of nameKeys) {
                if (txt.indexOf(n) !== -1) { const tmp = nameMap.get(n); if (tmp) colorInfo = { color: tmp, alpha: 1 }; resolvedHrid = nameToHrid.get(n); break; }
              }
            }
          }
          if (!colorInfo && resolvedHrid && hridNameMap.has(resolvedHrid)) {
            const nm = String(hridNameMap.get(resolvedHrid)).toLowerCase();
            const tmp = nameMap.get(nm) || null;
            if (tmp) colorInfo = { color: tmp, alpha: 1 };
          }
        }
      }
      if (colorInfo) {
        let target = null;
        try { target = findHighlightTarget(el) || findAssociatedIcon(el); } catch (e) { target = null; }
        if (target) { highlightElement(target, colorInfo.color, colorInfo.alpha); applied++; }
        }
      }

    // If nothing was highlighted, try a broader text-search fallback inside likely inventory containers
    if (!applied && nameKeys.length) {
      const roots = inventoryRoots.length ? inventoryRoots.slice() : [];
      if (!roots.length) {
        document.querySelectorAll('[id^="mwi-inventory-"]').forEach(e => roots.push(e));
        document.querySelectorAll('.inventory, .panel-content, .list, .items-list').forEach(e => roots.push(e));
      }
      // dedupe
      const uniqRoots = Array.from(new Set(roots));
      for (const root of uniqRoots) {
        if (!root) continue;
        const children = Array.from(root.querySelectorAll('*')).slice(0,1000);
        for (const el of children) {
          try {
            if (!el.textContent) continue;
            const txt = el.textContent.toLowerCase();
            for (const n of nameKeys) {
              if (txt.indexOf(n) !== -1) {
                const color = nameMap.get(n);
                if (color) { const target = findHighlightTarget(el) || el; highlightElement(target, color, 1); applied++; }
                break;
              }
            }
          } catch (e) {}
        }
      }
    }
    log('highlightInventory applied highlights:', applied);
  }

    // --- Settings UI (button + modal) ---
    function injectStyles() {
      const css = `
          #mwi-settings-btn { display:inline-flex; align-items:center; justify-content:center; min-width:36px; height:36px; padding:6px 10px; border-radius:6px; background:#222; color:#fff; border:1px solid rgba(255,255,255,0.06); cursor:pointer; margin-left:8px; transition: filter 120ms ease; }
          #mwi-settings-btn:hover { filter: brightness(1.25); }
          #mwi-settings-btn:active { transform: translateY(1px) scale(0.96); filter: brightness(0.85); }
          /* Frosted button style (default) */
          #mwi-settings-btn.mwi-btn-frosted { background: linear-gradient(90deg, rgba(255,68,204,0.18), rgba(68,170,255,0.18)); border: 1px solid rgba(255,255,255,0.15); color: transparent; background-clip: text; -webkit-background-clip: text; -webkit-text-fill-color: transparent; position: relative; }
          #mwi-settings-btn.mwi-btn-frosted::before { content:''; position:absolute; inset:0; border-radius:inherit; background: linear-gradient(90deg, rgba(255,68,204,0.18), rgba(68,170,255,0.18)); z-index:0; }
          #mwi-settings-btn.mwi-btn-frosted span { position:relative; z-index:1; background: linear-gradient(90deg, #ff44cc, #44aaff); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; }
          .mwi-push-btn { transition: filter 120ms ease !important; cursor: pointer; }
          .mwi-push-btn:hover { filter: brightness(1.25) !important; }
          .mwi-push-btn:active { transform: translateY(1px) scale(0.96) !important; filter: brightness(0.85) !important; }
          #mwi-settings-overlay { position:fixed; inset:0; background:rgba(0,0,0,0.45); display:flex; align-items:center; justify-content:center; z-index:9999999; }
          #mwi-settings-dialog { background: rgba(15,23,32,0.25); backdrop-filter: blur(18px) saturate(1.4); -webkit-backdrop-filter: blur(18px) saturate(1.4); border: 1px solid rgba(255,255,255,0.08); color:#e6eef8; padding:16px; border-radius:12px; width:520px; max-width:92%; box-shadow:0 8px 32px rgba(0,0,0,0.7); display:flex; flex-direction:column; position:relative; overflow:hidden; }
          #mwi-settings-dialog::before { content:''; position:absolute; inset:0; border-radius:inherit; pointer-events:none; background: radial-gradient(400px circle at var(--glow-x,50%) var(--glow-y,50%), rgba(255,68,204,0.13) 0%, transparent 70%); transition: background 0.1s ease; z-index:0; }
          #mwi-settings-dialog > * { position:relative; z-index:1; }
          /* Solid UI style overrides */
          #mwi-settings-dialog.mwi-ui-solid { background: #0f1720; backdrop-filter: none; -webkit-backdrop-filter: none; border: 1px solid rgba(255,255,255,0.12); }
          #mwi-settings-dialog.mwi-ui-solid::before { display: none; }
          #mwi-search-wrap { background: transparent; }
          #mwi-settings-dialog.mwi-ui-solid #mwi-search-wrap { background: #0f1720; }
          /* Dialog pop animations - more noticeable pop with overshoot */
          @keyframes mwi-pop-in {
            0% { transform: translateY(-20px) scale(0.9); opacity: 0; }
            100% { transform: translateY(0) scale(1); opacity: 1; }
          }
          @keyframes mwi-pop-out {
            0% { transform: translateY(0) scale(1); opacity: 1; }
            100% { transform: translateY(-20px) scale(0.9); opacity: 0; }
          }
          #mwi-settings-dialog { transform-origin: center top; /* start slightly up and smaller; transition to visible */ transform: translateY(-20px) scale(0.9); opacity: 0; transition: transform 200ms ease, opacity 200ms ease; }
          .mwi-dialog-open #mwi-settings-dialog { transform: translateY(0) scale(1); opacity: 1; }
          .mwi-dialog-closing #mwi-settings-dialog { animation: mwi-pop-out 200ms ease both; }
          /* Ensure the settings modal is not affected by site button/accent overrides */
          #mwi-settings-dialog, #mwi-settings-dialog * { --mwi-button-bg: unset !important; --mwi-accent: unset !important; --mwi-progress-bar: unset !important; --mwi-skill-actions: unset !important; --mwi-combat: unset !important; }
          #mwi-settings-dialog button, #mwi-settings-dialog .btn, #mwi-settings-dialog [class*="MuiButton"], #mwi-settings-dialog [class*="Button_"] {
            /* Don't override explicit inline backgrounds so modal buttons keep their intended colors */
            background-image: none !important; border-color: initial !important; box-shadow: initial !important; color: inherit !important;
          }
          #mwi-settings-dialog button::before, #mwi-settings-dialog button::after, #mwi-settings-dialog [class*="MuiButton"]::before, #mwi-settings-dialog [class*="MuiButton"]::after { background-image: none !important; }
          #mwi-settings-dialog h3 { margin:0 0 8px 0; font-size:16px; }
          #mwi-settings-close { position:absolute; top:10px; right:10px; cursor:pointer; background:transparent; border:0; color:#fff; font-size:16px; z-index:10000002; }
          /* Share modal (Import/Export) */
          #mwi-share-modal-overlay { position: fixed; inset: 0; display:flex; align-items:center; justify-content:center; background: rgba(0,0,0,0.6); z-index:10000020; }
          .mwi-share-modal { background:#0f1720; color:#e6eef8; padding:12px; border-radius:8px; width:560px; max-width:92%; box-shadow:0 8px 24px rgba(0,0,0,0.6); transform-origin: center top; transform: translateY(-20px) scale(0.9); opacity: 0; transition: transform 200ms ease, opacity 200ms ease; }
          .mwi-share-open .mwi-share-modal { transform: translateY(0) scale(1); opacity: 1; }
          .mwi-share-closing .mwi-share-modal { animation: mwi-pop-out 200ms ease both; }
          .mwi-share-modal textarea { width:100%; height:140px; resize:vertical; margin-bottom:8px; background:#071018; color:#e6eef8; border:1px solid rgba(255,255,255,0.06); border-radius:6px; padding:8px; outline:none; }
          .mwi-share-modal button { margin-left:6px; padding:6px 10px; border-radius:6px; background:#222; color:#fff; border:1px solid rgba(255,255,255,0.06); cursor:pointer; }
          #mwi-settings-content { overflow-y:auto; max-height: calc(80vh - 160px); padding-right:16px; scrollbar-gutter: stable; }
          .mwi-settings-notice { font-size:12px; color:#9fb7d7; margin:6px 0 8px 0; }
          .mwi-settings-row { margin:8px 0; display:flex; align-items:center; justify-content:space-between; }
          .mwi-settings-section { margin-top:12px; padding-top:8px; border-top:0; }
          .mwi-settings-section h4 { margin:0 0 8px 0; font-size:15px; color:#bcd3ea; }
          #mwi-settings-dialog h4 { text-decoration: underline; }
          /* sitewide customizable colors (set via JS variables) */
              body { color: var(--mwi-text, inherit) !important; }
              .GamePage_headerPanel__1T_cA { background-color: var(--mwi-header-bg, unset) !important; }
          :root.mwi-header-grad-active [class*="Header_header__"] { background: var(--mwi-header-grad) !important; }
          .panel, .panel-content, .Inventory_inventory__17CH2, .EquipmentPanel_equipmentPanel__29pDG, .AbilitiesPanel_abilitiesPanel__2kLc9, .HousePanel_housePanel__lpphK, .LoadoutsPanel_loadoutsPanel__Gc5VA, [class*="Inventory_inventory__"], [class*="EquipmentPanel_equipmentPanel__"], [class*="AbilitiesPanel_abilitiesPanel__"], [class*="HousePanel_housePanel__"], [class*="LoadoutsPanel_loadoutsPanel__"] { background-color: var(--mwi-panel-bg, unset) !important; }
          :root.mwi-tabs-bg-active body > :not(#mwi-settings-overlay) .MuiTabs-root { background-color: var(--mwi-tabs-bg) !important; }
          .GamePage_navPanel__3wbAU { background-color: var(--mwi-side-panel-bg, unset) !important; }
          /* Swap left/right panels */
          :root.mwi-swap-panels [class*="GamePage_gamePanel__"] { flex-direction: row-reverse !important; }
          :root.mwi-swap-panels [class*="GamePage_contentPanel__"] { flex-direction: row-reverse !important; }
          /* Move chat to top */
          :root.mwi-chat-top [class*="GamePage_middlePanel__"] { flex-direction: column-reverse !important; }
          /* Move header to bottom */
          :root.mwi-header-bottom [class*="GamePage_gamePage__"] { flex-direction: column-reverse !important; }
          .MainPanel_subPanelContainer__1i-H9 { background-color: var(--mwi-subpanel-bg, unset) !important; }
           .Chat_chat__3DQkj { background-color: var(--mwi-chat-bg, unset) !important; }
           /* Apply button background/color only when user explicitly sets them. These
             rules use helper classes on :root toggled by applySiteColors() so the
             site's native styles are preserved until the user overrides them. */
          /* Apply background, border, and remove shadows/gradients so custom button
             color appears even if the site uses gradients or pseudo-elements. Include
             Material-UI (Mui*) classes used on the site. */
          /* Apply button backgrounds only to specific MUI Tab buttons (page content only) */
          :root.mwi-button-bg-active body > :not(#mwi-settings-overlay) .MuiButtonBase-root.MuiTab-root[class*="MuiTab-textColorPrimary"] {
            background: var(--mwi-button-bg) !important;
            background-color: var(--mwi-button-bg) !important;
            background-image: none !important;
            border-color: var(--mwi-button-bg) !important;
            box-shadow: none !important;
            color: inherit !important;
          }
          /* Clear pseudo-element overlays only for those specific tab buttons */
          :root.mwi-button-bg-active body > :not(#mwi-settings-overlay) .MuiButtonBase-root.MuiTab-root[class*="MuiTab-textColorPrimary"]::before,
          :root.mwi-button-bg-active body > :not(#mwi-settings-overlay) .MuiButtonBase-root.MuiTab-root[class*="MuiTab-textColorPrimary"]::after {
            background-image: none !important;
            background: transparent !important;
            box-shadow: none !important;
            border: 0 !important;
          }
          /* Ensure MUI inner label elements inherit accent color when set */
          /* Accent color applied only to page content (exclude settings overlay).
             Restrict button/text accent to the specific Badge class so general
             buttons and tabs are not recolored by the 'Text Color' setting. */
          :root.mwi-accent-active body > :not(#mwi-settings-overlay) a:not([class*="Inventory_label"]), :root.mwi-accent-active body > :not(#mwi-settings-overlay) button:not(.Inventory_categoryButton__35s1x):not([class*="Inventory_label"]),
          :root.mwi-accent-active body > :not(#mwi-settings-overlay) .MuiBadge-root.TabsComponent_badge__1Du26.css-1rzb3uu {
            color: var(--mwi-accent) !important;
          }
          /* inactive inputs: visual hint when a color setting is not set */
          .mwi-inactive { filter: grayscale(80%) opacity(.55); }
          .mwi-range-disabled { opacity: .55; }
          /* Colors editor subsections */
          .mwi-colors-subsection { margin-top:8px; padding-top:6px; border-top:1px solid rgba(255,255,255,0.10); }
          .mwi-colors-subsection h5 { margin:6px 0; font-size:12px; color:#e6f4ff; }
          /* Large separator specifically above Site Colors */
          #mwi-section-site-colors { border-top:2px solid rgba(255,255,255,0.12); }
          #mwi-section-animations { border-top:2px solid rgba(255,255,255,0.12); }
          .mwi-anim-toggle-row { display:flex; align-items:center; gap:8px; margin:8px 0 4px; }
          .mwi-anim-toggle-row label { color:#c8dff5; font-size:12px; cursor:pointer; user-select:none; }
          .mwi-anim-toggle-row input[type=checkbox] { width:14px; height:14px; cursor:pointer; accent-color:#44aaff; }
          .mwi-anim-sub { margin-top:8px; padding-top:6px; border-top:none; }
          /* Large separator specifically above Inventory */
          #mwi-section-inventory { border-top:2px solid rgba(255,255,255,0.12); }
          /* Large separator above Customizer section */
          #mwi-section-customizer { border-top:none; }
          /* sub-sections inside Customizer */
          .mwi-customizer-sub { margin-top:8px; padding-top:6px; border-top:1px solid rgba(255,255,255,0.10); }
          .mwi-customizer-sub h5 { margin:4px 0 6px 0; font-size:12px; background:linear-gradient(90deg,#44aaff,#ff44cc); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; }
          /* Large separator specifically above Dev section */
          #mwi-section-dev { border-top:2px solid rgba(255,255,255,0.12); }
          /* Organize modal */
          #mwi-organize-dialog { transform-origin: center top; transform: translateY(-20px) scale(0.9); opacity: 0; transition: transform 200ms ease, opacity 200ms ease; }
          .mwi-organize-open #mwi-organize-dialog { transform: translateY(0) scale(1); opacity: 1; }
          .mwi-organize-closing #mwi-organize-dialog { animation: mwi-pop-out 200ms ease both; }
          /* Organize modal rows */
          .mwi-org-row { display:flex; align-items:center; padding:6px 8px; border:1px solid rgba(255,255,255,0.04); border-radius:6px; margin-bottom:4px; background:transparent; gap:0; }
          .mwi-org-row-handle { flex:0 0 24px; display:flex; align-items:center; justify-content:center; }
          .mwi-org-row-icon { flex:0 0 28px; display:flex; align-items:center; justify-content:center; }
          .mwi-org-row-label { flex:1 1 0; font-size:14px; padding-left:4px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
          .mwi-org-row-right { flex:0 0 auto; display:flex; align-items:center; gap:6px; margin-left:8px; }
          .mwi-org-separator { height:8px; margin:8px 0; border-top:1px solid rgba(255,255,255,0.06); }
          .mwi-org-list { max-height: 56vh; overflow:auto; padding:6px; }
          .mwi-org-row.dragging { opacity:0.4; }
          .mwi-org-row.drag-over-top { border-top: 2px solid #4caaff !important; }
          .mwi-org-row.drag-over-bottom { border-bottom: 2px solid #4caaff !important; }
          .mwi-drag-handle { display:flex; align-items:center; color:rgba(255,255,255,0.35); font-size:18px; line-height:1; margin-right:8px; cursor:grab; flex-shrink:0; user-select:none; padding:0 2px; }
          .mwi-drag-handle:hover { color:rgba(255,255,255,0.7); }
          /* Skill Actions: applied only when user enables it via settings */
          /* Skill Actions: applied only when user enables it via settings (page content only) */
          :root.mwi-skill-actions-active body > :not(#mwi-settings-overlay) .SkillAction_skillAction__1esCp,
          :root.mwi-skill-actions-active body > :not(#mwi-settings-overlay) [class*="SkillAction_skillAction__"] {
            background-color: var(--mwi-skill-actions) !important;
            background-image: none !important;
            box-shadow: none !important;
            color: inherit !important;
          }
          :root.mwi-skill-actions-active .SkillAction_skillAction__1esCp::before,
          :root.mwi-skill-actions-active .SkillAction_skillAction__1esCp::after,
          :root.mwi-skill-actions-active [class*="SkillAction_skillAction__"]::before,
          :root.mwi-skill-actions-active [class*="SkillAction_skillAction__"]::after {
            background-image: none !important; background: transparent !important; box-shadow: none !important; border:0 !important;
          }
          /* Skill XP Bar: left-side navigation experience bar coloring */
          :root.mwi-skill-xp-active body > :not(#mwi-settings-overlay) .NavigationBar_currentExperience__3GDeX,
          :root.mwi-skill-xp-active body > :not(#mwi-settings-overlay) [class*="NavigationBar_currentExperience__"] {
            background-color: var(--mwi-skill-xp) !important;
            background-image: none !important;
            box-shadow: none !important;
            color: inherit !important;
          }
          :root.mwi-skill-xp-active .NavigationBar_currentExperience__3GDeX::before,
          :root.mwi-skill-xp-active .NavigationBar_currentExperience__3GDeX::after,
          :root.mwi-skill-xp-active [class*="NavigationBar_currentExperience__"]::before,
          :root.mwi-skill-xp-active [class*="NavigationBar_currentExperience__"]::after {
            background-image: none !important; background: transparent !important; box-shadow: none !important; border:0 !important;
          }
          /* Left-side navigation label text color (NavigationBar_label) */
          :root.mwi-nav-label-active body > :not(#mwi-settings-overlay) .NavigationBar_label__1uH-y,
          :root.mwi-nav-label-active body > :not(#mwi-settings-overlay) [class*="NavigationBar_label__"] {
            color: var(--mwi-nav-label) !important;
          }
          /* Selected skill (active navigation link) */
          :root.mwi-nav-selected-active body > :not(#mwi-settings-overlay) .NavigationBar_navigationLink__3eAHA.NavigationBar_active__3R-QS,
          :root.mwi-nav-selected-active body > :not(#mwi-settings-overlay) [class*="NavigationBar_navigationLink__"][class*="NavigationBar_active__"] {
            background-color: var(--mwi-selected-skill) !important;
            background-image: none !important;
            box-shadow: none !important;
            color: inherit !important;
          }
          /* Inventory label text color (right-side panel labels) */
          :root.mwi-inventory-labels-active body > :not(#mwi-settings-overlay) .Inventory_label__XEOAx,
          :root.mwi-inventory-labels-active body > :not(#mwi-settings-overlay) [class*="Inventory_label__"] {
            color: var(--mwi-inventory-labels) !important;
          }
          /* Left-side navigation level text color */
          :root.mwi-level-active body > :not(#mwi-settings-overlay) .NavigationBar_level__3C7eR,
          :root.mwi-level-active body > :not(#mwi-settings-overlay) [class*="NavigationBar_level__"] {
            color: var(--mwi-level) !important;
          }
          /* Chat timestamp text color */
          :root.mwi-timestamp-active body > :not(#mwi-settings-overlay) .ChatMessage_timestamp__1iRZO,
          :root.mwi-timestamp-active body > :not(#mwi-settings-overlay) [class*="ChatMessage_timestamp__"] {
            color: var(--mwi-timestamp) !important;
          }
          /* Chat text override applied only to nodes we've explicitly marked
             (script checks computed color and sets data-mwi-chat-text-applied) */
          :root.mwi-chat-text-active body > :not(#mwi-settings-overlay) [data-mwi-chat-text-applied] {
            color: var(--mwi-chat-text) !important;
          }
          /* Chat system message text color */
          :root.mwi-system-message-active body > :not(#mwi-settings-overlay) .ChatMessage_systemMessage__3Jz9e,
          :root.mwi-system-message-active body > :not(#mwi-settings-overlay) [class*="ChatMessage_systemMessage__"] {
            color: var(--mwi-system-message) !important;
          }
          /* HP / MP bars (user-configurable) */
          :root.mwi-hp-active body > :not(#mwi-settings-overlay) .HitpointsBar_currentHp__5exLr {
            background-color: var(--mwi-hp) !important;
            background-image: none !important;
            box-shadow: none !important;
          }
          :root.mwi-hp-active body > :not(#mwi-settings-overlay) [class*="CombatUnit_heal__"] {
            background-color: var(--mwi-hp) !important;
            border-color: var(--mwi-hp) !important;
          }
          :root.mwi-mp-active body > :not(#mwi-settings-overlay) .ManapointsBar_currentMp__3xpqC {
            background-color: var(--mwi-mp) !important;
            background-image: none !important;
            box-shadow: none !important;
          }
          :root.mwi-mp-active body > :not(#mwi-settings-overlay) [class*="CombatUnit_mana__"] {
            background-color: var(--mwi-mp) !important;
            border-color: var(--mwi-mp) !important;
          }
          /* Hitsplat Damage / Miss (user-configurable) */
          :root.mwi-hit-dmg-active body > :not(#mwi-settings-overlay) [class*="CombatUnit_damage__"] {
            background-color: var(--mwi-hit-dmg) !important;
            border-color: var(--mwi-hit-dmg) !important;
          }
          :root.mwi-hit-miss-active body > :not(#mwi-settings-overlay) [class*="CombatUnit_miss__"] {
            background-color: var(--mwi-hit-miss) !important;
            border-color: var(--mwi-hit-miss) !important;
          }
          /* Attack bar (user-configurable) */
          :root.mwi-attack-active body > :not(#mwi-settings-overlay) .ProgressBar_innerBar__3Z_sf.ProgressBar_active__Do7AF {
            background-color: var(--mwi-attack) !important;
            background-image: none !important;
            box-shadow: none !important;
          }
          /* Bar background (user-configurable) */
          :root.mwi-bar-bg-active body > :not(#mwi-settings-overlay) [class*="HitpointsBar_hitpointsBar__"],
          :root.mwi-bar-bg-active body > :not(#mwi-settings-overlay) [class*="ManapointsBar_manapointsBar__"],
          :root.mwi-bar-bg-active body > :not(#mwi-settings-overlay) [class*="ProgressBar_progressBar__"] {
            background-color: var(--mwi-bar-bg) !important;
            background-image: none !important;
          }
          /* Consumables / Abilities */
          :root.mwi-consumables-active body > :not(#mwi-settings-overlay) .Item_item__2De2O.Item_small__1HxwE,
          :root.mwi-consumables-active body > :not(#mwi-settings-overlay) .Ability_ability__1njrh.Ability_small__1GKAt {
            background-color: var(--mwi-consumables) !important;
            background-image: none !important;
            box-shadow: none !important;
          }
          /* Custom full-page background image (scoped, opt-in). Uses --mwi-bg-image on :root when enabled. */
          :root.mwi-bg-active::before, :root.mwi-bg-preview::before {
            content: "";
            position: fixed;
            inset: 0;
            background-image: var(--mwi-bg-image, none);
              background-size: cover;
              background-position: center;
            background-repeat: no-repeat;
            opacity: var(--mwi-bg-opacity, 1);
            pointer-events: none;
            /* place the overlay above the original background but beneath typical UI elements */
            z-index: 0;
          }
          /* Force a 50% transparent overlay inside the header panel specifically.
             This creates a header-local pseudo-element that uses the same image
             but at 50% opacity and sits above the page-level overlay. */
          :root.mwi-bg-active body > :not(#mwi-settings-overlay) .GamePage_headerPanel__1T_cA,
          :root.mwi-bg-preview body > :not(#mwi-settings-overlay) .GamePage_headerPanel__1T_cA {
            position: relative; z-index: 2;
          }
          :root.mwi-bg-active body > :not(#mwi-settings-overlay) .GamePage_headerPanel__1T_cA::before,
          :root.mwi-bg-preview body > :not(#mwi-settings-overlay) .GamePage_headerPanel__1T_cA::before {
            content: "";
            position: absolute;
            inset: 0;
            background-image: var(--mwi-bg-image, none);
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
            opacity: 0.1; /* forced 10% transparency */
            pointer-events: none;
            z-index: 1; /* sits above the page overlay (z-index:0) but beneath header content (z-index:2)
                        so it only affects the header region */
          }
          /* Ensure the settings dialog remains above the custom background */
          #mwi-settings-dialog { z-index: 10000002; position: relative; }
          /* Interactables: clickable items, abilities, and house rooms on right panel */
          :root.mwi-interactables-active body > :not(#mwi-settings-overlay) .Item_item__2De2O.Item_clickable__3viV6,
          :root.mwi-interactables-active body > :not(#mwi-settings-overlay) .Ability_ability__1njrh.Ability_clickable__w9HcM,
          :root.mwi-interactables-active body > :not(#mwi-settings-overlay) .HousePanel_houseRoom__nOmpF,
          :root.mwi-interactables-active body > :not(#mwi-settings-overlay) [class*="Item_item__2De2O"][class*="Item_clickable__"],
          :root.mwi-interactables-active body > :not(#mwi-settings-overlay) [class*="Ability_ability__"][class*="Ability_clickable__"],
          :root.mwi-interactables-active body > :not(#mwi-settings-overlay) [class*="HousePanel_houseRoom__"] {
            background-color: var(--mwi-interactables) !important;
            background-image: none !important;
            box-shadow: none !important;
            color: inherit !important;
          }
          :root.mwi-interactables-active .Item_item__2De2O.Item_clickable__3viV6::before,
          :root.mwi-interactables-active .Item_item__2De2O.Item_clickable__3viV6::after,
          :root.mwi-interactables-active .Ability_ability__1njrh.Ability_clickable__w9HcM::before,
          :root.mwi-interactables-active .Ability_ability__1njrh.Ability_clickable__w9HcM::after,
          :root.mwi-interactables-active .HousePanel_houseRoom__nOmpF::before,
          :root.mwi-interactables-active .HousePanel_houseRoom__nOmpF::after,
          :root.mwi-interactables-active [class*="Item_item__2De2O"]::before,
          :root.mwi-interactables-active [class*="Item_item__2De2O"]::after,
          :root.mwi-interactables-active [class*="Ability_ability__"]::before,
          :root.mwi-interactables-active [class*="Ability_ability__"]::after,
          :root.mwi-interactables-active [class*="HousePanel_houseRoom__"]::before,
          :root.mwi-interactables-active [class*="HousePanel_houseRoom__"]::after {
            background-image: none !important; background: transparent !important; box-shadow: none !important; border:0 !important;
          }
          /* Combat: applied only when user enables it via settings */
          /* Combat: applied only when user enables it via settings (page content only) */
          :root.mwi-combat-active body > :not(#mwi-settings-overlay) .CombatUnit_combatUnit__1m3XT,
          :root.mwi-combat-active body > :not(#mwi-settings-overlay) [class*="CombatUnit_combatUnit__"] {
            background-color: var(--mwi-combat) !important;
            background-image: none !important;
            box-shadow: none !important;
            color: inherit !important;
          }
          :root.mwi-combat-active .CombatUnit_combatUnit__1m3XT::before,
          :root.mwi-combat-active .CombatUnit_combatUnit__1m3XT::after,
          :root.mwi-combat-active [class*="CombatUnit_combatUnit__"]::before,
          :root.mwi-combat-active [class*="CombatUnit_combatUnit__"]::after {
            background-image: none !important; background: transparent !important; box-shadow: none !important; border:0 !important;
          }
          /* Progress Bar: applied only when user enables it via settings (inner active bar) */
          /* Progress Bar: applied only when user enables it via settings (page content only) */
          :root.mwi-progress-bar-active body > :not(#mwi-settings-overlay) .ProgressBar_innerBar__3Z_sf.ProgressBar_active__Do7AF,
          :root.mwi-progress-bar-active body > :not(#mwi-settings-overlay) [class*="ProgressBar_innerBar__"],
          :root.mwi-progress-bar-active body > :not(#mwi-settings-overlay) [class*="ProgressBar_active__"] {
            background-color: var(--mwi-progress-bar) !important;
            background-image: none !important;
            box-shadow: none !important;
            color: inherit !important;
          }
          :root.mwi-progress-bar-active .ProgressBar_innerBar__3Z_sf.ProgressBar_active__Do7AF::before,
          :root.mwi-progress-bar-active .ProgressBar_innerBar__3Z_sf.ProgressBar_active__Do7AF::after,
          :root.mwi-progress-bar-active [class*="ProgressBar_innerBar__"]::before,
          :root.mwi-progress-bar-active [class*="ProgressBar_innerBar__"]::after,
          :root.mwi-progress-bar-active [class*="ProgressBar_active__"]::before,
          :root.mwi-progress-bar-active [class*="ProgressBar_active__"]::after {
            background-image: none !important; background: transparent !important; box-shadow: none !important; border:0 !important;
          }
          /* Strong overrides to ensure the settings modal is never restyled by
             site-wide active classes. These selectors use the ID to increase
             specificity so they win against other author !important rules. */
          :root.mwi-button-bg-active #mwi-settings-dialog button,
          :root.mwi-button-bg-active #mwi-settings-dialog [class*="Button_"],
          :root.mwi-button-bg-active #mwi-settings-dialog .btn,
          :root.mwi-button-bg-active #mwi-settings-dialog a.button,
          :root.mwi-button-bg-active #mwi-settings-dialog [role="button"],
          :root.mwi-button-bg-active #mwi-settings-dialog .MuiButton-root,
          :root.mwi-button-bg-active #mwi-settings-dialog [class*="MuiButton"] {
            /* Do not override explicit inline backgrounds; only remove gradients/overlays */
            background-image: none !important; border-color: initial !important; box-shadow: none !important; color: inherit !important;
          }
          :root.mwi-button-bg-active #mwi-settings-dialog button::before,
          :root.mwi-button-bg-active #mwi-settings-dialog button::after,
          :root.mwi-button-bg-active #mwi-settings-dialog [class*="Button_"]::before,
          :root.mwi-button-bg-active #mwi-settings-dialog [class*="Button_"]::after,
          :root.mwi-button-bg-active #mwi-settings-dialog .btn::before,
          :root.mwi-button-bg-active #mwi-settings-dialog .btn::after,
          :root.mwi-button-bg-active #mwi-settings-dialog [class*="MuiButton"]::before,
          :root.mwi-button-bg-active #mwi-settings-dialog [class*="MuiButton"]::after {
            background-image: none !important; background: transparent !important; box-shadow: none !important; border: 0 !important;
          }
          :root.mwi-accent-active #mwi-settings-dialog a, :root.mwi-accent-active #mwi-settings-dialog button,
          :root.mwi-accent-active #mwi-settings-dialog .MuiButton-root, :root.mwi-accent-active #mwi-settings-dialog .MuiTab-root,
          :root.mwi-accent-active #mwi-settings-dialog .MuiButton-label, :root.mwi-accent-active #mwi-settings-dialog .MuiTab-label {
            color: inherit !important;
          }
          :root.mwi-skill-actions-active #mwi-settings-dialog .SkillAction_skillAction__1esCp,
          :root.mwi-skill-actions-active #mwi-settings-dialog [class*="SkillAction_skillAction__"] {
            background-image: none !important; box-shadow: none !important;
          }
          :root.mwi-combat-active #mwi-settings-dialog .CombatUnit_combatUnit__1m3XT,
          :root.mwi-combat-active #mwi-settings-dialog #mwi-settings-dialog [class*="CombatUnit_combatUnit__"] {
            background-image: none !important; background: transparent !important; box-shadow: none !important; border:0 !important;
          }
          :root.mwi-progress-bar-active #mwi-settings-dialog .ProgressBar_innerBar__3Z_sf.ProgressBar_active__Do7AF,
          :root.mwi-progress-bar-active #mwi-settings-dialog [class*="ProgressBar_innerBar__"],
          :root.mwi-progress-bar-active #mwi-settings-dialog [class*="ProgressBar_active__"] {
            background-image: none !important; box-shadow: none !important; color: inherit !important;
          }
        `;
      const s = document.createElement('style'); s.textContent = css; document.head.appendChild(s);
    }

    function applyUIStyle() {
      try {
        const dialog = document.getElementById('mwi-settings-dialog');
        if (dialog) {
          if ((cfg.uiStyle || 'frosted') === 'solid') {
            dialog.classList.add('mwi-ui-solid');
          } else {
            dialog.classList.remove('mwi-ui-solid');
          }
        }
      } catch (e) {}
      try {
        const btn = document.getElementById('mwi-settings-btn');
        if (btn) {
          if ((cfg.btnStyle || 'frosted') === 'frosted') {
            btn.classList.add('mwi-btn-frosted');
            // wrap text in span for gradient text rendering
            if (!btn.querySelector('span')) {
              const sp = document.createElement('span'); sp.textContent = btn.textContent; btn.textContent = ''; btn.appendChild(sp);
            }
          } else {
            btn.classList.remove('mwi-btn-frosted');
            // unwrap span back to plain text
            const sp = btn.querySelector('span');
            if (sp) { btn.textContent = sp.textContent; }
          }
        }
      } catch (e) {}
    }

    // ── Combat animations ────────────────────────────────────────────────
    // Squash-and-stretch "kinetic impact" + colour-burst glow on hit.
    // Hooks the WS message stream to detect battle_updated damage events.

    function tryHitAnim(type, index, dmg) {
      try {
        let unitEl;
        if (type === 'monster') {
          const area = document.querySelector('.BattlePanel_monstersArea__2dzrY');
          if (!area || !area.children[0]) return;
          unitEl = area.children[0].children[index];
        } else {
          const area = document.querySelector('.BattlePanel_playersArea__vvwlB');
          if (!area || !area.children[0]) return;
          unitEl = area.children[0].children[index];
        }
        if (!unitEl) return;

        // Intensity scalar 0–1 (capped at 800 dmg for max punch)
        const t = Math.min(1, Math.max(0, dmg / 800));

        // Cancel any in-flight animations so back-to-back hits always start clean.
        if (unitEl._mwiHitAnim)  { try { unitEl._mwiHitAnim.cancel();  } catch (_) {} }
        if (unitEl._mwiVibeAnim) { try { unitEl._mwiVibeAnim.cancel(); } catch (_) {} }

        // ── Squash & stretch ───────────────────────────────────────────
        // More dramatic values — visibly rubber-like on heavier hits.
        const sqX = (1 + 0.52 * t).toFixed(3);   // wide squash
        const sqY = (1 - 0.40 * t).toFixed(3);   // flat squash
        const stX = (1 - 0.18 * t).toFixed(3);   // tall stretch narrow
        const stY = (1 + 0.30 * t).toFixed(3);   // tall stretch
        unitEl._mwiHitAnim = unitEl.animate(
          [
            { transform: 'scale(1, 1)',            offset: 0.00 },
            { transform: `scale(${sqX}, ${sqY})`, offset: 0.09 },
            { transform: `scale(${stX}, ${stY})`, offset: 0.26 },
            { transform: 'scale(1.04, 0.97)',      offset: 0.48 },
            { transform: 'scale(0.98, 1.03)',      offset: 0.65 },
            { transform: 'scale(1.01, 0.99)',      offset: 0.80 },
            { transform: 'scale(1, 1)',            offset: 1.00 }
          ],
          {
            duration: 460 + t * 200,
            easing: 'cubic-bezier(0.22, 0.61, 0.36, 1)',
            fill: 'none'
          }
        );
        unitEl._mwiHitAnim.onfinish = () => { unitEl._mwiHitAnim = null; };

        // ── Lateral vibration ──────────────────────────────────────────
        // Fast left-right rattle overlaid on the squash. Amplitude and rattle
        // count both scale with hit intensity so small hits get a tiny nudge
        // and big hits get a proper multi-cycle shudder.
        const vx = (3 + t * 9).toFixed(1);   // peak lateral offset px
        const vy = (1 + t * 3).toFixed(1);   // slight vertical component
        const vibeDur = 60 + t * 30;          // ms per half-cycle (faster = more frantic)
        const cycles  = Math.round(2 + t * 3); // number of left-right pairs
        const vibeFrames = [{ transform: 'translate(0,0)', offset: 0 }];
        for (let c = 0; c < cycles; c++) {
          const pct = (c + 0.5) / cycles;
          const decay = (1 - pct * 0.7).toFixed(3); // amplitude decays toward end
          const sign  = c % 2 === 0 ? 1 : -1;
          vibeFrames.push({
            transform: `translate(${(sign * vx * decay).toFixed(2)}px, ${(-vy * decay).toFixed(2)}px)`,
            offset: parseFloat(((c + 0.5) / cycles * 0.55).toFixed(3))
          });
        }
        vibeFrames.push({ transform: 'translate(0,0)', offset: 1.0 });
        unitEl._mwiVibeAnim = unitEl.animate(vibeFrames, {
          duration: vibeDur * cycles * 2 + 80,
          easing: 'ease-in-out',
          fill: 'none'
        });
        unitEl._mwiVibeAnim.onfinish = () => { unitEl._mwiVibeAnim = null; };

        // ── Colour-burst glow ──────────────────────────────────────────
        const iconEl = unitEl.querySelector(
          '.CombatUnit_monsterIcon__2g3AZ, .FullAvatar_fullAvatar__3RB2h'
        ) || unitEl;
        if (iconEl._mwiGlowAnim) { try { iconEl._mwiGlowAnim.cancel(); } catch (_) {} }
        const glowPx  = (7 + t * 18).toFixed(1);
        const glowClr = dmg > 0
          ? `rgba(255,${Math.round(180 - t * 150)},${Math.round(40 - t * 40)},0.92)`
          : 'rgba(80,255,120,0.80)';
        iconEl._mwiGlowAnim = iconEl.animate(
          [
            { filter: `drop-shadow(0 0 ${glowPx}px ${glowClr}) brightness(${(1.35 + t * 0.55).toFixed(2)})`,        offset: 0.00 },
            { filter: `drop-shadow(0 0 ${(glowPx * 0.65).toFixed(1)}px ${glowClr}) brightness(1.12)`,                offset: 0.30 },
            { filter: `drop-shadow(0 0 ${(glowPx * 0.2).toFixed(1)}px ${glowClr}) brightness(1.02)`,                 offset: 0.65 },
            { filter: 'none',                                                                                         offset: 1.00 }
          ],
          {
            duration: 520 + t * 200,
            easing: 'ease-out',
            fill: 'none'
          }
        );
        iconEl._mwiGlowAnim.onfinish = () => { iconEl._mwiGlowAnim = null; };
      } catch (e) {}
    }

    // ── Consumable / Ability usage animations ──────────────────────────
    // Debug helper — call mwiDebugUsage() in the browser console, then use a
    // consumable or ability. It will log every DOM mutation on those elements
    // so we can see exactly what signal fires.
    window.mwiDebugUsage = function() {
      console.log('[mwi-debug] Starting usage DOM observer. Use a consumable or ability now.');
      const obs = new MutationObserver((muts) => {
        for (const m of muts) {
          const target = m.target;
          const cls = (typeof target.className === 'string') ? target.className : (target.data !== undefined ? '#text' : '?');
          if (m.type === 'childList') {
            m.addedNodes.forEach(n => console.log('[mwi-debug] childList ADD', n.nodeName, typeof n.className === 'string' ? n.className : n.data, '| parent:', cls));
            m.removedNodes.forEach(n => console.log('[mwi-debug] childList REM', n.nodeName, typeof n.className === 'string' ? n.className : n.data, '| parent:', cls));
          } else if (m.type === 'attributes') {
            console.log('[mwi-debug] attr change [' + m.attributeName + ']', '\n  old:', m.oldValue, '\n  new:', target.getAttribute(m.attributeName), '\n  el:', cls);
          } else if (m.type === 'characterData') {
            console.log('[mwi-debug] text change old:"' + m.oldValue + '" → new:"' + m.target.data + '" | parent:', target.parentElement && (target.parentElement.className || target.parentElement.nodeName));
          }
        }
      });
      obs.observe(document.body, {
        childList: true, subtree: true,
        characterData: true, characterDataOldValue: true,
        attributes: true, attributeOldValue: true,
      });
      console.log('[mwi-debug] Observer active. Call mwiDebugUsageStop() to stop.');
      window.mwiDebugUsageStop = function() { obs.disconnect(); console.log('[mwi-debug] Stopped.'); };
    };

    function hookUsageAnim() {
      if (window._mwiUsageAnimHooked) return;
      window._mwiUsageAnimHooked = true;

      // Consumable: crunchy pop — quick squash (bite/crunch) then springy bounce back
      function playConsumeAnim(el) {
        if (!el || el._mwiConsumeAnim) return;
        el._mwiConsumeAnim = true;
        const a = el.animate([
          { transform: 'scale(1)',           filter: 'brightness(1)',    offset: 0.00 },
          { transform: 'scale(0.80, 0.78)', filter: 'brightness(1.9)',  offset: 0.10 }, // crunch
          { transform: 'scale(1.20, 1.18)', filter: 'brightness(1.5)',  offset: 0.28 }, // pop
          { transform: 'scale(0.93, 0.95)', filter: 'brightness(1.15)', offset: 0.46 },
          { transform: 'scale(1.04, 1.03)', filter: 'brightness(1.06)', offset: 0.63 },
          { transform: 'scale(1)',           filter: 'brightness(1)',    offset: 1.00 }
        ], { duration: 2000, easing: 'cubic-bezier(0.22, 0.61, 0.36, 1)', fill: 'none' });
        a.onfinish = () => { el._mwiConsumeAnim = false; };
      }

      // Ability: impactful surge — charge-up burst then crash-down, with fiery glow
      function playAbilityAnim(el) {
        if (!el || el._mwiAbilityAnim) return;
        el._mwiAbilityAnim = true;
        const a = el.animate([
          { transform: 'scale(1)',    filter: 'brightness(1)',                                              offset: 0.00 },
          { transform: 'scale(1.32)', filter: 'brightness(2.6) drop-shadow(0 0 14px rgba(255,180,40,1))', offset: 0.14 },
          { transform: 'scale(0.85)', filter: 'brightness(1.6) drop-shadow(0 0 9px rgba(255,90,20,0.8))', offset: 0.33 },
          { transform: 'scale(1.10)', filter: 'brightness(1.25) drop-shadow(0 0 5px rgba(255,70,0,0.4))', offset: 0.52 },
          { transform: 'scale(0.97)', filter: 'brightness(1.06)',                                          offset: 0.73 },
          { transform: 'scale(1)',    filter: 'brightness(1)',                                             offset: 1.00 }
        ], { duration: 2000, easing: 'cubic-bezier(0.22, 0.61, 0.36, 1)', fill: 'none' });
        a.onfinish = () => { el._mwiAbilityAnim = false; };
      }

      // ── Unified observer — triggered by CountdownOverlay add/remove.
      // Abilities:   CountdownOverlay ADDED to CombatAbility_combatAbility__ (new cooldown starts = ability fired)
      // Consumables: CountdownOverlay ADDED to CombatConsumable_combatConsumable__
      const obs = new MutationObserver((mutations) => {
        if (cfg.usageAnim === false) return;
        for (const mut of mutations) {
          if (mut.type !== 'childList') continue;
          const parentCls = typeof mut.target.className === 'string' ? mut.target.className : '';

          if (parentCls.includes('CombatAbility_combatAbility__')) {
            // Fire on addition of the countdown overlay (ability just activated)
            for (const node of mut.addedNodes) {
              if (node.nodeType !== 1) continue;
              const cls = typeof node.className === 'string' ? node.className : '';
              if (cls.includes('CountdownOverlay_countdownOverlay__')) {
                playAbilityAnim(mut.target);
                break;
              }
            }
          } else if (parentCls.includes('CombatConsumable_combatConsumable__')) {
            // Fire on addition of the countdown overlay (consumable just used)
            for (const node of mut.addedNodes) {
              if (node.nodeType !== 1) continue;
              const cls = typeof node.className === 'string' ? node.className : '';
              if (cls.includes('CountdownOverlay_countdownOverlay__')) {
                playConsumeAnim(mut.target);
                break;
              }
            }
          }
        }
      });
      obs.observe(document.body, { childList: true, subtree: true });
    }

    function hookCombatWS() {
      if (window._mwiCombatWSHooked) return;
      window._mwiCombatWSHooked = true;
      try {
        const dp = Object.getOwnPropertyDescriptor(MessageEvent.prototype, 'data');
        if (!dp) return;
        const oriGet = dp.get;
        let monsHP = [], monsCtr = [], plrsHP = [], plrsCtr = [];
        dp.get = function () {
          const socket = this.currentTarget;
          if (!(socket instanceof WebSocket)) return oriGet.call(this);
          if (!socket.url.includes('milkywayidle.com/ws')) return oriGet.call(this);
          const msg = oriGet.call(this);
          // Anti-loop: cache on instance so the prototype getter isn't called again
          Object.defineProperty(this, 'data', { value: msg });
          try {
            if (cfg.combatAnim !== false) {
              const obj = JSON.parse(msg);
              if (obj && obj.type === 'new_battle') {
                monsHP  = obj.monsters.map(m => m.currentHitpoints);
                monsCtr = obj.monsters.map(m => m.damageSplatCounter);
                plrsHP  = obj.players.map(p => p.currentHitpoints);
                plrsCtr = obj.players.map(p => p.damageSplatCounter);
              } else if (obj && obj.type === 'battle_updated' && monsHP.length) {
                const { mMap, pMap } = obj;
                Object.keys(mMap || {}).forEach(i => {
                  const m = mMap[i]; if (!m) return;
                  if ((monsCtr[i] ?? -1) < m.dmgCounter) {
                    tryHitAnim('monster', +i, Math.max(0, monsHP[i] - m.cHP));
                  }
                  monsHP[i] = m.cHP; monsCtr[i] = m.dmgCounter;
                });
                Object.keys(pMap || {}).forEach(i => {
                  const p = pMap[i]; if (!p) return;
                  if ((plrsCtr[i] ?? -1) < p.dmgCounter) {
                    tryHitAnim('player', +i, Math.max(0, plrsHP[i] - p.cHP));
                  }
                  plrsHP[i] = p.cHP; plrsCtr[i] = p.dmgCounter;
                });
              }
            }
          } catch (e) {}
          return msg;
        };
        Object.defineProperty(MessageEvent.prototype, 'data', dp);
      } catch (e) { log('hookCombatWS error', e); }
    }

    function createSettingsModal() {
      // If an older overlay exists (from a previous script version), remove it
      // so we recreate the modal with current event handlers.
      const existingOverlay = document.getElementById('mwi-settings-overlay');
      if (existingOverlay) existingOverlay.remove();
      const overlay = document.createElement('div'); overlay.id = 'mwi-settings-overlay';
      overlay.style.display = 'none';
      // helper to animate-close the modal (keeps consistent timing everywhere)
      function animateClose() {
        try {
          if (!overlay) return;
          overlay.classList.remove('mwi-dialog-open');
          overlay.classList.add('mwi-dialog-closing');
          setTimeout(() => {
            try { overlay.style.display = 'none'; overlay.classList.remove('mwi-dialog-closing'); } catch (e) {}
          }, 200);
        } catch (e) {}
      }
      // close modal when clicking outside the dialog
      overlay.addEventListener('click', (ev) => { try { if (ev.target === overlay) animateClose(); } catch (e) {} });
      // mouse-tracked glow on dialog (frosted mode only)
      overlay.addEventListener('mousemove', (ev) => {
        try {
          if ((cfg.uiStyle || 'frosted') !== 'frosted') return;
          const rect = dialog.getBoundingClientRect();
          const x = ((ev.clientX - rect.left) / rect.width * 100).toFixed(1) + '%';
          const y = ((ev.clientY - rect.top) / rect.height * 100).toFixed(1) + '%';
          dialog.style.setProperty('--glow-x', x);
          dialog.style.setProperty('--glow-y', y);
        } catch (e) {}
      });

      const dialog = document.createElement('div'); dialog.id = 'mwi-settings-dialog';
      const closeBtn = document.createElement('button'); closeBtn.id = 'mwi-settings-close'; closeBtn.textContent = '\u2715';
      closeBtn.addEventListener('click', () => animateClose());

      const title = document.createElement('h3'); title.textContent = 'MWI Customizer Settings - v1.2.2'; title.style.background = 'linear-gradient(90deg, #ff44cc, #44aaff)'; title.style.webkitBackgroundClip = 'text'; title.style.webkitTextFillColor = 'transparent'; title.style.backgroundClip = 'text';
      const notice = document.createElement('div'); notice.className = 'mwi-settings-notice'; notice.textContent = 'Refresh the page for changes to apply.';

      // Search bar (sticky, below notice)
      const searchWrap = document.createElement('div');
      searchWrap.id = 'mwi-search-wrap';
      searchWrap.style.cssText = 'position:sticky;top:0;z-index:10;padding:8px 16px 6px;margin:0 -16px;display:flex;align-items:center;gap:8px;border-bottom:1px solid rgba(255,255,255,0.08);margin-bottom:4px;';
      const searchInput = document.createElement('input'); searchInput.type = 'text'; searchInput.id = 'mwi-settings-search'; searchInput.placeholder = 'Search settings…';
      searchInput.style.cssText = 'flex:1;background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.15);border-radius:6px;padding:5px 10px;color:#e6eef8;font-size:13px;outline:none;font-family:inherit;transition:border-color 0.2s;min-width:0;';
      searchInput.addEventListener('focus', () => { searchInput.style.borderColor = '#44aaff'; });
      searchInput.addEventListener('blur', () => { searchInput.style.borderColor = 'rgba(255,255,255,0.15)'; });
      const clearBtn = document.createElement('button'); clearBtn.textContent = '✕'; clearBtn.title = 'Clear search';
      clearBtn.style.cssText = 'background:none;border:none;color:#99b7d9;font-size:13px;cursor:pointer;padding:0 4px;flex-shrink:0;opacity:0;transition:opacity 0.2s;';
      function runSearch() {
        const q = searchInput.value.trim().toLowerCase();
        clearBtn.style.opacity = q ? '1' : '0';
        const content = document.getElementById('mwi-settings-content');
        if (!content) return;
        if (!q) {
          content.querySelectorAll('.mwi-settings-section,.mwi-colors-subsection,.mwi-customizer-sub').forEach(el => { el.style.display = ''; });
          return;
        }
        // Search mwi-customizer-sub blocks (Themes, Background, Manage Elements, etc.)
        content.querySelectorAll('.mwi-customizer-sub').forEach(sub => {
          const txt = sub.textContent.toLowerCase();
          sub.style.display = txt.includes(q) ? '' : 'none';
        });
        content.querySelectorAll('.mwi-settings-section').forEach(section => {
          let sectionMatch = false;
          const h4 = section.querySelector('h4');
          if (h4 && h4.textContent.toLowerCase().includes(q)) { sectionMatch = true; }
          section.querySelectorAll('.mwi-colors-subsection').forEach(sub => {
            let subMatch = false;
            const h5 = sub.querySelector('h5');
            if (h5 && h5.textContent.toLowerCase().includes(q)) { subMatch = true; }
            sub.querySelectorAll('.mwi-settings-row').forEach(row => {
              const txt = row.textContent.toLowerCase();
              if (txt.includes(q)) subMatch = true;
            });
            sub.style.display = subMatch ? '' : 'none';
            if (subMatch) sectionMatch = true;
          });
          section.querySelectorAll(':scope > .mwi-settings-row').forEach(row => {
            const txt = row.textContent.toLowerCase();
            if (txt.includes(q)) sectionMatch = true;
          });
          // Also check mwi-customizer-sub children inside this section
          section.querySelectorAll(':scope > .mwi-customizer-sub').forEach(sub => {
            if (sub.style.display !== 'none') sectionMatch = true;
          });
          section.style.display = sectionMatch ? '' : 'none';
        });
      }
      searchInput.addEventListener('input', runSearch);
      clearBtn.addEventListener('click', () => { searchInput.value = ''; runSearch(); searchInput.focus(); });
      searchWrap.appendChild(searchInput); searchWrap.appendChild(clearBtn);

      const content = document.createElement('div'); content.id = 'mwi-settings-content'; content.style.marginTop = '8px';

      // Small helper to ensure the 'Borders' row appears before 'Glow'
      function reorderBordersGlow(root) {
        try {
          const inv = Array.from((root || document).querySelectorAll('.mwi-settings-section')).find(s => { try { const h = s.querySelector('h4'); return h && h.textContent && h.textContent.trim() === 'Inventory'; } catch (e) { return false; } });
          if (!inv) return;
          const rows = Array.from(inv.querySelectorAll('.mwi-settings-row'));
          const glow = rows.find(r => { const l = r.querySelector('label') || r.querySelector('div'); return l && l.textContent && l.textContent.trim() === 'Glow'; });
          const borders = rows.find(r => { const l = r.querySelector('label') || r.querySelector('div'); return l && l.textContent && l.textContent.trim() === 'Borders'; });
          if (borders && glow && glow.previousElementSibling !== borders) {
            try { glow.parentElement.insertBefore(borders, glow); } catch (e) { try { inv.insertBefore(borders, glow); } catch (e2) {} }
          }
        } catch (e) {}
      }

      // Colors section (sitewide)
      const colorsSection = document.createElement('div'); colorsSection.className = 'mwi-settings-section'; colorsSection.id = 'mwi-section-site-colors';
      const colorsTitle = document.createElement('h4'); colorsTitle.textContent = 'Site Colors'; colorsTitle.style.background = 'linear-gradient(90deg, #ff44cc, #44aaff)'; colorsTitle.style.webkitBackgroundClip = 'text'; colorsTitle.style.webkitTextFillColor = 'transparent'; colorsTitle.style.backgroundClip = 'text';
      colorsSection.appendChild(colorsTitle);
      // Remove the large separator that appears below Inventory (beneath Glow)
      // by clearing this section's top border.
      try { colorsSection.style.borderTop = '2px solid rgba(255,255,255,0.12)'; } catch (e) {}

      const colorsList = document.createElement('div'); colorsList.style.marginTop = '6px';

      // Background section (custom image overlay)
      const bgSection = document.createElement('div'); bgSection.className = 'mwi-customizer-sub'; bgSection.id = 'mwi-section-background';
      const bgTitle = document.createElement('h5'); bgTitle.textContent = 'Background'; bgSection.appendChild(bgTitle);
      const bgList = document.createElement('div'); bgList.style.marginTop = '6px';

      // MWI Customizer sub-section (UI style + button style)
      const mwiCfgSection = document.createElement('div'); mwiCfgSection.className = 'mwi-customizer-sub'; mwiCfgSection.id = 'mwi-section-mwi-cfg';
      const mwiCfgTitle = document.createElement('h5'); mwiCfgTitle.textContent = 'MWI Customizer'; mwiCfgSection.appendChild(mwiCfgTitle);
      try {
        // Settings UI dropdown
        const uiRow = document.createElement('div'); uiRow.className = 'mwi-settings-row';
        const uiLabel = document.createElement('label'); uiLabel.textContent = 'Settings UI';
        const uiSelect = document.createElement('select');
        [['frosted','Frosted'],['solid','Solid']].forEach(([v,t]) => { const o = document.createElement('option'); o.value=v; o.textContent=t; if ((cfg.uiStyle||'frosted')===v) o.selected=true; uiSelect.appendChild(o); });
        uiSelect.addEventListener('change', () => { cfg.uiStyle = uiSelect.value; saveSettings(); applyUIStyle(); });
        uiRow.appendChild(uiLabel); uiRow.appendChild(uiSelect); mwiCfgSection.appendChild(uiRow);
        // Settings Button dropdown
        const btnRow = document.createElement('div'); btnRow.className = 'mwi-settings-row';
        const btnLabel = document.createElement('label'); btnLabel.textContent = 'Settings Button';
        const btnSelect = document.createElement('select');
        [['frosted','Frosted'],['solid','Solid']].forEach(([v,t]) => { const o = document.createElement('option'); o.value=v; o.textContent=t; if ((cfg.btnStyle||'frosted')===v) o.selected=true; btnSelect.appendChild(o); });
        btnSelect.addEventListener('change', () => { cfg.btnStyle = btnSelect.value; saveSettings(); applyUIStyle(); });
        btnRow.appendChild(btnLabel); btnRow.appendChild(btnSelect); mwiCfgSection.appendChild(btnRow);
      } catch (e) {}

      // Themes selector
      const themesSection = document.createElement('div'); themesSection.className = 'mwi-customizer-sub'; themesSection.style.borderTop = 'none'; themesSection.style.paddingTop = '2px'; themesSection.id = 'mwi-section-themes';
      const themesTitle = document.createElement('h5'); themesTitle.textContent = 'Themes'; themesSection.appendChild(themesTitle);
      const themesList = document.createElement('div'); themesList.style.marginTop = '6px';
      try {
        const themeRow = document.createElement('div'); themeRow.className = 'mwi-settings-row';
        const themeLabel = document.createElement('label'); themeLabel.textContent = 'Preset theme';
        const themeSelect = document.createElement('select');
        for (const t of PRESET_THEMES) {
          const o = document.createElement('option'); o.value = t.key; o.textContent = t.label; if ((cfg.themeKey||'') === t.key) o.selected = true; themeSelect.appendChild(o);
        }
        themeSelect.addEventListener('change', () => {
          try {
            const key = themeSelect.value || '';
            cfg.themeKey = key;
            // find preset
            const t = PRESET_THEMES.find(x => x.key === key);
            if (t && t.siteColors) {
              // replace siteColors with theme values
              cfg.siteColors = cfg.siteColors || {};
              // clear existing
              for (const k of Object.keys(cfg.siteColors)) delete cfg.siteColors[k];
              // copy theme siteColors
              for (const kk of Object.keys(t.siteColors || {})) cfg.siteColors[kk] = t.siteColors[kk];
            } else {
              // restore defaults if no theme
              cfg.siteColors = JSON.parse(JSON.stringify(DEFAULT_CFG.siteColors || {}));
            }
            applySiteColors(); saveSettings();
            try { if (typeof renderColorsEditor === 'function') renderColorsEditor(colorsList); } catch (e) {}
          } catch (e) { log('theme select error', e); }
        });
        themeRow.appendChild(themeLabel); themeRow.appendChild(themeSelect); themesList.appendChild(themeRow);
        // Import / Export controls for sharing settings
        const shareRow = document.createElement('div'); shareRow.className = 'mwi-settings-row';
        shareRow.style.alignItems = 'center';
        const exportBtn = document.createElement('button'); exportBtn.type = 'button'; exportBtn.textContent = 'Export';
        // Export: primary green
        exportBtn.style.background = '#1f7d3d'; exportBtn.style.color = '#fff'; exportBtn.style.border = '0'; exportBtn.style.padding = '6px 10px'; exportBtn.style.borderRadius = '6px'; exportBtn.style.marginRight = '8px'; exportBtn.classList.add('mwi-push-btn');
        const importBtn = document.createElement('button'); importBtn.type = 'button'; importBtn.textContent = 'Import';
        // Import: primary blue
        importBtn.style.background = '#1f4a8a'; importBtn.style.color = '#fff'; importBtn.style.border = '0'; importBtn.style.padding = '6px 10px'; importBtn.style.borderRadius = '6px'; importBtn.style.marginRight = '8px'; importBtn.classList.add('mwi-push-btn');
        // hidden textarea to show the exported string or accept import
        // Build a reusable modal for Import/Export strings
        function openShareModal(mode, text) {
          try {
            // remove existing if present
            const existing = document.getElementById('mwi-share-modal-overlay');
            if (existing) existing.remove();
            const over = document.createElement('div'); over.id = 'mwi-share-modal-overlay'; over.style.position = 'fixed'; over.style.inset = '0'; over.style.background = 'rgba(0,0,0,0.6)'; over.style.display = 'flex'; over.style.alignItems = 'center'; over.style.justifyContent = 'center'; over.style.zIndex = '10000020';
            const modal = document.createElement('div'); modal.className = 'mwi-share-modal'; modal.style.background = '#0f1720'; modal.style.color = '#e6eef8'; modal.style.padding = '12px'; modal.style.borderRadius = '8px'; modal.style.width = '560px'; modal.style.maxWidth = '92%'; modal.style.boxShadow = '0 8px 24px rgba(0,0,0,0.6)'; modal.style.display = 'flex'; modal.style.flexDirection = 'column';
            const h = document.createElement('h4'); h.textContent = (mode === 'export') ? 'Export Settings' : 'Import Settings'; h.style.margin = '0 0 8px 0'; modal.appendChild(h);
            const ta = document.createElement('textarea'); ta.style.width = '100%'; ta.style.height = '140px'; ta.style.marginBottom = '8px'; ta.value = text || '';
            if (mode === 'export') { ta.readOnly = true; }
            modal.appendChild(ta);
            const row = document.createElement('div'); row.style.display = 'flex'; row.style.justifyContent = 'flex-end'; row.style.gap = '8px';
            if (mode === 'export') {
              const copyBtn = document.createElement('button'); copyBtn.type = 'button'; copyBtn.textContent = 'Copy'; copyBtn.classList.add('mwi-push-btn');
              copyBtn.addEventListener('click', async () => { try { await navigator.clipboard.writeText(ta.value); copyBtn.textContent = 'Copied'; setTimeout(() => copyBtn.textContent = 'Copy', 1200); } catch (e) { alert('Copy failed'); } });
              row.appendChild(copyBtn);
            } else {
              const applyBtn = document.createElement('button'); applyBtn.type = 'button'; applyBtn.textContent = 'Apply'; applyBtn.classList.add('mwi-push-btn');
              applyBtn.addEventListener('click', () => {
                try {
                  const val = (ta.value || '').trim(); if (!val) { alert('Paste an import string into the box then click Apply.'); return; }
                  let json = null;
                  try { json = decodeURIComponent(escape(atob(val))); } catch (e) { try { json = atob(val); } catch (e2) { throw new Error('Unable to decode string'); } }
                  let obj = null; try { obj = JSON.parse(json); } catch (e) { throw new Error('Invalid JSON payload'); }
                  if (!obj || typeof obj !== 'object') throw new Error('Invalid import data');
                  // allow applying any cfg key except dev-only keys
                  const allowed = Object.keys(cfg).filter(k => !DEV_KEYS.includes(k));
                  for (const k of Object.keys(obj)) if (allowed.includes(k)) cfg[k] = obj[k];
                  saveSettings(); applySiteColors();
                  try { applyHideOrganize(); } catch (e) {}
                  try { if (typeof renderColorsEditor === 'function') renderColorsEditor(colorsList); } catch (e) {}
                  // Show confirmation prompting the user to refresh (like Reset flow)
                  try {
                    if (document.getElementById('mwi-import-confirm')) return;
                    // remove the share modal so the confirmation appears above the settings overlay
                    try { over.remove(); } catch (e) {}
                    const conf = document.createElement('div'); conf.id = 'mwi-import-confirm';
                    conf.style.position = 'absolute'; conf.style.left = '50%'; conf.style.top = '50%';
                    conf.style.transform = 'translate(-50%, -50%)'; conf.style.zIndex = 10000003;
                    conf.style.background = '#071019'; conf.style.color = '#e6eef8'; conf.style.padding = '14px';
                    conf.style.borderRadius = '8px'; conf.style.boxShadow = '0 8px 24px rgba(0,0,0,0.6)'; conf.style.width = '420px';

                    const msg = document.createElement('div'); msg.style.marginBottom = '12px'; msg.style.fontSize = '13px';
                    msg.textContent = 'Import applied. Refresh the page to apply changes?';
                    const btnRow = document.createElement('div'); btnRow.style.textAlign = 'right';
                    const cancel = document.createElement('button'); cancel.textContent = 'Cancel'; cancel.style.marginRight = '8px';
                    cancel.addEventListener('click', () => { try { conf.remove(); } catch (e) {} });
                    const confirmNow = document.createElement('button'); confirmNow.textContent = 'Refresh Now';
                    confirmNow.style.background = '#1f7d3d'; confirmNow.style.color = '#fff'; confirmNow.style.border = '0'; confirmNow.style.padding = '8px 12px'; confirmNow.style.borderRadius = '6px';
                    confirmNow.addEventListener('click', () => {
                      try {
                        // Remove confirmation box and share modal, then close settings overlay and reload
                        try { conf.remove(); } catch (e) {}
                        try { over.remove(); } catch (e) {}
                        try { if (typeof animateClose === 'function') animateClose(); else if (overlay && overlay.style) overlay.style.display = 'none'; } catch (e) {}
                        setTimeout(() => { try { location.reload(); } catch (e) { log('reload after import failed', e); } }, 50);
                      } catch (e) { log('confirm import error', e); }
                    });

                    btnRow.appendChild(cancel); btnRow.appendChild(confirmNow);
                    conf.appendChild(msg); conf.appendChild(btnRow);
                    try { if (overlay) overlay.appendChild(conf); else document.body.appendChild(conf); } catch (e) { document.body.appendChild(conf); }
                  } catch (e) { log('import applied confirmation error', e); }
                } catch (e) { log('import error', e); alert('Import failed: ' + (e && e.message)); }
              });
              row.appendChild(applyBtn);
            }
            function closeShareModal() {
              over.classList.remove('mwi-share-open');
              over.classList.add('mwi-share-closing');
              setTimeout(() => { try { over.remove(); } catch (e) {} }, 200);
            }
            const closeBtn = document.createElement('button'); closeBtn.type = 'button'; closeBtn.textContent = 'Close'; closeBtn.classList.add('mwi-push-btn'); closeBtn.addEventListener('click', () => closeShareModal()); row.appendChild(closeBtn);
            modal.appendChild(row);
            over.appendChild(modal);
            // clicking outside the share modal closes it (but won't affect main modal)
            over.addEventListener('click', (ev) => { try { if (ev.target === over) closeShareModal(); } catch (e) {} });
            document.body.appendChild(over);
            requestAnimationFrame(() => requestAnimationFrame(() => over.classList.add('mwi-share-open')));
            ta.focus(); if (mode === 'export') ta.select();
          } catch (e) { log('openShareModal error', e); }
        }
        // Export implementation: produce compact base64 JSON and open modal
        exportBtn.addEventListener('click', async () => {
          try {
            // export all non-dev cfg keys
            const keys = Object.keys(cfg).filter(k => !DEV_KEYS.includes(k));
            const out = {};
            for (const k of keys) if (cfg[k] !== undefined) out[k] = cfg[k];
            const json = JSON.stringify(out);
            const encoded = btoa(unescape(encodeURIComponent(json)));
            openShareModal('export', encoded);
          } catch (e) { log('export error', e); alert('Export failed: ' + (e && e.message)); }
        });
        // Import implementation: open modal with empty textarea for paste
        importBtn.addEventListener('click', () => { try { openShareModal('import', ''); } catch (e) { log('import open error', e); } });
        const customLabel = document.createElement('label'); customLabel.textContent = 'Custom theme'; customLabel.style.flex = '1'; customLabel.style.marginRight = '8px';
        shareRow.appendChild(customLabel);
        shareRow.appendChild(importBtn); shareRow.appendChild(exportBtn); themesList.appendChild(shareRow);
      } catch (e) {}
      themesSection.appendChild(themesList);

      // Enable toggle
      try {
        const beRow = document.createElement('div'); beRow.className = 'mwi-settings-row';
        const beLabel = document.createElement('label'); beLabel.textContent = 'Enable background'; beLabel.htmlFor = 'mwi-bg-enabled-chk'; beLabel.style.cursor = 'pointer'; beLabel.style.flex = '1';
        const beChk = document.createElement('input'); beChk.type = 'checkbox'; beChk.id = 'mwi-bg-enabled-chk'; beChk.checked = !!cfg.backgroundEnabled;
        beChk.addEventListener('change', () => { cfg.backgroundEnabled = beChk.checked; applySiteColors(); saveSettings(); });
        beRow.appendChild(beLabel); beRow.appendChild(beChk); bgList.appendChild(beRow);
      } catch (e) {}

      // URL input + reset
      try {
        const urlRow = document.createElement('div'); urlRow.className = 'mwi-settings-row';
        const urlLabel = document.createElement('label'); urlLabel.textContent = 'Image URL';
        const urlInput = document.createElement('input'); urlInput.type = 'text'; urlInput.placeholder = 'https://...'; urlInput.value = cfg.backgroundUrl || '';
        urlInput.style.flex = '1'; urlInput.style.marginLeft = '8px';
        urlInput.addEventListener('change', () => {
          try {
            let v = (urlInput.value || '').trim();
            if (v) {
              // If no scheme present but looks like a domain/path, prefix https://
              // allow protocol-relative URLs (//cdn.example.com/img.png)
              if (!/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(v) && !v.startsWith('//')) {
                // naive domain detection (has a dot and no spaces)
                if (/^[^\s]+\.[^\s]+/.test(v)) v = 'https://' + v;
              }
            }
            cfg.backgroundUrl = v;
            applySiteColors(); saveSettings();
          } catch (e) { log('background url change error', e); }
        });
        // URL input (preview control removed)
        urlRow.appendChild(urlLabel); urlRow.appendChild(urlInput);
        bgList.appendChild(urlRow);

        // Opacity
        const opRow = document.createElement('div'); opRow.className = 'mwi-settings-row';
        const opLabel = document.createElement('label'); opLabel.textContent = 'Opacity';
        const opacityInput = document.createElement('input'); opacityInput.type = 'range'; opacityInput.min = 0; opacityInput.max = 100; opacityInput.value = String(Math.round((cfg.backgroundOpacity !== undefined ? cfg.backgroundOpacity : 1) * 100)); opacityInput.style.marginLeft = '8px';
        opacityInput.addEventListener('input', () => { cfg.backgroundOpacity = Number(opacityInput.value)/100; applySiteColors(); saveSettings(); });
        opRow.appendChild(opLabel); opRow.appendChild(opacityInput); bgList.appendChild(opRow);

        // size/position controls removed; overlay uses fixed cover/center
      } catch (e) {}

      bgSection.appendChild(bgList);

      // Hide/Organize Elements section (button opens organize modal)
      const hideSection = document.createElement('div'); hideSection.className = 'mwi-customizer-sub'; hideSection.id = 'mwi-section-hide-organize';
      const hideTitle = document.createElement('h5'); hideTitle.textContent = 'Manage Elements'; hideSection.appendChild(hideTitle);
      const hideList = document.createElement('div'); hideList.style.marginTop = '6px';
      try {
        const openBtnRow = document.createElement('div'); openBtnRow.className = 'mwi-settings-row';
        const openLabel = document.createElement('label'); openLabel.textContent = 'Customize left side panel'; openLabel.style.flex = '1';
        const openBtn = document.createElement('button'); openBtn.type = 'button'; openBtn.textContent = 'Manage';
        // Manage: neutral gray
        openBtn.style.background = '#6b7280'; openBtn.style.color = '#fff'; openBtn.style.border = '0'; openBtn.style.padding = '6px 10px'; openBtn.style.borderRadius = '6px'; openBtn.style.marginRight = '8px'; openBtn.classList.add('mwi-push-btn');
        openBtn.addEventListener('click', () => { try { openOrganizeModal(); } catch (e) { log('open organize error', e); } });
        openBtnRow.appendChild(openLabel); openBtnRow.appendChild(openBtn); hideList.appendChild(openBtnRow);
        // Swap panels toggle
        const swapRow = document.createElement('div'); swapRow.className = 'mwi-settings-row'; swapRow.style.marginTop = '8px';
        const swapChk = document.createElement('input'); swapChk.type = 'checkbox'; swapChk.id = 'mwi-swap-panels-chk'; swapChk.checked = (cfg.swapPanels === true);
        const swapLbl = document.createElement('label'); swapLbl.htmlFor = 'mwi-swap-panels-chk'; swapLbl.textContent = 'Swap left and right panels';
        swapChk.addEventListener('change', () => {
          cfg.swapPanels = swapChk.checked;
          saveSettings();
          document.documentElement.classList.toggle('mwi-swap-panels', cfg.swapPanels);
        });
        swapRow.appendChild(swapLbl); swapRow.appendChild(swapChk); hideList.appendChild(swapRow);
        // Chat to top toggle
        const chatTopRow = document.createElement('div'); chatTopRow.className = 'mwi-settings-row'; chatTopRow.style.marginTop = '8px';
        const chatTopChk = document.createElement('input'); chatTopChk.type = 'checkbox'; chatTopChk.id = 'mwi-chat-top-chk'; chatTopChk.checked = (cfg.chatTop === true);
        const chatTopLbl = document.createElement('label'); chatTopLbl.htmlFor = 'mwi-chat-top-chk'; chatTopLbl.textContent = 'Move chat to top'; chatTopLbl.style.cursor = 'pointer'; chatTopLbl.style.flex = '1';
        chatTopChk.addEventListener('change', () => {
          cfg.chatTop = chatTopChk.checked;
          saveSettings();
          document.documentElement.classList.toggle('mwi-chat-top', cfg.chatTop);
        });
        chatTopRow.appendChild(chatTopLbl); chatTopRow.appendChild(chatTopChk); hideList.appendChild(chatTopRow);
        // Header to bottom toggle
        const hdrRow = document.createElement('div'); hdrRow.className = 'mwi-settings-row'; hdrRow.style.marginTop = '8px';
        const hdrChk = document.createElement('input'); hdrChk.type = 'checkbox'; hdrChk.id = 'mwi-header-bottom-chk'; hdrChk.checked = (cfg.headerBottom === true);
        const hdrLbl = document.createElement('label'); hdrLbl.htmlFor = 'mwi-header-bottom-chk'; hdrLbl.textContent = 'Move header to bottom'; hdrLbl.style.cursor = 'pointer'; hdrLbl.style.flex = '1';
        hdrChk.addEventListener('change', () => {
          cfg.headerBottom = hdrChk.checked;
          saveSettings();
          document.documentElement.classList.toggle('mwi-header-bottom', cfg.headerBottom);
        });
        hdrRow.appendChild(hdrLbl); hdrRow.appendChild(hdrChk); hideList.appendChild(hdrRow);
      } catch (e) {}
      hideSection.appendChild(hideList);


      

      // Inventory section
      const invSection = document.createElement('div'); invSection.className = 'mwi-settings-section'; invSection.id = 'mwi-section-inventory';
      const invTitle = document.createElement('h4'); invTitle.textContent = 'Inventory Color Coding'; invTitle.style.background = 'linear-gradient(90deg, #ff44cc, #44aaff)'; invTitle.style.webkitBackgroundClip = 'text'; invTitle.style.webkitTextFillColor = 'transparent'; invTitle.style.backgroundClip = 'text';
      invSection.appendChild(invTitle);

      // Inventory setting: color mode dropdown
      const modeRow = document.createElement('div'); modeRow.className = 'mwi-settings-row';
      const modeLabel = document.createElement('label'); modeLabel.textContent = 'Color mode';
      const modeSelect = document.createElement('select');
      ['Quantity','All','None'].forEach(opt => {
        const o = document.createElement('option'); o.value = opt; o.textContent = opt; if (cfg.colorMode === opt) o.selected = true; modeSelect.appendChild(o);
      });
      modeSelect.addEventListener('change', () => {
        cfg.colorMode = modeSelect.value;
        saveSettings();
        try { if (window.MWI_InventoryHighlighter && window.MWI_InventoryHighlighter.reScan) window.MWI_InventoryHighlighter.reScan(); } catch (e) {}
        try { if (typeof updateInventoryEditorsVisibility === 'function') updateInventoryEditorsVisibility(); } catch (e) {}
      });
      modeRow.appendChild(modeLabel); modeRow.appendChild(modeSelect);
      invSection.appendChild(modeRow);

      // All-mode color picker row (hidden unless mode === 'All')
      const allRow = document.createElement('div'); allRow.className = 'mwi-settings-row';
      const allLabel = document.createElement('div'); allLabel.textContent = 'All Color'; allLabel.style.flex = '1'; allLabel.style.marginRight = '8px';
      const allInput = document.createElement('input'); allInput.type = 'color';
      try { allInput.value = (cfg.allColor && String(cfg.allColor).trim()) || '#1d8ce0'; } catch (e) { allInput.value = '#1d8ce0'; }
      allInput.addEventListener('input', () => { try { cfg.allColor = allInput.value; saveSettings(); if (window.MWI_InventoryHighlighter && window.MWI_InventoryHighlighter.reScan) window.MWI_InventoryHighlighter.reScan(); } catch (e) {} });
      allRow.appendChild(allLabel); allRow.appendChild(allInput);
      // alpha slider
      const allAlpha = document.createElement('input'); allAlpha.type = 'range'; allAlpha.min = 0; allAlpha.max = 100; allAlpha.style.marginLeft = '8px';
      try { allAlpha.value = String(Math.round((cfg.allAlpha !== undefined ? cfg.allAlpha : 1) * 100)); } catch (e) { allAlpha.value = '100'; }
      allAlpha.addEventListener('input', () => { try { cfg.allAlpha = Number(allAlpha.value)/100; saveSettings(); if (window.MWI_InventoryHighlighter && window.MWI_InventoryHighlighter.reScan) window.MWI_InventoryHighlighter.reScan(); } catch (e) {} });
      allRow.appendChild(allAlpha);
      // single clipboard shared across all color rows (site colors, all color, quantity tiers)
      let sharedColorClipboard = null;
      // copy button
      const allCopy = document.createElement('button'); allCopy.type = 'button'; allCopy.title = 'Copy color & opacity'; allCopy.textContent = '\u2398'; allCopy.classList.add('mwi-push-btn');
      allCopy.style.marginLeft = '8px'; allCopy.style.width = '26px'; allCopy.style.height = '22px'; allCopy.style.borderRadius = '4px'; allCopy.style.border = '1px solid rgba(255,255,255,0.06)'; allCopy.style.background = 'transparent'; allCopy.style.color = '#aaa'; allCopy.style.fontSize = '14px';
      allCopy.addEventListener('click', () => {
        try {
          sharedColorClipboard = { color: allInput.value, alpha: Number(allAlpha.value) };
          document.querySelectorAll('#mwi-settings-dialog .mwi-paste-btn').forEach(b => { b.style.color = '#ff44cc'; setTimeout(() => { b.style.color = '#aaa'; }, 600); });
          allCopy.style.color = '#ff44cc'; setTimeout(() => { allCopy.style.color = '#aaa'; }, 600);
        } catch(e) {}
      });
      // paste button
      const allPaste = document.createElement('button'); allPaste.type = 'button'; allPaste.title = 'Paste color & opacity'; allPaste.textContent = '⏶'; allPaste.classList.add('mwi-push-btn', 'mwi-paste-btn');
      allPaste.style.marginLeft = '2px'; allPaste.style.width = '26px'; allPaste.style.height = '22px'; allPaste.style.borderRadius = '4px'; allPaste.style.border = '1px solid rgba(255,255,255,0.06)'; allPaste.style.background = 'transparent'; allPaste.style.color = '#aaa'; allPaste.style.fontSize = '12px';
      allPaste.addEventListener('click', () => {
        try {
          if (!sharedColorClipboard) return;
          cfg.allColor = sharedColorClipboard.color; cfg.allAlpha = sharedColorClipboard.alpha / 100;
          allInput.value = sharedColorClipboard.color; allAlpha.value = String(sharedColorClipboard.alpha);
          saveSettings(); if (window.MWI_InventoryHighlighter && window.MWI_InventoryHighlighter.reScan) window.MWI_InventoryHighlighter.reScan();
          allPaste.style.color = '#44aaff'; setTimeout(() => { allPaste.style.color = '#aaa'; }, 600);
        } catch(e) {}
      });
      // reset button
      const allReset = document.createElement('button'); allReset.type = 'button'; allReset.title = 'Reset All color to default'; allReset.textContent = '↺'; allReset.classList.add('mwi-push-btn');
      allReset.style.marginLeft = '2px'; allReset.style.width = '26px'; allReset.style.height = '22px'; allReset.style.borderRadius = '4px'; allReset.style.border = '1px solid rgba(255,255,255,0.06)'; allReset.style.background = 'transparent'; allReset.style.color = '#fff';
      allReset.addEventListener('click', () => {
        try {
          if (DEFAULT_CFG && DEFAULT_CFG.allColor) cfg.allColor = DEFAULT_CFG.allColor; else delete cfg.allColor;
          cfg.allAlpha = (DEFAULT_CFG && DEFAULT_CFG.allAlpha !== undefined) ? DEFAULT_CFG.allAlpha : 1;
          try { allInput.value = cfg.allColor || '#1d8ce0'; } catch (e) { allInput.value = '#1d8ce0'; }
          allAlpha.value = String(Math.round((cfg.allAlpha !== undefined ? cfg.allAlpha : 1) * 100));
          saveSettings(); if (window.MWI_InventoryHighlighter && window.MWI_InventoryHighlighter.reScan) window.MWI_InventoryHighlighter.reScan();
        } catch (e) { log('reset all color error', e); }
      });
      allRow.appendChild(allCopy); allRow.appendChild(allPaste); allRow.appendChild(allReset);
      // do not append directly to invSection 窶・will be inserted into the category wrapper
      // (so All replaces Quantity in the same area)

      // Inventory setting: toggle inner curved border (disable the bright inset border)
      const innerRow = document.createElement('div'); innerRow.className = 'mwi-settings-row';
      const innerLabel = document.createElement('label'); innerLabel.textContent = 'Borders'; innerLabel.htmlFor = 'mwi-borders-chk'; innerLabel.style.cursor = 'pointer'; innerLabel.style.flex = '1';
      const innerChk = document.createElement('input'); innerChk.type = 'checkbox'; innerChk.id = 'mwi-borders-chk'; innerChk.checked = !!cfg.showInnerBorder;
      innerChk.addEventListener('change', () => { cfg.showInnerBorder = innerChk.checked; saveSettings(); try { if (window.MWI_InventoryHighlighter && window.MWI_InventoryHighlighter.reScan) window.MWI_InventoryHighlighter.reScan(); } catch (e) {} });
      innerRow.appendChild(innerLabel); innerRow.appendChild(innerChk);
      invSection.appendChild(innerRow);

      // Inventory setting: glow spread
      const spreadRow = document.createElement('div'); spreadRow.className = 'mwi-settings-row';
      const spreadLabel = document.createElement('label'); spreadLabel.textContent = 'Glow'; spreadLabel.style.flex = '1';
      const spreadInput = document.createElement('input'); spreadInput.type = 'number'; spreadInput.value = cfg.glowSpread || 6; spreadInput.min = 0;
      spreadInput.addEventListener('change', () => { cfg.glowSpread = Number(spreadInput.value) || cfg.glowSpread; window.MWI_InventoryHighlighter.setGlowSpread(cfg.glowSpread); saveSettings(); });
      const glowResetBtn = document.createElement('button'); glowResetBtn.type = 'button'; glowResetBtn.title = 'Reset to default'; glowResetBtn.textContent = '↺'; glowResetBtn.classList.add('mwi-push-btn');
      glowResetBtn.style.marginLeft = '2px'; glowResetBtn.style.width = '26px'; glowResetBtn.style.height = '22px'; glowResetBtn.style.borderRadius = '4px'; glowResetBtn.style.border = '1px solid rgba(255,255,255,0.06)'; glowResetBtn.style.background = 'transparent'; glowResetBtn.style.color = '#aaa'; glowResetBtn.style.fontSize = '14px'; glowResetBtn.style.cursor = 'pointer';
      glowResetBtn.addEventListener('click', () => { cfg.glowSpread = DEFAULT_CFG.glowSpread; spreadInput.value = cfg.glowSpread; try { window.MWI_InventoryHighlighter.setGlowSpread(cfg.glowSpread); } catch (e) {} saveSettings(); });
      spreadRow.appendChild(spreadLabel); spreadRow.appendChild(spreadInput); spreadRow.appendChild(glowResetBtn);
      invSection.appendChild(spreadRow);
      try { invSection.insertBefore(innerRow, spreadRow); } catch (e) {}

      // Category editor removed

      // Quantity tiers editor (editable colors for quantity thresholds) as a subcategory of Inventory
      const qtySection = document.createElement('div'); qtySection.className = 'mwi-colors-subsection';
      const qtyTitle = document.createElement('h5'); qtyTitle.textContent = 'Quantity Colors';
      qtySection.appendChild(qtyTitle);
      const qtyList = document.createElement('div'); qtyList.style.marginTop = '6px';

      function renderQuantityEditor(container) {
        container.innerHTML = '';
        const tiers = cfg.collectionQuantityTiers || [];
        if (!tiers.length) {
          const empty = document.createElement('div'); empty.style.fontSize = '12px'; empty.style.color = '#9fb7d7'; empty.textContent = 'No quantity tiers configured.'; container.appendChild(empty); return;
        }
        for (let i = 0; i < tiers.length; i++) {
          try {
            const t = tiers[i];
            const row = document.createElement('div'); row.className = 'mwi-settings-row';
            const lbl = document.createElement('div'); lbl.textContent = '≥ ' + (t.min || 0); lbl.style.flex = '1'; lbl.style.marginRight = '8px';
            const colorInput = document.createElement('input'); colorInput.type = 'color';
            try { colorInput.value = (t.color && String(t.color).trim()) || '#ffffff'; } catch (e) { colorInput.value = '#ffffff'; }
            colorInput.addEventListener('input', () => {
              try { cfg.collectionQuantityTiers[i].color = colorInput.value; saveSettings(); if (window.MWI_InventoryHighlighter && window.MWI_InventoryHighlighter.reScan) window.MWI_InventoryHighlighter.reScan(); } catch (e) { log('quantity color set error', e); }
            });
            row.appendChild(lbl); row.appendChild(colorInput);
            // alpha slider for quantity tier
            const aVal = (t.alpha !== undefined) ? t.alpha : 0.2;
            const alpha = document.createElement('input'); alpha.type = 'range'; alpha.min = 0; alpha.max = 100; alpha.value = String(Math.round(aVal*100)); alpha.style.marginLeft = '8px'; alpha.title = 'Opacity';
            alpha.addEventListener('input', () => {
              try { cfg.collectionQuantityTiers[i].alpha = Number(alpha.value)/100; saveSettings(); if (window.MWI_InventoryHighlighter && window.MWI_InventoryHighlighter.reScan) window.MWI_InventoryHighlighter.reScan(); } catch (e) { log('quantity alpha set error', e); }
            });
            // copy button
            const copyBtn = document.createElement('button'); copyBtn.type = 'button'; copyBtn.title = 'Copy color & opacity'; copyBtn.textContent = '\u2398'; copyBtn.classList.add('mwi-push-btn');
            copyBtn.style.marginLeft = '8px'; copyBtn.style.width = '26px'; copyBtn.style.height = '22px'; copyBtn.style.borderRadius = '4px'; copyBtn.style.border = '1px solid rgba(255,255,255,0.06)'; copyBtn.style.background = 'transparent'; copyBtn.style.color = '#aaa'; copyBtn.style.fontSize = '14px';
            copyBtn.addEventListener('click', () => {
              try {
                sharedColorClipboard = { color: colorInput.value, alpha: Number(alpha.value) };
                document.querySelectorAll('#mwi-settings-dialog .mwi-paste-btn').forEach(b => { b.style.color = '#ff44cc'; setTimeout(() => { b.style.color = '#aaa'; }, 600); });
                copyBtn.style.color = '#ff44cc'; setTimeout(() => { copyBtn.style.color = '#aaa'; }, 600);
              } catch(e) {}
            });
            // paste button
            const pasteBtn = document.createElement('button'); pasteBtn.type = 'button'; pasteBtn.title = 'Paste color & opacity'; pasteBtn.textContent = '⏶'; pasteBtn.classList.add('mwi-push-btn', 'mwi-paste-btn');
            pasteBtn.style.marginLeft = '2px'; pasteBtn.style.width = '26px'; pasteBtn.style.height = '22px'; pasteBtn.style.borderRadius = '4px'; pasteBtn.style.border = '1px solid rgba(255,255,255,0.06)'; pasteBtn.style.background = 'transparent'; pasteBtn.style.color = '#aaa'; pasteBtn.style.fontSize = '12px';
            pasteBtn.addEventListener('click', () => {
              try {
                if (!sharedColorClipboard) return;
                cfg.collectionQuantityTiers[i].color = sharedColorClipboard.color;
                cfg.collectionQuantityTiers[i].alpha = sharedColorClipboard.alpha / 100;
                colorInput.value = sharedColorClipboard.color; alpha.value = String(sharedColorClipboard.alpha);
                saveSettings(); if (window.MWI_InventoryHighlighter && window.MWI_InventoryHighlighter.reScan) window.MWI_InventoryHighlighter.reScan();
                pasteBtn.style.color = '#44aaff'; setTimeout(() => { pasteBtn.style.color = '#aaa'; }, 600);
              } catch(e) {}
            });
            // reset button
            const resetBtn = document.createElement('button'); resetBtn.type = 'button'; resetBtn.title = 'Reset this tier to default'; resetBtn.textContent = '↺'; resetBtn.classList.add('mwi-push-btn');
            resetBtn.style.marginLeft = '2px'; resetBtn.style.width = '26px'; resetBtn.style.height = '22px'; resetBtn.style.borderRadius = '4px'; resetBtn.style.border = '1px solid rgba(255,255,255,0.06)'; resetBtn.style.background = 'transparent'; resetBtn.style.color = '#fff';
            resetBtn.addEventListener('click', () => {
              try {
                if (DEFAULT_CFG && DEFAULT_CFG.collectionQuantityTiers && DEFAULT_CFG.collectionQuantityTiers[i]) {
                  cfg.collectionQuantityTiers[i].color = DEFAULT_CFG.collectionQuantityTiers[i].color;
                  cfg.collectionQuantityTiers[i].alpha = DEFAULT_CFG.collectionQuantityTiers[i].alpha !== undefined ? DEFAULT_CFG.collectionQuantityTiers[i].alpha : aVal;
                } else {
                  cfg.collectionQuantityTiers[i].alpha = aVal;
                }
                try { colorInput.value = (cfg.collectionQuantityTiers[i].color && String(cfg.collectionQuantityTiers[i].color).trim()) || '#ffffff'; } catch (e) {}
                alpha.value = String(Math.round((cfg.collectionQuantityTiers[i].alpha !== undefined ? cfg.collectionQuantityTiers[i].alpha : aVal)*100));
                saveSettings(); if (window.MWI_InventoryHighlighter && window.MWI_InventoryHighlighter.reScan) window.MWI_InventoryHighlighter.reScan();
              } catch (e) { log('reset quantity tier error', e); }
            });
            row.appendChild(alpha); row.appendChild(copyBtn); row.appendChild(pasteBtn); row.appendChild(resetBtn);
            container.appendChild(row);
          } catch (e) {}
        }
      }

      qtySection.appendChild(qtyList);
      renderQuantityEditor(qtyList);

      // Show/hide category vs quantity editors based on selected color mode
      function updateInventoryEditorsVisibility() {
        try {
          const mode = (cfg && cfg.colorMode) || (modeSelect && modeSelect.value) || 'None';
          if (mode === 'Quantity') {
            qtySection.style.display = '';
            allRow.style.display = 'none';
          } else if (mode === 'All') {
            qtySection.style.display = 'none';
            allRow.style.display = '';
          } else {
            qtySection.style.display = 'none';
            allRow.style.display = 'none';
          }
        } catch (e) {}
      }

      // initial visibility
      try { updateInventoryEditorsVisibility(); } catch (e) {}

      // Dev section (preserved keys / debug helpers)
      const devSection = document.createElement('div'); devSection.className = 'mwi-settings-section'; devSection.id = 'mwi-section-dev';
      const devTitle = document.createElement('h4'); devTitle.textContent = 'Dev'; devTitle.style.background = 'linear-gradient(90deg, #ff44cc, #44aaff)'; devTitle.style.webkitBackgroundClip = 'text'; devTitle.style.webkitTextFillColor = 'transparent'; devTitle.style.backgroundClip = 'text';
      devSection.appendChild(devTitle);
      const devList = document.createElement('div'); devList.style.marginTop = '6px';

      // Reset-on-refresh toggle
      try {
        const rrRow = document.createElement('div'); rrRow.className = 'mwi-settings-row';
        const rrLabel = document.createElement('label'); rrLabel.textContent = 'Reset to defaults on refresh';
        const rrChk = document.createElement('input'); rrChk.type = 'checkbox'; rrChk.checked = !!cfg.resetOnRefresh;
        rrChk.addEventListener('change', () => { cfg.resetOnRefresh = rrChk.checked; saveSettings(); });
        rrRow.appendChild(rrLabel); rrRow.appendChild(rrChk);
        devList.appendChild(rrRow);
      } catch (e) {}

      // Debug toggle (simple logger enable)
      try {
        const dRow = document.createElement('div'); dRow.className = 'mwi-settings-row';
        const dLabel = document.createElement('label'); dLabel.textContent = 'Enable debug logging';
        const dChk = document.createElement('input'); dChk.type = 'checkbox'; dChk.checked = !!cfg.debug;
        dChk.addEventListener('change', () => { cfg.debug = dChk.checked; saveSettings(); });
        dRow.appendChild(dLabel); dRow.appendChild(dChk);
        devList.appendChild(dRow);
      } catch (e) {}

      devSection.appendChild(devList);

      // Group Category and Quantity editors under an "Inventory Category" subsection
      const inventoryCategoryWrapper = document.createElement('div');
      inventoryCategoryWrapper.className = 'mwi-settings-section';
      // title removed per request: do not display "Inventory Category" text
      // Category editor removed; include quantity editor and the 'All' picker so
      // they occupy the same subsection and can be toggled (All replaces Quantity)
      inventoryCategoryWrapper.appendChild(qtySection);
      // append allRow (created earlier) into this wrapper so it shares the same area
      try { if (typeof allRow !== 'undefined' && allRow) inventoryCategoryWrapper.appendChild(allRow); } catch (e) {}
      invSection.appendChild(inventoryCategoryWrapper);

      // ensure local ordering now that rows exist
      try { reorderBordersGlow(invSection); } catch (e) {}

      // show/hide editors based on selected mode
      function renderColorsEditor(container) {
        container.innerHTML = '';
        const sc = cfg.siteColors || {};
        const groups = [
          { title: 'Header', fields: [
            { key: 'header', label: 'Header' , hasAlpha: true, alphaKey: 'headerAlpha', defaultAlpha: 0.2},
            { key: 'headerGrad', label: 'Header Gradient', hasAlpha: true, alphaKey: 'headerGradAlpha', defaultAlpha: 1},
            { key: 'progressBar', label: 'Progress Bar', hasAlpha: true, alphaKey: 'progressBarAlpha', defaultAlpha: 1}
          ]},
          { title: 'Combat', fields: [
            { key: 'combat', label: 'Combat', hasAlpha: true, alphaKey: 'combatAlpha', defaultAlpha: 1},
            { key: 'hp', label: 'HP', hasAlpha: true, alphaKey: 'hpAlpha', defaultAlpha: 1},
            { key: 'mp', label: 'MP', hasAlpha: true, alphaKey: 'mpAlpha', defaultAlpha: 1},
            { key: 'hitDmg', label: 'Hitsplat Damage', hasAlpha: true, alphaKey: 'hitDmgAlpha', defaultAlpha: 1},
            { key: 'hitMiss', label: 'Hitsplat Miss', hasAlpha: true, alphaKey: 'hitMissAlpha', defaultAlpha: 1},
            { key: 'attack', label: 'Attack', hasAlpha: true, alphaKey: 'attackAlpha', defaultAlpha: 1},
            { key: 'barBg', label: 'Bar Background', hasAlpha: true, alphaKey: 'barBgAlpha', defaultAlpha: 1}
          ,
            { key: 'consumables', label: 'Consumables / Abilities', hasAlpha: true, alphaKey: 'consumablesAlpha', defaultAlpha: 1}
          ]},
          { title: 'Main Panel', fields: [
            { key: 'subPanel', label: 'Panel' , hasAlpha: true, alphaKey: 'subPanelAlpha', defaultAlpha: 0.2},
            { key: 'skillActions', label: 'Skill Actions', hasAlpha: true, alphaKey: 'skillActionsAlpha', defaultAlpha: 1}
          ]},
          { title: 'Left Side Panel', fields: [
            { key: 'sidePanel', label: 'Panel' , hasAlpha: true, alphaKey: 'sidePanelAlpha', defaultAlpha: 0.2},
            { key: 'selectedSkill', label: 'Selected Skill', hasAlpha: true, alphaKey: 'selectedSkillAlpha', defaultAlpha: 1},
            { key: 'skillXPBar', label: 'Skill XP Bar', hasAlpha: true, alphaKey: 'skillXPBarAlpha', defaultAlpha: 1},
            { key: 'navLabel', label: 'Text Color', hasAlpha: true, alphaKey: 'navLabelAlpha', defaultAlpha: 1},
            { key: 'level', label: 'Level Text Color', hasAlpha: true, alphaKey: 'levelAlpha', defaultAlpha: 1}
          ]},
          { title: 'Right Side Panel', fields: [
            { key: 'panelBg', label: 'Panel' , hasAlpha: true, alphaKey: 'panelBgAlpha', defaultAlpha: 0.2},
            { key: 'inventoryLabels', label: 'Inventory Labels', hasAlpha: true, alphaKey: 'inventoryLabelsAlpha', defaultAlpha: 1},
            { key: 'interactables', label: 'Interactables', hasAlpha: true, alphaKey: 'interactablesAlpha', defaultAlpha: 1}
          ]},
          { title: 'Chat', fields: [
            { key: 'chatBg', label: 'Panel' , hasAlpha: true, alphaKey: 'chatBgAlpha', defaultAlpha: 0.2},
            { key: 'timestamp', label: 'Timestamp Color', hasAlpha: true, alphaKey: 'timestampAlpha', defaultAlpha: 1 },
            { key: 'chatText', label: 'Text Color', hasAlpha: true, alphaKey: 'chatTextAlpha', defaultAlpha: 1 },
            { key: 'systemMessage', label: 'System Message', hasAlpha: true, alphaKey: 'systemMessageAlpha', defaultAlpha: 1 }
          ]},
          { title: 'Tabs', fields: [
            { key: 'buttonBg', label: 'Tabs' , hasAlpha: true, alphaKey: 'buttonBgAlpha', defaultAlpha: 1},
            { key: 'tabsBg', label: 'Tabs Background', hasAlpha: true, alphaKey: 'tabsBgAlpha', defaultAlpha: 1},
            { key: 'accent', label: 'Text Color' , hasAlpha: true, alphaKey: 'accentAlpha', defaultAlpha: 1}
          ]}
        ];

        // clipboard for copy/paste between color rows
        // uses sharedColorClipboard from outer scope

        function buildRow(f) {
          try {
            const row = document.createElement('div'); row.className = 'mwi-settings-row';
            const lbl = document.createElement('div'); lbl.textContent = f.label; lbl.style.flex = '1'; lbl.style.marginRight = '8px';
            const colorInput = document.createElement('input'); colorInput.type = 'color';
            try { colorInput.value = (sc[f.key] && String(sc[f.key]).trim()) || '#ffffff'; } catch (e) { colorInput.value = '#ffffff'; }
            colorInput.addEventListener('input', () => {
              try {
                cfg.siteColors = cfg.siteColors || {};
                cfg.siteColors[f.key] = colorInput.value;
                if (f.hasAlpha && f.alphaKey && cfg.siteColors[f.alphaKey] === undefined) cfg.siteColors[f.alphaKey] = (f.defaultAlpha !== undefined ? f.defaultAlpha : 1);
                if (f.key === 'accent') cfg.siteColors.text = colorInput.value;
                try { const rng = row.querySelector('input[type="range"]'); if (rng) { rng.disabled = false; rng.classList.remove('mwi-range-disabled'); } colorInput.classList.remove('mwi-inactive'); } catch(e){}
                applySiteColors(); saveSettings();
              } catch (e) { log('site color set error', e); }
            });
            row.appendChild(lbl); row.appendChild(colorInput);
            if (f.hasAlpha) {
              const alpha = document.createElement('input'); alpha.type = 'range'; alpha.min = 0; alpha.max = 100; alpha.value = String(Math.round((sc[f.alphaKey] !== undefined ? sc[f.alphaKey] : (f.defaultAlpha !== undefined ? f.defaultAlpha : 1)) * 100)); alpha.style.marginLeft = '8px'; alpha.title = 'Opacity';
              alpha.addEventListener('input', () => {
                try { cfg.siteColors = cfg.siteColors || {}; cfg.siteColors[f.alphaKey] = Number(alpha.value)/100; applySiteColors(); saveSettings(); } catch (e) { log('site alpha set error', e); }
              });
              const isActive = sc[f.key] && String(sc[f.key]).trim() !== '';
              if (!isActive) { alpha.disabled = true; alpha.classList.add('mwi-range-disabled'); colorInput.classList.add('mwi-inactive'); }

              // Copy button
              const copyBtn = document.createElement('button'); copyBtn.type = 'button'; copyBtn.title = 'Copy color & opacity'; copyBtn.textContent = '\u2398'; copyBtn.classList.add('mwi-push-btn');
              copyBtn.style.marginLeft = '8px'; copyBtn.style.width = '26px'; copyBtn.style.height = '22px'; copyBtn.style.borderRadius = '4px'; copyBtn.style.border = '1px solid rgba(255,255,255,0.06)'; copyBtn.style.background = 'transparent'; copyBtn.style.color = '#aaa'; copyBtn.style.fontSize = '14px';
              copyBtn.addEventListener('click', () => {
                try {
                  sharedColorClipboard = { color: colorInput.value, alpha: Number(alpha.value) };
                  // Flash all paste buttons to indicate clipboard is ready
                  document.querySelectorAll('#mwi-settings-dialog .mwi-paste-btn').forEach(b => { b.style.color = '#ff44cc'; setTimeout(() => { b.style.color = '#aaa'; }, 600); });
                  copyBtn.style.color = '#ff44cc'; setTimeout(() => { copyBtn.style.color = '#aaa'; }, 600);
                } catch(e) {}
              });

              // Paste button
              const pasteBtn = document.createElement('button'); pasteBtn.type = 'button'; pasteBtn.title = 'Paste color & opacity'; pasteBtn.textContent = '⏶'; pasteBtn.className = 'mwi-paste-btn mwi-push-btn';
              pasteBtn.style.marginLeft = '2px'; pasteBtn.style.width = '26px'; pasteBtn.style.height = '22px'; pasteBtn.style.borderRadius = '4px'; pasteBtn.style.border = '1px solid rgba(255,255,255,0.06)'; pasteBtn.style.background = 'transparent'; pasteBtn.style.color = '#aaa'; pasteBtn.style.fontSize = '12px';
              pasteBtn.addEventListener('click', () => {
                try {
                  if (!sharedColorClipboard) return;
                  cfg.siteColors = cfg.siteColors || {};
                  cfg.siteColors[f.key] = sharedColorClipboard.color;
                  cfg.siteColors[f.alphaKey] = sharedColorClipboard.alpha / 100;
                  if (f.key === 'accent') cfg.siteColors.text = sharedColorClipboard.color;
                  colorInput.value = sharedColorClipboard.color;
                  alpha.value = String(sharedColorClipboard.alpha);
                  colorInput.classList.remove('mwi-inactive'); alpha.disabled = false; alpha.classList.remove('mwi-range-disabled');
                  applySiteColors(); saveSettings();
                  pasteBtn.style.color = '#44aaff'; setTimeout(() => { pasteBtn.style.color = '#aaa'; }, 600);
                } catch(e) {}
              });

              const resetBtn = document.createElement('button'); resetBtn.type = 'button'; resetBtn.title = 'Reset this setting to default'; resetBtn.textContent = '↺'; resetBtn.classList.add('mwi-push-btn');
              resetBtn.style.marginLeft = '2px'; resetBtn.style.width = '26px'; resetBtn.style.height = '22px'; resetBtn.style.borderRadius = '4px'; resetBtn.style.border = '1px solid rgba(255,255,255,0.06)'; resetBtn.style.background = 'transparent'; resetBtn.style.color = '#fff';
              resetBtn.addEventListener('click', () => {
                try {
                  cfg.siteColors = cfg.siteColors || {};
                  const defColor = (DEFAULT_CFG && DEFAULT_CFG.siteColors && DEFAULT_CFG.siteColors[f.key]) ? DEFAULT_CFG.siteColors[f.key] : '';
                  if (defColor) cfg.siteColors[f.key] = defColor; else delete cfg.siteColors[f.key];
                  const defAlpha = (DEFAULT_CFG && DEFAULT_CFG.siteColors && DEFAULT_CFG.siteColors[f.alphaKey] !== undefined) ? DEFAULT_CFG.siteColors[f.alphaKey] : (f.defaultAlpha !== undefined ? f.defaultAlpha : 1);
                  cfg.siteColors[f.alphaKey] = defAlpha;
                  try { if (defColor) colorInput.value = defColor; else colorInput.value = '#ffffff'; } catch(e){}
                  alpha.value = String(Math.round(cfg.siteColors[f.alphaKey]*100));
                  if (defColor) { colorInput.classList.remove('mwi-inactive'); alpha.disabled = false; alpha.classList.remove('mwi-range-disabled'); } else { colorInput.classList.add('mwi-inactive'); alpha.disabled = true; alpha.classList.add('mwi-range-disabled'); }
                  applySiteColors(); saveSettings();
                } catch (e) { log('reset single site color error', e); }
              });
              row.appendChild(alpha); row.appendChild(copyBtn); row.appendChild(pasteBtn); row.appendChild(resetBtn);
            }
            return row;
          } catch (e) { return null; }
        }

        for (let i = 0; i < groups.length; i++) {
          const g = groups[i];
          try {
            const sub = document.createElement('div'); sub.className = 'mwi-colors-subsection';
            const h = document.createElement('h5'); h.textContent = g.title; h.style.background = 'linear-gradient(90deg, #44aaff, #ff44cc)'; h.style.webkitBackgroundClip = 'text'; h.style.webkitTextFillColor = 'transparent'; h.style.backgroundClip = 'text'; sub.appendChild(h);
            // Remove the small separator for the first subsection (Header) so
            // it doesn't display a thin line directly beneath the 'Site Colors' title.
            if (i === 0) {
              try { sub.style.borderTop = 'none'; sub.style.marginTop = '0'; sub.style.paddingTop = '0'; h.style.marginTop = '0'; } catch (e) {}
            }
            for (const f of g.fields) {
              const r = buildRow(f);
              if (r) sub.appendChild(r);
            }
            container.appendChild(sub);
          } catch (e) {}
        }
      }
      const footer = document.createElement('div'); footer.style.marginTop = '12px'; footer.style.textAlign = 'right';

      // Append main sections into the content container so they're visible
      try {
        // ensure the colors list is part of the Colors section and render it
        try { colorsSection.appendChild(colorsList); renderColorsEditor(colorsList); } catch (e) {}
        // Customizer section wraps Themes, Background, Hide/Organize
        try {
          const customizerSection = document.createElement('div'); customizerSection.className = 'mwi-settings-section'; customizerSection.id = 'mwi-section-customizer';
          const customizerTitle = document.createElement('h4'); customizerTitle.textContent = 'Customizer'; customizerTitle.style.background = 'linear-gradient(90deg, #ff44cc, #44aaff)'; customizerTitle.style.webkitBackgroundClip = 'text'; customizerTitle.style.webkitTextFillColor = 'transparent'; customizerTitle.style.backgroundClip = 'text';
          customizerSection.appendChild(customizerTitle);
          customizerSection.appendChild(themesSection);
          customizerSection.appendChild(mwiCfgSection);
          customizerSection.appendChild(bgSection);
          customizerSection.appendChild(hideSection);
          content.appendChild(customizerSection);
        } catch (e) {}
        // Animations section
        try {
          const animSection = document.createElement('div'); animSection.className = 'mwi-settings-section'; animSection.id = 'mwi-section-animations';
          const animTitle = document.createElement('h4'); animTitle.textContent = 'Animations'; animTitle.style.background = 'linear-gradient(90deg, #ff44cc, #44aaff)'; animTitle.style.webkitBackgroundClip = 'text'; animTitle.style.webkitTextFillColor = 'transparent'; animTitle.style.backgroundClip = 'text';
          animSection.appendChild(animTitle);
          // Sitewide animations sub-section
          try {
            const sitewideSub = document.createElement('div'); sitewideSub.className = 'mwi-anim-sub';
            const sitewideSubTitle = document.createElement('h5'); sitewideSubTitle.textContent = 'Sitewide'; sitewideSubTitle.style.cssText = 'font-size:12px;margin:0 0 6px;background:linear-gradient(90deg,#44aaff,#ff44cc);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;';
            sitewideSub.appendChild(sitewideSubTitle);
            animSection.appendChild(sitewideSub);
          } catch (e) {}
          // Combat animations sub-section
          try {
            const combatSub = document.createElement('div'); combatSub.className = 'mwi-anim-sub';
            const combatSubTitle = document.createElement('h5'); combatSubTitle.textContent = 'Combat'; combatSubTitle.style.cssText = 'font-size:12px;margin:0 0 6px;background:linear-gradient(90deg,#44aaff,#ff44cc);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;';
            combatSub.appendChild(combatSubTitle);
            const combatRow = document.createElement('div'); combatRow.className = 'mwi-anim-toggle-row';
            const combatChk = document.createElement('input'); combatChk.type = 'checkbox'; combatChk.id = 'mwi-anim-combat-chk'; combatChk.checked = (cfg.combatAnim !== false);
            const combatLbl = document.createElement('label'); combatLbl.htmlFor = 'mwi-anim-combat-chk'; combatLbl.textContent = 'Hit impact - Inspired by MWI-Hit-Tracker';
            combatChk.addEventListener('change', () => { cfg.combatAnim = combatChk.checked; saveSettings(); });
            combatRow.appendChild(combatChk); combatRow.appendChild(combatLbl); combatSub.appendChild(combatRow);
            // Consumables / Abilities usage animation toggle
            const usageRow = document.createElement('div'); usageRow.className = 'mwi-anim-toggle-row';
            const usageChk = document.createElement('input'); usageChk.type = 'checkbox'; usageChk.id = 'mwi-anim-usage-chk'; usageChk.checked = (cfg.usageAnim !== false);
            const usageLbl = document.createElement('label'); usageLbl.htmlFor = 'mwi-anim-usage-chk'; usageLbl.textContent = 'Consumables / Abilities usage';
            usageChk.addEventListener('change', () => { cfg.usageAnim = usageChk.checked; saveSettings(); });
            usageRow.appendChild(usageChk); usageRow.appendChild(usageLbl); combatSub.appendChild(usageRow);
            animSection.appendChild(combatSub);
          } catch (e) {}
          content.appendChild(animSection);
        } catch (e) {}
        content.appendChild(invSection);
        content.appendChild(colorsSection);
        // include Dev in the scrolling content so it's not frozen
        try { content.appendChild(devSection); } catch (e) {}
      } catch (e) {}

      // Reset button area (centered at very bottom)
      const resetArea = document.createElement('div');
      resetArea.style.marginTop = '12px';
      resetArea.style.textAlign = 'center';
      // Refresh (left) + Reset (right) buttons
      const refreshBtn = document.createElement('button'); refreshBtn.id = 'mwi-settings-refresh'; refreshBtn.textContent = 'Refresh Page';
      refreshBtn.style.background = '#1f7d3d'; refreshBtn.style.color = '#fff'; refreshBtn.style.border = '0'; refreshBtn.style.padding = '8px 12px'; refreshBtn.style.borderRadius = '6px'; refreshBtn.style.marginRight = '8px'; refreshBtn.classList.add('mwi-push-btn');
      refreshBtn.addEventListener('click', () => { try { location.reload(); } catch (e) { log('refresh click error', e); } });

      const resetBtn = document.createElement('button'); resetBtn.id = 'mwi-settings-reset'; resetBtn.textContent = 'Reset to defaults';
      resetBtn.style.background = '#7f1d1d'; resetBtn.style.color = '#fff'; resetBtn.style.border = '0'; resetBtn.style.padding = '8px 12px'; resetBtn.style.borderRadius = '6px'; resetBtn.classList.add('mwi-push-btn');
      resetBtn.addEventListener('click', () => {
        try {
          if (document.getElementById('mwi-reset-confirm')) return;
          const conf = document.createElement('div'); conf.id = 'mwi-reset-confirm';
          conf.style.position = 'absolute'; conf.style.left = '50%'; conf.style.top = '50%';
          conf.style.transform = 'translate(-50%, -50%)'; conf.style.zIndex = 10000003;
          conf.style.background = '#071019'; conf.style.color = '#e6eef8'; conf.style.padding = '14px';
          conf.style.borderRadius = '8px'; conf.style.boxShadow = '0 8px 24px rgba(0,0,0,0.6)'; conf.style.width = '420px';

          const msg = document.createElement('div'); msg.style.marginBottom = '12px'; msg.style.fontSize = '13px';
          msg.textContent = 'Reset to defaults? This will clear your saved settings and then reload the page.';
          const btnRow = document.createElement('div'); btnRow.style.textAlign = 'right';
          const cancel = document.createElement('button'); cancel.textContent = 'Cancel'; cancel.style.marginRight = '8px';
          cancel.addEventListener('click', () => { try { conf.remove(); } catch (e) {} });
          const confirmNow = document.createElement('button'); confirmNow.textContent = 'Reset & Refresh';
          confirmNow.style.background = '#7f1d1d'; confirmNow.style.color = '#fff'; confirmNow.style.border = '0'; confirmNow.style.padding = '8px 12px'; confirmNow.style.borderRadius = '6px';
          confirmNow.addEventListener('click', () => {
            try {
              // Clear persisted settings, restore defaults in memory, persist, and reload.
              clearSettings();
              for (const k of Object.keys(DEFAULT_CFG)) {
                try { cfg[k] = JSON.parse(JSON.stringify(DEFAULT_CFG[k])); } catch (e) { cfg[k] = DEFAULT_CFG[k]; }
              }
              saveSettings();
              // Remove confirmation box and hide overlay before reload to avoid UI races
              try { conf.remove(); } catch (e) {}
              try { if (typeof animateClose === 'function') animateClose(); else if (overlay && overlay.style) overlay.style.display = 'none'; } catch (e) {}
              // Use a short timeout to allow the storage to flush in some browsers
              setTimeout(() => { try { location.reload(); } catch (e) { log('reload after reset failed', e); } }, 50);
            } catch (e) { log('confirm reset error', e); }
          });

          btnRow.appendChild(cancel); btnRow.appendChild(confirmNow);
          conf.appendChild(msg); conf.appendChild(btnRow);
          overlay.appendChild(conf);
        } catch (e) { log('reset modal error', e); }
      });
      resetArea.appendChild(refreshBtn);
      resetArea.appendChild(resetBtn);

      dialog.appendChild(closeBtn); dialog.appendChild(title); dialog.appendChild(notice); dialog.appendChild(searchWrap); dialog.appendChild(content); dialog.appendChild(footer);
      dialog.appendChild(resetArea);
      // signature footer (frozen, not part of scrollable content)
      try {
        const sig = document.createElement('div');
        sig.style.marginTop = '8px'; sig.style.fontSize = '12px'; sig.style.color = '#99b7d9'; sig.style.textAlign = 'center';
        sig.textContent = 'Maintained by ave (MWI username: collar)';
        // Links row: GitHub | Greasy Fork
        const links = document.createElement('div');
        links.style.marginTop = '6px'; links.style.fontSize = '12px'; links.style.color = '#99b7d9'; links.style.textAlign = 'center';
        const gh = document.createElement('a'); gh.href = 'https://github.com/collaring/mwi-customizer'; gh.textContent = 'GitHub'; gh.target = '_blank'; gh.style.cssText = 'color:#9ecbff;margin:0 8px;text-decoration:none;transition:color 200ms ease;background-clip:text;-webkit-background-clip:text;';
        const gfHoverStyle = 'background:linear-gradient(90deg,#44aaff,#ff44cc);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;color:transparent;';
        const ghHoverStyle = gfHoverStyle;
        gh.addEventListener('mouseenter', () => { gh.style.cssText += ghHoverStyle; });
        gh.addEventListener('mouseleave', () => { gh.style.cssText = 'color:#9ecbff;margin:0 8px;text-decoration:none;transition:color 200ms ease;'; });
        const sep = document.createElement('span'); sep.textContent = '|'; sep.style.color = '#6f8fa3'; sep.style.margin = '0 4px';
        const gf = document.createElement('a'); gf.href = 'https://greasyfork.org/en/scripts/570632-mwi-customizer'; gf.textContent = 'Greasy Fork'; gf.target = '_blank'; gf.style.cssText = 'color:#9ecbff;margin:0 8px;text-decoration:none;transition:color 200ms ease;';
        gf.addEventListener('mouseenter', () => { gf.style.cssText += gfHoverStyle; });
        gf.addEventListener('mouseleave', () => { gf.style.cssText = 'color:#9ecbff;margin:0 8px;text-decoration:none;transition:color 200ms ease;'; });
        const sep2 = document.createElement('span'); sep2.textContent = '|'; sep2.style.color = '#6f8fa3'; sep2.style.margin = '0 4px';
        const dc = document.createElement('a'); dc.href = 'https://discord.com/channels/891160051459436574/1485148839743721513'; dc.textContent = 'Discord'; dc.target = '_blank'; dc.style.cssText = 'color:#9ecbff;margin:0 8px;text-decoration:none;transition:color 200ms ease;';
        dc.addEventListener('mouseenter', () => { dc.style.cssText += gfHoverStyle; });
        dc.addEventListener('mouseleave', () => { dc.style.cssText = 'color:#9ecbff;margin:0 8px;text-decoration:none;transition:color 200ms ease;'; });
        const sep3 = document.createElement('span'); sep3.textContent = '|'; sep3.style.color = '#6f8fa3'; sep3.style.margin = '0 4px';
        const ws = document.createElement('a'); ws.href = 'https://ave.sh/'; ws.textContent = 'Website'; ws.target = '_blank'; ws.style.cssText = 'color:#9ecbff;margin:0 8px;text-decoration:none;transition:color 200ms ease;';
        ws.addEventListener('mouseenter', () => { ws.style.cssText += gfHoverStyle; });
        ws.addEventListener('mouseleave', () => { ws.style.cssText = 'color:#9ecbff;margin:0 8px;text-decoration:none;transition:color 200ms ease;'; });
        links.appendChild(gh); links.appendChild(sep); links.appendChild(gf); links.appendChild(sep2); links.appendChild(dc); links.appendChild(sep3); links.appendChild(ws);
        dialog.appendChild(sig); dialog.appendChild(links);
      } catch (e) {}
      overlay.appendChild(dialog); document.body.appendChild(overlay);
      // post-append safety: ensure ordering once dialog rows are inserted
      try {
        setTimeout(() => reorderBordersGlow(document.getElementById('mwi-settings-dialog')), 0);
        // compact observer: watch for row insertions and run reorder once
        const dlg = document.getElementById('mwi-settings-dialog');
        if (dlg) {
          const mo = new MutationObserver(() => { try { reorderBordersGlow(dlg); mo.disconnect(); } catch (e) {} });
          mo.observe(dlg, { childList: true, subtree: true });
        }
      } catch (e) {}
      
    }

    // close modal on Escape key when it's open; prefer closing organize/share modals first
    document.addEventListener('keydown', (ev) => {
      try {
        if (ev.key === 'Escape' || ev.key === 'Esc') {
            // close organize modal first (if open)
            const org = document.getElementById('mwi-organize-overlay');
            if (org) { try { org.classList.remove('mwi-organize-open'); org.classList.add('mwi-organize-closing'); setTimeout(() => { try { org.remove(); } catch (e) {} }, 200); } catch (e) {} return; }
            // then share/import modal
            const share = document.getElementById('mwi-share-modal-overlay');
            if (share) { try { share.classList.remove('mwi-share-open'); share.classList.add('mwi-share-closing'); setTimeout(() => { try { share.remove(); } catch (e) {} }, 200); } catch (e) {} return; }
            // finally close the main settings overlay (animate)
            const ov = document.getElementById('mwi-settings-overlay');
            if (ov && ov.style && ov.style.display === 'flex') {
              try { ov.classList.remove('mwi-dialog-open'); ov.classList.add('mwi-dialog-closing'); } catch (e) {}
              setTimeout(() => { try { ov.style.display = 'none'; ov.classList.remove('mwi-dialog-closing'); } catch (e) {} }, 220);
            }
        }
      } catch (e) {}
    });

    function openSettings() {
      try {
        // Always remove existing overlay and recreate modal so event handlers
        // (like the custom reset confirmation) are the current ones.
        const existing = document.getElementById('mwi-settings-overlay');
        if (existing) existing.remove();
        createSettingsModal();
        const ov = document.getElementById('mwi-settings-overlay');
        if (ov) {
          ov.style.display = 'flex';
          applyUIStyle();
          // trigger pop-in animation
            setTimeout(() => { try { ov.classList.add('mwi-dialog-open'); } catch (e) {} }, 10);
        }
      } catch (e) { log('openSettings error', e); }
    }


    function findFilterContainer() {
      const selectors = ['.item-filter', '.filter', '.ItemFilter', '[data-filter]', '.filters', '.controls'];
      for (const s of selectors) {
        const el = document.querySelector(s);
        if (el) return el;
      }
      // fallback: try inventory container header or rightmost toolbar
      const alt = document.querySelector('.Inventory_inventory__17CH2') || document.body;
      return alt;
    }

    function insertSettingsButton() {
      try {
        injectStyles(); createSettingsModal();
      // Prefer the item grid placement if available
      const grid = document.querySelector('.Inventory_itemGrid__20YAH');
      if (grid) {
        // ensure parent is positioned so absolute placement works
        const parent = grid.parentElement || grid;
        try {
          const cs = window.getComputedStyle(parent);
          if (cs.position === 'static' || !cs.position) parent.style.position = 'relative';
        } catch (e) {}
        const btn = document.createElement('button'); btn.id = 'mwi-settings-btn'; btn.title = 'MWI Customizer Settings'; btn.textContent = '\u2699 MWI Customizer';
        btn.setAttribute('aria-label', 'MWI Customizer Settings');
        btn.style.position = 'absolute'; btn.style.right = '8px'; btn.style.top = '8px'; btn.style.zIndex = 9999999;
        btn.addEventListener('click', openSettings);
        // append to parent so it sits over the grid on the far right
        parent.appendChild(btn);
        applyUIStyle();
        return;
      }

      const container = findFilterContainer();
      if (!container) return;
        // prefer adding to a toolbar-like area; if the found container is large, attach to its parent
        let target = container;
        if (container.tagName && container.tagName.toLowerCase() === 'body') {
          // place fixed near right edge if no filter container found
          const btn = document.createElement('button'); btn.id = 'mwi-settings-btn'; btn.title = 'MWI Customizer Settings'; btn.textContent = '\u2699 MWI Customizer';
          btn.style.position = 'fixed'; btn.style.right = '12px'; btn.style.bottom = '12px'; btn.style.zIndex = 9999999;
          btn.addEventListener('click', openSettings);
          document.body.appendChild(btn); applyUIStyle(); return;
        }
        // try to append next to container
        const btn = document.createElement('button'); btn.id = 'mwi-settings-btn'; btn.title = 'MWI Customizer Settings'; btn.textContent = '\u2699 MWI Customizer';
        btn.addEventListener('click', openSettings);
        // if container is inline/toolbar, append as child; otherwise append to its parent
        try { container.appendChild(btn); } catch (e) { container.parentElement && container.parentElement.appendChild(btn); }
      } catch (e) { log('insertSettingsButton error', e); }
    }

  // Main init
  (async function init() {
    log('Starting highlighter');
    // Wait a bit for game globals to initialize
    await waitFor(() => document.readyState === 'complete', 10000).catch(() => null);

    let colors = discoverCollectionColors();
    if (!(colors && (colors.hridMap && colors.hridMap.size || colors.nameMap && colors.nameMap.size))) {
      log('No collection-color map auto-detected. You may need to provide the game URL or DOM details.');
    }

    // initial highlight
    highlightInventory(colors);

    // observe DOM changes to re-run lightweight highlighting with debounce
    let pendingHighlightTimer = null;
    const observer = new MutationObserver(() => {
      try {
        if (pendingHighlightTimer) clearTimeout(pendingHighlightTimer);
        pendingHighlightTimer = setTimeout(() => {
          try { colors = discoverCollectionColors(); highlightInventory(colors); } catch (e) { log('debounced highlight error', e); }
          pendingHighlightTimer = null;
        }, 250);
      } catch (e) {}
    });
    observer.observe(document.body, { childList: true, subtree: true });

    // Try to insert the settings button once the inventory grid exists (or fallback immediately)
    // Also re-scan now that the grid is rendered so colors apply on first load
    try {
      await waitFor(() => document.querySelector('.Inventory_itemGrid__20YAH'), 10000, 250);
      colors = discoverCollectionColors();
      highlightInventory(colors);
    } catch (e) {}
    insertSettingsButton();
    hookCombatWS();
    try { hookUsageAnim(); } catch (e) {}

    // Re-insert the settings button if React ever removes it during a re-render.
    // Uses the existing body MutationObserver (observer) — piggyback a debounced check.
    let btnWatchTimer = null;
    const btnObserver = new MutationObserver(() => {
      try {
        if (btnWatchTimer) return; // already scheduled
        btnWatchTimer = setTimeout(() => {
          btnWatchTimer = null;
          try {
            if (!document.getElementById('mwi-settings-btn')) {
              log('Settings button missing — reinserting');
              insertSettingsButton();
            }
          } catch (e) {}
        }, 300);
      } catch (e) {}
    });
    btnObserver.observe(document.body, { childList: true, subtree: true });

    // expose for debugging / manual refresh
    window.MWI_InventoryHighlighter = {
      reScan: () => { try { if (pendingHighlightTimer) { clearTimeout(pendingHighlightTimer); pendingHighlightTimer = null; } colors = discoverCollectionColors(); highlightInventory(colors); } catch (e) { log('reScan error', e); } return colors; },
      highlightInventory: () => highlightInventory(colors),
      // runtime setter for glow spread (px) and re-run
      setGlowSpread: function(px) { try { cfg.glowSpread = Number(px) || cfg.glowSpread; highlightInventory(colors); saveSettings(); return cfg.glowSpread; } catch (e) { return null; } },
      setGlowBlur: function(px) { try { cfg.glowBlur = Number(px) || cfg.glowBlur; highlightInventory(colors); saveSettings(); return cfg.glowBlur; } catch (e) { return null; } },
      setGlowAlpha: function(a) { try { cfg.glowAlpha = Number(a); if (isNaN(cfg.glowAlpha)) cfg.glowAlpha = 0.08; highlightInventory(colors); saveSettings(); return cfg.glowAlpha; } catch (e) { return null; } },
      setBgAlpha: function(a) { try { cfg.bgAlpha = Number(a); if (isNaN(cfg.bgAlpha)) cfg.bgAlpha = 0.06; highlightInventory(colors); saveSettings(); return cfg.bgAlpha; } catch (e) { return null; } },
      // persistence helpers
      saveSettings: saveSettings,
      loadSettings: loadSettings,
      clearSettings: clearSettings,
      colors
    };

    log('MWI Inventory Highlighter ready. Use window.MWI_InventoryHighlighter.reScan() to refresh.');
  })();

})();