Map-Making Folders

Advanced tag organization and folder system for map-making.app

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Map-Making Folders
// @icon         https://img.icons8.com/?size=200&id=3509&format=png&color=ffffff
// @namespace    https://map-making.app/
// @version      8.6.2
// @description  Advanced tag organization and folder system for map-making.app
// @author       Youri Auski
// @match        https://map-making.app/*
// @grant        none
// @require      https://cdnjs.cloudflare.com/ajax/libs/lz-string/1.5.0/lz-string.min.js
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  const getMapId = () => { const m = location.pathname.match(/\/maps\/([^/?#]+)/); return m ? m[1] : null; };
  const SK = () => `mmapp_v6_${getMapId() || 'global'}`;

  let S = { folders: [], lastUpdate: 0 };
  let isDirty = false;

  function escapeHTML(str) {
    return str.replace(/[&<>'"]/g, tag => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#39;', '"': '&quot;' }[tag] || tag));
  }

  const setDirty = (state) => {
    isDirty = state;
    const btn = document.getElementById('mm-folder-save-btn');
    if (btn) {
      if (state) {
        btn.classList.add('mm-btn-dirty');
        btn.innerHTML = '<span class="button__label">Save Folders</span>';
      } else {
        btn.classList.remove('mm-btn-dirty');
        btn.innerHTML = '<span class="button__label">Folders Saved</span>';
      }
    }
  };

  const loadS = () => {
    try {
      const r = localStorage.getItem(SK());
      if (r) S = { folders: [], lastUpdate: 0, ...JSON.parse(r) };
      setDirty(false);
    } catch (_) {}
  };

  const saveS = (markDirty = true) => {
    try {
      invalidateFlatCache();
      S.lastUpdate = Date.now();
      localStorage.setItem(SK(), JSON.stringify(S));
      if (markDirty) setDirty(true);
    } catch (_) {}
  };

  const waitDOM = (selector, root = document, timeout = 6000) => {
    return new Promise(resolve => {
      const existing = root.querySelector(selector);
      if (existing) return resolve(existing);
      const obs = new MutationObserver(() => {
        const el = root.querySelector(selector);
        if (el) { obs.disconnect(); resolve(el); }
      });
      obs.observe(root, { childList: true, subtree: true });
      setTimeout(() => { obs.disconnect(); resolve(null); }, timeout);
    });
  };

  const uid = () => Math.random().toString(36).slice(2, 8) + Math.random().toString(36).slice(2, 8);

  const hexToRgb = h => {
    const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(h);
    return m ? [parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16)] : [100, 100, 200];
  };

  const lerp = (h1, h2, t) => {
    const a = hexToRgb(h1), b = hexToRgb(h2);
    return `rgb(${Math.round(a[0] + (b[0] - a[0]) * t)},${Math.round(a[1] + (b[1] - a[1]) * t)},${Math.round(a[2] + (b[2] - a[2]) * t)})`;
  };

  const lum = c => {
    const v = (c.startsWith('#') ? hexToRgb(c) : c.match(/\d+/g)?.map(Number)) || [128, 128, 128];
    return (0.299 * v[0] + 0.587 * v[1] + 0.114 * v[2]) / 255;
  };

  const textOn = bg => lum(bg) > 0.45 ? '#111' : '#fff';

  const rgbToHex = rgb => {
    if (!rgb) return '#ffffff';
    if (rgb.startsWith('#')) return rgb;
    const m = rgb.match(/\d+/g);
    if (!m || m.length < 3) return '#ffffff';
    return '#' + m.slice(0, 3).map(n => parseInt(n).toString(16).padStart(2, '0')).join('');
  };

  let _flatCache = null;
  let _flatCacheDirty = true;
  let _allTagsCache = null;

  const invalidateFlatCache = () => { _flatCacheDirty = true; _allTagsCache = null; };

  const _flatRaw = (l = S.folders) => l.flatMap(f => [f, ..._flatRaw(f.children || [])]);

  const flat = () => {
    if (_flatCacheDirty || !_flatCache) { _flatCache = _flatRaw(S.folders); _flatCacheDirty = false; }
    return _flatCache;
  };

  const getAssignedTags = () => {
    if (!_allTagsCache) _allTagsCache = new Set(flat().flatMap(f => f.tags || []));
    return _allTagsCache;
  };

  let recentPresets = [];
  try { recentPresets = JSON.parse(localStorage.getItem('mmapp_recent_presets') || '[]'); } catch (_) {}

  const saveRecentPreset = p => {
    recentPresets = recentPresets.filter(r => r.name !== p.name);
    recentPresets.unshift(p);
    if (recentPresets.length > 4) recentPresets.length = 4;
    localStorage.setItem('mmapp_recent_presets', JSON.stringify(recentPresets));
  };

  const GRADIENT_PRESETS = [
    // =====================================================================
    // REDS & FLAMES / ROUGES & FLAMMES (25)
    // =====================================================================
    { name: 'Volcanic Rouge Red',           colors: ['#1a0000', '#8b1a00', '#ff4500', '#ffaa00'] },
    { name: 'Ember Rouge Red',              colors: ['#2d0000', '#c0392b', '#e74c3c', '#f39c12'] },
    { name: 'Magma Flow Rouge Red',         colors: ['#0d0000', '#3d0000', '#9b2335', '#ff6b35', '#ffd700'] },
    { name: 'Inferno Rouge Red',            colors: ['#120000', '#4a0000', '#aa1100', '#ff4400', '#ffaa00', '#ffff00'] },
    { name: 'Phoenix Rouge Red',            colors: ['#1a0000', '#7d0000', '#c0392b', '#e67e22', '#f1c40f'] },
    { name: 'Campfire Rouge Red',           colors: ['#1a0a00', '#7a2800', '#e85d04', '#f4a261', '#ffcb77'] },
    { name: 'Red Giant Rouge Red',          colors: ['#100000', '#400000', '#a00000', '#ff4400', '#ffaa00'] },
    { name: 'Sunset Blaze Rouge Red',       colors: ['#1a0028', '#8b0050', '#cc2200', '#ff7700', '#ffdd00'] },
    { name: 'Hot Coals Rouge Red',          colors: ['#1c0a00', '#5c1a00', '#cc3300', '#ff7700'] },
    { name: 'Cinnabar Glow Rouge Red',      colors: ['#6a0010', '#e03020', '#f89060'] },
    { name: 'Dark Rust Rouge Red',          colors: ['#1a0800', '#600800', '#c02800'] },
    { name: 'Kiln Rouge Red',               colors: ['#200000', '#602000', '#d45500', '#f08020'] },
    { name: 'Crimson Tide Rouge Red',       colors: ['#180008', '#660020', '#cc0030', '#ff4060'] },
    { name: 'Forge Rouge Red',              colors: ['#0d0000', '#3a0a00', '#aa4400', '#dd7722', '#ffaa44'] },
    { name: 'Lava Lamp Rouge Red',          colors: ['#1a0028', '#ff0066', '#ff6600', '#ffcc00'] },
    { name: 'Ruby Depths Rouge Red',        colors: ['#0a0005', '#400010', '#900030', '#d00050', '#ff6080'] },
    { name: 'Pomegranate Rouge Red',        colors: ['#3a0010', '#880030', '#cc2040', '#e87880'] },
    { name: 'Blood Moon Rouge Red',         colors: ['#0a0000', '#3a0800', '#8a1a10', '#c84030', '#e88060'] },
    { name: 'Chili Rouge Red',              colors: ['#2a0000', '#7a1000', '#c03000', '#e06020', '#f0a060'] },
    { name: 'Molten Rouge Red',             colors: ['#0a0000', '#4a0800', '#c03000', '#f06000', '#ffb030'] },
    { name: 'Garnet Rouge Red',             colors: ['#300010', '#800030', '#c00050', '#e04080', '#f890b0'] },
    { name: 'Carnelian Rouge Red',          colors: ['#3a0808', '#9a2808', '#d05020', '#e88050', '#f8c0a0'] },
    { name: 'Rage Rouge Red',               colors: ['#1a0000', '#6a0000', '#cc0000', '#ff4000'] },
    { name: 'Scarlet Smoke Rouge Red',      colors: ['#2a0808', '#802020', '#c05040', '#e09080'] },
    { name: 'Fire & Ice Rouge Red Bleu Blue', colors: ['#cc0000', '#ff6600', '#ffffff', '#0066ff', '#0000cc'] },

    // =====================================================================
    // GREENS / VERTS (15)
    // =====================================================================
    { name: 'Jungle Canopy Vert Green',     colors: ['#0a1a00', '#1a4000', '#2d7020', '#60a840', '#a0d060'] },
    { name: 'Emerald Night Vert Green',     colors: ['#020a04', '#0a5828', '#30c878'] },
    { name: 'Spring Meadow Vert Green',     colors: ['#102800', '#2a6010', '#50a030', '#90d060', '#d0f890'] },
    { name: 'Fern Hollow Vert Green',       colors: ['#0a2010', '#1a5028', '#30a050', '#70d080', '#c0f0a0'] },
    { name: 'Pine Resin Vert Green',        colors: ['#0a1a08', '#1a3808', '#307020', '#60b040', '#a0d880'] },
    { name: 'Malachite Vert Green',         colors: ['#001a08', '#006030', '#00c860', '#40e888', '#a0ffc0'] },
    { name: 'Radioactive Vert Green',       colors: ['#001000', '#004000', '#00a000', '#80ff00', '#ccff80'] },
    { name: 'Acid Rain Vert Green',         colors: ['#001008', '#004020', '#00c060', '#80ff40', '#ccff00'] },
    { name: 'Cyber Green Vert Green',       colors: ['#001008', '#002a18', '#007040', '#00cc80', '#00ff88'] },
    { name: 'Circuit Vert Green',           colors: ['#001808', '#003818', '#006030', '#00a050', '#00e880'] },
    { name: 'Absinthe Vert Green',          colors: ['#0a1800', '#2a5000', '#60a000', '#a0d020', '#d0f060'] },
    { name: 'Sage Meadow Vert Green',       colors: ['#1a2808', '#3a5820', '#6a9040', '#9ab860', '#c8e090'] },
    { name: 'Dark Fern Vert Green',         colors: ['#0a180a', '#207020', '#50b050'] },
    { name: 'Forest Amber Vert Green Jaune Yellow', colors: ['#1a2008', '#385820', '#a89020'] },

    // =====================================================================
    // BLUES / BLEUS (10)
    // =====================================================================
    { name: 'Deep Dive Bleu Blue',          colors: ['#000510', '#001a40', '#003070', '#0060aa', '#00aacc'] },
    { name: 'Pacific Bleu Blue',            colors: ['#001020', '#003050', '#006688', '#00aabb', '#00ddee'] },
    { name: 'Wave Break Bleu Blue',         colors: ['#002040', '#004080', '#0080c0', '#40c0e0', '#c0f0ff'] },
    { name: 'Electric Blue Bleu Blue',      colors: ['#000520', '#000880', '#0040ff', '#00ccff', '#80ffff'] },
    { name: 'Cobalt Night Bleu Blue',       colors: ['#030510', '#081888', '#4070e8'] },
    { name: 'Lapis Bleu Blue',              colors: ['#000830', '#001870', '#0040c0', '#3070e0', '#7090ff'] },
    { name: 'Nordic Bleu Blue',             colors: ['#0a1820', '#183060', '#306098', '#5898d8', '#90c8f0'] },

    // =====================================================================
    // YELLOWS & GOLDS / JAUNES & ORS (15)
    // =====================================================================
    { name: 'Gold Jaune Yellow',            colors: ['#2a1800', '#8a5800', '#d0a000', '#f0d040', '#fff8c0'] },
    { name: 'Saffron Jaune Yellow',         colors: ['#3a1000', '#aa4000', '#e08000', '#f8c000', '#fff080'] },
    { name: 'Honey Jaune Yellow',           colors: ['#3a1800', '#9a5000', '#e09020', '#f8c840', '#fff8a0'] },
    { name: 'Summer Noon Jaune Yellow',     colors: ['#fff9c4', '#fff176', '#ffee58', '#fdd835', '#f9a825'] },
    { name: 'Sulfur Jaune Yellow',          colors: ['#1a1800', '#5a5000', '#c0a800', '#f0d800', '#ffffa0'] },
    { name: 'Pyrite Jaune Yellow',          colors: ['#2a2000', '#6a5010', '#c0a020', '#e8c840', '#f8f080'] },
    { name: 'Butterscotch Jaune Yellow',    colors: ['#3a1808', '#a05818', '#d09038', '#f0c860', '#fff8c0'] },
    { name: 'Caramel Jaune Yellow Marron Brown', colors: ['#2a1000', '#8a4010', '#d08030', '#e8c070', '#f8f0c0'] },
    { name: 'Sunbaked Jaune Yellow',        colors: ['#4a2800', '#9a5010', '#d08030', '#f0b060', '#f8e0a0'] },
    { name: 'Deco Gold Jaune Yellow',       colors: ['#1a1200', '#5a4200', '#c09000', '#e8c840', '#f8f0c0'] },
    { name: 'Harvest Moon Jaune Yellow',    colors: ['#1a0800', '#7a3000', '#c07020', '#e0a840', '#f8d880'] },
    { name: 'Topaz Jaune Yellow',           colors: ['#201000', '#703000', '#d08000', '#f0c040', '#fff0a0'] },
    { name: 'Smoked Gold Jaune Yellow',     colors: ['#3a3020', '#9a8830', '#e8d060'] },
    { name: 'Brass Jaune Yellow Marron Brown', colors: ['#a08020', '#c8a840', '#e8c870'] },
    { name: 'Solar Flare Jaune Yellow Rouge Red', colors: ['#ff0000', '#ff6600', '#ffcc00'] },

    // =====================================================================
    // PURPLES & VIOLETS / VIOLETS (15)
    // =====================================================================
    { name: 'Amethyst Violet Purple',       colors: ['#1a0028', '#4a0080', '#8800cc', '#cc66ff', '#f0ccff'] },
    { name: 'Nebula Violet Purple',         colors: ['#0a0020', '#300060', '#6000c0', '#c040e0', '#ff80ff'] },
    { name: 'Vaporwave Violet Purple',      colors: ['#1a0040', '#6600cc', '#cc00aa', '#ff0066', '#ff6600'] },
    { name: 'Retrowave Violet Purple',      colors: ['#080018', '#200050', '#800080', '#ff00ff', '#ff8800'] },
    { name: 'Quasar Violet Purple',         colors: ['#080010', '#280040', '#7800c0', '#c040ff', '#ff80dd'] },
    { name: 'Andromeda Violet Purple',      colors: ['#080018', '#180040', '#400088', '#8800cc', '#dd66ff'] },
    { name: 'Synthwave Violet Purple',      colors: ['#0a0020', '#2a0060', '#cc00ff', '#ff0099', '#ff6600'] },
    { name: 'Plasma Violet Purple',         colors: ['#080018', '#4000a0', '#c000ff', '#ff00cc', '#ffaa00'] },
    { name: 'Orchid Dusk Violet Purple',    colors: ['#1a1028', '#8838b8', '#e888e0'] },
    { name: 'Deep Wisteria Violet Purple',  colors: ['#1a0838', '#7850b0', '#d0b0e8'] },
    { name: 'Night Bloom Violet Purple',    colors: ['#0a0818', '#380858', '#a840c8', '#f090f0'] },
    { name: 'Berry Smoke Violet Purple',    colors: ['#280830', '#8a2870', '#e060c0'] },
    { name: 'Dusk Periwinkle Violet Purple', colors: ['#2a2848', '#8088d0', '#d0d8f8'] },
    { name: 'Plum Amber Violet Purple Jaune Yellow', colors: ['#2a0830', '#7a2860', '#e09030'] },
    { name: 'Ink Bloom Violet Purple',      colors: ['#0a0818', '#4a2060', '#c870d0'] },

    // =====================================================================
    // PINKS & ROSES / ROSES (10)
    // =====================================================================
    { name: 'Cherry Blossom Rose Pink',     colors: ['#fce4ec', '#f8bbd0', '#f48fb1', '#f06292', '#ec407a'] },
    { name: 'Cotton Candy Rose Pink',       colors: ['#ffb3c6', '#ffc6e0', '#e8c0f8', '#c0d0ff', '#b8f0ff'] },
    { name: 'Sakura Rose Pink',             colors: ['#fae0e8', '#f8c8d8', '#f0a8c0', '#e888a8', '#e07090'] },
    { name: 'Hot Pink Rose Pink',           colors: ['#200010', '#800050', '#ff0080', '#ff88cc', '#ffc0ff'] },
    { name: 'Raspberry Rose Pink',          colors: ['#2a0018', '#880040', '#d80068', '#f840a0', '#ff90cc'] },
    { name: 'Bubblegum Rose Pink',          colors: ['#ff99bb', '#ff99ee', '#cc99ff', '#99bbff', '#99ffee'] },
    { name: 'Hibiscus Rose Pink',           colors: ['#3a0018', '#a01840', '#e84880', '#f890b8', '#ffd0e0'] },
    { name: 'Rose Quartz Rose Pink',        colors: ['#3a1428', '#a04870', '#e080a8', '#f8c0d0', '#fff0f5'] },
    { name: 'Dreamsicle Rose Pink Orange',  colors: ['#ffe0c0', '#ffcc99', '#ffaa88', '#ff8899', '#ff66bb'] },
    { name: 'Blush Marble Rose Pink',       colors: ['#e8c8c8', '#f8e8e0', '#fff8f5'] },

    // =====================================================================
    // ORANGES (10)
    // =====================================================================
    { name: 'Terracotta Orange',            colors: ['#7a2810', '#c05030', '#e08050', '#f0b090', '#f8d8c0'] },
    { name: 'Mesa Orange',                  colors: ['#2a1000', '#7a3810', '#c07030', '#e0b060', '#f0d8a0'] },
    { name: 'Indian Summer Orange',         colors: ['#2a1000', '#8a4000', '#e07818', '#f8b840', '#fff8c0'] },
    { name: 'Jasper Orange',                colors: ['#8a3818', '#c86830', '#f0b888'] },
    { name: 'Tangerine Smoke Orange',       colors: ['#2a1a10', '#e08820'] },
    { name: 'Mango Orange',                 colors: ['#3a1800', '#c06010', '#f09030', '#f8c860', '#fff0b0'] },
    { name: 'Rust Belt Orange',             colors: ['#2a1200', '#8b3a00', '#c46a1a', '#e8a030'] },
    { name: 'Bronze Orange Marron Brown',   colors: ['#1a0800', '#6a3000', '#b07020', '#e0b050', '#f8e090'] },

    // =====================================================================
    // TEALS & CYANS / CYANS (12)
    // =====================================================================
    { name: 'Aurora Borealis Cyan',         colors: ['#000a20', '#003030', '#00aa88', '#00ff80', '#88ffcc'] },
    { name: 'Bioluminescent Cyan',          colors: ['#000820', '#001540', '#003366', '#00aaff', '#00ffcc'] },
    { name: 'Tide Pool Cyan',               colors: ['#0a1a2a', '#1a4060', '#2a8080', '#40c0b0', '#a0f0e0'] },
    { name: 'Blue Lagoon Cyan',             colors: ['#001a30', '#007070', '#00c0a0', '#80f0e0'] },
    { name: 'Sea Glass Cyan',               colors: ['#2a5050', '#50a090', '#80d0c0', '#c0f0e8'] },
    { name: 'Tidal Surge Cyan',             colors: ['#000810', '#002050', '#0060b0', '#20b0f0', '#a0ffff'] },
    { name: 'Peacock Ore Cyan',             colors: ['#001010', '#003838', '#006868', '#40a8c0', '#80e8ff'] },
    { name: 'Ion Storm Cyan',               colors: ['#000820', '#002060', '#0080ff', '#00ffcc', '#80ffff'] },
    { name: 'Tidal Pool Cyan',              colors: ['#0a2020', '#2a7878', '#80d8d0', '#d0f8f8'] },
    { name: 'Tourmaline Cyan Vert Green',   colors: ['#001820', '#005840', '#00a860', '#60e880', '#ccffcc'] },
    { name: 'Laser Grid Cyan',              colors: ['#000810', '#001840', '#00a0ff', '#00ffaa'] },

    // =====================================================================
    // BROWNS & EARTH TONES / MARRONS & TERRES (13)
    // =====================================================================
    { name: 'Espresso Marron Brown',        colors: ['#0a0500', '#2a1008', '#5a2810', '#8a5020', '#c09040'] },
    { name: 'Mocha Marron Brown',           colors: ['#1a0808', '#4a2010', '#8a4820', '#c08050', '#e8b890'] },
    { name: 'Sepia Marron Brown',           colors: ['#1a1000', '#5a4010', '#a08030', '#d0b870', '#f0e8c0'] },
    { name: 'Canyon Marron Brown',          colors: ['#3a1000', '#8a3010', '#c06020', '#e0a060', '#f0d0a0'] },
    { name: 'Redwood Marron Brown',         colors: ['#1a0800', '#5a1800', '#a04020', '#c07848', '#d8b090'] },
    { name: 'Ochre Marron Brown Jaune Yellow', colors: ['#3a2800', '#8a6010', '#d0a020', '#f0d050', '#f8f0c0'] },
    { name: 'Adobe Marron Brown',           colors: ['#6a3018', '#b07050', '#d0a880', '#e8d0b8'] },
    { name: 'Walnut Sage Marron Brown Vert Green', colors: ['#3a2010', '#6a4a20', '#90a870'] },
    { name: 'Cognac Marron Brown',          colors: ['#3a1000', '#8a3a10', '#d07030', '#f0c080'] },
    { name: 'Mahogany Marron Brown',        colors: ['#2a0808', '#6a1818', '#c06848', '#e8c0a0'] },
    { name: 'Tiger Eye Marron Brown Jaune Yellow', colors: ['#3a1800', '#8a4800', '#d08020', '#e8b860', '#f8e0a0'] },
    { name: 'Smoked Amber Marron Brown Jaune Yellow', colors: ['#3a3020', '#b09030', '#e8d060'] },
    { name: 'Western Marron Brown',         colors: ['#3a1a08', '#8a5020', '#c08840', '#e0b870', '#f0ddb0'] },

    // =====================================================================
    // MIXED DUOS / MÉLANGES INÉDITS
    // =====================================================================
    { name: 'Copper Teal Marron Brown Cyan', colors: ['#5a2800', '#a06030', '#408080', '#40c0c0'] },
    { name: 'Mocha Blue Marron Brown Bleu Blue', colors: ['#3a1808', '#8a5030', '#2050a0', '#4090e0'] },
    { name: 'Earth Sky Marron Brown Bleu Blue', colors: ['#6a3810', '#c09040', '#408888', '#80c8e0'] },
    { name: 'Bark Violet Marron Brown Violet Purple', colors: ['#5a3020', '#a07050', '#7040a0', '#c080e0'] },
    { name: 'Rust Cyan Orange Cyan',        colors: ['#9a2800', '#e06020', '#20a0a0', '#60f0e0'] },
    { name: 'Coffee Mint Marron Brown Vert Green', colors: ['#3a1808', '#8a5020', '#20a060', '#80e0b0'] },
    { name: 'Umber Teal Marron Brown Cyan', colors: ['#4a2808', '#9a6030', '#1a7878', '#40c0b8'] },
    { name: 'Bronze Cerulean Marron Brown Bleu Blue', colors: ['#6a3000', '#b07020', '#2060c0', '#60a0ff'] },
    { name: 'Caramel Azure Jaune Yellow Bleu Blue', colors: ['#c07820', '#e0b040', '#2080c0', '#80c8ff'] },
    { name: 'Clay Indigo Marron Brown Violet Purple', colors: ['#8a4020', '#d08050', '#2020a0', '#6060e0'] },
    { name: 'Coral Turquoise Rose Pink Cyan', colors: ['#e05050', '#f09080', '#20b0b0', '#60f0e0'] },
    { name: 'Gold Violet Jaune Yellow Violet Purple', colors: ['#c09000', '#e8c030', '#6020a0', '#c060e0'] },
    { name: 'Jade Amber Vert Green Jaune Yellow', colors: ['#1a7850', '#40c888', '#c89020', '#f0d040'] },
    { name: 'Navy Saffron Bleu Blue Jaune Yellow', colors: ['#0a1848', '#2858c8', '#e0a000', '#f8d840'] },
    { name: 'Magenta Lime Rose Pink Vert Green', colors: ['#c00060', '#f040a0', '#60c000', '#b0f000'] },
    { name: 'Aqua Peach Cyan Orange',       colors: ['#0a9090', '#40e0d0', '#e08050', '#f8c090'] },
    { name: 'Midnight Gold Noir Black Jaune Yellow', colors: ['#0a0808', '#1a1018', '#c08000', '#f0d040'] },
    { name: 'Green Burgundy Vert Green Rouge Red', colors: ['#1a4820', '#40a850', '#7a0820', '#c04060'] },
    { name: 'Arctic Ember Bleu Blue Rouge Red', colors: ['#c8e8f8', '#80c0e8', '#e85020', '#ff8040'] },
    { name: 'Forest Crimson Vert Green Rouge Red', colors: ['#0a2808', '#308030', '#880020', '#d04060'] },
    { name: 'Slate Lime Gris Gray Vert Green', colors: ['#3a4050', '#606880', '#a0c820', '#d0f050'] },
    { name: 'Charcoal Teal Gris Gray Cyan', colors: ['#1a2020', '#404848', '#10a090', '#40e0d0'] },
    { name: 'Plum Gold Violet Purple Jaune Yellow', colors: ['#2a0840', '#7820a0', '#c09000', '#f0c830'] },
    { name: 'Smoke Coral Gris Gray Orange', colors: ['#504850', '#909090', '#e07050', '#f8b090'] },
    { name: 'Ice Magma Bleu Blue Rouge Red', colors: ['#a0d0f8', '#4090e8', '#0020a0', '#d04000', '#ff8000'] },

    // =====================================================================
    // GALAXIES & COSMOS (10)
    // =====================================================================
    { name: 'Pulsar Violet Purple Bleu Blue', colors: ['#000820', '#001840', '#0040a0', '#00aaff', '#80ffff'] },
    { name: 'Stardust Violet Purple',       colors: ['#080010', '#200030', '#580060', '#9040a0', '#e0a0e0'] },
    { name: 'Binary Star Bleu Blue Jaune Yellow', colors: ['#000820', '#00204a', '#0080c0', '#ff8800', '#ffdd00'] },
    { name: 'Event Horizon Violet Purple',  colors: ['#000000', '#100020', '#300060', '#700090', '#aa00cc'] },
    { name: 'Dark Matter Violet Purple',    colors: ['#050005', '#100020', '#200040', '#400080'] },
    { name: 'Solar Wind Violet Purple',     colors: ['#0a0818', '#2a1040', '#6040c0', '#c0a0ff', '#ffd0ff'] },
    { name: 'Cosmic Dust Violet Purple',    colors: ['#0a0820', '#180840', '#380868', '#680890', '#a838b8'] },
    { name: 'Zodiac Violet Purple Rouge Red', colors: ['#0a0010', '#200040', '#4000a0', '#9000d0', '#f000f0', '#ff6600'] },
    { name: 'Supernova Bleu Blue',          colors: ['#000820', '#002040', '#0060a0', '#40b0ff', '#ffffff'] },
    { name: 'Wormhole Violet Purple',       colors: ['#000000', '#1a0030', '#5000a0', '#b040ff', '#ffffff'] },

    // =====================================================================
    // NEON & CYBERPUNK (8)
    // =====================================================================
    { name: 'Neon City Violet Purple Rouge Red', colors: ['#080010', '#2000a0', '#8000ff', '#ff00aa', '#ff6600'] },
    { name: 'Hologram Bleu Blue Violet Purple', colors: ['#001840', '#00a0ff', '#00ffee', '#ff00ee', '#ff8800'] },
    { name: 'Glitch Vert Green Violet Purple', colors: ['#000808', '#003000', '#00ff00', '#ff00ff', '#00ffff'] },
    { name: 'UV Violet Purple',             colors: ['#0a0020', '#3000a0', '#8000ff', '#cc80ff', '#ffffff'] },
    { name: 'Laser Cut Bleu Blue Cyan',     colors: ['#000010', '#0000a0', '#0080ff', '#00ffcc', '#ffffff'] },
    { name: 'Power Grid Bleu Blue Cyan',    colors: ['#000008', '#000040', '#001080', '#00a0ff', '#ccffff'] },
    { name: 'Night Market Violet Purple Rose Pink', colors: ['#080818', '#201040', '#602080', '#c060c0', '#f0a0e0'] },
    { name: 'Phase Shift Violet Purple Cyan', colors: ['#0a0028', '#4000c0', '#cc00ff', '#00ccff', '#ccffff'] },

    // =====================================================================
    // PASTELS & SOFT / PASTELS & DOUX (7)
    // =====================================================================
    { name: 'Macaron Rose Pink Vert Green', colors: ['#f9d5e5', '#fce4c5', '#d4f5e9', '#cfe4f7', '#e9d5f0'] },
    { name: 'Baby Blues Bleu Blue',         colors: ['#e0eeff', '#c8d8ff', '#a8c0ff', '#88a8ff', '#6888ff'] },
    { name: 'Sherbet Jaune Yellow Rose Pink', colors: ['#fff0c0', '#ffe0a0', '#ffc0a0', '#ffa0c0', '#e0a0e0'] },
    { name: 'Cloud Drift Bleu Blue',        colors: ['#f0f8ff', '#e0f0ff', '#d0e8ff', '#c0d8f8', '#b0c8f0'] },
    { name: 'Spearmint Cream Vert Green',   colors: ['#e0fff0', '#d0f8e8', '#c0f0e0', '#b0e8d8', '#a0d8d0'] },
    { name: 'Lilac Mist Violet Purple',     colors: ['#ece0ff', '#f0d8ff', '#f8d0ff', '#ffd0f0', '#ffe0e8'] },
    { name: 'Morning Mist Vert Green Bleu Blue', colors: ['#f8f0ff', '#e8e8ff', '#d8f0ff', '#c8f8f0', '#d0ffd8'] },

    // =====================================================================
    // EARTH & DESERTS / TERRES & DÉSERTS (7)
    // =====================================================================
    { name: 'Sahara Marron Brown Jaune Yellow', colors: ['#2a1800', '#8a5010', '#d09030', '#f0d070', '#f8f0d0'] },
    { name: 'Red Rock Rouge Red Marron Brown', colors: ['#2a0a00', '#6a2000', '#b05020', '#d09060', '#e8c8a0'] },
    { name: 'Dust Storm Marron Brown',      colors: ['#4a3828', '#9a8060', '#d0b888', '#f0e0c8'] },
    { name: 'Gobi Jaune Yellow Marron Brown', colors: ['#3a3020', '#7a7040', '#b8b070', '#e0d8a0', '#f8f5e0'] },
    { name: 'Flint Gris Gray',              colors: ['#2a2a28', '#585850', '#888880', '#b8b8b0', '#e0e0d8'] },
    { name: 'Petrified Marron Brown',       colors: ['#3a3028', '#7a6850', '#b0a080', '#d8c8a8', '#f0e8d0'] },
    { name: 'Outback Orange Marron Brown',  colors: ['#3a1800', '#9a5010', '#d09030', '#e8c070', '#f8e8c0'] },

    // =====================================================================
    // JEWELS & MINERALS / JOYAUX & MINÉRAUX (19)
    // =====================================================================
    { name: 'Sapphire Bleu Blue',           colors: ['#000820', '#001068', '#0040c0', '#4080ff', '#80b8ff'] },
    { name: 'Emerald Vert Green',           colors: ['#000e08', '#003020', '#007040', '#00c070', '#60e8a0'] },
    { name: 'Ruby Rouge Red',               colors: ['#180000', '#600010', '#cc0030', '#ff4060', '#ff99aa'] },
    { name: 'Opal Multicolore Multicolor',  colors: ['#f0f8ff', '#d0e8ff', '#e0d0ff', '#ffd0e8', '#d0ffe8'] },
    { name: 'Onyx Noir Black',              colors: ['#000000', '#0a0808', '#151010', '#201818', '#2a2020'] },
    { name: 'Alexandrite Violet Purple Vert Green', colors: ['#1a0028', '#6000a0', '#c040e0', '#40d0a0', '#00f0a0'] },
    { name: 'Rhodonite Rose Pink',          colors: ['#2a1020', '#7a3050', '#c05880', '#e898b8', '#f8d0e0'] },
    { name: 'Jade Vert Green',              colors: ['#0a1a10', '#1a5030', '#40a060', '#80cc90', '#c0f0c0'] },
    { name: 'Labradorite Bleu Blue Gris Gray', colors: ['#181820', '#303848', '#506888', '#7098c0', '#a0c8e8'] },
    { name: 'Selenite Blanc White',         colors: ['#d8d0e8', '#e0d8f0', '#e8e0f8', '#f0e8ff', '#f8f4ff'] },
    { name: 'Azurite Bleu Blue',            colors: ['#000a20', '#001848', '#003090', '#2060d0', '#60a0ff'] },
    { name: 'Sodalite Bleu Blue Violet Purple', colors: ['#050820', '#101840', '#201870', '#3030a8', '#5858e0'] },
    { name: 'Agate Rose Pink Gris Gray',    colors: ['#3a1828', '#8a3858', '#c07090', '#e8a8c0', '#f8d8e8'] },
    { name: 'Carnelian Orange Rouge Red',   colors: ['#3a0808', '#9a2808', '#d05020', '#e88050', '#f8c0a0'] },
    { name: 'Cinnabar Rouge Red',           colors: ['#2a0800', '#8a1800', '#cc3000', '#f06040', '#f8b0a0'] },

    // =====================================================================
    // SEASONS & NATURE / SAISONS & NATURE (10)
    // =====================================================================
    { name: 'Autumn Canopy Orange',         colors: ['#1a0800', '#6a2000', '#c06010', '#e0a020', '#f0d060'] },
    { name: 'Winter Frost Bleu Blue',       colors: ['#e8f4ff', '#d0e8ff', '#b8d8ff', '#a0c8ff', '#88b8ff'] },
    { name: 'Spring Thaw Vert Green',       colors: ['#d0e8d0', '#b0d8b0', '#80c880', '#60b880', '#40a870'] },
    { name: 'Late Summer Jaune Yellow Rouge Red', colors: ['#f8e070', '#f0b040', '#e88020', '#e06040', '#c84060'] },
    { name: 'Golden Hour Jaune Yellow Orange', colors: ['#1a0800', '#8a3000', '#e07010', '#f8a030', '#fff0a0'] },
    { name: 'Blue Hour Bleu Blue Violet Purple', colors: ['#0a0820', '#181840', '#302878', '#5050a8', '#8080d0'] },
    { name: 'May Day Vert Green Jaune Yellow', colors: ['#a0e860', '#c8f880', '#f0ff80', '#f8e860', '#f8c840'] },
    { name: 'Deep Winter Bleu Blue',        colors: ['#0a1020', '#182040', '#283060', '#404880', '#6068a0'] },
    { name: 'Birch Grove Marron Brown Vert Green', colors: ['#c8c0a0', '#e0d8b8', '#f0f0e0', '#d0e8c8', '#a0c888'] },
    { name: 'Rainforest Mist Vert Green',   colors: ['#0a1808', '#206030', '#50a060', '#a0d898', '#d0f8c8'] },

    // =====================================================================
    // METALLICS / MÉTALLIQUES (13)
    // =====================================================================
    { name: 'Rose Gold Rose Pink Marron Brown', colors: ['#2a0810', '#8a2840', '#d07070', '#e8a898', '#f8d8d8'] },
    { name: 'Gunmetal Gris Gray Bleu Blue', colors: ['#101518', '#202830', '#304050', '#406070', '#507888'] },
    { name: 'Iridescent Multicolore Multicolor', colors: ['#0040a0', '#00a080', '#80ff80', '#ffd040', '#ff0080'] },
    { name: 'Patina Vert Green Marron Brown', colors: ['#2a4028', '#508060', '#80b890', '#b0d8b8', '#d8f0d8'] },
    { name: 'Burnished Jaune Yellow Marron Brown', colors: ['#2a1800', '#8a5000', '#d09820', '#f0cc60', '#fff8c0'] },
    { name: 'Bismuth Violet Purple Gris Gray', colors: ['#3a3038', '#8070a0', '#c0a8e0', '#f0d8ff', '#ffffff'] },
    { name: 'Pewter Gris Gray',             colors: ['#303838', '#506068', '#708888', '#98b0b0', '#c0d0d0'] },
    { name: 'Chrome Gris Gray',             colors: ['#202020', '#505050', '#909090', '#c8c8c8', '#ffffff'] },
    { name: 'Anodized Bleu Blue',           colors: ['#000838', '#0010a0', '#0090ff', '#80d0ff', '#c0f0ff'] },
    { name: 'Gilded Jaune Yellow Noir Black', colors: ['#080400', '#3a2000', '#9a6000', '#e0a820', '#f8f080'] },
    { name: 'Platinum Gris Gray',           colors: ['#484848', '#787878', '#a8a8a8', '#d0d0d0', '#f0f0f0'] },
    { name: 'Silver Gris Gray',             colors: ['#383838', '#686868', '#989898', '#c8c8c8', '#f0f0f0'] },
    { name: 'Copper Orange Marron Brown',   colors: ['#2a0a00', '#8a3800', '#d07030', '#e8a860', '#f8d0a0'] },

    // =====================================================================
    // MOOD & EMOTION / HUMEUR & ÉMOTION (10)
    // =====================================================================
    { name: 'Serenity Bleu Blue',           colors: ['#e0f0ff', '#c0d8f8', '#a0c0f0', '#80a8e0', '#6090d0'] },
    { name: 'Nostalgia Marron Brown',       colors: ['#a08060', '#c0a878', '#d8c898', '#f0e8c0', '#f8f0d8'] },
    { name: 'Melancholy Bleu Blue Gris Gray', colors: ['#101828', '#283848', '#405870', '#608898', '#90b8c0'] },
    { name: 'Euphoria Violet Purple',       colors: ['#1a0040', '#6000c0', '#cc00ff', '#ff66ff', '#ffccff'] },
    { name: 'Wonder Bleu Blue',             colors: ['#000828', '#002060', '#0060d0', '#40a8ff', '#c0e8ff'] },
    { name: 'Triumph Rouge Red Jaune Yellow', colors: ['#200000', '#800000', '#ff0000', '#ff8800', '#ffff00'] },
    { name: 'Passion Rouge Red',            colors: ['#1a0000', '#6a0010', '#cc0030', '#ff3060', '#ff80a0'] },
    { name: 'Mystery Violet Purple Noir Black', colors: ['#050010', '#150030', '#350060', '#650090', '#9500c0'] },
    { name: 'Joy Multicolore Multicolor',   colors: ['#ff8800', '#ffcc00', '#88ff00', '#00ffcc', '#0088ff'] },
    { name: 'Hope Vert Green Bleu Blue',    colors: ['#c0d8f8', '#a0c0f0', '#80e8c8', '#a0f8a0', '#d0f8d0'] },

    // =====================================================================
    // VINTAGE & RETRO (9)
    // =====================================================================
    { name: '70s Harvest Orange',           colors: ['#5a2800', '#c86810', '#e0a030', '#f8d870', '#fff8e0'] },
    { name: 'Kodachrome Rouge Red Vert Green', colors: ['#9a3020', '#e06830', '#f8a840', '#f8e870', '#a0c8a0'] },
    { name: 'Disco Violet Purple Rouge Red', colors: ['#1a0030', '#6600cc', '#cc0066', '#ff6600', '#ffcc00'] },
    { name: 'Paisley Violet Purple',        colors: ['#2a0840', '#7820a0', '#d050c0', '#f098c0', '#f8d8e8'] },
    { name: 'Daguerreotype Gris Gray',      colors: ['#181818', '#484840', '#787860', '#a8a888', '#d8d8c8'] },
    { name: 'Psychedelic Multicolore Multicolor', colors: ['#1a0040', '#8800ff', '#ff0088', '#ff8800', '#88ff00'] },
    { name: 'Faded Marron Brown Gris Gray', colors: ['#a09888', '#b8b0a0', '#d0c8b8', '#e8e0d0', '#f5f0e8'] },
    { name: 'Art Deco Jaune Yellow Noir Black', colors: ['#0a0800', '#4a3800', '#c8a800', '#f8e840', '#fff8e0'] },

    // =====================================================================
    // INDUSTRIAL & URBAN / INDUSTRIEL & URBAIN (7)
    // =====================================================================
    { name: 'Concrete Gris Gray',           colors: ['#404040', '#606060', '#808080', '#a0a0a0', '#c0c0c0'] },
    { name: 'Asphalt Gris Gray Noir Black', colors: ['#101010', '#202020', '#383838', '#585858', '#787878'] },
    { name: 'Neon Sign Violet Purple Rouge Red', colors: ['#0a0010', '#3000a0', '#aa00ff', '#ff00aa', '#ff8800'] },
    { name: 'Subway Bleu Blue Gris Gray',   colors: ['#101820', '#203040', '#305060', '#408090', '#70a8c0'] },
    { name: 'Oxide Orange Marron Brown',    colors: ['#2a1008', '#7a3810', '#c07030', '#e0b060', '#f0d8b0'] },
    { name: 'Titanium Gris Gray',           colors: ['#383838', '#585858', '#808080', '#a8a8a8', '#d0d0d0'] },
    { name: 'Foundry Orange Noir Black',    colors: ['#100800', '#402000', '#aa5000', '#e09030', '#f8d080'] },

    // =====================================================================
    // WEATHER & ATMOSPHERE / MÉTÉO & ATMOSPHÈRE (9)
    // =====================================================================
    { name: 'Thunderhead Gris Gray Bleu Blue', colors: ['#101820', '#283848', '#406080', '#6088a8', '#a0c0d8'] },
    { name: 'Lightning Bleu Blue Blanc White', colors: ['#050510', '#101030', '#2020a0', '#6060ff', '#ffffff'] },
    { name: 'Rainbow Multicolore Multicolor', colors: ['#ff0000', '#ff8800', '#ffff00', '#00ff00', '#0088ff', '#8800ff'] },
    { name: 'Fog Bank Gris Gray',           colors: ['#202020', '#484848', '#787878', '#a8a8a8', '#d8d8d8'] },
    { name: 'Clear Sky Bleu Blue',          colors: ['#e8f4ff', '#d0e8ff', '#b0d0ff', '#80b0ff', '#5090ff'] },
    { name: 'El Nino Bleu Blue Jaune Yellow', colors: ['#0a2030', '#2060a0', '#50a0d0', '#90d0f0', '#f0f890'] },
    { name: 'Trade Wind Bleu Blue Cyan',    colors: ['#003058', '#006090', '#30a0c8', '#70d0e8', '#c0f0ff'] },
    { name: 'Permafrost Bleu Blue Blanc White', colors: ['#b0d0f0', '#c8e0f8', '#d8ecff', '#e8f4ff', '#f4faff'] },
    { name: 'Sirocco Jaune Yellow Marron Brown', colors: ['#2a2010', '#6a5818', '#b09830', '#d8c060', '#f0e8b0'] },

    // =====================================================================
    // CELESTIAL & SPIRITUAL / CÉLESTE & SPIRITUEL (8)
    // =====================================================================
    { name: 'Mandala Multicolore Multicolor', colors: ['#c00020', '#d06000', '#f0b800', '#60c020', '#0080c0', '#6000c0'] },
    { name: 'Chakra Multicolore Multicolor', colors: ['#cc0000', '#ff8800', '#ffcc00', '#00cc44', '#0044cc', '#6600cc'] },
    { name: 'Solstice Jaune Yellow Rouge Red', colors: ['#1a0800', '#8a4000', '#f0a000', '#f8e040', '#ffffff'] },
    { name: 'Equinox Vert Green',           colors: ['#002010', '#008040', '#00e870', '#80ffb0', '#ffffff'] },
    { name: 'Ether Violet Purple Blanc White', colors: ['#f8f0ff', '#f0e8ff', '#e8e0ff', '#e0d8ff', '#d8d0f8'] },
    { name: 'Astral Violet Purple',         colors: ['#080018', '#2000a0', '#8040ff', '#d080ff', '#ffffff'] },
    { name: 'Transcend Violet Purple Blanc White', colors: ['#1a0028', '#5000aa', '#d000ff', '#ff80ff', '#ffffff'] },

    // =====================================================================
    // CULTURAL & GEOGRAPHIC / CULTUREL & GÉOGRAPHIQUE (7)
    // =====================================================================
    { name: 'Kyoto Orange Marron Brown',    colors: ['#1a0800', '#8a3020', '#d08050', '#f0c090', '#f8e8d0'] },
    { name: 'Marrakech Rouge Red Jaune Yellow', colors: ['#3a0808', '#b84020', '#e89040', '#f8c870', '#f8f0c0'] },
    { name: 'Santorini Bleu Blue Blanc White', colors: ['#0a1848', '#2050a8', '#80b0e8', '#c0d8f8', '#ffffff'] },
    { name: 'Patagonia Bleu Blue Gris Gray', colors: ['#1a2830', '#305870', '#5090b0', '#90c0d8', '#d0e8f0'] },
    { name: 'Amazon Vert Green',            colors: ['#0a1800', '#1a5010', '#30a030', '#70d070', '#b0f8b0'] },
    { name: 'Fjord Bleu Blue',              colors: ['#0a1828', '#1a4060', '#305090', '#4888c8', '#90c0e8'] },
    { name: 'Bengal Rouge Red Orange',      colors: ['#1a0808', '#8a2820', '#d06038', '#f0a870', '#f8d8c0'] },

    // =====================================================================
    // CREATIVE EXTRAS / CRÉATIFS SUPPLÉMENTAIRES
    // =====================================================================
    { name: 'Glasswork Multicolore Multicolor', colors: ['#e0f0ff', '#f0e0ff', '#ffe0f0', '#fff0e0', '#e0ffe0'] },
    { name: 'Entropy Gris Gray Rose Pink',  colors: ['#f8f8f8', '#c0a0a0', '#a0a0c0', '#a0c0a0', '#808080'] },
    { name: 'Umbra Noir Black Gris Gray',   colors: ['#000000', '#080808', '#202020', '#484848', '#808080'] },
    { name: 'Prismatic Multicolore Multicolor', colors: ['#ff0044', '#ff8800', '#ffff00', '#00ff88', '#0088ff', '#8800ff'] },
    { name: 'Anti-Gravity Violet Purple Cyan', colors: ['#0a0018', '#180060', '#4800c0', '#c040ff', '#60ffff'] },
    { name: 'Drift Bleu Blue Blanc White',  colors: ['#c0d8f0', '#d0e8f8', '#e0f4ff', '#f0faff', '#f8fdff'] },
    { name: 'Tectonic Marron Brown Gris Gray', colors: ['#1a1010', '#504030', '#908060', '#c8c0a0', '#e8e8d8'] },
    { name: 'Black Hole Noir Black Violet Purple', colors: ['#000000', '#0a0005', '#200015', '#500030', '#aa0050'] },
    { name: 'Fracture Bleu Blue Gris Gray', colors: ['#101010', '#404060', '#6060a0', '#9090e0', '#e0e0ff'] },
    { name: 'Soldering Iron Jaune Yellow Orange', colors: ['#1a0800', '#6a2000', '#d06010', '#f0b040', '#ffe880'] },
    { name: 'Ink Wash Noir Black Gris Gray', colors: ['#101010', '#303030', '#606060', '#909090', '#c0c0c0'] },
    { name: 'Fresco Marron Brown Bleu Blue', colors: ['#8a7060', '#b8a888', '#d8c8a8', '#e8d8c0', '#f5eedd'] },
    { name: 'Watercolor Bleu Blue Rose Pink', colors: ['#a0c0e8', '#c0d8f0', '#d0e8f8', '#e8d0f0', '#f8c0d8'] },
    { name: 'Stained Glass Multicolore Multicolor', colors: ['#1a0028', '#4400aa', '#0066cc', '#00aa66', '#ccaa00', '#cc2200'] },
    { name: 'Pop Art Rose Pink Bleu Blue',  colors: ['#ff0088', '#ff8800', '#ffff00', '#00ff88', '#0088ff'] },
    { name: 'Minimalist Gris Gray',         colors: ['#f0f0f0', '#e0e0e0', '#c0c0c0', '#a0a0a0'] },
    { name: 'Cobalt Coral Bleu Blue Orange', colors: ['#0a1848', '#2050c0', '#f09080'] },
    { name: 'Coral Reef Bleu Blue Orange',  colors: ['#001830', '#00405a', '#007080', '#50b090', '#ff8844'] },
    { name: 'Highland Moor Marron Brown Gris Gray', colors: ['#201a10', '#504030', '#887858', '#b8a880', '#d8c8a8'] },
    { name: 'Savanna Jaune Yellow Marron Brown', colors: ['#2a2000', '#7a5a10', '#c09030', '#e0c060', '#f0e8a0'] },
    { name: 'Moss Stone Vert Green Gris Gray', colors: ['#1a1a10', '#3a4020', '#606840', '#90a060', '#c0c890'] },
    { name: 'Old Growth Vert Green',        colors: ['#0a1000', '#1a3000', '#304010', '#506020', '#788040'] },
    { name: 'Undergrowth Vert Green',       colors: ['#080e00', '#182808', '#305020', '#507840', '#80a860'] },
    { name: 'Wetland Vert Green Marron Brown', colors: ['#1a2808', '#385820', '#607040', '#90a068', '#c0c898'] },
    { name: 'Tundra Gris Gray Bleu Blue',   colors: ['#c8d8e8', '#a8c0d8', '#88a8c8', '#6888a8', '#486880'] },
    { name: 'Sahel Jaune Yellow Marron Brown', colors: ['#3a2800', '#8a7010', '#d0b040', '#e8d880', '#f8f5d0'] },
    { name: 'Medina Marron Brown Jaune Yellow', colors: ['#2a1808', '#8a5828', '#c0a060', '#e0d0a0', '#f8f0d8'] },
    { name: 'Orinoco Vert Green',           colors: ['#0a1208', '#205030', '#408860', '#70b890', '#b0e8c8'] },
    { name: 'Steppes Vert Green Jaune Yellow', colors: ['#3a3818', '#6a6828', '#a0a040', '#d0d070', '#f0f0a8'] },
    { name: 'Sanctuary Jaune Yellow Marron Brown', colors: ['#1a1810', '#4a4028', '#8a8040', '#c0b870', '#e8e0b0'] },
    { name: 'Sacred Flame Rouge Red Jaune Yellow', colors: ['#1a0000', '#aa2200', '#ff6600', '#ffcc00', '#ffffff'] },
    { name: 'Zenith Bleu Blue Blanc White', colors: ['#000810', '#002060', '#0080c0', '#40c0ff', '#ffffff'] },
    { name: 'Meridian Cyan Blanc White',    colors: ['#002030', '#008888', '#00e8e8', '#80ffff', '#ffffff'] },
    { name: 'Nirvana Bleu Blue Blanc White', colors: ['#d8f0ff', '#e0f0ff', '#e8f4ff', '#f0f8ff', '#f8fcff'] },
    { name: 'Rothko Rouge Red Orange',      colors: ['#3a0808', '#c02020', '#e86020', '#f0a040'] },
    { name: 'Bauhaus Multicolore Multicolor', colors: ['#cc0000', '#0000cc', '#ffcc00', '#2a2a2a'] },
    { name: 'Expressionist Rouge Red Jaune Yellow', colors: ['#1a0808', '#8a2020', '#e06030', '#f8b060', '#f8e0a0'] },
    { name: 'Impressionist Multicolore Multicolor', colors: ['#d0c890', '#a8c8b8', '#88a8d8', '#b888a8', '#d8a888'] },
    { name: 'Polaroid Gris Gray Blanc White', colors: ['#c0c0b8', '#d8d8d0', '#e8e8e0', '#f0f0e8', '#f8f8f8'] },
    { name: 'Victorian Violet Purple Gris Gray', colors: ['#1a0818', '#5a2850', '#9a6890', '#c8a0c0', '#e8d0e0'] },
    { name: 'Nouveau Vert Green Jaune Yellow', colors: ['#182808', '#4a6020', '#80a050', '#c0c888', '#e8e8c0'] },
    { name: 'Rose Gold Jade Rose Pink Vert Green', colors: ['#d07070', '#e8a898', '#408860', '#80c890'] },
    { name: 'Navy Amber Bleu Blue Jaune Yellow', colors: ['#0a1848', '#1a3a80', '#c89030', '#f8d060'] },
    { name: 'Indigo Coral Violet Purple Orange', colors: ['#1a0840', '#5030a0', '#e07060', '#f8b090'] },
    { name: 'Teal Wine Cyan Rouge Red',     colors: ['#1a4040', '#20a090', '#800830', '#c04060'] },
    { name: 'Mint Flame Vert Green Rouge Red', colors: ['#208868', '#60d0a8', '#d04010', '#f07040'] },
    { name: 'Slate Peach Gris Gray Orange', colors: ['#3a4858', '#6888a8', '#e8a870', '#f8d0a8'] },
    { name: 'Lilac Gold Violet Purple Jaune Yellow', colors: ['#8850b8', '#c090e0', '#c09020', '#f0d860'] },
    { name: 'Forest Sunset Vert Green Rouge Red', colors: ['#1a4010', '#407030', '#e07020', '#f8c060'] },

    // =====================================================================
    // NEW / NOUVEAUX — ROUGES & FEUX (20)
    // =====================================================================
    { name: 'Dragon Scale Rouge Red',       colors: ['#1a0000', '#5a0000', '#c00020', '#ff2020', '#ff9040'] },
    { name: 'Wildfire Rouge Red Orange',    colors: ['#200000', '#881000', '#e04000', '#ff8000', '#ffdd00'] },
    { name: 'Lava Crust Rouge Red',         colors: ['#0a0000', '#300000', '#800000', '#cc3300', '#ff6620'] },
    { name: 'Burning Rose Rouge Red Rose Pink', colors: ['#400010', '#a00030', '#e02060', '#f87090', '#ffb8cc'] },
    { name: 'Cherry Coal Rouge Red Noir Black', colors: ['#100000', '#400000', '#8a1020', '#cc3040'] },
    { name: 'Flamethrower Rouge Red Jaune Yellow', colors: ['#1a0000', '#7a1000', '#dd4000', '#ff8800', '#ffe000'] },
    { name: 'Coral Sunset Rouge Red Orange', colors: ['#3a0010', '#aa2820', '#e06040', '#f0a060', '#f8e0b0'] },
    { name: 'Magenta Blaze Rouge Red Violet Purple', colors: ['#200010', '#800040', '#e00080', '#ff40b0', '#ffaae0'] },
    { name: 'War Paint Rouge Red',          colors: ['#120000', '#5a0808', '#a82020', '#d85030'] },
    { name: 'Red Velvet Rouge Red',         colors: ['#1a0008', '#6a0018', '#b81030', '#e06070', '#f8b8c0'] },
    { name: 'Iron Heat Rouge Red Orange',   colors: ['#100000', '#3a0800', '#8a2800', '#d06000', '#f8c000'] },
    { name: 'Habanero Rouge Red Orange',    colors: ['#2a0000', '#8a1000', '#d03000', '#f07000', '#f8a030'] },
    { name: 'Caldera Rouge Red',            colors: ['#080000', '#280000', '#700000', '#c82000', '#ff6000'] },
    { name: 'Rose Flame Rouge Red Rose Pink', colors: ['#2a0018', '#8a0040', '#d03060', '#f06090', '#ffb0c0'] },
    { name: 'Lychee Rouge Red Rose Pink',   colors: ['#3a0010', '#880040', '#d06070', '#f0a0a8', '#f8d8d8'] },
    { name: 'Ember Cave Rouge Red Marron Brown', colors: ['#100400', '#402010', '#8a4020', '#c07040', '#e0a870'] },
    { name: 'Cerise Smoke Rouge Red',       colors: ['#1a0008', '#700028', '#c03050', '#e07080'] },
    { name: 'Torch Rouge Red Jaune Yellow', colors: ['#1a0000', '#600000', '#cc2000', '#f06000', '#ffb800'] },
    { name: 'Sunset Embers Rouge Red Orange Jaune Yellow', colors: ['#0a0000', '#4a0800', '#b04000', '#e08000', '#f8cc00', '#fffff0'] },
    { name: 'Red Shift Rouge Red Violet Purple', colors: ['#050010', '#280040', '#7a0088', '#cc0044', '#ff4000'] },

    // =====================================================================
    // NEW / NOUVEAUX — VERTS (20)
    // =====================================================================
    { name: 'Swamp Vert Green Marron Brown', colors: ['#081008', '#203818', '#406030', '#608850', '#90b870'] },
    { name: 'Chlorophyll Vert Green',       colors: ['#002800', '#007000', '#30c030', '#90f060', '#e0ffa0'] },
    { name: 'Lime Sherbet Vert Green Jaune Yellow', colors: ['#e0ff90', '#c8f870', '#a8f050', '#80e030', '#60c010'] },
    { name: 'Neon Moss Vert Green',         colors: ['#001000', '#003000', '#008800', '#40dd00', '#aaff40'] },
    { name: 'Seagrass Vert Green Cyan',     colors: ['#001808', '#005030', '#00a860', '#50d890', '#b0f8c0'] },
    { name: 'Canopy Glow Vert Green Jaune Yellow', colors: ['#0a1800', '#2a5010', '#50a020', '#90d040', '#d0f890'] },
    { name: 'Poison Ivy Vert Green',        colors: ['#001800', '#005020', '#20a040', '#70e070', '#c8ffc0'] },
    { name: 'Tea Garden Vert Green',        colors: ['#283818', '#4a6828', '#70a040', '#a8c878', '#d8eeb0'] },
    { name: 'Glacier Mint Vert Green Cyan', colors: ['#b0f0d8', '#90e0c8', '#70d0b8', '#50c0a8', '#30b098'] },
    { name: 'Pesto Vert Green Jaune Yellow', colors: ['#283010', '#506028', '#809040', '#b0c068', '#d8e0a0'] },
    { name: 'Green Flash Vert Green',       colors: ['#002000', '#006020', '#00c850', '#60ff90', '#ccffe0'] },
    { name: 'Phytoplankton Vert Green Cyan', colors: ['#002020', '#006050', '#00c888', '#60ffc0', '#ccffee'] },
    { name: 'Cactus Vert Green',            colors: ['#1a2810', '#3a5820', '#609038', '#90c060', '#c8e8a0'] },
    { name: 'Irish Mist Vert Green',        colors: ['#102008', '#306030', '#60a058', '#98c880', '#d0f0b8'] },
    { name: 'Verdigris Vert Green Cyan',    colors: ['#102820', '#308060', '#50c098', '#90e8c8', '#d0fff0'] },
    { name: 'Mangrove Vert Green Marron Brown', colors: ['#101808', '#304028', '#507840', '#80a860', '#b8d8a0'] },
    { name: 'Mojito Vert Green Jaune Yellow', colors: ['#203810', '#508028', '#80c040', '#b8e868', '#e8ffb0'] },
    { name: 'Velvet Moss Vert Green',       colors: ['#0a1200', '#203808', '#407020', '#68a840', '#a0d870'] },

    // =====================================================================
    // NEW / NOUVEAUX — BLEUS (20)
    // =====================================================================
    { name: 'Midnight Ocean Bleu Blue',     colors: ['#000308', '#000818', '#001838', '#003060', '#0060a0'] },
    { name: 'Steel Blue Bleu Blue Gris Gray', colors: ['#101828', '#203858', '#406898', '#6090c0', '#a0c0e8'] },
    { name: 'Arctic Deep Bleu Blue',        colors: ['#000820', '#002050', '#003880', '#006bbf', '#40a0e0'] },
    { name: 'Blue Morpho Bleu Blue',        colors: ['#000520', '#001060', '#0040c0', '#2090f8', '#80d0ff'] },
    { name: 'Ocean Trench Bleu Blue',       colors: ['#000005', '#000015', '#000838', '#001868', '#0038a0'] },
    { name: 'Cerulean Bleu Blue',           colors: ['#001838', '#004888', '#0098e0', '#50c8f8', '#b0eaff'] },
    { name: 'Denim Bleu Blue',              colors: ['#0a1828', '#204060', '#306898', '#5090c0', '#88b8e0'] },
    { name: 'Hydrothermal Bleu Blue Cyan',  colors: ['#000818', '#003060', '#0068b0', '#00b8d0', '#80f0ff'] },
    { name: 'Blueprint Bleu Blue',          colors: ['#000820', '#001848', '#002870', '#00409a', '#3080d0'] },
    { name: 'Ink River Bleu Blue Violet Purple', colors: ['#050010', '#100838', '#280870', '#4820a8', '#8060e0'] },
    { name: 'Frostbite Bleu Blue Blanc White', colors: ['#c8e8ff', '#d8f0ff', '#e8f8ff', '#f0fcff', '#ffffff'] },
    { name: 'Periwinkle Bleu Blue Violet Purple', colors: ['#181848', '#404898', '#6870c8', '#98a8e0', '#d0d8f8'] },
    { name: 'Twilight Sea Bleu Blue Violet Purple', colors: ['#080828', '#181858', '#302898', '#5050c8', '#8890e8'] },
    { name: 'Selene Bleu Blue',             colors: ['#0a0a20', '#182050', '#304898', '#6080d0', '#b0c8f0'] },
    { name: 'Icefield Bleu Blue Blanc White', colors: ['#b8d8f8', '#c8e4ff', '#d8eeff', '#e8f4ff', '#f4f9ff'] },
    { name: 'Neptunian Bleu Blue',          colors: ['#000818', '#001048', '#002890', '#1060c8', '#50a0f0'] },
    { name: 'Blue Flame Bleu Blue Cyan',    colors: ['#000020', '#000880', '#0040ff', '#00c8ff', '#80ffff'] },
    { name: 'Bay Fog Bleu Blue Gris Gray',  colors: ['#a8b8c8', '#c0d0e0', '#d8e8f0', '#e8f0f8', '#f4f8fc'] },
    { name: 'Tidewater Bleu Blue',          colors: ['#001828', '#004060', '#007898', '#30b0d0', '#80d8f0'] },
    { name: 'Starlight Bleu Blue Blanc White', colors: ['#080818', '#182040', '#3840a0', '#7080e0', '#d0d8ff'] },

    // =====================================================================
    // NEW / NOUVEAUX — JAUNES & ORS (20)
    // =====================================================================
    { name: 'Sunflower Jaune Yellow',       colors: ['#3a2000', '#9a6010', '#e0b020', '#f8e040', '#fffbc0'] },
    { name: 'Champagne Jaune Yellow Blanc White', colors: ['#e8d8a0', '#f0e4b8', '#f8f0d8', '#fcf8f0', '#fffff8'] },
    { name: 'Lemon Drop Jaune Yellow',      colors: ['#fffce0', '#fff8c0', '#fff090', '#ffe060', '#ffc820'] },
    { name: 'Wheat Field Jaune Yellow Marron Brown', colors: ['#3a2808', '#8a6818', '#d0a030', '#f0c860', '#f8f0d0'] },
    { name: 'Neon Lemon Jaune Yellow Vert Green', colors: ['#e0ff00', '#c8f000', '#a8e000', '#80c800', '#58a000'] },
    { name: 'Antiqued Gold Jaune Yellow Marron Brown', colors: ['#2a1800', '#6a4808', '#b08830', '#d8c068', '#f0e8b8'] },
    { name: 'Electric Lime Jaune Yellow Vert Green', colors: ['#003000', '#409000', '#a0f000', '#d8ff40', '#f8ffa0'] },
    { name: 'Old Gold Jaune Yellow',        colors: ['#2a2000', '#7a6000', '#c8a820', '#e8d060', '#f8f0c0'] },
    { name: 'Canary Jaune Yellow',          colors: ['#f8f080', '#f8e850', '#f8d820', '#e8c000', '#c8a000'] },
    { name: 'Chartreuse Jaune Yellow Vert Green', colors: ['#303800', '#608000', '#a0c000', '#d0f020', '#e8ff80'] },
    { name: 'Coin Jaune Yellow',            colors: ['#3a2800', '#8a6010', '#d0a820', '#f0d840', '#f8f8d0'] },
    { name: 'Midas Touch Jaune Yellow',     colors: ['#1a0800', '#7a4800', '#d08000', '#f0c020', '#fff8a0'] },
    { name: 'Amber Wave Jaune Yellow Orange', colors: ['#2a1000', '#8a4000', '#d08020', '#f0b840', '#f8e8c0'] },
    { name: 'Vanilla Jaune Yellow Blanc White', colors: ['#f8f0d0', '#f8ecc0', '#f8e8b0', '#f4e098', '#ecd880'] },
    { name: 'Solar Noon Jaune Yellow',      colors: ['#fffff0', '#ffff80', '#ffe820', '#ffc000', '#ff9800'] },
    { name: 'Pollen Jaune Yellow Vert Green', colors: ['#d0e880', '#e0f060', '#f0f840', '#f8f020', '#f8e000'] },
    { name: 'Gilded Rose Jaune Yellow Rose Pink', colors: ['#4a2018', '#a05828', '#e0b860', '#f8d888', '#f8f0c8'] },
    { name: 'Dandelion Jaune Yellow',       colors: ['#f8e870', '#f8d040', '#f8b810', '#e8a000', '#c07000'] },
    { name: 'Vintage Ivory Jaune Yellow Blanc White', colors: ['#f8f4e8', '#f8f0d8', '#f0e8c0', '#e8d8a0', '#d8c880'] },
    { name: 'Harvest Gold Jaune Yellow Orange', colors: ['#2a1400', '#7a4000', '#c08020', '#e8b040', '#f8e090'] },

    // =====================================================================
    // NEW / NOUVEAUX — VIOLETS (20)
    // =====================================================================
    { name: 'Ultraviolet Violet Purple',    colors: ['#050018', '#180060', '#5000c8', '#b000ff', '#e860ff'] },
    { name: 'Mauve Violet Purple Rose Pink', colors: ['#281030', '#703860', '#b07898', '#d8a8c0', '#f0d8e8'] },
    { name: 'Grape Crush Violet Purple',    colors: ['#1a0028', '#600080', '#a040c0', '#d080e0', '#f0c0f8'] },
    { name: 'Twilight Violet Purple Bleu Blue', colors: ['#080028', '#201060', '#502098', '#8048d0', '#c090f0'] },
    { name: 'Elderberry Violet Purple',     colors: ['#150018', '#480048', '#800060', '#c03080', '#e888b8'] },
    { name: 'Dark Orchid Violet Purple',    colors: ['#0a0018', '#300058', '#7800aa', '#c040e0', '#f090ff'] },
    { name: 'Pastel Lavender Violet Purple Blanc White', colors: ['#e0d8f8', '#e8e0ff', '#f0e8ff', '#f8f0ff', '#ffffff'] },
    { name: 'Velvet Violet Purple',         colors: ['#0a0010', '#2a0048', '#6800a8', '#b040e0', '#e880ff'] },
    { name: 'Heliotrope Violet Purple Rose Pink', colors: ['#280030', '#800080', '#d040d0', '#f880f0', '#ffc0ff'] },
    { name: 'Byzantine Violet Purple',      colors: ['#180028', '#500068', '#9000c0', '#d040e8', '#f890ff'] },
    { name: 'Iris Violet Purple Bleu Blue', colors: ['#180030', '#480080', '#7030c0', '#9868e0', '#c0a0f8'] },
    { name: 'Neon Grape Violet Purple',     colors: ['#100020', '#400080', '#9000ff', '#cc60ff', '#ee80ff'] },
    { name: 'Prune Violet Purple',          colors: ['#180018', '#500038', '#880050', '#c06880', '#e8a8b8'] },
    { name: 'Purple Dusk Violet Purple Bleu Blue', colors: ['#080020', '#200858', '#500898', '#8840c8', '#c090e8'] },
    { name: 'Morpho Violet Purple Bleu Blue', colors: ['#080018', '#200058', '#4818a8', '#8060d8', '#c0b0ff'] },
    { name: 'Aubergine Violet Purple',      colors: ['#0a0008', '#300018', '#600038', '#9a4060', '#c88090'] },
    { name: 'Lilac Dream Violet Purple Rose Pink', colors: ['#281838', '#785898', '#c0a0d8', '#e8d0f0', '#f8f0ff'] },
    { name: 'Frozen Violet Violet Purple Bleu Blue', colors: ['#d0d0f8', '#c0c8ff', '#b0c0ff', '#a0b8ff', '#90a8f8'] },

    // =====================================================================
    // NEW / NOUVEAUX — ROSES & PÊCHES (20)
    // =====================================================================
    { name: 'Neon Pink Rose Pink',          colors: ['#200010', '#900050', '#ff00a0', '#ff70d0', '#ffb0e8'] },
    { name: 'Flamingo Rose Pink',           colors: ['#e87878', '#f0a0a0', '#f8c8c0', '#f8e0d8', '#fff0f0'] },
    { name: 'Strawberry Cream Rose Pink',   colors: ['#400020', '#c03060', '#e87898', '#f8b8c0', '#fff0f5'] },
    { name: 'Deep Magenta Rose Pink Violet Purple', colors: ['#1a0010', '#700050', '#c00090', '#e850c0', '#f8a0e0'] },
    { name: 'Blush Peach Rose Pink Orange', colors: ['#f0c8b8', '#f8d8c8', '#f8e4d8', '#f8eee8', '#fff8f5'] },
    { name: 'Peony Rose Pink',              colors: ['#2a0018', '#8a2848', '#d05878', '#f090a8', '#f8d0d8'] },
    { name: 'Dusty Rose Rose Pink',         colors: ['#3a1828', '#8a5060', '#c08898', '#e0b8c0', '#f8e0e8'] },
    { name: 'Nectarine Rose Pink Orange',   colors: ['#e08060', '#f0a070', '#f8c888', '#f8e0a0', '#fff8d0'] },
    { name: 'Electric Rose Rose Pink',      colors: ['#1a0018', '#700060', '#d000a0', '#ff50d0', '#ffa8f0'] },
    { name: 'Cosmo Rose Pink Violet Purple', colors: ['#200020', '#800060', '#d040a0', '#f080d0', '#f8c8f0'] },
    { name: 'Guava Rose Pink Orange',       colors: ['#3a0010', '#a83040', '#e07060', '#f8a888', '#f8d8c8'] },
    { name: 'Ballet Rose Pink',             colors: ['#e8c8d0', '#f0d8e0', '#f8e8f0', '#f8f0f8', '#ffffff'] },
    { name: 'Sunset Rose Rose Pink Orange', colors: ['#2a0010', '#901040', '#e06060', '#f0a080', '#f8e0c0'] },
    { name: 'Powder Rose Pink Blanc White', colors: ['#f0d8e8', '#f8e4f0', '#f8ecf4', '#fef4f8', '#ffffff'] },
    { name: 'Crimson Rose Rouge Red Rose Pink', colors: ['#1a0010', '#700030', '#c02050', '#f06080', '#f8b0c0'] },
    { name: 'Sorbet Rose Pink',             colors: ['#ff99bb', '#ffaacc', '#ffbbdd', '#ffccee', '#ffeeff'] },
    { name: 'Tutti Frutti Rose Pink Multicolore', colors: ['#ff6699', '#ff9966', '#ffcc66', '#ccff66', '#66ccff'] },
    { name: 'Rose Gold Shimmer Rose Pink Jaune Yellow', colors: ['#8a3848', '#c07888', '#e0c0a8', '#f8e0c0', '#f8f4e8'] },
    { name: 'Petal Rose Pink',              colors: ['#f8e8f0', '#f0d0e4', '#e8b8d8', '#d898c0', '#c070a0'] },
    { name: 'Taffy Rose Pink Bleu Blue',    colors: ['#ff99cc', '#ee88ff', '#9988ff', '#88ccff', '#99ffee'] },

    // =====================================================================
    // NEW / NOUVEAUX — ORANGES & AMBERS (20)
    // =====================================================================
    { name: 'Papaya Orange',                colors: ['#3a1400', '#a04800', '#e08020', '#f8b840', '#f8e8a0'] },
    { name: 'Pumpkin Orange',               colors: ['#2a1000', '#8a3800', '#d06818', '#f0a040', '#f8d898'] },
    { name: 'Amber Resin Orange Marron Brown', colors: ['#2a1000', '#8a5020', '#d09030', '#f0c870', '#f8f0d8'] },
    { name: 'Saffron Dusk Orange Jaune Yellow', colors: ['#3a1800', '#a04800', '#e08800', '#f8c820', '#fff880'] },
    { name: 'Apricot Orange Rose Pink',     colors: ['#3a1800', '#a05030', '#e09060', '#f8c090', '#f8e0c8'] },
    { name: 'Sienna Orange Marron Brown',   colors: ['#2a0a00', '#8a3010', '#c06030', '#e09060', '#f8c8a8'] },
    { name: 'Peach Fuzz Orange Rose Pink',  colors: ['#f8d0a0', '#f8e0b8', '#f8e8d0', '#f8f0e8', '#fff8f4'] },
    { name: 'Clementine Orange',            colors: ['#3a0000', '#c03000', '#f07000', '#f8a820', '#f8e080'] },
    { name: 'Sherbet Orange Rose Pink',     colors: ['#f08040', '#f8a868', '#f8c898', '#f8d8b8', '#f8e8d8'] },
    { name: 'Hot Sauce Orange Rouge Red',   colors: ['#2a0000', '#880800', '#d04000', '#f07820', '#f8b850'] },
    { name: 'Marmalade Orange Jaune Yellow', colors: ['#3a0800', '#b04010', '#e08030', '#f8b840', '#f8e880'] },
    { name: 'Amber Alert Orange',           colors: ['#2a0800', '#8a3800', '#e08000', '#f8b020', '#f8f860'] },
    { name: 'Cider Orange Marron Brown',    colors: ['#2a1000', '#7a3808', '#c07828', '#e0a850', '#f0d898'] },
    { name: 'Marigold Orange Jaune Yellow', colors: ['#3a1800', '#a85808', '#e09818', '#f8c840', '#f8f0a0'] },
    { name: 'Tiger Lily Orange',            colors: ['#2a0800', '#9a2800', '#e06020', '#f89050', '#f8c8a8'] },
    { name: 'Neon Orange Orange',           colors: ['#1a0800', '#700000', '#dd4000', '#ff8000', '#ffcc00'] },
    { name: 'Persimmon Orange Rouge Red',   colors: ['#3a0800', '#a02810', '#d85828', '#f09060', '#f8c8a8'] },
    { name: 'Caramel Macchiato Orange Marron Brown', colors: ['#2a1000', '#7a4020', '#c08040', '#e8b870', '#f8e4c0'] },

    // =====================================================================
    // NEW / NOUVEAUX — CYANS & TEALS (20)
    // =====================================================================
    { name: 'Deep Teal Cyan',               colors: ['#001818', '#004848', '#008888', '#30c0b8', '#a0f0e8'] },
    { name: 'Electric Cyan Cyan',           colors: ['#001018', '#003050', '#0080c0', '#00e8ff', '#a0ffff'] },
    { name: 'Mermaid Cyan Vert Green',      colors: ['#001818', '#006050', '#00b888', '#50e8b8', '#b0fff0'] },
    { name: 'Neon Aqua Cyan',               colors: ['#000808', '#002828', '#009090', '#00f0e8', '#80fff8'] },
    { name: 'Marine Phosphor Cyan Bleu Blue', colors: ['#000818', '#002850', '#0060a0', '#20c0e0', '#a0fff8'] },
    { name: 'Submarine Cyan Bleu Blue',     colors: ['#001018', '#003038', '#006070', '#20a0b0', '#70d8e8'] },
    { name: 'Abalone Cyan Multicolore',     colors: ['#b0d8d0', '#b8d0e0', '#c8c8f0', '#d8c0f0', '#e8d0f0'] },
    { name: 'Patina Teal Cyan Vert Green',  colors: ['#102820', '#305040', '#508868', '#80b898', '#b8e0c8'] },
    { name: 'Hummingbird Cyan Vert Green',  colors: ['#002818', '#008060', '#20c0a0', '#80e8d0', '#d0fff8'] },
    { name: 'Caspian Cyan Bleu Blue',       colors: ['#001828', '#005070', '#0090b0', '#40c0d8', '#a0eef8'] },
    { name: 'Spearmint Cyan Vert Green',    colors: ['#003820', '#008050', '#30c888', '#90f8c0', '#d0fff0'] },
    { name: 'Glaucous Cyan Bleu Blue',      colors: ['#183848', '#307088', '#50a8c0', '#80d0e0', '#c0f0f8'] },
    { name: 'Night Aqua Cyan Noir Black',   colors: ['#001010', '#003030', '#006868', '#00c8c8', '#80ffff'] },
    { name: 'Celeste Cyan Blanc White',     colors: ['#b0e8f0', '#c8f0f8', '#d8f8ff', '#eafeff', '#f8ffff'] },
    { name: 'Lagoon Cyan Vert Green',       colors: ['#001820', '#006070', '#20a8a0', '#70d8d0', '#c0fff8'] },
    { name: 'Arcadia Cyan Vert Green',      colors: ['#002010', '#007858', '#30d0a8', '#90f0d8', '#d8fff8'] },
    { name: 'Brine Cyan',                   colors: ['#001018', '#003040', '#006070', '#40a8b8', '#80d8e8'] },
    { name: 'Aquamarine Cyan Vert Green',   colors: ['#002820', '#008070', '#30c8b0', '#80f0e0', '#d0fffc'] },

    // =====================================================================
    // NEW / NOUVEAUX — GRAYS & BLACKS (15)
    // =====================================================================
    { name: 'Graphite Gris Gray',           colors: ['#101010', '#282828', '#484848', '#707070', '#a0a0a0'] },
    { name: 'Storm Cloud Gris Gray Bleu Blue', colors: ['#181828', '#303848', '#506070', '#7898b0', '#a8c8d8'] },
    { name: 'Ash Gris Gray',                colors: ['#202018', '#484838', '#707058', '#989870', '#b8b898'] },
    { name: 'Volcanic Ash Gris Gray',       colors: ['#101010', '#282820', '#484840', '#686858', '#888870'] },
    { name: 'Slate Gris Gray Bleu Blue',    colors: ['#1a2028', '#303848', '#507078', '#7090a0', '#a0b8c0'] },
    { name: 'Moonlight Gris Gray',          colors: ['#282838', '#484858', '#686880', '#9898b0', '#c8c8d8'] },
    { name: 'Flint Spark Gris Gray Jaune Yellow', colors: ['#202020', '#484840', '#909080', '#d0d0c0', '#f8f8d8'] },
    { name: 'Matte Black Noir Black',       colors: ['#0a0a0a', '#141414', '#1e1e1e', '#282828', '#323232'] },
    { name: 'Steel Gris Gray',              colors: ['#202028', '#383840', '#585868', '#808090', '#b0b0c0'] },

    // =====================================================================
    // NEW / NOUVEAUX — WHITES & CREAMS (10)
    // =====================================================================
    { name: 'Pearl Blanc White',            colors: ['#f0f0f8', '#f4f4fc', '#f8f8ff', '#fcfcff', '#ffffff'] },
    { name: 'Cream Blanc White Jaune Yellow', colors: ['#f8f4e0', '#f8f0d8', '#f8ecc8', '#f0e8b8', '#e8e0a8'] },
    { name: 'Parchment Blanc White Marron Brown', colors: ['#f0e8d0', '#e8e0c8', '#e0d8b8', '#d8d0a8', '#d0c898'] },
    { name: 'Ivory Blanc White',            colors: ['#f8f4e8', '#f4f0e0', '#f0ecd8', '#ece8d0', '#e4e0c8'] },
    { name: 'Cloud Blanc White Bleu Blue',  colors: ['#f4f8ff', '#e8f0ff', '#dceaff', '#d0e4ff', '#c4deff'] },
    { name: 'Egret Blanc White Gris Gray',  colors: ['#f8f8f4', '#f0f0ec', '#e8e8e0', '#e0e0d8', '#d8d8d0'] },
    { name: 'Magnolia Blanc White Rose Pink', colors: ['#f8f4f8', '#f4ecf4', '#f0e4f0', '#e8dce8', '#e0d4e0'] },
    { name: 'Frost Blanc White Cyan',       colors: ['#f0f8ff', '#e4f4ff', '#d8f0ff', '#ccecff', '#c0e8ff'] },

    // =====================================================================
    // NEW / NOUVEAUX — COSMIC & SCI-FI (20)
    // =====================================================================
    { name: 'Nebula Core Violet Purple Rose Pink', colors: ['#080018', '#300060', '#8000d0', '#e040e0', '#ff90f0'] },
    { name: 'Cryogenic Bleu Blue Cyan',     colors: ['#000820', '#002060', '#008888', '#40e0e0', '#c0ffff'] },
    { name: 'Xenon Cyan Violet Purple',     colors: ['#000020', '#001060', '#2000c0', '#6000ff', '#00ffff'] },
    { name: 'Plasma Core Violet Purple Jaune Yellow', colors: ['#050010', '#2000a0', '#8800ff', '#ff8800', '#ffff00'] },
    { name: 'Quantum Foam Bleu Blue Violet Purple', colors: ['#000818', '#082070', '#3050b8', '#8090e0', '#e0e0ff'] },
    { name: 'Antimatter Violet Purple Noir Black', colors: ['#000000', '#100020', '#400080', '#9000d0', '#e040ff'] },
    { name: 'Neutron Star Blanc White Bleu Blue', colors: ['#ffffff', '#d0e8ff', '#a0c0ff', '#6088ff', '#2040ff'] },
    { name: 'Parsec Bleu Blue Violet Purple', colors: ['#000010', '#000840', '#0018a0', '#4030e0', '#c080ff'] },
    { name: 'Stellar Nursery Rose Pink Violet Purple', colors: ['#180038', '#600080', '#c040c0', '#f070d0', '#ffc0f0'] },
    { name: 'Hawking Radiation Jaune Yellow Blanc White', colors: ['#1a0800', '#884800', '#f0c000', '#f8f060', '#ffffff'] },
    { name: 'Singularity Violet Purple Noir Black', colors: ['#000000', '#050005', '#150015', '#350035', '#700070'] },
    { name: 'Chromosphere Rouge Red Jaune Yellow', colors: ['#100000', '#4a0000', '#b02000', '#f06000', '#ffe000'] },
    { name: 'Interstellar Bleu Blue',       colors: ['#000008', '#000020', '#001060', '#0040c0', '#20a0ff'] },
    { name: 'Pulsar Wind Cyan Violet Purple', colors: ['#000010', '#001050', '#0080c0', '#c000ff', '#ff80ff'] },
    { name: 'Red Dwarf Rouge Red Marron Brown', colors: ['#0a0000', '#380a00', '#882000', '#c06020', '#e0a070'] },
    { name: 'Cosmic Ray Cyan Blanc White',  colors: ['#001020', '#0040a0', '#00c0f0', '#80f0ff', '#ffffff'] },
    { name: 'Magnetar Violet Purple Cyan',  colors: ['#050015', '#180058', '#5010b0', '#0080ff', '#00ffcc'] },
    { name: 'Space Station Gris Gray Bleu Blue', colors: ['#101828', '#283848', '#406080', '#6090b0', '#90c0d8'] },
    { name: 'Ion Drive Bleu Blue Cyan',     colors: ['#000020', '#002080', '#00a0ff', '#80f0ff', '#ffffff'] },
    { name: 'Dark Nebula Violet Purple',    colors: ['#030005', '#100018', '#280038', '#580068', '#9808a8'] },

    // =====================================================================
    // NEW / NOUVEAUX — NATURE & TERROIR (20)
    // =====================================================================
    { name: 'Volcanic Soil Marron Brown Noir Black', colors: ['#0a0800', '#281808', '#503020', '#885040', '#b08870'] },
    { name: 'Basalt Gris Gray Noir Black',  colors: ['#080808', '#181810', '#282818', '#404030', '#585848'] },
    { name: 'Prairie Wind Vert Green Jaune Yellow', colors: ['#283818', '#508038', '#88b850', '#c0d878', '#e8f0b0'] },
    { name: 'Glacier Bleu Blue Blanc White', colors: ['#c0d8f0', '#d0e8f8', '#e0f0ff', '#f0f8ff', '#f8fcff'] },
    { name: 'Riverbed Marron Brown Gris Gray', colors: ['#1a1808', '#485028', '#788858', '#a8b880', '#d0d8b0'] },
    { name: 'Loam Marron Brown',            colors: ['#201008', '#604028', '#a07050', '#c8a880', '#e8d0b8'] },
    { name: 'Hot Spring Cyan Vert Green',   colors: ['#001818', '#007070', '#20c0b0', '#80f8e0', '#d0fff8'] },
    { name: 'Lichen Vert Green Gris Gray',  colors: ['#202818', '#486040', '#709868', '#a0c098', '#d0e8c8'] },
    { name: 'Tide Flat Gris Gray Cyan',     colors: ['#182028', '#305060', '#508890', '#80b8c8', '#b0d8e8'] },
    { name: 'Kelp Forest Vert Green',       colors: ['#001808', '#005030', '#208060', '#50b890', '#a0e8c8'] },
    { name: 'Bark Marron Brown',            colors: ['#1a0800', '#502010', '#8a4020', '#b06840', '#d09878'] },
    { name: 'Moss Rock Vert Green Gris Gray', colors: ['#181810', '#384830', '#607050', '#90a070', '#c0c8a0'] },
    { name: 'Fossil Gris Gray Marron Brown', colors: ['#2a2820', '#585040', '#888068', '#b0a890', '#d8d0b8'] },
    { name: 'Soil Layer Marron Brown',      colors: ['#100800', '#402810', '#804830', '#b08060', '#d8b898'] },
    { name: 'Creek Bed Bleu Blue Marron Brown', colors: ['#1a2028', '#405060', '#607880', '#88a8b0', '#c0d0d8'] },
    { name: 'Mushroom Marron Brown Gris Gray', colors: ['#2a2018', '#605848', '#988870', '#c0b098', '#e0d8c8'] },
    { name: 'Quartzite Gris Gray Blanc White', colors: ['#c0c0c8', '#d0d0d8', '#e0e0e8', '#f0f0f8', '#f8f8ff'] },
    { name: 'Mineral Spring Cyan Vert Green', colors: ['#001818', '#006858', '#30b8a0', '#80e8d8', '#d0fff8'] },
    { name: 'Dew Drop Vert Green Blanc White', colors: ['#d0f8e0', '#e0f8f0', '#f0fef8', '#f8fffd', '#ffffff'] },
    { name: 'Peat Marron Brown Noir Black',  colors: ['#0a0800', '#201808', '#402818', '#604030', '#885848'] },

    // =====================================================================
    // NEW / NOUVEAUX — FOOD & DRINK (15)
    // =====================================================================
    { name: 'Matcha Vert Green',            colors: ['#283818', '#508040', '#88b868', '#c0d898', '#e8f8c8'] },
    { name: 'Blueberry Violet Purple Bleu Blue', colors: ['#0a0818', '#281840', '#502880', '#7850a8', '#b0a0d0'] },
    { name: 'Raspberry Jam Rouge Red Rose Pink', colors: ['#1a0008', '#700030', '#c84060', '#f08098', '#f8c0d0'] },
    { name: 'Dark Chocolate Marron Brown Noir Black', colors: ['#0a0400', '#200c00', '#401808', '#682010', '#902818'] },
    { name: 'Mint Chocolate Vert Green Marron Brown', colors: ['#101808', '#305828', '#60a848', '#90d870', '#c0f8a0'] },
    { name: 'Lavender Honey Violet Purple Jaune Yellow', colors: ['#302848', '#708098', '#c0b8d8', '#e8d890', '#f8f0b8'] },
    { name: 'Espresso Cream Marron Brown Blanc White', colors: ['#180800', '#603818', '#c09858', '#e8d0a0', '#f8f0e0'] },
    { name: 'Mango Lassi Orange Jaune Yellow', colors: ['#3a1400', '#b05818', '#e8a840', '#f8d880', '#fff8d0'] },
    { name: 'Grenadine Rouge Red Orange',   colors: ['#2a0000', '#900000', '#e04000', '#f88020', '#ffc860'] },
    { name: 'Pistachio Vert Green Jaune Yellow', colors: ['#2a3818', '#607048', '#98a870', '#c8d0a0', '#e8f0d0'] },
    { name: 'Blue Cheese Bleu Blue Gris Gray', colors: ['#3a3848', '#6a7080', '#a0a8c0', '#c8d0e0', '#e8ecf8'] },
    { name: 'Sour Apple Vert Green Jaune Yellow', colors: ['#183800', '#409810', '#80d820', '#c0f840', '#e8ff90'] },
    { name: 'Black Sesame Noir Black Gris Gray', colors: ['#101010', '#201818', '#382820', '#504030', '#686050'] },
    { name: 'Pomelo Rose Pink Jaune Yellow', colors: ['#f8e8c0', '#f8d8a8', '#f8c890', '#f8a878', '#f8806a'] },
    { name: 'Tahini Jaune Yellow Marron Brown', colors: ['#3a2808', '#8a6820', '#c0a848', '#d8c890', '#f0e8d0'] },

    // =====================================================================
    // NEW / NOUVEAUX — ABSTRACT & ARTISTIC (20)
    // =====================================================================
    { name: 'Chiaroscuro Noir Black Blanc White', colors: ['#000000', '#181818', '#606060', '#b8b8b8', '#ffffff'] },
    { name: 'Negative Space Noir Black Blanc White', colors: ['#080808', '#303030', '#787878', '#d0d0d0', '#f8f8f8'] },
    { name: 'Oxidized Copper Orange Vert Green', colors: ['#1a0800', '#7a3818', '#b06020', '#408060', '#60a888'] },
    { name: 'Neon Void Violet Purple Cyan', colors: ['#000008', '#000030', '#0000c0', '#8000ff', '#00ffff'] },
    { name: 'Thermal Scan Bleu Blue Rouge Red', colors: ['#000040', '#0030a0', '#008888', '#a04000', '#ff2000'] },
    { name: 'Pixel Burn Violet Purple Orange', colors: ['#050010', '#280060', '#9800ff', '#ff8000', '#ffff00'] },
    { name: 'Glitch Art Rose Pink Bleu Blue', colors: ['#ff0088', '#ff0000', '#0000ff', '#00ffff', '#ffffff'] },
    { name: 'Infrared Rouge Red Jaune Yellow', colors: ['#000000', '#400000', '#c80000', '#ff8000', '#ffff00'] },
    { name: 'UV Scan Violet Purple Cyan',   colors: ['#000010', '#080040', '#4000c0', '#a000ff', '#00ffff'] },
    { name: 'Heat Map Rouge Red Bleu Blue', colors: ['#0000aa', '#0088ff', '#00ffaa', '#ffff00', '#ff0000'] },
    { name: 'Audio Wave Vert Green Bleu Blue', colors: ['#001818', '#00808a', '#00d0d0', '#80f8f8', '#ffffff'] },
    { name: 'Chroma Key Vert Green',        colors: ['#00a800', '#00c800', '#00e800', '#00ff00', '#80ff80'] },
    { name: 'Retroreflect Jaune Yellow Gris Gray', colors: ['#202020', '#808080', '#e8e880', '#f8f840', '#f8f800'] },
    { name: 'Overexposed Blanc White Jaune Yellow', colors: ['#f8f8d0', '#f8f8e0', '#f8f8f0', '#f8f8f8', '#ffffff'] },
    { name: 'Solarize Jaune Yellow Violet Purple', colors: ['#000000', '#400040', '#c000c0', '#f8a000', '#ffffff'] },
    { name: 'Double Exposure Bleu Blue Rose Pink', colors: ['#0a0028', '#280060', '#8040a8', '#d080c8', '#f8c0e0'] },
    { name: 'Color Bleed Rouge Red Bleu Blue', colors: ['#aa0000', '#cc4040', '#8040a0', '#4040cc', '#0000aa'] },
    { name: 'Film Grain Gris Gray Marron Brown', colors: ['#2a2018', '#484030', '#787060', '#a8a090', '#d0c8c0'] },
    { name: 'Burned Paper Marron Brown Noir Black', colors: ['#080400', '#281408', '#503020', '#807050', '#b0a080'] },
    { name: 'Lumen Jaune Yellow Blanc White', colors: ['#2a2000', '#888000', '#e8e000', '#f8f880', '#ffffff'] },

    // =====================================================================
    // NEW / NOUVEAUX — CULTURAL EXTRA (15)
    // =====================================================================
    { name: 'Oaxaca Orange Marron Brown',   colors: ['#3a0800', '#a03010', '#e07830', '#f0b870', '#f8e8c8'] },
    { name: 'Havana Marron Brown Jaune Yellow', colors: ['#2a1000', '#785018', '#c09030', '#e8c870', '#f8f0d0'] },
    { name: 'Casablanca Blanc White Bleu Blue', colors: ['#1a2848', '#2058a0', '#60a0d8', '#b0d8f0', '#f0f8ff'] },
    { name: 'Bali Vert Green Orange',       colors: ['#1a2000', '#508030', '#c08820', '#f0a840', '#f8e8c0'] },
    { name: 'Nairobi Vert Green Marron Brown', colors: ['#1a1808', '#486020', '#80a848', '#b8c880', '#d8e0b0'] },
    { name: 'Petra Marron Brown Rouge Red', colors: ['#2a0808', '#8a2818', '#c06030', '#e09060', '#f0c8a0'] },
    { name: 'Reykjavik Bleu Blue Gris Gray', colors: ['#0a1828', '#203858', '#406090', '#7098c0', '#a8c8e0'] },
    { name: 'Hanoi Vert Green Jaune Yellow', colors: ['#182808', '#408830', '#78c050', '#c0e888', '#e8f8d0'] },
    { name: 'Tulum Bleu Blue Vert Green',   colors: ['#001828', '#007878', '#30c0b0', '#80f0e0', '#d0fff8'] },
    { name: 'Isfahan Bleu Blue Jaune Yellow', colors: ['#0a1840', '#1a5080', '#4090d0', '#c0b040', '#f8e870'] },
    { name: 'Kathmandu Orange Marron Brown', colors: ['#2a1000', '#8a4018', '#d09030', '#f0c870', '#f8f0d0'] },
    { name: 'Lagos Rouge Red Orange',       colors: ['#1a0000', '#700000', '#c84010', '#f07830', '#f8c880'] },
    { name: 'Lima Vert Green Jaune Yellow', colors: ['#182008', '#508030', '#98c040', '#d0e880', '#f0f8c0'] },
    { name: 'Tbilisi Violet Purple Marron Brown', colors: ['#2a0828', '#783050', '#c07080', '#e0a8a0', '#f8d8d0'] },
    { name: 'Muscat Jaune Yellow Orange',   colors: ['#3a1808', '#a06028', '#e0a848', '#f8d880', '#f8f8e0'] },
];


  const gradColors = f => {
    if (f.noGrad) return f.tags.map(() => null);
    const n = f.tags.length;
    if (!n) return [];
    const g = f.gradient || [f.colorStart || '#c0f0f8', f.colorEnd || '#183848'];
    if (n === 1) return [g[0]];
    return f.tags.map((_, i) => {
      const p = (i / (n - 1)) * (g.length - 1);
      const idx = Math.floor(p);
      if (idx >= g.length - 1) return g[g.length - 1];
      return lerp(g[idx], g[idx + 1], p - idx);
    });
  };

  const gradAllColors = f => {
    const tagsCount = (f.tags || []).length;
    const aliasesCount = (f.aliases || []).length;
    const n = tagsCount + aliasesCount;
    if (f.noGrad || n === 0) return Array(n).fill(null);
    const g = f.gradient || [f.colorStart || '#c0f0f8', f.colorEnd || '#183848'];
    if (n === 1) return [g[0]];
    return Array.from({length: n}, (_, i) => {
      const p = (i / (n - 1)) * (g.length - 1);
      const idx = Math.floor(p);
      if (idx >= g.length - 1) return g[g.length - 1];
      return lerp(g[idx], g[idx + 1], p - idx);
    });
  };

  const gradChildColors = f => {
    if (!f.gradFolders || f.noGrad) return (f.children || []).map(() => null);
    const children = f.children || [];
    const n = children.length;
    if (!n) return [];
    const g = f.gradient || [f.colorStart || '#c0f0f8', f.colorEnd || '#183848'];
    if (n === 1) return [g[0]];
    return children.map((_, i) => {
      const p = (i / (n - 1)) * (g.length - 1);
      const idx = Math.floor(p);
      if (idx >= g.length - 1) return g[g.length - 1];
      return lerp(g[idx], g[idx + 1], p - idx);
    });
  };

  const findF = (id, l = S.folders) => {
    for (const f of l) {
      if (f.id === id) return f;
      const r = findF(id, f.children || []);
      if (r) return r;
    }
    return null;
  };

  const folderOf = tag => flat().find(f => (f.tags || []).includes(tag)) || null;
  const allTagsOf = f => [...(f.tags || []), ...(f.children || []).flatMap(allTagsOf)];
  const allTagsAndAliasesOf = f => {
    let t = [...(f.tags || [])];
    if (f.aliases) t.push(...f.aliases);
    return [...t, ...(f.children || []).flatMap(allTagsAndAliasesOf)];
  };

  const allCountableItemsOf = f => {
    let t = [...(f.tags || [])];
    if (f.countAliases !== false && f.aliases) t.push(...f.aliases);
    return [...t, ...(f.children || []).flatMap(allCountableItemsOf)];
  };

  const delF = (id, l = S.folders) => {
    const i = l.findIndex(f => f.id === id);
    if (i !== -1) { l.splice(i, 1); return true; }
    return l.some(f => delF(id, f.children || []));
  };

  function extractFolder(id, l = S.folders) {
    const i = l.findIndex(f => f.id === id);
    if (i !== -1) return l.splice(i, 1)[0];
    for (const f of l) { const found = extractFolder(id, f.children || []); if (found) return found; }
    return null;
  }

  function isDescendant(sourceId, targetId) {
    const source = findF(sourceId);
    if (!source) return false;
    const check = children => children.some(c => c.id === targetId || check(c.children || []));
    return check(source.children || []);
  }

  function getFolderPath(tagName) {
    const path = [];
    const search = (folders, ancestors) => {
      for (const f of folders) {
        const chain = [...ancestors, f];
        if ((f.tags || []).includes(tagName)) { path.push(...chain); return true; }
        if (search(f.children || [], chain)) return true;
      }
      return false;
    };
    search(S.folders, []);
    return path;
  }

  const getNativeLis = () => Array.from(document.querySelectorAll('li.tag.has-button:not([data-mm])'));

  const getMainUl = () => {
    const candidates = Array.from(document.querySelectorAll('ul.tag-list:not([role="listbox"])'));
    const withTags = candidates.find(ul => ul.querySelector('li.tag.has-button'));
    if (withTags) return withTags;
    const fromLi = document.querySelector('li.tag.has-button:not([data-mm])')?.closest('ul');
    if (fromLi) return fromLi;
    return candidates[0] || null;
  };

  const getLocOl = () => document.querySelector('section.location-preview ol.tag-list[role="listbox"]') || null;

  function nameFromLi(li) {
    const label = li.querySelector('label.tag_text, label');
    if (!label) return '';
    let n = '';
    label.childNodes.forEach(node => { if (node.nodeType === Node.TEXT_NODE) n += node.textContent; });
    return n.trim() || (label.textContent || '').replace(/\s*\d+\s*$/, '').trim();
  }

  const countFromLi = li => li?.querySelector('small')?.textContent?.trim() || '';

  let _nativeTagMapCache = null;
  let _nativeTagMapTimer = null;
  const liOfTag = name => {
    if (!_nativeTagMapCache) {
      _nativeTagMapCache = new Map();
      document.querySelectorAll('li.tag.has-button:not([data-mm])').forEach(li => {
        _nativeTagMapCache.set(nameFromLi(li), li);
      });
      if (!_nativeTagMapTimer) {
        _nativeTagMapTimer = setTimeout(() => { _nativeTagMapCache = null; _nativeTagMapTimer = null; }, 0);
      }
    }
    return _nativeTagMapCache.get(name) || null;
  };

  function getTagColor(li) {
    if (!li) return null;
    if (li.dataset.mmColor) return li.dataset.mmColor;
    const wasHidden = li.style.display === 'none';
    if (wasHidden) li.style.removeProperty('display');
    const bg = window.getComputedStyle(li).backgroundColor;
    if (wasHidden) li.style.setProperty('display', 'none', 'important');
    if (bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent') { li.dataset.mmColor = bg; return bg; }
    return null;
  }

  const STORAGE_PREFIX = '[⚠️_DO_NOT_DELETE_MM_CLOUD_SAVE]';
  const OLD_STORAGE_PREFIX = '[⚠️_NE_PAS_SUPPRIMER_MM_CLOUD_SAVE]';

  function getStorageTagLi() {
    return getNativeLis().find(li => {
      const n = nameFromLi(li);
      return n.startsWith(STORAGE_PREFIX) || n.startsWith(OLD_STORAGE_PREFIX);
    });
  }

  function showCloudSetupWizard() {
    return new Promise(res => {
      const ov = mk('div', '', 'position:fixed;inset:0;background:rgba(10,10,10,.7);backdrop-filter:blur(5px);-webkit-backdrop-filter:blur(5px);z-index:999999;display:flex;align-items:center;justify-content:center;');
      const box = mk('div', '', 'background:#1c1c1a;border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:32px;width:420px;color:#e8e8e8;font-family:"Open Sans",sans-serif;box-shadow:0 24px 64px rgba(0,0,0,.6), 0 0 0 1px rgba(255,255,255,.02) inset;text-align:left;position:relative;display:flex;flex-direction:column;gap:20px;');
      const header = mk('div', '', 'display:flex;align-items:center;gap:12px;');
      const iconWrap = mk('div', '', 'display:flex;align-items:center;justify-content:center;width:42px;height:42px;background:rgba(59,130,246,.15);border-radius:10px;color:#3b82f6;');
      iconWrap.innerHTML = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"></path></svg>`;
      const title = mk('h2', '', 'font-size:18px;font-weight:700;margin:0;color:#fff;letter-spacing:0.3px;');
      title.textContent = 'Cloud Sync Setup';
      header.append(iconWrap, title);
      box.appendChild(header);
      const p1 = mk('p', '', 'font-size:13.5px;color:rgba(255,255,255,.65);line-height:1.5;margin:0;');
      p1.innerHTML = `To securely save your folders to the cloud, the script needs a native tag to store its data. <b>You only need to do this once per map.</b>`;
      box.appendChild(p1);
      const stepsWrap = mk('div', '', 'display:flex;flex-direction:column;gap:12px;');
      const step1 = mk('div', '', 'display:flex;align-items:center;gap:14px;background:rgba(0,0,0,.25);padding:14px 16px;border-radius:12px;border:1px solid rgba(255,255,255,.04);');
      step1.innerHTML = `<div style="background:#3b82f6;color:#fff;width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11.5px;font-weight:bold;flex-shrink:0;">1</div><div style="font-size:13.5px;line-height:1.4;color:#ddd;">Add a location anywhere on your map.</div>`;
      const step2 = mk('div', '', 'display:flex;align-items:flex-start;gap:14px;background:rgba(0,0,0,.25);padding:14px 16px;border-radius:12px;border:1px solid rgba(255,255,255,.04);');
      step2.innerHTML = `<div style="background:#3b82f6;color:#fff;width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11.5px;font-weight:bold;flex-shrink:0;margin-top:2px;">2</div><div style="font-size:13.5px;line-height:1.4;color:#ddd;width:100%;">Give it the exact tag name below:<div style="display:flex;gap:8px;margin-top:12px;"><input type="text" value="${STORAGE_PREFIX}" readonly style="flex:1;background:rgba(0,0,0,.4);border:1px solid rgba(255,255,255,.1);border-radius:8px;color:#60a5fa;padding:10px 12px;font-family:monospace;font-size:11px;outline:none;" /><button id="mm-copy-btn" style="background:#2d2d2a;border:1px solid rgba(255,255,255,.1);border-radius:8px;color:#fff;padding:0 16px;cursor:pointer;font-weight:600;font-size:12px;transition:all .2s;">Copy</button></div></div>`;
      const step3 = mk('div', '', 'display:flex;align-items:center;gap:14px;background:rgba(0,0,0,.25);padding:14px 16px;border-radius:12px;border:1px solid rgba(255,255,255,.04);');
      step3.innerHTML = `<div style="background:#3b82f6;color:#fff;width:22px;height:22px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11.5px;font-weight:bold;flex-shrink:0;">3</div><div style="font-size:13.5px;line-height:1.4;color:#ddd;">Click <b>Save</b> at the bottom left of the panel.</div>`;
      stepsWrap.append(step1, step2, step3);
      box.appendChild(stepsWrap);
      setTimeout(() => {
        const copyBtn = box.querySelector('#mm-copy-btn');
        copyBtn.onclick = () => {
          navigator.clipboard.writeText(STORAGE_PREFIX);
          copyBtn.textContent = 'Copied!'; copyBtn.style.background = '#22c55e'; copyBtn.style.color = '#fff'; copyBtn.style.borderColor = '#16a34a';
          setTimeout(() => { copyBtn.textContent = 'Copy'; copyBtn.style.background = '#2d2d2a'; copyBtn.style.color = '#fff'; copyBtn.style.borderColor = 'rgba(255,255,255,.1)'; }, 2000);
        };
        copyBtn.onmouseenter = () => { if (copyBtn.textContent === 'Copy') copyBtn.style.background = '#3f3f3a'; };
        copyBtn.onmouseleave = () => { if (copyBtn.textContent === 'Copy') copyBtn.style.background = '#2d2d2a'; };
      }, 0);
      const btnRow = mk('div', '', 'display:flex;gap:12px;justify-content:center;margin-top:8px;');
      const cancelBtn = mk('button', '', 'background:transparent;border:1px solid rgba(255,255,255,.15);border-radius:10px;color:rgba(255,255,255,.6);padding:10px 18px;cursor:pointer;font-size:13px;font-weight:600;transition:all 0.2s;');
      cancelBtn.textContent = 'Cancel';
      cancelBtn.onmouseenter = () => { cancelBtn.style.borderColor = 'rgba(255,255,255,.3)'; cancelBtn.style.color = '#fff'; };
      cancelBtn.onmouseleave = () => { cancelBtn.style.borderColor = 'rgba(255,255,255,.15)'; cancelBtn.style.color = 'rgba(255,255,255,.6)'; };
      const doneBtn = mk('button', '', 'background:#fff;border:none;border-radius:10px;color:#121210;padding:10px 24px;cursor:pointer;font-size:13px;font-weight:700;transition:background 0.2s;');
      doneBtn.textContent = 'I created the tag';
      doneBtn.onmouseenter = () => doneBtn.style.background = '#e0e0e0';
      doneBtn.onmouseleave = () => doneBtn.style.background = '#fff';
      cancelBtn.onclick = () => { ov.remove(); res(false); };
      doneBtn.onclick = () => { ov.remove(); res(true); };
      btnRow.append(cancelBtn, doneBtn);
      box.appendChild(btnRow);
      ov.appendChild(box);
      document.body.appendChild(ov);
    });
  }

  function showSaveWarningModal() {
    return new Promise(res => {
      const ov = mk('div', '', 'position:fixed;inset:0;background:rgba(0,0,0,.8);z-index:99999;display:flex;align-items:center;justify-content:center;');
      const box = mk('div', '', 'background:rgba(22,22,19,0.85);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:24px;width:400px;color:#e8e8e8;font-family:"Open Sans",sans-serif;box-shadow:0 24px 64px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.05);');
      const ttl = mk('h2', '', 'margin:0 0 12px 0;font-size:16px;font-weight:700;color:#fff;'); ttl.textContent = 'Save Map & Folders';
      const p = mk('p', '', 'margin:0 0 20px 0;font-size:13px;color:rgba(255,255,255,.7);line-height:1.5;');
      p.textContent = 'Saving your folders requires saving the map. This will also save any recent locations or tags you added. Proceed?';
      box.append(ttl, p);
      const btnRow = mk('div', '', 'display:flex;gap:8px;justify-content:flex-end;');
      const bCancel = mk('button', '', 'background:rgba(0,0,0,.2);border:1px solid rgba(255,255,255,.1);border-radius:10px;color:rgba(255,255,255,.6);padding:8px 16px;cursor:pointer;font-size:12px;font-weight:600;transition:all 0.2s;');
      bCancel.textContent = 'Cancel';
      bCancel.onmouseenter = () => { bCancel.style.borderColor = 'rgba(255,255,255,.3)'; bCancel.style.color = '#fff'; };
      bCancel.onmouseleave = () => { bCancel.style.borderColor = 'rgba(255,255,255,.1)'; bCancel.style.color = 'rgba(255,255,255,.6)'; };
      const bSkip = mk('button', '', 'background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);border-radius:10px;color:rgba(255,255,255,.8);padding:8px 16px;cursor:pointer;font-size:12px;font-weight:600;transition:all 0.2s;');
      bSkip.textContent = "Understood, don't show again";
      bSkip.onmouseenter = () => bSkip.style.background = 'rgba(255,255,255,.1)';
      bSkip.onmouseleave = () => bSkip.style.background = 'rgba(255,255,255,.05)';
      const bSave = mk('button', '', 'background:#fff;border:none;border-radius:10px;color:#121210;padding:8px 20px;cursor:pointer;font-size:12px;font-weight:700;transition:background 0.2s;');
      bSave.textContent = 'Save';
      bSave.onmouseenter = () => bSave.style.background = '#e0e0e0';
      bSave.onmouseleave = () => bSave.style.background = '#fff';
      bCancel.onclick = () => { ov.remove(); res('cancel'); };
      bSkip.onclick = () => { ov.remove(); res('save_and_skip'); };
      bSave.onclick = () => { ov.remove(); res('save'); };
      btnRow.append(bCancel, bSkip, bSave);
      box.appendChild(btnRow);
      ov.appendChild(box);
      document.body.appendChild(ov);
    });
  }

  function injectFooterButtons() {
    const footerContainer = document.querySelector('.map-meta__actions');
    if (!footerContainer || document.getElementById('mm-footer-actions-wrapper')) return;
    const wrapper = mk('span', '', 'display:inline-flex; align-items:center; margin-left:12px;');
    wrapper.id = 'mm-footer-actions-wrapper';
    const saveBtn = mk('button', 'button button--primary' + (isDirty ? ' mm-btn-dirty' : ''));
    saveBtn.id = 'mm-folder-save-btn'; saveBtn.type = 'button'; saveBtn.title = 'Save folder tree to the Cloud';
    saveBtn.innerHTML = `<span class="button__label">${isDirty ? 'Save Folders' : 'Folders Saved'}</span>`;
    saveBtn.onclick = () => saveToCloud();
    const loadBtn = mk('button', 'button button--primary');
    loadBtn.id = 'mm-folder-load-btn'; loadBtn.type = 'button'; loadBtn.title = 'Restore folders from the Cloud';
    loadBtn.innerHTML = '<span class="button__label">Load</span>';
    loadBtn.onclick = () => loadFromCloud(true);
    wrapper.append(saveBtn, loadBtn);
    footerContainer.appendChild(wrapper);
  }

  async function saveToCloud() {
    if (typeof LZString === 'undefined') { alert('Error: LZString library failed to load.'); return; }
    let li = getStorageTagLi();
    if (!li) {
      const userDidSetup = await showCloudSetupWizard();
      if (!userDidSetup) return;
      await new Promise(r => setTimeout(r, 500));
      li = getStorageTagLi();
      if (!li) { alert('Storage tag not found. Make sure you created it with the exact name and clicked Save.'); return; }
    }
    const skipWarning = localStorage.getItem('mmapp_skip_save_warning') === 'true';
    if (!skipWarning) {
      const action = await showSaveWarningModal();
      if (action === 'cancel') return;
      if (action === 'save_and_skip') localStorage.setItem('mmapp_skip_save_warning', 'true');
    }
    const editBtn = li.querySelector('button.tag_button--edit, button[class*="edit"]');
    if (!editBtn) return;
    S.lastUpdate = Date.now();
    const compressed = LZString.compressToEncodedURIComponent(JSON.stringify(S));
    const currentName = nameFromLi(li);
    const prefixToUse = currentName.startsWith(OLD_STORAGE_PREFIX) ? OLD_STORAGE_PREFIX : STORAGE_PREFIX;
    const payload = `${prefixToUse}:::${compressed}`;
    editBtn.click();
    const nameInput = await waitDOM('div[role="dialog"] input[type="text"].input');
    if (!nameInput) {
  const notif = mk('div', '', 'position:fixed;top:20px;right:20px;background:rgba(30,10,10,0.92);border:1px solid rgba(248,113,113,.3);color:rgba(248,113,113,.95);padding:10px 18px;border-radius:10px;font-family:"Open Sans",sans-serif;font-size:13px;font-weight:600;z-index:999999;box-shadow:0 4px 20px rgba(0,0,0,.4);display:flex;align-items:center;gap:8px;');
  notif.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg> Save failed — dialog didn't open. Try again.`;
  document.body.appendChild(notif);
  setTimeout(() => notif.remove(), 4000);
  return;
    }
    const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
    if (nativeSetter) nativeSetter.call(nameInput, payload);
    else nameInput.value = payload;
    nameInput.dispatchEvent(new Event('input', { bubbles: true }));
    nameInput.dispatchEvent(new Event('change', { bubbles: true }));

    // --- PATCH DE SAUVEGARDE FIABLE ---
    const dialog = nameInput.closest('div[role="dialog"]');
    const saveModalBtn = dialog?.querySelector('.edit-tag-modal__actions button:last-child, button.save');

    if (saveModalBtn) {
      let checks = 0;
      while (saveModalBtn.disabled && checks < 10) {
        await new Promise(r => setTimeout(r, 50));
        checks++;
      }
      saveModalBtn.click();
    }

    setDirty(false);
    updateHideStyle();

    // Attente du rafraîchissement de la modale
    await new Promise(r => setTimeout(r, 350));

    let nativeSaveBtn = document.querySelector('button[data-qa="map-save"]');
    if (nativeSaveBtn) {
      let checksGlobal = 0;
      while (nativeSaveBtn.disabled && checksGlobal < 15) {
        await new Promise(r => setTimeout(r, 50));
        checksGlobal++;
        nativeSaveBtn = document.querySelector('button[data-qa="map-save"]');
      }
      if (nativeSaveBtn && !nativeSaveBtn.disabled) {
        await new Promise(r => setTimeout(r, 100));
        nativeSaveBtn.click();
      }
    } else {
      console.warn("[mm-folders] Could not find the native save button using data-qa!");
    }
    // ----------------------------------

    const notif = mk('div', '', 'position:fixed;top:20px;right:20px;background:rgba(15,20,15,0.88);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(74,222,128,.25);color:rgba(74,222,128,.95);padding:10px 18px;border-radius:10px;font-family:"Open Sans",sans-serif;font-size:13px;font-weight:600;z-index:999999;box-shadow:0 4px 20px rgba(0,0,0,.4);display:flex;align-items:center;gap:8px;');
    notif.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> Folders saved`;
    document.body.appendChild(notif);
    notif.animate([{opacity:0,transform:'translateY(-6px)'},{opacity:1,transform:'translateY(0)'}],{duration:200,fill:'forwards'});
    setTimeout(() => {
      notif.animate([{opacity:1},{opacity:0}],{duration:300,fill:'forwards'}).onfinish = () => notif.remove();
    }, 2500);
  }

  function loadFromCloud(force = false) {
    if (typeof LZString === 'undefined') { if (force) alert('Error: LZString library failed to load.'); return false; }
    const li = getStorageTagLi();
    if (!li) { if (force) alert(`No save found on this map.\n(No tag starting with ${STORAGE_PREFIX.substring(0, 10)}...)`); return false; }
    const name = nameFromLi(li);
    if (!name.includes(':::')) { if (force) alert('Storage tag exists but seems empty. Save your folders first.'); return false; }
    try {
      const dataPart = name.substring(name.indexOf(':::') + 3);
      const decoded = LZString.decompressFromEncodedURIComponent(dataPart);
      const parsed = JSON.parse(decoded || dataPart);
      if (parsed?.folders) {
        if (force || S.folders.length === 0 || (parsed.lastUpdate || 0) > S.lastUpdate) {
          if (force && !confirm('⚠️ Warning: Forcing Load will overwrite your current local folders with the Cloud save. Continue?')) return false;
          S = { folders: parsed.folders, lastUpdate: parsed.lastUpdate || Date.now() };
          invalidateFlatCache(); saveS(false); setDirty(false); render(); return true;
        }
      }
    } catch (e) { console.error('Cloud Load Error:', e); }
    return false;
  }

  function injectCSS() {
    if (document.getElementById('mm-css')) return;
    const s = document.createElement('style');
    s.id = 'mm-css';
    s.textContent = `
      /* --- VARIABLES GLOBALES --- */
      :root { --mm-glow-color: ${localStorage.getItem('mmapp_glow_color') || '#4ade80'}; }

      /* --- FIX FOUC barre de recherche : on cache l'input natif tant que le wrapper n'est pas prêt --- */
      /* --- EMPÊCHE LE SAUT DE BARRE & LE FLASH F5 --- */
      html, body { scrollbar-gutter: stable; }
      header.tool-block__header .input-group { width: 100% !important; }
      header.tool-block__header input.input[placeholder*="Filter"]:not(.mm-wrapper-injected) { opacity: 0 !important; pointer-events: none !important; position: absolute !important; }

      li[data-mm-folder] { list-style:none; margin:0; padding:2px 0; width:100%; box-sizing:border-box; }
      .mm-hd { display:flex; align-items:center; gap:5px; width:100%; height:32px; box-sizing:border-box; padding:0 10px 0 0; border-radius:999px; font-family:"Open Sans",sans-serif; font-size:16px; font-weight:400; cursor:grab; user-select:none; transition:filter .15s, box-shadow .15s; }
      .mm-hd:has(.mm-left-actions:hover, .mm-right-actions:hover) { cursor:default; }
      .mm-hd:active:not(:has(.mm-left-actions:hover, .mm-right-actions:hover)) { cursor:grabbing; }
      .mm-hd:hover { filter:brightness(1.08); }
      .mm-hd--on      { box-shadow:0 0 0 2px #fff!important; }
      .mm-hd--off     { opacity:.85; }
      .mm-hd--partial { box-shadow:0 0 0 2px rgba(255,255,255,.4)!important; }
      .mm-left-actions { display:flex; align-items:center; gap:2px; cursor:default; height:100%; padding-left:2px; }
      .mm-right-actions { display:flex; align-items:center; gap:4px; cursor:default; height:100%; }
      li[data-mm-folder].mm-drop-above { border-top:3px solid rgba(255,255,255,.8) !important; }
      li[data-mm-folder].mm-drop-after  { border-bottom:3px solid rgba(255,255,255,.8) !important; }
      li[data-mm-folder].mm-drop-inside > .mm-hd { box-shadow:0 0 0 2px rgba(255,255,255,.9), 0 0 12px rgba(255,255,255,.3) !important; filter:brightness(1.15); }
      .mm-arrow-zone { display:flex; align-items:center; justify-content:center; width:28px; height:28px; flex-shrink:0; border-radius:50%; cursor:pointer; transition:background .12s; }
      .mm-arrow-zone:hover { background:rgba(0,0,0,.22); }
      .mm-pencil { display:flex; align-items:center; justify-content:center; width:22px; height:22px; flex-shrink:0; cursor:pointer; border-radius:50%; opacity:.55; transition:opacity .1s,background .1s; }
      .mm-pencil:hover { opacity:1; background:rgba(0,0,0,.18); }
      .mm-body { display:flex; flex-wrap:wrap; gap:5px; padding:6px 8px 8px 16px; }
          /* Au repos : encore plus discret */
      .mm-dropzone { width:100%; padding:5px 12px; text-align:center; border:1.5px dashed rgba(255,255,255,.15); border-radius:8px; font-size:11px; font-family:"Open Sans",sans-serif; color:rgba(255,255,255,.25); font-style:italic; }

      /* En action : le fond passe à SEULEMENT 5%, la bordure à 40% (très doux) */
      .mm-body.mm-dh, .mm-dropzone.mm-dh {
          background: color-mix(in srgb, var(--folder-accent, #fff) 5%, transparent) !important;
          box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--folder-accent, #fff) 40%, transparent) !important;
          border-radius:8px !important;
          transition: background 0.15s;
      }

      .mm-hd.mm-dh { filter:brightness(0.75) !important; box-shadow: 0 0 0 2px rgba(255,255,255,.95) !important; border-radius:999px !important; }

      /* En action : texte bien visible mais sans piquer les yeux */
      .mm-dropzone.mm-dh { color: color-mix(in srgb, var(--folder-accent, #fff) 80%, transparent) !important; }
      li.mm-sep { list-style:none; height:1px; background:rgba(255,255,255,.1); margin:6px 4px; width:100%; display:block; }
      li.mm-addli { list-style:none; margin:4px 0 8px; width:100%; display:block; }
      .mm-addbtn { display:flex; align-items:center; justify-content:center; height:32px; padding:0 14px; border-radius:999px; border:none; cursor:pointer; background:#E0E4E5; color:#121210; font-size:16px; font-family:"Open Sans",sans-serif; font-weight:400; box-sizing:border-box; transition:background .15s; }
      .mm-addbtn:hover { background:#d0d4d6; }
      .mm-tag-btn { display:inline-flex; align-items:center; gap:5px; height:32px; padding:0 10px 0 8px; border-radius:999px; border:none; font-family:"Open Sans",sans-serif; font-size:16px; font-weight:400; cursor:pointer; transition:filter .12s, box-shadow .12s, transform .12s; white-space:nowrap; box-sizing: border-box; }
      .mm-tag-btn:hover { filter:brightness(1.12); transform:translateY(-1px); box-shadow:0 3px 8px rgba(0,0,0,.25); }
      .mm-tag-btn.mm-tag-btn--on { box-shadow: 0 0 0 2px #fff !important; }
      .mm-tag-btn.mm-tag-btn--alias { box-shadow: inset 0 0 0 3px rgba(0,0,0,0.3) !important; }
      .mm-tag-btn.mm-tag-btn--alias.mm-tag-btn--on { box-shadow: 0 0 0 2px #fff, inset 0 0 0 3px rgba(0,0,0,0.3) !important; }
      .mm-subaddbtn { background:rgba(255,255,255,.07); border:1.5px dashed rgba(255,255,255,.2); border-radius:999px; color:rgba(255,255,255,.4); font-size:11px; padding:2px 14px; height:24px; cursor:pointer; font-family:"Open Sans",sans-serif; font-weight:600; transition:color .12s,border-color .12s,background .12s; display:flex; align-items:center; width:fit-content; }
      .mm-subaddbtn:hover { color:rgba(255,255,255,.8); border-color:rgba(255,255,255,.5); background:rgba(255,255,255,.12); }
      .mm-sub-wrap { display:flex; flex-direction:column; gap:4px; padding:5px 0 3px 14px; }
      .mm-grad { width:24px; height:7px; border-radius:4px; flex-shrink:0; opacity:.85; }
      .mm-cnt { background:rgba(0,0,0,.2); border-radius:999px; padding:0 7px; font-size:11px; font-weight:700; flex-shrink:0; line-height:18px; }
      .mm-actbtn { background:rgba(0,0,0,.18); border:none; cursor:pointer; border-radius:999px; padding:1px 7px; font-size:11px; font-weight:600; flex-shrink:0; opacity:.75; transition:opacity .1s; font-family:inherit; line-height:18px; display:inline-flex; align-items:center; justify-content:center; }
      .mm-actbtn:hover { opacity:1; background:rgba(0,0,0,.32); }
      .mm-color-box, input[type="color"].mm-color-inp { width: 38px !important; height: 24px !important; border-radius: 6px !important; box-shadow: inset 0 0 0 1px rgba(255,255,255,0.15) !important; box-sizing: border-box !important; flex-shrink: 0 !important; padding: 0 !important; margin: 0 !important; cursor: pointer; display: inline-block; overflow: hidden; }
      .mm-grad-box { width: 58px !important; height: 24px !important; border-radius: 6px !important; box-shadow: inset 0 0 0 1px rgba(255,255,255,0.15) !important; box-sizing: border-box !important; flex-shrink: 0 !important; padding: 0 !important; margin: 0 !important; cursor: pointer; display: inline-block; overflow: hidden; }
      input[type="color"].mm-color-inp { background: rgba(0,0,0,0.25); -webkit-appearance: none; border: none !important; }
      input[type="color"].mm-color-inp::-webkit-color-swatch-wrapper { padding: 0; }
      input[type="color"].mm-color-inp::-webkit-color-swatch { border: none; border-radius: 5px; }
      input[type="color"].mm-color-inp::-moz-color-swatch { border: none; border-radius: 5px; }
      .mm-toggle-row { display:flex; align-items:center; gap:5px; flex-wrap:wrap; }
      .mm-toggle-pill { display:inline-flex; align-items:center; gap:5px; background:rgba(255,255,255,.05); border:1px solid rgba(255,255,255,.1); border-radius:999px; padding:3px 10px 3px 7px; cursor:pointer; font-size:11px; font-family:"Open Sans",sans-serif; color:rgba(255,255,255,.4); transition:all .15s; white-space:nowrap; user-select:none; line-height:1.4; }
      .mm-toggle-pill:hover { background:rgba(255,255,255,.1); color:rgba(255,255,255,.7); border-color:rgba(255,255,255,.2); }
      .mm-toggle-pill.mm-toggle-on { color:rgba(255,255,255,.8); border-color:rgba(255,255,255,.2); background:rgba(255,255,255,.08); }
      .mm-toggle-dot { width:6px; height:6px; border-radius:50%; background:rgba(255,255,255,.2); flex-shrink:0; transition:background .15s; }
      .mm-toggle-pill.mm-toggle-on .mm-toggle-dot { background:#4ade80; }
      body.mm-hide-dropzones .mm-dropzone { display:none !important; }
      body.mm-hide-subfolderbtns .mm-subaddbtn { display:none !important; }
      #mm-folder-save-btn { background-color: #1e3a8a !important; border-color: #1e3a8a !important; color: #cbd5e1 !important; transition: all 0.2s; }
      #mm-folder-save-btn:hover { background-color: #1e40af !important; border-color: #1e40af !important; color: #fff !important; }
      #mm-folder-save-btn.mm-btn-dirty { background-color: #3b82f6 !important; border-color: #3b82f6 !important; color: #fff !important; }
      #mm-folder-save-btn.mm-btn-dirty:hover { background-color: #2563eb !important; border-color: #2563eb !important; }
      #mm-folder-load-btn { background-color: #7B68EE !important; border-color: #7B68EE !important; color: #fff !important; margin-left: 6px; }
      #mm-folder-load-btn:hover { background-color: #6A5ACD !important; border-color: #6A5ACD !important; }
      body:not(.mm-search-mode).mm-loading li.tag.has-button:not([data-mm]) { display: none !important; }
      body.mm-search-mode ul.tag-list > li[data-mm="1"], body.mm-search-mode li.mm-sep, body.mm-search-mode li.mm-addli { display: none !important; }
      body.mm-loc-open ul.tag-list > li[data-mm="1"], body.mm-loc-open li.mm-sep, body.mm-loc-open li.mm-addli { display: none !important; }

      .mm-folder-highlight { box-shadow: 0 0 0 2px var(--mm-glow-color), 0 0 15px var(--mm-glow-color) !important; transition: box-shadow 0.3s ease; }

      /* --- FUSION DES BARRES DE RECHERCHE --- */
      body input.input[placeholder*="Filter"], header.tool-block__header input.input { background: rgba(0,0,0,.25) !important; border: 1px solid rgba(255,255,255,.1) !important; border-radius: 8px !important; color: #fff !important; box-shadow: none !important; transition: border-color 0.2s !important; }
      body input.input[placeholder*="Filter"]:focus { border-color: rgba(255,255,255,.4) !important; }
      #mm-search-wrapper { background: rgba(0,0,0,.25); border: 1px solid rgba(255,255,255,.1); border-radius: 8px; transition: border-color 0.2s; height: 32px; box-sizing: border-box; display: flex; align-items: center; }
      #mm-search-wrapper:focus-within { border-color: rgba(255,255,255,.4); }
      #mm-search-wrapper input.input { background: transparent !important; border: none !important; box-shadow: none !important; outline: none !important; color: #fff !important; margin: 0 !important; height: 100% !important; }
      .mm-folder-hidden { display: none !important; }

      /* --- TOOLTIP INTERACTIF --- */
      #mm-path-tooltip { position: fixed; z-index: 999999; display: flex; background: rgba(22, 22, 19, 0.92); border: 1px solid rgba(255,255,255,.08); box-shadow: 0 4px 18px rgba(0,0,0,.4); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); font-family: "Open Sans", sans-serif; font-size: 12.5px; opacity: 0; transform: translateY(3px); pointer-events: auto !important; cursor: pointer; transition: background 0.15s, border-color 0.15s, opacity .18s ease, transform .18s ease !important; flex-direction: column !important; align-items: flex-start !important; padding: 8px 12px !important; border-radius: 10px !important; }
      #mm-path-tooltip.mm-tt-visible { opacity: 1; transform: translateY(0); }
      #mm-path-tooltip:hover { background: rgba(40,40,35,0.98); border-color: rgba(255,255,255,0.2); box-shadow: 0 4px 24px rgba(0,0,0,0.4); }
      .mm-tt-path-wrap { display: flex; align-items: center; flex-direction: row; gap: 5px; }
      #mm-path-tooltip.mm-tt-col .mm-tt-path-wrap { flex-direction: column; align-items: flex-start; gap: 3px; }
      #mm-path-tooltip .mm-tt-row { display: flex; align-items: center; gap: 5px; white-space: nowrap; line-height: 1; }
      #mm-path-tooltip .mm-tt-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
      #mm-path-tooltip .mm-tt-name { font-weight: 600; color: #dcdcdc; letter-spacing: .01em; }
      #mm-path-tooltip .mm-tt-arrow { display: flex; align-items: center; justify-content: center; flex-shrink: 0; width: 12px; height: 12px; opacity: .4; }
      #mm-path-tooltip.mm-tt-col .mm-tt-connector { font-size: 10px; opacity: .28; line-height: 1; display: flex; align-items: center; user-select: none; }
      .mm-tt-hint { width: 100%; text-align: center; font-size: 9px; font-weight: 700; color: rgba(255, 255, 255, 0.35); margin-top: 6px; padding-top: 6px; border-top: 1px solid rgba(255,255,255,0.06); text-transform: uppercase; letter-spacing: 0.5px; }
      @keyframes mm-glow-pulse {
        0% { box-shadow: 0 0 0 3px var(--mm-glow-color), 0 0 18px var(--mm-glow-color); }
        100% { box-shadow: none; }
      }
      @keyframes mm-glow-folder {
        0% { box-shadow: 0 0 0 3px var(--mm-glow-color), 0 0 18px var(--mm-glow-color); }
        100% { box-shadow: none; }
      }
      .mm-glow-anim { animation: mm-glow-pulse 1.2s ease-out forwards !important; transform: none !important; }
      .mm-folder-glow-anim { animation: mm-glow-folder 1.2s ease-out forwards !important; transform: none !important; }
    `;
    (document.head || document.documentElement).appendChild(s);
  }

  function initHideToggles() {
    if (localStorage.getItem('mmapp_hide_dropzones') === 'true') document.body.classList.add('mm-hide-dropzones');
    if (localStorage.getItem('mmapp_hide_subfolderbtns') === 'true') document.body.classList.add('mm-hide-subfolderbtns');

    let hideTt = localStorage.getItem('mmapp_hide_tooltips');
    if (hideTt !== 'false') {
      localStorage.setItem('mmapp_hide_tooltips', 'true');
      document.body.classList.add('mm-hide-tooltips');
    }
  }

  if (!window.mmActivationSource) window.mmActivationSource = {};


  function updateHideStyle() {
    const isSearch = document.body.classList.contains('mm-search-mode');
    const assigned = getAssignedTags();
    document.querySelectorAll('li:not([data-mm])').forEach(li => {
      let hide = false;
      const t = li.textContent || '';
      if (t.includes(STORAGE_PREFIX) || t.includes(OLD_STORAGE_PREFIX)) {
        hide = true;
      } else if (!isSearch) {
        const name = nameFromLi(li);
        if (name && assigned.has(name)) hide = true;
      }
      if (hide) li.style.setProperty('display', 'none', 'important');
      else li.style.removeProperty('display');
    });
    document.querySelectorAll('.mm-tag-btn').forEach(btn => {
      if (!btn.dataset.mmTag) return;
      const tagName = btn.dataset.mmTag;
      const folder = folderOf(tagName);
      if (folder && (folder.gradTags === false || folder.noGrad)) {
        const li = liOfTag(tagName);
        if (li) { const bg = getTagColor(li) || '#5a5a8a'; btn.style.backgroundColor = bg; btn.style.color = textOn(bg); }
      }
    });
    document.body.classList.remove('mm-loading');
    document.body.classList.remove('mm-search-exiting');
  }

  function updateAllFolderVisuals() {
    if (!window.mmTagIntents) window.mmTagIntents = {};

    document.querySelectorAll('[data-mm-folder]').forEach(folderEl => {
      const f = findF(folderEl.getAttribute('data-mm-folder'));
      if (!f) return;
      const hd = Array.from(folderEl.children).find(c => c.classList.contains('mm-hd'));
      if (!hd) return;
      const fullyOn = isFolderFullyOn(f);
      const partialOn = !fullyOn && isFolderPartiallyOn(f);
      hd.classList.remove('mm-hd--on', 'mm-hd--off', 'mm-hd--partial');
      if (fullyOn) hd.classList.add('mm-hd--on');
      else if (partialOn) hd.classList.add('mm-hd--partial');
      else hd.classList.add('mm-hd--off');
    });

    document.querySelectorAll('.mm-tag-btn').forEach(btn => {
      const t = btn.dataset.mmTag;
      if (!t) return;
      const folderEl = btn.closest('[data-mm-folder]');
      const folderId = folderEl ? folderEl.getAttribute('data-mm-folder') : null;

      if (isTagVisuallyOnInFolder(t, folderId)) {
        btn.classList.add('mm-tag-btn--on');
      } else {
        btn.classList.remove('mm-tag-btn--on');
      }
    });
  }

  function enterSearchMode() {
    document.body.classList.add('mm-search-mode');
    document.querySelectorAll('li:not([data-mm])').forEach(li => {
      const t = li.textContent || '';
      if (!t.includes(STORAGE_PREFIX) && !t.includes(OLD_STORAGE_PREFIX)) li.style.removeProperty('display');
    });
    const so = document.getElementById('mm-search-options');
    if (so) so.style.display = 'flex';
  }

  function exitSearchMode() {
    hidePathTooltip(true);
    document.body.classList.remove('mm-search-mode');
    updateHideStyle();
    const so = document.getElementById('mm-search-options');
    if (so) so.style.display = 'none';
  }

  function watchHeaderFeatures() {
    const getHeader = () => document.querySelector('.tool-block__header');
    const getInput = () => document.querySelector('input.input[placeholder*="Filter"]');

    let _boundInput = null;
    let lastValue = '';
    let currentSearchMode = 'tags';
    let preSortSnapshot = null;
    let preCollapseState = null;
    let preSearchExpandedState = null;

    const SVG_TAG = `<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor"><path d="M5.5,7A1.5,1.5 0 0,1 4,5.5A1.5,1.5 0 0,1 5.5,4A1.5,1.5 0 0,1 7,5.5A1.5,1.5 0 0,1 5.5,7M21.41,11.58L12.41,2.58C12.05,2.22 11.55,2 11,2H4C2.89,2 2,2.89 2,4V11C2,11.55 2.22,12.05 2.59,12.41L11.58,21.41C11.95,21.77 12.45,22 13,22C13.55,22 14.05,21.77 14.41,21.41L21.41,14.41C21.78,14.05 22,13.55 22,13C22,12.45 21.77,11.94 21.41,11.58Z" /></svg>`;
    const SVG_FOLDER = `<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z" /></svg>`;

    const attachInput = input => {
      if (_boundInput === input) return;
      _boundInput = input;
      const onChange = () => {
        const val = input.value || '';
        if (val === lastValue) return;
        lastValue = val;

        if (val.length > 0) {
          document.body.classList.remove('mm-search-exiting');
          enterSearchMode();
        } else {
          document.body.classList.add('mm-search-exiting');
          exitSearchMode();
          if (!window.mmSkipRenderCascade) {
            setTimeout(reRenderFolders, 50);
            setTimeout(reRenderFolders, 150);
            setTimeout(reRenderFolders, 400);
            setTimeout(reRenderFolders, 800);
          } else {
            reRenderFolders();
            window.mmSkipRenderCascade = false;
          }
        }
      };
      input.addEventListener('input', onChange);
      const obs = new MutationObserver(onChange);
      obs.observe(input, { attributes: true, attributeFilter: ['value'] });
      if (input.value) onChange();
    };

    const runHeaderSetup = () => {
      const header = getHeader();
      const input = getInput();

      if (input && input !== _boundInput) attachInput(input);
      if (!header) return;

      if (!document.getElementById('mm-search-options')) {
       const searchOptions = mk('div', '', 'display:none; align-items:center; justify-content:flex-start; padding:10px 0 6px 0; margin-top:2px; width:100%; box-sizing:border-box; gap:5px;');
        searchOptions.id = 'mm-search-options';

        const makeTogglePill = (label, bodyClass, storageKey, defaultHidden = false) => {
          let val = localStorage.getItem(storageKey);
          if (val === null) {
            val = defaultHidden ? 'true' : 'false';
            localStorage.setItem(storageKey, val);
          }
          const isHidden = val === 'true';
          if (isHidden) document.body.classList.add(bodyClass);
          const pill = mk('button', 'mm-toggle-pill' + (isHidden ? '' : ' mm-toggle-on'));
          const dot = mk('span', 'mm-toggle-dot');
          const lbl = mk('span'); lbl.textContent = label;
          pill.append(dot, lbl);
          pill.onclick = e => {
            e.stopPropagation();
            const nowHidden = !document.body.classList.contains(bodyClass);
            if (nowHidden) {
              document.body.classList.add(bodyClass);
              localStorage.setItem(storageKey, 'true');
              pill.classList.remove('mm-toggle-on');
            } else {
              document.body.classList.remove(bodyClass);
              localStorage.setItem(storageKey, 'false');
              pill.classList.add('mm-toggle-on');
            }
          };
          return pill;
        };

        const hoverPill = makeTogglePill('Hover paths', 'mm-hide-tooltips', 'mmapp_hide_tooltips', true);
        const soLeft = mk('div', '', 'display:flex;align-items:center;gap:5px;flex:1;');
        const dispLbl = mk('span', '', 'color:#a0a0a0;font-size:10px;margin-right:2px;user-select:none;');
        dispLbl.textContent = 'display';
        soLeft.appendChild(dispLbl);
        soLeft.appendChild(hoverPill);
        searchOptions.insertBefore(soLeft, searchOptions.firstChild);
        header.insertAdjacentElement('afterend', searchOptions);
      }

      const btn = header.querySelector('.tool-block__title--collapsible');
      if (btn && !btn.dataset.mmHijacked) {
        btn.dataset.mmHijacked = "1";
        const svgIcon = btn.querySelector('svg');
        if (svgIcon) {
          svgIcon.style.transition = 'transform 0.2s ease';
          svgIcon.style.transformOrigin = 'center center';
        }

        ['click', 'mousedown', 'pointerdown'].forEach(evt => {
          btn.addEventListener(evt, (e) => {
            e.preventDefault(); e.stopPropagation();
            if (evt === 'click') {
              let allCollapsed = true;
              let changed = false;

              const checkAllCollapsed = (list) => {
                for (const f of list) { if (f.expanded) allCollapsed = false; if (f.children) checkAllCollapsed(f.children); }
              };
              checkAllCollapsed(S.folders);

              if (preCollapseState && allCollapsed) {
                const restore = (list) => {
                  for (const f of list) {
                    if (preCollapseState[f.id] !== undefined) {
                      if (f.expanded !== preCollapseState[f.id]) { f.expanded = preCollapseState[f.id]; changed = true; }
                    }
                    if (f.children) restore(f.children);
                  }
                };
                restore(S.folders);
                preCollapseState = null;
              } else {
                preCollapseState = {};
                const collapseAll = (list) => {
                  for (const f of list) {
                    preCollapseState[f.id] = f.expanded;
                    if (f.expanded) { f.expanded = false; changed = true; }
                    if (f.children) collapseAll(f.children);
                  }
                };
                collapseAll(S.folders);
              }

              if (svgIcon) svgIcon.style.transform = (!allCollapsed) ? 'rotate(-90deg)' : 'rotate(0deg)';
              if (changed) { saveS(false); reRenderFolders(); }
            }
          }, true);
        });
      }

      if (input && !document.getElementById('mm-search-wrapper')) {
        // --- FIX FOUC : marquer l'input comme "en cours d'injection" pour que le CSS ne le cache plus ---
        input.classList.add('mm-wrapper-injected');

        const wrapper = mk('div', '', 'position:relative; display:flex; flex:1; min-width:0; margin-left:8px; pointer-events:auto;');
        wrapper.id = 'mm-search-wrapper';

        input.parentNode.insertBefore(wrapper, input);
        wrapper.appendChild(input);

        input.style.setProperty('padding-right', '56px', 'important');
        input.style.setProperty('width', '100%', 'important');

        const customInput = mk('input', 'input mm-folder-search');
        customInput.placeholder = 'Filter folders...';
        customInput.style.cssText = 'flex:1; width:100%; display:none; padding-left:12px; padding-right:56px; box-sizing:border-box; background:transparent !important; border:none !important; color:#fff !important; outline:none; margin:0; -webkit-text-fill-color: initial !important; opacity: 1 !important; z-index: 2; position: relative; pointer-events: auto !important;';

        wrapper.appendChild(customInput);

        customInput.addEventListener('mousedown', e => { e.stopPropagation(); });
        customInput.addEventListener('click', e => { e.stopPropagation(); customInput.focus(); });

        const toggleBox = mk('div', '', 'position:absolute; right:8px; top:50%; transform:translateY(-50%); display:flex; gap:4px; z-index:10;');

        const tTag = mk('div', '', 'display:flex; align-items:center; justify-content:center; width:22px; height:22px; cursor:pointer; color:#fff; transition:color 0.2s;');
        tTag.innerHTML = SVG_TAG; tTag.title = "Search Tags";

        const tFol = mk('div', '', 'display:flex; align-items:center; justify-content:center; width:22px; height:22px; cursor:pointer; color:rgba(255,255,255,0.3); transition:color 0.2s;');
        tFol.innerHTML = SVG_FOLDER; tFol.title = "Search Folders";

        toggleBox.append(tTag, tFol);
        wrapper.appendChild(toggleBox);

        const updateToggle = (mode) => {
          if (currentSearchMode === mode) return;
          currentSearchMode = mode;

          const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
          if (input.value) { if (nativeSetter) nativeSetter.call(input, ''); else input.value = ''; input.dispatchEvent(new Event('input', {bubbles:true})); }
          if (customInput.value) { customInput.value = ''; customInput.dispatchEvent(new Event('input')); }

          if (mode === 'tags') {
            tTag.style.color = '#fff';
            tFol.style.color = 'rgba(255,255,255,0.3)';
            input.style.setProperty('display', 'block', 'important');
            customInput.style.setProperty('display', 'none', 'important');
            document.querySelectorAll('.mm-folder-hidden').forEach(el => el.classList.remove('mm-folder-hidden'));
            input.focus();
          } else {
            tFol.style.color = '#fff';
            tTag.style.color = 'rgba(255,255,255,0.3)';
            input.style.setProperty('display', 'none', 'important');
            customInput.style.setProperty('display', 'block', 'important');
            customInput.focus();
          }
        };

        tTag.addEventListener('mousedown', e => { e.preventDefault(); });
        tFol.addEventListener('mousedown', e => { e.preventDefault(); });
        tTag.onclick = () => updateToggle(currentSearchMode === 'tags' ? 'folders' : 'tags');
        tFol.onclick = () => updateToggle(currentSearchMode === 'folders' ? 'tags' : 'folders');

        customInput.addEventListener('input', (e) => {
          const term = e.target.value.toLowerCase().trim();

          if (!term) {
            document.querySelectorAll('.mm-folder-hidden').forEach(el => el.classList.remove('mm-folder-hidden'));
            if (preSearchExpandedState) {
              const restoreState = (list) => {
                for (const f of list) {
                  if (preSearchExpandedState[f.id] !== undefined) f.expanded = preSearchExpandedState[f.id];
                  if (f.children) restoreState(f.children);
                }
              };
              restoreState(S.folders);
              preSearchExpandedState = null;
              saveS(false); reRenderFolders();
            }
            return;
          }

          if (!preSearchExpandedState) {
            preSearchExpandedState = {};
            const saveState = (list) => {
              for (const f of list) { preSearchExpandedState[f.id] = f.expanded; if (f.children) saveState(f.children); }
            };
            saveState(S.folders);
          }

          let changed = false;
          const filterF = (list) => {
            let anyMatch = false;
            for (const f of list) {
              const el = document.querySelector(`[data-mm-folder="${f.id}"]`);
              let nameMatch = f.name.toLowerCase().includes(term);
              let childMatch = false;
              if (f.children && f.children.length) childMatch = filterF(f.children);

              if (nameMatch || childMatch) {
                anyMatch = true;
                if (el) el.classList.remove('mm-folder-hidden');
                if (childMatch && !f.expanded) { f.expanded = true; changed = true; }
              } else {
                if (el) el.classList.add('mm-folder-hidden');
              }
            }
            return anyMatch;
          };
          filterF(S.folders);
          if (changed) { saveS(false); reRenderFolders(); customInput.focus(); }
        });
      }

      const customInput = header.querySelector('.mm-folder-search');
      if (customInput) {
        if (currentSearchMode === 'tags' && input.style.display === 'none') {
          input.style.setProperty('display', 'block', 'important');
          customInput.style.setProperty('display', 'none', 'important');
        } else if (currentSearchMode === 'folders' && customInput.style.display === 'none') {
          input.style.setProperty('display', 'none', 'important');
          customInput.style.setProperty('display', 'block', 'important');
        }
      }

      const sortBtns = document.querySelectorAll('.tag-manager__sort .button-group__button');
      sortBtns.forEach(btn => {
        if (!btn.dataset.mmSortHijacked) {
          btn.dataset.mmSortHijacked = "1";
          btn.addEventListener('click', (e) => {
            const mode = btn.textContent.trim().toLowerCase();
            if (mode === 'name' || mode === 'amount') {
              if (!preSortSnapshot) preSortSnapshot = JSON.stringify(S.folders);
              const sortFolders = (list) => {
                if (mode === 'name') list.sort((a, b) => a.name.localeCompare(b.name));
                else if (mode === 'amount') {
                  const getAmt = f => allTagsAndAliasesOf(f).length;
                  list.sort((a, b) => getAmt(b) - getAmt(a));
                }
                list.forEach(f => { if (f.children) sortFolders(f.children); });
              };
              sortFolders(S.folders);
              saveS(false); reRenderFolders();
            } else if (mode === 'default') {
              if (preSortSnapshot) {
                S.folders = JSON.parse(preSortSnapshot);
                preSortSnapshot = null;
                saveS(false); reRenderFolders();
              }
            }
          });
        }
      });
    };

    runHeaderSetup();
    setInterval(runHeaderSetup, 800);
  }

  let _tooltip = null, _tooltipTimeout = null, _tooltipLi = null, _hideTooltipTimeout = null;

  function hidePathTooltip(force = false) {
    if (!_tooltip) return;
    if (force) {
      _tooltip.remove();
      _tooltip = null;
    } else {
      _tooltip.classList.remove('mm-tt-visible');
      setTimeout(() => {
        if (_tooltip && !_tooltip.classList.contains('mm-tt-visible')) {
          _tooltip.remove();
          _tooltip = null;
        }
      }, 150);
    }
  }

  // --- FIX TOOLTIP : positionné pour ne jamais obstruer le tag survolé ---
  function showPathTooltip(tagName, targetLi, mouseX, mouseY) {
    const path = getFolderPath(tagName);
    if (!path.length) { hidePathTooltip(true); return; }
    if (_tooltip && _tooltip.dataset.tag === tagName) return;
    _tooltip?.remove(); _tooltip = null;

    const tt = mk('div', '', ''); tt.id = 'mm-path-tooltip'; tt.dataset.tag = tagName;
    const totalChars = path.reduce((sum, f) => sum + f.name.length, 0);
    const isCol = totalChars > 35 || path.length > 3;
    if (isCol) tt.classList.add('mm-tt-col');

    const pathWrap = mk('div', 'mm-tt-path-wrap');
    path.forEach((folder, i) => {
      const isLast = i === path.length - 1;
      const row = mk('div', 'mm-tt-row');
      if (isCol && i > 0) { row.style.paddingLeft = (i * 9 + 2) + 'px'; row.style.borderLeft = `1.5px solid rgba(255,255,255,${Math.min(0.08 + i * 0.06, 0.24)})`; row.style.marginLeft = '4px'; }
      const bg = folder.color || '#c0f0f8';
      const dot = mk('div', 'mm-tt-dot'); dot.style.background = bg; dot.style.boxShadow = `0 0 5px ${bg}55`;
      const name = mk('span', 'mm-tt-name'); name.textContent = folder.name;
      row.appendChild(dot); row.appendChild(name);

      if (!isCol) {
        pathWrap.appendChild(row);
        if (!isLast) { const arr = mk('span', 'mm-tt-arrow'); arr.innerHTML = '<svg viewBox="0 0 24 24" width="10" height="10" fill="currentColor" style="color:rgba(255,255,255,.55)"><path d="M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z"/></svg>'; pathWrap.appendChild(arr); }
      } else {
        pathWrap.appendChild(row);
        if (!isLast) { const connector = mk('div', 'mm-tt-connector'); connector.style.paddingLeft = (i * 9 + 6) + 'px'; connector.style.marginTop = '-1px'; connector.style.marginBottom = '-1px'; connector.innerHTML = '↳'; pathWrap.appendChild(connector); }
      }
    });

    tt.appendChild(pathWrap);
    const hint = mk('div', 'mm-tt-hint');
    hint.textContent = 'Click to show in folder';
    tt.appendChild(hint);

    tt.onclick = (e) => {
      e.stopPropagation();
      hidePathTooltip(true);
      window.mmSkipRenderCascade = true;

      const customInput = document.querySelector('.mm-folder-search');
      if (customInput) { customInput.value = ''; customInput.dispatchEvent(new Event('input', {bubbles:true})); }

      const nativeInput = document.querySelector('input.input[placeholder*="Filter"]');
      if (nativeInput) {
        const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
        if (nativeSetter) nativeSetter.call(nativeInput, ''); else nativeInput.value = '';
        nativeInput.dispatchEvent(new Event('input', {bubbles:true}));
      }

      document.body.classList.remove('mm-search-mode', 'mm-search-exiting');
      reRenderFolders();
      showOriginalTag(tagName);
    };

    document.body.appendChild(tt); _tooltip = tt;

    // --- Positionnement intelligent : toujours à droite du tag, jamais dessus ---
    // --- Positionnement en dessous du tag ---
    requestAnimationFrame(() => {
      const ttRect = tt.getBoundingClientRect();
      const liRect = targetLi ? targetLi.getBoundingClientRect() : null;

      let left, top;

      if (liRect) {
        left = liRect.left;
        top = liRect.bottom + 6;
        // Si ça dépasse l'écran à droite
        if (left + ttRect.width > window.innerWidth - 8) {
          left = window.innerWidth - ttRect.width - 8;
        }
      } else {
        left = mouseX + 14;
        top = mouseY + 14;
      }

      // Bornes verticales
      if (top < 8) top = 8;
      if (top + ttRect.height > window.innerHeight - 8) top = window.innerHeight - ttRect.height - 8;

      tt.style.left = left + 'px';
      tt.style.top = top + 'px';
      requestAnimationFrame(() => tt.classList.add('mm-tt-visible'));
    });
  }

  function bindTooltipListeners() {
    document.addEventListener('mouseover', e => {
      if (!document.body.classList.contains('mm-search-mode')) return;
      if (document.body.classList.contains('mm-hide-tooltips')) return;

      // Si la souris passe sur le tooltip, on annule sa disparition
      if (e.target.closest('#mm-path-tooltip')) {
        clearTimeout(_hideTooltipTimeout);
        return;
      }

      const li = e.target.closest('li.tag.has-button:not([data-mm])');
      if (!li || li === _tooltipLi) return;
      _tooltipLi = li; clearTimeout(_tooltipTimeout); clearTimeout(_hideTooltipTimeout);
      const name = nameFromLi(li); if (!name) return;

      _tooltipTimeout = setTimeout(() => {
        if (_tooltipLi !== li) return;
        showPathTooltip(name, li, e.clientX, e.clientY);
      }, 100);
    }, true);

    document.addEventListener('mouseout', e => {
      if (e.relatedTarget && e.relatedTarget.closest('#mm-path-tooltip')) return;
      const li = e.target.closest('li.tag.has-button:not([data-mm])');
      if (!li || li.contains(e.relatedTarget) || li !== _tooltipLi) return;

      // On donne 350ms à l'utilisateur pour atteindre le tooltip
      _hideTooltipTimeout = setTimeout(() => {
        _tooltipLi = null; clearTimeout(_tooltipTimeout); hidePathTooltip();
      }, 350);
    }, true);
  }

  function showInfoModal() {
    const ov = mk('div', '', 'position:fixed;inset:0;background:rgba(0,0,0,.8);z-index:999999;display:flex;align-items:center;justify-content:center;');
    const box = mk('div', '', 'background:rgba(22,22,19,0.85);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:24px;width:420px;color:#e8e8e8;font-family:"Open Sans",sans-serif;box-shadow:0 24px 64px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.05);line-height:1.5;font-size:13px;');
    box.innerHTML = `
      <h2 style="margin:0 0 15px 0;font-size:17px;color:#fff;">Help & Warnings</h2>
      <ul style="padding-left:20px;margin-bottom:20px;color:rgba(255,255,255,.85);display:flex;flex-direction:column;gap:12px;">
        <li><b>Security:</b> This script NEVER deletes your original tags. Deleting a folder simply releases the tags inside it back to the main list.</li>
        <li><b>Aliases:</b> Right-click a tag button → "Create alias" to copy it visually. Aliases don't duplicate the native tag.</li>
        <li><b>Renaming:</b> If you rename a tag via the site's native menu, the script will ask if you want to update your aliases. The tag will temporarily leave its folder — drag it back in after renaming.</li>
        <li><b>Cloud Save:</b> Remember to click the <b>Save Folders</b> button. The script creates a special tag [⚠️_DO_NOT_DELETE...] on your map to hide the data. Do not delete it!</li>
        <li><b>Search:</b> When you type in the search bar, folders hide and all matching tags appear directly. Hover a tag (400ms) to see which folder it belongs to.</li>
      </ul>
      <div style="font-size:11px;opacity:.5;margin-bottom:20px;font-style:italic;">Note: This script is provided as is. The author is not responsible for the loss of your folder organization due to mishandling or unsaved cache clearing.</div>
      <div style="text-align:right;"><button id="mm-close-info" style="background:#fff;border:none;border-radius:10px;color:#121210;padding:10px 20px;cursor:pointer;font-weight:700;font-size:13px;box-shadow:0 4px 12px rgba(255,255,255,.2);transition:all .2s;">Got it!</button></div>
    `;
    ov.appendChild(box); document.body.appendChild(ov);
    const closeBtn = box.querySelector('#mm-close-info');
    closeBtn.onmouseenter = () => closeBtn.style.background = '#e0e0e0';
    closeBtn.onmouseleave = () => closeBtn.style.background = '#fff';
    closeBtn.onclick = () => ov.remove();
    ov.onclick = e => { if (e.target === ov) ov.remove(); };
  }

  const SVG_PEN = `<svg viewBox="0 0 24 24" width="14" height="14" fill="currentColor" style="pointer-events:none;flex-shrink:0"><path d="M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z"/></svg>`;
  const SVG_ARR = deg => `<svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" style="display:block;transition:transform .2s;transform:rotate(${deg}deg);pointer-events:none"><path d="M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z"/></svg>`;

  const mk = (tag, cls = '', css = '', attrs = {}) => {
    const e = document.createElement(tag);
    if (cls) e.className = cls;
    if (css) e.style.cssText = css;
    Object.entries(attrs).forEach(([k, v]) => e.setAttribute(k, v));
    return e;
  };

  let dragTag = null;
  let dragFolderId = null;
  let dragAlias = null;
  let dragAliasFolderId = null;

  function initDnD() {
    document.addEventListener('dragstart', e => {
      const li = e.target.closest('li.tag.has-button:not([data-mm])');
      if (!li) return;
      dragTag = nameFromLi(li);
      try { e.dataTransfer.setData('text/plain', dragTag); } catch (_) {}
      li.style.opacity = '.45';
    }, true);
   document.addEventListener('dragend', e => {
      const li = e.target.closest('li.tag.has-button:not([data-mm])');
      if (li) { li.style.opacity = ''; dragTag = null; }
      document.querySelectorAll('.mm-drag-spacer').forEach(s => s.remove());
      document.querySelectorAll('.mm-dh').forEach(el => el.classList.remove('mm-dh'));
    }, true);
  }

  function dndOn(el, folderId) {
    el.addEventListener('dragover', e => {
      if (dragFolderId || (!dragTag && !dragAlias)) return;

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

      if (dragTag) {
        const currentFolder = folderOf(dragTag);
        if (!currentFolder || currentFolder.id !== folderId) el.classList.add('mm-dh');
      } else if (dragAlias && dragAliasFolderId !== folderId && !el.classList.contains('mm-hd')) {
        el.classList.add('mm-dh');
      }

      if (el.classList.contains('mm-body')) {
        const isExplicitSpace = e.target.classList.contains('mm-dropzone') || e.target.classList.contains('mm-subaddbtn');
        let shouldGoToEnd = isExplicitSpace;

        // Si on survole le fond du dossier, on vérifie si on est VRAIMENT à la fin
        if (!shouldGoToEnd && e.target === el) {
          const tags = el.querySelectorAll('.mm-tag-btn');
          if (tags.length === 0) {
            shouldGoToEnd = true;
          } else {
            const lastTag = tags[tags.length - 1];
            const rect = lastTag.getBoundingClientRect();

            // On est "à la fin" si la souris est plus bas que le dernier tag
            if (e.clientY > rect.bottom) {
              shouldGoToEnd = true;
            }
            // Ou si on est à la même hauteur, mais à sa droite
            else if (e.clientY > rect.top && e.clientX > rect.right) {
              shouldGoToEnd = true;
            }
          }
        }

        // On ne déplace la barre à la fin QUE si c'est légitime (ça évite le flicker)
        if (shouldGoToEnd) {
          let spacer = el.querySelector('.mm-drag-spacer');
          if (!spacer) {
            spacer = document.createElement('div');
            spacer.className = 'mm-drag-spacer';
            spacer.style.cssText = 'display:inline-flex;width:4px;height:32px;background:rgba(255,255,255,0.6);border-radius:2px;flex-shrink:0;pointer-events:none;margin:0 2px;';
          }
          const addSub = el.querySelector('.mm-subaddbtn');
          if (addSub) el.insertBefore(spacer, addSub);
          else el.appendChild(spacer);
        }
      }
    });

    el.addEventListener('dragleave', e => {
      if (!el.contains(e.relatedTarget)) el.classList.remove('mm-dh');
    });

    el.addEventListener('drop', e => {
      if (dragFolderId) return;
      el.classList.remove('mm-dh');

      let spacer = null;
      let insertBefore = null;
      if (el.classList.contains('mm-body')) {
        spacer = el.querySelector('.mm-drag-spacer');
        if (spacer) {
          insertBefore = spacer.nextSibling;
          spacer.remove();
        }
      }

      const targetTag = insertBefore?.classList?.contains('mm-tag-btn') ? insertBefore.dataset.mmTag : null;
      const targetIsAlias = insertBefore?.classList?.contains('mm-tag-btn--alias') ?? false;

      if (dragAlias) {
        const tag = dragAlias, fromId = dragAliasFolderId;
        e.preventDefault(); e.stopPropagation();
        dragAlias = null; dragAliasFolderId = null;

        if (fromId !== folderId) moveAlias(tag, fromId, folderId);

        if (el.classList.contains('mm-body')) {
          reorderMixed(tag, true, targetTag, targetIsAlias, folderId);
        }
      } else {
        const tag = dragTag || e.dataTransfer.getData('text/plain');
        if (!tag) return;
        const currentFolder = folderOf(tag);
        e.preventDefault(); e.stopPropagation();
        dragTag = null;

        if (!currentFolder || currentFolder.id !== folderId) moveTag(tag, folderId);

        if (el.classList.contains('mm-body')) {
          reorderMixed(tag, false, targetTag, targetIsAlias, folderId);
        }
      }
    });
  }

  function reRenderFolders() {
    const ul = getMainUl();
    if (ul) renderInto(ul);
    updateHideStyle();
  }

  function moveTag(tag, folderId) {
    const cleanTag = tag.trim();
    let changed = false;
    document.querySelectorAll('.mm-tag-btn').forEach(btn => {
      if (btn.dataset.mmTag === cleanTag && !btn.classList.contains('mm-tag-btn--alias')) { btn.remove(); changed = true; }
    });
    const walkRemove = (list) => {
      for (const f of list) {
        if (f.tags) { const ol = f.tags.length; f.tags = f.tags.filter(t => t.trim() !== cleanTag); if (f.tags.length !== ol) changed = true; }
        if (f.children) walkRemove(f.children);
      }
    };
    walkRemove(S.folders);
    const f = findF(folderId);
    if (f && !f.tags.some(t => t.trim() === cleanTag)) {
      f.tags.push(cleanTag);
      // --- FIX DnD : ouvrir le dossier de destination après un drop ---
      if (!f.expanded) { f.expanded = true; }
      changed = true;
    }
    if (changed) { invalidateFlatCache(); saveS(); reRenderFolders(); }
  }

  function removeTag(tag) {
    const cleanTag = tag.trim();
    let changed = false;
    document.querySelectorAll('.mm-tag-btn').forEach(btn => {
      if (btn.dataset.mmTag === cleanTag) { btn.remove(); changed = true; }
    });
    const walk = (list) => {
      for (const f of list) {
        if (f.tags) { const ol = f.tags.length; f.tags = f.tags.filter(t => t.trim() !== cleanTag); if (f.tags.length !== ol) changed = true; }
        if (f.aliases) { const ol = f.aliases.length; f.aliases = f.aliases.filter(t => t.trim() !== cleanTag); if (f.aliases.length !== ol) changed = true; }
        if (f.children) walk(f.children);
      }
    };
    walk(S.folders);
    if (changed) { invalidateFlatCache(); saveS(); reRenderFolders(); }
  }

  function addAlias(tag, folderId) {
    const f = findF(folderId);
    if (!f) return;
    if (!f.aliases) f.aliases = [];
    if (!f.aliasConfig) f.aliasConfig = {};

    f.aliases.push(tag);
    f.aliasConfig[tag] = { ...f.aliasConfig[tag], customName: tag };

    invalidateFlatCache();
    saveS();
    reRenderFolders();
  }

  function removeAlias(tag, folderId) {
    const f = findF(folderId);
    if (!f || !f.aliases) return;
    const idx = f.aliases.indexOf(tag);
    if (idx !== -1) {
      f.aliases.splice(idx, 1);
      invalidateFlatCache(); saveS(); reRenderFolders();
    }
  }

  function moveAlias(tag, fromFolderId, toFolderId) {
    if (fromFolderId === toFolderId) return;
    const from = findF(fromFolderId);
    const to = findF(toFolderId);
    if (!from || !to) return;

    const configToMove = from.aliasConfig ? from.aliasConfig[tag] : null;

    const idx = from.aliases.indexOf(tag);
    if (idx !== -1) from.aliases.splice(idx, 1);
    if (from.aliasConfig) delete from.aliasConfig[tag];

    if (!to.aliases) to.aliases = [];
    if (!to.aliasConfig) to.aliasConfig = {};

    to.aliases.push(tag);
    if (configToMove) to.aliasConfig[tag] = configToMove;

    if (!to.expanded) to.expanded = true;
    invalidateFlatCache();
    saveS();
    reRenderFolders();
  }

    function showRenameModal(oldName, newName, count) {
    return new Promise(res => {
      const ov = mk('div', '', 'position:fixed;inset:0;background:rgba(0,0,0,.7);backdrop-filter:blur(3px);z-index:999999;display:flex;align-items:center;justify-content:center;');
      const box = mk('div', '', 'background:rgba(22,22,19,0.95);border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:24px;width:380px;color:#e8e8e8;font-family:"Open Sans",sans-serif;box-shadow:0 24px 64px rgba(0,0,0,.8);');

      // En-tête : ICÔNE CRAYON EN BLANC (stroke="#fff" au lieu de "#60a5fa")
      const header = mk('div', '', 'display:flex;align-items:center;gap:10px;margin-bottom:12px;');
      header.innerHTML = `<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg><h2 style="margin:0;font-size:16px;font-weight:700;color:#fff;">Tag Renamed</h2>`;
      box.appendChild(header);

      // Texte d'intro
      const text = mk('p', '', 'margin:0 0 20px 0;font-size:13px;color:rgba(255,255,255,.7);line-height:1.4;');
      text.innerHTML = `<b>"${escapeHTML(oldName)}"</b> is now <b>"${escapeHTML(newName)}"</b>.<br>Update its ${count} alias(es)?`;
      box.appendChild(text);

      const btnWrap = mk('div', '', 'display:flex;flex-direction:column;gap:8px;');

      // Fonction utilitaire pour créer les boutons avec des codes couleurs clairs
      const createBtn = (icon, title, desc, type = 'normal') => {
        let bg, border, hoverBg, textColor;

        if (type === 'success') { // VERT
          bg = 'rgba(74,222,128,.08)'; border = 'rgba(74,222,128,.2)'; hoverBg = 'rgba(74,222,128,.15)'; textColor = '#4ade80';
        } else if (type === 'info') { // BLEU
          bg = 'rgba(96,165,250,.08)'; border = 'rgba(96,165,250,.2)'; hoverBg = 'rgba(96,165,250,.15)'; textColor = '#60a5fa';
        } else if (type === 'danger') { // ROUGE
          bg = 'rgba(248,113,113,.08)'; border = 'rgba(248,113,113,.2)'; hoverBg = 'rgba(248,113,113,.15)'; textColor = '#f87171';
        }

        const b = mk('button', '', `display:flex;align-items:center;gap:14px;background:${bg};border:1px solid ${border};border-radius:12px;padding:12px 14px;color:${textColor};cursor:pointer;text-align:left;transition:all .2s;`);
        b.innerHTML = `
          <div style="display:flex;align-items:center;justify-content:center;color:${textColor};">${icon}</div>
          <div style="display:flex;flex-direction:column;gap:2px;">
            <span style="font-weight:600;font-size:13px;color:${textColor};">${title}</span>
            <span style="font-size:11px;opacity:.7;font-weight:400;color:${textColor};">${desc}</span>
          </div>
        `;
        b.onmouseenter = () => { b.style.background = hoverBg; };
        b.onmouseleave = () => { b.style.background = bg; };
        return b;
      };

      const svgSync = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/></svg>`;
      const svgKeep = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>`;
      const svgTrash = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>`;

      // On applique les types : 'success' (vert), 'info' (bleu), 'danger' (rouge)
      const btnUpdateAll = createBtn(svgSync, 'Rename Tag & Aliases', `Update everything to "${escapeHTML(newName)}"`, 'success');
      const btnKeepName = createBtn(svgKeep, 'Keep Custom Alias Names', 'Only update the original tag name', 'info');
      const btnDelete = createBtn(svgTrash, 'Delete Aliases', 'Remove them from folders', 'danger');

      btnUpdateAll.onclick = () => { ov.remove(); res('update_all'); };
      btnKeepName.onclick = () => { ov.remove(); res('keep_name'); };
      btnDelete.onclick = () => { ov.remove(); res('delete'); };

      btnWrap.append(btnUpdateAll, btnKeepName, btnDelete);
      box.appendChild(btnWrap);
      ov.appendChild(box);
      document.body.appendChild(ov);
    });
  }


  // --- FEATURE : Détection de renommage natif et proposition de mise à jour des alias ---
  let _tagNamesSnapshot = new Map(); // tagId -> name, suivi entre les dialogues
  function watchNativeTagRenames() {
    const obs = new MutationObserver(() => {
      const dialog = document.querySelector('div[role="dialog"]');
      if (!dialog) return;

      const input = dialog.querySelector('input[type="text"].input');
      if (!input || dialog.dataset.mmRenameWatched) return;
      dialog.dataset.mmRenameWatched = '1';

      const oldName = input.value || '';
      if (!oldName || oldName.startsWith(STORAGE_PREFIX) || oldName.startsWith(OLD_STORAGE_PREFIX)) return;

      // On capte la touche Entrée ou le clic sur "Save"
      input.addEventListener('keydown', e => { if (e.key === 'Enter') dialog.dataset.mmSavedName = input.value; });
      const btns = dialog.querySelectorAll('button');
      const saveBtn = btns[btns.length - 1];
      if (saveBtn) saveBtn.addEventListener('mousedown', () => { dialog.dataset.mmSavedName = input.value; });

      const dialogObs = new MutationObserver(() => {
        if (document.contains(dialog)) return;
        dialogObs.disconnect();

        const newName = dialog.dataset.mmSavedName;
        if (!newName || newName === oldName) return;

        // On cible TOUS les dossiers qui ont le tag (vrai tag ou alias)
        const foldersToUpdate = flat().filter(f =>
          (f.tags && f.tags.includes(oldName)) ||
          (f.aliases && f.aliases.includes(oldName))
        );
        if (!foldersToUpdate.length) return;

        setTimeout(async () => {
          const totalAliases = foldersToUpdate.reduce((sum, f) => sum + (f.aliases ? f.aliases.filter(a => a === oldName).length : 0), 0);

          let action = 'update_all';
          if (totalAliases > 0) {
            action = await showRenameModal(oldName, newName, totalAliases);
          }

          foldersToUpdate.forEach(f => {
            if (f.tags && f.tags.includes(oldName)) {
              f.tags = f.tags.map(t => t === oldName ? newName : t);
            }
            if (f.aliases && f.aliases.includes(oldName)) {
              if (action === 'delete') {
                f.aliases = f.aliases.filter(a => a !== oldName);
                if (f.aliasConfig) delete f.aliasConfig[oldName];
              } else {
                f.aliases = f.aliases.map(a => a === oldName ? newName : a);
                if (f.aliasConfig && f.aliasConfig[oldName]) {
                  f.aliasConfig[newName] = { ...f.aliasConfig[oldName] };
                  if (action === 'update_all') {
                    f.aliasConfig[newName].customName = newName;
                  }
                  delete f.aliasConfig[oldName];
                } else if (action === 'keep_name') {
                  if (!f.aliasConfig) f.aliasConfig = {};
                  f.aliasConfig[newName] = { applyGrad: true, useOriginal: false, customColor: '#5a5a8a', customName: oldName };
                }
              }
            }
          });

          _nativeTagMapCache = null;
          _flatCacheDirty = true;
          _allTagsCache = null;
          invalidateFlatCache();
          saveS();

          // Attend que le DOM natif affiche le nouveau nom avant de re-render
          const waitForRename = (name, maxTries = 40, interval = 150) => {
            return new Promise(resolve => {
              let tries = 0;
              const check = setInterval(() => {
                tries++;
                _nativeTagMapCache = null;
                const lis = document.querySelectorAll('li.tag.has-button:not([data-mm])');
                const found = Array.from(lis).some(el => nameFromLi(el) === name);
                if (found || tries >= maxTries) {
                  clearInterval(check);
                  resolve(found);
                }
              }, interval);
            });
          };

          waitForRename(newName).then(() => {
            _nativeTagMapCache = null;
            invalidateFlatCache();
            reRenderFolders();
          });

        }, 300);
      });
      dialogObs.observe(document.body, { childList: true, subtree: true });
    });
    obs.observe(document.body, { childList: true, subtree: true });

    // Intercepter le nom sauvegardé avant fermeture du dialogue
    document.addEventListener('click', e => {
      const dialog = document.querySelector('div[role="dialog"]');
      if (!dialog) return;
      const btn = e.target.closest('.edit-tag-modal__actions button, button.save');
      if (!btn) return;
      const input = dialog.querySelector('input[type="text"].input');
      if (input) _lastDialogSavedName = input.value;
    }, true);
  }
  let _lastDialogSavedName = null;

  function showOriginalTag(tagName) {
    const f = folderOf(tagName);
    if (!f) return;
    const path = getFolderPath(tagName);
    let changed = false;
    path.forEach(pf => {
      if (!pf.expanded) { pf.expanded = true; changed = true; }
    });

    if (changed) { saveS(false); reRenderFolders(); }

    const glowColor = localStorage.getItem('mmapp_glow_color') || '#4ade80';

    let attempts = 0;
    if (window.mmGlowInterval) clearInterval(window.mmGlowInterval);

    window.mmGlowInterval = setInterval(() => {
      attempts++;
      const folderEl = document.querySelector(`[data-mm-folder="${f.id}"]`);
      if (folderEl) {
        clearInterval(window.mmGlowInterval);
        const tagBtns = Array.from(folderEl.querySelectorAll('.mm-tag-btn:not(.mm-tag-btn--alias)'));
        const targetBtn = tagBtns.find(b => b.dataset.mmTag === tagName);
        const el = targetBtn || folderEl.querySelector('.mm-hd') || folderEl;

        el.scrollIntoView({ block: 'center' });

        el.style.transition = 'box-shadow 0.2s';
        el.style.setProperty('box-shadow', `0 0 0 3px ${glowColor}, 0 0 18px ${glowColor}bb`, 'important');

        setTimeout(() => {
          if (el) {
            el.style.transition = 'box-shadow 0.8s ease-out';
            el.style.removeProperty('box-shadow');
            setTimeout(() => el.style.removeProperty('transition'), 800);
          }
        }, 1200);
      } else if (attempts > 20) {
        clearInterval(window.mmGlowInterval);
      }
    }, 50);
  }
  function reorderFolder(dragId, targetId) {
    if (dragId === targetId) return;
    const dragged = extractFolder(dragId); if (!dragged) return;
    const insert = list => { const i = list.findIndex(f => f.id === targetId); if (i !== -1) { list.splice(i, 0, dragged); return true; } return list.some(f => insert(f.children || [])); };
    if (!insert(S.folders)) S.folders.push(dragged);
    saveS(); reRenderFolders();
  }

  function moveFolderInto(dragId, targetId) {
    if (dragId === targetId) return;
    if (isDescendant(dragId, targetId)) return;
    const dragged = extractFolder(dragId); if (!dragged) return;
    const target = findF(targetId);
    if (!target) { S.folders.push(dragged); saveS(); reRenderFolders(); return; }
    if (!target.children) target.children = [];
    target.children.push(dragged);
    // --- FIX DnD : ouvrir le dossier parent quand on y dépose un sous-dossier ---
    target.expanded = true;
    saveS(); reRenderFolders();
  }

  function reorderTag(draggedName, targetName) {
    if (draggedName === targetName) return;
    const targetFolder = folderOf(targetName); if (!targetFolder) return;
    const sourceFolder = folderOf(draggedName); if (!sourceFolder || sourceFolder.id !== targetFolder.id) return;
    targetFolder.tags = targetFolder.tags.filter(t => t !== draggedName);
    const newTargetIndex = targetFolder.tags.indexOf(targetName);
    targetFolder.tags.splice(newTargetIndex, 0, draggedName);
    saveS(); reRenderFolders();
  }

  function reorderAlias(draggedName, targetName, folderId) {
    if (draggedName === targetName) return;
    const f = findF(folderId);
    if (!f || !f.aliases) return;
    f.aliases = f.aliases.filter(t => t !== draggedName);
    const idx = f.aliases.indexOf(targetName);
    if (idx !== -1) f.aliases.splice(idx, 0, draggedName);
    else f.aliases.push(draggedName);
    saveS(); reRenderFolders();
  }

   function reorderMixed(dragName, isDragAlias, targetName, isTargetAlias, folderId) {
    const f = findF(folderId);
    if (!f) return;
    if (!f.itemsOrder) {
      f.itemsOrder = [];
      if (f.tags) f.tags.forEach(t => f.itemsOrder.push('tag:' + t));
      if (f.aliases) f.aliases.forEach(t => f.itemsOrder.push('alias:' + t));
    }
    const dragKey = (isDragAlias ? 'alias:' : 'tag:') + dragName;
    if (!f.itemsOrder.includes(dragKey)) f.itemsOrder.push(dragKey);

    const targetKey = (isTargetAlias ? 'alias:' : 'tag:') + targetName;

    f.itemsOrder = f.itemsOrder.filter(k => k !== dragKey);
    const tIdx = f.itemsOrder.indexOf(targetKey);
    if (tIdx !== -1) f.itemsOrder.splice(tIdx, 0, dragKey);
    else f.itemsOrder.push(dragKey);

    saveS(); reRenderFolders();
  }

  function modal(cfg) {
    return new Promise(res => {
      const ov = mk('div', '', 'position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:99999;display:flex;align-items:center;justify-content:center;', { 'data-mm': '1' });
      const box = mk('div', '', 'background:rgba(22,22,19,0.85);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,0.08);border-radius:16px;padding:24px 20px;width:320px;color:#e8e8e8;font-family:"Open Sans",sans-serif;font-size:13px;box-shadow:0 24px 64px rgba(0,0,0,0.6), inset 0 1px 0 rgba(255,255,255,0.05);');
      const ttl = mk('div', '', 'font-size:16px;font-weight:700;margin-bottom:20px;color:#fff;'); ttl.textContent = cfg.title; box.appendChild(ttl);
      const fels = {};

      const mkToggleBtn = (label, active) => {
        const btn = mk('button', '', `display:flex;align-items:center;justify-content:center;width:100%;border-radius:10px;padding:10px 12px;cursor:pointer;font-size:12px;font-family:"Open Sans",sans-serif;margin-bottom:8px;transition:all .2s;font-weight:600;border:1px solid transparent;`);
        btn.textContent = label;
        btn._isActive = active;
        btn._updateVis = () => {
          if (btn._isActive) {
            btn.style.background = 'rgba(255,255,255,.08)';
            btn.style.color = '#fff';
            btn.style.borderColor = 'rgba(255,255,255,.15)';
            btn.style.boxShadow = '0 2px 8px rgba(0,0,0,.1)';
          } else {
            btn.style.background = 'rgba(0,0,0,.15)';
            btn.style.color = 'rgba(255,255,255,.35)';
            btn.style.borderColor = 'rgba(255,255,255,.05)';
            btn.style.boxShadow = 'inset 0 2px 4px rgba(0,0,0,.1)';
          }
        };
        btn._updateVis();
        btn._toggle = () => {
          btn._isActive = !btn._isActive;
          btn._updateVis();
        };
        return btn;
      };

      const collect = () => {
        const r = {};
        Object.entries(fels).forEach(([k, e]) => {
          if (e.type === 'checkbox') r[k] = e.checked;
          else if (e.type === 'custom') r[k] = e.value;
          else r[k] = e.value;
        });
        return r;
      };
      const confirm_ = () => { cleanup(); ov.remove(); res(collect()); };
      const cancel_ = () => { cleanup(); ov.remove(); res(null); };
      const onKeyDown = e => {
        if (e.key === 'Escape') { e.preventDefault(); e.stopPropagation(); cancel_(); }
        if (e.key === 'Enter' && e.target.tagName !== 'BUTTON') { e.preventDefault(); confirm_(); }
      };
      const cleanup = () => document.removeEventListener('keydown', onKeyDown, true);
      document.addEventListener('keydown', onKeyDown, true);

      (cfg.fields || []).forEach(f => {
        const lbl = mk('label', '', 'display:block;font-size:10px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:rgba(255,255,255,.4);margin-bottom:6px;'); lbl.textContent = f.label; box.appendChild(lbl);
        const inp = mk('input');
        inp.type = 'text'; inp.placeholder = f.placeholder || ''; inp.value = f.value || '';
        inp.style.cssText = 'background:rgba(0,0,0,.25);border:1px solid rgba(255,255,255,.1);border-radius:10px;color:#fff;padding:10px 14px;font-size:13px;margin-bottom:14px;box-sizing:border-box;outline:none;font-family:"Open Sans",sans-serif;width:100%;display:block;box-shadow:inset 0 2px 4px rgba(0,0,0,.2);transition:border-color .2s;';
        inp.onfocus = () => inp.style.borderColor = 'rgba(255,255,255,.4)';
        inp.onblur = () => inp.style.borderColor = 'rgba(255,255,255,.1)';
        fels[f.key] = inp; box.appendChild(inp);
      });

      if (cfg.showFolderColor) {
        const lbl = mk('label', '', 'display:block;font-size:10px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:rgba(255,255,255,.4);margin-bottom:6px;'); lbl.textContent = 'Folder color'; box.appendChild(lbl);
        const fcRow = mk('div', '', 'display:flex;gap:8px;align-items:center;margin-bottom:6px;');
        const inp = mk('input', 'mm-color-inp'); inp.type = 'color'; inp.value = cfg.folderColor || '#c0f0f8';
        const fcHex = mk('input'); fcHex.type = 'text'; fcHex.value = inp.value; fcHex.maxLength = 7;
        fcHex.style.cssText = 'flex:1;background:rgba(0,0,0,.25);border:1px solid rgba(255,255,255,.1);border-radius:8px;color:#fff;padding:6px 10px;font-size:12px;font-family:monospace;outline:none;min-width:0;box-shadow:inset 0 2px 4px rgba(0,0,0,.2);transition:border-color .2s;box-sizing:border-box;';
        fcHex.onfocus = () => fcHex.style.borderColor = 'rgba(255,255,255,.4)';
        fcHex.onblur = () => fcHex.style.borderColor = 'rgba(255,255,255,.1)';
        inp.oninput = () => { fcHex.value = inp.value; };
        fcHex.oninput = () => { const v = fcHex.value.startsWith('#') ? fcHex.value : '#' + fcHex.value; if (/^#[0-9a-fA-F]{6}$/.test(v)) inp.value = v; };
        fcRow.append(inp, fcHex);
        fels.folderColor = inp; box.appendChild(fcRow);

        let useParentColorState = !!cfg.useParentColor;
        if (cfg.inheritedColor) {
          const upcRow = mk('div', '', 'display:flex;align-items:center;gap:8px;margin-bottom:16px;');
          const preview = mk('div', 'mm-color-box', `background:${cfg.inheritedColor};pointer-events:none;`);
          const upcBtn = mkToggleBtn('Use parent color', useParentColorState);
          upcBtn.style.marginBottom = '0';
          upcBtn.onclick = e => {
            e.preventDefault(); e.stopPropagation();
            upcBtn._toggle();
            useParentColorState = upcBtn._isActive;
            fcRow.style.opacity = useParentColorState ? '.35' : '1';
            fcRow.style.pointerEvents = useParentColorState ? 'none' : '';
          };
          if (useParentColorState) { fcRow.style.opacity = '.35'; fcRow.style.pointerEvents = 'none'; }
          upcRow.append(preview, upcBtn);
          box.appendChild(upcRow);
        } else {
          fcRow.style.marginBottom = '16px';
        }
        fels.useParentColor = { get checked() { return useParentColorState; }, type: 'checkbox' };
      }

      if (cfg.showColors) {
        let pinnedPresets = [];
try { pinnedPresets = JSON.parse(localStorage.getItem('mmapp_pinned_presets') || '[]'); } catch(_) {}
const savePin = name => {
  if (!pinnedPresets.includes(name)) pinnedPresets.push(name);
  localStorage.setItem('mmapp_pinned_presets', JSON.stringify(pinnedPresets));
};
const removePin = name => {
  pinnedPresets = pinnedPresets.filter(n => n !== name);
  localStorage.setItem('mmapp_pinned_presets', JSON.stringify(pinnedPresets));
};
const isPinned = name => pinnedPresets.includes(name);
        const lbl = mk('label', '', 'display:block;font-size:10px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:rgba(255,255,255,.4);margin-bottom:6px;');
        lbl.textContent = 'Gradient Colors (2 to 6)'; box.appendChild(lbl);
        const colorRow = mk('div', '', 'display:flex;gap:5px;margin-bottom:10px;align-items:center;width:100%;box-sizing:border-box;');
        let currentColors = [...(cfg.colors || ['#c0f0f8', '#183848'])];
        if (currentColors.length < 2) currentColors.push('#183848');
        const prev = mk('div', '', 'width:100%;height:5px;border-radius:4px;margin-bottom:12px;opacity:0.9;flex-shrink:0;');
        const upd = () => { prev.style.background = `linear-gradient(to right, ${currentColors.join(', ')})`; };
        const allPresets = [...GRADIENT_PRESETS];
        try { const stored = JSON.parse(localStorage.getItem('mmapp_custom_presets') || '[]'); stored.forEach(p => { if (p.name && p.colors) allPresets.push(p); }); } catch (_) {}

        const showAllGradientsModal = (presets, applyFn) => {
          const ov2 = mk('div', '', 'position:fixed;inset:0;background:rgba(0,0,0,.75);z-index:999999;display:flex;align-items:center;justify-content:center;');
          const box2 = mk('div', '', 'background:rgba(22,22,19,0.95);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:1px solid rgba(255,255,255,.08);border-radius:16px;padding:24px;width:420px;height:500px;max-height:85vh;display:flex;flex-direction:column;box-shadow:0 24px 64px rgba(0,0,0,.8), inset 0 1px 0 rgba(255,255,255,.05);');
          const topRow = mk('div', '', 'display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;flex-shrink:0;');
          const title = mk('div', '', 'color:#fff;font-weight:700;font-size:16px;font-family:"Open Sans",sans-serif;'); title.textContent = 'All Presets';
          const closeBtn = mk('button', '', 'background:transparent;border:none;color:rgba(255,255,255,.5);cursor:pointer;font-size:18px;line-height:1;padding:0;transition:color .2s;'); closeBtn.innerHTML = '✕';
          closeBtn.onmouseenter = () => closeBtn.style.color = '#fff'; closeBtn.onmouseleave = () => closeBtn.style.color = 'rgba(255,255,255,.5)'; closeBtn.onclick = () => ov2.remove();
          topRow.append(title, closeBtn);
          const searchInput = mk('input', '', 'background:rgba(0,0,0,.25);border:1px solid rgba(255,255,255,.1);border-radius:10px;color:#fff;padding:10px 14px;font-size:13px;margin-bottom:16px;outline:none;font-family:"Open Sans",sans-serif;box-shadow:inset 0 2px 4px rgba(0,0,0,.2);transition:border-color .2s;');
          searchInput.placeholder = 'Search "blue", "rose", "dark"...';
          searchInput.onfocus = () => searchInput.style.borderColor = 'rgba(255,255,255,.4)'; searchInput.onblur = () => searchInput.style.borderColor = 'rgba(255,255,255,.1)';

         const grid = mk('div', '', 'display:grid;grid-template-columns:repeat(5,1fr);gap:6px;overflow-y:auto;padding-right:8px;flex:1;min-height:0;align-content:start;');
          grid.style.scrollbarWidth = 'thin'; grid.style.scrollbarColor = 'rgba(255,255,255,.2) transparent';
          const renderGrid = filterText => {
            grid.innerHTML = '';
            let term = filterText.toLowerCase();
            const map = { 'bleu': 'blue', 'rouge': 'red', 'vert': 'green', 'jaune': 'yellow', 'noir': 'dark', 'blanc': 'white' };
            Object.entries(map).forEach(([fr, en]) => { term = term.replace(fr, en); });
            const filtered = presets.filter(p => p.name.toLowerCase().includes(term));
            if (!filtered.length) { const noRes = mk('div', '', 'width:100%;color:rgba(255,255,255,.4);font-size:12px;text-align:center;padding:10px;'); noRes.textContent = 'No preset found.'; grid.appendChild(noRes); return; }
            filtered.forEach(p => {
              const chip = mk('div', '', `background:linear-gradient(to right,${p.colors.join(',')});height:26px;border-radius:6px;box-shadow:inset 0 0 0 1px rgba(255,255,255,0.15);cursor:pointer;transition:transform 0.15s ease;width:100%;`);
              chip.title = p.name;
              chip.onmouseenter = () => chip.style.transform = 'scale(1.05)'; chip.onmouseleave = () => chip.style.transform = 'scale(1)';
              chip.onclick = () => { applyFn(p.colors, p); ov2.remove(); }; grid.appendChild(chip);
            });
          };
          searchInput.oninput = e => renderGrid(e.target.value); renderGrid('');
          box2.append(topRow, searchInput, grid); ov2.appendChild(box2); ov2.onclick = e => { if (e.target === ov2) ov2.remove(); }; document.body.appendChild(ov2);
          setTimeout(() => searchInput.focus(), 30);
        };
        let renderRecents = () => {};
        const buildChip = (p, applyFn) => {
  const chip = mk('div', '', `background:linear-gradient(to right,${p.colors.join(',')});height:24px;border-radius:6px;box-shadow:inset 0 0 0 1px rgba(255,255,255,0.15);cursor:pointer;transition:transform 0.15s ease;width:100%;position:relative;`);
  chip.title = isPinned(p.name) ? p.name + ' ★ (right-click to unpin)' : p.name + ' (right-click to pin)';
  chip.onmouseenter = () => chip.style.transform = 'scale(1.05)';
  chip.onmouseleave = () => chip.style.transform = 'scale(1)';
  chip.onclick = e => { e.preventDefault(); e.stopPropagation(); saveRecentPreset(p); applyFn(p.colors); renderRecents(); };
  chip.oncontextmenu = e => {
    e.preventDefault(); e.stopPropagation();
    if (isPinned(p.name)) { removePin(p.name); } else { savePin(p.name); }
    renderPinned();
    chip.title = isPinned(p.name) ? p.name + ' ★ (right-click to unpin)' : p.name + ' (right-click to pin)';
  };
  return chip;
};

        const recentsWrap = mk('div', '', 'margin-bottom:12px;');
        const recentsHeaderRow = mk('div', '', 'display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;');
        const recentsLbl = mk('div', '', 'font-size:9px;font-weight:700;letter-spacing:.7px;text-transform:uppercase;color:rgba(255,255,255,.4);'); recentsLbl.textContent = 'Recently Used';
        recentsHeaderRow.appendChild(recentsLbl); recentsWrap.appendChild(recentsHeaderRow);
        const recentsGrid = mk('div', '', 'display:grid;grid-template-columns:repeat(4,1fr);gap:6px;'); recentsWrap.appendChild(recentsGrid);
        renderRecents = () => {
          if (!recentPresets.length) { recentsWrap.style.display = 'none'; return; }
          recentsWrap.style.display = 'block'; recentsGrid.innerHTML = '';
          recentPresets.slice(0, 4).forEach(p => recentsGrid.appendChild(buildChip(p, colors => { currentColors = [...colors]; renderInputs(); upd(); })));
        };
        box.appendChild(recentsWrap); renderRecents();
        // ── PINNED ──
const pinnedWrap = mk('div', '', 'margin-bottom:12px;');
const pinnedLbl = mk('div', '', 'font-size:9px;font-weight:700;letter-spacing:.7px;text-transform:uppercase;color:rgba(255,255,255,.4);margin-bottom:6px;');
pinnedLbl.textContent = '★ Pinned';
pinnedWrap.appendChild(pinnedLbl);
const pinnedGrid = mk('div', '', 'display:grid;grid-template-columns:repeat(4,1fr);gap:6px;');
pinnedWrap.appendChild(pinnedGrid);
const renderPinned = () => {
  const pinned = allPresets.filter(p => isPinned(p.name));
  if (!pinned.length) { pinnedWrap.style.display = 'none'; return; }
  pinnedWrap.style.display = 'block';
  pinnedGrid.innerHTML = '';
  pinned.forEach(p => {
    const chip = mk('div', '', `background:linear-gradient(to right,${p.colors.join(',')});height:24px;border-radius:6px;box-shadow:inset 0 0 0 1px rgba(255,255,255,0.15);cursor:pointer;transition:transform 0.15s ease;width:100%;`);
    chip.title = p.name + ' ★ (right-click to unpin)';
    chip.onmouseenter = () => chip.style.transform = 'scale(1.05)';
    chip.onmouseleave = () => chip.style.transform = 'scale(1)';
    chip.onclick = e => { e.preventDefault(); e.stopPropagation(); currentColors = [...p.colors]; renderInputs(); upd(); };
    chip.oncontextmenu = e => { e.preventDefault(); e.stopPropagation(); removePin(p.name); renderPinned(); };
    pinnedGrid.appendChild(chip);
  });
};
box.appendChild(pinnedWrap);
renderPinned();
// ── /PINNED ──
        const presetsWrap = mk('div', '', 'margin-bottom:12px;');
        const presetsHeaderRow = mk('div', '', 'display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;');
        const presetsLbl = mk('div', '', 'font-size:9px;font-weight:700;letter-spacing:.7px;text-transform:uppercase;color:rgba(255,255,255,.4);'); presetsLbl.textContent = 'Presets';
        const expandBtn = mk('button', '', 'background:transparent;border:none;color:rgba(255,255,255,.5);font-size:10px;cursor:pointer;padding:2px 6px;font-family:"Open Sans",sans-serif;letter-spacing:.5px;border-radius:6px;border:1px solid rgba(255,255,255,.15);transition:all .2s;');
        expandBtn.textContent = `See all (${allPresets.length}) ↗`;
        expandBtn.onmouseenter = () => { expandBtn.style.background = 'rgba(255,255,255,.1)'; expandBtn.style.color = '#fff'; expandBtn.style.borderColor = 'rgba(255,255,255,.3)'; };
        expandBtn.onmouseleave = () => { expandBtn.style.background = 'transparent'; expandBtn.style.color = 'rgba(255,255,255,.5)'; expandBtn.style.borderColor = 'rgba(255,255,255,.15)'; };
        presetsHeaderRow.append(presetsLbl, expandBtn); presetsWrap.appendChild(presetsHeaderRow);
       const presetsGrid = mk('div', '', 'display:grid;grid-template-columns:repeat(4,1fr);gap:8px;');
        const PRESETS_VISIBLE = 8;
        const renderPresets = () => {
  presetsGrid.innerHTML = '';
  const seen = new Set();
  const mixed = [];
  for (const p of allPresets) {
    const firstColor = p.colors[0];
    const r = parseInt(firstColor.slice(1,3),16);
    const g = parseInt(firstColor.slice(3,5),16);
    const b = parseInt(firstColor.slice(5,7),16);
    const bucket = r > 100 && g < 80 && b < 80 ? 'red'
      : g > 100 && r < 80 && b < 80 ? 'green'
      : b > 100 && r < 80 && g < 80 ? 'blue'
      : r > 100 && g > 80 && b < 60 ? 'orange'
      : r > 80 && b > 80 && g < 60 ? 'purple'
      : r > 80 && g > 80 && b < 60 ? 'yellow'
      : r > 80 && b > 60 && g < 80 ? 'pink'
      : r < 50 && g < 50 && b < 50 ? 'dark'
      : 'other';
    if (!seen.has(bucket)) { seen.add(bucket); mixed.push(p); }
  }
  for (const p of allPresets) {
    if (mixed.length >= PRESETS_VISIBLE) break;
    if (!mixed.includes(p)) mixed.push(p);
  }
  mixed.slice(0, PRESETS_VISIBLE).forEach(p => presetsGrid.appendChild(buildChip(p, colors => {
    currentColors = [...colors]; renderInputs(); upd();
  })));
  expandBtn.textContent = `See all (${allPresets.length}) ↗`;
};
        expandBtn.onclick = e => {
          e.preventDefault(); e.stopPropagation();
          showAllGradientsModal(allPresets, (colors, preset) => { currentColors = [...colors]; if (preset) { saveRecentPreset(preset); renderRecents(); } renderInputs(); upd(); });
        };
        presetsWrap.appendChild(presetsGrid);
        const savePresetRow = mk('div', '', 'display:flex;gap:6px;align-items:center;margin-top:6px;');
        const savePresetBtn = mk('button', '', 'background:rgba(255,255,255,.05);border:1px dashed rgba(255,255,255,.2);border-radius:6px;color:rgba(255,255,255,.5);font-size:11px;cursor:pointer;padding:4px 8px;font-family:"Open Sans",sans-serif;transition:all .2s;flex:1;');
        savePresetBtn.textContent = '+ Save current as preset';
        savePresetBtn.onmouseenter = () => { savePresetBtn.style.color = '#fff'; savePresetBtn.style.borderColor = 'rgba(255,255,255,.4)'; savePresetBtn.style.background = 'rgba(255,255,255,.1)'; };
        savePresetBtn.onmouseleave = () => { savePresetBtn.style.color = 'rgba(255,255,255,.5)'; savePresetBtn.style.borderColor = 'rgba(255,255,255,.2)'; savePresetBtn.style.background = 'rgba(255,255,255,.05)'; };
        savePresetBtn.onclick = e => {
          e.preventDefault(); e.stopPropagation();
          const name = prompt('Preset name?', 'My gradient'); if (!name) return;
          const custom = { name, colors: [...currentColors], custom: true };
          allPresets.push(custom);
          try { const stored = JSON.parse(localStorage.getItem('mmapp_custom_presets') || '[]'); stored.push(custom); localStorage.setItem('mmapp_custom_presets', JSON.stringify(stored)); } catch (_) {}
          saveRecentPreset(custom); renderRecents(); renderPresets();
        };
        savePresetRow.appendChild(savePresetBtn); presetsWrap.appendChild(savePresetRow); renderPresets(); box.append(presetsWrap);
        const renderInputs = () => {
          colorRow.innerHTML = '';
          currentColors.forEach((c, idx) => {
            const colWrap = mk('div', '', 'display:flex;flex-direction:column;gap:4px;flex:1;min-width:0;align-items:center;');
            const inp = mk('input', 'mm-color-inp'); inp.type = 'color'; inp.value = c;
            const hexEl = mk('input'); hexEl.type = 'text'; hexEl.value = c; hexEl.maxLength = 7;
            hexEl.style.cssText = 'width:100%;background:rgba(0,0,0,.25);border:1px solid rgba(255,255,255,.1);border-radius:6px;color:rgba(255,255,255,.8);padding:4px 6px;font-size:10.5px;font-family:monospace;outline:none;box-sizing:border-box;box-shadow:inset 0 2px 4px rgba(0,0,0,.2);transition:border-color .2s;text-align:center;';
            hexEl.onfocus = () => hexEl.style.borderColor = 'rgba(255,255,255,.4)'; hexEl.onblur = () => hexEl.style.borderColor = 'rgba(255,255,255,.1)';
            inp.oninput = () => { currentColors[idx] = inp.value; hexEl.value = inp.value; upd(); };
            hexEl.oninput = () => { const v = hexEl.value.startsWith('#') ? hexEl.value : '#' + hexEl.value; if (/^#[0-9a-fA-F]{6}$/.test(v)) { inp.value = v; currentColors[idx] = v; upd(); } };
            colWrap.append(inp, hexEl); colorRow.appendChild(colWrap);
          });
          const controls = mk('div', '', 'display:flex;flex-direction:column;gap:3px;margin-left:5px;');
          const btnAdd = mk('button', '', 'background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.05);border-radius:6px;color:#fff;width:22px;height:16px;font-size:10px;cursor:pointer;display:flex;align-items:center;justify-content:center;');
          btnAdd.textContent = '+'; btnAdd.onclick = e => { e.preventDefault(); if (currentColors.length < 6) { currentColors.push(currentColors[currentColors.length - 1]); renderInputs(); upd(); } };
          const btnRem = mk('button', '', 'background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.05);border-radius:6px;color:#fff;width:22px;height:16px;font-size:10px;cursor:pointer;display:flex;align-items:center;justify-content:center;');
          btnRem.textContent = '-'; btnRem.onclick = e => { e.preventDefault(); if (currentColors.length > 2) { currentColors.pop(); renderInputs(); upd(); } };
          const btnInv = mk('button', '', 'background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.05);border-radius:6px;color:#fff;width:22px;height:18px;font-size:11px;cursor:pointer;display:flex;align-items:center;justify-content:center;margin-top:2px;');
          btnInv.innerHTML = '⇄'; btnInv.title = 'Invert gradient'; btnInv.onclick = e => { e.preventDefault(); currentColors.reverse(); renderInputs(); upd(); };
          controls.append(btnAdd, btnRem, btnInv); colorRow.appendChild(controls);
        };
        renderInputs(); upd(); box.append(colorRow, prev);

        let gradTagsState = cfg.gradTags !== false && !cfg.noGrad;
        let gradFoldersState = !!cfg.gradFolders && !cfg.noGrad;

        const btnGradTags = mkToggleBtn('Apply gradient to tags', gradTagsState);
        const btnGradFolders = mkToggleBtn('Apply gradient to sub-folders', gradFoldersState);
        const syncStates = () => {
          const noGrad = !btnGradTags._isActive && !btnGradFolders._isActive;
          colorRow.style.opacity = noGrad ? '.35' : '1'; colorRow.style.pointerEvents = noGrad ? 'none' : '';
          prev.style.opacity = noGrad ? '.35' : '.8';
        };
        btnGradTags.onclick = e => { e.preventDefault(); e.stopPropagation(); btnGradTags._toggle(); gradTagsState = btnGradTags._isActive; syncStates(); };
        btnGradFolders.onclick = e => { e.preventDefault(); e.stopPropagation(); btnGradFolders._toggle(); gradFoldersState = btnGradFolders._isActive; syncStates(); };
        syncStates();
        box.append(btnGradTags, btnGradFolders);
        fels.noGrad = { get checked() { return !btnGradTags._isActive && !btnGradFolders._isActive; }, type: 'checkbox' };
        fels.gradTags = { get checked() { return gradTagsState; }, type: 'checkbox' };
        fels.gradFolders = { get checked() { return gradFoldersState; }, type: 'checkbox' };
        fels.gradientColors = { get value() { return currentColors; }, type: 'custom' };
      }

      if (cfg.showAliasOptions) {
        const sep = mk('div', '', 'height:1px;background:rgba(255,255,255,.06);margin:8px 0 12px;');
        box.appendChild(sep);
        const aliasLbl = mk('label', '', 'display:block;font-size:10px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:rgba(255,255,255,.4);margin-bottom:6px;');
        aliasLbl.textContent = 'Aliases settings'; box.appendChild(aliasLbl);
        let countAliasesState = cfg.countAliases !== false;
        const btnCA = mkToggleBtn('Count aliases in folder total', countAliasesState);
        btnCA.onclick = e => { e.preventDefault(); e.stopPropagation(); btnCA._toggle(); countAliasesState = btnCA._isActive; };
        box.appendChild(btnCA);
        fels.countAliases = { get checked() { return countAliasesState; }, type: 'checkbox' };
      }

      if (cfg.showAliasEdit) {
        const aliasData = cfg.aliasData || {};
        let applyGradState = aliasData.applyGrad !== false;
        let useOriginalState = !!aliasData.useOriginal;
        let customColor = aliasData.customColor || '#5a5a8a';
        let customName = aliasData.customName || aliasData.originalTag || '';

        const nameLbl = mk('label', '', 'display:block;font-size:10px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:rgba(255,255,255,.4);margin-bottom:6px;');
        nameLbl.textContent = 'Alias Display Name';
        box.appendChild(nameLbl);

        const nameInp = mk('input');
        nameInp.type = 'text'; nameInp.value = customName;
        nameInp.style.cssText = 'background:rgba(0,0,0,.25);border:1px solid rgba(255,255,255,.1);border-radius:10px;color:#fff;padding:10px 14px;font-size:13px;margin-bottom:4px;box-sizing:border-box;outline:none;font-family:"Open Sans",sans-serif;width:100%;display:block;box-shadow:inset 0 2px 4px rgba(0,0,0,.2);transition:border-color .2s;';
        nameInp.onfocus = () => nameInp.style.borderColor = 'rgba(255,255,255,.4)';
        nameInp.onblur = () => nameInp.style.borderColor = 'rgba(255,255,255,.1)';
        nameInp.oninput = () => { customName = nameInp.value; };
        box.appendChild(nameInp);

        const nameDesc = mk('div', '', 'font-size:10px;color:rgba(255,255,255,.35);margin-bottom:16px;line-height:1.4;');
        nameDesc.textContent = 'This only changes the alias name, and will not affect the original tag.';
        box.appendChild(nameDesc);

        const colLbl = mk('label', '', 'display:block;font-size:10px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:rgba(255,255,255,.4);margin-bottom:6px;');
        colLbl.textContent = 'Alias Color';
        box.appendChild(colLbl);

        let recentColors = [];
        try { recentColors = JSON.parse(localStorage.getItem('mmapp_recent_colors') || '["#5a5a8a", "#e45b5b", "#4ade80"]'); } catch (_) {}
        const saveColor = c => {
          recentColors = recentColors.filter(r => r !== c);
          recentColors.unshift(c);
          if (recentColors.length > 3) recentColors.length = 3;
          localStorage.setItem('mmapp_recent_colors', JSON.stringify(recentColors));
        };

        const colRow = mk('div', '', 'display:flex;align-items:center;gap:8px;margin-bottom:6px;width:100%;box-sizing:border-box;');

        const recentsWrap = mk('div', '', 'display:flex;gap:6px; margin-right:4px;');
        const renderRecentColors = () => {
          recentsWrap.innerHTML = '';
          recentColors.slice(0, 3).forEach(c => {
            const chip = mk('div', 'mm-color-box', `background:${c};transition: transform 0.15s ease;`);
            chip.onmouseenter = () => chip.style.transform = 'scale(1.1)';
            chip.onmouseleave = () => chip.style.transform = 'scale(1)';
            chip.onclick = () => {
              customColor = c; inp.value = c; hex.value = c; saveColor(c); renderRecentColors();
              applyGradBtn._isActive = false; applyGradBtn._updateVis();
              useOrigBtn._isActive = false; useOrigBtn._updateVis();
              syncAliasStates();
            };
            recentsWrap.appendChild(chip);
          });
        };

        const inp = mk('input', 'mm-color-inp'); inp.type = 'color'; inp.value = customColor;
        const hex = mk('input'); hex.type = 'text'; hex.value = customColor;
        hex.style.cssText = 'flex:1;background:rgba(0,0,0,.25);border:1px solid rgba(255,255,255,.1);border-radius:6px;color:#fff;padding:5px 8px;font-size:12px;outline:none;min-width:0;box-sizing:border-box;box-shadow:inset 0 2px 4px rgba(0,0,0,.2);transition:border-color .2s;font-family:monospace;';

        const applyGradBtn = mkToggleBtn('Apply folder gradient', applyGradState);
        const useOrigBtn = mkToggleBtn('Use native map color', useOriginalState);

        const syncAliasStates = () => {
          const disabled = applyGradBtn._isActive || useOrigBtn._isActive;
          colRow.style.opacity = disabled ? '0.35' : '1';
          colRow.style.pointerEvents = disabled ? 'none' : 'auto';
        };

        inp.oninput = () => {
          hex.value = inp.value; customColor = inp.value;
          applyGradBtn._isActive = false; applyGradBtn._updateVis();
          useOrigBtn._isActive = false; useOrigBtn._updateVis();
          syncAliasStates();
        };
        inp.onchange = () => { saveColor(inp.value); renderRecentColors(); };
        hex.oninput = () => {
          const v = hex.value.startsWith('#') ? hex.value : '#'+hex.value;
          if(/^#[0-9a-fA-F]{6}$/.test(v)) {
            inp.value = v; customColor = v; saveColor(v); renderRecentColors();
            applyGradBtn._isActive = false; applyGradBtn._updateVis();
            useOrigBtn._isActive = false; useOrigBtn._updateVis();
            syncAliasStates();
          }
        };
        hex.onfocus = () => hex.style.borderColor = 'rgba(255,255,255,.4)';
        hex.onblur = () => hex.style.borderColor = 'rgba(255,255,255,.1)';

        renderRecentColors();

        applyGradBtn.onclick = e => {
          e.preventDefault(); e.stopPropagation(); applyGradBtn._toggle();
          if(applyGradBtn._isActive) { useOrigBtn._isActive = false; useOrigBtn._updateVis(); }
          syncAliasStates();
        };
        useOrigBtn.onclick = e => {
          e.preventDefault(); e.stopPropagation(); useOrigBtn._toggle();
          if(useOrigBtn._isActive) { applyGradBtn._isActive = false; applyGradBtn._updateVis(); }
          syncAliasStates();
        };

        colRow.append(recentsWrap, inp, hex);
        box.appendChild(colRow);

        const colDesc = mk('div', '', 'font-size:10px;color:rgba(255,255,255,.35);margin-bottom:16px;line-height:1.4;');
        colDesc.textContent = "This color only applies to your Alias, and will not change the original tag's color.";
        box.appendChild(colDesc);

        box.append(applyGradBtn, useOrigBtn);
        syncAliasStates();

        fels.applyGrad = { get checked() { return applyGradBtn._isActive; }, type: 'checkbox' };
        fels.useOriginal = { get checked() { return useOrigBtn._isActive; }, type: 'checkbox' };
        fels.customColor = { get value() { return customColor; }, type: 'custom' };
        fels.customName = { get value() { return customName.trim(); }, type: 'custom' };
      }

      const acts = mk('div', '', 'display:flex;gap:8px;justify-content:flex-end;margin-top:10px;');
      const bC = mk('button', '', 'background:rgba(0,0,0,.2);border:1px solid rgba(255,255,255,.1);border-radius:10px;color:rgba(255,255,255,.6);padding:10px 20px;cursor:pointer;font-size:13px;font-family:"Open Sans",sans-serif;font-weight:600;transition:all .2s;'); bC.textContent = 'Cancel';
      const bO = mk('button', '', 'background:#fff;border:none;border-radius:10px;color:#121210;padding:10px 20px;cursor:pointer;font-size:13px;font-weight:700;font-family:"Open Sans",sans-serif;box-shadow:0 4px 12px rgba(255,255,255,.2);transition:all .2s;'); bO.textContent = cfg.okText || 'OK';
      bC.onmouseenter = () => { bC.style.borderColor = 'rgba(255,255,255,.3)'; bC.style.color = '#fff'; };
      bC.onmouseleave = () => { bC.style.borderColor = 'rgba(255,255,255,.1)'; bC.style.color = 'rgba(255,255,255,.6)'; };
      bO.onmouseenter = () => bO.style.background = '#e0e0e0';
      bO.onmouseleave = () => bO.style.background = '#fff';
      acts.append(bC, bO); box.appendChild(acts); ov.appendChild(box); document.body.appendChild(ov);
      bO.onclick = confirm_; bC.onclick = cancel_;
      ov.onmousedown = e => { if (e.target === ov) cancel_(); };
      setTimeout(() => box.querySelector('input[type=text]')?.focus(), 30);
    });
  }

  let _ctx = null;
  const closeCtx = () => { _ctx?.remove(); _ctx = null; };

  function showCtx(x, y, items) {
    closeCtx();
    const m = mk('div', '', `position:fixed;left:${x}px;top:${y}px;background:rgba(22,22,19,0.95);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,0.08);border-radius:10px;padding:6px;z-index:100000;min-width:240px;max-height:45vh;overflow-y:auto;box-shadow:0 12px 40px rgba(0,0,0,0.6);font-family:"Open Sans",sans-serif;font-size:13px;color:#e8e8e8;`, { 'data-mm': '1', 'data-mm-ctx': '1' });
    m.style.scrollbarWidth = 'thin'; m.style.scrollbarColor = 'rgba(255,255,255,.2) transparent';
    _ctx = m;

    items.forEach(item => {
      if (item === '---') { const s = mk('div', '', 'height:1px;background:rgba(255,255,255,.08);margin:4px 0;'); m.appendChild(s); return; }
      const d = mk('div', '', 'padding:6px 10px;cursor:pointer;border-radius:6px;display:flex;align-items:center;gap:8px;position:relative;transition:background 0.1s;');
      d.onmouseenter = () => d.style.background = 'rgba(255,255,255,.1)';
      d.onmouseleave = () => d.style.background = 'transparent';

      if (item.html) {
        d.innerHTML = item.html;
      } else if (item.sub?.length) {
        d.innerHTML = (item.icon ? `<span style="min-width:16px;opacity:.6;display:inline-block;text-align:center;">${item.icon}</span>` : '') + `<span style="flex:1">${item.label}</span><span style="opacity:.3;font-size:9px">▶</span>`;
        const sub = mk('div', '', `display:none;position:absolute;left:calc(100% + 4px);top:-4px;background:rgba(22,22,19,0.95);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,0.08);border-radius:10px;padding:6px;min-width:200px;max-height:300px;overflow-y:auto;box-shadow:0 12px 40px rgba(0,0,0,0.6);z-index:100001;font-family:"Open Sans",sans-serif;font-size:13px;`);
        item.sub.forEach(s => {
          const si = mk('div', '', 'padding:6px 10px;cursor:pointer;border-radius:6px;display:flex;align-items:center;gap:8px;white-space:nowrap;color:#e8e8e8;');
          si.onmouseenter = () => si.style.background = 'rgba(255,255,255,.08)'; si.onmouseleave = () => si.style.background = 'transparent';
          si.innerHTML = s.htmlLabel || ((s.icon ? `<span style="min-width:16px;opacity:.6;display:inline-block;text-align:center;">${s.icon}</span>` : '') + `<span>${s.label}</span>`);
          si.onmousedown = e => { e.preventDefault(); e.stopPropagation(); closeCtx(); s.action?.(); };
          sub.appendChild(si);
        });
        d.appendChild(sub);
        d.onmouseenter = () => { d.style.background = 'rgba(255,255,255,.08)'; sub.style.display = 'block'; };
        d.onmouseleave = () => { d.style.background = 'transparent'; sub.style.display = 'none'; };
      } else {
        d.innerHTML = (item.icon ? `<span style="min-width:16px;opacity:.6;display:inline-block;text-align:center;">${item.icon}</span>` : '') + `<span>${item.label}</span>`;
      }

      d.onmousedown = e => {
        if (!item.sub) { e.preventDefault(); e.stopPropagation(); closeCtx(); item.action?.(); }
      };
      m.appendChild(d);
    });

    document.body.appendChild(m);
    requestAnimationFrame(() => {
      const r = m.getBoundingClientRect();
      if (r.right > window.innerWidth) m.style.left = (x - r.width - 8) + 'px';
      if (r.bottom > window.innerHeight) m.style.top = (y - r.height - 8) + 'px';
    });

    const outsideClick = e => {
      if (_ctx && !e.target.closest('[data-mm-ctx]')) {
        closeCtx();
        document.removeEventListener('mousedown', outsideClick);
      }
    };
    setTimeout(() => document.addEventListener('mousedown', outsideClick), 10);
  }

  function clickNative(tagName) {
    const li = liOfTag(tagName);
    if (!li) return;
    (li.querySelector('label.tag_text, label') || li).click();
  }

  async function setNativeTagColor(tagName, hexColor, finalDelay = 100) {
    const li = liOfTag(tagName);
    if (!li) return false;
    const editBtn = li.querySelector('button.tag_button--edit, button[class*="edit"]');
    if (!editBtn) return false;
    editBtn.click();
    const hexInput = await waitDOM('div[role="dialog"] input.input.hex-color, div[role="dialog"] input[class*="hex-color"]');
    if (!hexInput) { const dialog = document.querySelector('div[role="dialog"]'); dialog?.querySelectorAll('button')[0]?.click(); return false; }
    const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
    const hex = hexColor.replace('#', '');
    if (nativeSetter) nativeSetter.call(hexInput, hex); else hexInput.value = hex;
    hexInput.dispatchEvent(new Event('input', { bubbles: true }));
    hexInput.dispatchEvent(new Event('change', { bubbles: true }));
    await new Promise(r => setTimeout(r, 80));
    const dialog = hexInput.closest('div[role="dialog"]');
    const btns = dialog?.querySelectorAll('.edit-tag-modal__actions button, button.save');
    btns?.[btns.length - 1]?.click();
    await new Promise(r => setTimeout(r, finalDelay));
    return true;
  }

  async function applyFolderColorsToNative(folder) {
    let failed = 0;
    if (folder.gradTags !== false && !folder.noGrad) {

      // 1. On recrée l'ordre visuel exact (Tags + Alias mélangés)
      const allColors = gradAllColors(folder);
      let items = [];
      if (folder.tags) folder.tags.forEach(t => items.push({ id: t, isAlias: false }));
      if (folder.aliases) folder.aliases.forEach(t => items.push({ id: t, isAlias: true }));

      if (folder.itemsOrder) {
        items.sort((a, b) => {
          const kA = (a.isAlias ? 'alias:' : 'tag:') + a.id;
          const kB = (b.isAlias ? 'alias:' : 'tag:') + b.id;
          let iA = folder.itemsOrder.indexOf(kA);
          let iB = folder.itemsOrder.indexOf(kB);
          if (iA === -1) iA = 99999;
          if (iB === -1) iB = 99999;
          return iA - iB;
        });
      }

      // 2. On applique les couleurs en respectant CET ordre visuel
      for (let i = 0; i < items.length; i++) {
        const item = items[i];
        if (!item.isAlias) { // On ne colorise que les vrais tags sur la map
          const targetColor = allColors[i] || folder.colorStart || '#c0f0f8';
          const ok = await setNativeTagColor(item.id, rgbToHex(targetColor), 120);
          if (!ok) failed++;
        }
      }
    }

    // Application récursive aux sous-dossiers
    for (const child of folder.children || []) {
      failed += await applyFolderColorsToNative(child);
    }
    return failed;
  }

  async function applyTagToLoc(tagName) {
    const searchInput = document.querySelector('section.location-preview input[type="text"], .location-preview-tags input, input[placeholder*="tag" i], input[placeholder*="Add"]');
    if (!searchInput) return false;
    const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
    const setVal = v => {
      if (nativeSetter) nativeSetter.call(searchInput, v); else searchInput.value = v;
      searchInput.dispatchEvent(new Event('input', { bubbles: true }));
      searchInput.dispatchEvent(new Event('change', { bubbles: true }));
    };
    searchInput.focus(); setVal(tagName);
    return new Promise(resolve => {
      let tries = 0;
      const interval = setInterval(() => {
        tries++;
        const ol = getLocOl();
        if (ol) {
          for (const li of ol.querySelectorAll('li:not([data-mm])')) {
            const span = li.querySelector('span.tag_text, span[class*="tag_text"]');
            const name = (span?.textContent || '').trim();
            if (name !== tagName) continue;
            const btn = li.querySelector('button[class*="add"]') || li.querySelector('button');
            (btn || li).click();
            clearInterval(interval);
            setTimeout(() => { setVal(''); searchInput.blur(); }, 80);
            resolve(true); return;
          }
        }
        if (tries > 20) {
  clearInterval(interval);
  const notif = mk('div', '', 'position:fixed;top:20px;right:20px;background:rgba(30,10,10,0.92);border:1px solid rgba(248,113,113,.3);color:rgba(248,113,113,.95);padding:10px 18px;border-radius:10px;font-family:"Open Sans",sans-serif;font-size:13px;font-weight:600;z-index:999999;box-shadow:0 4px 20px rgba(0,0,0,.4);display:flex;align-items:center;gap:8px;');
  notif.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg> Tag "${escapeHTML(tagName)}" not found in location panel.`;
  document.body.appendChild(notif);
  setTimeout(() => notif.remove(), 4000);
  resolve(false);
}
      }, 60);
    });
  }

  async function newFolder(parentId = null) {
    const parent = parentId ? findF(parentId) : null;
    const r = await modal({
      title: parentId ? 'New subfolder' : 'New folder',
      fields: [{ key: 'name', label: 'Name', type: 'text', placeholder: 'e.g. Guardrails' }],
      showFolderColor: true, folderColor: parent?.color || '#c0f0f8',
      showColors: true, colors: parent?.gradient || ['#c0f0f8', '#183848'],
      noGrad: parent?.noGrad || false, gradTags: parent?.gradTags !== false, gradFolders: !!parent?.gradFolders,
      showAliasOptions: true, countAliases: true,
      okText: 'Create'
    });
    if (!r) return; // Si on clique sur Cancel, on annule
      const folderName = r.name.trim() || 'New folder'; // Si c'est vide, nom par défaut
      const gradientColors = r.gradientColors || ['#c0f0f8', '#183848'];
      const f = {
        id: uid(), name: folderName, color: r.folderColor || '#c0f0f8',
      gradient: gradientColors, colorStart: gradientColors[0], colorEnd: gradientColors[gradientColors.length - 1],
      noGrad: !!r.noGrad, gradTags: r.gradTags !== false, gradFolders: !!r.gradFolders,
      expanded: true, visible: true,
      tags: [], aliases: [], countAliases: !!r.countAliases,
      children: []
    };
    if (parentId) { const p = findF(parentId); if (p) { p.children.push(f); saveS(); reRenderFolders(); return; } }
    S.folders.push(f); saveS(); reRenderFolders();
  }

  async function editFolder(id) {
    const f = findF(id); if (!f) return;
    const r = await modal({
      title: 'Edit folder',
      fields: [{ key: 'name', label: 'Name', type: 'text', value: f.name }],
      showFolderColor: true, folderColor: f.color || '#c0f0f8',
      inheritedColor: f._inheritedColor || null, useParentColor: !!f.useParentColor,
      showColors: true, colors: f.gradient || ['#c0f0f8', '#183848'],
      noGrad: f.noGrad || false, gradTags: f.gradTags !== false, gradFolders: !!f.gradFolders,
      showAliasOptions: true, countAliases: f.countAliases !== false,
      okText: 'Save'
    });
    if (!r) return;
    const folderName = r.name.trim() || 'Unnamed folder';
    const gradientColors = r.gradientColors || ['#c0f0f8', '#183848'];
    f.name = folderName; f.color = r.folderColor || f.color;
    f.gradient = gradientColors; f.colorStart = gradientColors[0]; f.colorEnd = gradientColors[gradientColors.length - 1];
    f.noGrad = !!r.noGrad; f.gradTags = r.gradTags !== false; f.gradFolders = !!r.gradFolders;
    f.useParentColor = !!r.useParentColor;
    f.countAliases = r.countAliases !== false;
    saveS(); reRenderFolders();
  }

 function isTagVisuallyOnInFolder(tag, folderId) {
    const li = liOfTag(tag);
    const nativelyOn = li && li.classList.contains('is-selected');

    // Le dossier a-t-il l'intention d'être allumé ?
    if (window.mmTagIntents && window.mmTagIntents[tag] && window.mmTagIntents[tag].size > 0) {
      const intentSet = window.mmTagIntents[tag];
      return intentSet.has(folderId) || flat().some(f => isDescendant(folderId, f.id) && intentSet.has(f.id));
    }

    // Anti-flicker : si on vient tout juste de l'éteindre, on force le visuel "éteint" le temps que le site suive.
    if (window.mmFlickerBlock && window.mmFlickerBlock[tag] && Date.now() - window.mmFlickerBlock[tag] < 300) {
      return false;
    }

    // Si aucune intention stockée (ex: clic direct sur le tag natif à côté)
    return nativelyOn;
  }

  function isFolderFullyOn(folder) {
    const allItems = [];
    const walk = f => {
      [...(f.tags || []), ...(f.aliases || [])].forEach(t => allItems.push({tag: t, folderId: f.id}));
      (f.children || []).forEach(walk);
    };
    walk(folder);

    const validItems = allItems.filter(i => !!liOfTag(i.tag));
    if (!validItems.length) return false;

    return validItems.every(i => isTagVisuallyOnInFolder(i.tag, i.folderId));
  }

  function isFolderPartiallyOn(folder) {
    const allItems = [];
    const walk = f => {
      [...(f.tags || []), ...(f.aliases || [])].forEach(t => allItems.push({tag: t, folderId: f.id}));
      (f.children || []).forEach(walk);
    };
    walk(folder);

    const validItems = allItems.filter(i => !!liOfTag(i.tag));
    return validItems.some(i => isTagVisuallyOnInFolder(i.tag, i.folderId));
  }

  function toggleVis(folder) {
    if (!window.mmTagIntents) window.mmTagIntents = {};
    if (!window.mmFlickerBlock) window.mmFlickerBlock = {};

    const targetState = !isFolderFullyOn(folder);
    const allFoldersInTree = flat().filter(f => f.id === folder.id || isDescendant(folder.id, f.id));

    let tagsToToggleNative = new Set();
    let nativeTurnOn = new Set();
    let nativeTurnOff = new Set();

    allFoldersInTree.forEach(f => {
      const directTags = [...(f.tags || []), ...(f.aliases || [])].filter(t => !!liOfTag(t));
      directTags.forEach(tag => {
        if (!window.mmTagIntents[tag]) window.mmTagIntents[tag] = new Set();

        const li = liOfTag(tag);
        const isNativelyOn = li && li.classList.contains('is-selected');

        if (targetState === false) {
           // On retire ce dossier des intentions d'allumage
           window.mmTagIntents[tag].delete(f.id);
           // S'il n'y a plus AUCUN dossier qui veut ce tag, on l'éteint nativement
           if (window.mmTagIntents[tag].size === 0 && isNativelyOn) {
               nativeTurnOff.add(tag);
               window.mmFlickerBlock[tag] = Date.now(); // Bloque le flicker
           }
        } else {
           // Si c'était complètement éteint avant, on le rallume nativement
           if (window.mmTagIntents[tag].size === 0 && !isNativelyOn) {
               nativeTurnOn.add(tag);
           }
           window.mmTagIntents[tag].add(f.id);
        }
      });
    });

    folder.visible = targetState;
    saveS(false);

    // Mise à jour visuelle instantanée pour l'utilisateur
    updateAllFolderVisuals();

    // Déclenchement des clics natifs en arrière-plan
    const tagsToClick = [...nativeTurnOn, ...nativeTurnOff];
    if (!tagsToClick.length) return;

    const BATCH_SIZE = 25, BATCH_DELAY = 1;
    const runBatch = (index) => {
      const batch = tagsToClick.slice(index, index + BATCH_SIZE);
      batch.forEach(tag => clickNative(tag));
      if (index + BATCH_SIZE < tagsToClick.length) setTimeout(() => runBatch(index + BATCH_SIZE), BATCH_DELAY);
      else {
        setTimeout(updateAllFolderVisuals, 20);
        setTimeout(updateAllFolderVisuals, 60);
        setTimeout(updateAllFolderVisuals, 150);
      }
    };
    runBatch(0);
  }

async function editAlias(tagName, folderId) {
    const f = findF(folderId);
    if (!f) return;
    const conf = (f.aliasConfig && f.aliasConfig[tagName]) ? { ...f.aliasConfig[tagName] } : { applyGrad: true, useOriginal: false, customColor: '#5a5a8a', customName: tagName };
    const r = await modal({
      title: 'Edit Alias',
      fields: [],
      showAliasEdit: true,
      aliasData: { ...conf, originalTag: tagName },
      okText: 'Save'
    });
    if (r) {
      if (!f.aliasConfig) f.aliasConfig = {};
      f.aliasConfig[tagName] = {
        applyGrad: !!r.applyGrad,
        useOriginal: !!r.useOriginal,
        customColor: r.customColor || '#5a5a8a',
        customName: r.customName || tagName
      };
      saveS();
      reRenderFolders();
    }
  }

  function buildTagBtn(tag, color, isAlias = false, parentFolderId = null) {
    const li = liOfTag(tag);
    const count = countFromLi(li);
    const bg = color || getTagColor(li) || '#5a5a8a';
    const fg = textOn(bg);
    const isOn = li?.classList.contains('is-selected') ?? false;

    let displayName = tag;
    if (isAlias && parentFolderId) {
      const f = findF(parentFolderId);
      if (f && f.aliasConfig && f.aliasConfig[tag] && f.aliasConfig[tag].customName) {
        displayName = f.aliasConfig[tag].customName;
      }
    }

    const btn = mk('button',
      'mm-tag-btn' + (isOn ? ' mm-tag-btn--on' : '') + (isAlias ? ' mm-tag-btn--alias' : ''),
      '', { 'data-mm': '1', 'draggable': 'true' }
    );
    btn.style.backgroundColor = bg;
    btn.style.color = fg;
    btn.dataset.mmTag = tag;

   // Gestion du Drag & Drop pour le REORDER (Tags ET Aliases)
    // Gestion du Drag & Drop mixte
    btn.addEventListener('dragover', e => {
      const isTagDrag = dragTag && (dragTag !== tag || isAlias);
      const isAliasDrag = dragAlias && (dragAlias !== tag || !isAlias); // Fix : On a enlevé la restriction de dossier
      if (!isTagDrag && !isAliasDrag) return;
      e.preventDefault(); e.stopPropagation();

      const body = btn.closest('.mm-body');
      if (body) {
        let spacer = body.querySelector('.mm-drag-spacer');
        if (!spacer) {
          spacer = document.createElement('div');
          spacer.className = 'mm-drag-spacer';
          spacer.style.cssText = 'display:inline-flex;width:3px;height:32px;background:rgba(255,255,255,0.6);border-radius:2px;flex-shrink:0;pointer-events:none;margin:0 2px;';
        }
        const rect = btn.getBoundingClientRect();
        const threshold = rect.left + rect.width * 0.5; // On coupe exactement à la moitié
        if (e.clientX < threshold) {
          body.insertBefore(spacer, btn);
        } else {
          body.insertBefore(spacer, btn.nextSibling);
        }
      }
    });

    btn.addEventListener('dragleave', e => {
      const body = btn.closest('.mm-body');
      if (body) {
        const rel = e.relatedTarget;
        if (!rel || (!body.contains(rel) && !rel.classList?.contains('mm-drag-spacer'))) {
          body.querySelector('.mm-drag-spacer')?.remove();
        }
      }
    });

    btn.addEventListener('drop', e => {
      const body = btn.closest('.mm-body');
      const spacer = body?.querySelector('.mm-drag-spacer');
      let insertBefore = null;
      if (spacer) {
        insertBefore = spacer.nextSibling;
        spacer.remove();
      }

      const isTagDrag = dragTag && (dragTag !== tag || isAlias);
      const isAliasDrag = dragAlias && (dragAlias !== tag || !isAlias);
      if (!isTagDrag && !isAliasDrag) return;

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

      const targetBtn = insertBefore?.classList?.contains('mm-tag-btn') ? insertBefore : null;
      const targetTag = targetBtn?.dataset?.mmTag;
      const targetIsAlias = targetBtn?.classList?.contains('mm-tag-btn--alias') ?? false;

      if (isTagDrag) {
        const dt = dragTag; dragTag = null;
        const currentFolder = folderOf(dt);
        if (!currentFolder || currentFolder.id !== parentFolderId) moveTag(dt, parentFolderId);

        if (targetTag) reorderMixed(dt, false, targetTag, targetIsAlias, parentFolderId);
        else reorderMixed(dt, false, null, false, parentFolderId);
      } else {
        const da = dragAlias; dragAlias = null;
        const fromId = dragAliasFolderId; dragAliasFolderId = null;
        if (fromId !== parentFolderId) moveAlias(da, fromId, parentFolderId);

        if (targetTag) reorderMixed(da, true, targetTag, targetIsAlias, parentFolderId);
        else reorderMixed(da, true, null, false, parentFolderId);
      }
    });

    // Fix INFAILLIBLE du stylo
   const pen = mk('span', '', 'opacity:.7;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;width:24px;height:24px;');
    pen.innerHTML = SVG_PEN;

    pen.addEventListener('pointerup', e => {
      e.stopPropagation();
      e.preventDefault();
      if (isAlias) {
        editAlias(tag, parentFolderId);
      } else {
        const nat = liOfTag(tag);
        if (nat) nat.querySelector('button.tag_button--edit, button[class*="edit"]')?.click();
      }
    });
    pen.addEventListener('pointerdown', e => { e.stopPropagation(); e.preventDefault(); });
    pen.addEventListener('dragstart', e => e.preventDefault());

    btn.appendChild(pen);

    const nameSp = mk('span', '', 'pointer-events:none;');
    nameSp.textContent = displayName;
    btn.appendChild(nameSp);

    if (count) {
      const cSp = mk('small', '', 'margin-left:0.375rem;font-weight:600;vertical-align:middle;pointer-events:none;');
      cSp.textContent = count;
      btn.appendChild(cSp);
    }

    // Le clic centralisé qui résout tous les problèmes
    // Le clic centralisé qui résout tous les problèmes
    // Le clic centralisé qui résout tous les problèmes
    btn.onclick = async e => {
      e.stopPropagation();

      if (e.target === pen || pen.contains(e.target)) {
        e.preventDefault();
        return;
      }

      if (!window.mmTagIntents) window.mmTagIntents = {};
      if (!window.mmTagIntents[tag]) window.mmTagIntents[tag] = new Set();
      if (!window.mmFlickerBlock) window.mmFlickerBlock = {};

      const isOn = btn.classList.contains('mm-tag-btn--on');
      const nativelyOn = li?.classList.contains('is-selected');

      let shouldFireNative = false;

      if (isOn) {
         window.mmTagIntents[tag].delete(parentFolderId);
         if (window.mmTagIntents[tag].size === 0 && nativelyOn) {
             shouldFireNative = true;
             window.mmFlickerBlock[tag] = Date.now(); // Adieu flicker !
         }
      } else {
         if (window.mmTagIntents[tag].size === 0 && !nativelyOn) {
             shouldFireNative = true;
         }
         window.mmTagIntents[tag].add(parentFolderId);
      }

      // 1. On donne l'illusion de vitesse
      updateAllFolderVisuals();

      // 2. On effectue le vrai clic natif seulement si nécessaire
      if (shouldFireNative) {
        if (getLocOl()) {
          await applyTagToLoc(tag);
          setTimeout(updateAllFolderVisuals, 60);
        } else {
          clickNative(tag);
          setTimeout(updateAllFolderVisuals, 20);
          setTimeout(updateAllFolderVisuals, 60);
          setTimeout(updateAllFolderVisuals, 150);
        }
      }
    };

    btn.addEventListener('dragstart', e => {
      if (e.target === pen || pen.contains(e.target)) { e.preventDefault(); return; }
      if (isAlias) {
        dragAlias = tag;
        dragAliasFolderId = parentFolderId;
        dragTag = null;
      } else {
        dragTag = tag;
        dragAlias = null;
        dragAliasFolderId = null;
      }
      try { e.dataTransfer.setData('text/plain', tag); } catch (_) {}
      const ghost = btn.cloneNode(true);
      ghost.style.cssText = `position:fixed;top:0;left:-9999px;background-color:${bg};color:${fg};padding:0 10px 0 8px;height:32px;border-radius:999px;display:inline-flex;align-items:center;font-family:"Open Sans",sans-serif;font-size:16px;white-space:nowrap;pointer-events:none;z-index:-1;`;
      document.body.appendChild(ghost);
      e.dataTransfer.setDragImage(ghost, 40, 16);
      setTimeout(() => { btn.style.opacity = '.45'; ghost.remove(); }, 50);
    });

   btn.addEventListener('dragend', () => {
      btn.style.opacity = '';
      if (isAlias) { dragAlias = null; dragAliasFolderId = null; }
      else dragTag = null;
      // Nettoyer tous les spacers et indicateurs qui traînent
      document.querySelectorAll('.mm-drag-spacer').forEach(s => s.remove());
      document.querySelectorAll('.mm-dh').forEach(el => el.classList.remove('mm-dh'));
    });

    btn.addEventListener('contextmenu', e => {
      e.preventDefault(); e.stopPropagation();

      const getDepth = (id, list = S.folders, currentDepth = 0) => {
        for (const f of list) { if (f.id === id) return currentDepth; const d = getDepth(id, f.children || [], currentDepth + 1); if (d !== -1) return d; }
        return -1;
      };

      if (isAlias) {
        const openMovePanel = () => {
          setTimeout(() => {
            showCtx(e.clientX, e.clientY, flat().map(f => {
              const depth = getDepth(f.id);
              const bg = f.color || '#c0f0f8';
              const isCurrent = f.id === parentFolderId;
              const pad = depth * 14;
              let connector = depth > 0 ? `<div style="position:absolute;left:${pad - 8}px;top:0;height:50%;border-left:1.5px solid rgba(255,255,255,0.15);border-bottom:1.5px solid rgba(255,255,255,0.15);width:6px;border-bottom-left-radius:3px;"></div>` : '';
              const html = `<div style="display:flex;align-items:center;gap:6px;padding-left:${pad}px;position:relative;width:100%;">${connector}<div style="width:8px;height:8px;border-radius:50%;background:${bg};box-shadow:0 0 5px ${bg}55;flex-shrink:0;"></div><span style="font-weight:${isCurrent ? '700' : '600'};color:${isCurrent ? '#fff' : '#dcdcdc'};flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0.01em;">${escapeHTML(f.name)}</span>${isCurrent ? '<span style="color:rgba(255,255,255,0.5);font-size:11px;font-weight:400;margin-left:4px;">✓</span>' : ''}</div>`;
              return { html, action: () => moveAlias(tag, parentFolderId, f.id) };
            }));
          }, 50);
        };

        showCtx(e.clientX, e.clientY, [
          { html: `<span style="font-weight:700;color:rgba(255,255,255,.4);font-size:10px;letter-spacing:.05em;">ALIAS</span>&nbsp;<span style="font-weight:600;color:#fff;">${escapeHTML(displayName)}</span>` },
          '---',
          { label: 'Move to folder...', action: openMovePanel },
          { label: 'Show origin', action: () => showOriginalTag(tag) },
          { icon: '✕', label: 'Remove alias from this folder', action: () => removeAlias(tag, parentFolderId) }
        ]);
      } else {
        const natLi = liOfTag(tag);
        if (!natLi) return;
        const observer = new MutationObserver((mutations, obs) => {
          const nativeMenu = document.querySelector('[data-side="right"][role="menu"].context-menu, [role="menu"].context-menu');
          if (nativeMenu) {
            if (!nativeMenu.querySelector('[data-mm-injected]')) injectIntoNativeMenu(tag, nativeMenu);
            obs.disconnect();
            natLi.style.removeProperty('position'); natLi.style.removeProperty('left'); natLi.style.removeProperty('top');
            natLi.style.removeProperty('opacity'); natLi.style.removeProperty('pointer-events'); natLi.style.removeProperty('z-index');
            natLi.style.setProperty('display', 'none', 'important');
          }
        });
        observer.observe(document.body, { childList: true, subtree: true });
        setTimeout(() => observer.disconnect(), 500);
        natLi.style.removeProperty('display');
        natLi.style.setProperty('position', 'fixed', 'important');
        natLi.style.setProperty('left', e.clientX + 'px', 'important');
        natLi.style.setProperty('top', e.clientY + 'px', 'important');
        natLi.style.setProperty('opacity', '0', 'important');
        natLi.style.setProperty('pointer-events', 'auto', 'important');
        natLi.style.setProperty('z-index', '-1', 'important');
        natLi.dispatchEvent(new MouseEvent('contextmenu', { bubbles: true, cancelable: true, clientX: e.clientX, clientY: e.clientY, button: 2 }));
      }
    });
        if (window.mmTagToGlow === tag && Date.now() < window.mmTagGlowEnd && !isAlias) {
      btn.classList.add('mm-glow-anim');
    }
    return btn;
  }

  function injectIntoNativeMenu(tag, nativeMenu) {
    const cur = folderOf(tag);
    const allF = flat();

    const sep = document.createElement('div');
    sep.setAttribute('data-mm-injected', '1');
    sep.style.cssText = 'height:1px;background:rgba(255,255,255,.1);margin:3px 0;';
    nativeMenu.appendChild(sep);

    if (allF.length) {
      const moveItem = document.createElement('div');
      moveItem.setAttribute('data-mm-injected', '1');
      moveItem.setAttribute('role', 'menuitem');
      moveItem.setAttribute('tabindex', '-1');
      moveItem.className = 'context-menu__item';
      moveItem.textContent = ' Move to folder...';
      moveItem.onclick = e => {
        e.stopPropagation();
        const rect = moveItem.getBoundingClientRect();
        document.body.click();
        const getDepth = (id, list = S.folders, currentDepth = 0) => {
          for (const f of list) { if (f.id === id) return currentDepth; const d = getDepth(id, f.children || [], currentDepth + 1); if (d !== -1) return d; }
          return -1;
        };
        const cur2 = folderOf(tag);
        setTimeout(() => {
          showCtx(rect.right + 4, rect.top, flat().map(f => {
            const depth = getDepth(f.id);
            const bg = f.color || '#c0f0f8';
            const isCurrent = f.id === cur2?.id;
            const pad = depth * 14;
            let connector = '';
            if (depth > 0) connector = `<div style="position:absolute;left:${pad - 8}px;top:0;height:50%;border-left:1.5px solid rgba(255,255,255,0.15);border-bottom:1.5px solid rgba(255,255,255,0.15);width:6px;border-bottom-left-radius:3px;"></div>`;
            const html = `<div style="display:flex;align-items:center;gap:6px;padding-left:${pad}px;position:relative;width:100%;">${connector}<div style="width:8px;height:8px;border-radius:50%;background:${bg};box-shadow:0 0 5px ${bg}55;flex-shrink:0;"></div><span style="font-weight:${isCurrent ? '700' : '600'};color:${isCurrent ? '#fff' : '#dcdcdc'};flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0.01em;">${escapeHTML(f.name)}</span>${isCurrent ? '<span style="color:rgba(255,255,255,0.5);font-size:11px;font-weight:400;margin-left:4px;">✓</span>' : ''}</div>`;
            return { html, action: () => moveTag(tag, f.id) };
          }));
        }, 50);
      };
      nativeMenu.appendChild(moveItem);
    }

    // --- "Create several aliases" supprimé ---
    if (cur) {
      const aliasItem = document.createElement('div');
      aliasItem.setAttribute('data-mm-injected', '1');
      aliasItem.setAttribute('role', 'menuitem');
      aliasItem.setAttribute('tabindex', '-1');
      aliasItem.className = 'context-menu__item';
      aliasItem.textContent = 'Create alias';
      aliasItem.title = 'Create an alias copy — drag it to another folder';
      aliasItem.onclick = e => {
        e.stopPropagation(); document.body.click();
        setTimeout(() => addAlias(tag, cur.id), 100);
      };
      nativeMenu.appendChild(aliasItem);
    }

    if (cur) {
      const removeItem = document.createElement('div');
      removeItem.setAttribute('data-mm-injected', '1');
      removeItem.setAttribute('role', 'menuitem');
      removeItem.setAttribute('tabindex', '-1');
      removeItem.className = 'context-menu__item';
      removeItem.textContent = `Remove from "${cur.name}"`;
      removeItem.onclick = (e) => {
        e.preventDefault(); e.stopPropagation(); document.body.click();
        setTimeout(() => removeTag(tag), 150);
      };
      nativeMenu.appendChild(removeItem);
    }

    const nativeDelete = Array.from(nativeMenu.querySelectorAll('.context-menu__item')).find(el => el.textContent.toLowerCase().includes('delete') || el.querySelector('.icon-trash') || el.textContent.includes('Supprimer'));
    if (nativeDelete) nativeDelete.addEventListener('click', () => { setTimeout(() => removeTag(tag), 150); });
  }

  function bindCtxMenu() {
    document.addEventListener('contextmenu', e => {
      if (e.target.closest('[data-mm]')) return;
      const li = e.target.closest('li.tag.has-button');
      if (!li) return;
      const tag = nameFromLi(li); if (!tag) return;
      const observer = new MutationObserver((mutations, obs) => {
        const nativeMenu = document.querySelector('[role="menu"].context-menu');
        if (nativeMenu && !nativeMenu.querySelector('[data-mm-injected]')) { injectIntoNativeMenu(tag, nativeMenu); obs.disconnect(); }
      });
      observer.observe(document.body, { childList: true, subtree: true });
      setTimeout(() => observer.disconnect(), 400);
    }, true);
  }

  function needsRender() {
    const ul = getMainUl();
    const footer = document.querySelector('.map-meta__actions');
    if (footer && !document.getElementById('mm-footer-actions-wrapper')) return true;
    if (ul) return !ul.querySelector('[data-mm="1"]');
    return false;
  }

  async function deleteFolder(id) {
    const f = findF(id); if (!f) return;
    if (!confirm(`Delete folder "${f.name}"?\n\n(The tags inside will be moved back to the main list, they won't be deleted from your map)`)) return;
    delF(id); saveS(); reRenderFolders();
  }

  function buildFolder(folder, depth = 0, isLast = false, parentGradColor = null) {
    const li = mk('li', '', '', { 'data-mm': '1', 'data-mm-folder': folder.id });
    folder._inheritedColor = parentGradColor || null;
    const bg = (parentGradColor && folder.useParentColor !== false) ? parentGradColor : folder.color || '#c0f0f8';
    const fg = textOn(bg);
    const gradArr = folder.gradient || [folder.colorStart || '#3b82f6', folder.colorEnd || '#06b6d4'];
    const grad = `linear-gradient(90deg, ${gradArr.join(', ')})`;
    const fullyOn = isFolderFullyOn(folder);
    const partialOn = !fullyOn && isFolderPartiallyOn(folder);
    const hdClass = fullyOn ? ' mm-hd--on' : (partialOn ? ' mm-hd--partial' : ' mm-hd--off');
    const hd = mk('div', 'mm-hd' + hdClass);
    hd.style.backgroundColor = bg; hd.style.color = fg;
    dndOn(hd, folder.id);
    hd.setAttribute('draggable', 'true');
    hd.addEventListener('dragstart', e => {
      if (dragTag || dragAlias) return;
      if (e.target.closest('.mm-left-actions, .mm-right-actions')) { e.preventDefault(); return; }
      e.stopPropagation(); dragFolderId = folder.id;
      setTimeout(() => { if (dragFolderId) li.style.opacity = '.5'; }, 0);
      try { e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/plain', ''); } catch (_) {}
    });
    hd.addEventListener('dragend', () => { li.style.opacity = ''; dragFolderId = null; });
    li.addEventListener('dragover', e => {
      if (dragTag || dragAlias) { e.preventDefault(); return; } // <--- LE FILET DE SÉCURITÉ
      if (!dragFolderId || dragFolderId === folder.id) return;
      if (isDescendant(dragFolderId, folder.id)) return;
      e.preventDefault(); e.stopPropagation();
      const rect = hd.getBoundingClientRect();
      const isTopHalf = e.clientY < rect.top + rect.height / 2;
      if (isTopHalf) { li.classList.add('mm-drop-above'); li.classList.remove('mm-drop-inside', 'mm-drop-after'); }
      else if (isLast && e.clientY > rect.bottom - 6) { li.classList.add('mm-drop-after'); li.classList.remove('mm-drop-above', 'mm-drop-inside'); }
      else { li.classList.add('mm-drop-inside'); li.classList.remove('mm-drop-above', 'mm-drop-after'); }
    });
    li.addEventListener('dragleave', e => { if (!li.contains(e.relatedTarget)) li.classList.remove('mm-drop-above', 'mm-drop-inside', 'mm-drop-after'); });
    li.addEventListener('drop', e => {
      if (dragTag || dragAlias) {
         e.preventDefault(); e.stopPropagation();
         const isAliasDrop = !!dragAlias;
         const tag = dragAlias || dragTag || e.dataTransfer.getData('text/plain');
         const fromId = dragAliasFolderId;
         dragAlias = null; dragTag = null; dragAliasFolderId = null;

         if (!tag) return;

         if (isAliasDrop) {
           if (fromId !== folder.id) moveAlias(tag, fromId, folder.id);
           reorderMixed(tag, true, null, false, folder.id);
         } else {
           const currentFolder = folderOf(tag);
           if (!currentFolder || currentFolder.id !== folder.id) moveTag(tag, folder.id);
           reorderMixed(tag, false, null, false, folder.id);
         }
         return;
      }
      const wasAbove = li.classList.contains('mm-drop-above');
      const wasAfter = li.classList.contains('mm-drop-after');
      li.classList.remove('mm-drop-above', 'mm-drop-inside', 'mm-drop-after');
      if (!dragFolderId || dragFolderId === folder.id || dragTag || dragAlias) return;
      if (isDescendant(dragFolderId, folder.id)) return;
      e.preventDefault(); e.stopPropagation();
      const id = dragFolderId; dragFolderId = null;
      if (wasAbove) reorderFolder(id, folder.id);
      else if (wasAfter) { const dragged = extractFolder(id); if (dragged) { S.folders.push(dragged); saveS(); reRenderFolders(); } }
      else moveFolderInto(id, folder.id);
    });
    const leftActions = mk('div', 'mm-left-actions');
    const az = mk('div', 'mm-arrow-zone');
    az.innerHTML = SVG_ARR(folder.expanded ? 90 : 0);
    az.onclick = e => {
      e.stopPropagation();
      folder.expanded = !folder.expanded; saveS(false);
      const svg = az.querySelector('svg');
      if (svg) svg.style.transform = `rotate(${folder.expanded ? 90 : 0}deg)`;
      if (!folder.expanded) {
        li.querySelectorAll(':scope > .mm-sub-wrap, :scope > .mm-body').forEach(el => el.remove());
      } else {
        if (folder.children?.length) {
          const sw = mk('div', 'mm-sub-wrap', '', { 'data-mm': '1' });
          const childColors = gradChildColors(folder);
          folder.children.forEach((c, ci) => sw.appendChild(buildFolder(c, depth + 1, false, childColors[ci] || null)));
          li.appendChild(sw);
        }
        const body = buildFolderBody(folder);
        li.appendChild(body);
      }
    };
    const pen = mk('span', 'mm-pencil'); pen.innerHTML = SVG_PEN; pen.title = 'Edit'; pen.style.color = fg;
    pen.onclick = e => { e.stopPropagation(); editFolder(folder.id); };
    leftActions.append(az, pen);
    const nameSp = mk('span', '', 'flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;');
    nameSp.textContent = folder.name;
    const gd = mk('div', 'mm-grad'); gd.style.background = grad;
    const cnt = mk('span', 'mm-cnt'); cnt.style.color = fg;

    const countableItems = Array.from(new Set(allCountableItemsOf(folder)));
    const tagCount = countableItems.length;
    const locCount = countableItems.reduce((sum, tag) => sum + (parseInt(countFromLi(liOfTag(tag))) || 0), 0);
    cnt.textContent = locCount > 0 ? `${tagCount} · ${locCount} locs` : tagCount;

    const rightActions = mk('div', 'mm-right-actions');
    const colBtn = mk('button', 'mm-actbtn'); colBtn.textContent = 'Apply colors'; colBtn.title = 'Apply gradient colors to native tags'; colBtn.style.cssText += ';font-size:10px;padding:1px 8px;color:' + fg;
    colBtn.onclick = async e => {
      e.stopPropagation();
      const n = allTagsOf(folder).length; if (!n) return;
      const secs = Math.ceil(n * 0.5);
      const timeStr = secs < 60 ? `~${secs} seconds` : `~${Math.ceil(secs / 60)} minutes`;
      if (confirm(`Apply gradient to the ${n} tags of "${folder.name}"?\n\n⚠️ This will modify the actual tag colors in the app and take ${timeStr}.\n\nPlease DO NOT click anything until the button says 'Done!'.`)) {
        colBtn.textContent = 'Applying...'; colBtn.style.opacity = '0.5'; colBtn.style.pointerEvents = 'none';
        const failed = await applyFolderColorsToNative(folder);
        colBtn.textContent = failed > 0 ? `Done (${failed} failed)` : 'Done!';
        if (failed > 0) console.warn(`[mm-folders] ${failed} tag(s) could not be recolored.`);
        setTimeout(() => { colBtn.textContent = 'Apply colors'; colBtn.style.opacity = '1'; colBtn.style.pointerEvents = 'auto'; }, 2500);
      }
    };
    const delBtn = mk('button', 'mm-actbtn'); delBtn.textContent = '✕'; delBtn.title = 'Delete'; delBtn.style.color = fg;
    delBtn.onclick = e => { e.stopPropagation(); deleteFolder(folder.id); };
    rightActions.append(colBtn, delBtn);
    hd.append(leftActions, nameSp, gd, cnt, rightActions);
    hd.onclick = e => { if (e.target.closest('.mm-arrow-zone,.mm-pencil,.mm-actbtn')) return; e.stopPropagation(); e.preventDefault(); toggleVis(folder); };
    li.appendChild(hd);
    if (folder.expanded) {
      if (folder.children?.length) {
        const sw = mk('div', 'mm-sub-wrap', '', { 'data-mm': '1' });
        const childColors = gradChildColors(folder);
        folder.children.forEach((c, ci) => sw.appendChild(buildFolder(c, depth + 1, false, childColors[ci] || null)));
        li.appendChild(sw);
      }
      const body = buildFolderBody(folder);
      li.appendChild(body);
    }
      if (window.mmTagToGlow === folder.id && Date.now() < window.mmTagGlowEnd) {
      hd.classList.add('mm-folder-glow-anim');
    }
    return li;
  }

  function buildFolderBody(folder) {
    const body = mk('div', 'mm-body', '', { 'data-mm': '1' });

    // 1. On récupère la couleur de base
    const bg = (folder._inheritedColor && folder.useParentColor !== false) ? folder._inheritedColor : folder.color || '#c0f0f8';
    body.style.setProperty('--folder-bg', bg);

    // 2. Fonction qui transforme n'importe quelle couleur sombre en sa version "Saturée et Lumineuse"
    const getVibrant = c => {
      let [r, g, b] = (c.startsWith('#') ? hexToRgb(c) : c.match(/\d+/g)?.map(Number)) || [128,128,128];
      r/=255; g/=255; b/=255;
      let max = Math.max(r,g,b), min = Math.min(r,g,b), d = max-min;
      let h = 0;
      if (d !== 0) {
        if (max === r) h = ((g-b)/d) + (g < b ? 6 : 0);
        else if (max === g) h = (b-r)/d + 2;
        else h = (r-g)/d + 4;
      }
      // On force la saturation à 95% et la clarté à 65% (Zéro pastel, 100% vibrant !)
      return `hsl(${Math.round(h*60)}, 95%, 65%)`;
    };

    // 3. Si la couleur est sombre, on utilise la version vibrante pure, sinon la couleur normale
    const isDark = lum(bg) < 0.3;
    body.style.setProperty('--folder-accent', isDark ? getVibrant(bg) : bg);

    dndOn(body, folder.id);
    const hasTags = (folder.tags || []).length > 0;
    const hasAliases = (folder.aliases || []).length > 0;
    if (!hasTags && !hasAliases) {
      const dz = mk('div', 'mm-dropzone'); dz.textContent = '↓ Drop tags here'; dndOn(dz, folder.id); body.appendChild(dz);
    } else {
      const allColors = gradAllColors(folder);

      let items = [];
      if (folder.tags) folder.tags.forEach(t => items.push({ id: t, isAlias: false }));
      if (folder.aliases) folder.aliases.forEach(t => items.push({ id: t, isAlias: true }));

      // --- PATCH D'AUTO-RÉPARATION ---
      if (!folder.itemsOrder) folder.itemsOrder = [];
      let needsSave = false;

      items.forEach(item => {
        const key = (item.isAlias ? 'alias:' : 'tag:') + item.id;
        if (!folder.itemsOrder.includes(key)) {
          folder.itemsOrder.push(key);
          needsSave = true;
        }
      });

      const originalLength = folder.itemsOrder.length;
      folder.itemsOrder = folder.itemsOrder.filter(key =>
        items.some(i => ((i.isAlias ? 'alias:' : 'tag:') + i.id) === key)
      );
      if (folder.itemsOrder.length !== originalLength) needsSave = true;

      if (needsSave) saveS(false);
      // -------------------------------

      if (folder.itemsOrder) {
         items.sort((a, b) => {
           const kA = (a.isAlias ? 'alias:' : 'tag:') + a.id;
           const kB = (b.isAlias ? 'alias:' : 'tag:') + b.id;
           let iA = folder.itemsOrder.indexOf(kA);
           let iB = folder.itemsOrder.indexOf(kB);
           if (iA === -1) iA = 99999;
           if (iB === -1) iB = 99999;
           return iA - iB;
         });
      }

      items.forEach((item, cIdx) => {
         let c = folder.gradTags !== false ? allColors[cIdx] : null;
         if (item.isAlias) {
           const conf = folder.aliasConfig?.[item.id];
           if (conf) {
             if (conf.useOriginal) c = null;
             else if (conf.applyGrad === false) c = conf.customColor;
           }
         }
         body.appendChild(buildTagBtn(item.id, c, item.isAlias, folder.id));
      });

      if (!hasTags) {
        const dz = mk('div', 'mm-dropzone'); dz.textContent = '↓ Drop tags here'; dndOn(dz, folder.id); body.appendChild(dz);
      }
    }

    const addSub = mk('button', 'mm-subaddbtn', '', { 'data-mm': '1' });
    addSub.textContent = '+ New subfolder';
    addSub.onclick = ev => { ev.stopPropagation(); newFolder(folder.id); };
    body.appendChild(addSub);
    return body;
  }

  function renderInto(container) {
    if (!container) return;
    container.querySelectorAll('[data-mm="1"]').forEach(e => e.remove());
    container.querySelectorAll('.mm-sep,.mm-addli').forEach(e => e.remove());
    invalidateFlatCache();
    const addLi = mk('li', 'mm-addli', '', { 'data-mm': '1' });

    const topWrap = mk('div', '', 'display:flex;align-items:center;justify-content:space-between;width:100%;margin-bottom:6px;box-sizing:border-box;');
    const leftBtns = mk('div', '', 'display:flex;align-items:center;');

    const addBtn = mk('button', 'mm-addbtn'); addBtn.innerHTML = '<span>+ New folder</span>';
    addBtn.onclick = () => newFolder(null);
    addBtn.addEventListener('dragover', e => { if (dragTag) { e.preventDefault(); addBtn.style.outline = '2px dashed rgba(0,0,0,.3)'; } });
    addBtn.addEventListener('dragleave', () => addBtn.style.outline = '');
    addBtn.addEventListener('drop', async e => {
      e.preventDefault(); addBtn.style.outline = '';
      const tag = dragTag || e.dataTransfer.getData('text/plain'); if (!tag) return;
      const r = await modal({
        title: `New folder for "${tag}"`,
        fields: [{ key: 'name', label: 'Name', type: 'text', placeholder: 'Folder name' }],
        showFolderColor: true, folderColor: '#c0f0f8',
        showColors: true, colors: ['#c0f0f8', '#183848'], okText: 'Create'
      });
      if (!r) return;
      const folderName = r.name.trim() || 'New folder';
      const gradientColors = r.gradientColors || ['#c0f0f8', '#183848'];
      const f = {
        id: uid(), name: folderName, color: r.folderColor || '#c0f0f8',
        gradient: gradientColors, colorStart: gradientColors[0], colorEnd: gradientColors[gradientColors.length - 1],
        noGrad: !!r.noGrad, gradTags: r.gradTags !== false, gradFolders: !!r.gradFolders,
        expanded: true, visible: true, tags: [tag], aliases: [], countAliases: true, children: []
      };
      S.folders.push(f); dragTag = null; saveS(); reRenderFolders();
    });

    const exportBtn = mk('button', 'mm-actbtn', 'margin-left:6px;color:#a0a0a0;font-size:10px;background:transparent;');
    exportBtn.textContent = 'Export'; exportBtn.title = 'Export folders (local JSON)';
    exportBtn.onclick = () => {
      const blob = new Blob([JSON.stringify(S, null, 2)], { type: 'application/json' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a'); a.href = url; a.download = `mm-folders-${getMapId() || 'map'}.json`; a.click(); URL.revokeObjectURL(url);
    };
    const importBtn = mk('button', 'mm-actbtn', 'margin-left:4px;color:#a0a0a0;font-size:10px;background:transparent;');
    importBtn.textContent = 'Import'; importBtn.title = 'Import folders (local JSON)';
    importBtn.onclick = () => {
      const input = document.createElement('input'); input.type = 'file'; input.accept = '.json';
      input.onchange = e => {
        const file = e.target.files[0]; if (!file) return;
        const reader = new FileReader();
        reader.onload = ev => {
          try {
            const parsed = JSON.parse(ev.target.result);
            if (!parsed.folders) { alert('Invalid file — no folders found.'); return; }
            if (!confirm(`Import ${parsed.folders.length} folder(s)?\n(Current folders will be replaced.)`)) return;
            S = { folders: parsed.folders }; saveS(); reRenderFolders();
          } catch (_) { alert('JSON file read error.'); }
        };
        reader.readAsText(file);
      };
      input.click();
    };
    const infoBtn = mk('button', 'mm-actbtn', 'margin-left:4px;background:transparent;padding:2px;cursor:pointer;display:flex;align-items:center;');
    infoBtn.title = 'Help & Warnings';
    infoBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" style="fill:#a0a0a0;"><path d="M12 2C6.489 2 2 6.489 2 12s4.489 10 10 10 10-4.489 10-10S17.511 2 12 2zm0 2c4.43 0 8 3.57 8 8s-3.57 8-8 8-8-3.57-8-8 3.57-8 8-8zm-1 5v2h2V9h-2zm0 4v6h2v-6h-2z"/></svg>`;
    infoBtn.onclick = showInfoModal;

    leftBtns.append(addBtn, exportBtn, importBtn, infoBtn);

    const toggleRow = mk('div', 'mm-toggle-row', 'display:flex; align-items:center; gap:5px;');
    const dispLbl = mk('span', '', 'color:#a0a0a0;font-size:10px;margin-right:2px;user-select:none;');
    dispLbl.textContent = 'display';
    toggleRow.appendChild(dispLbl);

    const makeTogglePill = (label, bodyClass, storageKey) => {
      const isHidden = localStorage.getItem(storageKey) === 'true';
      if (isHidden) document.body.classList.add(bodyClass);
      else document.body.classList.remove(bodyClass);
      const pill = mk('button', 'mm-toggle-pill' + (isHidden ? '' : ' mm-toggle-on'));
      const dot = mk('span', 'mm-toggle-dot');
      const lbl = mk('span'); lbl.textContent = label;
      pill.append(dot, lbl);
      pill.onclick = e => {
        e.stopPropagation();
        const nowHidden = !document.body.classList.contains(bodyClass);
        if (nowHidden) {
          document.body.classList.add(bodyClass);
          localStorage.setItem(storageKey, 'true');
          pill.classList.remove('mm-toggle-on');
        } else {
          document.body.classList.remove(bodyClass);
          localStorage.setItem(storageKey, 'false');
          pill.classList.add('mm-toggle-on');
        }
      };
      return pill;
    };

    const glowColor = localStorage.getItem('mmapp_glow_color') || '#4ade80';
    const glowPill = mk('button', 'mm-toggle-pill mm-toggle-on');
    glowPill.style.position = 'relative';
    const glowDot = mk('span', 'mm-toggle-dot');
    glowDot.style.cssText = `background:${glowColor}; width:6px; height:6px; border-radius:50%; flex-shrink:0; transition:background .15s;`;
    const glowLbl = mk('span'); glowLbl.textContent = 'Show origin color';
    const glowInp = mk('input');
    glowInp.type = 'color';
    glowInp.value = glowColor;
    glowInp.style.cssText = 'position:absolute;opacity:0;width:100%;height:100%;top:0;left:0;cursor:pointer;border:none;padding:0;margin:0;';
    glowPill.append(glowDot, glowLbl, glowInp);
    glowInp.oninput = (e) => {
      const c = e.target.value;
      localStorage.setItem('mmapp_glow_color', c);
      document.documentElement.style.setProperty('--mm-glow-color', c);
      glowDot.style.background = c;
    };
    toggleRow.appendChild(glowPill);

    toggleRow.appendChild(makeTogglePill('Drop zones', 'mm-hide-dropzones', 'mmapp_hide_dropzones'));
    toggleRow.appendChild(makeTogglePill('+ Subfolders', 'mm-hide-subfolderbtns', 'mmapp_hide_subfolder_btns'));

    topWrap.append(leftBtns, toggleRow);
    addLi.appendChild(topWrap);

    container.insertBefore(addLi, container.firstChild);
    let last = addLi;
    S.folders.forEach((f, i) => {
      const li = buildFolder(f, 0, i === S.folders.length - 1);
      last.insertAdjacentElement('afterend', li);
      last = li;
    });
    if (S.folders.length) {
      const sep = mk('li', 'mm-sep', '', { 'data-mm': '1' });
      last.insertAdjacentElement('afterend', sep);
      const dropOutLi = mk('li', '', 'list-style:none;', { 'data-mm': '1' });
      const dropOut = mk('div', '', 'padding:4px 8px;border:1.5px dashed rgba(255,255,255,.15);border-radius:8px;font-size:11px;font-family:"Open Sans",sans-serif;color:rgba(255,255,255,.25);text-align:center;font-style:italic;transition:border-color .15s,color .15s;margin-bottom:4px;');
      dropOut.textContent = '↓ Drop here to remove from folder';
      dropOut.addEventListener('dragover', e => {
        if (!dragTag && !dragAlias) return;
        e.preventDefault();
        dropOut.style.borderColor = 'rgba(255,100,100,.6)'; dropOut.style.color = 'rgba(255,150,150,.8)';
      });
      dropOut.addEventListener('dragleave', () => { dropOut.style.borderColor = ''; dropOut.style.color = ''; });
      dropOut.addEventListener('drop', e => {
        e.preventDefault(); dropOut.style.borderColor = ''; dropOut.style.color = '';
        if (dragAlias) {
          const tag = dragAlias, fromId = dragAliasFolderId;
          dragAlias = null; dragAliasFolderId = null;
          removeAlias(tag, fromId);
        } else {
          const tag = dragTag || e.dataTransfer.getData('text/plain');
          if (tag) { dragTag = null; removeTag(tag); }
        }
      });
      dropOutLi.appendChild(dropOut);
      sep.insertAdjacentElement('afterend', dropOutLi);
    }
  }

  function render() {
    if (!getMapId()) return;
    injectFooterButtons();
    const ol = getLocOl();
    const ul = getMainUl();
    if (ol) {
      document.body.classList.add('mm-loc-open');
      if (ul && !ul.querySelector('[data-mm="1"]')) renderInto(ul);
    } else {
      document.body.classList.remove('mm-loc-open');
      if (ul) renderInto(ul);
    }
    updateHideStyle();
  }

  function watchDOM() {
    let _t = null;
    let colorSyncInterval = null;
    new MutationObserver(mutations => {
      let needsColorSync = false;
      let syncRender = false;
      for (const m of mutations) {
        if (m.removedNodes.length) {
          m.removedNodes.forEach(n => {
            if (n.nodeType !== 1) return;
            if (n.getAttribute?.('role') === 'dialog' || n.classList?.contains('edit-tag-modal')) needsColorSync = true;
          });
        }
        if (m.addedNodes.length) {
          m.addedNodes.forEach(n => {
            if (n.nodeType !== 1) return;
            if (n.tagName === 'UL' && n.classList.contains('tag-list') && !n.hasAttribute('role')) syncRender = true;
            const processNode = el => {
              if (el.tagName === 'LI' && !el.hasAttribute('data-mm')) {
                el.setAttribute('draggable', 'true');
                const ul = el.closest('ul.tag-list:not([role="listbox"])');
                if (ul && !ul.querySelector('[data-mm="1"]')) syncRender = true;
                const txt = el.textContent || '';
                if (txt.includes(STORAGE_PREFIX) || txt.includes(OLD_STORAGE_PREFIX)) { el.style.setProperty('display', 'none', 'important'); }
                else if (!document.body.classList.contains('mm-search-mode')) {
                  const name = nameFromLi(el);
                  if (name && getAssignedTags().has(name)) el.style.setProperty('display', 'none', 'important');
                }
              }
            };
            processNode(n);
            if (n.querySelectorAll) n.querySelectorAll('li:not([data-mm])').forEach(processNode);
          });
        }
      }
      if (syncRender && needsRender()) render();
      if (needsColorSync) {
        clearInterval(colorSyncInterval);
        let ticks = 0;
        colorSyncInterval = setInterval(() => {
          document.querySelectorAll('li:not([data-mm])').forEach(li => delete li.dataset.mmColor);
          updateHideStyle(); ticks++;
          if (ticks > 6) clearInterval(colorSyncInterval);
        }, 250);
      }
      clearTimeout(_t);
      _t = setTimeout(() => { if (needsRender()) render(); else updateHideStyle(); }, 50);
    }).observe(document.body, { childList: true, subtree: true });
    setInterval(() => { if (needsRender()) render(); }, 5000);
  }

  function watchNav() {
    let last = location.href;
    const check = () => {
      if (location.href === last) return;
      last = location.href;
      document.getElementById('mm-hide-css')?.remove();
      invalidateFlatCache(); loadS();
      setTimeout(() => render(), 700);
    };
    window.addEventListener('popstate', check);
    const orig = history.pushState.bind(history);
    history.pushState = (...a) => { orig(...a); check(); };
    setInterval(check, 1500);
  }

  function boot() {
    document.body.classList.add('mm-loading');
    loadS();
    initHideToggles();
    initDnD();
    bindCtxMenu();
    bindTooltipListeners();
    watchHeaderFeatures();
    watchNav();
    watchDOM();
    watchNativeTagRenames();

    window.addEventListener('beforeunload', e => { if (!isDirty) return; e.preventDefault(); e.returnValue = ''; });
    setTimeout(() => document.body.classList.remove('mm-loading'), 3000);

    let tries = 0;
    let rendered = false;

    function tryRender() {
      if (rendered) return;
      tries++;
      if (document.querySelectorAll('li.tag.has-button').length > 0 || document.querySelector('.map-meta__actions')) {
        rendered = true;
        loadFromCloud(false);
        render();
      } else if (tries < 25) {
        setTimeout(tryRender, 500);
      }
    }

    const obs = new MutationObserver(() => {
      if (document.querySelectorAll('li.tag.has-button').length > 0 || document.querySelector('.map-meta__actions')) {
        obs.disconnect();
        setTimeout(tryRender, 80);
      }
    });
    obs.observe(document.body, { childList: true, subtree: true });
    setTimeout(tryRender, 800);
    setTimeout(tryRender, 2200);
  }

  injectCSS();

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', boot);
  } else {
    boot();
  }
})();