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.12.9.2
// @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
// ==/UserScript==

// Versions-Änderungen
// 1.12.9
// FIX: Beim Scrollen im SettingsUI wurde teilweise die Website gescrollt.
// FIX: Auf Touch-Geräten war keine Eingabe im Maximalpreis Filter möglich.
// FIX: Wurde während der Suche in Wort-/Händlerliste ein Eintrag gelöscht, sprang der Zähler von xx/xx auf xx und zeigte nur noch die Gesamtzahl der Einträge.
// CHANGE: Optimierung der Vorschläge in der WordSuggestionList.
// CHANGE: Robustere und präzisere Wortfilterung.
// 1.12.9.1
// FIX: Auf Touch Geräten wurde nicht in der WordSuggestionList gescrollt.
// 1.12.9.2
// FIX: Eingabe im Maximalpreis Filter verursachte Probleme bei Punkt und Komma.


// --- 1. Initialisierung und Grundeinstellungen ---
// Einbinden von Font Awesome für Icons
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);

const preventAutoCloseStyle = document.createElement('style');
preventAutoCloseStyle.textContent = `
    .subNavMenu.keep-open {
        display: block !important;
        visibility: visible !important;
        opacity: 1 !important;
        pointer-events: auto !important;
    }
`;
document.head.appendChild(preventAutoCloseStyle);

// Add constant for touch detection
const IS_TOUCH_DEVICE = ('ontouchstart' in window) ||
      (navigator.maxTouchPoints > 0) ||
      (navigator.msMaxTouchPoints > 0);

// Konstanten und Variablen
const HIDDEN_DEALS_KEY = 'hiddenDeals';
const MERCHANT_PAGE_SELECTOR = '.merchant-banner';
const HIDE_COLD_DEALS_KEY = 'hideColdDeals';
const MAX_PRICE_KEY = 'maxPrice';

function throttle(func, limit) {
    let inThrottle;
    return function(...args) {
        if (!inThrottle) {
            func.apply(this, args);
            inThrottle = true;
            setTimeout(() => {
                inThrottle = false;
                return false;
            }, limit);
        }
    }
}

// DOM-Beobachter einrichten
const observer = new MutationObserver(throttle(() => {
    processArticles();
    addSettingsButton();
    addHideButtons();
}, 250));

// Filter-UI Beobachter
const filterObserver = new MutationObserver((mutations) => {
    mutations.forEach(mutation => {
        if (mutation.addedNodes.length) {
            const filterMenu = document.querySelector('.subNavMenu-list');
            if (filterMenu && !document.getElementById('maxPriceFilterInput')) {
                injectMaxPriceFilter();
            }
        }
    });
});

// Globale Zustandsvariablen
let excludeWords = [];
let excludeMerchantIDs = [];
let hiddenDeals = [];
let suggestedWords = [];
let activeSubUI = null;
let dealThatOpenedSettings = null;
let settingsDiv = null;
let merchantListDiv = null;
let wordsListDiv = null;
let uiClickOutsideHandler = null;
let isSettingsOpen = false;
let hideColdDeals = localStorage.getItem(HIDE_COLD_DEALS_KEY) === 'true';
let maxPrice = parseFloat(localStorage.getItem(MAX_PRICE_KEY)) || 0;
let suggestionClickHandler = null;

// --- 2. Theme-System ---
// Farbkonstanten für Light/Dark Mode
const THEME_COLORS = {
    light: {
        background: '#f9f9f9',
        border: '#ccc',
        text: '#333',
        buttonBg: '#f0f0f0',
        buttonBorder: '#ccc',
        inputBg: '#fff',
        itemBg: '#f0f0f0',
        itemHoverBg: '#e8e8e8'
    },
    dark: {
        background: '#1f1f1f',
        border: '#2d2d2d',
        text: '#ffffff',
        buttonBg: '#2d2d2d',
        buttonBorder: '#3d3d3d',
        inputBg: '#2d2d2d',
        itemBg: '#2d2d2d',
        itemHoverBg: '#3d3d3d'
    }
};

// Theme-Erkennung
function isDarkMode() {
    // Check system preference
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

    // Check document theme
    const htmlElement = document.documentElement;
    const bodyElement = document.body;

    // Check for dark theme indicators
    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')); // System dark + no explicit light

    return isDark;
}

// Theme-Farben abrufen
function getThemeColors() {
    const isDark = isDarkMode();
    return isDark ? THEME_COLORS.dark : THEME_COLORS.light;
}

// Theme Observer erstellen
const themeObserver = new MutationObserver(() => {
    requestAnimationFrame(() => {
        const isLight = !isDarkMode();
        updateAllUIThemes(isLight);
    });
});

// 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 isLight = !isDarkMode();
        updateAllUIThemes(isLight);
    });
});

// Hide Button Theme Observer
const hideButtonThemeObserver = new MutationObserver(() => {
    const isLight = !isDarkMode();

    requestAnimationFrame(() => {
        document.querySelectorAll('.custom-hide-button').forEach(button => {
            if (button) {
                const bgColor = isLight ? '#ffffff' : '#1d1f20';
                const borderColor = isLight ? 'rgba(3,12,25,0.23)' : 'rgb(107, 109, 109)';
                button.style.cssText = `
                    position: absolute !important;
                    left: 50% !important;
                    top: 50% !important;
                    transform: translate(-50%, -50%) !important;
                    z-index: 10002 !important;
                    background: ${bgColor} !important;
                    border: 1px solid ${borderColor} !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(isLight) {
    // Update buttons
    document.querySelectorAll('.custom-hide-button').forEach(button => {
        if (button) {
            const bgColor = isLight ? '#ffffff' : '#1d1f20';
            button.style.setProperty('background', bgColor, 'important');
        }
    });

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

    // Update filter menu if open
    const filterMenu = document.querySelector('.subNavMenu-list');
    if (filterMenu) {
        const colors = getThemeColors();
        const inputs = filterMenu.querySelectorAll('input');
        inputs.forEach(input => {
            input.style.borderColor = colors.border;
            input.style.backgroundColor = colors.inputBg;
            input.style.color = colors.text;
        });
    }
}

// --- 3. Datenverwaltung ---
// Storage-Synchronisation
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;
        }
    }

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

// Speicherfunktionen
function saveHiddenDeals() {
    GM_setValue('hiddenDeals', hiddenDeals);
    localStorage.setItem('hiddenDeals', JSON.stringify(hiddenDeals));
}

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));
}

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;
}

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;
}

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;
}

function saveMaxPrice(price) {

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

// --- 4. Kernfunktionen ---
// Artikel verarbeiten und filtern
function processArticles() {
    // Cache für bereits verarbeitete Artikel
    const processedDeals = new Set();

    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';
    });
}

// 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;
        }
    }

    // Price check
    if (maxPrice > 0) {
        const priceSelectors = ['.threadItemCard-price', '.thread-price', '[class*="price"]', '.cept-tp'];

        for (const selector of priceSelectors) {
            const priceElement = article.querySelector(selector);
            if (!priceElement) continue;

            try {
                const priceText = priceElement.textContent.trim();
                const priceMatch = priceText.match(/([\d.,]+)\s*€/);

                if (priceMatch) {
                    const price = parseFloat(priceMatch[1].replace('.', '').replace(',', '.'));
                    if (!isNaN(price) && price > maxPrice) return true;
                }
            } catch (error) {
                continue;
            }
        }
    }

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

    // Check excludeWords
    if (excludeWords.some(word => {
        const searchTerm = word.toLowerCase();

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

        // Handle words with special characters (+)
        if (searchTerm.includes('+')) {
            return processedTitle.includes(searchTerm);
        }

        // Handle multi-word phrases (like "eau de toilette" or "internet radio")
        if (searchTerm.includes(' ') || searchTerm.includes('-')) {
            const variations = [
                searchTerm,                              // original form
                searchTerm.replace(/-/g, ' '),          // hyphen to space
                searchTerm.replace(/-/g, ''),           // without hyphen
                searchTerm.replace(/ /g, ''),           // without spaces
                searchTerm.replace(/-/g, ' ').trim(),   // normalized spaces
                searchTerm.replace(/ /g, '-')           // space to hyphen
            ];

            // Remove duplicates
            const uniqueVariations = [...new Set(variations)];

            return uniqueVariations.some(variant => {
                // For multi-word variations, all words must be present in order
                if (variant.includes(' ')) {
                    const words = variant.split(' ').filter(w => w.length > 0);
                    let lastIndex = -1;

                    return words.every(word => {
                        const index = processedTitle.indexOf(word, lastIndex + 1);
                        if (index === -1) return false;
                        lastIndex = index;
                        return true;
                    });
                }

                // For single words or compound words
                return processedTitle.includes(variant);
            });
        }

        // Use word boundaries for normal words
        const regex = new RegExp(`\\b${searchTerm}\\b`, 'i');
        return regex.test(processedTitle);
    })) 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;
}

function hideDeal(deal) {
    deal.style.display = 'none';
}

function getWordsFromTitle(deal) {
    const titleElement = deal.querySelector('.thread-title');
    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'];
    const ignoreChars = ['&', '+', '!', '-', '/', '%', '–'];
    const units = ['MB/s', 'GB/s', 'KB/s', 'Mbit/s', 'Gbit/s', 'Kbit/s'];
    const priceContextWords = ['effektiv'];

    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) => {
        // Prüfe erst auf bekannte Einheiten
        if (units.some(unit => word.includes(unit))) {
            // Entferne nur Sonderzeichen am Ende die nicht zur Einheit gehören
            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 ersetzen
        let tempTitle = title;
        const replacements = new Map();

        units.forEach((unit, index) => {
            const placeholder = `__UNIT${index}__`;
            while (tempTitle.includes(unit)) {
                tempTitle = tempTitle.replace(unit, placeholder);
                replacements.set(placeholder, unit);
            }
        });

        // Split und Einheiten wiederherstellen
        return tempTitle
            .split(/[\s\/]+/)
            .map(word => {
                replacements.forEach((unit, placeholder) => {
                    if (word.includes(placeholder)) {
                        word = word.replace(placeholder, unit);
                    }
                });
                return word;
            });
    };

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

// --- 5. Benutzeroberfläche (UI) ---
function setupScrollHandling() {
    let isScrollingUI = false;
    let lastActiveUI = null;
    let touchStartY = 0;

    function handleMouseEnter(e) {
        const targetUI = e.currentTarget;
        if (targetUI) {
            lastActiveUI = targetUI;
        }
    }

    function handleMouseLeave() {
        lastActiveUI = null;
    }

    function handleScroll(e) {
        // Check if scrolling happens in a scrollable list
        const scrollableElement = e.target.closest('#merchantList, #wordsList, #wordSuggestionList');

        if (scrollableElement) {
            // Allow scrolling within scrollable lists
            const isAtTop = scrollableElement.scrollTop === 0;
            const isAtBottom = scrollableElement.scrollTop + scrollableElement.clientHeight >= scrollableElement.scrollHeight;

            // Only prevent scrolling at top/bottom of list
            if ((isAtTop && e.deltaY < 0) || (isAtBottom && e.deltaY > 0)) {
                e.preventDefault();
                e.stopPropagation();
            }
            return; // Exit early for scrollable elements
        }

        if (IS_TOUCH_DEVICE) {
            if (isScrollingUI) {
                e.preventDefault();
                e.stopPropagation();
            }
            return;
        }

        // Desktop handling
        if (lastActiveUI) {
            const rect = lastActiveUI.getBoundingClientRect();
            const mouseIsOverUI = e.clientX >= rect.left &&
                                e.clientX <= rect.right &&
                                e.clientY >= rect.top &&
                                e.clientY <= rect.bottom;

            if (mouseIsOverUI && !e.target.closest('#merchantList, #wordsList, #wordSuggestionList')) {
                e.preventDefault();
                e.stopPropagation();
            }
        }
    }

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

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

        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('#merchantList, #wordsList');

        if (scrollableElement) {
            const deltaY = touchStartY - touch.clientY;
            const isAtTop = scrollableElement.scrollTop === 0;
            const isAtBottom = scrollableElement.scrollTop + scrollableElement.clientHeight >= scrollableElement.scrollHeight;

            // Erlaube Scrollen in der Liste wenn nicht am Anfang/Ende
            if ((isAtTop && deltaY < 0) || (isAtBottom && deltaY > 0)) {
                e.preventDefault();
            }
        } else {
            // Blockiere Scrollen außerhalb der Listen
            e.preventDefault();
        }

        touchStartY = touch.clientY;
    }

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

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

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

    // Initial Setup
    setupAllElements();

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

    document.addEventListener('wheel', handleScroll, { passive: false });

    // MutationObserver für dynamisch hinzugefügte UIs
    const observer = new MutationObserver(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')]
            .forEach(el => {
                if (el?.parentNode) {
                    el.removeEventListener('mouseenter', handleMouseEnter);
                    el.removeEventListener('mouseleave', handleMouseLeave);
                }
            });
        observer.disconnect();
    };
}

// UI-Basis
function initUIContainers() {
    settingsDiv = document.createElement('div');
    merchantListDiv = document.createElement('div');
    wordsListDiv = document.createElement('div');
}

// Einstellungsfenster erstellen
function createSettingsUI() {
    if (isSettingsOpen) return;
    isSettingsOpen = true;

    // 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%);
        padding: 15px;
        background: ${colors.background};
        border: 1px solid ${colors.border};
        border-radius: 5px;
        z-index: 1000;
        width: 300px;
        max-height: 90vh;
        overflow: visible;
        color: ${colors.text};
    `;

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

    // Process articles when opening settings
    processArticles();

    // Conditional merchant button HTML - only show if merchant exists
    const merchantButtonHtml = showMerchantButton ? `
        <button id="hideMerchantButton" style="
            width: 100%;
            margin-top: 5px;
            padding: 5px 10px;
            background: ${colors.buttonBg};
            border: 1px solid ${colors.buttonBorder};
            border-radius: 3px;
            cursor: pointer;
            color: ${colors.text};
        ">
            <i class="fas fa-store-slash"></i> Alle Deals von <span style="font-weight: bold">${merchantName}</span> ausblenden
        </button>
    ` : '';

    const wordInputSection = `
        <div style="margin-bottom: 20px;">
            <div style="display: flex; align-items: center; gap: 4px;">
                <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: 8px;
                        background: ${colors.inputBg};
                        border: 1px solid ${colors.border};
                        border-radius: 3px;
                        color: ${colors.text};
                    ">
                ${IS_TOUCH_DEVICE ? `
                    <button id="enableKeyboardButton"
                        style="
                            flex-shrink: 0;
                            width: 36px;
                            padding: 8px;
                            background: ${colors.buttonBg};
                            border: 1px solid ${colors.buttonBorder};
                            border-radius: 3px;
                            cursor: pointer;
                            color: ${colors.text};
                        ">
                        <i class="fas fa-keyboard"></i>
                    </button>
                ` : ''}
                <button id="addWordButton"
                    style="
                        flex-shrink: 0;
                        width: 36px;
                        padding: 8px;
                        background: ${colors.buttonBg};
                        border: 1px solid ${colors.buttonBorder};
                        border-radius: 3px;
                        cursor: pointer;
                        color: ${colors.text};
                    ">
                    <i class="fas fa-plus"></i>
                </button>
            </div>
        </div>`;

    settingsDiv.innerHTML = `
        <h4 style="margin-bottom: 15px; color: ${colors.text}">Einstellungen zum Ausblenden</h4>
        ${wordInputSection}
        ${merchantButtonHtml}

        <!-- List Management Section -->
        <div style="margin-top: 20px; display: flex; flex-direction: column; gap: 10px;">
            <button id="showWordsListButton" style="
                width: 100%;
                padding: 8px;
                background: ${colors.buttonBg};
                border: 1px solid ${colors.buttonBorder};
                border-radius: 3px;
                cursor: pointer;
                color: ${colors.text};">
                <i class="fas fa-list"></i> Wortfilter verwalten
            </button>
            <button id="showMerchantListButton" style="
                width: 100%;
                padding: 8px;
                background: ${colors.buttonBg};
                border: 1px solid ${colors.buttonBorder};
                border-radius: 3px;
                cursor: pointer;
                color: ${colors.text};">
                <i class="fas fa-store"></i> Händlerfilter verwalten
            </button>
        </div>

        <!-- Action Buttons -->
        <div style="margin-top: 20px; text-align: right; display: flex; justify-content: flex-end; gap: 5px;">
            <button id="createBackupButton" style="padding: 8px; background: none; border: none; cursor: pointer; color: ${colors.text};" title="Backup erstellen">
                <i class="fas fa-file-export"></i>
            </button>
            <button id="restoreBackupButton" style="padding: 8px; background: none; border: none; cursor: pointer; color: ${colors.text};" title="Wiederherstellen">
                <i class="fas fa-file-import"></i>
            </button>
            <input type="file" id="restoreFileInput" style="display: none;" />
            <button id="closeSettingsButton" style="padding: 8px; background: none; border: none; cursor: pointer; color: ${colors.text};" title="Schließen">
                <i class="fas fa-times"></i>
            </button>
        </div>`;

    // Explicitly add to DOM
    document.body.appendChild(settingsDiv);

    if (IS_TOUCH_DEVICE) {
        const input = document.getElementById('newWordInput');
        const keyboardButton = document.getElementById('enableKeyboardButton');

        if (input && keyboardButton) {
            let keyboardEnabled = false;
            let ignoreNextFocus = false;

            // Focus handler für Input
            input.addEventListener('focus', (e) => {
                if (ignoreNextFocus) {
                    ignoreNextFocus = false;
                    return;
                }

                if (!keyboardEnabled) {
                    // Verhindern dass die Tastatur erscheint wenn nicht explizit aktiviert
                    e.preventDefault();
                    input.blur();

                    // Zeige Wortvorschläge
                    if (suggestedWords.length === 0) {
                        suggestedWords = getWordsFromTitle(dealThatOpenedSettings);
                    }
                    if (suggestedWords.length > 0) {
                        updateSuggestionList();
                    }
                }
            });

            // Keyboard Button Handler
            keyboardButton.addEventListener('click', () => {
                const input = document.getElementById('newWordInput');
                if (!input) return;

                // Entferne readonly und aktiviere Tastatur
                input.removeAttribute('readonly');
                keyboardEnabled = true;

                // Verstecke Wortvorschläge
                const suggestionList = document.getElementById('wordSuggestionList');
                if (suggestionList) {
                    suggestionList.remove();
                }

                // Verhindern dass der nächste Focus die Wortvorschläge öffnet
                ignoreNextFocus = true;

                // Fokussiere Input und öffne Tastatur
                input.focus();

                // Setze einen Timer um keyboardEnabled zurückzusetzen
                setTimeout(() => {
                    keyboardEnabled = false;
                }, 100);
            });
        }
    }

    setupClickOutsideHandler();
    updateUITheme();

    const actionButtons = settingsDiv.querySelectorAll('#closeSettingsButton, #createBackupButton, #restoreBackupButton');
    actionButtons.forEach(btn => {
        btn.style.cssText = `
            padding: 8px;
            background: none;
            border: none;
            cursor: pointer;
            color: ${colors.text};
        `;
    });

    // Add word input handler
    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();
            }
        });
    }

    // Add enter key handler for input
    document.getElementById('newWordInput').addEventListener('keypress', (e) => {
        if (e.key === 'Enter') {
            document.getElementById('addWordButton').click();
        }
    });

    // Only add merchant button listener if button exists
    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();
                }
            }
        });
    }

    // Add merchant list button listener
    document.getElementById('showMerchantListButton').addEventListener('click', () => {
        const btn = document.getElementById('showMerchantListButton');

        if (btn.hasAttribute('data-processing')) return;

        btn.setAttribute('data-processing', 'true');

        if (activeSubUI === 'merchant') {
            closeActiveSubUI();
            btn.innerHTML = '<i class="fas fa-store"></i> Händlerfilter verwalten';
            activeSubUI = null;
        } else {
            closeActiveSubUI();
            createMerchantListUI();
            activeSubUI = 'merchant';
            btn.innerHTML = '<i class="fas fa-times"></i> Händlerfilter ausblenden';
        }

        btn.removeAttribute('data-processing');
    });

    // Add words list button listener
    document.getElementById('showWordsListButton').addEventListener('click', () => {
        const btn = document.getElementById('showWordsListButton');

        if (activeSubUI === 'words') {
            closeActiveSubUI();
            btn.innerHTML = '<i class="fas fa-list"></i> Wortfilter verwalten';
            activeSubUI = null;
        } else {
            closeActiveSubUI();
            createExcludeWordsUI();
            activeSubUI = 'words';
            btn.innerHTML = '<i class="fas fa-times"></i> Wortfilter ausblenden';
        }
    });

    // Always ensure close button works
    document.getElementById('closeSettingsButton').addEventListener('click', (e) => {
        e.stopPropagation(); // Prevent event bubbling
        cleanup();
    });

    // Backup/Restore Event Listeners
    document.getElementById('createBackupButton').addEventListener('click', backupData);

    document.getElementById('restoreBackupButton').addEventListener('click', () => {
        document.getElementById('restoreFileInput').click();
    });

    document.getElementById('restoreFileInput').addEventListener('change', restoreData);

    // Add event listeners only if newWordInput exists
    const newWordInput = document.getElementById('newWordInput');
    if (newWordInput) {
        // 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);
    });

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

    const maxPriceInput = document.getElementById('maxPriceFilterInput'); // Note the correct ID
    if (maxPriceInput) {
        maxPriceInput.addEventListener('change', (e) => {
            const price = parseFloat(e.target.value);
            if (!isNaN(price) && price >= 0) {
                saveMaxPrice(price);
                processArticles();
            }
        });
    }

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

    // Scroll-Handling einrichten
    const cleanupScrollHandling = setupScrollHandling();

    // Cleanup erweitern
    const oldCleanup = cleanup;
    cleanup = () => {
        cleanupScrollHandling();
        oldCleanup();
    };
}

// Listen-Management
// 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;
        z-index: 1001;
        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="text-align: right;">
            <button id="closeMerchantListButton" style="padding: 8px 12px; background: none; border: none; cursor: pointer;" title="Schließen">
                <i class="fas fa-times"></i>
            </button>
        </div>
    `;

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

    // 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;
        z-index: 1001;
        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="text-align: right;">
            <button id="closeWordsListButton" style="padding: 8px 12px; background: none; border: none; cursor: pointer;" title="Schließen">
                <i class="fas fa-times"></i>
            </button>
        </div>
    `;

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

    // 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();
    });
}

// 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);
            });
        }
    }
}

// UI-Komponenten
// Wort zur Liste hinzufügen
function addWordToList(word, wordsList) {
    const div = document.createElement('div');
    div.className = 'word-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="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>
    `;

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

// 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);
}

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; /* Für besseres Scrolling auf iOS */
    `;

    // 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 });
    }

    // Rest of the function stays the same
    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);
    };

    // Add to existing cleanup function
    const oldCleanup = cleanup;
    cleanup = () => {
        cleanupListeners();
        oldCleanup();
    };
}

// UI-Styling
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;
            });
        }
    });
}

// Update word/merchant item styles in list creation
function updateItemStyles(item, colors) {
    item.style.cssText = `
        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;
    `;
}

// Update createMerchantListUI and createExcludeWordsUI
function updateListStyles(listDiv, colors) {
    // Apply styles to list items
    listDiv.querySelectorAll('.merchant-item, .word-item').forEach(item => {
        updateItemStyles(item, colors);
    });

    // Update search input
    const searchInput = listDiv.querySelector('input[type="text"]');
    if (searchInput) {
        searchInput.style.cssText = `
            width: 100%;
            padding: 5px;
            margin-bottom: 10px;
            background: ${colors.inputBg};
            border: 1px solid ${colors.border};
            color: ${colors.text};
            border-radius: 3px;
        `;
    }

    // Update clear button
    const clearButton = listDiv.querySelector('[id*="clear"]');
    if (clearButton) {
        clearButton.style.cssText = `
            width: 100%;
            padding: 5px 10px;
            background: ${colors.buttonBg};
            border: 1px solid ${colors.buttonBorder};
            color: ${colors.text};
            border-radius: 3px;
            cursor: pointer;
            margin-top: 10px;
        `;
    }
}

//
function getSubUIPosition() {
    if (IS_TOUCH_DEVICE) {
        return `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
        `;
    }
    return `
        position: fixed;
        top: 50%;
        left: calc(50% + 310px);
        transform: translate(-50%, -50%);
    `;
}

// Aktive Sub-UIs schließen
function closeActiveSubUI() {
    if (activeSubUI === 'merchant') {
        merchantListDiv?.remove();
        const btn = document.getElementById('showMerchantListButton');
        if (btn) {
            btn.innerHTML = '<i class="fas fa-store"></i> Händlerfilter verwalten';
            btn.removeAttribute('data-processing');
        }
    } else if (activeSubUI === 'words') {
        wordsListDiv?.remove();
        const btn = document.getElementById('showWordsListButton');
        if (btn) {
            btn.innerHTML = '<i class="fas fa-list"></i> Wortfilter verwalten';
        }
    }

    activeSubUI = null;
}

// --- 6. Event Handler ---
// 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')) {
            return;
        }

        // Get current UI states
        const settingsOpen = settingsDiv?.parentNode;
        const merchantsOpen = merchantListDiv?.parentNode;
        const wordsOpen = wordsListDiv?.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));

        if (clickedOutside) {
            cleanup();

            // Explicit cleanup of UI elements
            if (settingsDiv?.parentNode) settingsDiv.remove();
            if (merchantListDiv?.parentNode) merchantListDiv.remove();
            if (wordsListDiv?.parentNode) wordsListDiv.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);
}

// Wort-Auswahl Handler
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;
    }
}

// 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})`;
    }
}

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})`;
    }
}

// Add after other global functions
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;
}

// --- 7. Button-Management ---
// Button-Funktionen
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: ${isDarkMode() ? '#1d1f20' : '#ffffff'} !important;
            border: 1px solid ${isDarkMode() ? 'rgb(107, 109, 109)' : 'rgba(3,12,25,0.23)'} !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 {
                    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');
                hiddenDeals.push(dealId);
                saveHiddenDeals();
                hideDeal(deal);
                return false;
            };
        }

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

function addMerchantPageHideButton() {
    // Check if we're on a merchant page
    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;

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

    // Create hide button
    const hideButton = document.createElement('button');
    hideButton.innerHTML = '<i class="fas fa-store-slash"></i>';
    hideButton.title = `Alle Deals von ${merchantName} ausblenden`;
    hideButton.style.cssText = `
        padding: 8px;
        background: #f0f0f0;
        border: 1px solid #ccc;
        border-radius: 3px;
        cursor: pointer;
    `;

    // Add click handler
    hideButton.addEventListener('click', () => {
        const merchantsData = loadExcludeMerchants();

        // Check if ID already exists
        if (!merchantsData.some(m => m.id === merchantId)) {
            // Add new merchant at start of array
            merchantsData.unshift({ id: merchantId, name: merchantName });
            saveExcludeMerchants(merchantsData);
            processArticles();
        }
    });

    // Add button to page
    hideButtonContainer.appendChild(hideButton);
    merchantBanner.appendChild(hideButtonContainer);
}

// --- 8. Filter-System ---
// Filter-Funktionalität
function injectMaxPriceFilter() {
    const filterForm = document.querySelector('.subNavMenu-list form:first-of-type ul');
    if (!filterForm) return;

    // Get theme colors
    const colors = getThemeColors();
    const isDark = isDarkMode();

    // Create list items for the filters
    const filterItems = document.createElement('li');
    filterItems.innerHTML = `
        <!-- Cold Deals Toggle -->
        <div class="flex boxAlign-jc--all-sb boxAlign-ai--all-c space--h-3 space--v-3 subNavMenu-item--separator">
            <span class="subNavMenu-text mute--text space--r-2 overflow--wrap-off">Kalte Deals ausblenden</span>
            <label class="checkbox checkbox--brand checkbox--mode-special">
                <input
                    class="input checkbox-input"
                    type="checkbox"
                    id="hideColdDealsToggle"
                    ${hideColdDeals ? 'checked' : ''}
                >
                <span class="tGrid-cell tGrid-cell--shrink">
                    <span class="checkbox-box flex--inline boxAlign-jc--all-c boxAlign-ai--all-c">
                        <svg width="18px" height="14px" class="icon icon--tick checkbox-tick">
                            <use xlink:href="/assets/img/ico_707ed.svg#tick"></use>
                        </svg>
                    </span>
                </span>
            </label>
        </div>

        <!-- Price Filter -->
        <div class="flex boxAlign-jc--all-sb boxAlign-ai--all-c space--h-3 space--v-3">
            <span class="subNavMenu-text mute--text space--r-2 overflow--wrap-off">
                Maximalpreis filtern
            </span>
            <input
                type="text"
                inputmode="decimal"
                pattern="[0-9]*[.,]?[0-9]*"
                id="maxPriceFilterInput"
                value="${maxPrice.toLocaleString('de-DE', {
                    minimumFractionDigits: 0,
                    maximumFractionDigits: 2
                })}"
                placeholder="€"
                style="
                    width: 80px;
                    padding: 4px 8px;
                    border: 1px solid var(--border-color, ${isDarkMode() ? '#6b6d6d' : '#c5c7ca'});
                    border-radius: 4px;
                    margin-left: auto;
                    text-align: right;
                    background: ${isDark ? '#1d1f20' : colors.inputBg} !important;
                    color: ${colors.text};
                    font-size: 14px;
                    line-height: 1.5;
                "
            >
        </div>`;

    // Insert at the beginning of the filter form
    filterForm.appendChild(filterItems);

    // Add event listeners
    const coldDealsToggle = document.getElementById('hideColdDealsToggle');
    if (coldDealsToggle) {
        coldDealsToggle.addEventListener('change', (e) => {
            hideColdDeals = e.target.checked;
            GM_setValue('hideColdDeals', hideColdDeals);
            localStorage.setItem(HIDE_COLD_DEALS_KEY, hideColdDeals);
            processArticles();
        });
    }

    const priceInput = document.getElementById('maxPriceFilterInput');
    if (priceInput) {
        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');
            }
        };

        // Prevent menu from closing on mobile keyboard open
        if (IS_TOUCH_DEVICE) {
            const subNavMenu = document.querySelector('.subNavMenu');
            
            priceInput.addEventListener('focus', () => {
                // Add a class to prevent auto-close
                subNavMenu?.classList.add('keep-open');
                
                // Select all text
                priceInput.select();
                
                // Prevent any existing scroll handlers from closing the menu
                const preventClose = (e) => {
                    if (document.activeElement === priceInput) {
                        e.stopPropagation();
                    }
                };
                
                // Capture phase to intercept before other handlers
                window.addEventListener('scroll', preventClose, true);
                
                // Cleanup on blur
                const cleanup = () => {
                    subNavMenu?.classList.remove('keep-open');
                    window.removeEventListener('scroll', preventClose, true);
                    priceInput.removeEventListener('blur', cleanup);
                };
                
                priceInput.addEventListener('blur', cleanup, { once: true });
            });
        } else {
            // Desktop focus handler
            priceInput.addEventListener('focus', () => {
                priceInput.select();
            });
        }

        priceInput.addEventListener('input', (e) => {
            e.stopPropagation();
            e.target.value = formatPrice(e.target.value);
        });

        priceInput.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();
            }
        });
    }
}

// --- 9. Backup und Wiederherstellung ---
// Backup-Funktionen
function backupData() {
    try {
        // Aktuelle Daten neu laden
        const currentWords = loadExcludeWords();
        const currentMerchants = loadExcludeMerchants();

        // Backup mit aktuellen Daten erstellen
        const backup = {
            excludeWords: currentWords,
            merchantsData: currentMerchants, // Nur merchantsData speichern
            maxPrice: maxPrice,
            hideColdDeals: hideColdDeals
        };

        const blob = new Blob([JSON.stringify(backup, null, 2)], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
        a.href = url;
        a.download = `mydealz_backup_${timestamp}.json`;
        a.click();
        URL.revokeObjectURL(url);

    } catch (error) {
        alert('Fehler beim Erstellen des Backups: ' + error.message);
    }
}

// Backup wiederherstellen
function restoreData(event) {
    const file = event.target.files[0];
    if (!file || file.type !== 'application/json') {
        alert('Bitte wählen Sie eine gültige JSON-Datei aus.');
        return;
    }

    const reader = new FileReader();
    reader.onload = function(e) {
        try {
            const restoredData = JSON.parse(e.target.result);

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

            // Merge Wörter (Duplikate werden automatisch entfernt)
            restoredData.excludeWords.forEach(word => currentWords.add(word));
            const mergedWords = Array.from(currentWords);

            // Merge Händler (bei gleicher ID behält der existierende Eintrag Vorrang)
            restoredData.merchantsData.forEach(merchant => {
                if (!currentMerchants.has(merchant.id)) {
                    currentMerchants.set(merchant.id, merchant);
                }
            });
            const mergedMerchants = Array.from(currentMerchants.values());

            // Speichere zusammengeführte Daten
            GM_setValue('excludeWords', mergedWords);
            localStorage.setItem('excludeWords', JSON.stringify(mergedWords));
            excludeWords = mergedWords;

            saveExcludeMerchants(mergedMerchants);

            // Behalte existierende Einstellungen wenn vorhanden
            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);
            }

            if (isSettingsOpen) {
                updateUITheme();
            }
            processArticles();

            alert('Backup wurde erfolgreich wiederhergestellt.');

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

    reader.readAsText(file);
}

// --- 10. Hilfsfunktionen ---
// HTML dekodieren
function decodeHtml(html) {
    const txt = document.createElement('textarea');
    txt.innerHTML = html;
    return txt.value;
}

function cleanup() {
    // Remove settings UI
    if (settingsDiv?.parentNode) {
        settingsDiv.remove();
        isSettingsOpen = false;
    }

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

    // Close merchant & words lists
    if (merchantListDiv?.parentNode) merchantListDiv.remove();
    if (wordsListDiv?.parentNode) wordsListDiv.remove();

    // Reset UI states
    if (activeSubUI === 'merchant' || activeSubUI === 'words') {
        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;

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

    // Reset suggestion state
    suggestedWords = [];

    // Don't disconnect the main observer
    // Instead, reinitialize it to ensure it's working
    initObserver();
}

function resetUIState() {
    isSettingsOpen = false;
    activeSubUI = null;
    dealThatOpenedSettings = null;
    suggestedWords = [];

    settingsDiv?.remove();
    merchantListDiv?.remove();
    wordsListDiv?.remove();
}

// --- 11. Initialisierung ---
// Startup
function init() {
    // Daten synchronisieren
    syncStorage();
    excludeWords = loadExcludeWords();

    // UI initialisieren
    initializeUI();

    // Observer starten
    initObserver();
}

function initializeUI() {
    // Initial UI Setup
    processArticles();
    addSettingsButton();
    addHideButtons();
    addMerchantPageHideButton();

    // Initialize filter observer
    filterObserver.observe(document.body, {
        childList: true,
        subtree: true
    });

    // Add filters if menu already exists
    const filterMenu = document.querySelector('.subNavMenu-list');
    if (filterMenu) {
        injectMaxPriceFilter();
    }
}

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

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

// 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);
})();