Greasy Fork is available in English.

mydealz Manager

Deals gezielt ausblenden mittels X Button, Filtern nach Händlern und Wörtern im Titel. Teure und kalte Deals ausblenden.

// ==UserScript==
// @name         mydealz Manager
// @namespace    http://tampermonkey.net/
// @version      1.15.0
// @description  Deals gezielt ausblenden mittels X Button, Filtern nach Händlern und Wörtern im Titel. Teure und kalte Deals ausblenden.
// @author       Flo (https://www.mydealz.de/profile/Basics0119) (https://github.com/9jS2PL5T) & Moritz Baumeister (https://www.mydealz.de/profile/BobBaumeister) (https://github.com/grapefruit89)
// @license      MIT
// @match        https://www.mydealz.de/*
// @match        https://www.preisjaeger.at/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=mydealz.de
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// ==/UserScript==

// Versions-Änderungen
// 1.13.0
// ADD: Funktion um den Teilen-Button auszublenden.
// ADD: Warnung bei mehreren aktiven mydealz Manager Versionen.
// ADD: Funktion um Banner & Widgets auszublenden.
// 1.14.0
// ADD: Funktion zum Speichern der Sortierung bei Dealsuche.
// 1.15.0
// ADD: Drag & Drop für SettingsUI

//#region --- 1. Initialisierung und Grundeinstellungen ---

// ===== Konstanten und Konfiguration =====
// --- Storage Keys ---
const VERSION_PREFIX = 'mdm_version_';
const HIDDEN_DEALS_KEY = 'hiddenDeals';
const HIDE_COLD_DEALS_KEY = 'hideColdDeals';
const MAX_PRICE_KEY = 'maxPrice';
const LAST_HIDDEN_DEAL_SHOWN = 'lastHiddenDealShown';
const PREFERRED_SORT_KEY = 'mydealz_preferred_sort';

// --- Selektoren ---
const ARTICLE_SELECTOR = '.thread--deal, .thread--type--list';
const MERCHANT_PAGE_SELECTOR = '.merchant-banner';

// --- System/Performance Konstanten ---
const CLEANUP_TIME = 30000;
const IS_TOUCH_DEVICE = ('ontouchstart' in window) ||
      (navigator.maxTouchPoints > 0) ||
      (navigator.msMaxTouchPoints > 0);
const DEBUG = false;

// --- Feature Flags ---
const FEATURES = {
    hideMatchingMerchantNames: 'hideMatchingMerchantNames',
    hideShareButtons: 'hideShareButtons',
    rememberSort: 'rememberSort'
};

// ===== Instanzerkennung und Cleanup =====
(function detectMultipleInstances() {
    const currentVersion = GM_info.script.version;
    const now = Date.now();

    try {
        // Setze Marker für diese Version
        const myKey = VERSION_PREFIX + currentVersion;
        localStorage.setItem(myKey, now.toString());

        // Prüfe auf alle aktiven Versionen
        const activeVersions = new Set();
        for (let i = 0; i < localStorage.length; i++) {
            const key = localStorage.key(i);
            if (!key?.startsWith(VERSION_PREFIX)) continue;

            const version = key.replace(VERSION_PREFIX, '');
            const timestamp = parseInt(localStorage.getItem(key) || '0');

            if ((now - timestamp) < CLEANUP_TIME) {
                activeVersions.add(version);
            }
        }

        if (activeVersions.size > 1) {
            const warningMsg = `⚠️ Warnung: Es wurden mehrere Versionen des mydealz Managers gefunden!\n\nAktive Versionen:\n${Array.from(activeVersions).join('\n')}\n\nBitte deaktiviere alle Versionen bis auf eine in deinem Script-Manager.`;
            alert(warningMsg);
        }
    } catch (e) {
        console.error('Error in instance detection:', e);
    }
})();

// Cleanup beim Entladen der Seite
window.addEventListener('unload', () => {
    try {
        localStorage.removeItem(VERSION_PREFIX + GM_info.script.version);
    } catch (e) {
        // Ignoriere Fehler beim Cleanup
    }
});

// ===== UI-Ressourcen =====
// --- Font Awesome Einbindung ---
const fontAwesomeLink = document.createElement('link');
fontAwesomeLink.rel = 'stylesheet';
fontAwesomeLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css';
document.head.appendChild(fontAwesomeLink);

// --- Style Elemente ---
const preventAutoCloseStyle = document.createElement('style');
preventAutoCloseStyle.textContent = ``;
document.head.appendChild(preventAutoCloseStyle);

// ===== UI-Konfiguration =====
// --- Titel-Speicher ---
const ORIGINAL_TITLES = new Map();

// --- Sidebar Elemente ---
const SIDEBAR_ELEMENTS = {
    banners: {
        headerBanners: {
            name: "Banner im Header",
            selector: '.messages',
            storageKey: 'hideHeaderBanners',
            hidden: false
        },
        feedBanners: {
            name: "Banner im Feed",
            selector: '[id^="customBannerList-id-"], #eventBannerPortal',
            storageKey: 'hideFeedBanners',
            hidden: false
        }
    },
    widgets: {
        topDiscussions: {
            name: "Widgets",
            selector: '.card.card--type-vertical.listLayout-box.aGrid.card--responsive',
            storageKey: 'hideTopDiscussionsWidget',
            hidden: false
        }
    }
};

// ===== Observer-Konfiguration =====
const observer = new MutationObserver(throttle(() => {
    processArticles();
    addSettingsButton();
    addHideButtons();
}, 250));

// ===== UI-Zustand =====
// --- Hauptfenster ---
let isSettingsOpen = false;
let activeSubUI = null;
let dealThatOpenedSettings = null;

// --- UI-Elemente ---
let settingsDiv = null;
let merchantListDiv = null;
let wordsListDiv = null;
let uiClickOutsideHandler = null;

// ===== Filter-Zustand =====
// --- Ausschlusslisten ---
let excludeWords = [];
let excludeMerchantIDs = [];
let hiddenDeals = [];

// --- Filter-Einstellungen ---
let hideColdDeals = localStorage.getItem(HIDE_COLD_DEALS_KEY) === 'true';
let maxPrice = parseFloat(localStorage.getItem(MAX_PRICE_KEY)) || 0;

// ===== Temporäre Daten =====
// --- Vorschläge ---
let suggestedWords = [];
let suggestionClickHandler = null;

// --- Letzte Aktionen ---
let lastHiddenDeal = null; // Speichert nur den letzten ausgeblendeten Deal
let lastHiddenDealShown = false; // Wurde der letzte ausgeblendete Deal bereits angezeigt?

// ===== Menü-Commands =====
// --- Command IDs ---
let menuCommandId;
let merchantCommandId;
let backupCommandId;
let restoreCommandId;

// --- Feature-Flags ---
let hideMatchingMerchantNames = GM_getValue('hideMatchingMerchantNames', false);
let hideCustomBanners = GM_getValue('hideCustomBanners', false);
let hideShareButtons = GM_getValue('hideShareButtons', false);

// --- Temporäre Listen ---
let recentHiddenDeals = [];
//#endregion





//#region --- 2. Hilfsfunktionen (Utility Functions) ---
// ===== HTML & Text Verarbeitung =====
// HTML dekodieren
function decodeHtml(html) {
    const txt = document.createElement('textarea');
    txt.innerHTML = html;
    return txt.value;
}

// Regex-Sonderzeichen escapen
function escapeRegExp(string) {
    return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

// ===== Performance Optimierung =====
// Funktion zur Begrenzung der Ausführungshäufigkeit (Throttling)
function throttle(func, limit) {
    let inThrottle;
    return function(...args) {
        if (!inThrottle) {
            func.apply(this, args);
            inThrottle = true;
            setTimeout(() => {
                inThrottle = false;
                return false;
            }, limit);
        }
    }
}

// Liefert Theme-spezifische Farben basierend auf aktuellem Theme
function getThemeColors() {
    // Theme-Erkennung inline
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    const htmlElement = document.documentElement;
    const bodyElement = document.body;

    const isDark =
          htmlElement.classList.contains('dark') ||
          bodyElement.classList.contains('dark') ||
          htmlElement.getAttribute('data-theme') === 'dark' ||
          document.querySelector('html[data-theme="dark"]') !== null ||
          (prefersDark && !htmlElement.classList.contains('light'));

    // Direkt die entsprechenden Farben zurückgeben
    return isDark ? THEME_COLORS.dark : THEME_COLORS.light;
}

// === Text-Analyse ===
// Wörter aus Deal-Titel extrahieren
function getWordsFromTitle(deal) {
    const titleElement = deal.querySelector('.thread-title a');
    if (!titleElement) return [];

    const rawTitle = titleElement.querySelector('a')?.getAttribute('title') || titleElement.innerText || '';

    const keepWords = ['von', 'der', 'die', 'das', 'bei', 'mit', 'und', 'oder', 'auf', 'für', 'durch', 'bis', 'ab'];
    const ignoreWords = [
        'Euro', 'EUR', 'VSK', '€', 'VGP', 'cent', 'Cent',
        'o.', // oder
        'z.B.', 'z.b.', // zum Beispiel
        'inkl.', // inklusive
        'max.', // maximal
        'min.', // minimal
        'ca.', // circa
        'vs.', // versus
        'eff.', // effektiv
        'mtl.', // monatlich
        'bzw.', // beziehungsweise
        'evtl.', // eventuell
        'uvm.', // und vieles mehr
        'etc.', // et cetera
        'zzgl.', // zuzüglich
        'Nr.', 'nr.', // Nummer
        'St.', 'st.', // Stück
        'usw.', // und so weiter
        'u.a.', // unter anderem
        'u.U.', // unter Umständen
        'ggf.', // gegebenenfalls
        'p.', // pro/per
    ];
    const ignoreChars = ['&', '+', '!', '-', '/', '%', '–'];
    const units = ['MB/s', 'GB/s', 'KB/s', 'Mbit/s', 'Gbit/s', 'Kbit/s'];
    const priceContextWords = ['effektiv'];
    const specialBrands = ['RTL+'];

    const isDate = (word) => {
        return /^\d{1,2}[.,]\d{1,2}(?:[.,]\d{2,4})?$/.test(word);
    };

    const isPriceContext = (word) => {
        if (!priceContextWords.includes(word.toLowerCase())) return false;
        // Prüfe ob im Titel ein Preis vorkommt
        const hasPricePattern = /\d+(?:[.,]\d{2})?(?:€|EUR|Euro)/i;
        return hasPricePattern.test(rawTitle);
    };

    const isPrice = (word) => {
        return /^~?\d+(?:[.,]\d{2})?(?:€|EUR)?$/.test(word) ||
            /^\d+(?:[.,]\d{2})?(?:\s*cent|\s*Cent)$/i.test(word);
    };

    const isPercentage = (word) => {
        return /^\d+\s*%?$/.test(word) && rawTitle.includes('%');
    };

    const cleanWord = (word) => {
        // Check for special brands first
        if (specialBrands.includes(word)) {
            return word;
        }

        // Rest of the existing cleanWord function
        if (units.some(unit => word.includes(unit))) {
            const cleanedWord = word.trim();
            return cleanedWord.replace(/[,;:!?.]+$/, '');
        }

        return word
            .trim()
            .replace(/^[^a-zA-Z0-9äöüÄÖÜß]+|[^a-zA-Z0-9äöüÄÖÜß]+$/g, '')
            .replace(/^[&+!%–]+$/, '')
            .replace(/[-,]+$/, '');
    };

    const shouldKeepWord = (word) => {
        const lowerWord = word.toLowerCase();

        if (!word || word.length === 0) return false;
        if (ignoreChars.includes(word)) return false;
        if (ignoreWords.some(ignore => ignore.toLowerCase() === lowerWord)) return false;
        if (isDate(word)) return false;
        if (isPrice(word)) return false;
        if (isPercentage(word)) return false;
        if (isPriceContext(word)) return false;

        // Behalte spezielle Wörter
        if (keepWords.includes(lowerWord)) return true;
        if (units.some(unit => word === unit)) return true;

        return true;
    };

    const splitTitle = (title) => {
        // Temporär Einheiten und Abkürzungen schützen
        let tempTitle = title;
        const replacements = new Map();

        // Erst die Einheiten schützen
        units.forEach((unit, index) => {
            const placeholder = `__UNIT${index}__`;
            while (tempTitle.includes(unit)) {
                tempTitle = tempTitle.replace(unit, placeholder);
                replacements.set(placeholder, unit);
            }
        });

        // Dann die Abkürzungen schützen (z.B. "o." als ganzes Wort)
        ignoreWords.forEach((word, index) => {
            if (word.includes('.')) {
                const placeholder = `__ABBR${index}__`;
                // Verbesserte Regex für Abkürzungen, die auch Zahlen berücksichtigt
                const regex = new RegExp(`\\b${word.replace('.', '\\.')}\\s*(?=\\d|\\s|$)`, 'g');
                while (regex.test(tempTitle)) {
                    tempTitle = tempTitle.replace(regex, (match) => {
                        const replacement = ' '; // Ersetze Abkürzung durch Leerzeichen
                        return replacement;
                    });
                }
            }
        });

        // Split und Platzhalter wiederherstellen
        return tempTitle
            .split(/[\s\/]+/)
            .map(word => {
            replacements.forEach((original, placeholder) => {
                if (word.includes(placeholder)) {
                    word = word.replace(placeholder, original);
                }
            });
            return word;
        })
            .filter(word => word.length > 0); // Entferne leere Strings
    };

    return splitTitle(rawTitle)
        .map(cleanWord)
        .filter(shouldKeepWord)
        .filter((word, index, self) => self.indexOf(word) === index);
}

//#endregion





//#region --- 3. Datenverwaltung ---
// ===== Einstellungen laden/speichern =====
// Laden aller gespeicherten Einstellungen
function loadSettings() {
    // Lade Wortfilter und Händlerfilter
    excludeWords = loadExcludeWords();
    const merchantsData = loadExcludeMerchants();
    excludeMerchantIDs = merchantsData.map(m => m.id);

    // Lade Preisfilter
    maxPrice = parseFloat(GM_getValue('maxPrice', 0)) || 0;

    // Lade UI-Einstellungen
    hideColdDeals = GM_getValue('hideColdDeals', false);

    hideMatchingMerchantNames = GM_getValue('hideMatchingMerchantNames', false);
    window.hideMatchingMerchantNames = hideMatchingMerchantNames;

    // Lade Banner-Einstellung und aktualisiere basierend auf individuellen Einstellungen
    hideCustomBanners = GM_getValue('hideCustomBanners', false);

    // Wenn hideCustomBanners nicht explizit aktiviert ist, prüfe ob alle individuellen
    // Elemente ausgeblendet sind und setze hideCustomBanners entsprechend
    if (!hideCustomBanners) {
        const allHidden = Object.values(SIDEBAR_ELEMENTS).every(element => element.hidden);
        if (allHidden && Object.values(SIDEBAR_ELEMENTS).length > 0) {
            hideCustomBanners = true;
        }
    }

    window.hideCustomBanners = hideCustomBanners;

    // Lade Share Button Einstellung
    hideShareButtons = GM_getValue('hideShareButtons', false);
    window.hideShareButtons = hideShareButtons;

    // Lade versteckte Deals
    hiddenDeals = GM_getValue('hiddenDeals', []);

    // Lade letzten versteckten Deal
    lastHiddenDeal = GM_getValue('lastHiddenDeal', null);
    lastHiddenDealShown = GM_getValue(LAST_HIDDEN_DEAL_SHOWN, false);

    // Wenn lastHiddenDeal null ist, setze auch lastHiddenDealShown auf true
    if (!lastHiddenDeal) {
        lastHiddenDealShown = true;
        GM_setValue(LAST_HIDDEN_DEAL_SHOWN, true);
    }

    // Lade Banner-Status
    Object.keys(SIDEBAR_ELEMENTS.banners).forEach(key => {
        const element = SIDEBAR_ELEMENTS.banners[key];
        element.hidden = GM_getValue(element.storageKey, false);

        // Sofort Sichtbarkeit anwenden
        if (element.hidden) {
            document.querySelectorAll(element.selector).forEach(el => {
                el.style.display = 'none';
            });
        }
    });

    // Lade Sortierungsspeicher-Einstellung
    window.rememberSort = GM_getValue('rememberSort', true);

    const applyWidgetVisibilityOnce = () => {
        Object.keys(SIDEBAR_ELEMENTS.widgets).forEach(key => {
            const element = SIDEBAR_ELEMENTS.widgets[key];
            element.hidden = GM_getValue(element.storageKey, false);

            if (element.hidden) {
                document.querySelectorAll(element.selector).forEach(el => {
                    el.style.display = 'none';
                });
            }
        });
    };

    // Einmalig ausführen mit Verzögerung für dynamische Elemente
    setTimeout(applyWidgetVisibilityOnce, 500);

    // UI Updates in einem requestAnimationFrame bündeln
    requestAnimationFrame(() => {
        updateCustomBannerIcon();
        updateSidebarElementsUI();
    });
}

const combinedObserver = new MutationObserver(throttle(() => {
    // Prozessiere Artikel und UI
    processArticles();
    addSettingsButton();
    addHideButtons();

    // Prüfe Widget-Sichtbarkeit
    Object.keys(SIDEBAR_ELEMENTS.widgets).forEach(key => {
        const element = SIDEBAR_ELEMENTS.widgets[key];
        if (element.hidden) {
            document.querySelectorAll(element.selector).forEach(el => {
                el.style.display = 'none';
            });
        }
    });
}, 250));

// Observer starten
combinedObserver.observe(document.body, {
    childList: true,
    subtree: true
});

// Storage-Synchronisation zwischen GM und localStorage
async function syncStorage() {
    // Prüfe ob Migration bereits durchgeführt wurde
    const migrationComplete = GM_getValue('migrationComplete', false);

    // Lese Daten aus beiden Speichern
    const gmExcludeWords = GM_getValue('excludeWords', null);
    const gmExcludeMerchants = GM_getValue('excludeMerchantsData', null);
    const gmHiddenDeals = GM_getValue('hiddenDeals', null);
    const gmHideColdDeals = GM_getValue('hideColdDeals', null);
    const gmMaxPrice = GM_getValue('maxPrice', null);

    const lsExcludeWords = JSON.parse(localStorage.getItem('excludeWords') || 'null');
    const lsExcludeMerchants = JSON.parse(localStorage.getItem('excludeMerchantsData') || 'null');
    const lsHiddenDeals = JSON.parse(localStorage.getItem('hiddenDeals') || 'null');
    const lsHideColdDeals = localStorage.getItem('hideColdDeals') || 'null';
    const lsMaxPrice = localStorage.getItem('maxPrice') || 'null';

    let migrationPerformed = false;

    // Migriere Wörter
    const effectiveWords = gmExcludeWords || lsExcludeWords || [];
    if (effectiveWords.length > 0) {
        GM_setValue('excludeWords', effectiveWords);
        localStorage.setItem('excludeWords', JSON.stringify(effectiveWords));
        excludeWords = effectiveWords;
        migrationPerformed = true;
    }

    // Migriere Händler
    const effectiveMerchants = gmExcludeMerchants || lsExcludeMerchants || [];
    if (effectiveMerchants.length > 0) {
        GM_setValue('excludeMerchantsData', effectiveMerchants);
        excludeMerchantIDs = effectiveMerchants.map(m => m.id);
        GM_setValue('excludeMerchantIDs', excludeMerchantIDs);
        localStorage.setItem('excludeMerchantsData', JSON.stringify(effectiveMerchants));
        migrationPerformed = true;
    }

    // Migriere versteckte Deals
    const effectiveHiddenDeals = gmHiddenDeals || lsHiddenDeals || [];
    if (effectiveHiddenDeals.length > 0) {
        GM_setValue('hiddenDeals', effectiveHiddenDeals);
        localStorage.setItem('hiddenDeals', JSON.stringify(effectiveHiddenDeals));
        hiddenDeals = effectiveHiddenDeals;
        migrationPerformed = true;
    }

    // Migriere Einstellungen
    if (!migrationComplete) {
        if (gmHideColdDeals !== null || lsHideColdDeals !== 'null') {
            const effectiveHideColdDeals = gmHideColdDeals ?? (lsHideColdDeals === 'true');
            GM_setValue('hideColdDeals', effectiveHideColdDeals);
            localStorage.setItem('hideColdDeals', effectiveHideColdDeals.toString());
            hideColdDeals = effectiveHideColdDeals;
            migrationPerformed = true;
        }

        if (gmMaxPrice !== null || lsMaxPrice !== 'null') {
            const effectiveMaxPrice = gmMaxPrice || lsMaxPrice;
            GM_setValue('maxPrice', effectiveMaxPrice);
            localStorage.setItem('maxPrice', effectiveMaxPrice);
            maxPrice = parseFloat(effectiveMaxPrice);
            migrationPerformed = true;
        }

        // rememberSort
        const gmRememberSort = GM_getValue('rememberSort', null);
        const lsRememberSort = localStorage.getItem('rememberSort') === 'true';
        const effectiveRememberSort = gmRememberSort !== null ? gmRememberSort : lsRememberSort;
        GM_setValue('rememberSort', effectiveRememberSort);
        localStorage.setItem('rememberSort', effectiveRememberSort.toString());
        window.rememberSort = effectiveRememberSort;

        // hideMatchingMerchantNames
        const gmHideMatchingMerchantNames = GM_getValue('hideMatchingMerchantNames', null);
        const lsHideMatchingMerchantNames = localStorage.getItem('hideMatchingMerchantNames') === 'true';
        const effectiveHideMatchingMerchantNames = gmHideMatchingMerchantNames !== null ?
              gmHideMatchingMerchantNames : lsHideMatchingMerchantNames;
        GM_setValue('hideMatchingMerchantNames', effectiveHideMatchingMerchantNames);
        localStorage.setItem('hideMatchingMerchantNames', effectiveHideMatchingMerchantNames.toString());
        window.hideMatchingMerchantNames = effectiveHideMatchingMerchantNames;

        // hideShareButtons
        const gmHideShareButtons = GM_getValue('hideShareButtons', null);
        const lsHideShareButtons = localStorage.getItem('hideShareButtons') === 'true';
        const effectiveHideShareButtons = gmHideShareButtons !== null ?
              gmHideShareButtons : lsHideShareButtons;
        GM_setValue('hideShareButtons', effectiveHideShareButtons);
        localStorage.setItem('hideShareButtons', effectiveHideShareButtons.toString());
        window.hideShareButtons = effectiveHideShareButtons;

        // hideCustomBanners
        const gmHideCustomBanners = GM_getValue('hideCustomBanners', null);
        const lsHideCustomBanners = localStorage.getItem('hideCustomBanners') === 'true';
        const effectiveHideCustomBanners = gmHideCustomBanners !== null ?
              gmHideCustomBanners : lsHideCustomBanners;
        GM_setValue('hideCustomBanners', effectiveHideCustomBanners);
        localStorage.setItem('hideCustomBanners', effectiveHideCustomBanners.toString());
        window.hideCustomBanners = effectiveHideCustomBanners;

        // Sidebar Elements (Banner & Widgets)
        Object.entries(SIDEBAR_ELEMENTS).forEach(([category, items]) => {
            Object.entries(items).forEach(([key, element]) => {
                const storageKey = element.storageKey;
                const gmValue = GM_getValue(storageKey, null);
                const lsValue = localStorage.getItem(storageKey) === 'true';

                const effectiveValue = gmValue !== null ? gmValue : lsValue;
                GM_setValue(storageKey, effectiveValue);
                localStorage.setItem(storageKey, effectiveValue.toString());
                element.hidden = effectiveValue;
            });
        });

        migrationPerformed = true;
    }

    // Markiere Migration als abgeschlossen nur wenn tatsächlich Daten migriert wurden
    if (migrationPerformed) {
        GM_setValue('migrationComplete', true);
    }
}

// ===== Wortfilter-Verwaltung =====
// Speichern von Wortfiltern
function saveExcludeWords(words) {
    // Normalisiere Groß-/Kleinschreibung und entferne Duplikate
    const normalizedWords = words.reduce((acc, word) => {
        const lowerWord = word.toLowerCase();
        const exists = acc.some(w => w.toLowerCase() === lowerWord);
        if (!exists) {
            acc.push(word); // Behält originale Schreibweise bei
        }
        return acc;
    }, []);

    // Speichere nur die normalisierte Version
    GM_setValue('excludeWords', normalizedWords);
    localStorage.setItem('excludeWords', JSON.stringify(normalizedWords));
}

// Laden von Wortfiltern
function loadExcludeWords() {
    // Load from GM storage
    const gmWords = GM_getValue('excludeWords', []);

    // Load from localStorage
    let lsWords = [];
    try {
        lsWords = JSON.parse(localStorage.getItem('excludeWords') || '[]');
    } catch (e) {
    }

    // Show final result
    const result = gmWords.length > 0 ? gmWords : lsWords;

    return result;
}

// ===== Deal-Verwaltung =====
// Speichern ausgeblendeter Deals
function saveHiddenDeals() {
    GM_setValue('hiddenDeals', hiddenDeals);
    localStorage.setItem('hiddenDeals', JSON.stringify(hiddenDeals));
}

// ===== Händler-Verwaltung =====
// Speichern von Händlerfiltern
function saveExcludeMerchants(merchantsData) {
    const validMerchants = merchantsData.filter(m =>
                                                m && typeof m.id !== 'undefined' && m.id !== null &&
                                                typeof m.name !== 'undefined' && m.name !== null
                                               );
    const ids = validMerchants.map(m => m.id);

    GM_setValue('excludeMerchantIDs', ids);
    GM_setValue('excludeMerchantsData', validMerchants);
    localStorage.setItem('excludeMerchantsData', JSON.stringify(validMerchants));

    excludeMerchantIDs = ids;
}

// Laden von Händlerfiltern
function loadExcludeMerchants() {
    const merchantsData = GM_getValue('excludeMerchantsData', []);
    const legacyIds = GM_getValue('excludeMerchantIDs', []);

    // Filter out invalid entries
    const validMerchants = merchantsData.filter(m =>
                                                m &&
                                                typeof m.id !== 'undefined' &&
                                                m.id !== null &&
                                                typeof m.name !== 'undefined' &&
                                                m.name !== null
                                               );

    // Convert legacy IDs if needed
    if (validMerchants.length === 0 && legacyIds.length > 0) {
        return legacyIds
            .filter(id => id && typeof id !== 'undefined')
            .map(id => ({ id, name: id }));
    }

    return validMerchants;
}

// ===== Preis-Verwaltung =====
// Speichern des Maximalpreises
function saveMaxPrice(price) {

    // Convert to number if it's a string
    if (typeof price === 'string') {
        price = parseFloat(price.replace(',', '.')) || 0;
    }

    GM_setValue('maxPrice', price);
    localStorage.setItem('maxPrice', price.toString());
    maxPrice = price;
}
//#endregion





//#region --- 4. UI-System ---
// ===== Basis UI-Funktionen =====

// Container, Styles, Theme
function initUIContainers() {
    settingsDiv = document.createElement('div');
    merchantListDiv = document.createElement('div');
    wordsListDiv = document.createElement('div');
}

function updateUITheme() {
    const colors = getThemeColors();

    [settingsDiv, merchantListDiv, wordsListDiv].forEach(div => {
        if (div?.parentNode) {
            div.style.background = colors.background;
            div.style.border = `1px solid ${colors.border}`;
            div.style.color = colors.text;

            // Update all buttons and inputs
            div.querySelectorAll('button:not([id*="close"])').forEach(btn => {
                btn.style.background = colors.buttonBg;
                btn.style.border = `1px solid ${colors.buttonBorder}`;
                btn.style.color = colors.text;
            });

            div.querySelectorAll('input').forEach(input => {
                input.style.background = colors.inputBg;
                input.style.border = `1px solid ${colors.border}`;
                input.style.color = colors.text;
            });
        }
    });
}

// === UI-Komponenten ===
// --- Dialog-Erstellung ---
function createSettingsUI() {
    if (isSettingsOpen) return;
    isSettingsOpen = true;

    // Lade versteckte Deals neu
    const oldHiddenDeals = [...hiddenDeals]; // Copy old state
    hiddenDeals = GM_getValue('hiddenDeals', []);

    // Lade versteckte Deals neu
    hiddenDeals = GM_getValue('hiddenDeals', []);

    // Konsistente Überprüfung des "already shown" Status
    const wasAlreadyShown = GM_getValue(LAST_HIDDEN_DEAL_SHOWN, false);

    // Wenn bereits angezeigt oder kein letzter Deal vorhanden, dann nicht mehr anzeigen
    if (!lastHiddenDeal || wasAlreadyShown) {
        lastHiddenDealShown = true;
        GM_setValue(LAST_HIDDEN_DEAL_SHOWN, true);
    } else {
        lastHiddenDealShown = false;
        // GM_setValue nicht hier setzen, erst beim Schließen des UI
    }

    // Initialize containers
    initUIContainers();

    const colors = getThemeColors();

    // Get merchant info from current deal
    let merchantName = null;
    let showMerchantButton = false;

    settingsDiv.style.cssText = `
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 300px;
        height: 300px;
        max-width: 90vw;
        max-height: 90vh;
        background: ${colors.background};
        border: 1px solid ${colors.border};
        border-radius: 5px;
        padding: 8px 15px;
        z-index: 1000;
        color: ${colors.text};
        display: flex;
        flex-direction: column;
    `;

    if (dealThatOpenedSettings) {
        const merchantLink = dealThatOpenedSettings.querySelector('a[data-t="merchantLink"]');
        if (merchantLink) {
            merchantName = merchantLink.textContent.trim();
            showMerchantButton = true;
        }
    }

    // Process articles when opening settings
    processArticles();

    // Header
    const header = document.createElement('div');
    header.className = 'accordion-header'; // Klasse für Drag-Funktionalität
    header.style.cssText = `
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 8px;
        flex-shrink: 0;
        cursor: move; // Cursor für Drag-Anzeige
        padding: 10px;
        user-select: none;
        background: ${colors.background};
        border-bottom: 1px solid ${colors.border};
    `;

    // Scrollbarer Content-Container
    const contentContainer = document.createElement('div');
    contentContainer.style.cssText = `
        flex-grow: 1;
        overflow-y: auto;
        margin-right: -5px;
        padding-right: 5px;
        margin-bottom: 5px; 
        max-height: calc(300px - 60px);
    `;
    contentContainer.id = 'mdm-settings-content'; // ID hinzufügen für einfacheres Debugging

    // Accordion-Sektionen definieren und hinzufügen
    const sections = {
        quickActions: createAccordionSection('Schnellaktionen', 'bolt'),
        filter: createAccordionSection('Filter', 'filter'),
        features: createAccordionSection('Funktionen', 'toggle-on'),
        backup: createAccordionSection('Backup', 'save')
    };

    // Quick Actions Section (standardmäßig offen)
    sections.quickActions.content.innerHTML = `
    <div class="section-content" style="display: flex; flex-direction: column; gap: 6px;"> <!-- Reduced gap from 8px to 6px -->
        <!-- Word Input - mit nativer mydealz Suchfeld-Optik -->
        <div style="margin-bottom: 6px;"> <!-- Reduced from 8px to 6px -->
            <div style="display: flex; align-items: center; gap: 4px;">
                <div class="search-box" style="
                    flex: 1;
                    position: relative;
                    display: flex;
                    align-items: center;
                    background: ${colors.inputBg};
                    border: 1px solid ${colors.border};
                    border-radius: 8px;
                    padding: 0 8px;
                    height: 36px;
                    transition: all 0.2s ease;
                    overflow: hidden;
                ">
                    <input id="newWordInput"
                        autocomplete="off"
                        ${IS_TOUCH_DEVICE ? 'readonly' : ''}
                        placeholder="Neues Wort..."
                        title="Deals mit hier eingetragenen Wörtern im Titel werden ausgeblendet."
                        style="
                            flex: 1;
                            min-width: 0;
                            padding: 0;
                            border: none;
                            outline: none;
                            background: transparent;
                            color: ${colors.text};
                            font-size: 14px;
                            height: 100%;
                        ">
                </div>
                ${IS_TOUCH_DEVICE ? `
                    <button id="enableKeyboardButton" style="...">
                        <i class="fas fa-keyboard"></i>
                    </button>
                ` : ''}
                <button id="addWordButton" style="...">
                    <i class="fas fa-plus"></i>
                </button>
            </div>
        </div>

        ${showMerchantButton ? `
            <button id="hideMerchantButton" style="...">
                <i class="fas fa-store-slash"></i> Alle Deals von <span style="font-weight: bold">${merchantName}</span> ausblenden
            </button>
        ` : ''}

        ${lastHiddenDeal && !lastHiddenDealShown ? `
            <div id="lastHiddenDealSection" style="...">
                <!-- Last hidden deal content -->
            </div>
        ` : ''}
    </div>
    `;

    // Filter Section
    sections.filter.content.innerHTML = `
        <div class="section-content" style="display: flex; flex-direction: column; gap: 6px;">
            <button id="showWordsListButton" class="menu-button">
                <i class="fas fa-list"></i> Wortfilter verwalten
            </button>

            <!-- Separator -->
            <div style="height: 1px; background: ${colors.border}; opacity: 0.3; margin: 4px 0;"></div>

            <button id="showMerchantListButton" class="menu-button">
                <i class="fas fa-store"></i> Händlerfilter verwalten
            </button>

            <!-- Separator -->
            <div style="height: 1px; background: ${colors.border}; opacity: 0.3; margin: 4px 0;"></div>

            <div class="toggle-option" style="display: flex; justify-content: space-between; align-items: center;">
                <span title="Deals unter 0° werden ausgeblendet">Kalte Deals</span>
                <button type="button" id="hideColdDeals" class="eye-toggle" style="...">
                    <i class="fas ${hideColdDeals ? 'fa-eye-slash' : 'fa-eye'}"></i>
                </button>
            </div>

            <!-- Separator -->
            <div style="height: 1px; background: ${colors.border}; opacity: 0.3; margin: 4px 0;"></div>

            <div style="display: flex; align-items: center; gap: 10px;">
                <label style="flex-grow: 1" title="Deals über diesem Preis werden ausgeblendet">
                    Teure Deals
                </label>
                <input
                    type="text"
                    inputmode="decimal"
                    pattern="[0-9]*[.,]?[0-9]*"
                    id="settingsMaxPrice"
                    value="${maxPrice.toLocaleString('de-DE', {
        minimumFractionDigits: 0,
        maximumFractionDigits: 2
    })}"
                    placeholder="€"
                    style="
                        width: 80px;
                        padding: 4px 8px;
                        text-align: right;
                        background: ${colors.inputBg};
                        border: 1px solid ${colors.border};
                        border-radius: 3px;
                        color: ${colors.text};
                    "
                >
            </div>
        </div>
    `;

    // Vor dem Öffnen des UIs den Status der Icons aktualisieren
    const anyHidden = Object.values(SIDEBAR_ELEMENTS).some(element => element.hidden);
    const allHidden = Object.values(SIDEBAR_ELEMENTS).length > 0 &&
          Object.values(SIDEBAR_ELEMENTS).every(element => element.hidden);

    // Passt hideCustomBanners basierend auf dem tatsächlichen Status der Elemente an
    if (allHidden) {
        window.hideCustomBanners = true;
        GM_setValue('hideCustomBanners', true);
    } else if (anyHidden) {
        // Bei teilweiser Sichtbarkeit soll hideCustomBanners deaktiviert sein
        window.hideCustomBanners = false;
        GM_setValue('hideCustomBanners', false);
    } else {
        window.hideCustomBanners = false;
        GM_setValue('hideCustomBanners', false);
    }

    // Aktualisiere die Icon-Klasse und Aria-Label für hideCustomBanners vor dem Hinzufügen
    const customBannerIconClass = allHidden ? 'fa-eye-slash' :
    anyHidden ? 'fa-eye-low-vision' :
    'fa-eye';

    const customBannerAriaLabel = allHidden ? 'Elemente versteckt' :
    anyHidden ? 'Einige Elemente versteckt' :
    'Elemente sichtbar';

    // Features Section
    sections.features.content.innerHTML = `
        <div class="section-content" style="display: flex; flex-direction: column; gap: 6px;">
            ${document.querySelector('[data-t="shareBtn"]') ? `
                <div class="toggle-option" style="display: flex; justify-content: space-between; align-items: center;">
                    <span title="Blendet den Teilen Button in jedem Deal in der Übersicht aus">Teilen Button</span>
                    <button type="button" id="hideShareButtons" class="eye-toggle" style="
                        background: none;
                        border: none;
                        cursor: pointer;
                        font-size: 18px;
                        color: ${colors.text};
                        width: 30px;
                        height: 30px;
                        display: flex;
                        align-items: center;
                        justify-content: center;
                    ">
                        <i class="fas ${window.hideShareButtons ? 'fa-eye-slash' : 'fa-eye'}"
                        aria-label="${window.hideShareButtons ? 'Share Buttons versteckt' : 'Share Buttons sichtbar'}"></i>
                    </button>
                </div>

                <!-- Separator -->
                <div style="height: 1px; background: ${colors.border}; opacity: 0.3; margin: 6px 0;"></div>
            ` : ''}

            <div class="toggle-option" style="
                display: flex;
                justify-content: space-between;
                align-items: center;
                position: relative;
            ">
                <button type="button" id="openSidebarElementsButton" class="text-button" style="
                    background: none;
                    border: none;
                    cursor: pointer;
                    text-align: left;
                    padding: 0;
                    color: ${colors.text};
                    font-size: inherit;
                    position: relative;
                    z-index: 2;
                    flex-grow: 1;
                    display: flex;
                    align-items: center;
                " title="${window.innerWidth <= 768 ? 'Verwalte Banner und Widgets' : 'Verwalte Banner und Widgets'}">
                    ${window.innerWidth <= 768 ? 'Banner & Feed-Elemente' : 'Banner & Widgets'}
                </button>

                <!-- Senkrechter Trennstrich -->
                <div style="
                    width: 1px;
                    height: 18px;
                    background-color: ${colors.border};
                    margin: 0 10px;
                    opacity: 0.7;
                "></div>

                <button type="button" id="hideCustomBanners" class="eye-toggle" style="
                    background: none;
                    border: none;
                    cursor: pointer;
                    font-size: 18px;
                    color: ${colors.text};
                    width: 30px;
                    height: 30px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                ">
                    <i class="fas ${customBannerIconClass}"
                    aria-label="${customBannerAriaLabel}"></i>
                </button>
            </div>

            <!-- Separator -->
            <div style="height: 1px; background: ${colors.border}; opacity: 0.3; margin: 6px 0;"></div>

            <div class="toggle-option" style="display: flex; justify-content: space-between; align-items: center;">
                <span style="display: flex; align-items: center; cursor: help;" title="Gibt es zu dem Deal einen hinterlegten Händler und befindet sich der Name des Händlers im Titel, so wird dieser Name aus dem Titel ausgeblendet.">
                    Händler im Titel
                </span>
                <button type="button" id="hideMatchingMerchantNames" class="eye-toggle" style="
                    background: none;
                    border: none;
                    cursor: pointer;
                    font-size: 18px;
                    color: ${colors.text};
                    width: 30px;
                    height: 30px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                ">
                    <i class="fas ${window.hideMatchingMerchantNames ? 'fa-eye-slash' : 'fa-eye'}"
                    aria-label="${window.hideMatchingMerchantNames ? 'Händlernamen versteckt' : 'Händlernamen sichtbar'}"></i>
                </button>
            </div>

            <!-- Separator -->
            <div style="height: 1px; background: ${colors.border}; opacity: 0.3; margin: 6px 0;"></div>

            <!-- Neue Toggle-Option für Sortierung merken (VERSCHOBEN UNTER HÄNDLER IM TITEL) -->
            <div class="toggle-option" style="display: flex; justify-content: space-between; align-items: center;">
                <span style="display: flex; align-items: center; cursor: help;" title="Standardmäßig wird nach Relevanz sortiert. Wählt der Nutzer eine andere Sortierung, wird diese gespeichert und bei der nächsten Suche automatisch angewandt.">
                    Sortierung merken
                </span>
                <button type="button" id="rememberSort" class="toggle-switch" style="
                    background: none;
                    border: none;
                    cursor: pointer;
                    font-size: 18px;
                    color: ${colors.text};
                    width: 30px;
                    height: 30px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                ">
                    <i class="fas ${window.rememberSort ? 'fa-toggle-on' : 'fa-toggle-off'}"
                    aria-label="${window.rememberSort ? 'Sortierung wird gespeichert' : 'Sortierung wird nicht gespeichert'}"></i>
                </button>
            </div>
        </div>
    `;

    // Backup Section
    sections.backup.content.innerHTML = `
        <div class="section-content" style="display: flex; flex-direction: column; gap: 6px;">
            <button id="backupDataButton" class="menu-button">
                <i class="fas fa-download"></i> Backup erstellen
            </button>

            <!-- Separator -->
            <div style="height: 1px; background: ${colors.border}; opacity: 0.3; margin: 4px 0;"></div>

            <button id="restoreDataButton" class="menu-button">
                <i class="fas fa-upload"></i> Backup wiederherstellen
            </button>
            <input type="file"
                id="restoreFileInput"
                accept=".json"
                style="display: none;">
        </div>
    `;

    // Add sections to container
    Object.values(sections).forEach(({section}) => {
        contentContainer.appendChild(section);
    });

    // Erste Sektion automatisch öffnen und andere schließen
    Object.values(sections).forEach(({section}, index) => {
        const header = section.querySelector('.accordion-header');
        const content = section.querySelector('.accordion-content');
        const icon = header.querySelector('.fa-chevron-down');

        if (index === 0) { // Schnellaktionen
            content.style.display = 'block';
            icon.style.transform = 'rotate(180deg)';
        } else {
            content.style.display = 'none';
            icon.style.transform = '';
        }
    });

    // Footer mit fixem Schließen-Button - weniger Abstand zum Content
    const footer = document.createElement('div');
    footer.style.cssText = `
        margin-top: 2px;
        flex-shrink: 0;
        display: flex;
        justify-content: center;
    `;

    footer.innerHTML = `
        <button id="closeSettingsButton" class="button button--type-secondary button--mode-default button--shape-circle">
            <span>Schließen</span>
        </button>
    `;

    // Zusammenbau der UI
    settingsDiv.appendChild(header);
    settingsDiv.appendChild(contentContainer);
    settingsDiv.appendChild(footer);
    document.body.appendChild(settingsDiv);

    // Sammle alle Cleanup-Funktionen
    const cleanupFunctions = [];

    // Füge Draggable Cleanup hinzu
    const cleanupDraggable = makeDraggable(settingsDiv);
    if (cleanupDraggable) cleanupFunctions.push(cleanupDraggable);

    // Füge Scroll Handling Cleanup hinzu
    const cleanupScrollHandling = setupScrollHandling();
    if (cleanupScrollHandling) cleanupFunctions.push(cleanupScrollHandling);

    // Erweitere die Hauptcleanup-Funktion einmalig
    const oldCleanup = cleanup;
    cleanup = () => {
        // Führe alle registrierten Cleanup-Funktionen aus
        cleanupFunctions.forEach(fn => fn());
        // Führe original Cleanup aus
        oldCleanup();
    };

    // Nach dem Hinzufügen zum DOM den Button anpassen
    document.getElementById('closeSettingsButton').style.cssText = `
        padding: 8px 16px;
        display: inline-block;
        width: auto;
        min-width: 100px;
        text-align: center;
    `;

    // Event-Listener für den Sortierung Button:
    document.getElementById('rememberSort')?.addEventListener('click', async (e) => {
        // Toggle state
        const newState = !window.rememberSort;
        window.rememberSort = newState;
        GM_setValue('rememberSort', newState);

        // Wenn Feature deaktiviert wurde, gespeicherte Sortierung entfernen
        if (!newState && localStorage.getItem(PREFERRED_SORT_KEY)) {
            localStorage.removeItem(PREFERRED_SORT_KEY);
            if (DEBUG) console.log('[MDM Sort] Gespeicherte Sortierung gelöscht (Feature deaktiviert)');
        }

        // Update icon
        const icon = e.currentTarget.querySelector('i');
        if (icon) {
            icon.className = `fas ${newState ? 'fa-toggle-on' : 'fa-toggle-off'}`;
            icon.setAttribute('aria-label', newState ? 'Sortierung wird gespeichert' : 'Sortierung wird nicht gespeichert');
        }
    });

    // Accordion section styling - reduce padding and margins
    const accordionSectionStyle = document.createElement('style');
    accordionSectionStyle.textContent = `
        .accordion-section {
            margin-bottom: 4px;
        }
        .accordion-header {
            font-size: 18px;
            font-weight: bold;
            padding: 6px 8px !important;
            color: var(--primary-color, #24a300) !important;
        }
        .accordion-content {
            padding: 6px 8px !important;
        }
    `;
    document.head.appendChild(accordionSectionStyle);

    // Backup/Restore Buttons korrekt referenzieren
    const backupButton = document.getElementById('backupDataButton');
    const restoreButton = document.getElementById('restoreDataButton');
    const restoreFileInput = document.getElementById('restoreFileInput');

    // Event Listener für den versteckten Datei-Input
    if (restoreFileInput) {
        restoreFileInput.addEventListener('change', (e) => {
            restoreData(e);
        });
    }

    if (backupButton) {
        backupButton.addEventListener('click', () => {
            backupData();
        });
    }

    if (restoreButton) {
        restoreButton.addEventListener('click', () => {
            if (restoreFileInput) {
                restoreFileInput.click();
            } else {
            }
        });
    }

    // Add Word Button
    const addWordButton = document.getElementById('addWordButton');
    if (addWordButton) {
        addWordButton.addEventListener('click', () => {
            const newWordInput = document.getElementById('newWordInput');
            const newWord = newWordInput.value.trim();

            // Lade aktuelle Wörter neu um sicherzustellen dass wir die komplette Liste haben
            excludeWords = loadExcludeWords();

            // Prüfe ob das Wort (unabhängig von Groß-/Kleinschreibung) bereits existiert
            const wordExists = excludeWords.some(word => word.toLowerCase() === newWord.toLowerCase());

            if (newWord && !wordExists) {
                excludeWords.unshift(newWord); // Füge neues Wort zur bestehenden Liste hinzu
                saveExcludeWords(excludeWords);
                newWordInput.value = '';
                processArticles();
                cleanup();

                suggestedWords = [];
                const suggestionList = document.getElementById('wordSuggestionList');
                if (suggestionList) {
                    suggestionList.remove();
                }
            } else if (wordExists) {
                // Erstelle und zeige Fehlermeldung
                const errorMsg = document.createElement('div');
                errorMsg.style.cssText = `
                    position: absolute;
                    top: 100%;
                    left: 0;
                    right: 0;
                    padding: 8px;
                    margin-top: 4px;
                    background: #ffebee;
                    color: #c62828;
                    border: 1px solid #ef9a9a;
                    border-radius: 3px;
                    font-size: 12px;
                    z-index: 1003;
                `;
                errorMsg.textContent = `"${newWord}" ist bereits in der Liste vorhanden.`;

                // Füge Fehlermeldung zum Input-Container hinzu
                const inputContainer = newWordInput.parentElement;
                inputContainer.style.position = 'relative';
                inputContainer.appendChild(errorMsg);

                // Entferne Fehlermeldung nach 3 Sekunden
                setTimeout(() => {
                    errorMsg.remove();
                }, 3000);

                // Selektiere den Text im Input für einfaches Überschreiben
                newWordInput.select();
            }
        });
    }

    // Enable Keyboard Button (für Touch-Geräte)
    const enableKeyboardButton = document.getElementById('enableKeyboardButton');
    if (enableKeyboardButton) {
        enableKeyboardButton.addEventListener('click', () => {
            const newWordInput = document.getElementById('newWordInput');
            if (newWordInput) {
                newWordInput.readOnly = false;
                newWordInput.focus();
            }
        });
    }

    // Hide Merchant Button
    const hideMerchantButton = document.getElementById('hideMerchantButton');
    if (hideMerchantButton && showMerchantButton) {
        hideMerchantButton.addEventListener('click', () => {
            if (!dealThatOpenedSettings) return;

            const merchantLink = dealThatOpenedSettings.querySelector('a[href*="merchant-id="]');
            if (!merchantLink) return;

            const merchantIDMatch = merchantLink.getAttribute('href').match(/merchant-id=(\d+)/);
            if (!merchantIDMatch) return;

            const merchantID = merchantIDMatch[1];
            const merchantName = dealThatOpenedSettings.querySelector('a[data-t="merchantLink"]').textContent.trim();

            const merchantsData = loadExcludeMerchants();
            if (!merchantsData.some(m => m.id === merchantID)) {
                merchantsData.unshift({ id: merchantID, name: merchantName });
                saveExcludeMerchants(merchantsData);
                processArticles();
                cleanup(); // Close settings UI

                // Aktualisiere Listen wenn UI offen
                if (activeSubUI === 'merchant') {
                    updateActiveLists();
                }
            }
        });
    }

    // Show Words List Button
    const showWordsListButton = document.getElementById('showWordsListButton');
    if (showWordsListButton) {
        showWordsListButton.addEventListener('click', () => {
            if (switchSubUI('words')) {
                createExcludeWordsUI();
            }
        });
    }

    // Show Merchant List Button
    const showMerchantListButton = document.getElementById('showMerchantListButton');
    if (showMerchantListButton) {
        showMerchantListButton.addEventListener('click', () => {
            if (switchSubUI('merchant')) {
                createMerchantListUI();
            }
        });
    }

    // Sidebar Elements Button
    document.getElementById('openSidebarElementsButton').addEventListener('click', () => {
        if (switchSubUI('sidebar')) {
            createSidebarElementsUI();
        }
    });

    // Add event listeners only if newWordInput exists
    const newWordInput = document.getElementById('newWordInput');
    if (newWordInput) {
        // Enter Key Handler für das Eingabefeld
        newWordInput.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') {
                e.preventDefault();
                const word = newWordInput.value.trim();
                if (word && word.length > 0) {
                    // Add to excludeWords if not already in the list
                    if (!excludeWords.includes(word)) {
                        excludeWords.push(word);
                        saveExcludeWords(excludeWords);
                        processArticles();
                    }

                    // Clear the input field
                    newWordInput.value = '';
                    // Close suggestion list
                    document.getElementById('wordSuggestionList')?.remove();
                }
            }
        });

        // Unified focus handler
        newWordInput.addEventListener('focus', () => {
            // Get fresh words from current deal if none exist
            if (suggestedWords.length === 0) {
                suggestedWords = getWordsFromTitle(dealThatOpenedSettings);
            }

            // Always show suggestion list if words exist
            if (suggestedWords.length > 0) {
                updateSuggestionList();
            }
        }, { once: false }); // Allow multiple focus events
    }

    // Click Outside Handler anpassen
    createSuggestionClickHandler();

    // Cleanup bei UI-Schließung
    document.getElementById('closeSettingsButton').addEventListener('click', () => {
        document.removeEventListener('click', suggestionClickHandler);
        cleanup();
    });

    // Add cleanup to window unload
    window.addEventListener('unload', cleanup);

    const maxPriceInput = document.getElementById('settingsMaxPrice'); // Korrekter ID
    if (maxPriceInput) {
        // Focus-Handler hinzufügen, der den Inhalt markiert
        maxPriceInput.addEventListener('focus', () => {
            maxPriceInput.select();
        });

        // Formatierer für die Eingabe
        const formatPrice = (value) => {
            let cleaned = value.replace(/[^\d.,]/g, '');
            const parts = cleaned.split(',');

            // Begrenze Nachkommastellen auf 2
            if (parts.length > 1) {
                parts[1] = parts[1].slice(0, 2); // Maximal 2 Stellen nach dem Komma
                cleaned = parts[0] + ',' + parts[1];
            }

            if (parts.length > 2) {
                cleaned = parts.slice(0, -1).join('') + ',' + parts.slice(-1)[0].slice(0, 2);
            }

            if (parts.length === 2) {
                const intPart = parts[0].replace(/\./g, '');
                return Number(intPart).toLocaleString('de-DE') + ',' + parts[1];
            } else {
                const intPart = cleaned.replace(/\./g, '');
                return Number(intPart).toLocaleString('de-DE');
            }
        };

        // Input-Handler hinzufügen für die Live-Formatierung
        maxPriceInput.addEventListener('input', (e) => {
            e.stopPropagation();
            e.target.value = formatPrice(e.target.value);
        });

        // Beim Verlassen des Feldes den Wert speichern
        maxPriceInput.addEventListener('blur', (e) => {
            const value = e.target.value;
            const numStr = value.replace(/\./g, '').replace(',', '.');
            const numericValue = parseFloat(numStr);

            if (!isNaN(numericValue) && numericValue >= 0) {
                saveMaxPrice(numericValue);
                processArticles();
            }
        });

        // Behandlung für Touch-Geräte
        if (IS_TOUCH_DEVICE) {
            maxPriceInput.addEventListener('focus', () => {
                // Öffnet die numerische Tastatur auf Touch-Geräten
                maxPriceInput.setAttribute('inputmode', 'decimal');

                // Markiert den Text für einfaches Überschreiben
                maxPriceInput.select();
            });
        }
    }

    // Get initial word suggestions
    suggestedWords = dealThatOpenedSettings ? getWordsFromTitle(dealThatOpenedSettings) : [];

    // Event-Listener für die "Zurück"-Buttons bei kürzlich ausgeblendeten Deals
    document.querySelector('.restore-deal-button')?.addEventListener('click', (e) => {
        const dealId = e.currentTarget.dataset.dealId;

        // Deal aus hiddenDeals entfernen
        hiddenDeals = hiddenDeals.filter(id => id !== dealId);
        saveHiddenDeals();

        // Deal als angezeigt markieren
        lastHiddenDealShown = true;
        GM_setValue(LAST_HIDDEN_DEAL_SHOWN, true);

        // UI aktualisieren
        document.getElementById('lastHiddenDealSection').style.display = 'none';

        // Finde den wiederhergestellten Deal
        const restoredDeal = document.getElementById(dealId);
        if (restoredDeal) {
            // Hide-Button Container zurücksetzen
            const hideButtonContainer = restoredDeal.querySelector('.cept-vote-temp div');
            if (hideButtonContainer) {
                hideButtonContainer.style.display = 'none';
            }
        }

        // Deals neu verarbeiten
        processArticles();
    });

    // Setup ClickOutsideHandler für das Settings-UI
    setupClickOutsideHandler();

    document.getElementById('hideShareButtons')?.addEventListener('click', async (e) => {
        // Toggle state
        const newState = !window.hideShareButtons;
        window.hideShareButtons = newState;
        GM_setValue('hideShareButtons', newState);

        // Update icon
        const icon = e.currentTarget.querySelector('i');
        if (icon) {
            icon.className = newState ? 'fas fa-eye-slash' : 'fas fa-eye';
            icon.setAttribute('aria-label', newState ? 'Share Buttons versteckt' : 'Share Buttons sichtbar');
        }

        // Update visibility
        updateShareButtonsVisibility(newState);

        await Promise.resolve();
        processArticles();
    });

    document.getElementById('hideMatchingMerchantNames')?.addEventListener('click', async (e) => {
        // Toggle state
        const newState = !window.hideMatchingMerchantNames;
        window.hideMatchingMerchantNames = newState;
        GM_setValue('hideMatchingMerchantNames', newState);

        // Update icon
        const icon = e.currentTarget.querySelector('i');
        if (icon) {
            icon.className = `fas ${newState ? 'fa-eye-slash' : 'fa-eye'}`;
            icon.setAttribute('aria-label', newState ? 'Händlernamen versteckt' : 'Händlernamen sichtbar');
        }

        // Update visibility
        await Promise.resolve();
        processArticles();
    });

    // Event Handler für den Custom Banner-Toggle
    document.getElementById('hideCustomBanners')?.addEventListener('click', async () => {
        // Toggle state
        const newState = !window.hideCustomBanners;

        // Aktualisiere alle SIDEBAR_ELEMENTS nur im Status
        Object.keys(SIDEBAR_ELEMENTS).forEach(key => {
            const element = SIDEBAR_ELEMENTS[key];
            element.hidden = newState;
            GM_setValue(element.storageKey, newState);
        });

        // Aktualisiere die Haupt-Variable
        window.hideCustomBanners = newState;
        GM_setValue('hideCustomBanners', newState);

        // Haupt-Icon aktualisieren
        updateCustomBannerIcon();

        // WICHTIG: Aktualisiere auch die UI-Elemente in der Sidebar
        updateSidebarElementsUI();
    });

    document.getElementById('hideColdDeals')?.addEventListener('click', async (e) => {
        // Toggle state
        hideColdDeals = !hideColdDeals;

        // Save to storage
        GM_setValue('hideColdDeals', hideColdDeals);
        localStorage.setItem(HIDE_COLD_DEALS_KEY, hideColdDeals.toString());

        // Update icon
        const icon = e.currentTarget.querySelector('i');
        if (icon) {
            icon.className = `fas ${hideColdDeals ? 'fa-eye-slash' : 'fa-eye'}`;
            icon.setAttribute('aria-label', hideColdDeals ? 'Kalte Deals versteckt' : 'Kalte Deals sichtbar');
        }

        // Reprocess articles to apply the change
        await Promise.resolve();
        processArticles();
    });

}

function makeDraggable(element) {
    // Don't make draggable on touch devices
    if (IS_TOUCH_DEVICE) return;

    let isDragging = false;
    let offsetX = 0, offsetY = 0;
    let wasMoved = false;

    // Header für Drag-Funktionalität
    const header = element.querySelector('.accordion-header:first-child');
    if (!header) return;

    header.style.cursor = 'move';
    header.style.userSelect = 'none';

    const startDrag = (e) => {
        // Nur bei linker Maustaste
        if (e.button !== 0) return;

        isDragging = true;
        const rect = element.getBoundingClientRect();
        offsetX = e.clientX - rect.left;
        offsetY = e.clientY - rect.top;

        // Initial position setzen wenn noch nicht verschoben
        if (!wasMoved) {
            element.style.left = rect.left + 'px';
            element.style.top = rect.top + 'px';
            element.style.transform = 'none';
            element.style.right = 'auto';
            element.style.bottom = 'auto';
            wasMoved = true;
        }

        // Prevent text selection during drag
        document.body.style.userSelect = 'none';
    };

    const drag = (e) => {
        if (!isDragging) return;

        const newLeft = e.clientX - offsetX;
        const newTop = e.clientY - offsetY;

        const rect = element.getBoundingClientRect();
        const maxX = window.innerWidth - rect.width;
        const maxY = window.innerHeight - rect.height;

        // Hauptfenster Position aktualisieren
        const finalLeft = Math.min(Math.max(0, newLeft), maxX);
        const finalTop = Math.min(Math.max(0, newTop), maxY);
        
        element.style.left = finalLeft + 'px';
        element.style.top = finalTop + 'px';

        // Direkt die Sub-UIs aktualisieren
        if (wordsListDiv?.parentNode || merchantListDiv?.parentNode || document.getElementById('sidebarElementsDiv')) {
            const settingsRect = element.getBoundingClientRect();
            [
                wordsListDiv,
                merchantListDiv,
                document.getElementById('sidebarElementsDiv'),
                document.getElementById('wordSuggestionList')
            ].forEach(ui => {
                if (ui?.parentNode) {
                    ui.style.position = 'fixed';
                    ui.style.top = `${settingsRect.top}px`;
                    ui.style.left = `${settingsRect.right + 10}px`;
                }
            });
        }
    };

    const stopDrag = () => {
        if (!isDragging) return;

        isDragging = false;
        document.body.style.userSelect = '';

        // Position speichern
        const rect = element.getBoundingClientRect();
        GM_setValue('mdmSettingsPos', JSON.stringify({
            left: rect.left,
            top: rect.top,
            wasMoved: true
        }));

        // Finale Position der Sub-UIs aktualisieren
        const settingsRect = element.getBoundingClientRect();
        [
            wordsListDiv,
            merchantListDiv,
            document.getElementById('sidebarElementsDiv'),
            document.getElementById('wordSuggestionList')
        ].forEach(ui => {
            if (ui?.parentNode) {
                ui.style.position = 'fixed';
                ui.style.top = `${settingsRect.top}px`;
                ui.style.left = `${settingsRect.right + 10}px`;
            }
        });
    };

    header.addEventListener('mousedown', startDrag);
    document.addEventListener('mousemove', drag);
    document.addEventListener('mouseup', stopDrag);

    // Gespeicherte Position wiederherstellen
    const savedPos = GM_getValue('mdmSettingsPos');
    if (savedPos) {
        try {
            const pos = JSON.parse(savedPos);
            if (pos.wasMoved) {
                wasMoved = true;
                element.style.left = pos.left + 'px';
                element.style.top = pos.top + 'px';
                element.style.transform = 'none';
                element.style.right = 'auto';
                element.style.bottom = 'auto';

                // Auch die Sub-UIs an die gespeicherte Position anpassen
                const settingsRect = element.getBoundingClientRect();
                [
                    wordsListDiv,
                    merchantListDiv,
                    document.getElementById('sidebarElementsDiv'),
                    document.getElementById('wordSuggestionList')
                ].forEach(ui => {
                    if (ui?.parentNode) {
                        ui.style.position = 'fixed';
                        ui.style.top = `${settingsRect.top}px`;
                        ui.style.left = `${settingsRect.right + 10}px`;
                    }
                });
            }
        } catch (e) {
            console.error('Error restoring settings position:', e);
        }
    }

    // Cleanup-Funktion zurückgeben
    return () => {
        header.removeEventListener('mousedown', startDrag);
        document.removeEventListener('mousemove', drag);
        document.removeEventListener('mouseup', stopDrag);
    };
}

function createSidebarElementsUI() {
    const colors = getThemeColors();
    const isMobile = window.innerWidth <= 768;

    const sidebarElementsDiv = document.createElement('div');
    sidebarElementsDiv.id = 'sidebarElementsDiv';
    sidebarElementsDiv.style.cssText = `
        ${getSubUIPosition()}
        padding: 15px;
        background-color: ${colors.background};
        border: 1px solid ${colors.border};
        border-radius: 5px;
        width: 300px;
        color: ${colors.text};
        z-index: 10003;
        box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    `;

    // Gerätetyp erkennen für angepasste Bezeichnungen
    const sidebarText = isMobile ? "Feed" : "Seitenleiste";
    let elementsHTML = '';

    Object.entries({
        banner: {
            title: "Banner",
            keys: ['headerBanners', 'feedBanners', 'voteBox']
        },
        widgets: {
            title: isMobile ? "Feed-Elemente" : "Widgets",
            keys: Object.keys(SIDEBAR_ELEMENTS.widgets) // Ändere dies um alle Widget-Keys einzuschließen
        }
    }).forEach(([catKey, category]) => {
        elementsHTML += `
            <div class="sidebar-category" style="margin-bottom: 15px;">
                <h4 style="margin: 0 0 8px 0; font-size: 14px;">${category.title}</h4>
                <div style="display: flex; flex-direction: column; gap: 6px;">
        `;

        category.keys.forEach(key => {
            // Prüfe ob es ein Banner oder Widget Element ist
            const element = SIDEBAR_ELEMENTS[catKey === 'banner' ? 'banners' : 'widgets'][key];
            if (!element) return;

            const isActive = !element.hidden;

            elementsHTML += `
                <div class="sidebar-element" style="
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    padding: 8px;
                    background: ${colors.itemBg};
                    border: 1px solid ${colors.border};
                    border-radius: 3px;
                ">
                    <span style="font-size: 14px;">${element.name}</span>
                    <button class="toggle-sidebar-element" data-key="${key}" data-type="${catKey}" style="
                        background: none;
                        border: none;
                        cursor: pointer;
                        font-size: 16px;
                        color: ${colors.text};
                        width: 30px;
                        height: 30px;
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        padding: 0;
                    ">
                        <i class="fas ${isActive ? 'fa-eye' : 'fa-eye-slash'}"
                        aria-label="${isActive ? 'Element sichtbar' : 'Element versteckt'}"></i>
                    </button>
                </div>
            `;
        });

        elementsHTML += `
                </div>
            </div>
        `;
    });

    sidebarElementsDiv.innerHTML = `
        <div style="margin-bottom: 15px;">
            ${elementsHTML}
        </div>
        <div style="
            display: flex;
            justify-content: center;
            margin-top: 20px;
        ">
            <button id="closeSidebarElementsButton" class="button button--type-secondary button--mode-default button--shape-circle" style="
                padding: 8px 16px;
                display: inline-block;
                width: auto;
                min-width: 100px;
                text-align: center;
                font-size: 14px;
            ">
                <span>Schließen</span>
            </button>
        </div>
    `;

    document.body.appendChild(sidebarElementsDiv);

    // Event-Listener für die Toggle-Buttons
    document.querySelectorAll('.toggle-sidebar-element').forEach(button => {
        button.addEventListener('click', (e) => {
            const key = button.dataset.key;
            const type = button.dataset.type;
            const elementGroup = type === 'banner' ? SIDEBAR_ELEMENTS.banners : SIDEBAR_ELEMENTS.widgets;

            if (!key || !elementGroup[key]) return;

            const element = elementGroup[key];
            const newState = !element.hidden;

            element.hidden = newState;
            GM_setValue(element.storageKey, newState);

            // Wende Sichtbarkeit auf DOM-Elemente an
            document.querySelectorAll(element.selector).forEach(el => {
                el.style.display = newState ? 'none' : '';
            });

            updateSidebarElementsUI();
            updateCustomBannerIcon();
        });
    });

    // Event-Listener für den Schließen-Button hinzufügen - nur dieses UI schließen
    document.getElementById('closeSidebarElementsButton').addEventListener('click', (e) => {
        e.stopPropagation(); // Verhindert Event-Bubbling
        const sidebarDiv = document.getElementById('sidebarElementsDiv');
        if (sidebarDiv) {
            sidebarDiv.remove();
        }
    });
}

// Togglen der Feed-Banner
function toggleFeedBanners(hide) {
    const feedBannerConfig = SIDEBAR_ELEMENTS.banners.feedBanners;
    if (!feedBannerConfig) return;

    // Speichere Status
    feedBannerConfig.hidden = hide;
    GM_setValue(feedBannerConfig.storageKey, hide);

    // Wende Sichtbarkeit auf alle Feed-Banner an
    document.querySelectorAll('[id^="customBannerList-id-"]').forEach(banner => {
        banner.style.display = hide ? 'none' : '';
    });

    // Update Icon im UI
    updateSidebarElementsUI();
    updateCustomBannerIcon();
}

// Accordion-Sektion erstellen
function createAccordionSection(title, iconName) {
    const section = document.createElement('div');
    section.className = 'accordion-section';
    const colors = getThemeColors();

    section.innerHTML = `
        <div class="accordion-header" style="
            display: flex;
            align-items: center;
            padding: 10px;
            cursor: pointer;
            user-select: none;
            background: ${colors.background};
            border-bottom: 1px solid ${colors.border};
            position: relative;
            z-index: 1;
        ">
            <i class="fas fa-${iconName}" style="margin-right: 10px;"></i>
            <span>${title}</span>
            <i class="fas fa-chevron-down" style="margin-left: auto; transition: transform 0.3s"></i>
        </div>
        <div class="accordion-content" style="
            display: none;
            padding: 10px;
            position: relative;
            z-index: 0;
            border-bottom: 1px solid ${colors.border};
        ">
            <div class="accordion-inner" style="
                display: flex;
                flex-direction: column;
                gap: 12px;
            ">
            </div>
        </div>
    `;


    // Hole Referenzen
    const header = section.querySelector('.accordion-header');
    const content = section.querySelector('.accordion-content');

    header.onclick = () => {
        // Schließe alle anderen Sektionen
        document.querySelectorAll('.accordion-section').forEach(otherSection => {
            if (otherSection !== section) {
                const otherContent = otherSection.querySelector('.accordion-content');
                const otherIcon = otherSection.querySelector('.fa-chevron-down');
                if (otherContent) {
                    otherContent.style.display = 'none';
                }
                if (otherIcon) {
                    otherIcon.style.transform = '';
                }
            }
        });

        // Öffne/Schließe aktuelle Sektion
        const isOpen = content.style.display === 'block';
        content.style.display = isOpen ? 'none' : 'block';
        header.querySelector('.fa-chevron-down').style.transform = isOpen ? '' : 'rotate(180deg)';
    };

    return {
        section,
        content: section.querySelector('.accordion-inner')
    };
}

// --- Filterlisten-Erstellung ---
// Händlerliste erstellen
function createMerchantListUI() {
    const colors = getThemeColors();
    merchantListDiv.style.cssText = `
        ${getSubUIPosition()}
        padding: 15px;
        background: ${colors.background};
        border: 1px solid ${colors.border};
        border-radius: 5px;
        width: 300px;
        color: ${colors.text};
    `;

    const currentMerchants = loadExcludeMerchants();

    const merchantListHTML = currentMerchants.map(merchant => `
        <div class="merchant-item" style="
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 5px;
            padding: 5px;
            background: ${colors.itemBg};
            color: ${colors.text};
            border: 1px solid ${colors.border};
            border-radius: 3px;">
            <span>${merchant.name}</span>
            <button class="delete-merchant" data-id="${merchant.id}" style="
                background: none;
                border: none;
                cursor: pointer;
                color: ${colors.text};">
                <i class="fas fa-times"></i>
            </button>
        </div>
    `).join('');

    merchantListDiv.innerHTML = `
        <h4 style="margin-bottom: 10px;">Ausgeblendete Händler (${currentMerchants.length})</h4>
        <input type="text" id="merchantSearch" placeholder="Händler suchen..."
            style="
                width: 100%;
                padding: 5px;
                margin-bottom: 10px;
                background: ${colors.inputBg};
                border: 1px solid ${colors.border};
                color: ${colors.text};
                border-radius: 3px;">
        <div style="margin-bottom: 15px;">
            <div id="merchantList" style="
                margin-bottom: 10px;
                height: 200px;
                overflow-y: auto;
                padding-right: 5px;
                min-height: 200px;">
                ${merchantListHTML}
            </div>
            <button id="clearMerchantListButton" style="
                width: 100%;
                padding: 5px 10px;
                background: ${colors.buttonBg};
                border: 1px solid ${colors.buttonBorder};
                color: ${colors.text};
                border-radius: 3px;
                cursor: pointer;
                margin-top: 10px;">
                <i class="fas fa-trash"></i> Alle Händler entfernen
            </button>
        </div>
        <div style="
            margin-top: 20px;
            display: flex;
            justify-content: center;
        ">
            <button id="closeMerchantListButton" class="button button--type-secondary button--mode-default button--shape-circle">
                <span>Schließen</span>
            </button>
        </div>
    `;

    // Add the div to the document body
    document.body.appendChild(merchantListDiv);
    setupClickOutsideHandler();

    // Nach dem Hinzufügen zum DOM den Button anpassen
    document.getElementById('closeMerchantListButton').style.cssText = `
        padding: 8px 16px;
        display: inline-block;
        width: auto;
        min-width: 100px;
        text-align: center;
    `;

    // Add search functionality
    const searchInput = document.getElementById('merchantSearch');
    searchInput.addEventListener('input', (e) => {
        const searchTerm = e.target.value.toLowerCase();
        let visibleCount = 0;
        // Hole aktuelle Händler statt die ursprüngliche Liste zu verwenden
        const currentMerchants = loadExcludeMerchants();
        const totalCount = currentMerchants.length;

        document.querySelectorAll('.merchant-item').forEach(item => {
            const merchantName = item.querySelector('span').textContent.toLowerCase();
            const isVisible = merchantName.includes(searchTerm);
            item.style.display = isVisible ? 'flex' : 'none';
            if (isVisible) visibleCount++;
        });

        // Update heading counter
        const heading = merchantListDiv.querySelector('h4');
        if (heading) {
            heading.textContent = searchTerm
                ? `Ausgeblendete Händler (${visibleCount}/${totalCount})`
                : `Ausgeblendete Händler (${totalCount})`;
        }
    });

    // Alle Händler entfernen Button
    document.getElementById('clearMerchantListButton').addEventListener('click', () => {
        if (confirm('Möchten Sie wirklich alle Händler aus der Liste entfernen?')) {
            saveExcludeMerchants([]);
            document.getElementById('merchantList').innerHTML = '';
            excludeMerchantIDs = [];
            processArticles();

            // Immediately update counter in heading
            const heading = merchantListDiv.querySelector('h4');
            if (heading) {
                heading.textContent = 'Ausgeblendete Händler (0)';
            }
        }
    });

    document.querySelectorAll('.delete-merchant').forEach(button => {

        button.addEventListener('click', function(e) {
            handleMerchantDelete(e);
        });
    });

    // Update close button handlers in createMerchantListUI
    document.getElementById('closeMerchantListButton').addEventListener('click', (e) => {
        e.stopPropagation(); // Prevent event bubbling
        closeActiveSubUI();
    });
}
// Wörterliste erstellen
function createExcludeWordsUI() {
    const colors = getThemeColors();
    wordsListDiv.style.cssText = `
        ${getSubUIPosition()}
        padding: 15px;
        background: ${colors.background};
        border: 1px solid ${colors.border};
        border-radius: 5px;
        width: 300px;
        color: ${colors.text};
    `;

    const currentWords = loadExcludeWords();

    const wordsListHTML = currentWords.map(word => `
        <div class="word-item" style="
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 5px;
            padding: 5px;
            background: ${colors.itemBg};
            color: ${colors.text};
            border: 1px solid ${colors.border};
            border-radius: 3px;">
            <span style="word-break: break-word;">${word}</span>
            <button class="delete-word" data-word="${word}" style="
                background: none;
                border: none;
                cursor: pointer;
                color: ${colors.text};">
                <i class="fas fa-times"></i>
            </button>
        </div>
    `).join('');

    wordsListDiv.innerHTML = `
        <h4 style="margin-bottom: 10px;">Ausgeblendete Wörter (${currentWords.length})</h4>
        <input type="text" id="wordSearch" placeholder="Wörter suchen..."
            style="
                width: 100%;
                padding: 5px;
                margin-bottom: 10px;
                background: ${colors.inputBg};
                border: 1px solid ${colors.border};
                color: ${colors.text};
                border-radius: 3px;">
        <div style="margin-bottom: 15px;">
            <div id="wordsList" style="
                margin-bottom: 10px;
                height: 200px;
                overflow-y: auto;
                padding-right: 5px;
                min-height: 200px;">
                ${wordsListHTML}
            </div>
            <button id="clearWordsListButton" style="
                width: 100%;
                padding: 5px 10px;
                background: ${colors.buttonBg};
                border: 1px solid ${colors.buttonBorder};
                color: ${colors.text};
                border-radius: 3px;
                cursor: pointer;
                margin-top: 10px;">
                <i class="fas fa-trash"></i> Alle Wörter entfernen
            </button>
        </div>
        <div style="
            margin-top: 20px;
            display: flex;
            justify-content: center;
        ">
            <button id="closeWordsListButton" class="button button--type-secondary button--mode-default button--shape-circle">
                <span>Schließen</span>
            </button>
        </div>
    `;

    // Add the div to the document body
    document.body.appendChild(wordsListDiv);
    setupClickOutsideHandler();

    // Nach dem Hinzufügen zum DOM den Button anpassen
    document.getElementById('closeWordsListButton').style.cssText = `
        padding: 8px 16px;
        display: inline-block;
        width: auto;
        min-width: 100px;
        text-align: center;
    `;

    // Add search functionality
    const searchInput = document.getElementById('wordSearch');
    searchInput.addEventListener('input', (e) => {
        const searchTerm = e.target.value.toLowerCase();
        let visibleCount = 0;
        // Hole aktuelle Wörter statt die ursprüngliche Liste zu verwenden
        const currentWords = loadExcludeWords();
        const totalCount = currentWords.length;

        document.querySelectorAll('.word-item').forEach(item => {
            const word = item.querySelector('span').textContent.toLowerCase();
            const isVisible = word.includes(searchTerm);
            item.style.display = isVisible ? 'flex' : 'none';
            if (isVisible) visibleCount++;
        });

        // Update heading counter
        const heading = wordsListDiv.querySelector('h4');
        if (heading) {
            heading.textContent = searchTerm
                ? `Ausgeblendete Wörter (${visibleCount}/${totalCount})`
                : `Ausgeblendete Wörter (${totalCount})`;
        }
    });

    // Alle Wörter entfernen Button
    document.getElementById('clearWordsListButton').addEventListener('click', () => {
        if (confirm('Möchten Sie wirklich alle Wörter aus der Liste entfernen?')) {
            saveExcludeWords([]);
            document.getElementById('wordsList').innerHTML = '';
            excludeWords = [];
            processArticles();

            // Immediately update counter in heading
            const heading = wordsListDiv.querySelector('h4');
            if (heading) {
                heading.textContent = 'Ausgeblendete Wörter (0)';
            }
        }
    });

    // Add delete handlers
    document.querySelectorAll('.delete-word').forEach(button => {

        button.addEventListener('click', function(e) {
            handleWordDelete(e);
        });
    });

    // Update close button handlers in createExcludeWordsUI
    document.getElementById('closeWordsListButton').addEventListener('click', (e) => {
        e.stopPropagation(); // Prevent event bubbling
        closeActiveSubUI();
    });
    // Before adding to DOM
    document.body.appendChild(wordsListDiv);

    setupClickOutsideHandler();
}

// === UI-Updates ===
// --- Listen & Status ---
// Liste der Händler/Wörter aktualisieren
function updateActiveLists() {
    const colors = getThemeColors();

    if (activeSubUI === 'merchant' && merchantListDiv) {
        const merchantList = document.getElementById('merchantList');
        if (merchantList) {
            const currentMerchants = loadExcludeMerchants();
            merchantList.innerHTML = currentMerchants.map(merchant => `
                <div class="merchant-item" style="
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    margin-bottom: 5px;
                    padding: 5px;
                    background: ${colors.itemBg};
                    color: ${colors.text};
                    border: 1px solid ${colors.border};
                    border-radius: 3px;">
                    <div style="display: flex; flex-direction: column;">
                        <span>${merchant.name}</span>
                        <span style="color: ${colors.text}; opacity: 0.7; font-size: 0.8em;">ID: ${merchant.id}</span>
                    </div>
                    <button class="delete-merchant" data-id="${merchant.id}" style="
                        background: none;
                        border: none;
                        cursor: pointer;
                        color: ${colors.text};">
                        <i class="fas fa-times"></i>
                    </button>
                </div>
            `).join('');

            // Event Listener neu hinzufügen
            document.querySelectorAll('.delete-merchant').forEach(button => {

                button.addEventListener('click', function(e) {
                    handleMerchantDelete(e);
                });
            });
        }
    } else if (activeSubUI === 'words' && wordsListDiv) {
        const wordsList = document.getElementById('wordsList');
        if (wordsList) {
            const currentWords = loadExcludeWords();
            wordsList.innerHTML = currentWords.map(word => `
                <div class="word-item" style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px; padding: 5px; background: #f0f0f0; border-radius: 3px;">
                    <span style="word-break: break-word;">${word}</span>
                    <button class="delete-word" data-word="${word}" style="background: none; border: none; cursor: pointer; color: #666;">
                        <i class="fas fa-times"></i>
                    </button>
                </div>
            `).join('');

            // Event Listener neu hinzufügen
            document.querySelectorAll('.delete-word').forEach(button => {
                button.addEventListener('click', handleWordDelete);
            });
        }
    }
}
function updateSuggestionList() {
    // Save scroll position if list exists
    const oldList = document.getElementById('wordSuggestionList');
    const scrollPosition = oldList?.scrollTop || 0;

    // Remove old list if exists
    if (oldList) oldList.remove();

    // Filter and check for words
    suggestedWords = suggestedWords.filter(word => !excludeWords.includes(word));
    if (!suggestedWords.length) return;

    const inputField = document.getElementById('newWordInput');
    const inputRect = inputField.getBoundingClientRect();
    const colors = getThemeColors();

    // Create suggestion list with fixed positioning
    const wordSuggestionList = document.createElement('div');
    wordSuggestionList.id = 'wordSuggestionList';
    wordSuggestionList.style.cssText = `
        position: fixed;
        top: ${inputRect.bottom}px;
        left: ${inputRect.left}px;
        width: ${inputRect.width}px;
        max-height: 200px;
        overflow-y: auto;
        background: ${colors.background};
        border: 1px solid ${colors.border};
        color: ${colors.text};
        border-radius: 3px;
        z-index: 1002;
        box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        display: block;
        -webkit-overflow-scrolling: touch; 
    `;

    // Add touch event handlers for mobile scrolling
    if (IS_TOUCH_DEVICE) {
        let touchStartY = 0;
        let scrollStartY = 0;

        wordSuggestionList.addEventListener('touchstart', (e) => {
            touchStartY = e.touches[0].pageY;
            scrollStartY = wordSuggestionList.scrollTop;
            // Verhindern dass der Touch-Event die Liste schließt
            e.stopPropagation();
        }, { passive: true });

        wordSuggestionList.addEventListener('touchmove', (e) => {
            const touchY = e.touches[0].pageY;
            const deltaY = touchStartY - touchY;
            wordSuggestionList.scrollTop = scrollStartY + deltaY;

            // Verhindern dass die Seite scrollt während in der Liste gescrollt wird
            if (wordSuggestionList.scrollHeight > wordSuggestionList.clientHeight) {
                const isAtTop = wordSuggestionList.scrollTop === 0;
                const isAtBottom = wordSuggestionList.scrollTop + wordSuggestionList.clientHeight >= wordSuggestionList.scrollHeight;

                if ((isAtTop && deltaY < 0) || (isAtBottom && deltaY > 0)) {
                    e.preventDefault();
                }
            }
        }, { passive: false });

        wordSuggestionList.addEventListener('touchend', (e) => {
            e.stopPropagation();
        }, { passive: true });
    }

    wordSuggestionList.innerHTML = suggestedWords
        .map(word => `
            <div class="word-suggestion-item" style="padding: 10px; border-bottom: 1px solid #eee; cursor: pointer; transition: background-color 0.2s;">
                ${word}
            </div>
        `).join('');

    document.body.appendChild(wordSuggestionList);
    wordSuggestionList.scrollTop = scrollPosition;

    // Add event listeners for items
    wordSuggestionList.querySelectorAll('.word-suggestion-item').forEach(item => {
        item.addEventListener('mouseenter', () => {
            item.style.backgroundColor = colors.itemBg;
        });
        item.addEventListener('mouseleave', () => {
            item.style.backgroundColor = colors.background;
        });
        item.addEventListener('click', handleWordSelection);
    });

    // Update position on scroll/resize
    const updatePosition = () => {
        const newRect = inputField.getBoundingClientRect();
        wordSuggestionList.style.top = `${newRect.bottom}px`;
        wordSuggestionList.style.left = `${newRect.left}px`;
    };

    window.addEventListener('scroll', updatePosition, true);
    window.addEventListener('resize', updatePosition);

    // Clean up event listeners when list is removed
    const cleanupListeners = () => {
        window.removeEventListener('scroll', updatePosition, true);
        window.removeEventListener('resize', updatePosition);
    };
}

// Share-Buttons Ein-/Ausblenden
function updateShareButtonsVisibility(hide) {
    const styleId = 'mdm-hide-share-buttons-style';
    let styleElement = document.getElementById(styleId);

    if (hide) {
        if (!styleElement) {
            styleElement = document.createElement('style');
            styleElement.id = styleId;
            styleElement.textContent = `
                button[data-t="shareBtn"] {
                    display: none !important;
                }
            `;
            document.head.appendChild(styleElement);
        }
    } else if (styleElement) {
        styleElement.remove();
    }
}
// Custom Banner Icon aktualisieren
function updateCustomBannerIcon() {
    // Suche das Icon-Element im DOM
    const iconElement = document.querySelector('#hideCustomBanners i');
    if (!iconElement) return;

    // Prüfe Status der individuellen Elemente
    const anyHidden = Object.values(SIDEBAR_ELEMENTS).some(element => element.hidden);
    const allHidden = Object.values(SIDEBAR_ELEMENTS).length > 0 &&
          Object.values(SIDEBAR_ELEMENTS).every(element => element.hidden);

    // Setze das Icon basierend auf dem Status
    if (allHidden) {
        // Wenn alle Elemente ausgeblendet sind, Auge durchgestrichen
        iconElement.className = 'fas fa-eye-slash';
        iconElement.setAttribute('aria-label', 'Custom Banner versteckt');
    } else if (anyHidden) {
        // Wenn einige Elemente ausgeblendet sind, Low-Vision Icon
        iconElement.className = 'fas fa-eye-low-vision';
        iconElement.setAttribute('aria-label', 'Einige Banner versteckt');
    } else {
        // Wenn alle Elemente sichtbar sind, normales Auge
        iconElement.className = 'fas fa-eye';
        iconElement.setAttribute('aria-label', 'Custom Banner sichtbar');
    }
}
// Sidebar-Elemente UI aktualisieren
function updateSidebarElementsUI() {

    const sidebarElementsDiv = document.getElementById('sidebarElementsDiv');
    if (!sidebarElementsDiv) return;

    document.querySelectorAll('.toggle-sidebar-element').forEach(button => {
        const key = button.dataset.key;
        const type = button.dataset.type;
        // Prüfe sowohl Banner als auch Widgets
        const elementGroup = type === 'banner' ? SIDEBAR_ELEMENTS.banners : SIDEBAR_ELEMENTS.widgets;

        if (!key || !elementGroup[key]) return;

        const element = elementGroup[key];
        const icon = button.querySelector('i');
        if (icon) {
            icon.className = `fas ${element.hidden ? 'fa-eye-slash' : 'fa-eye'}`;
            icon.setAttribute('aria-label', element.hidden ? 'Element versteckt' : 'Element sichtbar');
        }
    });

    Object.entries(SIDEBAR_ELEMENTS).forEach(([category, items]) => {
        Object.entries(items).forEach(([key, element]) => {
        });
    });

}

// === Event-Handler ===
// --- Click & Touch ---
// Klick-Handler außerhalb der UI
function setupClickOutsideHandler() {
    if (uiClickOutsideHandler) {
        document.removeEventListener('click', uiClickOutsideHandler);
    }

    uiClickOutsideHandler = (e) => {
        // Early exit for clicks on UI controls
        if (e.target.closest('.settings-button') ||
            e.target.closest('#showMerchantListButton') ||
            e.target.closest('#showWordsListButton') ||
            e.target.closest('#openSidebarElementsButton') ||
            e.target.closest('#closeSidebarElementsButton')) {
            return;
        }

        // Get current UI states
        const settingsOpen = settingsDiv?.parentNode;
        const merchantsOpen = merchantListDiv?.parentNode;
        const wordsOpen = wordsListDiv?.parentNode;
        const sidebarElementsOpen = document.getElementById('sidebarElementsDiv')?.parentNode;

        // Check if click was outside all UIs
        const clickedOutside = (!settingsOpen || !settingsDiv.contains(e.target)) &&
              (!merchantsOpen || !merchantListDiv.contains(e.target)) &&
              (!wordsOpen || !wordsListDiv.contains(e.target)) &&
              (!sidebarElementsOpen || !document.getElementById('sidebarElementsDiv').contains(e.target));

        if (clickedOutside) {
            cleanup();

            // Explicit cleanup of UI elements
            if (settingsDiv?.parentNode) settingsDiv.remove();
            if (merchantListDiv?.parentNode) merchantListDiv.remove();
            if (wordsListDiv?.parentNode) wordsListDiv.remove();

            // Sicherer Zugriff mit optionaler Verkettung
            const sidebarDiv = document.getElementById('sidebarElementsDiv');
            if (sidebarDiv?.parentNode) sidebarDiv.remove();

            // Reset states
            isSettingsOpen = false;
            activeSubUI = null;

            // Remove handler
            document.removeEventListener('click', uiClickOutsideHandler);
            uiClickOutsideHandler = null;
        }
    };

    // Add with delay to prevent immediate trigger
    setTimeout(() => {
        document.addEventListener('click', uiClickOutsideHandler);
    }, 100);
}
function createSuggestionClickHandler() {
    // Remove old handler if exists
    if (suggestionClickHandler) {
        document.removeEventListener('click', suggestionClickHandler);
    }

    suggestionClickHandler = (e) => {
        const list = document.getElementById('wordSuggestionList');
        const input = document.getElementById('newWordInput');

        if (!list?.contains(e.target) && !input?.contains(e.target)) {
            list?.remove();
        }
    };

    document.addEventListener('click', suggestionClickHandler);
    return suggestionClickHandler;
}
function handleWordSelection(e) {
    e.preventDefault();
    e.stopPropagation();

    const wordSuggestionList = document.getElementById('wordSuggestionList');
    const scrollPosition = wordSuggestionList.scrollTop; // Save scroll position

    const word = e.target.textContent.trim();
    const newWordInput = document.getElementById('newWordInput');
    const currentValue = newWordInput.value.trim();

    newWordInput.value = currentValue ? `${currentValue} ${word}` : word;
    suggestedWords = suggestedWords.filter(w => w !== word);

    updateSuggestionList();
    newWordInput.focus();

    // Restore scroll position after list update
    const updatedList = document.getElementById('wordSuggestionList');
    if (updatedList) {
        updatedList.scrollTop = scrollPosition;
    }
}
function setupScrollHandling() {
    let isScrollingUI = false;
    let lastActiveUI = null;
    let touchStartY = 0;

    // Hilfsfunktion zum Prüfen ob ein Element scrollbar ist
    const isScrollable = (element) => {
        return element.scrollHeight > element.clientHeight;
    };

    // Hilfsfunktion zum Prüfen ob ein Element am Anfang/Ende des Scrollbereichs ist
    const isAtScrollLimit = (element, delta) => {
        if (delta > 0) {
            return element.scrollTop + element.clientHeight >= element.scrollHeight - 1;
        } else {
            return element.scrollTop <= 0;
        }
    };

    function handleScroll(e) {
        // Prüfe ob der Mauszeiger über einem UI-Element ist
        const isOverUI = e.target.closest('#mdm-settings-popup, #merchantListDiv, #wordsListDiv, #wordSuggestionList, #sidebarElementsDiv') ||
              settingsDiv?.contains(e.target) ||
              merchantListDiv?.contains(e.target) ||
              wordsListDiv?.contains(e.target) ||
              document.getElementById('sidebarElementsDiv')?.contains(e.target);

        if (isOverUI) {
            // Verhindern des Standard-Scroll-Verhaltens (Website-Scrolling)
            e.preventDefault();

            // Finde das scrollbare übergeordnete Element
            const scrollableContainer = e.target.closest('#mdm-settings-content, #merchantList, #wordsList, #wordSuggestionList, #sidebarElementsDiv');

            if (scrollableContainer && isScrollable(scrollableContainer)) {
                // Manuelles Scrollen des Containers implementieren
                const deltaY = e.deltaY || e.detail || e.wheelDelta;
                const scrollAmount = deltaY > 0 ? 40 : -40; // Scroll-Schrittgröße

                // Scrolle den Container
                scrollableContainer.scrollTop += scrollAmount;
            }

            // Event-Propagation stoppen
            e.stopPropagation();
            return false;
        }
    }

    // Event-Listener für das Mausrad mit passiver Option auf false (damit preventDefault funktioniert)
    document.addEventListener('wheel', handleScroll, { passive: false });

    function handleTouchStart(e) {
        const touch = e.touches[0];
        touchStartY = touch.clientY;

        const uiElements = [
            settingsDiv,
            merchantListDiv,
            wordsListDiv,
            document.getElementById('wordSuggestionList'),
            document.getElementById('sidebarElementsDiv')
        ];

        isScrollingUI = uiElements.some(el => {
            if (!el?.parentNode) return false;
            const rect = el.getBoundingClientRect();
            return touch.clientX >= rect.left &&
                touch.clientX <= rect.right &&
                touch.clientY >= rect.top &&
                touch.clientY <= rect.bottom;
        });
    }

    function handleTouchMove(e) {
        if (!isScrollingUI) return;

        const touch = e.touches[0];
        const scrollableElement = e.target.closest('#mdm-settings-content, #merchantList, #wordsList, #sidebarElementsDiv');

        if (scrollableElement && isScrollable(scrollableElement)) {
            const deltaY = touchStartY - touch.clientY;

            // Immer preventDefault aufrufen, um Seiten-Scrolling zu verhindern
            e.preventDefault();

            // Scrollen des UI-Elements
            scrollableElement.scrollTop += deltaY;
        } else {
            // Blockiere Scrollen außerhalb der Listen
            e.preventDefault();
        }

        touchStartY = touch.clientY;
    }

    function handleMouseEnter() {
        isScrollingUI = true;
        lastActiveUI = this;
    }

    function handleMouseLeave() {
        isScrollingUI = false;
        lastActiveUI = null;
    }

    function setupUIElement(element) {
        if (!element?.parentNode) return;

        element.addEventListener('mouseenter', handleMouseEnter);
        element.addEventListener('mouseleave', handleMouseLeave);
    }

    function setupAllElements() {
        // Füge auch sidebarElementsDiv zu den zu überwachenden Elementen hinzu
        [
            settingsDiv,
            merchantListDiv,
            wordsListDiv,
            document.getElementById('wordSuggestionList'),
            document.getElementById('sidebarElementsDiv')
        ].forEach(setupUIElement);
    }

    // Initial Setup
    setupAllElements();

    // Event Listener
    if (IS_TOUCH_DEVICE) {
        document.addEventListener('touchstart', handleTouchStart, { passive: true });
        document.addEventListener('touchmove', handleTouchMove, { passive: false });
    }

    // MutationObserver für dynamisch hinzugefügte UIs
    const observer = new MutationObserver(mutations => {
        mutations.forEach(mutation => {
            if (mutation.addedNodes.length) {
                // Prüfe auf neu hinzugefügtes Seitenleisten-UI
                const addedSidebarUI = Array.from(mutation.addedNodes).find(
                    node => node.id === 'sidebarElementsDiv'
                );
                if (addedSidebarUI) {
                    setupUIElement(addedSidebarUI);
                }
            }
        });
        setupAllElements();
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true
    });

    // Cleanup-Funktion
    return () => {
        if (IS_TOUCH_DEVICE) {
            document.removeEventListener('touchstart', handleTouchStart);
            document.removeEventListener('touchmove', handleTouchMove);
        }
        document.removeEventListener('wheel', handleScroll);
        [
            settingsDiv,
            merchantListDiv,
            wordsListDiv,
            document.getElementById('wordSuggestionList'),
            document.getElementById('sidebarElementsDiv')
        ].forEach(el => {
            if (el?.parentNode) {
                el.removeEventListener('mouseenter', handleMouseEnter);
                el.removeEventListener('mouseleave', handleMouseLeave);
            }
        });
        observer.disconnect();
    };
}

// --- Delete-Operationen ---
function handleWordDelete(e) {
    e.preventDefault();
    e.stopPropagation();

    const deleteButton = e.target.closest('.delete-word');
    if (!deleteButton) return;

    const wordToDelete = deleteButton.dataset.word;
    const wordItem = deleteButton.closest('.word-item');

    // Update excludeWords array
    excludeWords = excludeWords.filter(word => word !== wordToDelete);
    saveExcludeWords(excludeWords);

    // Get search state and counts
    const searchInput = document.getElementById('wordSearch');
    const searchTerm = searchInput?.value.trim().toLowerCase();
    const totalItems = document.querySelectorAll('.word-item').length;

    // Calculate visible items for search
    let visibleCount = 0;
    if (searchTerm) {
        const visibleItems = Array.from(document.querySelectorAll('.word-item')).filter(item => {
            const itemWord = item.querySelector('span').textContent.toLowerCase();
            const isVisible = itemWord.includes(searchTerm) && itemWord !== wordToDelete.toLowerCase();
            return isVisible;
        });
        visibleCount = visibleItems.length;
    }

    // Remove item and update UI
    wordItem.remove();
    processArticles();

    // Update counter in heading
    const heading = wordsListDiv.querySelector('h4');
    if (heading) {
        const newTotal = totalItems - 1;
        heading.textContent = searchTerm
            ? `Ausgeblendete Wörter (${visibleCount}/${newTotal})`
            : `Ausgeblendete Wörter (${newTotal})`;
    }
}
// Händler-Löschung Handler
function handleMerchantDelete(e) {
    e.preventDefault();
    e.stopPropagation();

    const deleteButton = e.target.closest('.delete-merchant');
    if (!deleteButton) return;

    const idToDelete = deleteButton.dataset.id;
    const merchantItem = deleteButton.closest('.merchant-item');

    // Update merchants array
    const merchantsData = loadExcludeMerchants();
    const updatedMerchants = merchantsData.filter(m => m.id !== idToDelete);
    saveExcludeMerchants(updatedMerchants);

    // Get search state and counts
    const searchInput = document.getElementById('merchantSearch');
    const searchTerm = searchInput?.value.trim().toLowerCase();
    const totalItems = document.querySelectorAll('.merchant-item').length;

    // Calculate visible items for search
    let visibleCount = 0;
    if (searchTerm) {
        const visibleItems = Array.from(document.querySelectorAll('.merchant-item')).filter(item => {
            const merchantName = item.querySelector('span').textContent.toLowerCase();
            const isVisible = merchantName.includes(searchTerm) &&
                  item.querySelector('.delete-merchant').dataset.id !== idToDelete;
            return isVisible;
        });
        visibleCount = visibleItems.length;
    }

    // Remove item and update UI
    merchantItem.remove();
    processArticles();

    // Update counter in heading
    const heading = merchantListDiv.querySelector('h4');
    if (heading) {
        const newTotal = totalItems - 1;
        heading.textContent = searchTerm
            ? `Ausgeblendete Händler (${visibleCount}/${newTotal})`
            : `Ausgeblendete Händler (${newTotal})`;
    }
}

// === Layout & UI-Hilfen ===
// Sub-UI Position berechnen
function getSubUIPosition() {
    const settingsRect = settingsDiv?.getBoundingClientRect();
    
    if (!settingsRect) return '';

    if (IS_TOUCH_DEVICE) {
        return `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            z-index: 10002;
        `;
    } else {
        const gap = 10;
        return `
            position: fixed;
            top: ${settingsRect.top}px;
            left: ${settingsRect.right + gap}px;
            z-index: 10002;
        `;
    }
}

// Funktion zum Aktualisieren der Sub-UI Positionen
function updateSubUIPositions() {
    // Skip position updates on mobile
    if (IS_TOUCH_DEVICE) return;

    // Settings-UI Position ermitteln
    const settingsDiv = document.getElementById('mdm-settings-popup') || document.querySelector('[id^="mdm-settings"]');
    if (!settingsDiv) return;

    const settingsRect = settingsDiv.getBoundingClientRect();
    const subUIs = [
        document.getElementById('wordsListDiv'),
        document.getElementById('merchantListDiv'),
        document.getElementById('sidebarElementsDiv')
    ];

    // Aktualisiere Position für jedes vorhandene Sub-UI
    subUIs.forEach(ui => {
        if (ui?.parentNode) {
            ui.style.position = 'fixed';
            ui.style.top = `${settingsRect.top}px`;
            ui.style.left = `${settingsRect.right + 10}px`; // 10px Abstand
            ui.style.zIndex = '10002';
        }
    });
}

// Händler zur Liste hinzufügen
function addMerchantToList(merchant, merchantList) {
    const div = document.createElement('div');
    div.className = 'merchant-item';
    div.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px; padding: 5px; background: #f0f0f0; border-radius: 3px;';
    div.innerHTML = `
        <span style="font-weight: bold;">${merchant.name}</span>
        <button class="delete-merchant" data-id="${merchant.id}" style="background: none; border: none; cursor: pointer; color: #666;">
            <i class="fas fa-times"></i>
        </button>
    `;

    // Insert at beginning of list
    merchantList.insertBefore(div, merchantList.firstChild);
}

// Helper function to manage Sub-UI states
function switchSubUI(newUI) {
    // If trying to open the same UI that's already active, close it
    if (activeSubUI === newUI) {
        closeActiveSubUI();
        return false;
    }

    // Close any active Sub-UI first
    if (activeSubUI) {
        closeActiveSubUI();
    }

    // Set new active UI
    activeSubUI = newUI;

    // Update button texts
    const merchantButton = document.getElementById('showMerchantListButton');
    const wordsButton = document.getElementById('showWordsListButton');
    
    if (merchantButton) {
        merchantButton.innerHTML = activeSubUI === 'merchant' 
            ? '<i class="fas fa-times"></i> Händlerfilter schließen'
            : '<i class="fas fa-store"></i> Händlerfilter verwalten';
    }
    
    if (wordsButton) {
        wordsButton.innerHTML = activeSubUI === 'words'
            ? '<i class="fas fa-times"></i> Wortfilter schließen'
            : '<i class="fas fa-list"></i> Wortfilter verwalten';
    }

    return true;
}

function closeActiveSubUI() {
    if (activeSubUI === 'merchant') {
        merchantListDiv?.remove();
    } else if (activeSubUI === 'words') {
        wordsListDiv?.remove();
    } else if (activeSubUI === 'sidebar') {
        document.getElementById('sidebarElementsDiv')?.remove();
    }

    // Reset button texts
    const merchantButton = document.getElementById('showMerchantListButton');
    const wordsButton = document.getElementById('showWordsListButton');
    
    if (merchantButton) {
        merchantButton.innerHTML = '<i class="fas fa-store"></i> Händlerfilter verwalten';
        merchantButton.removeAttribute('data-processing');
    }
    
    if (wordsButton) {
        wordsButton.innerHTML = '<i class="fas fa-list"></i> Wortfilter verwalten';
    }

    activeSubUI = null;
}

//#endregion





//#region --- 5. Deal-Verarbeitung ---
// ===== Hauptfunktionen =====
// Artikel verarbeiten und filtern
function processArticles() {
    // Am Anfang der Funktion den aktuellen Status aus Storage laden
    window.hideCustomBanners = GM_getValue('hideCustomBanners', false);
    const processedDeals = new Set();
    const articles = document.querySelectorAll('article.thread--deal, article.thread--voucher');
    let hiddenCount = 0;

    articles.forEach(article => {
        // Debug: Test if shouldExcludeArticle is being called
        const shouldExclude = shouldExcludeArticle(article);

        if (shouldExclude) {
            // FIX: Sicherstellen, dass die Anzeige wirklich auf 'none' gesetzt wird
            article.style.display = 'none';
            article.setAttribute('data-hidden-by-mydealz-manager', 'true'); // Markieren für Debug-Zwecke
            hiddenCount++;
        } else {
            // Sicherstellen, dass der Artikel sichtbar ist
            article.style.display = '';
            article.removeAttribute('data-hidden-by-mydealz-manager');
        }
    });

    document.querySelectorAll('article.thread--type-list').forEach(deal => {
        // Korrigierter Selektor für die Temperatur
        const tempElement = deal.querySelector('.cept-vote-temp span');
        const temperatureText = tempElement ? tempElement.textContent.trim() : null;

        // Extrahiere nur die Zahl aus dem Text
        const temperatureMatch = temperatureText ? temperatureText.match(/([-+]?\d+)°/) : null;
        const temperature = temperatureMatch ? parseInt(temperatureMatch[1]) : null;

        const isCold = temperature !== null && temperature < 0;

        // Markiere das Element für bessere Sichtbarkeit im Debug
        deal.dataset.cold = isCold ? 'true' : 'false';

        if (hideColdDeals && isCold) {
            deal.style.display = 'none';
        } else {
            deal.style.display = ''; // Reset display
        }
    });

    // Bestehende Deal-Verarbeitung
    const deals = document.querySelectorAll('article.thread--deal, article.thread--voucher');
    deals.forEach(deal => {
        const dealId = deal.getAttribute('id');

        // Skip wenn bereits verarbeitet
        if (processedDeals.has(dealId)) return;
        processedDeals.add(dealId);

        if (hiddenDeals.includes(dealId)) {
            hideDeal(deal);
            return;
        }

        if (shouldExcludeArticle(deal)) {
            hideDeal(deal);
            return;
        }

        deal.style.display = 'block';
        deal.style.opacity = '1';

        // Custom Banner Handling
        if (window.hideCustomBanners) {
            Object.entries(SIDEBAR_ELEMENTS).forEach(([category, items]) => {
                Object.entries(items).forEach(([key, element]) => {
                    const elements = document.querySelectorAll(element.selector);
                    elements.forEach(el => {
                        const oldDisplay = el.style.display;
                        el.style.display = element.hidden ? 'none' : '';
                    });
                });
            });
        }

        // Händlername im Titel
        if (window.hideMatchingMerchantNames) {
            const titleElement = deal.querySelector('.thread-title');
            const merchantLink = deal.querySelector('a[data-t="merchantLink"]');

            if (titleElement && merchantLink) {
                const merchantName = merchantLink.textContent.trim();
                const titleLink = titleElement.querySelector('a');

                if (titleLink) {
                    // Speichere ursprünglichen Titel falls noch nicht geschehen
                    if (!ORIGINAL_TITLES.has(dealId)) {
                        ORIGINAL_TITLES.set(dealId, titleLink.textContent);
                    }

                    const originalTitle = ORIGINAL_TITLES.get(dealId) || titleLink.textContent;
                    const newTitle = removeMerchantNameFromTitle(originalTitle, merchantName);
                    titleLink.textContent = newTitle;
                }
            }
        } else {
            // Originaltitel wiederherstellen falls vorhanden
            const titleLink = deal.querySelector('.thread-title a');
            const dealId = deal.getAttribute('id');

            if (titleLink && ORIGINAL_TITLES.has(dealId)) {
                titleLink.textContent = ORIGINAL_TITLES.get(dealId);
            }
        }
    });

    // Sortierungsspeicher verarbeiten
    processSortRemembering();

}

// ===== Filterlogik =====
// Ausschlussprüfung für Artikel
function shouldExcludeArticle(article) {
    const titleElement = article.querySelector('.thread-title');
    if (!titleElement) return false;

    // 2. Quick checks (temperature & price)
    // Temperature check
    if (hideColdDeals) {
        const tempElement = article.querySelector('.cept-vote-temp .overflow--wrap-off');
        if (tempElement) {
            const temp = parseInt(tempElement.textContent);
            if (!isNaN(temp) && temp < 0) return true;
        }
    }

    const dealId = article.getAttribute('id');

    // Price check
    if (maxPrice > 0) {
        const priceSelectors = ['.thread-price', '.text--color-greyShade'];

        for (const selector of priceSelectors) {
            const priceElement = article.querySelector(selector);
            if (priceElement) {
                const priceText = priceElement.textContent.trim();

                // Ignore percentage discounts
                if (priceText.includes('%')) {
                    continue;
                }

                // Ignore negative values (e.g., "-20€")
                if (priceText.startsWith('-')) {
                    continue;
                }

                // Check if the text contains a price in € format
                if (!priceText.includes('€')) {
                    continue;
                }

                // Extract numeric price - handle European format (47.170,00€)
                const euroFormatMatch = priceText.match(/([\d.,]+)\s*€/);
                if (euroFormatMatch) {
                    let extractedPrice = euroFormatMatch[1];

                    // Remove all dots first (thousand separators)
                    extractedPrice = extractedPrice.replace(/\./g, '');
                    // Then replace comma with dot for decimal
                    extractedPrice = extractedPrice.replace(',', '.');

                    // Hier ist die wichtige Änderung: const hinzufügen
                    const priceValue = parseFloat(extractedPrice);

                    if (!isNaN(priceValue) && priceValue > maxPrice) {
                        return true;
                    }
                }
            }
        }
    }

    // 3. Complex checks
    // Get title text
    const rawTitle = titleElement.querySelector('a')?.getAttribute('title') || titleElement.innerText;

    // Hilfsfunktion für ß zu ss und ue zu ü Konvertierung
    function normalizeGerman(text) {
        return text.toLowerCase()
            .replace(/ß/g, 'ss')
            .replace(/ue/g, 'ü');
    }

    // Normalisiere den Titel
    const processedTitle = normalizeGerman(rawTitle);

    // Check excludeWords
    if (excludeWords.some(word => {
        const searchTerm = normalizeGerman(word);
        const lowerTitle = normalizeGerman(processedTitle);

        // Handle words in brackets like [CB]
        if (searchTerm.startsWith('[') && searchTerm.endsWith(']')) {
            const match = lowerTitle.includes(searchTerm);
            return match;
        }

        // Handle words with special characters (+)
        if (searchTerm.includes('+')) {
            const match = lowerTitle.includes(searchTerm);
            return match;
        }

        // Handle multi-word phrases
        if (searchTerm.includes(' ') || searchTerm.includes('-')) {
            // Keine Variationen mehr erzeugen - nur exakte Matches erlauben
            const variations = [searchTerm];
            const uniqueVariations = [...new Set(variations)];

            return uniqueVariations.some(variant => {
                if (variant.includes(' ')) {
                    const words = variant.split(' ').filter(w => w.length > 0);
                    const firstWord = words[0];
                    const firstWordBoundaryRegex = new RegExp(`\\b${firstWord}\\b`, 'i');
                    if (!firstWordBoundaryRegex.test(lowerTitle)) {
                        return false;
                    }

                    // ZUSÄTZLICHE PRÜFUNG: Wenn der Suchbegriff eine exakte Teilmenge des Titels ist
                    const spaceJoinedSearchTerm = words.join(' ');
                    if (lowerTitle.includes(spaceJoinedSearchTerm)) {
                        return true;
                    }

                    // Wenn keine exakte Übereinstimmung gefunden wurde, ist es kein Match
                    return false;
                }

                // For hyphenated variations, ensure exact match with proper boundaries
                if (variant.includes('-')) {
                    // Exact hyphenated match required
                    const escapedVariant = variant.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
                    const regex = new RegExp(`\\b${escapedVariant}\\b`, 'i');
                    return regex.test(lowerTitle);
                }

                return false;
            });
        }

        // Für einzelne Wörter: Einfache Wortgrenzen-Prüfung
        const escapedTerm = searchTerm.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
        const regex = new RegExp(`\\b${escapedTerm}\\b`, 'i');
        return regex.test(lowerTitle);
    })) return true;

    // Merchant check
    const merchantLink = article.querySelector('a[href*="merchant-id="]');
    if (merchantLink) {
        const merchantIDMatch = merchantLink.getAttribute('href').match(/merchant-id=(\d+)/);
        if (merchantIDMatch && excludeMerchantIDs.includes(merchantIDMatch[1])) {
            return true;
        }
    }

    return false;
}

// ===== Deal-Management =====
// Deal ausblenden
function hideDeal(deal) {
    deal.style.cssText = 'display: none !important';
    deal.setAttribute('data-hidden-by-mydealz-manager', 'true');
}

// Letzten versteckten Deal speichern
function saveLastHiddenDeal() {
    GM_setValue('lastHiddenDeal', lastHiddenDeal);
    localStorage.setItem('lastHiddenDeal', JSON.stringify(lastHiddenDeal));
}

// Funktion zur Verarbeitung der Sortierung
function processSortRemembering() {
    // Wenn Feature deaktiviert ist, lösche gespeicherte Sortierung
    // und lass mydealz sein Standard-Verhalten nutzen
    if (!window.rememberSort) {
        // Prüfen, ob eine gespeicherte Sortierung existiert und entfernen
        if (localStorage.getItem(PREFERRED_SORT_KEY)) {
            localStorage.removeItem(PREFERRED_SORT_KEY);
            if (DEBUG) console.log('[MDM Sort] Gespeicherte Sortierung gelöscht (Feature deaktiviert)');
        }
        return;
    }

    // Prüfen, ob wir auf einer Suchseite sind
    if (window.location.pathname.includes('/search')) {
        // Parameter aus URL auslesen
        const params = new URLSearchParams(window.location.search);
        const currentSort = params.get('sortBy');

        // Wenn eine Sortierung vorhanden ist, speichern
        if (currentSort) {
            localStorage.setItem(PREFERRED_SORT_KEY, currentSort);
            if (DEBUG) console.log('[MDM Sort] Sortierung gespeichert: ' + currentSort);
        } else {
            // Wenn keine Sortierung gesetzt ist, aber eine gespeicherte existiert
            const savedSort = localStorage.getItem(PREFERRED_SORT_KEY);

            if (savedSort && !window.location.href.includes('sortBy=')) {
                // Neue URL mit der gespeicherten Sortierung erstellen
                let newUrl = window.location.href;
                const separator = newUrl.includes('?') ? '&' : '?';
                newUrl += separator + 'sortBy=' + savedSort;

                // Umleitung zur neuen URL mit kleiner Verzögerung
                if (DEBUG) console.log('[MDM Sort] Wende Sortierung an: ' + savedSort);
                setTimeout(() => {
                    window.location.href = newUrl;
                }, 100);
            }
        }
    }

    // Suchformulare abfangen und anpassen
    const searchForms = document.querySelectorAll('form[action*="/search"]');
    searchForms.forEach(form => {
        // Prüfen, ob das Formular bereits verarbeitet wurde
        if (form.dataset.sortingModified === 'true') return;

        // Markieren, dass das Formular verarbeitet wurde
        form.dataset.sortingModified = 'true';

        // Event-Listener für das Absenden des Formulars hinzufügen
        form.addEventListener('submit', function(e) {
            // Nur fortfahren, wenn Feature aktiviert ist
            if (!window.rememberSort) return;

            const savedSort = localStorage.getItem(PREFERRED_SORT_KEY);

            if (savedSort) {
                if (DEBUG) console.log('[MDM Sort] Füge Sortierung zur Suchanfrage hinzu: ' + savedSort);

                // Prüfen, ob bereits ein sortBy-Feld vorhanden ist
                let sortByInput = form.querySelector('input[name="sortBy"]');

                // Wenn kein sortBy-Feld existiert, eines erstellen
                if (!sortByInput) {
                    sortByInput = document.createElement('input');
                    sortByInput.type = 'hidden';
                    sortByInput.name = 'sortBy';
                    form.appendChild(sortByInput);
                }

                // Sortierung setzen
                sortByInput.value = savedSort;
            }
        });
    });
}

//#endregion





//#region --- 6. Initialisierung und Setup ---
function init() {
    // ===== 1. Grundeinstellungen und gespeicherte Daten laden =====
    // --- Grundeinstellungen ---
    hideCustomBanners = GM_getValue('hideCustomBanners', false);
    syncStorage();
    excludeWords = loadExcludeWords();
    loadSettings();

    // --- Deal-Listen ---
    hiddenDeals = GM_getValue('hiddenDeals', []);
    recentHiddenDeals = GM_getValue('recentHiddenDeals', []);

    // --- Letzter versteckter Deal ---
    lastHiddenDeal = GM_getValue('lastHiddenDeal', null);
    lastHiddenDealShown = GM_getValue(LAST_HIDDEN_DEAL_SHOWN, false);

    // Automatische Markierung als "angezeigt" wenn kein Deal vorhanden
    if (!lastHiddenDeal) {
        lastHiddenDealShown = true;
        GM_setValue(LAST_HIDDEN_DEAL_SHOWN, true);
    }

    // --- Sortierung merken ---
    window.rememberSort = GM_getValue('rememberSort', true);
    processSortRemembering();

    // ===== 2. Filter-Einstellungen =====
    // --- Preisfilter ---
    maxPrice = parseFloat(localStorage.getItem(MAX_PRICE_KEY)) || 0;

    // --- Kalte Deals ---
    hideColdDeals = localStorage.getItem(HIDE_COLD_DEALS_KEY) === 'true';

    // ===== 3. Feature-Flags und UI-Status =====
    // --- Banner und Widgets ---
    window.hideCustomBanners = hideCustomBanners;
    updateCustomBannerIcon();

    // --- Share Buttons ---
    window.hideShareButtons = GM_getValue('hideShareButtons', false);
    updateShareButtonsVisibility(window.hideShareButtons);

    // --- Händlernamen ---
    window.hideMatchingMerchantNames = GM_getValue('hideMatchingMerchantNames', false);

    // ===== 5. System-Initialisierung =====

    // --- UI ---
    initializeUI();
    initObserver();

}

//#endregion





//#region --- 7. Backup und Wiederherstellung ---
// ===== Backup-Funktionen =====
// --- Datei-Erstellung ---
function createBackupFile(backup, deviceName) {
    const blob = new Blob([JSON.stringify(backup, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');

    // Neues Datumsformat
    const now = new Date();
    const timestamp = now.toISOString()
    .replace('T', '_') // T durch _ ersetzen
    .split('.')[0] // Millisekunden entfernen
    .replace(/:/g, '.') // : durch . ersetzen
    .replace(/-/g, '-'); // - behalten

    a.href = url;
    a.download = `mydealz_backup_${deviceName}_${timestamp}.json`;
    a.click();
    URL.revokeObjectURL(url);
}

// --- Backup-Prozess ---
function backupData() {
    try {
        // 1. Daten laden
        const currentWords = loadExcludeWords();
        const currentMerchants = loadExcludeMerchants();

        // 2. Backup-Objekt erstellen
        const backup = {
            excludeWords: currentWords,
            merchantsData: currentMerchants,
            maxPrice: maxPrice,
            hideColdDeals: hideColdDeals
        };

        // 3. Geräte-Erkennung
        let deviceType = "Desktop";
        if (IS_TOUCH_DEVICE) {
            // Überprüfe, ob es ein mobiles Gerät ist
            const userAgent = navigator.userAgent.toLowerCase();
            if (userAgent.includes('iphone') || userAgent.includes('ipad')) {
                deviceType = "iOS";
            } else if (userAgent.includes('android')) {
                deviceType = "Android";
            } else {
                deviceType = "Tablet/Touch";
            }
        }

        // 4. Gerätenamen-Verwaltung
        const DEVICE_NAME_KEY = 'mdm_device_name';
        const customDeviceName = localStorage.getItem(DEVICE_NAME_KEY) || GM_getValue(DEVICE_NAME_KEY, '');

        // 5. Backup-Erstellung
        if (!customDeviceName) {
            // Neuen Gerätenamen abfragen
            const newName = prompt(
                "Wie möchtest du dieses Gerät nennen?\n" +
                "Dies hilft dir, Backups von verschiedenen Geräten zu unterscheiden.",
                deviceType
            );

            if (newName !== null) {
                const deviceName = newName.trim() || deviceType;
                // In beiden Speichern ablegen
                localStorage.setItem(DEVICE_NAME_KEY, deviceName);
                GM_setValue(DEVICE_NAME_KEY, deviceName);

                // Mit dem neuen Namen das Backup erstellen
                createBackupFile(backup, deviceName);
            }
        } else {
            // Mit dem vorhandenen Namen das Backup erstellen
            createBackupFile(backup, customDeviceName);
        }
    } catch (error) {
        console.error('Backup error:', error);
        alert('Fehler beim Erstellen des Backups: ' + error.message);
    }
}

// ===== Wiederherstellungs-Funktionen =====
// --- Daten-Wiederherstellung ---
function restoreData(event) {
    // 1. Datei-Validierung
    const file = event.target.files[0];
    if (!file || file.type !== 'application/json') {
        console.error('Invalid file:', file);
        alert('Bitte wählen Sie eine gültige JSON-Datei aus.');
        return;
    }

    // 2. Datei-Verarbeitung
    const reader = new FileReader();
    reader.onload = function(e) {
        try {
            // 3. Daten-Parsing
            const restoredData = JSON.parse(e.target.result);

            // 4. Aktuelle Daten laden
            const currentWords = new Set(loadExcludeWords());
            const currentMerchants = new Map(
                loadExcludeMerchants().map(m => [m.id, m])
            );

            // 5. Daten zusammenführen
            // --- Wörter ---
            restoredData.excludeWords.forEach(word => currentWords.add(word));
            const mergedWords = Array.from(currentWords);

            // --- Händler ---
            restoredData.merchantsData.forEach(merchant => {
                if (!currentMerchants.has(merchant.id)) {
                    currentMerchants.set(merchant.id, merchant);
                }
            });
            const mergedMerchants = Array.from(currentMerchants.values());

            // 6. Daten speichern
            // --- Wortfilter ---
            GM_setValue('excludeWords', mergedWords);
            localStorage.setItem('excludeWords', JSON.stringify(mergedWords));
            excludeWords = mergedWords;

            // --- Händlerfilter ---
            saveExcludeMerchants(mergedMerchants);

            // --- Einstellungen ---
            if (typeof restoredData.maxPrice === 'number' && maxPrice === 0) {
                saveMaxPrice(restoredData.maxPrice);
            }

            if (typeof restoredData.hideColdDeals === 'boolean' && !hideColdDeals) {
                hideColdDeals = restoredData.hideColdDeals;
                GM_setValue('hideColdDeals', hideColdDeals);
                localStorage.setItem('hideColdDeals', hideColdDeals);
            }

            // 7. UI aktualisieren
            if (isSettingsOpen) {
                updateUITheme();
            }
            processArticles();

            alert('Backup wurde erfolgreich wiederhergestellt.');

        } catch (error) {
            console.error('Restore error:', error);
            alert('Fehler beim Wiederherstellen des Backups: ' + error.message);
        }
    };

    reader.readAsText(file);
}

//#endregion





//#region --- 8. Hilfsfunktionen ---
// ===== Text-Verarbeitung =====
// --- Händlernamen-Verarbeitung ---
function removeMerchantNameFromTitle(title, merchant) {
    if (!title || !merchant) return title;

    // Normalisiere Händlernamen und hole Konfiguration
    const merchantName = merchant.toLowerCase()
                            .replace('...', '')
    
    // Spezialfall für eSIM.sm - wir wollen "eSIM" nicht entfernen, da es ein Produktname ist
    if (merchantName === 'esim.sm' && title.toLowerCase().includes('auf esim')) {
        return title;
    }

    // Extrahiere den Basis-Namen aus dem Händlernamen, wenn es sich um eine Domain handelt
    let baseShopName = merchantName;
    if (merchantName.includes('-shop')) {
        baseShopName = merchantName.split('-shop')[0];
    } else if (merchantName.includes('.')) {
        // Extrahiere den Basisnamen aus Domains wie CDKeys.com -> CDKeys
        baseShopName = merchantName.split('.')[0];
    }

    // Handle special case for any merchant-related pattern in parentheses at beginning
    if (title.match(/^\([^)]+\)/i)) {
        const lowerTitle = title.toLowerCase();
        const lowerMerchant = merchantName.toLowerCase();

        // Check if merchant name is contained in the parentheses at the beginning
        if (lowerTitle.substring(0, lowerTitle.indexOf(')')).includes(lowerMerchant)) {
            // Prüfe auf Slash-Format
            if (title.match(/^\([^/]+\/[^)]+\)/i)) {
                // Behandle Slash-Format separat
                return title.replace(
                    new RegExp(`\\(${merchantName}\\s*/\\s*(.+?)\\)`, 'i'),
                    '($1)'
                );
            }
            return title.replace(/^\([^)]+\)\s*/, '');
        }
    }

    // Händler-spezifische Transformationen definieren
    const getMerchantConfig = (merchant) => {
        switch (merchant) {
            case 'Netto Marken-Discount':
                return {
                    abbreviations: ['netto md'],
                    replacements: [
                        // Entfernt "Netto Marken Discount -" nach lokaler Angabe
                        { from: /(\[\s*lokal[^\]]+\])\s*netto\s+marken[-\s]discount\s*-\s*/i, to: '$1 ' },
                        // Entfernt "bei Netto Marken-Discount gibt es"
                        { from: /\s+bei\s+netto\s+marken[-\s]discount\s+gibt\s+es\s*/i, to: ' ' },
                        // Standardfälle für Netto
                        { from: /(?<!\[.+)\s*(?:bei\s+)?netto\s+marken[-\s]discount[-\s]*/i, to: ' ' }
                    ],
                    keepBrands: []
                };
            case 'Kaufland':
                return {
                    abbreviations: [],
                    replacements: [
                        { from: /kaufland[\s-]card/i, to: 'K-Card' },
                        // Entfernt "bei Kaufland" auch in der Mitte
                        { from: /\s+bei\s+kaufland(?:\s*-\s*)/i, to: ' - ' }
                    ],
                    keepBrands: ['Card']
                };
            case 'Amazon':
                return {
                    abbreviations: [],
                    replacements: [
                        // Besonders behandelte Muster für Amazon Prime
                        { from: /\[amazon\s+prime\]/i, to: '[Prime]' },
                        { from: /\[amazon\s+(prime\s+\w+)\]/i, to: '[$1]' },
                        // Ersetze "Amazon Prime" mit "Prime" (außerhalb von Klammern)
                        { from: /\bamazon\s+prime\b/i, to: 'Prime' },
                        // Erhalte "Prime Video", "Prime Gaming" usw.
                        { from: /\bamazon\s+(prime\s+\w+)\b/i, to: '$1' }
                    ],
                    keepBrands: ['Prime']
                };
            case 'Best Secret':
                return {
                    abbreviations: ['BestSecret'],
                    replacements: [],
                    keepBrands: []
                };
            case 'TradePub.com':  // Füge zusätzliche Schreibweise hinzu
                return {
                    abbreviations: ['tradepub', 'Tradepub'],  // Beide Schreibweisen
                    replacements: [
                        { from: /\s+bei\s+tradepub\.com(?:\s+|$)/i, to: ' ' },
                        { from: /^tradepub\.com:\s*/i, to: '' },
                        { from: /^\(tradepub\)\s*/i, to: '' },
                        // Neues Pattern für (Tradepub) mit Groß-/Kleinschreibung
                        { from: /^\((?:Tradepub|TRADEPUB|tradepub)\)\s*/i, to: '' }
                    ],
                    keepBrands: []
                };
            case 'Netto':
                return {
                    abbreviations: ['netto mit hund'],
                    replacements: [
                        // Entfernt "[Netto mit Hund]" Format
                        { from: /\[netto\s+mit\s+hund\]\s*/i, to: '' }
                    ],
                    keepBrands: []
                };
            case 'A.T.U':
                return {
                    abbreviations: ['atu', 'a.t.u'],
                    replacements: [
                        { from: /(Sale)\s+bei\s+(?:ATU|A\.T\.U)(\s*;\s*)(Ab)/i, to: '$1$2$3' }
                    ],
                    keepBrands: []
                };
            case 'Uber Eats':
                return {
                    abbreviations: ['ubereats'],
                    replacements: [
                        // Spezifisches Pattern für "[UberEats Member Days]" Format
                        { from: /\[UberEats\s+(Member\s+Days)\]/i, to: '[$1]' }
                    ],
                    keepBrands: ['Member Days']
                };             
            default:
                return { abbreviations: [], replacements: [], keepBrands: [] };
        }
    };

    const config = getMerchantConfig(merchant);

    // Führe erst spezielle Ersetzungen durch
    let result = title;
    config.replacements.forEach(({ from, to }) => {
        result = result.replace(from, to);
    });

    // Spezielle Muster für [Händler| Format]
    result = result.replace(new RegExp(`\\[${merchantName.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}\\|\\s*`, 'i'), '[');
    
    // Wenn wir einen Basis-Namen extrahiert haben, auch diesen behandeln
    if (baseShopName !== merchantName) {
        result = result.replace(new RegExp(`\\[${baseShopName.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')}\\|\\s*`, 'i'), '[');
    }

    // Erstelle Domain-Varianten für den Händlernamen und den Basis-Namen
    const createDomainVariants = (name) => [
        `${name}.com`,
        `${name}.de`,
        `${name}.co.uk`,
        `${name}-shop.com`,
        `${name}-shop.de`
    ];

    const domainVariants = createDomainVariants(merchantName);
    
    // Füge auch Domain-Varianten für den Basis-Namen hinzu
    if (baseShopName !== merchantName) {
        domainVariants.push(...createDomainVariants(baseShopName));
    }

    // Entferne explizit [Domain]-Muster am Anfang des Titels
    const handleBracketedDomain = (shopName) => {
        const escapedName = shopName.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
        result = result.replace(new RegExp(`\\[${escapedName}\\.com\\]`, 'i'), '');
        result = result.replace(new RegExp(`\\[${escapedName}\\.de\\]`, 'i'), '');
        result = result.replace(new RegExp(`\\[${escapedName}\\.co\\.uk\\]`, 'i'), '');
    };

    // Wende auf beide Namen an
    handleBracketedDomain(merchantName);
    if (baseShopName !== merchantName) {
        handleBracketedDomain(baseShopName);
    }

    // Erstelle Varianten des Händlernamens
    const merchantVariants = [
        merchantName,
        merchantName.replace(/\s+/g, '-'),
        merchantName.replace(/\-/g, ' '),
        ...config.abbreviations,
        ...domainVariants
    ];

    // Den Basisnamen auch zu den Varianten hinzufügen
    if (baseShopName !== merchantName) {
        merchantVariants.push(baseShopName);
        merchantVariants.push(baseShopName.replace(/\s+/g, '-'));
        merchantVariants.push(baseShopName.replace(/\-/g, ' '));
    }

    // Und, in umgekehrter Richtung, wenn der Händlername bereits eine Domain ist
    if (merchantName.includes('.') || merchantName.includes('-shop')) {
        // Entferne TLD und mögliche Zusätze wie "-shop"
        const baseName = merchantName
            .split('.')[0]  // Entferne TLD (.com, .de, etc.)
            .replace(/-shop$/, '')  // Entferne mögliches "-shop" am Ende
            .replace(/[^\w\s-]/g, ''); // Entferne alle Sonderzeichen außer Bindestriche und Leerzeichen
            
        merchantVariants.push(baseName);
        // Füge auch Varianten mit unterschiedlicher Groß-/Kleinschreibung hinzu
        merchantVariants.push(baseName.toLowerCase());
        merchantVariants.push(baseName.toUpperCase());
    }

    // Entferne Händlernamen
    merchantVariants.forEach(variant => {
        // Spezialfall für Domain-Formate wie "target.com"
        if (variant.includes('.')) {
            // Genereller Ansatz, um "target.com" zu entfernen
            const baseDomain = variant.split('.')[0];
            const escapedBase = baseDomain.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
            const escapedVariant = variant.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');

            // Entferne "[domain.com]" Format am Anfang
            result = result.replace(new RegExp(`\\[${escapedVariant}\\]\\s*`, 'i'), '');

            // Entferne auch domänenspezifische Top-Level-Domains - das ist der Teil, der fehlt
            result = result.replace(new RegExp(`\\[${escapedBase}\\.com\\]\\s*`, 'i'), '');
            result = result.replace(new RegExp(`\\[${escapedBase}\\.de\\]\\s*`, 'i'), '');
            result = result.replace(new RegExp(`\\[${escapedBase}\\.co\\.uk\\]\\s*`, 'i'), '');

            // Spezifisches Pattern für "bei Target.com für" - umfassendere Lösung
            result = result.replace(new RegExp(`\\s+bei\\s+${escapedBase}\\.com\\s+für`, 'i'), ' für');

            // Fallback-Pattern, um alle "bei domain.tld" Formate zu entfernen
            result = result.replace(new RegExp(`\\s+bei\\s+${escapedBase}\\.[a-z.]+(?:\\s+|$)`, 'i'), ' ');
        }

        // Für Namen mit Punkten, verwende spezifischere Ersetzungsmuster
        const needsSpecialBoundary = variant.includes('.');
        const escapedVariant = variant.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
        const wordBoundaryPattern = needsSpecialBoundary ? escapedVariant : `\\b${escapedVariant}\\b`;

        if (needsSpecialBoundary) {

        } else {
            // Handle parentheses with multiple entries separated by slashes first
            const parenthesesPattern = new RegExp(
                `\\(([^/]*?\\s*)?${escapedVariant}\\s*/\\s*([^)]+)\\)`,
                'i'
            );
            if (result.match(parenthesesPattern)) {
                const match = result.match(parenthesesPattern);
                const before = match[1] ? match[1].trim() : '';
                const after = match[2].trim();
                const newContent = [before, after].filter(Boolean).join(' / ');
                result = result.replace(parenthesesPattern, `(${newContent})`);
            }

            // Standard patterns for merchant names without punctuation
            result = result
                .replace(new RegExp(`\\s+bei\\s+${wordBoundaryPattern}\\s+`, 'i'), ' ')
                .replace(new RegExp(`\\s+(?:bei\\s+)?${escapedVariant}(?:[-–]|\\s)*$`, 'i'), '')
                .replace(new RegExp(`\\s+auf\\s+${escapedVariant}$`, 'i'), '')
                .replace(new RegExp(`\\s+auf\\s+${escapedVariant}(?=\\s|$)`, 'i'), '');
        }

        result = result
            // Die restlichen Standardmuster
            .replace(new RegExp(`\\(${escapedVariant}:\\s*`, 'i'), '(')
            .replace(new RegExp(`${escapedVariant}:\\s*`, 'i'), '')

            // Händler am Anfang (mit optionalem Punkt danach)
            .replace(new RegExp(`^${escapedVariant}\\s*\\.?\\s*[-–]?\\s*`, 'i'), '')

            // FIX: Händler in eckigen Klammern mit optionalen Leerzeichen
            .replace(new RegExp(`\\[\\s*${escapedVariant}\\s*\\]\\s*`, 'i'), '')

            // Händler mit Punkt als Trenner
            .replace(new RegExp(`^${escapedVariant}\\.\\s*`, 'i'), '')
            .replace(new RegExp(`\\s+${escapedVariant}\\.\\s+`, 'i'), ' ')
            .replace(new RegExp(`\\s+${escapedVariant}\\.\\s*$`, 'i'), '')

            // Händler in Klammern mit fehlenden Klammern
            .replace(new RegExp(`^${escapedVariant}\\)\\s*`, 'i'), '')
            .replace(new RegExp(`\\(${escapedVariant}$`, 'i'), '')
            
            .replace(new RegExp(`\\(${escapedVariant}\\s+`, 'i'), '(');
    });

    return result.replace(/\s+/g, ' ').trim();
}

function shortenMerchantName(title) {
    // Special cases for merchant names
    const replacements = {
        'Kaufland Card': 'K-Card',
        'Kaufland': '',
        // Add more special cases here if needed
    };

    let newTitle = title;
    for (const [merchant, replacement] of Object.entries(replacements)) {
        // Case insensitive replace with word boundaries
        const regex = new RegExp(`\\b${merchant}\\b`, 'i');
        newTitle = newTitle.replace(regex, replacement);
    }

    return newTitle.trim();
}

// ===== UI-Management =====
// --- Cleanup & Reset ---
function cleanup() {
    // Remove settings UI and always reset state
    if (settingsDiv?.parentNode) settingsDiv.remove();
    isSettingsOpen = false;

    // Der wichtige Teil - wenn das UI geschlossen wird und ein Deal ausgeblendet wurde
    if (lastHiddenDeal && !lastHiddenDealShown) {
        lastHiddenDealShown = true;
        GM_setValue(LAST_HIDDEN_DEAL_SHOWN, true);
    }

    // Add word suggestion list cleanup
    const suggestionList = document.getElementById('wordSuggestionList');
    if (suggestionList) {
        suggestionList.remove();
    }

    // Close merchant & words lists with state logging
    if (merchantListDiv?.parentNode) {
        merchantListDiv.remove();
    }
    if (wordsListDiv?.parentNode) {
        wordsListDiv.remove();
    }

    // Schließe auch das Sidebar Elements UI wenn vorhanden
    const sidebarElementsDiv = document.getElementById('sidebarElementsDiv');
    if (sidebarElementsDiv?.parentNode) {
        sidebarElementsDiv.remove();
    }

    // Reset UI states with logging
    if (activeSubUI) {
        const btn = document.getElementById(`show${activeSubUI === 'merchant' ? 'Merchant' : 'Words'}ListButton`);
        if (btn) {
            btn.innerHTML = activeSubUI === 'merchant' ?
                '<i class="fas fa-store"></i> Händlerfilter verwalten' :
            '<i class="fas fa-list"></i> Wortfilter verwalten';
            btn.removeAttribute('data-processing');
        }
    }
    activeSubUI = null;
    dealThatOpenedSettings = null; // Reset auch den aktiven Deal

    // Clean up handlers
    document.removeEventListener('click', suggestionClickHandler);
    document.removeEventListener('click', uiClickOutsideHandler);
    window.removeEventListener('unload', cleanup);
    uiClickOutsideHandler = null;

    // Reset suggestion state
    suggestedWords = [];
}

//#endregion





//#region --- 9. Theming und UI-Darstellung ---
// Farbkonstanten für Light/Dark Mode
const THEME_COLORS = {
    light: {
        background: '#ffffff',
        border: 'rgba(3,12,25,0.23)',
        text: '#333333',
        buttonBg: '#f5f5f5',
        buttonBorder: '#d0d0d0',
        inputBg: '#ffffff',
        itemBg: '#f8f8f8'
    },
    dark: {
        background: '#1d1f20',
        border: 'rgb(107, 109, 109)',
        text: '#ffffff',
        buttonBg: '#2d2d2d',
        buttonBorder: '#3d3d3d',
        inputBg: '#1d1f20',
        itemBg: '#2a2a2a'
    }
};

// Theme Observer erstellen
const themeObserver = new MutationObserver(() => {
    requestAnimationFrame(() => {
        const colors = getThemeColors();
        updateAllUIThemes(colors);
    });
});

// Observer für beide Elemente einrichten
const targetNodes = [document.documentElement, document.body];
targetNodes.forEach(node => {
    themeObserver.observe(node, {
        attributes: true,
        attributeFilter: ['class', 'data-theme']
    });
});

// System Theme Observer
const systemThemeObserver = window.matchMedia('(prefers-color-scheme: dark)');
systemThemeObserver.addEventListener('change', () => {
    requestAnimationFrame(() => {
        const colors = getThemeColors();
        updateAllUIThemes(colors);
    });
});

// Hide Button Theme Observer
const hideButtonThemeObserver = new MutationObserver(() => {
    const colors = getThemeColors();

    requestAnimationFrame(() => {
        document.querySelectorAll('.custom-hide-button').forEach(button => {
            if (button) {
                button.style.cssText = `
                    position: absolute !important;
                    left: 50% !important;
                    top: 50% !important;
                    transform: translate(-50%, -50%) !important;
                    z-index: 10002 !important;
                    background: ${colors.background} !important;
                    border: 1px solid ${colors.border} !important;
                    border-radius: 50% !important;
                    cursor: pointer !important;
                    padding: 4px !important;
                    width: 28px !important;
                    height: 28px !important;
                    display: flex !important;
                    align-items: center !important;
                    justify-content: center !important;
                    pointer-events: all !important;
                    box-shadow: none !important;
                    font-size: 12px !important;
                `;
            }
        });

        // Update settings UI wenn offen
        if (isSettingsOpen) {
            updateUITheme();
        }
    });
});

// Start observing theme changes
hideButtonThemeObserver.observe(document.documentElement, {
    attributes: true,
    attributeFilter: ['class']
});

// Theme Update Funktionen
function updateAllUIThemes() {
    const colors = getThemeColors();

    // Update buttons
    document.querySelectorAll('.custom-hide-button').forEach(button => {
        if (button) {
            button.style.setProperty('background', colors.background, 'important');
            button.style.setProperty('border-color', colors.border, 'important');
        }
    });

    // Update open UIs
    if (isSettingsOpen || activeSubUI) {
        updateUITheme();
    }
}
//#endregion





//#region --- 10. Button-Management ---

function addSettingsButton() {
    const deals = document.querySelectorAll('article.thread--deal, article.thread--voucher');

    deals.forEach(deal => {
        if (deal.hasAttribute('data-settings-added')) return;

        const footer = deal.querySelector('.threadListCard-footer, .threadCardLayout-footer');
        if (!footer) return;

        // Create settings button
        const settingsBtn = document.createElement('button');
        settingsBtn.className = 'flex--shrink-0 button button--type-text button--mode-secondary button--square';
        settingsBtn.title = 'mydealz Manager Einstellungen';
        settingsBtn.setAttribute('data-t', 'mdmSettings');
        settingsBtn.style.cssText = `
            display: inline-flex !important;
            align-items: center !important;
            justify-content: center !important;
            padding: 6px !important;
            border: none !important;
            background: transparent !important;
            cursor: pointer !important;
            margin: 0 4px !important;
            min-width: 32px !important;
            min-height: 32px !important;
            position: relative !important;
            z-index: 2 !important;
        `;

        settingsBtn.innerHTML = `
            <span class="flex--inline boxAlign-ai--all-c">
                <svg width="20" height="20" class="icon icon--gear">
                    <use xlink:href="/assets/img/ico_707ed.svg#gear"></use>
                </svg>
            </span>
        `;

        // Insert at correct position (before comments button)
        const commentsBtn = footer.querySelector('[href*="comments"]');
        if (commentsBtn) {
            commentsBtn.parentNode.insertBefore(settingsBtn, commentsBtn);
        } else {
            footer.prepend(settingsBtn);
        }

        deal.setAttribute('data-settings-added', 'true');

        settingsBtn.onclick = (e) => {
            e.preventDefault();
            e.stopPropagation();

            if (isSettingsOpen) {
                if (dealThatOpenedSettings === deal) {
                    cleanup();
                } else {
                    // Komplett neues UI erstellen statt nur den Button zu aktualisieren
                    cleanup();
                    dealThatOpenedSettings = deal;
                    createSettingsUI(); // Dies erstellt das UI in der korrekten Reihenfolge
                }
            } else {
                dealThatOpenedSettings = deal;
                createSettingsUI();
            }
            return false;
        };
    });
}

function addHideButtons() {
    const deals = document.querySelectorAll('article:not([data-button-added])');

    deals.forEach(deal => {
        if (deal.hasAttribute('data-button-added')) return;

        // Check for expired status
        const isExpired = deal.querySelector('.color--text-TranslucentSecondary .size--all-s')?.textContent.includes('Abgelaufen');

        // Get temperature container
        const voteTemp = deal.querySelector('.cept-vote-temp');
        if (!voteTemp) return;

        // Remove popover
        const popover = voteTemp.querySelector('.popover-origin');
        if (popover) popover.remove();

        // Find temperature span for expired deals
        const tempSpan = isExpired ? voteTemp.querySelector('span') : null;
        const targetElement = isExpired ? tempSpan : voteTemp;

        if (!targetElement) return;

        const hideButtonContainer = document.createElement('div');
        hideButtonContainer.style.cssText = `
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            display: none;
            z-index: 10001;
            pointer-events: none;
        `;

        const hideButton = document.createElement('button');
        hideButton.innerHTML = '❌';
        hideButton.className = 'vote-button overflow--visible custom-hide-button';
        hideButton.title = 'Deal verbergen';
        hideButton.style.cssText = `
            position: absolute !important;
            left: 50% !important;
            top: 50% !important;
            transform: translate(-50%, -50%) !important;
            z-index: 10002 !important;
            background: ${getThemeColors().background} !important;
            border: 1px solid ${getThemeColors().border} !important;
            border-radius: 50% !important;
            cursor: pointer !important;
            padding: 4px !important;
            width: 28px !important;
            height: 28px !important;
            display: flex !important;
            align-items: center !important;
            justify-content: center !important;
            pointer-events: all !important;
            box-shadow: none !important;
            font-size: 12px !important;
        `;

        // Position relative to container
        if (!targetElement.style.position) {
            targetElement.style.position = 'relative';
        }

        if (IS_TOUCH_DEVICE) {
            let buttonVisible = false;
            const dealId = deal.getAttribute('id');

            // Add scroll handler to hide button
            const scrollHandler = () => {
                if (buttonVisible) {
                    buttonVisible = false;
                    hideButtonContainer.style.display = 'none';
                } else if (hideButtonContainer.style.display === 'block') {
                }
            };

            // Add scroll listener
            window.addEventListener('scroll', scrollHandler, { passive: true });

            targetElement.addEventListener('touchstart', (e) => {
                e.preventDefault();
                e.stopPropagation();

                if (!buttonVisible) {
                    buttonVisible = true;
                    hideButtonContainer.style.display = 'block';
                } else {
                    const dealId = deal.getAttribute('id');
                    const dealTitle = deal.querySelector('.thread-title')?.textContent.trim() || 'Unbekannter Deal';

                    // Aktuellen Deal speichern
                    lastHiddenDeal = {
                        id: dealId,
                        title: dealTitle,
                        timestamp: Date.now()
                    };

                    // "Deal wurde angezeigt" auf false setzen
                    lastHiddenDealShown = false;
                    GM_setValue(LAST_HIDDEN_DEAL_SHOWN, false);

                    // Speichern des letzten ausgeblendeten Deals
                    saveLastHiddenDeal();

                    hiddenDeals.push(dealId);
                    saveHiddenDeals();
                    hideDeal(deal);
                    window.removeEventListener('scroll', scrollHandler);
                }
            }, true);

            targetElement.addEventListener('touchend', () => {
                if (!buttonVisible) {
                    hideButtonContainer.style.display = 'none';
                }
            }, true);
        } else {
            targetElement.addEventListener('mouseenter', () => {
                hideButtonContainer.style.display = 'block';
            }, true);

            targetElement.addEventListener('mouseleave', () => {
                hideButtonContainer.style.display = 'none';
            }, true);

            hideButton.onclick = (e) => {
                e.preventDefault();
                e.stopPropagation();
                const dealId = deal.getAttribute('id');
                const dealTitle = deal.querySelector('.thread-title')?.textContent.trim() || 'Unbekannter Deal';

                // Aktuellen Deal speichern
                lastHiddenDeal = {
                    id: dealId,
                    title: dealTitle,
                    timestamp: Date.now()
                };

                // "Deal wurde angezeigt" auf false setzen und persistieren
                lastHiddenDealShown = false;
                GM_setValue(LAST_HIDDEN_DEAL_SHOWN, false);

                saveLastHiddenDeal();
                hiddenDeals.push(dealId);
                saveHiddenDeals();
                hideDeal(deal);
                return false;
            };
        }

        hideButtonContainer.appendChild(hideButton);
        targetElement.appendChild(hideButtonContainer);
        deal.setAttribute('data-button-added', 'true');
    });
}

function getMerchantButtonText(merchantName) {
    return `Alle Deals von ${merchantName}`;
}

function addMerchantPageHideButton() {
    const urlParams = new URLSearchParams(window.location.search);
    const merchantId = urlParams.get('merchant-id');
    const merchantBanner = document.querySelector(MERCHANT_PAGE_SELECTOR);
    const merchantName = document.querySelector('.merchant-banner__title')?.textContent.trim();

    if (!merchantId || !merchantBanner || !merchantName) return;

    const hideButtonContainer = document.createElement('div');
    hideButtonContainer.style.cssText = `
        display: inline-flex;
        align-items: center;
        margin-left: 10px;
    `;

    const hideButton = document.createElement('button');
    hideButton.style.cssText = `
        display: inline-flex;
        align-items: center;
        gap: 8px;
        padding: 8px 12px;
        background: #f0f0f0;
        border: 1px solid #ccc;
        border-radius: 3px;
        cursor: pointer;
        font-size: 14px;
    `;

    const buttonText = getMerchantButtonText(merchantName);
    hideButton.innerHTML = `
        <span style="display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;">
            <i class="fas fa-store-slash"></i>
            <span>${buttonText}</span>
        </span>
    `;
    hideButton.title = `${buttonText} ausblenden`;

    hideButton.addEventListener('click', () => {
        const merchantsData = loadExcludeMerchants();
        if (!merchantsData.some(m => m.id === merchantId)) {
            merchantsData.unshift({ id: merchantId, name: merchantName });
            saveExcludeMerchants(merchantsData);
            processArticles();
        }
    });

    hideButtonContainer.appendChild(hideButton);
    merchantBanner.appendChild(hideButtonContainer);
}

// Helfer-Funktion, um den Zustand der Toggle-Buttons zu aktualisieren
function updateToggleButtonsState() {
    const buttons = document.querySelectorAll('.toggle-sidebar-element');
    buttons.forEach(button => {
        const key = button.dataset.key;
        if (key && SIDEBAR_ELEMENTS[key]) {
            const element = SIDEBAR_ELEMENTS[key];
            const icon = button.querySelector('i');
            if (icon) {
                icon.className = `fas ${element.hidden ? 'fa-eye-slash' : 'fa-eye'}`;
                icon.setAttribute('aria-label', element.hidden ? 'Element versteckt' : 'Element sichtbar');
            }
        }
    });
}

//#endregion





//#region --- 11. Skript-Initialisierung ---
// Initial beim Start aufrufen
registerMenuCommands();

// Start script - nach DOM ready
if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
} else {
    init();
}

// Aufräumen bestehender Daten beim Skriptstart
(function cleanupMerchantData() {
    const merchants = loadExcludeMerchants();
    saveExcludeMerchants(merchants);
})();

//#endregion





//#region --- 12. Spezialisierte Komponenten ---
function initializeUI() {
    // Initial UI Setup
    processArticles();
    addSettingsButton();
    addHideButtons();
    addMerchantPageHideButton();
}

// Observer Initialisierung
function initObserver() {
    observer.disconnect();
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });

    // Sofortige Verarbeitung
    requestAnimationFrame(() => {
        processArticles();
        addSettingsButton();
        addHideButtons();
    });
}

function registerMenuCommands() {
    // Alte Menüs erst abmelden
    if (menuCommandId !== undefined) {
        GM_unregisterMenuCommand(menuCommandId);
    }

    // Menüeintrag zum Öffnen der Einstellungen registrieren
    menuCommandId = GM_registerMenuCommand('mydealz Manager Einstellungen', () => {
        // Einstellungen für aktuellen Deal öffnen
        dealThatOpenedSettings = document.querySelector('article.thread--deal, article.thread--voucher');
        createSettingsUI();
    });
}

//#endregion





//#region --- 13. Dokumentation ---
/*
===================================================================================
--- Funktionsübersicht mydealz Manager ---
===================================================================================

detectMultipleInstances() - Erkennt parallele Ausführungen des Scripts (ab 1.13.x)
getThemeColors() - Liefert Theme-spezifische Farben basierend auf aktuellem Theme
processArticles() - Verarbeitet und filtert alle Deals
shouldExcludeArticle() - Prüft ob ein Deal ausgeblendet werden soll
createSettingsUI() - Erstellt das Haupteinstellungsfenster
addSettingsButton() - Fügt Einstellungs-Button zu Deals hinzu
addHideButtons() - Fügt X-Button zum Ausblenden hinzu
backupData() - Erstellt Backup der Einstellungen
restoreData() - Stellt Backup-Daten wieder her
decodeHtml() - Konvertiert HTML-Entities
cleanup() - Räumt UI-Elemente auf
syncStorage() - Synchronisiert GM und localStorage
saveExcludeWords() - Speichert Wortfilter
loadExcludeWords() - Lädt Wortfilter
saveExcludeMerchants() - Speichert Händlerfilter
loadExcludeMerchants() - Lädt Händlerfilter
saveMaxPrice() - Speichert Maximalpreis
createMerchantListUI() - Zeigt Händlerliste
createExcludeWordsUI() - Zeigt Wortfilterliste
updateActiveLists() - Aktualisiert Listen im UI
handleMerchantDelete() - Löscht Händler aus Filter
handleWordDelete() - Löscht Wort aus Filter
setupScrollHandling() - Konfiguriert Scroll-Verhalten
updateUITheme() - Aktualisiert UI-Farben
init() - Initialisiert das Script
removeMerchantNameFromTitle() - Entfernt Händlernamen aus Deal-Titeln
throttle() - Begrenzt die Ausführungshäufigkeit von Funktionen
getWordsFromTitle() - Extrahiert relevante Wörter aus Deal-Titeln
hideDeal() - Blendet einen Deal aus
initUIContainers() - Initialisiert UI-Container
updateSuggestionList() - Aktualisiert Wortvorschläge
handleWordSelection() - Verarbeitet Wortauswahl
setupClickOutsideHandler() - Konfiguriert Außenbereich-Klicks
createSuggestionClickHandler() - Erstellt Handler für Wortvorschläge
registerMenuCommands() - Registriert Script-Manager Menüeinträge
saveHiddenDeals() - Speichert ausgeblendete Deals
saveLastHiddenDeal() - Speichert zuletzt ausgeblendeten Deal
initializeUI() - Initialisiert Benutzeroberfläche
initObserver() - Initialisiert DOM-Beobachter
addMerchantPageHideButton() - Fügt Händler-Ausblenden-Button hinzu
injectDealFilters() - Fügt Deal-Filter in die UI ein

===================================================================================
*/
//#endregion