Ultimate Steam Enhancer

Добавляет множество функций для улучшения взаимодействия с магазином и сообществом (Полный список на странице скрипта)

スクリプトをインストール?
作者が勧める他のスクリプト

SteamDB - Sales; Ultimate Enhancerも気に入るかもしれません

スクリプトをインストール
このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Ultimate Steam Enhancer
// @namespace    https://store.steampowered.com/
// @version      2.1.3
// @description  Добавляет множество функций для улучшения взаимодействия с магазином и сообществом (Полный список на странице скрипта)
// @author       0wn3df1x
// @license      MIT
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/15.7.1/nouislider.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/chartjs-plugin-datalabels.min.js
// @match        https://store.steampowered.com/*
// @match        *://*steamcommunity.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_getResourceText
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// @grant        GM_deleteValue
// @grant        unsafeWindow
// @connect      zoneofgames.ru
// @connect      raw.githubusercontent.com
// @connect      gist.githubusercontent.com
// @connect      store.steampowered.com
// @connect      api.steampowered.com
// @connect      steamcommunity.com
// @connect      community.akamai.steamstatic.com
// @connect      community.cloudflare.steamstatic.com
// @connect      community.fastly.steamstatic.com
// @connect      shared.akamai.steamstatic.com
// @connect      shared.cloudflare.steamstatic.com
// @connect      shared.fastly.steamstatic.com
// @connect      umadb.ro
// @connect      api.github.com
// @connect      howlongtobeat.com
// @connect      vgtimes.ru
// @connect      api.digiseller.com
// @connect      plati.market
// @connect      digiseller.mycdn.ink
// @connect      steambuy.com
// @connect      steammachine.ru
// @connect      playo.ru
// @connect      steampay.com
// @connect      gabestore.ru
// @connect      static.gabestore.ru
// @connect      gamersbase.store
// @connect      coreplatform.blob.core.windows.net
// @connect      cdn-contentprod.azureedge.net
// @connect      cdn-resize.enaza.games
// @connect      cdn-static.enaza.games
// @connect      www.igromagaz.ru
// @connect      gamesforfarm.com
// @connect      shared.fastly.steamstatic.com
// @connect      i.imgur.com
// @connect      zaka-zaka.com
// @connect      images.zaka-zaka.com
// @connect      gamazavr.ru
// @connect      gameray.ru
// @connect      shop.buka.ru
// @connect      upload.wikimedia.org
// @connect      keysforgamers.com
// @connect      api4.ggsel.com
// @connect      ggsel.net
// @connect      cdn.ggsel.com
// @connect      explorer.kupikod.com
// @connect      rushbe.ru
// @connect      cdn.jsdelivr.net
// @connect      img.shields.io
// ==/UserScript==


(function() {
    'use strict';

    const FALLBACK_REGIONS = ['us', 'ch', 'kz', 'jp'];

    function makeGMRequest(options) {
        return new Promise((resolve, reject) => {
            options.onload = (response) => {
                if (response.status >= 200 && response.status < 400) {
                    resolve(response);
                } else {
                    reject(new Error(`Запрос не удался, статус ${response.status}: ${options.method} ${options.url}`));
                }
            };
            options.onerror = (err) => reject(new Error(`Сетевая ошибка: ${options.method} ${options.url}. Details: ${JSON.stringify(err)}`));
            options.ontimeout = () => reject(new Error(`Таймаут: ${options.method} ${options.url}`));
            GM_xmlhttpRequest(options);
        });
    }

    function injectPageAndRunModules(responseText) {
        for (let i = 1; i < 99999; i++) {
            window.clearInterval(i);
            window.clearTimeout(i);
        }

        const injectionScript = `
            <script type="text/javascript">
                window.addEventListener('DOMContentLoaded', () => {
                    window.USE_unlocked_page_ready = true;
                    console.log('[U.S.E. Injected Script] DOMContentLoaded сработал, страница готова.');
                });
            </script>
        `;

        const modifiedResponseText = responseText.replace('</head>', `${injectionScript}</head>`);

        document.open();
        document.write(modifiedResponseText);
        document.close();

        const maxRetries = 40;
        let retries = 0;
        const readyCheckInterval = setInterval(() => {
            if (unsafeWindow.USE_unlocked_page_ready) {
                clearInterval(readyCheckInterval);
                console.log('[U.S.E. Userscript] Обнаружен сигнал готовности от новой страницы. Запускаем модули USE.');
                setTimeout(runUSEModules, 250);
            } else {
                retries++;
                if (retries > maxRetries) {
                    clearInterval(readyCheckInterval);
                    console.error('[U.S.E.] Время ожидания готовности страницы истекло. Пытаюсь запустить модули вслепую...');
                    setTimeout(runUSEModules, 250);
                }
            }
        }, 250);
    }

    async function handleComplexBypass() {
        const appId = window.location.pathname.match(/\/app\/(\d+)/)?.[1];
        if (!appId) {
            console.error('[U.S.E.] Не удалось определить AppID на странице.');
            return;
        }

        document.body.innerHTML = `
            <div style="font-family: 'Motiva Sans', sans-serif; color: #c7d5e0; background-color: #1b2838; text-align: center; padding: 100px 20px; height: 100vh; font-size: 1.8em; line-height: 1.5;">
                <p>Обнаружена региональная блокировка.</p>
                <p>Запускаю многоступенчатый обход...</p>
                <p id="use-unblock-status" style="font-size: 0.8em; color: #8f98a0; margin-top: 20px;"></p>
                <p style="font-size: 0.7em; color: #8f98a0;">(Ultimate Steam Enhancer)</p>
            </div>`;
        const statusElement = document.getElementById('use-unblock-status');
        const gameUrl = `https://store.steampowered.com/app/${appId}/`;

        try {
            await attemptBypassWithFallbacks(gameUrl, statusElement);
        } catch (error) {
            console.error('[U.S.E.] Ошибка в процессе обхода:', error);
            if (statusElement) {
                statusElement.textContent = `Ошибка: ${error.message}`;
                statusElement.style.color = '#ff6961';
            }
        }
    }

    async function getAnonymousSession(retryCount = 0) {
        const MAX_RETRIES = 2;
        console.log(`[U.S.E. Unblocker] Попытка #${retryCount + 1} получения анонимной сессии...`);

        const sessionUrl = 'https://store.steampowered.com/join/?l=russian';

        try {
            const response = await makeGMRequest({
                method: "GET",
                url: sessionUrl,
                headers: {
                    'Accept-Language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7'
                },
                anonymous: true
            });

            const headers = response.responseHeaders;

            const sessionidMatch = headers.match(/sessionid=([^;]+)/);
            const browseridMatch = headers.match(/browserid=([^;]+)/);

            const sessionid = sessionidMatch ? sessionidMatch[1] : null;
            const browserid = browseridMatch ? browseridMatch[1] : null;

            if (sessionid && browserid) {
                console.log(`[U.S.E. Unblocker] Успешно получены sessionid=${sessionid}, browserid=${browserid}`);
                return { sessionid, browserid };
            }

            console.warn('[U.S.E. Unblocker] Не удалось получить cookies с текущей попытки. Заголовки ответа:', { headers });

            if (retryCount < MAX_RETRIES) {
                await new Promise(resolve => setTimeout(resolve, 500));
                return getAnonymousSession(retryCount + 1);
            } else {
                throw new Error('Не удалось получить анонимный sessionid/browserid после нескольких попыток.');
            }

        } catch (error) {
            console.error(`[U.S.E. Unblocker] Ошибка при запросе сессии (попытка ${retryCount + 1}):`, error);
            if (retryCount < MAX_RETRIES) {
                await new Promise(resolve => setTimeout(resolve, 500));
                return getAnonymousSession(retryCount + 1);
            }
            throw error instanceof Error ? error : new Error('Не удалось выполнить запрос для получения анонимной сессии.');
        }
    }

    async function attemptBypassWithFallbacks(baseUrl, statusElement) {
        statusElement.textContent = 'Шаг 1: Получение анонимной сессии...';
        const { sessionid, browserid } = await getAnonymousSession();
        const baseCookies = `sessionid=${sessionid}; browserid=${browserid};`;
        const ageBypassCookies = `birthtime=631152001; wants_mature_content=1;`;

        const userDefaultRegion = GM_getValue('use_incognito_default_region', 'US').toLowerCase();
        const regionsToTry = [...new Set([userDefaultRegion, ...FALLBACK_REGIONS])];

        let success = false;

        for (let i = 0; i < regionsToTry.length; i++) {
            const regionCode = regionsToTry[i];
            const countryCookie = `steamCountry=${regionCode.toUpperCase()};`;
            const gamePageUrl = new URL(baseUrl);
            gamePageUrl.searchParams.set('cc', regionCode);
            gamePageUrl.searchParams.set('l', 'russian');

            statusElement.textContent = `Шаг ${i + 2}/${regionsToTry.length + 1}: Попытка обхода через регион [${regionCode.toUpperCase()}]...`;

            try {
                const initialPageResponse = await makeGMRequest({
                    method: "GET",
                    url: gamePageUrl.href,
                    headers: {
                        'Cookie': `${baseCookies} ${countryCookie}`,
                        'Accept-Language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7'
                    },
                    anonymous: true
                });

                let responseText = initialPageResponse.responseText;

                const isRegionBlocked = responseText.includes('Данный товар недоступен в вашем регионе') || responseText.includes('is not available in your country');

                if (isRegionBlocked) {
                    console.log(`[U.S.E.] Регион ${regionCode.toUpperCase()} заблокирован. Пробуем следующий.`);
                    continue;
                }

                if (responseText.includes('agegate_birthday_selector')) {
                    statusElement.textContent = `Регион [${regionCode.toUpperCase()}] успешен. Обход возрастного ограничения...`;

                    const finalPageResponse = await makeGMRequest({
                        method: "GET",
                        url: gamePageUrl.href,
                        headers: {
                            'Cookie': `${baseCookies} ${countryCookie} ${ageBypassCookies}`,
                            'Accept-Language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7'
                        },
                        anonymous: true
                    });

                    if (finalPageResponse.responseText.includes('agegate_birthday_selector')) {
                        console.error(`[U.S.E.] Не удалось обойти возрастное ограничение в регионе ${regionCode.toUpperCase()}.`);
                        continue;
                    }
                    responseText = finalPageResponse.responseText;
                }

                statusElement.textContent = `Успешно! Загрузка страницы из региона [${regionCode.toUpperCase()}]...`;
                injectPageAndRunModules(responseText);
                success = true;
                return;

            } catch (error) {
                console.warn(`[U.S.E.] Ошибка при попытке обхода через регион ${regionCode.toUpperCase()}:`, error.message);
            }
        }

        if (!success) {
            throw new Error('Не удалось обойти региональную блокировку ни через один из доступных регионов: ' + regionsToTry.join(', ').toUpperCase());
        }
    }

    function addIncognitoButton() {
        const isButtonEnabled = GM_getValue('use_incognito_button_enabled', false);
        if (!isButtonEnabled) {
            return;
        }

        if (document.getElementById('use-incognito-btn')) {
            return;
        }

        const logoHolder = document.getElementById('logo_holder');
        if (!logoHolder) {
            console.error('[U.S.E.] Не удалось найти #logo_holder для добавления кнопки.');
            return;
        }

        const incognitoBtn = document.createElement('a');
        incognitoBtn.href = 'javascript:void(0);';
        incognitoBtn.id = 'use-incognito-btn';
        incognitoBtn.innerText = 'in';
        incognitoBtn.title = 'Перезагрузить страницу в виртуальном режиме инкогнито (U.S.E.)';

        GM_addStyle(`
            #logo_holder {
                position: relative;
            }
            #use-incognito-btn {
                position: absolute;
                top: -7px;
                right: 100%;
                margin-right: 10px;
                transform: translateY(-50%);
                padding: 4px 10px;
                background-color: #C5C3C0;
                color: #171D25;
                font-weight: 500;
                font-size: 14px;
                border-radius: 3px;
                text-decoration: none;
                line-height: 1.5;
                box-shadow: 0 0 5px rgba(0,0,0,0.5);
                transition: all 0.2s ease-in-out;
            }
            #use-incognito-btn:hover {
                background-color: #171D25;
                color: white;
                text-decoration: none;
                transform: translateY(-50%) scale(1.05);
                box-shadow: 0 0 10px rgba(0,0,0,0.7);
            }
        `);

        logoHolder.appendChild(incognitoBtn);

        incognitoBtn.addEventListener('click', (e) => {
            e.preventDefault();
            console.log('[U.S.E.] Активация режима инкогнито вручную...');
            loadPageIncognito(window.location.href);
        });
    }

    async function loadPageIncognito(url) {
        document.body.innerHTML = `
            <div style="font-family: 'Motiva Sans', sans-serif; color: #c7d5e0; background-color: #1b2838; text-align: center; padding: 100px 20px; height: 100vh; font-size: 1.8em; line-height: 1.5;">
                <p>Перезагрузка страницы в режиме "Инкогнито"...</p>
                <p id="use-incognito-status" style="font-size: 0.8em; color: #8f98a0; margin-top: 20px;"></p>
                <p style="font-size: 0.7em; color: #8f98a0;">(Ultimate Steam Enhancer)</p>
            </div>`;
        const statusElement = document.getElementById('use-incognito-status');

        try {
            await attemptBypassWithFallbacks(url, statusElement);
        } catch (error) {
            console.error('[U.S.E.] Ошибка в процессе ручной загрузки в режиме инкогнито:', error);
            if (statusElement) {
                statusElement.textContent = `Произошла ошибка: ${error.message}`;
                statusElement.style.color = '#ff6961';
            }
        }
    }

    (function unblockerDispatcher() {
         const isIncognitoModeEnabled = GM_getValue('use_incognito_mode_enabled', true);

         if (isIncognitoModeEnabled && window.location.pathname.includes('/app/')) {
            const russianLockMessage = 'Данный товар недоступен в вашем регионе';
            const englishLockMessage = 'This item is currently unavailable in your region';
             const errorBox = document.getElementById('error_box');

             if (errorBox && (errorBox.innerText.includes(russianLockMessage) || errorBox.innerText.includes(englishLockMessage))) {
                 handleComplexBypass();
                 return;
             }
         }

         runUSEModules();
     })();


    function runUSEModules() {
    GM_addStyle('.banner_open_in_steam { display: none !important; }');
    addIncognitoButton();
    const scriptsConfig = {
        // Основные скрипты
        gamePage: true, // Скрипт для страницы игры (индикаторы о наличии русского перевода; получение дополнительных обзоров) | https://store.steampowered.com/app/*
        hltbData: true, // Скрипт для страницы игры (HLTB; получение сведений о времени прохождения) | https://store.steampowered.com/app/*
        friendsPlaytime: true, // Скрипт для страницы игры (Время друзей & Достижения) | https://store.steampowered.com/app/*
        earlyaccdata: true, // Скрипт для страницы игры (Ранний доступ) | https://store.steampowered.com/app/*
        zogInfo: true, // Скрипт для страницы игры (ZOG; получение сведение о наличии русификаторов) | https://store.steampowered.com/app/*
        platiSales: true, // Скрипт для страницы игры (Plati; отображение цен с Plati.Market) | https://store.steampowered.com/app/*
        salesMaster: true, // Скрипт для страницы игры (%; агрегатор цен из разных магазинов) | https://store.steampowered.com/app/*
        pageGiftHelper: true, // Скрипт для страницы игры, для проверки возможности отправки подарка друзьям в других странах | https://store.steampowered.com/app/*
        catalogInfo: true, // Скрипт для получения дополнительной информации об игре при наведении на неё на странице поиска по каталогу | https://store.steampowered.com/search/
        catalogHider: false, // Скрипт скрытия игр на странице поиска по каталогу | https://store.steampowered.com/search/
        newsFilter: true, // Скрипт для скрытия новостей в новостном центре: | https://store.steampowered.com/news/
        Kaznachei: true, // Скрипт для показа годовых и исторических продаж предмета на торговой площадке Steam | https://steamcommunity.com/market/listings/*
        homeInfo: true, // Скрипт для получения дополнительной информации об игре при наведении на неё на странице вашей активности Steam | https://steamcommunity.com/my/
        stelicasRoulette: true, //Скрипт для выбора случайной игры из ваших коллекций с помощью Stelicas и рулетки на странице вашей активности Steam | https://steamcommunity.com/my/
        Sledilka: true, // Скрипт для получения уведомлений об изменении дат/статуса игр (вишлист/библиотека) и показа календаря релизов | Глобально
        wishlistGiftHelper: true, // Скрипт для проверки возможности отправки подарка из списка желаемого друзьям в других странах | https://steamcommunity.com/my/wishlist/
        RuRegionalPriceAnalyzer: true, // Скрипт для страницы игры (Анализатор цен; цена РФ vs рекомендованная; рейтинг цен) | https://store.steampowered.com/app/*
        // Дополнительные настройки
        autoExpandHltb: false, // Автоматически раскрывать спойлер HLTB
        autoLoadReviews: false, // Автоматически загружать дополнительные обзоры
        toggleEnglishLangInfo: false, // Отображает данные об английском языке в дополнительной информации при поиске по каталогу и в активности (функция для переводчиков)
        salesMasterAutoSearch: false, // Автоматически запускать поиск при открытии окна "Агрегатора цен (%)"
        salesMasterAutoInsertTitle: true // Автоматически подставлять название игры в фильтр "Агрегатора цен (%)" после сбора данных
    };


    /* --- Код для настроек U.S.E. --- */
	const useDefaultSettings = {
	    gamePage: true, hltbData: true, friendsPlaytime: true, earlyaccdata: true, zogInfo: true, pageGiftHelper: true,
	    platiSales: true, salesMaster: true, catalogInfo: true, catalogHider: false, newsFilter: true,
	    Kaznachei: true, homeInfo: true, Sledilka: true, wishlistGiftHelper: true, stelicasRoulette: true, RuRegionalPriceAnalyzer: true,
	    autoExpandHltb: false, autoLoadReviews: false, toggleEnglishLangInfo: false,
        salesMasterAutoSearch: false, salesMasterAutoInsertTitle: true,
        incognitoModeEnabled: true, showIncognitoButton: false, incognitoDefaultRegion: 'US'
	};

    const useIncognitoRegions = {
        'AU': { name: 'Австралийский доллар' },
        'BR': { name: 'Бразильский реал' },
        'GB': { name: 'Британский фунт' },
        'VN': { name: 'Вьетнамский донг' },
        'HK': { name: 'Гонконгский доллар' },
        'AE': { name: 'Дирхам ОАЭ' },
        'US': { name: 'Доллар США' },
        'EU': { name: 'Евро' },
        'IL': { name: 'Израильский новый шекель' },
        'IN': { name: 'Индийская рупия' },
        'ID': { name: 'Индонезийская рупия' },
        'KZ': { name: 'Казахстанский тенге' },
        'CA': { name: 'Канадский доллар' },
        'QA': { name: 'Катарский риал' },
        'CN': { name: 'Китайский юань' },
        'CO': { name: 'Колумбийское песо' },
        'CR': { name: 'Коста-риканский колон' },
        'KW': { name: 'Кувейтский динар' },
        'AR': { name: 'Лат. Ам. - Доллар США' },
        'MY': { name: 'Малазийский ринггит' },
        'TR': { name: 'MENA - Доллар США' },
        'MX': { name: 'Мексиканское песо' },
        'NZ': { name: 'Новозеландский доллар' },
        'NO': { name: 'Норвежская крона' },
        'PE': { name: 'Перуанский соль' },
        'PL': { name: 'Польский злотый' },
        'RU': { name: 'Российский рубль' },
        'SA': { name: 'Саудовский риал' },
        'SG': { name: 'Сингапурский доллар' },
        'AZ': { name: 'СНГ - Доллар США' },
        'TW': { name: 'Тайваньский доллар' },
        'TH': { name: 'Тайский бат' },
        'UA': { name: 'Украинская гривна' },
        'UY': { name: 'Уругвайское песо' },
        'PH': { name: 'Филиппинское песо' },
        'CL': { name: 'Чилийское песо' },
        'CH': { name: 'Швейцарский франк' },
        'PK': { name: 'Юж. Азия - Доллар США' },
        'ZA': { name: 'Южноафриканский рэнд' },
        'KR': { name: 'Южнокорейская вона' },
        'JP': { name: 'Японская иена' }
    };

    const dependentModules = {
        gamePage: ['hltbData', 'zogInfo', 'friendsPlaytime']
    };

    let useCurrentSettings = { ...useDefaultSettings, ...GM_getValue('useSettings', {}) };

    Object.assign(scriptsConfig, useCurrentSettings);

    // --- Данные для настроек: метки, заголовки, описания и категории ---
    const settingInfo = {
        // --- Страница игры ---
        gamePage: {
            category: 'gamePage',
            label: "Индикаторы / Доп. обзоры / Монитор обзоров",
            title: "Индикаторы перевода, доп. обзоры и глобальный монитор обзоров",
            details: `
                <p><strong>Что делает:</strong></p>
                <ol style="margin-left: 20px; padding-left: 5px; list-style-type: decimal;">
                    <li style="margin-bottom: 0.7em;">Отображает значки-индикаторы наличия русского языка (интерфейс, озвучка, субтитры) прямо на странице игры.</li>
                    <li style="margin-bottom: 0.7em;">Добавляет под стандартными обзорами блок с расширенной статистикой (загружается по щелчку или автоматически, если включена опция):
                        <ul>
                            <li><strong>Тотальные:</strong> Все обзоры Steam (включая активации ключами).</li>
                            <li><strong>Безкитайские:</strong> Обзоры за исключением написанных на китайском языке.</li>
                            <li><strong>Русские:</strong> Только обзоры на русском языке.</li>
                        </ul>
                    </li>
                    <img src="https://i.imgur.com/fcdZh8b.png" alt="Пример индикаторов и обзоров 1" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                    <hr style="border: none; border-top: 1px solid #444a52; margin: 1.5em 0;">
                    <li style="margin-bottom: 0.7em;">Модальные окна:
                        <ul>
                             <li>При щелчке по строке "Русские" открывается окно с актуальными <strong>русскоязычными обзорами</strong> для этой игры.</li>
                             <img src="https://i.imgur.com/MOEyAlM.png" alt="Пример индикаторов и обзоров 2" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                             <hr style="border: none; border-top: 1px solid #444a52; margin: 1.5em 0;">
                             <li>При щелчке по строке "Тотальные" открывается окно <strong>"Глобальный монитор обзоров"</strong>. Этот инструмент позволяет собрать (по кнопке "Собрать") и визуализировать статистику обзоров по <strong>27 языкам</strong> Steam. Он показывает таблицу с рейтингом языков по количеству обзоров и доле в общей массе, а также интерактивную круговую диаграмму для наглядного представления.</li>
                             <img src="https://i.imgur.com/2azVyAW.png" alt="Пример индикаторов и обзоров 3" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                        </ul>
                    </li>
                </ol>
                <div style="margin-top: 15px; margin-bottom: 10px; padding: 10px; background-color: rgba(255, 179, 0, 0.1); border: 1px solid rgba(255, 179, 0, 0.4); border-radius: 4px; font-size: 0.95em; line-height: 1.4;">
                    <p style="margin: 0 0 5px 0; font-weight: bold; color: #FFB300;">⚠️ Важное замечание о зависимостях:</p>
                    <p style="margin: 0; color: #c6d4df;">Отключение этого модуля приведет к автоматическому отключению или нарушению корректной работы модулей «Время прохождения (HLTB)», «Русификаторы (ZOG)» и «Время друзей / Глобальные достижения», так как они критически зависят от его функционала по отображению элементов на странице игры.</p>
                </div>
            `
        },
        RuRegionalPriceAnalyzer: {
            category: 'gamePage',
            label: "Анализатор цен",
            title: "Анализатор цен",
            details: `
                <p><strong>Что делает:</strong> Добавляет кнопку "Анализатор цен" на страницу игры. Этот инструмент позволяет анализировать региональные цены двумя способами: в рублях (по умолчанию) и в долларах США.</p>

                <p>После нажатия кнопки "Сбор данных" в специальном окне, модуль выполняет следующее в зависимости от выбранного режима:</p>

                <div style="display: flex; gap: 20px; margin-top:10px; margin-bottom:10px;">
                    <div style="flex: 1; padding:10px; background-color: rgba(0,0,0,0.1); border-radius:4px;">
                        <h4 style="margin-top:0; color: #67c1f5;">Режим Рублей (по умолчанию):</h4>
                        <ul>
                            <li>Определяет AppID текущей игры и запрашивает цены через официальное API Steam (<code>IStoreBrowseService/GetItems</code>) для множества регионов.</li>
                            <li>В качестве базы для расчета <strong>рекомендованной рублевой цены</strong> используется цена в США (USD).</li>
                            <li>Цены из всех регионов, включая Россию, <strong>конвертируются в рубли</strong> по актуальным обменным курсам для прямого сопоставления.</li>
                            <li>Производится ключевое сравнение: фактическая цена в российском Steam сопоставляется с <strong>официально рекомендованной Valve ценой для России</strong>. Отклонения подсвечиваются.</li>
                            <li>Отображается <strong>рейтинг российской цены</strong> среди всех проанализированных стран, позволяя увидеть её место от самой дешёвой к самой дорогой в рублевом эквиваленте.</li>
                        </ul>
                    </div>
                    <div style="flex: 1; padding:10px; background-color: rgba(0,0,0,0.1); border-radius:4px;">
                        <h4 style="margin-top:0; color: #67c1f5;">Режим Долларов США (переключаемый):</h4>
                        <ul>
                            <li>Активируется кнопкой "USD" в окне анализатора. Интерфейс и названия валют <strong>переключаются на английский язык</strong>.</li>
                            <li>Цены всех регионов также запрашиваются через API Steam и <strong>конвертируются в доллары США</strong>.</li>
                            <li>Цена в США используется как <strong>базовый ориентир (100%)</strong> для сравнения.</li>
                            <li>Отображается <strong>процентное отклонение</strong> цен других регионов от цены в США.</li>
                            <li>Представляется общий рейтинг всех региональных цен в долларовом эквиваленте.</li>
                            <li>Этот режим полезен для оценки ценовой политики при общении с разработчиками/издателями.</li>
                        </ul>
                    </div>
                </div>

                <p>В обоих режимах, если игра в США бесплатна или цена не найдена, возможности анализа могут быть ограничены. Вся собранная информация представляется в модальном окне.</p>

                <div style="margin-top: 15px; padding: 10px; background-color: rgba(103, 193, 245, 0.1); border: 1px solid rgba(103, 193, 245, 0.35); border-radius: 4px; font-size: 0.95em; line-height: 1.4;">
                    <p style="margin: 0 0 5px 0; font-weight: bold; color: #67c1f5;">⚠️ Важная информация:</p>
                    <p style="margin: 0; color: #c6d4df;">Каждый полный сбор данных подразумевает отправку <strong>~41 запроса</strong> к серверам Steam (количество зависит от числа доступных регионов). Пожалуйста, используйте эту функцию обдуманно. Частое нажатие кнопки на разных играх в течение короткого периода времени может привести к временному ограничению доступа к API Steam (обычно на 5-15 минут).</p>
                </div>
                <img src="https://i.imgur.com/OzebvaA.png" alt="Пример интерфейса анализатора цен" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
            `
        },
        hltbData: {
            category: 'gamePage',
            label: "Время прохождения (HLTB)",
            title: "Время прохождения HLTB",
            details: `
                <p><strong>Что делает:</strong> Добавляет компактный блок с информацией о времени прохождения игры, полученной с популярного сайта HowLongToBeat.com.</p>
                <p>Показывает среднее время для разных стилей:</p>
                <ul>
                    <li>Только основной сюжет.</li>
                    <li>Сюжет + дополнительные задания.</li>
                    <li>Полное прохождение (100%).</li>
                    <li>Усредненное время для всех стилей.</li>
                </ul>
                <p>Рядом со временем указывается количество игроков, на чьих данных основана статистика. Поиск игры в базе HLTB идет по названию, при неоднозначности предлагается выбор из похожих вариантов.</p>
                <img src="https://i.imgur.com/6tgxA2s.png" alt="Пример HLTB 1" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
            `
        },
        platiSales: {
            category: 'gamePage',
            label: "Поиск цен Plati.Market",
            title: "Поиск цен на Plati.Market",
            details: `
                <p><strong>Что делает:</strong> Добавляет кнопку "Plati" рядом с кнопкой "В желаемое" на странице игры. Нажатие открывает полноэкранное окно для поиска предложений по этой игре на торговой площадке Plati.Market.</p>
                <p><strong>Возможности окна поиска:</strong></p>
                <ul>
                    <li>Автозаполнение поиска названием текущей игры.</li>
                    <li>Ручной ввод и поиск.</li>
                    <li>Подсказки при вводе (API Plati).</li>
                    <li>Сортировка по цене, продажам, релевантности, названию, дате, рейтингу продавца и др.</li>
                    <li>Фильтрация по цене (RUR, USD, EUR, UAH), продажам, рейтингу, наличию плохих отзывов/возвратов, участию в скидках, дате добавления.</li>
                    <li>Исключение товаров по ключевым словам (панель справа).</li>
                    <li>Сохранение фильтров, сортировки, валюты и исключений.</li>
                    <li>Возможность экспортировать и импортировать список исключений.</li>
                </ul>
                 <p>Используются официальные API Plati.Market.</p>
               <img src="https://i.imgur.com/lyL8i5g.png" alt="Кнопка Plati" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                <img src="https://i.imgur.com/X5NDh6D.png" alt="Окно Plati" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
            `
        },
        zogInfo: {
            category: 'gamePage',
            label: "Русификаторы (ZOG)",
            title: "Информация о наличии переводов с ZOG (ZoneOfGames)",
            details: `
                <p><strong>Что делает:</strong> Добавляет блок с информацией о наличии русификаторов для игры на сайте ZoneOfGames.ru.</p>
                <p>В блоке отображается:</p>
                <ul>
                    <li>Название игры (ведет на страницу игры в базе ZOG).</li>
                    <li>Список доступных русификаторов. Каждая запись является ссылкой на соответствующий файл/страницу на ZOG.</li>
                    <li>Если переводы не найдены, выводится соответствующее сообщение.</li>
                </ul>
                <p>Поиск происходит в <strong>реальном времени</strong>. Скрипт автоматически определяет название игры, выполняет поиск по алфавитному указателю на ZoneOfGames.ru и предлагает вам выбрать наиболее точное совпадение.</p>
                <img src="https://i.imgur.com/XgAVWAp.png" alt="Пример ZOG 21" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
            `
        },
        salesMaster: {
            category: 'gamePage',
            label: "Агрегатор цен (%)",
            title: "Агрегатор цен (%)",
            details: `
                <p><strong>Что делает:</strong> Добавляет кнопку "%" рядом с кнопкой "В желаемое" на странице игры. Нажатие открывает модальное окно с ценами на эту игру из различных цифровых магазинов.</p>
                <p><strong>Возможности окна агрегатора:</strong></p>
                <ul>
                    <li>Отображение предложений из магазинов: SteamBuy, Playo, SteamPay, Gabestore, GamersBase, Igromagaz, GamesForFarm, Gamazavr, GameRay, KupiKod, KeysForGamers, Zaka-zaka, Buka, GGSEL, Plati.Market, Rushbe и текущей страницы Steam.</li>
                    <li>Переключение валют: Возможность просмотра всех цен в рублях (RUB, по умолчанию) или в долларах США (USD), с автоматической конвертацией по актуальному курсу. Выбор валюты сохраняется.</li>
                    <li>Сортировка по цене, проценту скидки, сумме скидки, названию.</li>
                    <li>Фильтрация по диапазону цен, проценту и сумме скидки, наличию скидки, названию (слова через ";"), магазинам.</li>
                    <li>Исключение товаров по ключевым словам.</li>
                    <li>Сохранение состояния фильтров, сортировки и исключений.</li>
                    <li>Возможность экспортировать и импортировать список исключений.</li>
                </ul>
                 <p>Использует различные методы для получения цен (API, парсинг HTML).</p>
                <img src="https://i.imgur.com/PsrocCt.png" alt="Пример Агрегатора 1" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                <img src="https://i.imgur.com/DcidcTe.png" alt="Пример Агрегатора 2" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
            `
        },
        friendsPlaytime: {
            category: 'gamePage',
            label: "Время друзей / Глобальные достижения",
            title: "Информация о времени друзей и статистике достижений",
            details: `
                <p><strong>Что делает:</strong> Добавляет на страницу игры два независимых блока, расширяющих информацию о действиях ваших друзей и глобальной статистике достижений.</p>

                <h4 style="color: #67c1f5; border-bottom: 1px solid #444a52; padding-bottom: 5px; margin-top: 20px;">1. Плавающий блок статистики (у шапки игры)</h4>
                <p>Справа от изображения игры появляется компактный значок, при нажатии на который загружается и отображается сводная статистика:</p>
                <div style="display: flex; gap: 20px; margin-top:10px; margin-bottom:10px;">
                    <div style="flex: 1;">
                        <p><strong>Время друзей:</strong></p>
                        <ul>
                            <li>Максимальное время в игре (и ник друга со ссылкой).</li>
                            <li>Среднее время (с указанием кол-ва друзей).</li>
                            <li>Минимальное время в игре.</li>
                        </ul>
                    </div>
                    <div style="flex: 1;">
                        <p><strong>Глобальные достижения:</strong></p>
                        <ul>
                            <li>Процент "платины" (самое редкое достижение).</li>
                            <li>Средний прогресс выполнения всех достижений.</li>
                        </ul>
                    </div>
                </div>
                <img src="https://i.imgur.com/9TaMCbZ.png" alt="Пример Время друзей / Ачивки" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">

                <hr style="border: none; border-top: 1px solid #444a52; margin: 1.5em 0;">

                <h4 style="color: #67c1f5; border-bottom: 1px solid #444a52; padding-bottom: 5px; margin-top: 20px;">2. Информационный блок друзей (в правой колонке)</h4>
                <div style="margin-top: 10px; margin-bottom: 15px; padding: 10px; background-color: rgba(255, 179, 0, 0.1); border: 1px solid rgba(255, 179, 0, 0.4); border-radius: 4px; font-size: 0.95em; line-height: 1.4;">
                    <p style="margin: 0 0 5px 0; font-weight: bold; color: #FFB300;">⚠️ Важное примечание:</p>
                    <p style="margin: 0; color: #c6d4df;">Этот блок появляется только в том случае, если Steam не отображает на странице стандартный блок с рекомендациями друзей (например, на страницах, открытых с помощью виртуального режима инкогнито).</p>
                </div>
                <p>Скрипт добавляет в правую колонку подробный список друзей, взаимодействовавших с игрой, сгруппированный по категориям:</p>
                <ul>
                    <li>Друзья, игравшие недавно (за последние 2 недели).</li>
                    <li>Все друзья, когда-либо игравшие в игру (объединяет недавних и игравших ранее).</li>
                    <li>Все друзья, имеющие игру в библиотеке.</li>
                    <li>Друзья, которые добавили игру в свой список желаемого.</li>
                </ul>
                <p>Каждая категория сопровождается сеткой из шести аватаров друзей со ссылками на их профили.</p>
                <img src="https://i.imgur.com/6jbZ03L.png" alt="Пример" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
            `
        },
        pageGiftHelper: {
            category: 'gamePage',
            label: "Доступность подарков (страница игры)",
            title: "Доступность подарков (страница игры)",
            details: `
                <p><strong>Что делает:</strong> Добавляет кнопку "GIFT" в блок с кнопкой "В желаемое" на странице игры.</p>
                <p>Нажатие открывает окно, где можно:</p>
                <ul>
                    <li>Выбрать регион друга из списка.</li>
                    <li>Нажать "Узнать", чтобы запросить цену игры в этом регионе.</li>
                    <li>Увидеть цену друга (сконвертированную в вашу валюту), процент разницы и вердикт (<span style="color:#77dd77; font-weight:bold;">Можно подарить</span> / <span style="color:#ff6961; font-weight:bold;">Нельзя подарить</span>), основанный на правилах Steam о разнице цен (±10%).</li>
                </ul>
                <p>Использует те же механизмы получения цен и курсов валют, что и помощник для списка желаемого.</p>
                 <img src="https://i.imgur.com/jDdf4pR.png" alt="Пример PageGiftHelper 1" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                `
        },
        earlyaccdata: {
            category: 'gamePage',
            label: "Индикатор раннего доступа",
            title: "Индикатор раннего доступа",
            details: `
                <p><strong>Что делает:</strong> Показывает небольшую плашку над изображением игры с информацией о статусе раннего доступа (Early Access).</p>
                <ul>
                    <li><strong>Если игра еще в раннем доступе:</strong> Отображается, сколько времени игра уже находится в нем (например, "В раннем доступе уже 1 год и 3 месяца").</li>
                    <img src="https://i.imgur.com/6iGlcTf.png" alt="Пример Раннего Доступа 2" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                    <hr style="border: none; border-top: 1px solid #444a52; margin: 1.5em 0;">
                    <li><strong>Если игра вышла из раннего доступа:</strong> Отображается, сколько времени игра провела в нем до релиза (например, "Вышла спустя 2 года раннего доступа").</li>
                    <img src="https://i.imgur.com/SPzJrpi.png" alt="Пример Раннего Доступа 1" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                </ul>
                <p>Расчет времени динамический. Использует даты со страницы Steam, а также может подтягивать дату старта раннего доступа из собственной базы для вышедших игр, если Steam ее не показывает.</p>
            `
        },

        // --- Каталог ---
        catalogInfo: {
            category: 'catalog',
            label: "Доп. инфо / Фильтры",
            title: "Дополнительная информация и фильтрация в каталоге поиска",
            details: `
                <p><strong>Что делает:</strong> Расширяет функционал страницы поиска по каталогу Steam (<a href="https://store.steampowered.com/search/" target="_blank" style="color:#67c1f5;">store.steampowered.com/search/</a>).</p>
                <p><strong>При наведении:</strong></p>
                <ul>
                    <li>Появляется всплывающая подсказка слева от строки игры с подробной информацией: издатели, разработчики, серия, отзывы (% и кол-во), статус раннего доступа, поддержка русского/английского языков, первые 5 меток, краткое описание.</li>
                    <img src="https://i.imgur.com/U7DYIvJ.png" alt="Пример Доп. Инфо" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                </ul>
                <hr style="border: none; border-top: 1px solid #444a52; margin: 1.5em 0;">
                <p><strong>Фильтры (панель справа):</strong></p>
                <ul>
                    <li><strong>Русский перевод:</strong>
                        <ul>
                            <li><em>Только текст:</em> Игры с рус. интерфейсом/субтитрами (без озвучки).</li>
                            <li><em>Озвучка:</em> Игры с русской озвучкой.</li>
                            <li><em>Без перевода:</em> Игры без русского языка.</li>
                        </ul>
                    <img src="https://i.imgur.com/nLfsBzR.png" alt="Пример Фильтра Языка" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                    </li>
                    <hr style="border: none; border-top: 1px solid #444a52; margin: 1.5em 0;">
                     <li><strong>DLC:</strong>
                        <ul>
                            <li><em>Только ваши DLC:</em> Показывает только DLC для игр, которые есть в вашей библиотеке (сами DLC подсвечиваются фиолетовым фоном).</li>
                        </ul>
                    </li>
                    <img src="https://i.imgur.com/MqjuXoD.png" alt="Пример Фильтра DLC" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                </ul>
                 <p>Фильтры применяются динамически по мере получения данных от API.</p>
            `
        },
        catalogHider: {
            category: 'catalog',
            label: "Скрытие игр",
            title: "Система скрытия игр в каталоге поиска",
            details: `
                <p><strong>Что делает:</strong> Добавляет инструменты для массового скрытия неинтересующих игр прямо со страницы поиска по каталогу.</p>
                <p><strong>Элементы интерфейса:</strong></p>
                <ul>
                    <li>Счетчик отображаемых игр (слева вверху).</li>
                    <li>Чекбокс слева от каждой игры (кроме уже купленных/скрытых/в желаемом) для отметки на скрытие.</li>
                    <li>Кнопка "Скрыть выбранное" (слева вверху).</li>
                </ul>
                <p><strong>Принцип работы:</strong></p>
                <ol>
                    <li>Отмечаете чекбоксами игры, которые хотите скрыть.</li>
                    <li>Нажимаете "Скрыть выбранное".</li>
                    <li>Скрипт добавляет эти игры в ваш официальный список игнорируемых в Steam и удаляет их элементы со страницы.</li>
                </ol>
                <p>В отличие от стандартного механизма Steam, элементы полностью удаляются из DOM, что улучшает производительность при работе с большим количеством результатов.</p>
                <p><strong>Внимание:</strong> Рекомендуется использовать только при необходимости массового скрытия. Для обычного просмотра каталога лучше отключать эту опцию.</p>
                <img src="https://i.imgur.com/uCA8x2P.png" alt="Пример Скрытия Игр" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
            `
        },
         // --- Сообщество / Активность ---
        homeInfo: {
            category: 'community',
            label: "Доп. инфо в ленте активности",
            title: "Дополнительная информация в ленте активности Steam",
            details: `
                <p><strong>Что делает:</strong> Добавляет всплывающую подсказку при наведении на название игры в вашей ленте активности Steam (<a href="https://steamcommunity.com/my/home" target="_blank" style="color:#67c1f5;">steamcommunity.com/my/home</a>).</p>
                <p>Подсказка содержит подробную информацию об игре, аналогичную той, что показывается в каталоге поиска:</p>
                <ul>
                    <li>Название и изображение-шапка.</li>
                    <li>Дата выхода.</li>
                    <li>Издатели, разработчики, серия игр.</li>
                    <li>Отзывы (% и кол-во).</li>
                    <li>Статус раннего доступа.</li>
                    <li>Поддержка русского и английского языков.</li>
                    <li>Первые 5 меток.</li>
                    <li>Краткое описание.</li>
                </ul>
                 <p>Данные загружаются через API Steam.</p>
                 <img src="https://i.imgur.com/xE75iU8.png" alt="Пример Инфо в Ленте" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
           `
        },
        stelicasRoulette: {
            category: 'community',
            label: "Рулетка Stelicas",
            title: "Рулетка Stelicas - Случайный выбор игры из ваших коллекций",
            details: `
                <p><strong>Что делает:</strong> Добавляет блок "Рулетка Stelicas" на страницу вашей активности Steam (<a href="https://steamcommunity.com/my/home" target="_blank" style="color:#67c1f5;">steamcommunity.com/my/home</a>). Позволяет загрузить CSV-файл, сгенерированный приложением <a href="https://github.com/0wn3dg0d/Stelicas" target="_blank" style="color:#67c1f5;">Stelicas</a>, применить к нему разнообразные фильтры и случайным образом выбрать игру из вашей коллекции.</p>
                <p><strong>Возможности:</strong></p>
                <ul style="margin-left: 20px; padding-left: 5px; list-style-type: disc;">
                    <li style="margin-bottom: 0.5em;">Загрузка CSV-данных из Stelicas (содержащих информацию о ваших играх и коллекциях).</li>
                    <li style="margin-bottom: 0.5em;"><strong>Система фильтрации:</strong> по категориям коллекций Stelicas, дате выхода, пользовательским тегам, поддержке русского языка (интерфейс, субтитры, озвучка), а также по диапазонам количества отзывов и общего рейтинга игры.</li>
                    <li style="margin-bottom: 0.5em;">Анимированная рулетка для выбора случайной игры из отфильтрованного списка.</li>
                    <li style="margin-bottom: 0.5em;">Возможность включить приоритет по отзывам и рейтингу, чтобы игры с лучшими показателями имели больше шансов на выпадение.</li>
                    <li style="margin-bottom: 0.5em;">Переключение в режим <strong>просмотра всей отфильтрованной подборки</strong> игр в виде удобных карточек (изображение и название).</li>
                    <li style="margin-bottom: 0.5em;">Отображение подробной информации о выбранной (или просматриваемой в подборке) игре: постер, название, рейтинг и количество отзывов, краткое описание, основные теги, точная дата выхода, разработчики/издатели, информация о поддержке русского языка.</li>
                    <li style="margin-bottom: 0.5em;">Прямые ссылки на страницу игры в сообществе Steam и для её запуска через протокол <code>steam://run/&lt;AppID&gt;</code>.</li>
                </ul>
                <p><strong>Как пользоваться:</strong></p>
                <ul style="margin-left: 20px; padding-left: 5px; list-style-type: disc;">
                    <li style="margin-bottom: 0.5em;">Подробная инструкция по подготовке CSV-файла и использованию всех функций рулетки доступна по нажатию на значок вопроса <strong>?</strong> в правом верхнем углу окна самой рулетки.</li>
                </ul>
                <p><em>Примечание: Качество работы и полнота информации в рулетке напрямую зависят от корректности и актуальности данных в предоставленном CSV-файле из Stelicas.</em></p>
                <img src="https://i.imgur.com/KDfW10m.png" alt="Пример модального окна Рулетки Stelicas с фильтрами" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333; border-radius: 4px;">
            `
        },
        // --- Торговая площадка ---
        Kaznachei: {
            category: 'market',
            label: "Продажи предмета",
            title: "Информация об исторических продажах на торговой площадке Steam",
            details: `
                <p><strong>Что делает:</strong> Добавляет информационный блок на страницу предмета на торговой площадке Steam (<a href="https://steamcommunity.com/market/" target="_blank" style="color:#67c1f5;">steamcommunity.com/market/</a>).</p>
                <p>Блок содержит:</p>
                <ul>
                    <li>Таблицу с историей продаж по годам:
                        <ul>
                            <li>Общая сумма продаж за год (в рублях).</li>
                            <li>Примерная сумма, полученная разработчиком игры.</li>
                            <li>Примерная сумма, полученная Valve.</li>
                        </ul>
                    </li>
                    <li>Итоговую сумму продаж за все время.</li>
                    <li>Итоговые суммы, полученные разработчиком и Valve.</li>
                </ul>
                 <p>Данные загружаются через API истории цен Steam.</p>
                <img src="https://i.imgur.com/ZPnzyNH.png" alt="Пример Продаж 1" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
            `
        },
         // --- Новости / Список желаемого ---
        Sledilka: {
            category: 'news_wishlist',
            label: "Наблюдатель (Желаемое/Библиотека)",
            title: "Наблюдатель: Отслеживание изменений в списке желаемого и библиотеке",
            details: `
                <p><strong>Что делает:</strong> Отслеживает изменения в вашем списке желаемого Steam и в вашей библиотеке игр, отображает календарь релизов.</p>
                <p><strong>Основные функции:</strong></p>
                <ol style="margin-left: 20px; padding-left: 5px; list-style-type: decimal;">
                    <li style="margin-bottom: 0.7em;">В правом верхнем углу страниц Steam появляется кнопка "Наблюдатель".</li>
                    <li style="margin-bottom: 0.7em;"><strong>Индикаторы статуса (Ж/Б):</strong> Показывают, как давно обновлялись данные для <strong>Ж</strong>елаемого и <strong>Б</strong>иблиотеки.</li>
                    <li style="margin-bottom: 0.7em;"><strong>Счетчик уведомлений:</strong> Показывает количество новых (непрочитанных) изменений.</li>
                    <li style="margin-bottom: 0.7em;"><strong>Панель уведомлений (по щелчку на кнопку):</strong>
                        <ul style="margin-top: 0.8em; margin-left: 15px; list-style-type: disc;">
                            <li style="margin-bottom: 0.5em;">Кнопка "Обновить" для ручного запуска проверки (использует Steam API).</li>
                            <li style="margin-bottom: 0.5em;"><strong>Настройки (значок ⚙️):</strong> Открывает выпадающее меню с опциями:
                                <ul style="margin-top: 0.5em; margin-left: 15px; list-style-type: square;">
                                    <li style="margin-bottom: 0.3em;"><strong>Список желаемого / Библиотека:</strong> Позволяют включать/отключать проверку для каждой из секций.</li>
                                    <li style="margin-bottom: 0.3em;"><strong>Перепроверять игры с русским:</strong> <em>(Опция для Библиотеки)</em>. По умолчанию включена. Если её <strong>отключить</strong>, скрипт пропустит проверку игр, для которых уже известно о наличии <strong>любой</strong> русской локализации. Это значительно ускоряет повторные обновления.</li>
                                    <li style="margin-bottom: 0.3em;"><strong>...только без полной локализации:</strong> <em>(Доступна, если предыдущая опция отключена)</em>. Если включить, то из повторной проверки будут исключаться только игры с <strong>полной</strong> локализацией (интерфейс+озвучка+субтитры). Игры с частичным переводом продолжат проверяться.</li>
                                </ul>
                            </li>
                            <li style="margin-bottom: 0.5em;">Список изменений:
                                <ul style="margin-top: 0.5em; margin-left: 15px; list-style-type: square;">
                                    <li style="margin-bottom: 0.3em;"><strong>Список желаемого:</strong> Изменение даты выхода, статуса раннего доступа или русского языка.</li>
                                    <li style="margin-bottom: 0.3em;"><strong>Библиотека:</strong> Выход игры из раннего доступа, появление/изменение русского языка (и тип локализации).</li>
                                </ul>
                            </li>
                            <li style="margin-bottom: 0.5em;">Кнопки для отметки уведомления как прочитанного (конверт) или удаления (крестик).</li>
                            <li style="margin-bottom: 0.5em;">Кнопка "Очистить" для удаления всех уведомлений.</li>
                            <li style="margin-bottom: 0.5em;">Кнопка "Календарь".</li>
                            <li style="margin-bottom: 0.5em;">Кнопка "Хранилище" для очистки сохраненных данных.</li>
                        </ul>
                     </li>
                     <img src="https://i.imgur.com/BpuDq6U.png" alt="Пример Трекера 1" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                     <hr style="border: none; border-top: 1px solid #444a52; margin: 1.5em 0;">
                     <li style="margin-bottom: 0.7em;"><strong>Календарь релизов (по щелчку на кнопку "Календарь"):</strong>
                        <ul style="margin-top: 0.8em; margin-left: 15px; list-style-type: disc;">
                            <li style="margin-bottom: 0.5em;">Отображает игры из вашего списка желаемого в виде календаря по месяцам.</li>
                            <li style="margin-bottom: 0.5em;">Показывает игры с точными датами выхода в будущем.</li>
                            <li style="margin-bottom: 0.5em;">Для игр с примерной датой (месяц, квартал, год) отображается подсказка при наведении.</li>
                            <li style="margin-bottom: 0.5em;">Позволяет подгружать следующие месяцы.</li>
                        </ul>
                     </li>
                     <img src="https://i.imgur.com/b5PDYG3.png" alt="Пример Календаря" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                     <hr style="border: none; border-top: 1px solid #444a52; margin: 1.5em 0;">
                      <li style="margin-bottom: 0.7em;"><strong>Хранилище (по щелчку на кнопку "Хранилище"):</strong>
                        <ul style="margin-top: 0.8em; margin-left: 15px; list-style-type: disc;">
                            <li style="margin-bottom: 0.5em;">Позволяет очистить кэш дат/статусов для списка желаемого или для игр библиотеки.</li>
                        </ul>
                     </li>
                     <img src="https://i.imgur.com/nI6Uoo0.png" alt="Пример Хранилища" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                </ol>
                <p>Требует авторизации. Обработка больших списков/библиотек может занять время. Используйте новые опции в настройках для ускорения сканирования библиотеки.</p>
            `
        },
        newsFilter: {
            category: 'news_wishlist',
            label: "Фильтр новостей",
            title: "Система скрытия новостей в новостном центре",
            details: `
                <p><strong>Что делает:</strong> Позволяет гибко управлять отображением новостей в новостном центре Steam (<a href="https://store.steampowered.com/news/" target="_blank" style="color:#67c1f5;">store.steampowered.com/news/</a>), скрывая неинтересные материалы.</p>
                <p><strong>Основные возможности и использование:</strong></p>
                <ol style="margin-left: 20px; padding-left: 5px; list-style-type: decimal;">
                    <li style="margin-bottom: 0.7em;">
                        <strong>Выбор новостей для скрытия:</strong>
                        <ul>
                            <li>На каждой новости в правой части изображения появляется крупный квадратный чекбокс.</li>
                            <li>При установке галочки новость становится полупрозрачной (<em>"мягкое" скрытие</em>) и отмечается для последующего подтверждения скрытия. Повторный щелчок снимает отметку.</li>
                        </ul>
                    </li>
                    <li style="margin-bottom: 0.7em;">
                        <strong>Панель управления (справа вверху):</strong>
                        <ul>
                            <li><strong>"Скрыть выбранные (X)":</strong> Нажатие этой кнопки перемещает все отмеченные (полупрозрачные) новости в постоянное хранилище. Новость исчезает с экрана (или становится затемненной, если включен режим "Показать скрытое"). Счетчик в скобках показывает, сколько новостей сейчас выбрано.</li>
                            <li><strong>"В хранилище: X":</strong> Эта надпись показывает общее количество новостей, находящихся в вашем постоянном хранилище скрытых новостей.</li>
                            <li><strong>"Отменить":</strong> Появляется после подтверждения скрытия и активна 6 секунд. Позволяет отменить последнее действие по добавлению новостей в хранилище.</li>
                            <li><strong>"Показать скрытое" / "Спрятать скрытое":</strong> Переключатель. Если выбрано "Показать скрытое", новости из вашего хранилища будут отображаться в ленте, но в затемненном виде. В режиме "Спрятать скрытое" они полностью исчезают.</li>
                            <li><strong>"Хранилище":</strong> Открывает модальное окно для управления списком постоянно скрытых новостей.</li>
                        </ul>
                    </li>
                <img src="https://i.imgur.com/iYTtyWk.png" alt="Пример интерфейса фильтра новостей" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                     <hr style="border: none; border-top: 1px solid #444a52; margin: 1.5em 0;">
                    <li style="margin-bottom: 0.7em;">
                        <strong>Панель "Хранилище скрытых новостей":</strong>
                        <ul>
                            <li>Отображает список всех новостей, добавленных в постоянное хранилище. Для каждой записи указывается название игры, заголовок новости и ее AppID.</li>
                            <li><strong>"Вернуть":</strong> Кнопка напротив каждой записи позволяет удалить новость из хранилища и немедленно отобразить ее в ленте (если она еще присутствует в DOM). Чекбокс на этой новости также снова станет активным.</li>
                            <li><strong>"Очистить хранилище":</strong> Удаляет все новости из вашего списка постоянно скрытых. Требует подтверждения.</li>
                            <li><strong>"Закрыть":</strong> Закрывает панель хранилища.</li>
                            <img src="https://i.imgur.com/T5pUb9a.png" alt="Пример интерфейса хранилища" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
                        </ul>
                    </li>
                </ol>
            `
        },
        wishlistGiftHelper: {
            category: 'news_wishlist',
            label: "Доступность подарков (список желаемого)",
            title: "Доступность подарков (список желаемого)",
            details: `
                <p><strong>Что делает:</strong> Добавляет кнопку со значком лупы <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14" fill="currentColor" style="vertical-align: middle;"><path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path></svg> на страницу списка желаемого, позволяющую определить, какие игры можно подарить друзьям в других регионах.</p>
                <p><strong>Основные функции:</strong></p>
                <ul>
                    <li>Загружает игры из отображаемого списка желаемого и выводит их в виде информативных карточек.</li>
                    <li>На карточках отображается подробная информация: цена, скидка, рейтинг, дата выхода, издатель, разработчик, серия, метки, поддержка русского языка и статус раннего доступа.</li>
                    <li><strong>Для пользователей из РФ:</strong> на карточках также отображается информация о соответствии стоимости рекомендованной региональной цене (РРЦ) от Valve. Показывается статус (дороже, дешевле или равно РРЦ), сумма и процент отклонения.</li>
                    <li>Предоставляет гибкую систему фильтрации по цене, скидке, рейтингу, дате выхода, поддержке русского языка, статусу раннего доступа, а также <strong>по соответствию РРЦ (для РФ)</strong>.</li>
                    <li>Активирует режим <strong>помощника подарков</strong>:
                        <ul>
                            <li>Вы выбираете регион вашего друга.</li>
                            <li>Скрипт запрашивает цены на игры из списка желаемого для выбранного региона.</li>
                            <li>Цены друга конвертируются в вашу валюту (используется API курсов валют).</li>
                            <li>Отображается <strong>разница в цене</strong> между вашим регионом и регионом друга (с цветовой индикацией: <span style="color:#77dd77; font-weight:bold;">зелёный</span> - можно дарить (разница до ±10%), <span style="color:#ff6961; font-weight:bold;">красный</span> - нельзя).</li>
                            <li>Доступен фильтр <strong>"Можно подарить"</strong>, который показывает только те игры, у которых разница в цене до ±10% и которые Steam разрешает покупать в подарок.</li>
                        </ul>
                    </li>
                </ul>
                 <p>Это помогает легко найти подходящие и экономически целесообразные подарки для друзей за границей.</p>
                 <p><i><small>*Примечание: Скорость загрузки данных зависит от размера списка желаемого.</small></i></p>
                 <img src="https://i.imgur.com/wq9eRCW.png" alt="Пример WishlistGiftHelper 1" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">`
        },
        // --- Дополнительные ---
        autoExpandHltb: {
            category: 'additional',
            label: "Авто-раскрытие HLTB",
            title: "Автоматически раскрывать спойлер HLTB",
            details: "<p>Если включено, блок с информацией о времени прохождения (HLTB) на странице игры будет автоматически раскрываться при загрузке страницы (если основной модуль HLTB включен).</p><p>Удобно, если вы всегда хотите видеть эту информацию без лишнего щелчка.</p>"
        },
        salesMasterAutoSearch: {
            category: 'additional',
            label: "Авто-сбор цен в агрегаторе цен",
            title: "Автоматический сбор цен в агрегаторе цен (%)",
            details: "<p>Если опция включена, при открытии модального окна <strong>Агрегатора цен (%)</strong> сбор предложений из магазинов начнется автоматически, без необходимости нажимать кнопку 'Обновить %'.</p><p>Это удобно, если вы всегда хотите сразу видеть актуальные цены при каждом открытии окна.</p>"
        },
        autoLoadReviews: {
            category: 'additional',
            label: "Авто-загрузка доп. обзоров",
            title: "Автоматически загружать дополнительные обзоры",
            details: "<p>Если включено, блок с дополнительными обзорами (Тотальные, Безкитайские, Русские) на странице игры будет загружаться автоматически при загрузке страницы (если основной модуль 'Индикаторы/Обзоры' включен).</p><p>Экономит щелчок, если вам всегда нужна эта статистика.</p>"
        },
        salesMasterAutoInsertTitle: {
            category: 'additional',
            label: "Авто-подстановка названия в агрегаторе цен",
            title: "Автоматическая подстановка названия в агрегаторе цен (%)",
            details: `
                <p>Если опция включена, после завершения сбора данных (как ручного, так и автоматического) название текущей игры будет автоматически вставлено в поле фильтра по названию.</p>
                <div style="margin-top: 15px; padding: 10px; background-color: rgba(255, 179, 0, 0.1); border: 1px solid rgba(255, 179, 0, 0.4); border-radius: 4px; font-size: 0.95em; line-height: 1.4;">
                    <p style="margin: 0 0 5px 0; font-weight: bold; color: #FFB300;">⚠️ Важно:</p>
                    <p style="margin: 0; color: #c6d4df;">Для более точного поиска рекомендуется сокращать подставленное название. Например, вместо "DEATH STRANDING DIRECTOR'S CUT" лучше оставить только "DEATH STRANDING". Это поможет найти предложения, где продавцы могли изменить или сократить название, например, "Death Stranding (Director's Cut)" или "Death Stranding D.C.".</p>
                </div>
            `
        },
        toggleEnglishLangInfo: {
            category: 'additional',
            label: "Показ инфо об англ. языке",
            title: "Отображать данные об английском языке",
            details: "<p><strong>Функция для переводчиков и интересующихся.</strong> Если включено, в блоках дополнительной информации (в каталоге при наведении и в ленте активности при наведении) будет также отображаться информация о поддержке английского языка (интерфейс, озвучка, субтитры), аналогично русскому.</p><p>По умолчанию эта информация скрыта для экономии места.</p>"
        },
        incognitoModeEnabled: {
            category: 'incognitoMode',
            label: "Виртуальный режим «Инкогнито»",
            title: "Главный переключатель виртуального режима «Инкогнито» (В.Р.И.)",
            details: `
                <p><strong>Что делает:</strong> Полностью включает или отключает основную функцию В.Р.И. — автоматический обход региональных блокировок.</p>
                <ul>
                    <li><strong>Включено (по умолчанию):</strong> Если скрипт обнаружит на странице игры сообщение "Данный товар недоступен в вашем регионе", он автоматически попытается загрузить страницу через выбранный регион В.Р.И.</li>
                    <li><strong>Отключено:</strong> Автоматический обход блокировок производиться не будет. Страница с региональным ограничением останется без изменений.</li>
                </ul>
                <div style="margin-top: 15px; padding: 10px; background-color: rgba(255, 179, 0, 0.1); border: 1px solid rgba(255, 179, 0, 0.4); border-radius: 4px; font-size: 0.95em; line-height: 1.4;">
                    <p style="margin: 0; color: #c6d4df;"><strong>Важно:</strong> Это главный переключатель. Его отключение деактивирует автоматический обход, даже если остальные настройки В.Р.И. (кнопка, регион) заданы. Ручной запуск через кнопку "in" по-прежнему будет работать.</p>
                </div>
                <img src="https://i.imgur.com/TGmRkOP.png" alt="Пример" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
            `
         },
        showIncognitoButton: {
            category: 'incognitoMode',
            label: "Кнопка режима «Инкогнито»",
            title: "Отображение кнопки ручного включения режима «Инкогнито»",
            details: `
                <p><strong>Что делает:</strong> Добавляет или убирает кнопку "in" рядом с логотипом Steam.</p>
                <p>Эта кнопка позволяет вручную перезагрузить любую страницу Steam в «виртуальном режиме инкогнито».</p>
                <ul>
                    <li><strong>Включено:</strong> Кнопка "in" будет видна.</li>
                    <li><strong>Отключено:</strong> Кнопка "in" будет скрыта.</li>
                </ul>
                <p><em>Примечание:</em> Отключение кнопки не отключает сам режим инкогнито. Он запускается автоматически для просмотра заблокированных страниц. Эта опция контролирует только элемент для ручного запуска.</p>
                <img src="https://i.imgur.com/FyKBRMa.png" alt="Пример кнопки Инкогнито" style="max-width: 90%; height: auto; margin-top: 10px; display: block; margin-left: auto; margin-right: auto; border: 1px solid #333;">
            `
        },
        incognitoDefaultRegion: {
            category: 'incognitoMode',
            label: "Регион В.Р.И.",
            title: "Выбор региона по умолчанию для виртуального режима «Инкогнито»",
            details: `
                <p><strong>Что делает:</strong> Позволяет выбрать регион, от которого будут осуществляться запросы в режиме «Инкогнито».</p>
                <p>По умолчанию используется <strong>US (США)</strong>, так как это наиболее универсальный регион.</p>
                <p>Изменение этого параметра повлияет на:</p>
                <ul>
                    <li>Автоматический обход региональных блокировок.</li>
                    <li>Ручной запуск режима инкогнито через кнопку 'in'.</li>
                </ul>
            `
        }
    };

    function showInfoModal(settingKey) {
        const existingInfoModal = document.getElementById('useSettingInfoModal');
        if (existingInfoModal) existingInfoModal.remove();

        const infoData = settingInfo[settingKey];
        if (!infoData) return;

        const infoModal = document.createElement('div');
        infoModal.id = 'useSettingInfoModal';
        infoModal.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #1f2c3a;
            color: #c6d4df;
            padding: 25px;
            border-radius: 5px;
            border: 1px solid #8f98a0;
            box-shadow: 0 5px 25px rgba(0, 0, 0, 0.7);
            z-index: 10002;
            display: block;
            width: 800px;
            max-width: 90vw;
            max-height: 90vh;
            overflow-y: auto;
            font-family: "Motiva Sans",
            Sans-serif,
            Arial;
            font-size: 14px;
            scrollbar-color: #4b6f9c #1b2838;
            scrollbar-width: thin;
        `;
        infoModal.style.setProperty('--scrollbar-track-color-info', '#1b2838');
        infoModal.style.setProperty('--scrollbar-thumb-color-info', '#4b6f9c');
         GM_addStyle(`
            #useSettingInfoModal::-webkit-scrollbar {
            	width: 8px;
            }

            #useSettingInfoModal::-webkit-scrollbar-track {
            	background: var(--scrollbar-track-color-info);
            	border-radius: 4px;
            }

            #useSettingInfoModal::-webkit-scrollbar-thumb {
            	background-color: var(--scrollbar-thumb-color-info);
            	border-radius: 4px;
            	border: 2px solid var(--scrollbar-track-color-info);
            }

            #useSettingInfoModal::-webkit-scrollbar-thumb:hover {
            	background-color: #67c1f5;
            }

            #useSettingInfoModal p {
            	margin-bottom: 1em;
            	line-height: 1.6;
            }

            #useSettingInfoModal ul {
            	margin-left: 20px;
            	margin-bottom: 5px;
            	list-style-position: outside;
            }

            #useSettingInfoModal li {
            	margin-bottom: 0.5em;
            }

            #useSettingInfoModal strong {
            	color: #67c1f5;
            }

            #useSettingInfoModal img {
            	border-radius: 3px;
            }

            #useSettingInfoModal a {
            	color: #67c1f5;
            	text-decoration: none;
            }

            #useSettingInfoModal a:hover {
            	text-decoration: underline;
            }
        `);

        const title = document.createElement('h3');
        title.textContent = infoData.title || "Информация";
        title.style.cssText = 'margin-top: 0; margin-bottom: 20px; color: #67c1f5; text-align: center; font-weight: 500; font-size: 17px;';
        infoModal.appendChild(title);

        const detailsDiv = document.createElement('div');
        detailsDiv.innerHTML = infoData.details || "Описание отсутствует.";
        infoModal.appendChild(detailsDiv);

        const closeButton = document.createElement('button');
        closeButton.textContent = 'Закрыть';
        closeButton.style.cssText = `
            display: block; margin: 25px auto 0; padding: 10px 25px;
            background-color: #8f98a0; color: #1b2838; border: none;
            border-radius: 3px; cursor: pointer; font-size: 14px; font-weight: bold;
            transition: background-color 0.2s;
        `;
        closeButton.onmouseover = () => closeButton.style.backgroundColor = '#aab5c1';
        closeButton.onmouseout = () => closeButton.style.backgroundColor = '#8f98a0';
        closeButton.addEventListener('click', function() {
            infoModal.remove();
        });
        infoModal.appendChild(closeButton);

        document.body.appendChild(infoModal);
    }

    function createSettingRow(key) {
         const settingData = settingInfo[key];
         if (!settingData) return null;

         const row = document.createElement('div');
         row.style.cssText = 'display: flex; align-items: center; justify-content: space-between; min-height: 24px;';

         const labelContainer = document.createElement('label');
         labelContainer.style.cssText = 'display: flex; align-items: center; cursor: pointer; flex-grow: 1; margin-right: 10px;';

         const checkbox = document.createElement('input');
         checkbox.type = 'checkbox';
         if (key === 'showIncognitoButton') {
             checkbox.checked = GM_getValue('use_incognito_button_enabled', false);
         } else if (key === 'incognitoModeEnabled') {
             checkbox.checked = GM_getValue('use_incognito_mode_enabled', true);
         } else {
             checkbox.checked = useCurrentSettings[key];
         }
         checkbox.dataset.settingKey = key;
         checkbox.style.cssText = 'margin-right: 10px; accent-color: #67c1f5; cursor: pointer; width: 16px; height: 16px; flex-shrink: 0;';

         const labelText = document.createElement('span');
         labelText.textContent = settingData.label || key;
         labelText.style.lineHeight = '1.3';

         if (key === 'gamePage') {
             labelText.style.color = '#9E9E9E';
             checkbox.style.accentColor = '#FFB300';

             const dependentLabelsTooltip = dependentModules.gamePage
                 .map(depKey => `'${settingInfo[depKey]?.label || depKey}'`)
                 .join(', ');
             labelContainer.title = `Отключение этого модуля приведет к нарушению работы или полному отключению модулей: ${dependentLabelsTooltip}. Эти модули критически зависят от данного модуля.`;
         }

         checkbox.addEventListener('change', function() {
             const currentSettingKey = this.dataset.settingKey;
             const isChecked = this.checked;

             if (currentSettingKey === 'showIncognitoButton') {
                 GM_setValue('use_incognito_button_enabled', isChecked);
             } else if (currentSettingKey === 'incognitoModeEnabled') {
 			 	GM_setValue('use_incognito_mode_enabled', isChecked);
             } else if (currentSettingKey === 'gamePage' && !isChecked) {
                 const dependentFullNames = dependentModules.gamePage
                     .map(depKey => `'${settingInfo[depKey]?.label || depKey}'`)
                     .join(', ');
                 showConfirmationModal(
                     'Подтверждение отключения',
                     `Отключение этого модуля приведёт к отключению модулей: ${dependentFullNames}. Вы уверены?`,
                     () => {
                         useCurrentSettings[currentSettingKey] = false;
                         scriptsConfig[currentSettingKey] = false;

                         dependentModules.gamePage.forEach(depKey => {
                             useCurrentSettings[depKey] = false;
                             scriptsConfig[depKey] = false;
                             const depCheckbox = document.querySelector(`input[data-setting-key="${depKey}"]`);
                             if (depCheckbox) {
                                 depCheckbox.checked = false;
                             }
                         });
                         GM_setValue('useSettings', useCurrentSettings);
                     },
                     () => {
                         this.checked = true;
                     }
                 );
             } else {
                 useCurrentSettings[currentSettingKey] = isChecked;
                 scriptsConfig[currentSettingKey] = isChecked;
                 GM_setValue('useSettings', useCurrentSettings);
             }
         });

         labelContainer.appendChild(checkbox);
         labelContainer.appendChild(labelText);
         row.appendChild(labelContainer);

         const infoButton = document.createElement('span');
         infoButton.textContent = 'ⓘ';
         infoButton.style.cssText = `
             cursor: pointer; color: #67c1f5; font-size: 18px;
             line-height: 1; font-weight: bold;
             margin-left: 5px; padding: 0 4px; border-radius: 3px; user-select: none;
             transition: color 0.2s, background-color 0.2s;
             flex-shrink: 0; vertical-align: middle;
         `;
         infoButton.title = 'Подробнее...';
         infoButton.onmouseover = () => { infoButton.style.backgroundColor = 'rgba(103, 193, 245, 0.2)'; };
         infoButton.onmouseout = () => { infoButton.style.backgroundColor = 'transparent'; };
         infoButton.addEventListener('click', (e) => {
             e.stopPropagation();
             showInfoModal(key);
         });

         row.appendChild(infoButton);
         return row;
     }

	function createSettingSelectRow(key, options) {
	    const settingData = settingInfo[key];
	    if (!settingData) return null;

	    const row = document.createElement('div');
	    row.style.cssText = 'display: flex; align-items: center; justify-content: space-between; min-height: 24px; padding: 5px 0;';

	    const labelContainer = document.createElement('label');
	    labelContainer.style.cssText = 'display: flex; align-items: center; cursor: default; flex-grow: 1; margin-right: 10px;';

	    const labelText = document.createElement('span');
	    labelText.textContent = settingData.label || key;
	    labelText.style.lineHeight = '1.3';
	    labelText.style.marginRight = '10px';
	    labelText.style.flexShrink = '0';
	    labelContainer.appendChild(labelText);

	    const select = document.createElement('select');
	    select.dataset.settingKey = key;
	    select.style.cssText = `
	        flex-grow: 1;
	        padding: 4px 6px;
	        background-color: #2a3f5a;
	        color: #c6d4df;
	        border: 1px solid #567d9c;
	        border-radius: 3px;
	        cursor: pointer;
	        font-size: 13px;
	    `;

	    const sortedOptions = Object.entries(options).sort(([, a], [, b]) => a.name.localeCompare(b.name));

	    sortedOptions.forEach(([code, data]) => {
	        const option = document.createElement('option');
	        option.value = code;
	        option.textContent = `${data.name} (${code})`;
	        select.appendChild(option);
	    });

	    select.value = GM_getValue('use_incognito_default_region', 'US');

	    select.addEventListener('change', function() {
	        const selectedValue = this.value;
	        useCurrentSettings[key] = selectedValue;
	        GM_setValue('use_incognito_default_region', selectedValue);
	    });

	    labelContainer.appendChild(select);
	    row.appendChild(labelContainer);

	    const infoButton = document.createElement('span');
	    infoButton.textContent = 'ⓘ';
	    infoButton.style.cssText = `
	        cursor: pointer; color: #67c1f5; font-size: 18px; line-height: 1;
	        font-weight: bold; margin-left: 5px; padding: 0 4px; border-radius: 3px;
	        user-select: none; transition: color 0.2s, background-color 0.2s;
	        flex-shrink: 0; vertical-align: middle;
	    `;
	    infoButton.title = 'Подробнее...';
	    infoButton.onmouseover = () => { infoButton.style.backgroundColor = 'rgba(103, 193, 245, 0.2)'; };
	    infoButton.onmouseout = () => { infoButton.style.backgroundColor = 'transparent'; };
	    infoButton.addEventListener('click', (e) => {
	        e.stopPropagation();
	        showInfoModal(key);
	    });
	    row.appendChild(infoButton);

	    return row;
	}

    function createSettingsModal() {
        const existingModal = document.getElementById('useSettingsModal');
        if (existingModal) existingModal.remove();

        const modal = document.createElement('div');
        modal.id = 'useSettingsModal';
        modal.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #171a21;
            color: #c6d4df;
            padding: 30px;
            border-radius: 5px;
            border: 1px solid #67c1f5;
            box-shadow: 0 5px 30px rgba(0, 0, 0, 0.8);
            z-index: 10001;
            display: block;
            width: 800px;
            max-height: 90vh;
            overflow-y: auto;
            font-family: "Motiva Sans",
            Sans-serif,
            Arial;
            font-size: 14px;
            scrollbar-color: #4b6f9c #1b2838;
            scrollbar-width: thin;
        `;
        modal.style.setProperty('--scrollbar-track-color', '#1b2838');
        modal.style.setProperty('--scrollbar-thumb-color', '#4b6f9c');

        GM_addStyle(`
            #useSettingsModal::-webkit-scrollbar {
                width: 8px;
            }
            #useSettingsModal::-webkit-scrollbar-track {
                background: var(--scrollbar-track-color);
                border-radius: 4px;
            }
            #useSettingsModal::-webkit-scrollbar-thumb {
                background-color: var(--scrollbar-thumb-color);
                border-radius: 4px;
                border: 2px solid var(--scrollbar-track-color);
            }
            #useSettingsModal::-webkit-scrollbar-thumb:hover {
                background-color: #67c1f5;
            }
            #useCreditsFooter {
                position: absolute;
                bottom: 5px;
                right: 0;
                font-size: 12px;
                color: #8091a2;
                text-align: right;
                line-height: 1.4;
                z-index: 1;
                pointer-events: none;
            }
            #useCreditsFooter a {
                color: #8f98a0;
                text-decoration: none;
                pointer-events: auto;
            }
            #useCreditsFooter a:hover {
                color: #67c1f5;
                text-decoration: underline;
            }
            #useCreditsFooter .author-line {
                margin-bottom: 3px;
            }

            #useOfficialPageFooter {
                position: absolute;
                bottom: 7px;
                line-height: 1;
                z-index: 1;
            }
            #useOfficialPageFooter a {
                display: inline-block;
                text-decoration: none;
                transition: opacity 0.2s;
            }
            #useOfficialPageFooter a:hover {
                opacity: 0.85;
            }
            #useOfficialPageFooter img {
                display: block;
                border: none;
                width: 171px;
                height: 24px;
            }
        `);

        const mainTitleHeader = document.createElement('h2');
        mainTitleHeader.textContent = 'Настройки Ultimate Steam Enhancer';
        mainTitleHeader.style.cssText = 'margin-top: 0; margin-bottom: 25px; color: #67c1f5; text-align: center; font-weight: 500; font-size: 18px;';
        modal.appendChild(mainTitleHeader);

        const categories = {
            gamePage: { title: 'Для страницы игры', container: document.createElement('div') },
            catalog: { title: 'Для каталога', container: document.createElement('div') },
            community: { title: 'Для ленты активности', container: document.createElement('div') },
            market: { title: 'Для торговой площадки', container: document.createElement('div') },
            news_wishlist: { title: 'Для списка желаемого / Новостей', container: document.createElement('div') },
            additional: { title: 'Дополнительные настройки', container: document.createElement('div') },
            incognitoMode: { title: 'Виртуальный режим «Инкогнито»', container: document.createElement('div') }
        };

        for (const catKey in categories) {
            const category = categories[catKey];
            category.container.style.marginBottom = '25px';
            const categoryTitle = document.createElement('h4');
            categoryTitle.textContent = category.title;
            categoryTitle.style.cssText = 'color: #c6d4df; border-bottom: 1px solid #4b6f9c; padding-bottom: 6px; margin-bottom: 12px; font-size: 15px; font-weight: normal;';
            category.container.appendChild(categoryTitle);
            const checkboxesGrid = document.createElement('div');
            checkboxesGrid.style.cssText = 'display: grid; grid-template-columns: 1fr 1fr; gap: 10px 25px;';
            category.container.appendChild(checkboxesGrid);
            modal.appendChild(category.container);
        }

        for (const key of Object.keys(settingInfo)) {
            const settingData = settingInfo[key];
            if (settingData && settingData.category && categories[settingData.category]) {
                if (useCurrentSettings.hasOwnProperty(key)) {
                    let settingRow;
                    if (key === 'incognitoDefaultRegion') {
                        settingRow = createSettingSelectRow(key, useIncognitoRegions);
                    } else {
                        settingRow = createSettingRow(key);
                    }

                    if (settingRow) {
                        const gridContainer = categories[settingData.category].container.querySelector('div[style*="grid-template-columns"]');
                        if (gridContainer) {
                            gridContainer.appendChild(settingRow);
                        }
                    }
                }
            }
        }

        const bottomActionsWrapper = document.createElement('div');
        bottomActionsWrapper.id = 'useBottomActionsWrapper';
        bottomActionsWrapper.style.position = 'relative';
        bottomActionsWrapper.style.marginTop = '30px';

        const creditsFooter = document.createElement('div');
        creditsFooter.id = 'useCreditsFooter';

        const authorLine = document.createElement('div');
        authorLine.className = 'author-line';
        authorLine.textContent = 'by 0wn3df1x';
        creditsFooter.appendChild(authorLine);

        const zogLine = document.createElement('div');
        zogLine.appendChild(document.createTextNode('и '));
        const zogLink = document.createElement('a');
        zogLink.href = 'https://www.zoneofgames.ru';
        zogLink.target = '_blank';
        zogLink.title = 'Перейти на ZoneOfGames.ru';
        zogLink.textContent = 'команда ZoneOfGames.ru';
        zogLine.appendChild(zogLink);
        creditsFooter.appendChild(zogLine);

        bottomActionsWrapper.appendChild(creditsFooter);

        const officialPageFooter = document.createElement('div');
        officialPageFooter.id = 'useOfficialPageFooter';

        const pageLink = document.createElement('a');
        pageLink.href = 'https://greasyfork.org/ru/scripts/526180-ultimate-steam-enhancer';
        pageLink.target = '_blank';
        pageLink.title = 'Страница на Greasy Fork';

        const badgeImage = document.createElement('img');
        badgeImage.src = 'https://img.shields.io/badge/Страница_на-GreasyFork-blue.svg';
        badgeImage.alt = 'Страница на Greasy Fork';

        pageLink.appendChild(badgeImage);
        officialPageFooter.appendChild(pageLink);
        bottomActionsWrapper.appendChild(officialPageFooter);

        const closeButton = document.createElement('button');
        closeButton.textContent = 'Закрыть';
        closeButton.style.cssText = `
            display: block; margin: 0 auto;
            padding: 10px 30px;
            background-color: #67c1f5; color: #1b2838; border: none;
            border-radius: 3px; cursor: pointer; font-size: 15px; font-weight: bold;
            transition: background-color 0.2s;
            position: relative; z-index: 2;
        `;
        closeButton.onmouseover = () => closeButton.style.backgroundColor = '#8ad3f7';
        closeButton.onmouseout = () => closeButton.style.backgroundColor = '#67c1f5';
        closeButton.addEventListener('click', function() {
            modal.remove();
        });

        bottomActionsWrapper.appendChild(closeButton);

        modal.appendChild(bottomActionsWrapper);

        document.body.appendChild(modal);
    }

    function addLoggedInSettingsMenuItem(accountDropdown) {
        const logoutLink = accountDropdown.querySelector('a[href="javascript:Logout();"]');
        if (!logoutLink || document.getElementById('use_settings_menu_item')) {
            return;
        }

        const settingsMenuItem = document.createElement('a');
        settingsMenuItem.className = 'popup_menu_item';
        settingsMenuItem.id = 'use_settings_menu_item';
        settingsMenuItem.href = '#';
        settingsMenuItem.textContent = 'Настройки U.S.E.';
        settingsMenuItem.style.color = '#67c1f5';
        settingsMenuItem.style.fontWeight = 'bold';


        settingsMenuItem.addEventListener('click', function(event) {
            event.preventDefault();
            event.stopPropagation();
            createSettingsModal();
        });

        const popupBody = accountDropdown.querySelector('.popup_body.popup_menu');
        if (popupBody) {
            popupBody.insertBefore(settingsMenuItem, logoutLink);
        }
    }

    function addLoggedOutSettingsMenuItem(globalActionMenu) {
        const languagePulldown = document.getElementById('language_pulldown');
        const loginLink = globalActionMenu.querySelector('a[href*="/login"]');

        if (!languagePulldown || !loginLink || document.getElementById('use_settings_logged_out_link')) {
            return;
        }

        const separator = document.createTextNode('\u00A0|\u00A0');

        const settingsLinkElement = document.createElement('a');
        settingsLinkElement.href = '#';
        settingsLinkElement.id = 'use_settings_logged_out_link';
        settingsLinkElement.className = 'global_action_link';
        settingsLinkElement.textContent = 'Настройки U.S.E.';
        settingsLinkElement.style.color = '#67c1f5';
        settingsLinkElement.style.fontWeight = 'bold';

        settingsLinkElement.addEventListener('click', (e) => {
            e.preventDefault();
            createSettingsModal();
        });

        globalActionMenu.appendChild(separator);
        globalActionMenu.appendChild(settingsLinkElement);
    }

    function addSettingsButtonGlobal() {
        const globalActionMenu = document.getElementById('global_action_menu');
        if (!globalActionMenu) {
            return;
        }

        const existingLoggedInButton = document.getElementById('use_settings_menu_item');
        if (existingLoggedInButton) {
            existingLoggedInButton.remove();
        }

        const existingLoggedOutLink = document.getElementById('use_settings_logged_out_link');
        if (existingLoggedOutLink) {
            const prevNode = existingLoggedOutLink.previousSibling;
            if (prevNode && prevNode.nodeType === Node.TEXT_NODE && prevNode.textContent === '\u00A0|\u00A0') {
                prevNode.remove();
            }
            existingLoggedOutLink.remove();
        }

        const accountDropdown = document.getElementById('account_dropdown');
        if (accountDropdown) {
            addLoggedInSettingsMenuItem(accountDropdown);
        } else {
            addLoggedOutSettingsMenuItem(globalActionMenu);
        }
    }

    let globalUiAttempts = 0;
    const globalUiMaxAttempts = 20;
    const globalUiInterval = setInterval(() => {
        const globalHeader = document.getElementById('global_header');

        if (globalHeader || globalUiAttempts >= globalUiMaxAttempts) {
            clearInterval(globalUiInterval);
            if (globalHeader) {
                addSettingsButtonGlobal();

                const observer = new MutationObserver((mutationsList, obs) => {
                    const isNowLoggedIn = !!document.getElementById('account_dropdown');

                    const loggedInButtonPresent = !!document.getElementById('use_settings_menu_item');
                    const loggedOutLinkPresent = !!document.getElementById('use_settings_logged_out_link');

                    let needsRebuild = false;

                    if (isNowLoggedIn) {
                        if (!loggedInButtonPresent || loggedOutLinkPresent) {
                            needsRebuild = true;
                        }
                    } else {
                        const loginPageMarker = !!document.querySelector('#global_action_menu a[href*="/login"]');

                        if (loginPageMarker) {
                            if (!loggedOutLinkPresent || loggedInButtonPresent) {
                                needsRebuild = true;
                            }
                        } else if (loggedInButtonPresent || loggedOutLinkPresent) {
                            needsRebuild = true;
                        }
                    }

                    if (needsRebuild) {
                        addSettingsButtonGlobal();
                    }
                });

                observer.observe(globalHeader, {
                    childList: true,
                    subtree: true
                });
            }
        }
        globalUiAttempts++;
    }, 500);

    function showConfirmationModal(titleText, messageText, onConfirm, onCancel) {
        const existingConfirmModal = document.getElementById('useConfirmationModal');
        if (existingConfirmModal) existingConfirmModal.remove();

        const confirmModal = document.createElement('div');
        confirmModal.id = 'useConfirmationModal';
        confirmModal.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #1f2c3a;
            color: #c6d4df;
            padding: 25px;
            border-radius: 5px;
            border: 1px solid #FFB300;
            box-shadow: 0 5px 25px rgba(0, 0, 0, 0.7);
            z-index: 10003;
            display: block;
            width: 500px;
            max-width: 90vw;
            font-family: "Motiva Sans", Sans-serif, Arial;
            font-size: 14px;
        `;

        const title = document.createElement('h3');
        title.textContent = titleText;
        title.style.cssText = 'margin-top: 0; margin-bottom: 15px; color: #FFB300; text-align: center; font-weight: 500; font-size: 17px;';
        confirmModal.appendChild(title);

        const message = document.createElement('p');
        message.textContent = messageText;
        message.style.cssText = 'margin-bottom: 25px; line-height: 1.6; text-align: center;';
        confirmModal.appendChild(message);

        const buttonContainer = document.createElement('div');
        buttonContainer.style.cssText = 'display: flex; justify-content: space-around;';

        const confirmButton = document.createElement('button');
        confirmButton.textContent = 'Да';
        confirmButton.style.cssText = `
            padding: 10px 25px; background-color: #FFB300; color: #1b2838; border: none;
            border-radius: 3px; cursor: pointer; font-size: 14px; font-weight: bold;
            transition: background-color 0.2s;
        `;
        confirmButton.onmouseover = () => confirmButton.style.backgroundColor = '#FFC107';
        confirmButton.onmouseout = () => confirmButton.style.backgroundColor = '#FFB300';
        confirmButton.addEventListener('click', function() {
            onConfirm();
            confirmModal.remove();
        });

        const cancelButton = document.createElement('button');
        cancelButton.textContent = 'Нет';
        cancelButton.style.cssText = `
            padding: 10px 25px; background-color: #8f98a0; color: #1b2838; border: none;
            border-radius: 3px; cursor: pointer; font-size: 14px; font-weight: bold;
            transition: background-color 0.2s;
        `;
        cancelButton.onmouseover = () => cancelButton.style.backgroundColor = '#aab5c1';
        cancelButton.onmouseout = () => cancelButton.style.backgroundColor = '#8f98a0';
        cancelButton.addEventListener('click', function() {
            onCancel();
            confirmModal.remove();
        });

        buttonContainer.appendChild(confirmButton);
        buttonContainer.appendChild(cancelButton);
        confirmModal.appendChild(buttonContainer);

        document.body.appendChild(confirmModal);
    }

    // Скрипт для страницы игры (индикаторы о наличии русского перевода; получение дополнительных обзоров) | https://store.steampowered.com/app/*
    if (scriptsConfig.gamePage && unsafeWindow.location.pathname.includes('/app/')) {
        (function() {
            'use strict';

            if (typeof ChartDataLabels !== 'undefined') {
                Chart.register(ChartDataLabels);
            } else {
                console.error("ChartDataLabels plugin is not loaded. Make sure the @require line is correct.");
            }

            function createFruitIndicator(apple, hasSupport, orange) {
                const banana = document.createElement('div');
                banana.style.position = 'relative';
                banana.style.cursor = 'pointer';

                const grape = document.createElement('div');
                grape.style.width = '60px';
                grape.style.height = '60px';
                grape.style.borderRadius = '4px';
                grape.style.display = 'flex';
                grape.style.alignItems = 'center';
                grape.style.justifyContent = 'center';
                grape.style.background = hasSupport ? 'rgba(66, 135, 245, 0.2)' : 'rgba(0, 0, 0, 0.1)';
                grape.style.border = `1px solid ${hasSupport ? '#2A5891' : '#3c3c3c'}`;
                grape.style.opacity = '0.95';
                grape.style.transition = 'transform 0.3s ease, box-shadow 0.3s ease';
                grape.style.overflow = 'hidden';
                grape.style.position = 'relative';
                grape.style.transform = 'translateZ(0)';

                const kiwi = document.createElement('div');
                kiwi.innerHTML = apple;
                kiwi.style.width = '30px';
                kiwi.style.height = '30px';
                kiwi.style.display = 'block';
                kiwi.style.margin = '0 auto';
                kiwi.style.transition = 'fill 0.3s ease';

                grape.appendChild(kiwi);

                const svgElement = kiwi.querySelector('svg');

                function setColor(hasSupport) {
                    const borderColor = hasSupport ? '#2A5891' : '#3c3c3c';
                    const svgFill = hasSupport ? '#FFFFFF' : '#0E1C25';

                    grape.style.border = `1px solid ${borderColor}`;
                    if (svgElement) {
                        svgElement.style.fill = svgFill;
                    }
                }

                setColor(hasSupport);

                const pineapple = document.createElement('div');
                const hasLabel = hasSupport ? orange : getGenitiveCase(orange);
                pineapple.textContent = hasSupport ? `Есть ${orange}` : `Нет ${hasLabel}`;
                pineapple.style.position = 'absolute';
                pineapple.style.top = '50%';
                pineapple.style.left = '100%';
                pineapple.style.transform = 'translateY(-50%) translateX(10px)';
                pineapple.style.background = 'rgba(0, 0, 0, 0.8)';
                pineapple.style.color = '#fff';
                pineapple.style.padding = '8px 12px';
                pineapple.style.borderRadius = '8px';
                pineapple.style.fontSize = '14px';
                pineapple.style.whiteSpace = 'nowrap';
                pineapple.style.opacity = '0';
                pineapple.style.transition = 'opacity 0.3s ease';
                pineapple.style.zIndex = '10000';
                pineapple.style.pointerEvents = 'none';
                banana.appendChild(pineapple);

                banana.addEventListener('mouseenter', () => {
                    grape.style.transform = 'scale(1.1) translateZ(0)';
                    pineapple.style.opacity = '1';
                });

                banana.addEventListener('mouseleave', () => {
                    grape.style.transform = 'scale(1) translateZ(0)';
                    pineapple.style.opacity = '0';
                });

                banana.appendChild(grape);
                return banana;
            }

            function getGenitiveCase(orange) {
                switch (orange) {
                    case 'интерфейс':
                        return 'интерфейса';
                    case 'озвучка':
                        return 'озвучки';
                    case 'субтитры':
                        return 'субтитров';
                    default:
                        return orange;
                }
            }

            function checkRussianSupport() {
                const mango = document.querySelector('#languageTable table.game_language_options');
                if (!mango) return { interface: false, voice: false, subtitles: false };

                const strawberry = mango.querySelectorAll('tr');
                for (let blueberry of strawberry) {
                    const watermelon = blueberry.querySelector('td.ellipsis');
                    if (watermelon && /русский|Russian/i.test(watermelon.textContent.trim())) {
                        const cherry = blueberry.querySelector('td.checkcol:nth-child(2) span');
                        const raspberry = blueberry.querySelector('td.checkcol:nth-child(3) span');
                        const blackberry = blueberry.querySelector('td.checkcol:nth-child(4) span');
                        return {
                            interface: cherry !== null,
                            voice: raspberry !== null,
                            subtitles: blackberry !== null
                        };
                    }
                }
                return { interface: false, voice: false, subtitles: false };
            }

            function addRussianIndicators() {
                const russianSupport = checkRussianSupport();
                if (!russianSupport) return;

                let lemon = document.querySelector('#gameHeaderImageCtn');
                if (!lemon) return;

                const existingIndicatorContainer = lemon.querySelector('.use-rus-indicator-container');
                if (existingIndicatorContainer) {
                    existingIndicatorContainer.remove();
                }

                const lime = document.createElement('div');
                lime.className = 'use-rus-indicator-container';
                lime.style.position = 'absolute';
                lime.style.top = '-10px';
                lime.style.left = 'calc(100% + 10px)';
                lime.style.display = 'flex';
                lime.style.flexDirection = 'column';
                lime.style.gap = '15px';
                lime.style.alignItems = 'flex-start';
                lime.style.zIndex = '2';
                lime.style.marginTop = '10px';

                const peach = createFruitIndicator(`<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12,0C5.38,0,0,5.38,0,12s5.38,12,12,12s12-5.38,12-12S18.62,0,12,0z M12,22C6.49,22,2,17.51,2,12S6.49,2,12,2	s10,4.49,10,10S17.51,22,12,22z M10.5,10h3v8h-3V10z M10.5,5h3v3h-3V5z" /></svg>`, russianSupport.interface, 'интерфейс');
                const plum = createFruitIndicator(`<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M15,21v-2c3.86,0,7-3.14,7-7s-3.14-7-7-7V3c4.96,0,9,4.04,9,9S19.96,21,15,21z M15,17v-2c1.65,0,3-1.35,3-3s-1.35-3-3-3V7 c2.76,0,5,2.24,5,5S17.76,17,15,17z M1,12v4h5l6,5V3L6,8H1V12" /></svg>`, russianSupport.voice, 'озвучка');
                const apricot = createFruitIndicator(`<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g><path d="M11,24l-4.4-5H0V0h23v19h-7.6L11,24z M2,17h5.4l3.6,4l3.6-4H21V2H2V17z" /></g><g><rect x="5" y="8" width="3" height="3" /></g><g><rect x="10" y="8" width="3" height="3" /></g><g><rect x="15" y="8" width="3" height="3" /></g></svg>`, russianSupport.subtitles, 'субтитры');

                lime.appendChild(peach);
                lime.appendChild(plum);
                lime.appendChild(apricot);

                lemon.style.position = 'relative';
                lemon.appendChild(lime);

                const appName = document.querySelector('#appHubAppName.apphub_AppName');
                if (appName) {
                    appName.style.maxWidth = '530px';
                    appName.style.overflow = 'hidden';
                    appName.style.textOverflow = 'ellipsis';
                    appName.style.whiteSpace = 'nowrap';
                    appName.title = appName.textContent;
                }
            }

            const additionalReviewsSettings = {
                showTotalReviews: true,
                showNonChineseReviews: true,
                showRussianReviews: true
            };

            let allReviewsDataGlobal = null;
            let schineseDataGlobal = null;
            let russianDataGlobal = null;
            let appidGlobal = null;

            function fetchReviews(appid, language, callback) {
                let url = `https://store.steampowered.com/appreviews/${appid}?json=1&language=${language}&purchase_type=all`;
                GM_xmlhttpRequest({
                    method: "GET",
                    url: url,
                    timeout: 15000,
                    onload: function(response) {
                        if (response.status >= 200 && response.status < 400) {
                            try {
                                let data = JSON.parse(response.responseText);
                                if (data.success === 1) {
                                    callback(data.query_summary);
                                } else {
                                    console.error(`Steam API error for ${language}:`, data);
                                    callback(null);
                                }
                            } catch (e) {
                                console.error(`Error parsing Steam API response for ${language}:`, e);
                                callback(null);
                            }
                        } else {
                            console.error(`Steam API request failed for ${language}. Status: ${response.status}`);
                            callback(null);
                        }
                    },
                    onerror: function(error) {
                        console.error(`Network error fetching reviews for ${language}:`, error);
                        callback(null);
                    },
                    ontimeout: function() {
                        console.error(`Timeout fetching reviews for ${language}`);
                        callback(null);
                    }
                });
            }

            function fetchRussianReviewsHTML(appid, filter, callback) {
                let url = `https://store.steampowered.com/appreviews/${appid}?language=russian&purchase_type=all&filter=${filter}&day_range=365`;
                GM_xmlhttpRequest({
                    method: "GET",
                    url: url,
                    timeout: 15000,
                    onload: function(response) {
                        if (response.status >= 200 && response.status < 400) {
                            try {
                                let data = JSON.parse(response.responseText);
                                if (data.success === 1) {
                                    callback(data.html);
                                } else {
                                    console.error('Error fetching Russian reviews HTML (success != 1):', data);
                                    callback('<p style="color: #ff6961;">Ошибка загрузки обзоров.</p>');
                                }
                            } catch (e) {
                                console.error('Error parsing Russian reviews HTML:', e);
                                callback('<p style="color: #ff6961;">Ошибка обработки ответа.</p>');
                            }
                        } else {
                            console.error(`Failed to fetch Russian reviews HTML. Status: ${response.status}`);
                            callback('<p style="color: #ff6961;">Ошибка сети при загрузке обзоров.</p>');
                        }
                    },
                    onerror: function(error) {
                        console.error('Network error fetching Russian reviews HTML:', error);
                        callback('<p style="color: #ff6961;">Ошибка сети.</p>');
                    },
                    ontimeout: function() {
                        console.error('Timeout fetching Russian reviews HTML');
                        callback('<p style="color: #ff6961;">Таймаут загрузки обзоров.</p>');
                    }
                });
            }

            function addStyles() {
                GM_addStyle(`
                        .additional-reviews {
                        	margin-top: 10px;
                        	padding-top: 10px;
                        	border-top: 1px solid #3e4c583d;
                        }

                        .additional-reviews .user_reviews_summary_row {
                        	display: flex;
                        	line-height: 16px;
                        	margin-bottom: 5px;
                        }

                        .additional-reviews .user_reviews_summary_row.clickable {
                        	cursor: pointer;
                        	transition: background-color 0.2s;
                        	border-radius: 2px;
                        	padding: 2px 4px;
                        	margin: 0 5px 5px -4px;
                        }

                        .additional-reviews .user_reviews_summary_row.clickable:hover {
                        	background-color: rgba(103, 193, 245, 0.1);
                        }

                        .additional-reviews .subtitle {
                        	flex: 1;
                        	color: #556772;
                        	font-size: 12px;
                        	user-select: none;
                        }

                        .additional-reviews .summary {
                        	flex: 3;
                        	color: #c6d4df;
                        	font-size: 12px;
                        	overflow: hidden;
                        	white-space: nowrap;
                        	text-overflow: ellipsis;
                        }

                        .additional-reviews .game_review_summary {
                        	font-weight: normal;
                        }

                        .additional-reviews .positive {
                        	color: #66c0f4;
                        }

                        .additional-reviews .mixed {
                        	color: #B9A074;
                        }

                        .additional-reviews .negative {
                        	color: #a34c25;
                        }

                        .additional-reviews .no_reviews {
                        	color: #929396;
                        }

                        .additional-reviews .responsive_hidden {
                        	color: #556772;
                        	margin-left: 5px;
                        }

                        .additional-reviews .summary-error {
                        	color: #ff6961;
                        	font-style: italic;
                        }

                        .ofxmodal {
                        	display: none;
                        	position: fixed;
                        	z-index: 1000;
                        	left: 0;
                        	top: 0;
                        	width: 100%;
                        	height: 100%;
                        	overflow: auto;
                        	background-color: rgba(0, 0, 0, 0.85);
                        	backdrop-filter: blur(3px);
                        }

                        .ofxmodal-content {
                        	background-color: #1b2838;
                        	margin: 8% auto;
                        	padding: 25px;
                        	border: 1px solid #567d9c;
                        	width: 80%;
                        	max-width: 900px;
                        	color: #c6d4df;
                        	position: relative;
                        	max-height: 80vh;
                        	overflow-y: auto;
                        	border-radius: 4px;
                        	font-family: "Motiva Sans", Arial, sans-serif;
                        	scrollbar-color: #4b6f9c #1b2838;
                        	scrollbar-width: thin;
                        }

                        .ofxmodal-content::-webkit-scrollbar {
                        	width: 8px;
                        }

                        .ofxmodal-content::-webkit-scrollbar-track {
                        	background: #1b2838;
                        	border-radius: 4px;
                        }

                        .ofxmodal-content::-webkit-scrollbar-thumb {
                        	background-color: #4b6f9c;
                        	border-radius: 4px;
                        	border: 2px solid #1b2838;
                        }

                        .ofxclose {
                            background: none;
                            border: none;
                            color: #aaa;
                            font-size: 30px;
                            font-weight: normal;
                            padding: 0 5px;
                            line-height: 1;
                            cursor: pointer;
                            transition: color 0.2s ease;
                            position: absolute;
                            top: 15px;
                            right: 15px;
                            z-index: 1001;
                        }

                        .ofxclose:hover {
                            color: #fff;
                            background: none;
                            transform: none;
                        }

                        .ofxclose:active {
                            color: #fff;
                            background: none;
                            transform: none;
                        }

                        .refresh-button {
                        	position: absolute;
                        	top: 20px;
                        	left: 25px;
                        	background: #66c0f4;
                        	color: #1b2838;
                        	padding: 10px 20px;
                        	border: none;
                        	cursor: pointer;
                        	z-index: 1001;
                        	border-radius: 2px;
                        	transition: background 0.2s ease, color 0.2s ease;
                        	font-weight: 500;
                        }

                        .refresh-button:hover {
                        	background: #45b0e6;
                        	color: #fff;
                        }

                        .refresh-button:active {
                        	background: #329cd4;
                        	transform: translateY(1px);
                        }

                        #reviews-container .review_box {
                        	background-color: #16202d;
                        	border: 1px solid #2a3f5a;
                        	margin-bottom: 15px;
                        	border-radius: 3px;
                        }

                        #reviews-container .title {
                        	color: #67c1f5;
                        }

                        #reviews-container .hours {
                        	color: #8f98a0;
                        }

                        #reviews-container .content {
                        	color: #acb2b8;
                        }

                        #reviews-container .posted,
                        #reviews-container .found_helpful {
                        	color: #556772;
                        	font-size: 11px;
                        }

                        #globalReviewsModal {
                        	display: none;
                        	position: fixed;
                        	z-index: 10000;
                        	left: 0;
                        	top: 0;
                        	width: 100%;
                        	height: 100%;
                        	overflow: hidden;
                        	background-color: rgba(0, 0, 0, 0.9);
                        	backdrop-filter: blur(5px);
                        	color: #c6d4df;
                        	font-family: "Motiva Sans", Arial, sans-serif;
                        }

                        #globalReviewsModal .modal-content-inner {
                        	background-color: #101822;
                        	margin: 3vh auto;
                        	padding: 0;
                        	border: 1px solid #67c1f5;
                        	width: 94%;
                        	max-width: 1400px;
                        	height: 94vh;
                        	display: flex;
                        	flex-direction: column;
                        	border-radius: 5px;
                        	box-shadow: 0 10px 40px rgba(0, 0, 0, 0.6);
                        }

                        #globalReviewsModal .modal-header {
                        	padding: 15px 25px;
                        	background-color: #16202d;
                        	border-bottom: 1px solid #2a3f5a;
                        	display: flex;
                        	justify-content: space-between;
                        	align-items: center;
                        	flex-shrink: 0;
                        }

                        #globalReviewsModal .modal-title {
                        	font-size: 20px;
                        	color: #67c1f5;
                        	font-weight: 500;
                        	margin: 0;
                        }

                        #globalReviewsModal .modal-close-btn {
                        	font-size: 30px;
                        	color: #aaa;
                        	background: none;
                        	border: none;
                        	cursor: pointer;
                        	line-height: 1;
                        	padding: 0 5px;
                        	transition: color 0.2s;
                        }

                        #globalReviewsModal .modal-close-btn:hover {
                        	color: #fff;
                        }

                        #globalReviewsModal .modal-body {
                        	display: flex;
                        	flex-grow: 1;
                        	overflow: hidden;
                        	padding: 20px 25px;
                        	gap: 25px;
                        }

                        #globalReviewsModal .modal-left-panel {
                        	width: 55%;
                        	display: flex;
                        	flex-direction: column;
                        	overflow: hidden;
                        }

                        #globalReviewsModal .modal-right-panel {
                        	width: 45%;
                        	display: flex;
                        	justify-content: center;
                        	align-items: center;
                        	position: relative;
                        	background-color: #16202d;
                        	border-radius: 4px;
                        	border: 1px solid #2a3f5a;
                        	padding: 15px;
                        }

                        #globalReviewsModal .controls-area {
                        	margin-bottom: 15px;
                        	display: flex;
                        	gap: 15px;
                        	align-items: center;
                        	flex-shrink: 0;
                        }

                        #globalReviewsModal .collect-btn {
                        	background: #66c0f4;
                        	color: #1b2838;
                        	padding: 10px 22px;
                        	border: none;
                        	cursor: pointer;
                        	border-radius: 3px;
                        	font-size: 14px;
                        	font-weight: bold;
                        	transition: background 0.2s, transform 0.1s;
                        }

                        #globalReviewsModal .collect-btn:hover:not(:disabled) {
                        	background: #8ad3f7;
                        }

                        #globalReviewsModal .collect-btn:active:not(:disabled) {
                        	transform: scale(0.98);
                        }

                        #globalReviewsModal .collect-btn:disabled {
                        	background: #556772;
                        	color: #8f98a0;
                        	cursor: not-allowed;
                        	opacity: 0.7;
                        }

                        #globalReviewsModal .progress-area {
                        	flex-grow: 1;
                        	display: flex;
                        	flex-direction: column;
                        	justify-content: center;
                        }

                        #globalReviewsModal .progress-bar-container {
                        	width: 100%;
                        	background-color: #0a1016;
                        	border-radius: 5px;
                        	height: 20px;
                        	overflow: hidden;
                        	border: 1px solid #2a3f5a;
                        	box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.4);
                        }

                        #globalReviewsModal .progress-bar-inner {
                        	width: 0%;
                        	height: 100%;
                        	background-color: #4b6f9c;
                        	background-image: linear-gradient(-45deg, rgba(255, 255, 255, .1) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .1) 50%, rgba(255, 255, 255, .1) 75%, transparent 75%, transparent);
                        	background-size: 30px 30px;
                        	transition: width 0.4s ease;
                        	text-align: right;
                        	color: #fff;
                        	font-weight: bold;
                        	line-height: 20px;
                        	font-size: 11px;
                        	padding-right: 8px;
                        	text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
                        }

                        #globalReviewsModal .progress-text {
                        	font-size: 11px;
                        	color: #8f98a0;
                        	margin-top: 3px;
                        	text-align: left;
                        	height: 1.2em;
                        }

                        #globalReviewsModal .table-container {
                        	flex-grow: 1;
                        	overflow: auto;
                        	border: 1px solid #2a3f5a;
                        	border-radius: 3px;
                        	background: #16202d;
                        	scrollbar-color: #4b6f9c #16202d;
                        	scrollbar-width: thin;
                        }

                        #globalReviewsModal .table-container::-webkit-scrollbar {
                        	width: 8px;
                        }

                        #globalReviewsModal .table-container::-webkit-scrollbar-track {
                        	background: #16202d;
                        	border-radius: 0 3px 3px 0;
                        }

                        #globalReviewsModal .table-container::-webkit-scrollbar-thumb {
                        	background-color: #4b6f9c;
                        	border-radius: 4px;
                        	border: 2px solid #16202d;
                        }

                        #globalReviewsModal .reviews-table {
                        	width: 100%;
                        	border-collapse: collapse;
                        	font-size: 13px;
                        }

                        #globalReviewsModal .reviews-table th,
                        #globalReviewsModal .reviews-table td {
                        	padding: 9px 12px;
                        	text-align: left;
                        	border-bottom: 1px solid #2a3f5a;
                        	white-space: nowrap;
                        }

                        #globalReviewsModal .reviews-table th {
                        	background-color: #1f2c3a;
                        	color: #8f98a0;
                        	font-weight: normal;
                        	position: sticky;
                        	top: 0;
                        	z-index: 1;
                        }

                        #globalReviewsModal .reviews-table td {
                        	color: #acb2b8;
                        	vertical-align: middle;
                        }

                        #globalReviewsModal .reviews-table tr:last-child td {
                        	border-bottom: none;
                        }

                        #globalReviewsModal .reviews-table tr:hover td {
                        	background-color: rgba(103, 193, 245, 0.05);
                        }

                        #globalReviewsModal .reviews-table .col-rank {
                        	width: 40px;
                        	text-align: center;
                        	color: #8f98a0;
                        }

                        #globalReviewsModal .reviews-table .col-check {
                        	width: 40px;
                        	text-align: center;
                        }

                        #globalReviewsModal .reviews-table .col-lang {
                        	width: auto;
                        }

                        #globalReviewsModal .reviews-table .col-count {
                        	width: 90px;
                        	text-align: right;
                        }

                        #globalReviewsModal .reviews-table .col-percent-total {
                        	width: 80px;
                        	text-align: right;
                        	color: #8f98a0;
                        }

                        #globalReviewsModal .reviews-table .col-percent-pos {
                        	width: 70px;
                        	text-align: right;
                        }

                        #globalReviewsModal .reviews-table input[type=checkbox] {
                        	accent-color: #67c1f5;
                        	width: 16px;
                        	height: 16px;
                        	cursor: pointer;
                        	vertical-align: middle;
                        }

                        #globalReviewsModal .no-reviews-info {
                        	margin-top: 15px;
                        	font-size: 13px;
                        	color: #8f98a0;
                        	padding: 0 5px;
                        }

                        #globalReviewsModal .chart-container {
                        	width: 100%;
                        	height: 100%;
                        	position: relative;
                        }

                        #globalReviewsModal #reviewsPieChart {
                        	max-width: 100%;
                        	max-height: 100%;
                        }

                        #globalReviewsModal .modal-footer {
                        	padding: 15px 25px;
                        	border-top: 1px solid #2a3f5a;
                        	background-color: #16202d;
                        	text-align: center;
                        	font-size: 12px;
                        	color: #8f98a0;
                        	line-height: 1.4;
                        	flex-shrink: 0;
                        }
                    `);
            }

            function formatNumber(number) {
                return number.toLocaleString('ru-RU');
            }

            function getReviewClass(percent, totalReviews) {
                if (totalReviews === 0) return 'no_reviews';
                if (percent === null || typeof percent === 'undefined') return 'no_reviews';
                if (percent >= 70) return 'positive';
                if (percent >= 40) return 'mixed';
                return 'negative';
            }

            function addLoadButton() {
                let reviewsContainer = document.querySelector('.user_reviews');
                if (reviewsContainer) {
                    const existingButton = document.getElementById('load-reviews-button');
                    if (existingButton) existingButton.remove();
                    const existingReviews = document.querySelector('.additional-reviews');
                    if (existingReviews) existingReviews.remove();

                    let additionalReviewsContainer = document.createElement('div');
                    additionalReviewsContainer.className = 'additional-reviews';

                    let loadButton = document.createElement('div');
                    loadButton.className = 'user_reviews_summary_row clickable';
                    loadButton.id = 'load-reviews-button';
                    loadButton.innerHTML = `
                            <div class="subtitle column all">Доп. обзоры:</div>
                            <div class="summary column">
                                <span class="game_review_summary no_reviews">Загрузить статистику</span>
                            </div>
                        `;

                    additionalReviewsContainer.appendChild(loadButton);
                    reviewsContainer.appendChild(additionalReviewsContainer);

                    loadButton.addEventListener('click', loadAdditionalReviews);

                    if (scriptsConfig.autoLoadReviews) {
                        loadAdditionalReviews();
                    }
                }
            }

            function loadAdditionalReviews() {
                appidGlobal = unsafeWindow.location.pathname.match(/\/app\/(\d+)/)[1];
                if (!appidGlobal) return;

                let loadButton = document.getElementById('load-reviews-button');
                if (loadButton) {
                    loadButton.querySelector('.game_review_summary').textContent = 'Загрузка...';
                    loadButton.style.pointerEvents = 'none';
                    loadButton.style.opacity = '0.6';
                }

                const languagesToFetch = ['all', 'schinese', 'russian'];
                let fetchedData = {};
                let completedRequests = 0;

                languagesToFetch.forEach(language => {
                    fetchReviews(appidGlobal, language, (summaryData) => {
                        fetchedData[language] = summaryData;
                        completedRequests++;

                        if (completedRequests === languagesToFetch.length) {
                            allReviewsDataGlobal = fetchedData['all'];
                            schineseDataGlobal = fetchedData['schinese'];
                            russianDataGlobal = fetchedData['russian'];
                            displayAdditionalReviews(allReviewsDataGlobal, schineseDataGlobal, russianDataGlobal);

                            if (loadButton) {
                                loadButton.remove();
                            }
                        }
                    });
                });
            }

            function displayAdditionalReviews(allReviews, schineseReviews, russianReviews) {
                let additionalReviewsContainer = document.querySelector('.additional-reviews');
                if (!additionalReviewsContainer) return;

                additionalReviewsContainer.innerHTML = '';

                const addReviewRow = (id, title, reviewsData, isClickable = false, onClick = null) => {
                    const row = document.createElement('div');
                    row.className = 'user_reviews_summary_row';
                    if (isClickable) {
                        row.classList.add('clickable');
                        row.addEventListener('click', onClick);
                    }
                    row.id = id;

                    let percent = 0;
                    let total = 0;
                    let statusClass = 'no_reviews';
                    let summaryText = 'Нет данных';
                    let errorText = null;

                    if (reviewsData === null) {
                        errorText = 'Ошибка загрузки';
                        statusClass = 'summary-error';
                    } else if (reviewsData) {
                        total = reviewsData.total_reviews;
                        if (total > 0) {
                            percent = total > 0 ? Math.round((reviewsData.total_positive / total) * 100) : 0;
                            statusClass = getReviewClass(percent, total);
                            summaryText = `${percent}% из ${formatNumber(total)} положительные`;
                        } else {
                            summaryText = 'Нет обзоров';
                            statusClass = 'no_reviews';
                        }
                    } else {
                        summaryText = 'Нет данных';
                        statusClass = 'no_reviews';
                    }

                    row.innerHTML = `
                            <div class="subtitle column all">${title}:</div>
                            <div class="summary column">
                                <span class="game_review_summary ${statusClass}">${errorText || summaryText}</span>
                            </div>
                        `;
                    additionalReviewsContainer.appendChild(row);
                };

                if (additionalReviewsSettings.showTotalReviews) {
                    addReviewRow('total-reviews-row', 'Тотальные', allReviews, true, openGlobalReviewsModal);
                }

                if (additionalReviewsSettings.showNonChineseReviews) {
                    let nonChineseSummary = null;
                    let nonChineseError = null;
                    if (allReviews === null || schineseReviews === null) {
                        nonChineseError = 'Ошибка загрузки';
                    } else if (allReviews && schineseReviews) {
                        nonChineseSummary = { total_reviews: 0, total_positive: 0, review_score: 0 };
                        nonChineseSummary.total_reviews = Math.max(0, allReviews.total_reviews - schineseReviews.total_reviews);
                        nonChineseSummary.total_positive = Math.max(0, allReviews.total_positive - schineseReviews.total_positive);
                        if (nonChineseSummary.total_reviews > 0) {
                            const percent = Math.round((nonChineseSummary.total_positive / nonChineseSummary.total_reviews) * 100);
                            if (percent >= 70) nonChineseSummary.review_score = 8;
                            else if (percent >= 40) nonChineseSummary.review_score = 5;
                            else nonChineseSummary.review_score = 2;
                        } else {
                            nonChineseSummary.review_score = 0;
                        }
                    }
                    const row = document.createElement('div');
                    row.className = 'user_reviews_summary_row';
                    row.id = 'non-chinese-reviews-row';
                    let percent = 0;
                    let total = 0;
                    let statusClass = 'no_reviews';
                    let summaryText = 'Нет данных';

                    if (nonChineseError) {
                        summaryText = nonChineseError;
                        statusClass = 'summary-error';
                    } else if (nonChineseSummary) {
                        total = nonChineseSummary.total_reviews;
                        if (total > 0) {
                            percent = Math.round((nonChineseSummary.total_positive / total) * 100);
                            statusClass = getReviewClass(percent, total);
                            summaryText = `${percent}% из ${formatNumber(total)} положительные`;
                        } else {
                            summaryText = 'Нет обзоров';
                            statusClass = 'no_reviews';
                        }
                    }

                    row.innerHTML = `
                            <div class="subtitle column all">Безкитайские:</div>
                            <div class="summary column">
                                <span class="game_review_summary ${statusClass}">${summaryText}</span>
                            </div>
                        `;
                    additionalReviewsContainer.appendChild(row);
                }

                if (additionalReviewsSettings.showRussianReviews) {
                    addReviewRow('russian-reviews-row', 'Русские', russianReviews, true, openRussianReviewsModal);
                }
            }

            function openRussianReviewsModal() {
                let modal = document.getElementById('russianReviewsModal');
                if (!modal) {
                    modal = document.createElement('div');
                    modal.id = 'russianReviewsModal';
                    modal.className = 'ofxmodal';
                    modal.innerHTML = `
                            <div class="ofxmodal-content">
                                <span class="ofxclose" title="Закрыть">&times;</span>
                                <button class="refresh-button" id="refresh-reviews">Загрузить актуальные</button>
                                <h3 style="text-align: center; color: #67c1f5; margin-top: 5px; margin-bottom: 25px;">Русскоязычные обзоры</h3>
                                <div id="reviews-container" style="padding-top: 10px;">Загрузка...</div>
                            </div>
                        `;
                    document.body.appendChild(modal);

                    modal.querySelector('.ofxclose').addEventListener('click', () => modal.style.display = 'none');
                    modal.querySelector('#refresh-reviews').addEventListener('click', () => refreshRussianReviews(modal));
                    modal.addEventListener('click', (event) => {
                        if (event.target === modal) {
                            modal.style.display = 'none';
                        }
                    });
                }

                modal.style.display = 'block';
                loadRussianReviews(modal, 'all');
            }

            function refreshRussianReviews(modal) {
                modal.querySelector('#reviews-container').innerHTML = 'Загрузка актуальных...';
                loadRussianReviews(modal, 'recent');
            }

            function loadRussianReviews(modal, filter) {
                if (!appidGlobal) return;
                fetchRussianReviewsHTML(appidGlobal, filter, function(html) {
                    const container = modal.querySelector('#reviews-container');
                    container.innerHTML = html;
                    container.querySelector('#LoadMoreReviewsall')?.remove();
                    container.querySelector('#LoadMoreReviewsrecent')?.remove();
                    container.querySelectorAll('a').forEach(a => a.target = '_blank');
                });
            }

            let globalReviewsChart = null;
            let allLanguageData = [];

            const steamLanguages = {
                'english': 'Английский', 'german': 'Немецкий', 'french': 'Французский', 'italian': 'Итальянский',
                'koreana': 'Корейский', 'spanish': 'Испанский', 'schinese': 'Упр. китайский',
                'tchinese': 'Трад. китайский',
                'russian': 'Русский', 'thai': 'Тайский', 'japanese': 'Японский',
                'portuguese': 'Португальский', 'polish': 'Польский', 'danish': 'Датский', 'dutch': 'Нидерландский',
                'finnish': 'Финский', 'norwegian': 'Норвежский', 'swedish': 'Шведский', 'hungarian': 'Венгерский',
                'czech': 'Чешский', 'romanian': 'Румынский', 'turkish': 'Турецкий', 'bulgarian': 'Болгарский',
                'greek': 'Греческий', 'ukrainian': 'Украинский', 'latam': 'Испанский Лат. Ам.',
                'vietnamese': 'Вьетнамский', 'indonesian': 'Индонезийский', 'brazilian': 'Португ. (Браз.)'
            };

            function openGlobalReviewsModal() {
                let modal = document.getElementById('globalReviewsModal');
                if (!modal) {
                    modal = createGlobalReviewsModalStructure();
                    document.body.appendChild(modal);
                }
                const tableBody = document.getElementById('global-reviews-table-body');
                const noReviewsInfo = document.getElementById('global-reviews-no-reviews-info');
                const collectBtn = document.getElementById('global-reviews-collect-btn');
                const progressBar = document.getElementById('global-reviews-progress-bar');
                const progressText = document.getElementById('global-reviews-progress-text');

                if (tableBody) {
                    tableBody.innerHTML = '<tr><td colspan="6" style="text-align:center; padding: 20px; color: #8f98a0;">Нажмите "Собрать", чтобы загрузить данные.</td></tr>';
                }
                if (noReviewsInfo) {
                    noReviewsInfo.textContent = '';
                } else {
                    console.error("Element with ID 'global-reviews-no-reviews-info' not found during reset!");
                }
                if (collectBtn) {
                    collectBtn.disabled = false;
                }
                if (progressBar) {
                    progressBar.style.width = '0%';
                    progressBar.textContent = '';
                }
                if (progressText) {
                    progressText.textContent = '';
                }

                if (globalReviewsChart) {
                    globalReviewsChart.destroy();
                    globalReviewsChart = null;
                }

                const modalElement = document.getElementById('globalReviewsModal');
                if (modalElement) {
                    modalElement.style.display = 'block';
                } else {
                    console.error("Modal element #globalReviewsModal not found when trying to display!");
                }
                document.body.style.overflow = 'hidden';
            }

            function closeGlobalReviewsModal() {
                const modal = document.getElementById('globalReviewsModal');
                if (modal) {
                    modal.style.display = 'none';
                    if (modal._escHandler) {
                        document.removeEventListener('keydown', modal._escHandler);
                        delete modal._escHandler;
                    }
                }
                document.body.style.overflow = '';
            }

            function createGlobalReviewsModalStructure() {
                const modal = document.createElement('div');
                modal.id = 'globalReviewsModal';
                modal.innerHTML = `
                        <div class="modal-content-inner">
                            <div class="modal-header">
                                <h3 class="modal-title">Глобальный монитор обзоров</h3>
                                <button class="modal-close-btn" title="Закрыть">&times;</button>
                            </div>
                            <div class="modal-body">
                                <div class="modal-left-panel">
                                    <div class="controls-area">
                                        <button id="global-reviews-collect-btn" class="collect-btn">Собрать</button>
                                        <div class="progress-area">
                                            <div class="progress-bar-container">
                                                <div id="global-reviews-progress-bar" class="progress-bar-inner"></div>
                                            </div>
                                            <div id="global-reviews-progress-text" class="progress-text"></div>
                                        </div>
                                    </div>
                                    <div class="table-container">
                                        <table class="reviews-table">
                                            <thead>
                                                <tr>
                                                    <th class="col-rank">#</th>
                                                    <th class="col-check" title="Показать на диаграмме">📊</th>
                                                    <th class="col-lang">Язык</th>
                                                    <th class="col-count">Обзоры</th>
                                                    <th class="col-percent-total">% Общ</th>
                                                    <th class="col-percent-pos">% 👍</th>
                                                </tr>
                                            </thead>
                                            <tbody id="global-reviews-table-body">
                                               <tr><td colspan="6" style="text-align:center; padding: 20px; color: #8f98a0;">Нажмите "Собрать", чтобы загрузить данные.</td></tr>
                                            </tbody>
                                        </table>
                                    </div>
                                    <div id="global-reviews-no-reviews-info" class="no-reviews-info"></div>
                                </div>
                                <div class="modal-right-panel">
                                    <div class="chart-container">
                                        <canvas id="reviewsPieChart"></canvas>
                                    </div>
                                </div>
                            </div>
                            <div class="modal-footer">
                                <strong>Внимание:</strong> Загрузка данных для каждого языка отправляет отдельный запрос к Steam.<br>Частое использование на множестве игр может привести к временным ограничениям со стороны Steam.
                            </div>
                        </div>
                    `;

                modal.querySelector('.modal-close-btn').addEventListener('click', closeGlobalReviewsModal);
                modal.querySelector('#global-reviews-collect-btn').addEventListener('click', () => {
                    startGlobalReviewCollection(appidGlobal, russianDataGlobal, schineseDataGlobal);
                });
                modal.addEventListener('click', (event) => {
                    if (event.target === modal) {
                        closeGlobalReviewsModal();
                    }
                });
                modal._escHandler = (event) => {
                    if (event.key === "Escape") {
                        closeGlobalReviewsModal();
                    }
                };
                document.addEventListener('keydown', modal._escHandler);

                return modal;
            }

            async function startGlobalReviewCollection(appid, existingRussianData, existingSchineseData) {
                const collectBtn = document.getElementById('global-reviews-collect-btn');
                const progressBar = document.getElementById('global-reviews-progress-bar');
                const progressText = document.getElementById('global-reviews-progress-text');
                const tableBody = document.getElementById('global-reviews-table-body');
                const noReviewsInfo = document.getElementById('global-reviews-no-reviews-info');

                if (!collectBtn || !progressBar || !progressText || !tableBody || !noReviewsInfo) {
                    console.error("[Global Reviews Monitor] Could not find all necessary modal elements. Aborting collection.");
                    if (tableBody) tableBody.innerHTML = '<tr><td colspan="6" style="text-align:center; padding: 20px; color: #ff6961;">Ошибка: Не найдены элементы интерфейса. Попробуйте закрыть и снова открыть окно.</td></tr>';
                    return;
                }

                collectBtn.disabled = true;
                tableBody.innerHTML = '<tr><td colspan="6" style="text-align:center; padding: 20px; color: #8f98a0;">Загрузка данных... <span class="spinner"></span></td></tr>';
                noReviewsInfo.textContent = '';
                if (globalReviewsChart) {
                    globalReviewsChart.destroy();
                    globalReviewsChart = null;
                }
                const canvas = document.getElementById('reviewsPieChart');
                if (canvas) {
                    const ctx = canvas.getContext('2d');
                    ctx.clearRect(0, 0, canvas.width, canvas.height);
                }

                allLanguageData = [];

                if (existingRussianData && typeof existingRussianData === 'object') {
                    allLanguageData.push({ langCode: 'russian', langName: steamLanguages['russian'], summary: existingRussianData, visible: true, fetched: true });
                } else {
                    allLanguageData.push({ langCode: 'russian', langName: steamLanguages['russian'], summary: null, visible: true, fetched: false });
                }
                if (existingSchineseData && typeof existingSchineseData === 'object') {
                    allLanguageData.push({ langCode: 'schinese', langName: steamLanguages['schinese'], summary: existingSchineseData, visible: true, fetched: true });
                } else {
                    allLanguageData.push({ langCode: 'schinese', langName: steamLanguages['schinese'], summary: null, visible: true, fetched: false });
                }

                const languagesToFetch = Object.keys(steamLanguages).filter(lang => lang !== 'russian' && lang !== 'schinese');
                const totalLanguagesToFetch = languagesToFetch.length;
                let completedFetches = 0;
                let errors = 0;

                const updateProgress = () => {
                    const totalCompleted = completedFetches + errors;
                    const percentage = totalLanguagesToFetch > 0 ? Math.round((totalCompleted / totalLanguagesToFetch) * 100) : 100;
                    if (progressBar) {
                        progressBar.style.width = `${percentage}%`;
                        progressBar.textContent = `${percentage}%`;
                    }
                    if (progressText) {
                        progressText.textContent = `Обработано: ${totalCompleted} из ${totalLanguagesToFetch} языков (Успешно: ${completedFetches}, Ошибок: ${errors})`;
                    }
                };

                progressBar.textContent = '';
                updateProgress();

                for (const langCode of languagesToFetch) {
                    if (!appid) {
                        console.error("[Global Reviews Monitor] AppID is missing, stopping fetch loop.");
                        if (progressText) progressText.textContent = 'Ошибка: AppID не найден.';
                        if (collectBtn) collectBtn.disabled = false;
                        return;
                    }

                    const langName = steamLanguages[langCode];
                    try {
                        const summaryData = await new Promise((resolve) => {
                            fetchReviews(appid, langCode, resolve);
                        });

                        const existingIndex = allLanguageData.findIndex(d => d.langCode === langCode);
                        if (existingIndex > -1) {
                            allLanguageData[existingIndex].summary = summaryData;
                            allLanguageData[existingIndex].fetched = (summaryData !== null);
                        } else {
                            allLanguageData.push({ langCode, langName, summary: summaryData, visible: true, fetched: (summaryData !== null) });
                        }

                        if (summaryData !== null) {
                            completedFetches++;
                        } else {
                            errors++;
                        }
                    } catch (error) {
                        console.error(`Error processing fetch for ${langName}:`, error);
                        const existingIndex = allLanguageData.findIndex(d => d.langCode === langCode);
                        if (existingIndex === -1) {
                            allLanguageData.push({ langCode, langName, summary: null, visible: true, fetched: false });
                        }
                        errors++;
                    }
                    updateProgress();
                    await new Promise(resolve => setTimeout(resolve, 200));
                }

                renderGlobalReviewResults();
                if (collectBtn) collectBtn.disabled = false;
                if (progressText) progressText.textContent += ' - Готово!';
            }

            function renderGlobalReviewResults() {
                const tableBody = document.getElementById('global-reviews-table-body');
                const noReviewsInfo = document.getElementById('global-reviews-no-reviews-info');
                if (!tableBody || !noReviewsInfo) return;

                tableBody.innerHTML = '';
                noReviewsInfo.textContent = '';

                const languagesWithErrors = allLanguageData.filter(data => !data.fetched && data.summary === null);
                const validLanguageData = allLanguageData.filter(data => data.fetched && data.summary !== null);
                const languagesWithZeroReviews = [];

                const totalReviews = validLanguageData.reduce((sum, data) => sum + (data.summary?.total_reviews || 0), 0);

                validLanguageData.sort((a, b) => (b.summary?.total_reviews || 0) - (a.summary?.total_reviews || 0));

                if (validLanguageData.length === 0 && languagesWithErrors.length === 0) {
                    tableBody.innerHTML = '<tr><td colspan="6" style="text-align:center; padding: 20px; color: #8f98a0;">Нет обзоров ни на одном языке или не удалось загрузить данные.</td></tr>';
                    return;
                } else if (validLanguageData.length === 0 && languagesWithErrors.length > 0) {
                    tableBody.innerHTML = '<tr><td colspan="6" style="text-align:center; padding: 20px; color: #ff6961;">Не удалось загрузить данные об обзорах.</td></tr>';
                }

                validLanguageData.forEach((data, index) => {
                    const summary = data.summary;
                    const reviewCount = summary?.total_reviews || 0;
                    const positiveCount = summary?.total_positive || 0;
                    const percentTotal = totalReviews > 0 ? ((reviewCount / totalReviews) * 100).toFixed(1) : '0.0';
                    const percentPositive = reviewCount > 0 ? Math.round((positiveCount / reviewCount) * 100) : 0;
                    const reviewClass = getReviewClass(percentPositive, reviewCount);

                    if (reviewCount === 0) {
                        languagesWithZeroReviews.push(data.langName);
                        return;
                    }

                    const row = document.createElement('tr');
                    row.dataset.langCode = data.langCode;
                    row.innerHTML = `
                            <td class="col-rank">${index + 1}</td>
                            <td class="col-check"><input type="checkbox" class="chart-toggle-checkbox" data-lang-code="${data.langCode}" ${data.visible ? 'checked' : ''}></td>
                            <td class="col-lang">${data.langName}</td>
                            <td class="col-count">${formatNumber(reviewCount)}</td>
                            <td class="col-percent-total">${percentTotal}%</td>
                            <td class="col-percent-pos"><span class="game_review_summary ${reviewClass}">${reviewCount > 0 ? percentPositive + '%' : '-'}</span></td>
                        `;
                    tableBody.appendChild(row);
                });

                tableBody.querySelectorAll('.chart-toggle-checkbox').forEach(checkbox => {
                    checkbox.addEventListener('change', handleChartToggle);
                });

                let infoTextParts = [];
                if (languagesWithZeroReviews.length > 0) {
                    infoTextParts.push(`На этих языках нет обзоров: ${languagesWithZeroReviews.join(', ')}`);
                }
                if (languagesWithErrors.length > 0) {
                    infoTextParts.push(`Ошибки загрузки для: ${languagesWithErrors.map(l => l.langName).join(', ')}`);
                }
                noReviewsInfo.textContent = infoTextParts.join('. ');

                updateGlobalReviewsChart();
            }

            function handleChartToggle(event) {
                const langCode = event.target.dataset.langCode;
                const isVisible = event.target.checked;

                const langData = allLanguageData.find(d => d.langCode === langCode);
                if (langData) {
                    langData.visible = isVisible;
                }
                updateGlobalReviewsChart();
            }

            function updateGlobalReviewsChart() {
                const ctx = document.getElementById('reviewsPieChart')?.getContext('2d');
                if (!ctx) return;

                const visibleData = allLanguageData
                    .filter(data => data.visible && data.summary && data.summary.total_reviews > 0)
                    .sort((a, b) => (b.summary?.total_reviews || 0) - (a.summary?.total_reviews || 0));

                const chartLabels = [];
                const chartDataPoints = [];
                const chartColors = [];
                let otherCount = 0;
                const otherLanguagesTooltipDetails = [];

                const topN = 6;

                const totalVisibleReviews = visibleData.reduce((sum, data) => sum + data.summary.total_reviews, 0);

                const colorPalette = [
                    '#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b',
                    '#e377c2', '#7f7f7f', '#bcbd22', '#17becf', '#aec7e8', '#ffbb78',
                    '#98df8a', '#ff9896', '#c5b0d5', '#c49c94', '#f7b6d2', '#c7c7c7',
                    '#dbdb8d', '#9edae5'
                ];

                visibleData.forEach((data, index) => {
                    const count = data.summary.total_reviews;
                    if (index < topN) {
                        chartLabels.push(data.langName);
                        chartDataPoints.push(count);
                        chartColors.push(colorPalette[index % colorPalette.length]);
                    } else {
                        otherCount += count;
                        otherLanguagesTooltipDetails.push(`${data.langName}: ${formatNumber(count)}`);
                    }
                });

                if (otherCount > 0) {
                    chartLabels.push('Другие');
                    chartDataPoints.push(otherCount);
                    chartColors.push('#808080');
                }

                if (globalReviewsChart) {
                    globalReviewsChart.destroy();
                    globalReviewsChart = null;
                }

                if (chartDataPoints.length > 0) {
                    globalReviewsChart = new Chart(ctx, {
                        type: 'pie',
                        data: {
                            labels: chartLabels,
                            datasets: [{
                                data: chartDataPoints,
                                backgroundColor: chartColors,
                                borderColor: '#101822',
                                borderWidth: 2,
                                hoverOffset: 8,
                                hoverBorderColor: '#FFF'
                            }]
                        },
                        options: {
                            responsive: true,
                            maintainAspectRatio: false,
                            animation: {
                                animateScale: true,
                                animateRotate: true
                            },
                            plugins: {
                                legend: {
                                    position: 'right',
                                    align: 'center',
                                    labels: {
                                        color: '#c6d4df',
                                        padding: 12,
                                        font: { size: 12 },
                                        boxWidth: 12,
                                        usePointStyle: true,
                                    }
                                },
                                tooltip: {
                                    callbacks: {
                                        label: function(context) {
                                            let label = context.label || '';
                                            const value = context.parsed || 0;
                                            const percentage = totalVisibleReviews > 0 ? ((value / totalVisibleReviews) * 100).toFixed(1) : 0;
                                            let tooltipText = [];

                                            if (label) {
                                                tooltipText.push(`${label}: ${formatNumber(value)} (${percentage}%)`);
                                            }

                                            if (context.label === 'Другие' && otherLanguagesTooltipDetails.length > 0) {
                                                tooltipText.push('');
                                                tooltipText.push('Включает:');
                                                const maxTooltipItems = 10;
                                                const displayedItems = otherLanguagesTooltipDetails.slice(0, maxTooltipItems);
                                                const remainingItems = otherLanguagesTooltipDetails.length - maxTooltipItems;
                                                tooltipText.push(...displayedItems);
                                                if (remainingItems > 0) {
                                                    tooltipText.push(`...и еще ${remainingItems}`);
                                                }
                                            }
                                            return tooltipText;
                                        }
                                    },
                                    backgroundColor: 'rgba(16, 24, 34, 0.9)',
                                    titleFont: { size: 13, weight: 'bold' },
                                    bodyFont: { size: 12 },
                                    padding: 10,
                                    cornerRadius: 4,
                                    bodySpacing: 4,
                                    multiKeyBackground: 'transparent'
                                },
                                datalabels: {
                                    formatter: (value, ctx) => {
                                        const percentage = totalVisibleReviews > 0 ? ((value / totalVisibleReviews) * 100) : 0;
                                        if (percentage < 3) {
                                            return null;
                                        }
                                        let label = ctx.chart.data.labels[ctx.dataIndex] || '';
                                        if (label.length > 15 && label !== 'Другие') {
                                            const parts = label.split(' ');
                                            label = parts.length > 1 ? parts[0] : label.substring(0, 12) + '...';
                                        }
                                        return `${label}\n${percentage.toFixed(0)}%`;
                                    },
                                    color: '#FFFFFF',
                                    font: {
                                        weight: 'bold',
                                        size: 12,
                                        family: '"Motiva Sans", Arial, sans-serif'
                                    },
                                    backgroundColor: 'rgba(16, 24, 34, 0.75)',
                                    borderRadius: 3,
                                    padding: {
                                        top: 3,
                                        bottom: 3,
                                        left: 6,
                                        right: 6
                                    },
                                    anchor: 'end',
                                    align: 'start',
                                    offset: 15,
                                    display: function(context) {
                                        const percentage = totalVisibleReviews > 0 ? ((context.dataset.data[context.dataIndex] / totalVisibleReviews) * 100) : 0;
                                        return percentage >= 3;
                                    },
                                }
                            },
                            layout: {
                                padding: {
                                    top: 25,
                                    bottom: 25,
                                    left: 25,
                                    right: 25
                                }
                            }
                        }
                    });
                } else {
                    const canvas = document.getElementById('reviewsPieChart');
                    if (canvas) {
                        const ctx = canvas.getContext('2d');
                        ctx.clearRect(0, 0, canvas.width, canvas.height);
                        ctx.fillStyle = '#8f98a0';
                        ctx.textAlign = 'center';
                        ctx.font = '14px "Motiva Sans", Arial, sans-serif';
                        ctx.fillText('Нет данных для отображения диаграммы', canvas.width / 2, canvas.height / 2);
                    }
                }
            }

            function getLanguageColor(index) {
                const colors = [
                    '#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b',
                    '#e377c2', '#7f7f7f', '#bcbd22', '#17becf', '#aec7e8', '#ffbb78',
                    '#98df8a', '#ff9896', '#c5b0d5', '#c49c94', '#f7b6d2', '#c7c7c7',
                    '#dbdb8d', '#9edae5'
                ];
                return colors[index % colors.length];
            }

            function main() {
                addStyles();
                addRussianIndicators();
                addLoadButton();
            }

            const observer = new MutationObserver((mutations, obs) => {
                const reviewsContainer = document.querySelector('.user_reviews');
                const headerImage = document.querySelector('#gameHeaderImageCtn');
                const langTable = document.querySelector('#languageTable');

                if (headerImage) {
                    main();
                    obs.disconnect();
                }
            });

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

        })();
    }

    // Скрипт для страницы игры (HLTB; получение сведений о времени прохождения) | https://store.steampowered.com/app/*
    if (window.location.pathname.includes('/app/') && scriptsConfig.hltbData) {
        (async function() {
            let hltbBlock = document.createElement('div');
            Object.assign(hltbBlock.style, {
                position: 'absolute',
                top: '0',
                left: '334px',
                width: '30px',
                height: '30px',
                background: 'rgba(27, 40, 56, 0.95)',
                padding: '15px',
                borderRadius: '4px',
                border: '1px solid #3c3c3c',
                boxShadow: '0 0 10px rgba(0, 0, 0, 0.5)',
                zIndex: '2',
                fontFamily: 'Arial, sans-serif',
                overflow: 'hidden',
                opacity: '0',
                transition: 'opacity 0.3s ease, width 0.3s ease, height 0.3s ease'
            });

            let triangle = document.createElement('div');
            triangle.className = 'triangle-down';
            Object.assign(triangle.style, {
                position: 'absolute',
                bottom: '5px',
                left: '50%',
                transform: 'translateX(-50%)',
                width: '0',
                height: '0',
                borderLeft: '5px solid transparent',
                borderRight: '5px solid transparent',
                borderTop: '5px solid #67c1f5',
                cursor: 'pointer'
            });

            let title = document.createElement('div');
            Object.assign(title.style, {
                fontSize: '12px',
                fontWeight: 'bold',
                color: '#67c1f5',
                marginBottom: '10px',
                cursor: 'pointer'
            });
            title.textContent = 'HLTB';

            let content = document.createElement('div');
            Object.assign(content.style, {
                fontSize: '14px',
                color: '#c6d4df',
                display: 'none',
                whiteSpace: 'auto',
                padding: '0 0'
            });

            hltbBlock.append(triangle, title, content);
            document.querySelector('#gameHeaderImageCtn').appendChild(hltbBlock);

            let hltb_gameHeaderImageCtnNode = null;
            let hltb_gameHeaderImageCtnObserverInstance = null;
            let hltb_russianIndicatorsNode = null;
            let hltb_russianIndicatorsObserverInstance = null;


            const fadeInElement = (element) => {
                element.style.opacity = '0';
                requestAnimationFrame(() => {
                    element.style.opacity = '1';
                });
            };

            const updateHltbPosition = () => {
                let topPosition = '0px';
                if (scriptsConfig.gamePage) {
                    const russianIndicators = document.querySelector('#gameHeaderImageCtn > div[style*="position: absolute; top: -10px; left: calc(100% + 10px);"]');
                    if (russianIndicators) {
                        topPosition = `${russianIndicators.offsetTop + russianIndicators.offsetHeight + 16}px`;
                    }
                }
                hltbBlock.style.top = topPosition;
                hltbBlock.style.left = '334px';
                if (hltbBlock.style.opacity === '0') {
                    fadeInElement(hltbBlock);
                }
            };

            const hltb_manageRussianIndicatorsObserver = () => {
                const currentRussianIndicators = document.querySelector('#gameHeaderImageCtn > div[style*="position: absolute; top: -10px; left: calc(100% + 10px);"]');

                if (currentRussianIndicators) {
                    if (currentRussianIndicators !== hltb_russianIndicatorsNode || !hltb_russianIndicatorsObserverInstance) {
                        if (hltb_russianIndicatorsObserverInstance) {
                            hltb_russianIndicatorsObserverInstance.disconnect();
                        }
                        hltb_russianIndicatorsNode = currentRussianIndicators;
                        if (scriptsConfig.gamePage) {
                            hltb_russianIndicatorsObserverInstance = new MutationObserver(() => {
                                updateHltbPosition();
                            });
                            hltb_russianIndicatorsObserverInstance.observe(hltb_russianIndicatorsNode, {
                                attributes: true,
                                childList: true,
                                subtree: true
                            });
                        }
                    }
                } else {
                    if (hltb_russianIndicatorsObserverInstance) {
                        hltb_russianIndicatorsObserverInstance.disconnect();
                        hltb_russianIndicatorsObserverInstance = null;
                    }
                    hltb_russianIndicatorsNode = null;
                }
            };

            const hltb_setupPageChangeObservers = () => {
                hltb_gameHeaderImageCtnNode = document.querySelector('#gameHeaderImageCtn');
                if (!hltb_gameHeaderImageCtnNode) {
                    console.warn("HLTB: #gameHeaderImageCtn not found for main observer.");
                    return;
                }

                if (hltb_gameHeaderImageCtnObserverInstance) {
                    hltb_gameHeaderImageCtnObserverInstance.disconnect();
                }

                hltb_gameHeaderImageCtnObserverInstance = new MutationObserver((mutations) => {
                    let needsPosUpdateDueToContainerChange = false;
                    let russianIndicatorsPotentiallyChanged = false;

                    for (const mutation of mutations) {
                        if (mutation.type === 'childList') {
                            russianIndicatorsPotentiallyChanged = true;
                            needsPosUpdateDueToContainerChange = true;
                            break;
                        }
                    }

                    if (russianIndicatorsPotentiallyChanged) {
                        hltb_manageRussianIndicatorsObserver();
                    }
                    if (needsPosUpdateDueToContainerChange) {
                        updateHltbPosition();
                    }
                });

                hltb_gameHeaderImageCtnObserverInstance.observe(hltb_gameHeaderImageCtnNode, {
                    childList: true,
                    subtree: true
                });
                hltb_manageRussianIndicatorsObserver();
            };

            updateHltbPosition();
            hltb_setupPageChangeObservers();


            const handleClick = async function() {
                if (content.style.display === 'none') {
                    hltbBlock.style.transition = 'width 0.3s ease, height 0.3s ease';
                    updateHltbPosition();
                    await new Promise(resolve => setTimeout(resolve, 50));

                    hltbBlock.style.width = '200px';
                    hltbBlock.style.height = '40px';
                    await new Promise(resolve => setTimeout(resolve, 300));

                    content.textContent = 'Ищем в базе...';
                    content.style.display = 'block';
                    triangle.classList.remove('triangle-down');
                    triangle.classList.add('triangle-up');
                    triangle.style.borderTop = 'none';
                    triangle.style.borderBottom = '5px solid #67c1f5';

                    let gameName = getGameName();
                    let gameNameNormalized = normalizeGameName(gameName);
                    let orangutanFetchUrl = 'https://umadb.ro/hltb/fetch.php';
                    let orangutanHltbUrl = "https://howlongtobeat.com";

                    try {
                        const response = await new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: orangutanFetchUrl,
                                onload: resolve,
                                onerror: reject,
                                ontimeout: reject,
                                timeout: 7000
                            });
                        });
                        if (response.status === 200) {
                            const key = response.responseText.trim();
                            orangutanHltbUrl = "https://howlongtobeat.com" + key;
                        } else {
                            throw new Error('Failed to fetch key. Status: ' + response.status);
                        }
                    } catch (error) {
                        content.textContent = 'Ошибка при получении ключа.';
                        return;
                    }

                    let chimpQuery = '{"searchType":"games","searchTerms":[' + gameNameNormalized + '],"searchPage":1,"size":20,"searchOptions":{"games":{"userId":0,"platform":"","sortCategory":"popular","rangeCategory":"main","rangeTime":{"min":null,"max":null},"gameplay":{"perspective":"","flow":"","genre":"","difficulty":""},"rangeYear":{"min":"","max":""},"modifier":""},"users":{"sortCategory":"postcount"},"lists":{"sortCategory":"follows"},"filter":"","sort":0,"randomizer":0},"useCache":true}';
                    GM_xmlhttpRequest({
                        method: "POST",
                        url: orangutanHltbUrl,
                        data: chimpQuery,
                        headers: {
                            "Content-Type": "application/json",
                            "origin": "https://howlongtobeat.com",
                            "referer": "https://howlongtobeat.com/"
                        },
                        onload: async function(response) {
                            let baboonData = { count: 0, data: [] };
                            if (!response.responseText.includes("<title>HowLongToBeat - 404</title>")) {
                                try {
                                    baboonData = JSON.parse(response.responseText);
                                } catch (e) {
                                    content.textContent = 'Ошибка при обработке данных.';
                                    return;
                                }
                            }

                            if (baboonData.count === 0 && /[а-яё]/i.test(gameName)) {
                                const appId = unsafeWindow.location.pathname.split('/')[2];
                                const steamApiUrl = `https://api.steampowered.com/IStoreBrowseService/GetItems/v1?input_json={"ids": [{"appid": ${appId}}], "context": {"language": "english", "country_code": "US", "steam_realm": 1}, "data_request": {"include_assets": true}}`;
                                try {
                                    const steamResponse = await new Promise((resolve, reject) => {
                                        GM_xmlhttpRequest({
                                            method: "GET",
                                            url: steamApiUrl,
                                            onload: resolve,
                                            onerror: reject
                                        });
                                    });
                                    if (steamResponse.status === 200) {
                                        const steamData = JSON.parse(steamResponse.responseText);
                                        const englishName = steamData.response.store_items[0]?.name;
                                        if (englishName) {
                                            gameName = englishName;
                                            gameNameNormalized = normalizeGameName(gameName);
                                            chimpQuery = '{"searchType":"games","searchTerms":[' + gameNameNormalized + '],"searchPage":1,"size":20,"searchOptions":{"games":{"userId":0,"platform":"","sortCategory":"popular","rangeCategory":"main","rangeTime":{"min":null,"max":null},"gameplay":{"perspective":"","flow":"","genre":"","difficulty":""},"rangeYear":{"min":"","max":""},"modifier":""},"users":{"sortCategory":"postcount"},"lists":{"sortCategory":"follows"},"filter":"","sort":0,"randomizer":0},"useCache":true}';
                                            const secondResponse = await new Promise((resolve, reject) => {
                                                GM_xmlhttpRequest({
                                                    method: "POST",
                                                    url: orangutanHltbUrl,
                                                    data: chimpQuery,
                                                    headers: {
                                                        "Content-Type": "application/json",
                                                        "origin": "https://howlongtobeat.com",
                                                        "referer": "https://howlongtobeat.com/"
                                                    },
                                                    onload: resolve,
                                                    onerror: reject
                                                });
                                            });
                                            if (secondResponse.status === 200) {
                                                baboonData = JSON.parse(secondResponse.responseText);
                                            }
                                        }
                                    }
                                } catch (error) {
                                    console.error('Ошибка при запросе к Steam API:', error);
                                }
                            }

                            if (baboonData.count > 0) {
                                const matches = findPossibleMatches(gameName, baboonData.data);
                                if (matches.length > 0) {
                                    renderPossibleMatches(matches);
                                    hltbBlock.style.height = `${content.scrollHeight + 30}px`;
                                    return;
                                }
                            }
                            renderContent(baboonData.data[0]);
                            hltbBlock.style.height = `${content.scrollHeight + 30}px`;
                        },
                        onerror: function(error) { content.textContent = 'Ошибка при запросе к HLTB.'; },
                        ontimeout: function() { content.textContent = 'Тайм-аут при запросе к HLTB.'; },
                        timeout: 10000
                    });
                } else {
                    content.style.display = 'none';
                    hltbBlock.style.height = '30px';
                    hltbBlock.style.width = '30px';
                    triangle.classList.remove('triangle-up');
                    triangle.classList.add('triangle-down');
                    triangle.style.borderBottom = 'none';
                    triangle.style.borderTop = '5px solid #67c1f5';
                }
            };

            title.onclick = handleClick;
            triangle.onclick = handleClick;
            window.addEventListener('resize', updateHltbPosition);

            function normalizeGameName(name) {
                return name.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-zа-яё0-9 _'\-!]/gi, '').toLowerCase().split(/\s+/).map(word => `"${word}"`).join(",");
            }

            function findPossibleMatches(gameName, data) {
                const cleanGameName = gameName.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-zа-яё0-9 _'\-!]/gi, '').toLowerCase();
                return data.map(item => {
                    const cleanItemName = item.game_name.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-zа-яё0-9 _'\-!]/gi, '').toLowerCase();
                    const similarity = calculateSimilarity(cleanGameName, cleanItemName);
                    const startsWith = cleanItemName.startsWith(cleanGameName);
                    return { ...item, percentage: similarity, startsWith: startsWith };
                }).filter(item => item.percentage > 50 || item.startsWith)
                .sort((a, b) => {
                    if (a.startsWith && !b.startsWith) return -1;
                    if (!a.startsWith && b.startsWith) return 1;
                    return b.percentage - a.percentage;
                }).slice(0, 5);
            }

            function calculateSimilarity(str1, str2) {
                const len = Math.max(str1.length, str2.length);
                if (len === 0) return 100;
                const distance = levenshteinDistance(str1, str2);
                return Math.round(((len - distance) / len) * 100);
            }

            function levenshteinDistance(str1, str2) {
                const m = str1.length; const n = str2.length;
                const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
                for (let i = 0; i <= m; i++) {
                    for (let j = 0; j <= n; j++) {
                        if (i === 0) dp[i][j] = j;
                        else if (j === 0) dp[i][j] = i;
                        else dp[i][j] = Math.min(dp[i - 1][j - 1] + (str1[i - 1] === str2[j - 1] ? 0 : 1), dp[i - 1][j] + 1, dp[i][j - 1] + 1);
                    }
                }
                return dp[m][n];
            }

            function getTextWidth(text, font) {
                const canvas = document.createElement('canvas'); const context = canvas.getContext('2d');
                context.font = font; const metrics = context.measureText(text); return metrics.width;
            }

            function renderPossibleMatches(matches) {
                content.innerHTML = '';
                const title = document.createElement('div');
                title.textContent = 'Возможные совпадения:';
                title.style.color = '#67c1f5'; title.style.marginBottom = '10px'; content.appendChild(title);
                const list = document.createElement('ul');
                list.style.paddingLeft = '15px'; list.style.marginTop = '5px'; list.style.marginBottom = '0';
                matches.forEach(match => {
                    const li = document.createElement('li'); li.style.marginBottom = '8px';
                    const link = document.createElement('a'); link.href = '#';
                    link.textContent = `${match.game_name} (${match.percentage}%)`;
                    link.style.color = '#c6d4df'; link.style.wordBreak = 'break-word'; link.style.textDecoration = 'none';
                    link.onclick = () => { renderContent(match); hltbBlock.style.height = `${content.scrollHeight + 30}px`; return false; };
                    li.appendChild(link); list.appendChild(li);
                });
                const noMatch = document.createElement('li'); noMatch.style.marginBottom = '8px';
                const noMatchLink = document.createElement('a'); noMatchLink.href = '#';
                noMatchLink.textContent = 'Ничего не подходит';
                noMatchLink.style.color = '#c6d4df'; noMatchLink.style.wordBreak = 'break-word'; noMatchLink.style.textDecoration = 'none';
                noMatchLink.onclick = () => { renderContent(null); hltbBlock.style.height = `${content.scrollHeight + 30}px`; return false; };
                noMatch.appendChild(noMatchLink); list.appendChild(noMatch); content.appendChild(list);
                let maxWidth = 0;
                content.querySelectorAll('a').forEach(link => {
                    const text = link.textContent; const font = window.getComputedStyle(link).font;
                    const width = getTextWidth(text, font); if (width > maxWidth) maxWidth = width;
                });
                hltbBlock.style.width = `${Math.max(maxWidth + 40, 250)}px`;
            }

            function renderContent(entry) {
                content.innerHTML = '';
                if (!entry) { content.textContent = 'Игра не найдена в базе HLTB'; return; }
                const titleLink = document.createElement('a');
                titleLink.href = `https://howlongtobeat.com/game/${entry.game_id}`; titleLink.target = '_blank';
                titleLink.textContent = entry.game_name || 'Без названия';
                titleLink.style.color = '#67c1f5'; titleLink.style.wordBreak = 'break-word'; content.appendChild(titleLink);
                const list = document.createElement('ul');
                list.style.paddingLeft = '15px'; list.style.marginTop = '5px'; list.style.marginBottom = '0';
                const times = [
                    { label: 'Только сюжет', time: entry.comp_main, count: entry.comp_main_count },
                    { label: 'Сюжет + доп.', time: entry.comp_plus, count: entry.comp_plus_count },
                    { label: 'Комплеционист', time: entry.comp_100, count: entry.comp_100_count },
                    { label: 'Все стили', time: entry.comp_all, count: entry.comp_all_count }
                ];
                times.forEach(time => {
                    const li = document.createElement('li'); li.style.marginBottom = '8px';
                    const timeText = time.time ? formatTime(time.time) : "X";
                    li.innerHTML = `${time.label}: <span style="color: #fff;">${timeText}</span> (${time.count} чел.)`;
                    list.appendChild(li);
                });
                content.appendChild(list);
                let maxWidth = 0;
                content.querySelectorAll('li').forEach(child => {
                    const text = child.textContent; const font = window.getComputedStyle(child).font;
                    const width = getTextWidth(text, font); if (width > maxWidth) maxWidth = width;
                });
                hltbBlock.style.width = `${Math.max(maxWidth + 30, 200)}px`;
                hltbBlock.style.whiteSpace = 'nowrap';
            }

            function formatTime(seconds) {
                const hours = Math.floor(seconds / 3600); const minutes = Math.round((seconds % 3600) / 60);
                if (hours === 0) return `${minutes} м.`;
                else if (hours + (minutes / 60) >= hours + 0.5) return `${hours + 1} ч.`;
                else return `${hours} ч.`;
            }

            function getGameName() {
                return document.querySelector('.apphub_AppName').textContent.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[’]/g, "'").replace(/[^a-zA-Zа-яёА-ЯЁ0-9 _'\-!]/g, '').trim().toLowerCase();
            }

            if (scriptsConfig.autoExpandHltb) {
                handleClick();
            }
        })();
    }

    // Скрипт для страницы игры (ZOG; получение сведений о наличии русификаторов) | https://store.steampowered.com/app/*
    if (window.location.pathname.includes('/app/') && scriptsConfig.zogInfo) {
        (async function() {
            const zogBlock = document.createElement('div');
            Object.assign(zogBlock.style, {
                position: 'absolute', left: '334px', width: '30px', height: '30px',
                background: 'rgba(27, 40, 56, 0.95)', padding: '15px', borderRadius: '4px',
                border: '1px solid #3c3c3c', boxShadow: '0 0 10px rgba(0, 0, 0, 0.5)',
                zIndex: '2', fontFamily: 'Arial, sans-serif', overflow: 'hidden',
                transition: 'all 0.3s ease', visibility: 'hidden', opacity: '0'
            });

            let hltbBlockElement, hltbObserverInstance, hltbTransitionHandlerFunc,
                russianIndicatorsNode, russianIndicatorsObserverInstance,
                gameHeaderImageCtnNode, gameHeaderImageCtnObserverInstance;
            let isFirstUpdate = true;

            const alphabetMap = {
                'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7, 'h': 8, 'i': 9, 'j': 10,
                'k': 11, 'l': 12, 'm': 13, 'n': 14, 'o': 15, 'p': 16, 'q': 17, 'r': 18, 's': 19,
                't': 20, 'u': 21, 'v': 22, 'w': 23, 'x': 24, 'y': 25, 'z': 26, '#': 0
            };
            const russianAlphabetMap = {
                'а': 1, 'б': 2, 'в': 3, 'г': 4, 'д': 5, 'е': 6, 'ё': 6, 'ж': 7, 'з': 8, 'и': 9,
                'й': 9, 'к': 10, 'л': 11, 'м': 12, 'н': 13, 'о': 14, 'п': 15, 'р': 16, 'с': 17,
                'т': 18, 'у': 19, 'ф': 20, 'х': 21, 'ц': 22, 'ч': 23, 'ш': 24, 'щ': 25, 'э': 26,
                'ю': 27, 'я': 28
            };

            const updatePosition = () => {
                const localHltbBlock = document.querySelector('#gameHeaderImageCtn > div[style*="background: rgba(27, 40, 56, 0.95)"]');
                const localRussianIndicators = document.querySelector('#gameHeaderImageCtn > div[style*="position: absolute; top: -10px; left: calc(100% + 10px);"]');
                if (localHltbBlock && scriptsConfig.hltbData) {
                    zogBlock.style.top = `${localHltbBlock.offsetTop + localHltbBlock.offsetHeight + 16}px`;
                } else if (localRussianIndicators && scriptsConfig.gamePage) {
                    zogBlock.style.top = `${localRussianIndicators.offsetTop + localRussianIndicators.offsetHeight + 16}px`;
                } else {
                    if (document.querySelector('#gameHeaderImageCtn')) zogBlock.style.top = '0px';
                }
                zogBlock.style.left = '334px';
                zogBlock.style.zIndex = '2';
                if (isFirstUpdate) {
                    requestAnimationFrame(() => {
                        zogBlock.style.visibility = 'visible';
                        zogBlock.style.opacity = '1';
                    });
                    isFirstUpdate = false;
                }
            };

            const manageHltbObserver = () => {
                const currentHltbBlock = document.querySelector('#gameHeaderImageCtn > div[style*="background: rgba(27, 40, 56, 0.95)"]');
                if (currentHltbBlock) {
                    if (currentHltbBlock !== hltbBlockElement) {
                        if (hltbObserverInstance) hltbObserverInstance.disconnect();
                        if (hltbBlockElement && hltbTransitionHandlerFunc) hltbBlockElement.removeEventListener('transitionend', hltbTransitionHandlerFunc);
                        hltbBlockElement = currentHltbBlock;
                        if (scriptsConfig.hltbData) {
                            hltbObserverInstance = new ResizeObserver(updatePosition);
                            hltbObserverInstance.observe(hltbBlockElement);
                            hltbTransitionHandlerFunc = updatePosition;
                            hltbBlockElement.addEventListener('transitionend', hltbTransitionHandlerFunc);
                        }
                    }
                } else {
                    if (hltbObserverInstance) hltbObserverInstance.disconnect();
                    if (hltbBlockElement && hltbTransitionHandlerFunc) hltbBlockElement.removeEventListener('transitionend', hltbTransitionHandlerFunc);
                    hltbBlockElement = hltbObserverInstance = hltbTransitionHandlerFunc = null;
                }
            };

            const manageRussianIndicatorsObserver = () => {
                const currentIndicators = document.querySelector('#gameHeaderImageCtn > div[style*="position: absolute; top: -10px; left: calc(100% + 10px);"]');
                if (currentIndicators) {
                    if (currentIndicators !== russianIndicatorsNode) {
                        if (russianIndicatorsObserverInstance) russianIndicatorsObserverInstance.disconnect();
                        russianIndicatorsNode = currentIndicators;
                        if (scriptsConfig.gamePage) {
                            russianIndicatorsObserverInstance = new MutationObserver(mutations => mutations.forEach(m => { if (m.type === 'attributes' && m.attributeName === 'style') updatePosition(); }));
                            russianIndicatorsObserverInstance.observe(russianIndicatorsNode, { attributes: true, attributeFilter: ['style'] });
                        }
                    }
                } else {
                    if (russianIndicatorsObserverInstance) russianIndicatorsObserverInstance.disconnect();
                    russianIndicatorsNode = russianIndicatorsObserverInstance = null;
                }
            };

            const initDynamicElementObservers = () => {
                manageHltbObserver();
                manageRussianIndicatorsObserver();
            };

            const setupPageChangeObservers = () => {
                gameHeaderImageCtnNode = document.querySelector('#gameHeaderImageCtn');
                if (!gameHeaderImageCtnNode) return;
                if (gameHeaderImageCtnObserverInstance) gameHeaderImageCtnObserverInstance.disconnect();
                gameHeaderImageCtnObserverInstance = new MutationObserver(mutations => {
                    if (mutations.some(m => m.type === 'childList')) {
                        initDynamicElementObservers();
                        updatePosition();
                    }
                });
                gameHeaderImageCtnObserverInstance.observe(gameHeaderImageCtnNode, { childList: true, subtree: true });
                initDynamicElementObservers();
            };

            const title = document.createElement('div');
            Object.assign(title.style, { fontSize: '12px', fontWeight: 'bold', color: '#67c1f5', marginBottom: '10px', cursor: 'pointer' });
            title.textContent = 'ZOG';

            const content = document.createElement('div');
            Object.assign(content.style, { display: 'none', color: '#c6d4df', fontSize: '14px', maxWidth: '300px', overflowY: 'auto', whiteSpace: 'normal', lineHeight: '1.4', padding: '0 5px' });

            const arrow = document.createElement('div');
            Object.assign(arrow.style, { position: 'absolute', bottom: '5px', left: '50%', width: '0', height: '0', borderLeft: '5px solid transparent', borderRight: '5px solid transparent', borderTop: '5px solid #67c1f5', cursor: 'pointer', transition: 'transform 0.3s ease', transform: 'translateX(-50%)' });

            zogBlock.append(arrow, title, content);
            document.querySelector('#gameHeaderImageCtn').appendChild(zogBlock);

            await new Promise(resolve => setTimeout(resolve, 10));
            setupPageChangeObservers();
            updatePosition();

            const toggleBlock = async (el) => content.style.display === 'none' ? await expandBlock(el) : collapseBlock(el);
            title.onclick = () => toggleBlock(arrow);
            arrow.onclick = () => toggleBlock(arrow);

            async function expandBlock(arrowElement) {
                Object.assign(zogBlock.style, { transition: 'width 0.3s ease, height 0.3s ease', width: '300px', height: '40px' });
                arrowElement.style.transform = 'translateX(-50%) rotate(180deg)';
                await new Promise(resolve => setTimeout(resolve, 300));
                content.style.display = 'block';
                content.textContent = 'Запрос названия игры...';
                await new Promise(r => requestAnimationFrame(r));
                const englishName = await getEnglishGameName(getAppId()) || getGameName();
                content.textContent = 'Поиск на Zone of Games...';
                await new Promise(r => requestAnimationFrame(r));
                try {
                    const possibleMatches = await findGamesOnZog(englishName);
                    renderPossibleMatches(possibleMatches, englishName);
                    zogBlock.style.height = `${content.scrollHeight + 40}px`;
                    updatePosition();
                } catch (error) {
                    console.error("ZOG Search Error:", error);
                    content.textContent = 'Ошибка поиска на ZOG.';
                }
            }

            function collapseBlock(arrowElement) {
                Object.assign(zogBlock.style, { transition: 'width 0.3s ease, height 0.3s ease', width: '30px', height: '30px' });
                arrowElement.style.transform = 'translateX(-50%) rotate(0deg)';
                content.style.display = 'none';
                content.innerHTML = '';
                updatePosition();
            }

            async function getEnglishGameName(appId) {
                const url = `https://api.steampowered.com/IStoreBrowseService/GetItems/v1?input_json=${JSON.stringify({ ids: [{ appid: parseInt(appId) }], context: { language: "english", country_code: "US" }, data_request: { include_basic_info: true } })}`;
                try {
                    const response = await new Promise((resolve, reject) => GM_xmlhttpRequest({ method: "GET", url, onload: resolve, onerror: reject, ontimeout: reject }));
                    if (response.status === 200) return JSON.parse(response.responseText).response?.store_items?.[0]?.name;
                } catch (e) { console.error('Ошибка при запросе к Steam API:', e); }
                return null;
            }

            async function findGamesOnZog(gameName) {
                const isRussian = /[а-яё]/i.test(gameName);
                const activeMap = isRussian ? russianAlphabetMap : alphabetMap;
                const articles = ['the', 'a', 'an'];
                const words = gameName.toLowerCase().split(' ');
                const searchLetters = new Set();

                if (!isRussian && articles.includes(words[0]) && words.length > 1) {
                    searchLetters.add(words[0][0]);
                    if (activeMap[words[1][0]]) searchLetters.add(words[1][0]);
                } else {
                    let firstChar = gameName.toLowerCase().charAt(0);
                    searchLetters.add(activeMap.hasOwnProperty(firstChar) ? firstChar : '#');
                }

                const allGamesFound = [];
                const uniquePaths = new Set();
                for (const letter of searchLetters) {
                    const isNonAlpha = letter === '#';
                    const pageNum = activeMap[letter];
                    if (pageNum === undefined) continue;
                    const baseUrl = isNonAlpha ? 'https://www.zoneofgames.ru/games/eng/' : (isRussian ? 'https://www.zoneofgames.ru/games/rus/' : 'https://www.zoneofgames.ru/games/eng/');
                    const url = `${baseUrl}${pageNum}/`;
                    try {
                        const response = await new Promise((resolve, reject) => GM_xmlhttpRequest({ method: 'GET', url, onload: resolve, onerror: reject }));
                        const doc = new DOMParser().parseFromString(response.responseText, 'text/html');
                        doc.querySelectorAll('td.gameinfoblock a').forEach(link => {
                            const path = link.getAttribute('href');
                            if (path && !uniquePaths.has(path)) {
                                const rawTitle = link.textContent.trim();
                                const articleMatch = rawTitle.match(/,\s+(The|An|A)$/i);
                                let title = articleMatch ? `${articleMatch[1]} ${rawTitle.replace(articleMatch[0], '').trim()}` : rawTitle;
                                allGamesFound.push({ title, path });
                                uniquePaths.add(path);
                            }
                        });
                    } catch (e) { console.error(`Ошибка при загрузке страницы '${url}':`, e); }
                }
                return allGamesFound;
            }

            async function fetchAndRenderLocalizations(gamePath) {
                const fullUrl = `https://www.zoneofgames.ru${gamePath}`;
                content.innerHTML = 'Загрузка русификаторов...';
                try {
                    const response = await new Promise((resolve, reject) => GM_xmlhttpRequest({ method: 'GET', url: fullUrl, onload: resolve, onerror: reject }));
                    const doc = new DOMParser().parseFromString(response.responseText, 'text/html');
                    const localizations = [];
                    const translationLabel = Array.from(doc.querySelectorAll('b')).find(b => b.textContent.trim() === 'Переводы:');
                    if (translationLabel) {
                        const table = translationLabel.closest('table');
                        if (table) {
                            table.querySelectorAll('tr').forEach(row => {
                                const linkEl = row.querySelector('a');
                                if (linkEl?.getAttribute('href')) {
                                    localizations.push({
                                        name: linkEl.textContent.trim(),
                                        size: row.querySelector('td:last-child')?.textContent.trim() || '',
                                        link: `https://www.zoneofgames.ru${linkEl.getAttribute('href')}`
                                    });
                                }
                            });
                        }
                    }
                    const gameTitle = doc.querySelector('td.blockstyle > b > font')?.textContent.trim() || 'Выбранная игра';
                    renderContent({ title: gameTitle, url: fullUrl, localizations });
                    zogBlock.style.height = `${content.scrollHeight + 40}px`;
                    updatePosition();
                } catch (e) {
                    content.textContent = 'Ошибка загрузки локализаций.';
                    console.error("Ошибка получения страницы игры:", e);
                }
            }

            function renderContent(entry) {
                content.innerHTML = '';
                if (!entry) {
                    content.textContent = 'Игра не найдена в базе ZOG';
                    return;
                }
                const titleLink = Object.assign(document.createElement('a'), { href: entry.url, target: '_blank', textContent: entry.title || 'Без названия' });
                Object.assign(titleLink.style, { color: '#67c1f5', wordBreak: 'break-word', textDecoration: 'none' });
                content.appendChild(titleLink);
                const list = document.createElement('ul');
                Object.assign(list.style, { paddingLeft: '15px', marginTop: '5px', marginBottom: '0' });
                if (entry.localizations?.length > 0) {
                    entry.localizations.forEach(loc => {
                        const li = document.createElement('li');
                        li.style.marginBottom = '8px';
                        const link = Object.assign(document.createElement('a'), { href: loc.link, target: '_blank', textContent: `${loc.name} ${loc.size}` });
                        Object.assign(link.style, { color: '#c6d4df', wordBreak: 'break-word', textDecoration: 'none' });
                        li.appendChild(link);
                        list.appendChild(li);
                    });
                } else {
                    const li = Object.assign(document.createElement('li'), { textContent: 'Русификаторы отсутствуют' });
                    li.style.color = '#999';
                    list.appendChild(li);
                }
                content.appendChild(list);
            }

            function renderPossibleMatches(matches, originalGameName) {
                content.innerHTML = '';
                const title = Object.assign(document.createElement('div'), { textContent: 'Возможные совпадения:' });
                Object.assign(title.style, { color: '#67c1f5', marginBottom: '10px' });
                content.appendChild(title);
                const list = document.createElement('ul');
                Object.assign(list.style, { paddingLeft: '15px', marginTop: '5px', marginBottom: '0' });
                const processedMatches = findPossibleMatches(originalGameName, matches);
                if (processedMatches.length === 0) {
                    renderContent(null);
                    return;
                }
                processedMatches.forEach(match => {
                    const li = document.createElement('li');
                    li.style.marginBottom = '8px';
                    const link = Object.assign(document.createElement('a'), { href: `https://www.zoneofgames.ru${match.item.path}`, target: '_blank', textContent: `${match.item.title} (${match.percentage}%)` });
                    Object.assign(link.style, { color: '#c6d4df', wordBreak: 'break-word', textDecoration: 'none', cursor: 'pointer' });
                    link.onclick = (e) => {
                        e.preventDefault();
                        fetchAndRenderLocalizations(match.item.path);
                    };
                    li.appendChild(link);
                    list.appendChild(li);
                });
                content.appendChild(list);
            }

            function findPossibleMatches(gameName, data) {
                const cleanGameName = gameName.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-zа-яё0-9 _'\-!]/gi, '').toLowerCase();
                return data.map(item => {
                        const cleanItemName = item.title.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-zа-яё0-9 _'\-!]/gi, '').toLowerCase();
                        return { item, percentage: calculateSimilarity(cleanGameName, cleanItemName), startsWith: cleanItemName.startsWith(cleanGameName) };
                    })
                    .filter(item => item.percentage > 45 || item.startsWith)
                    .sort((a, b) => {
                        if (a.startsWith && !b.startsWith) return -1;
                        if (!a.startsWith && b.startsWith) return 1;
                        return b.percentage - a.percentage;
                    })
                    .slice(0, 5);
            }

            function calculateSimilarity(str1, str2) {
                let longer = str1, shorter = str2;
                if (str1.length < str2.length) { longer = str2; shorter = str1; }
                if (longer.length === 0) return 100.0;
                return Math.round(((longer.length - levenshteinDistance(longer, shorter)) / longer.length) * 100);
            }

            function levenshteinDistance(s1, s2) {
                const costs = [];
                for (let i = 0; i <= s1.length; i++) {
                    let lastValue = i;
                    for (let j = 0; j <= s2.length; j++) {
                        if (i === 0) costs[j] = j;
                        else if (j > 0) {
                            let newValue = costs[j - 1];
                            if (s1.charAt(i - 1) !== s2.charAt(j - 1)) newValue = Math.min(newValue, lastValue, costs[j]) + 1;
                            costs[j - 1] = lastValue;
                            lastValue = newValue;
                        }
                    }
                    if (i > 0) costs[s2.length] = lastValue;
                }
                return costs[s2.length];
            }

            function getAppId() { return unsafeWindow.location.pathname.split('/')[2]; }
            function getGameName() { return document.querySelector('.apphub_AppName')?.textContent.trim() || ''; }
        })();
    }

    // Скрипт для страницы игры (Время друзей & Достижения) | https://store.steampowered.com/app/*
    if (window.location.pathname.includes('/app/') && scriptsConfig.friendsPlaytime) {
        (async function() {
            const appIdMatch = unsafeWindow.location.pathname.match(/\/app\/(\d+)/);
            if (!appIdMatch) return;
            const appId = appIdMatch[1];
            const gameName = document.querySelector('#appHubAppName')?.textContent.trim() || 'этой игры';

            async function fetchAndParseAllFriendsData(appId) {
                const url = `https://steamcommunity.com/my/friendsthatplay/${appId}`;
                const results = {
                    recent: {
                        count: 0,
                        blocks: []
                    },
                    ever: {
                        count: 0,
                        blocks: []
                    },
                    own: {
                        count: 0,
                        blocks: []
                    },
                    wishlist: {
                        count: 0,
                        blocks: []
                    }
                };

                try {
                    const response = await new Promise((resolve, reject) => {
                        GM_xmlhttpRequest({
                            method: "GET",
                            url: url,
                            timeout: 15000,
                            onload: resolve,
                            onerror: reject,
                            ontimeout: () => reject(new Error('Timeout'))
                        });
                    });

                    if (response.status !== 200) throw new Error(`HTTP Status ${response.status}`);

                    const parser = new DOMParser();
                    const doc = parser.parseFromString(response.responseText, 'text/html');
                    const allHeaders = doc.querySelectorAll('.mainSectionHeader.friendListSectionHeader');

                    const keywords = {
                        recent: ['последние 2 недели', 'последних 2 недель', 'in the last 2 weeks'],
                        ever: ['когда-либо игравшие', 'когда-либо игравшие в', 'previously'],
                        own: ['имеющие', 'имеющие в', 'in their library'],
                        wishlist: ['которые хотят', 'who want']
                    };

                    allHeaders.forEach(header => {
                        const text = header.textContent.trim().toLowerCase();
                        const container = header.nextElementSibling;

                        if (!container || !container.matches('.profile_friends')) return;

                        const blocks = Array.from(container.querySelectorAll('.friendBlock'));
                        const count = blocks.length;

                        for (const key in keywords) {
                            if (keywords[key].some(k => text.includes(k.toLowerCase()))) {
                                results[key] = { count, blocks };
                                break;
                            }
                        }
                    });
                    return results;
                } catch (error) {
                    return results;
                }
            }

            function buildAvatarGrid(blocks) {
                const grid = document.createElement('div');
                grid.className = 'friend_blocks_grid';
                blocks.slice(0, 6).forEach(block => {
                    const profileLink = block.querySelector('a.friendBlockLinkOverlay')?.href;
                    const miniprofile = block.dataset.miniprofile;
                    const avatarImgSrc = block.querySelector('.playerAvatar img')?.src;
                    const statusClass = block.classList.contains('in-game') ? 'friend_status_in-game' : (block.classList.contains('online') ? 'friend_status_online' : 'friend_status_offline');
                    if (!profileLink || !miniprofile || !avatarImgSrc) return;

                    const link = document.createElement('a');
                    link.style.display = 'inline-block';
                    link.href = profileLink;
                    link.className = `friend_block_holder ${statusClass}`;
                    link.dataset.miniprofile = miniprofile;

                    const avatarDiv = document.createElement('div');
                    avatarDiv.className = 'friend_block_avatar';
                    avatarDiv.style.display = 'inline-block';

                    const img = document.createElement('img');
                    img.src = avatarImgSrc;

                    avatarDiv.appendChild(img);
                    link.appendChild(avatarDiv);
                    grid.appendChild(link);
                });
                return grid;
            }

            async function createFriendsInfoBlock() {
                const targetContainer = document.querySelector('.rightcol.game_meta_data');
                if (!targetContainer) return;

                const friendsBlock = document.createElement('div');
                friendsBlock.className = 'block responsive_apppage_details_right recommendation_reasons';
                friendsBlock.innerHTML = `<p class="reason info" style="text-align:center;">Загрузка данных о друзьях (U.S.E.)...</p>`;
                targetContainer.prepend(friendsBlock);

                const data = await fetchAndParseAllFriendsData(appId);

                const getUniqueBlocks = (blocksArrays) => {
                    const unique = new Map();
                    blocksArrays.flat().forEach(block => {
                        const id = block.dataset.miniprofile;
                        if (id && !unique.has(id)) {
                            unique.set(id, block);
                        }
                    });
                    return Array.from(unique.values());
                };

                const allEverPlayedBlocks = getUniqueBlocks([data.recent.blocks, data.ever.blocks]);
                const allOwnedBlocks = getUniqueBlocks([data.recent.blocks, data.ever.blocks, data.own.blocks]);

                let finalHTML = '';

                if (data.recent.count > 0) {
                    finalHTML += `<p class="reason for">Друзей, игравших недавно: ${data.recent.count}</p>`;
                    finalHTML += buildAvatarGrid(data.recent.blocks).outerHTML + '<hr>';
                }

                if (allEverPlayedBlocks.length > 0) {
                    finalHTML += `<p class="reason for"><a href="https://steamcommunity.com/my/friendsthatplay/${appId}" target="_blank">Друзей, когда-либо игравших в игру: ${allEverPlayedBlocks.length}</a></p>`;
                    finalHTML += buildAvatarGrid(allEverPlayedBlocks).outerHTML + '<hr>';
                }

                if (allOwnedBlocks.length > 0) {
                    finalHTML += `<p class="reason for"><a href="https://steamcommunity.com/my/friendsthatplay/${appId}" target="_blank">Друзей, имеющих игру в библиотеке: ${allOwnedBlocks.length}</a></p>`;
                    finalHTML += buildAvatarGrid(allOwnedBlocks).outerHTML + '<hr>';
                }

                if (data.wishlist.count > 0) {
                    finalHTML += `<p class="reason for"><a href="https://steamcommunity.com/my/friendsthatplay/${appId}" target="_blank">Друзей, которые хотят эту игру: ${data.wishlist.count}</a></p>`;
                    finalHTML += buildAvatarGrid(data.wishlist.blocks).outerHTML + '<hr>';
                }

                friendsBlock.innerHTML = finalHTML.length > 0 ? finalHTML.replace(/<hr>$/, '') : `<p class="reason info">Нет данных о действиях друзей с этой игрой.</p>`;
            }

            const recommendationBlock = document.querySelector('.recommendation_reasons');
            if (!recommendationBlock) {
                await createFriendsInfoBlock();
            }

            const headerCtn = document.querySelector('#gameHeaderImageCtn');
            if (headerCtn) {
                const statsBlock = document.createElement('div');
                statsBlock.style.position = 'absolute';
                statsBlock.style.top = '0px';
                statsBlock.style.left = '406px';
                statsBlock.style.width = '30px';
                statsBlock.style.height = '30px';
                statsBlock.style.background = 'rgba(27, 40, 56, 0.95)';
                statsBlock.style.padding = '15px';
                statsBlock.style.borderRadius = '4px';
                statsBlock.style.border = '1px solid #3c3c3c';
                statsBlock.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.5)';
                statsBlock.style.zIndex = '1';
                statsBlock.style.fontFamily = 'Arial, sans-serif';
                statsBlock.style.overflow = 'hidden';
                statsBlock.style.transition = 'all 0.3s ease';

                const triangle = document.createElement('div');
                triangle.style.position = 'absolute';
                triangle.style.bottom = '5px';
                triangle.style.left = '50%';
                triangle.style.transform = 'translateX(-50%)';
                triangle.style.width = '0';
                triangle.style.height = '0';
                triangle.style.borderLeft = '5px solid transparent';
                triangle.style.borderRight = '5px solid transparent';
                triangle.style.borderTop = '5px solid #67c1f5';
                triangle.style.cursor = 'pointer';
                statsBlock.appendChild(triangle);

                const title = document.createElement('div');
                title.style.display = 'flex';
                title.style.alignItems = 'center';
                title.style.marginBottom = '7px';
                title.style.cursor = 'pointer';

                const combinedImg = document.createElement('div');
                combinedImg.style.width = '29px';
                combinedImg.style.height = '29px';
                combinedImg.style.backgroundImage = 'url(https://gist.githubusercontent.com/0wn3dg0d/9c259eebc40a1e97397ccf3da7ee7bd6/raw/SUEftach.png)';
                combinedImg.style.backgroundSize = 'contain';
                combinedImg.style.backgroundPosition = 'center';

                title.appendChild(combinedImg);
                statsBlock.appendChild(title);

                const content = document.createElement('div');
                content.style.fontSize = '14px';
                content.style.color = '#c6d4df';
                content.style.display = 'none';
                content.style.padding = '0';
                statsBlock.appendChild(content);

                const toggleBlock = async () => {
                    if (content.style.display === 'none') {
                        statsBlock.style.width = '250px';
                        statsBlock.style.height = '60px';
                        content.style.display = 'block';
                        content.textContent = 'Загрузка...';
                        triangle.style.borderTop = 'none';
                        triangle.style.borderBottom = '5px solid #67c1f5';
                        try {
                            const friendsData = await loadFriendsDataForStats();
                            const achievementsData = await loadAchievementsDataForStats();
                            content.innerHTML = '';
                            const friendsTitle = document.createElement('div');
                            friendsTitle.style.fontSize = '12px';
                            friendsTitle.style.fontWeight = 'bold';
                            friendsTitle.style.color = '#67c1f5';
                            friendsTitle.style.marginBottom = '5px';
                            friendsTitle.textContent = 'ВРЕМЯ ДРУЗЕЙ';
                            content.appendChild(friendsTitle);
                            if (friendsData.length > 0) {
                                const maxHours = Math.max(...friendsData.map(f => f.hours));
                                const minHours = Math.min(...friendsData.map(f => f.hours));
                                const avgHours = friendsData.reduce((sum, f) => sum + f.hours, 0) / friendsData.length;
                                const maxPlayers = friendsData.filter(f => f.hours === maxHours);
                                const maxEl = document.createElement('div');
                                maxEl.style.marginBottom = '4px';
                                maxEl.innerHTML = `<span style="color: #67c1f5;">Макс:</span> ${maxHours.toFixed(1)} ч.`;
                                if (maxPlayers.length > 0) {
                                    maxEl.innerHTML += ` (${maxPlayers.map(p => `<a href="${p.profile}" target="_blank" style="color: #c6d4df; text-decoration: none;">${p.name}</a>`).join(', ')})`;
                                }
                                const avgEl = document.createElement('div');
                                avgEl.style.marginBottom = '4px';
                                avgEl.innerHTML = `<span style="color: #67c1f5;">Среднее:</span> ${avgHours.toFixed(1)} ч. (${friendsData.length} чел.)`;
                                const minEl = document.createElement('div');
                                minEl.innerHTML = `<span style="color: #67c1f5;">Минимальное:</span> ${minHours.toFixed(1)} ч.`;
                                content.append(maxEl, avgEl, minEl);
                            } else {
                                const noData = document.createElement('div');
                                noData.textContent = 'Друзья не играли';
                                noData.style.marginBottom = '12px';
                                content.appendChild(noData);
                            }
                            const achTitle = document.createElement('div');
                            achTitle.style.fontSize = '12px';
                            achTitle.style.fontWeight = 'bold';
                            achTitle.style.color = '#67c1f5';
                            achTitle.style.margin = '16px 0 5px 0';
                            achTitle.textContent = 'ГЛОБАЛЬНЫЕ ДОСТИЖЕНИЯ';
                            content.appendChild(achTitle);
                            if (achievementsData.hasAchievements) {
                                const platinumEl = document.createElement('div');
                                platinumEl.style.marginBottom = '4px';
                                platinumEl.innerHTML = `<span style="color: #67c1f5;">Платина:</span> ${achievementsData.platinumPercent}%`;
                                const averageEl = document.createElement('div');
                                averageEl.innerHTML = `<span style="color: #67c1f5;">Средний прогресс:</span> ${achievementsData.averageAdjustedPercent}%`;
                                content.append(platinumEl, averageEl);
                            } else {
                                const noAch = document.createElement('div');
                                noAch.textContent = achievementsData.error === 'Достижения отсутствуют' ? 'Достижений нет' : achievementsData.error;
                                noAch.style.marginBottom = '12px';
                                content.appendChild(noAch);
                            }
                            statsBlock.style.height = `${content.scrollHeight + 38}px`;
                        } catch (error) {
                            content.textContent = 'Ошибка загрузки';
                            statsBlock.style.height = '60px';
                        }
                    } else {
                        content.style.display = 'none';
                        statsBlock.style.height = '30px';
                        statsBlock.style.width = '30px';
                        triangle.style.borderBottom = 'none';
                        triangle.style.borderTop = '5px solid #67c1f5';
                    }
                };

                async function loadFriendsDataForStats() {
                    const friendsUrl = `https://steamcommunity.com/my/friendsthatplay/${appId}`;
                    try {
                        const response = await new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: friendsUrl,
                                onload: resolve,
                                onerror: reject,
                                timeout: 5000
                            });
                        });
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(response.responseText, 'text/html');
                        const playedBlocks = [];
                        const headers = doc.querySelectorAll('.mainSectionHeader.friendListSectionHeader');
                        const playedKeywords = ['последние 2 недели', 'in the last 2 weeks', 'когда-либо игравшие', 'previously'];
                        headers.forEach(header => {
                            const headerText = header.textContent;
                            if (playedKeywords.some(keyword => headerText.includes(keyword))) {
                                const container = header.nextElementSibling;
                                if (container && container.matches('.profile_friends')) {
                                    const blocks = container.querySelectorAll('.friendBlock');
                                    playedBlocks.push(...blocks);
                                }
                            }
                        });
                        return playedBlocks.map(block => {
                            const contentBlock = block.querySelector('.friendBlockContent');
                            if (!contentBlock) return null;
                            const timeText = contentBlock.querySelector('.friendSmallText')?.textContent.trim();
                            let hours = 0;
                            if (timeText) {
                                const timeParts = timeText.split('/');
                                const relevantTimePart = timeParts.length > 1 ? timeParts[1] : timeParts[0];
                                const hoursMatch = relevantTimePart.match(/(\d+[,.]?\d*)\s*(?:ч|hrs)\.?/);
                                if (hoursMatch && hoursMatch[1]) {
                                    hours = parseFloat(hoursMatch[1].replace(',', '.')) || 0;
                                }
                            }
                            return {
                                name: contentBlock.firstChild.textContent.trim(),
                                hours: hours,
                                profile: block.querySelector('a.friendBlockLinkOverlay')?.href
                            };
                        }).filter(f => f && f.hours > 0);
                    } catch (error) {
                        return [];
                    }
                }

                async function loadAchievementsDataForStats() {
                    const achievementsUrl = `https://steamcommunity.com/stats/${appId}/achievements/`;
                    try {
                        const response = await new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: achievementsUrl,
                                onload: resolve,
                                onerror: reject,
                                timeout: 8000
                            });
                        });
                        if (response.status !== 200) return {
                            hasAchievements: false,
                            error: 'Ошибка загрузки страницы'
                        };
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(response.responseText, 'text/html');
                        if (doc.querySelector('.no_achievements_message')) return {
                            hasAchievements: false,
                            error: 'Достижения отсутствуют'
                        };
                        const percentElements = doc.querySelectorAll('.achievePercent');
                        if (percentElements.length === 0) return {
                            hasAchievements: false,
                            error: 'Достижения отсутствуют'
                        };
                        const percents = Array.from(percentElements).map(el => parseFloat(el.textContent.trim().replace('%', '')) || 0).filter(p => p > 0);
                        if (percents.length === 0) return {
                            hasAchievements: false,
                            error: 'Нет данных'
                        };
                        const maxPercent = Math.max(...percents);
                        const minPercent = Math.min(...percents);
                        const adjustment = 100 - maxPercent;
                        const adjustedPercents = percents.map(p => p + adjustment);
                        const averageAdjusted = adjustedPercents.reduce((sum, p) => sum + p, 0) / adjustedPercents.length;
                        return {
                            hasAchievements: true,
                            platinumPercent: (minPercent + adjustment).toFixed(1),
                            averageAdjustedPercent: averageAdjusted.toFixed(1)
                        };
                    } catch (error) {
                        return {
                            hasAchievements: false,
                            error: 'Ошибка соединения'
                        };
                    }
                }
                title.addEventListener('click', toggleBlock);
                triangle.addEventListener('click', toggleBlock);
                headerCtn.appendChild(statsBlock);
            }
        })();
    }

    // Скрипт для страницы игры (Ранний доступ) | https://store.steampowered.com/app/*
    if (window.location.pathname.includes('/app/') && scriptsConfig.earlyaccdata) {
        (function() {
            'use strict';

            const EAORDATE_STORAGE_KEY = 'USE_EarlyAccess_ordateData';
            const EAORDATE_URL = 'https://gist.githubusercontent.com/0wn3dg0d/58a8e35f3d34014ea749a22d02f7e203/raw/eaordate.json';
            const CACHE_DURATION = 180 * 24 * 60 * 60 * 1000; // 6 месяцев

            const getYearForm = (n) => {
                n = Math.abs(n) % 100;
                const n1 = n % 10;
                if (n > 10 && n < 20) return 'лет';
                if (n1 === 1) return 'год';
                if (n1 >= 2 && n1 <= 4) return 'года';
                return 'лет';
            };

            const getMonthForm = (n) => {
                n = Math.abs(n) % 100;
                const n1 = n % 10;
                if (n > 10 && n < 20) return 'месяцев';
                if (n1 === 1) return 'месяц';
                if (n1 >= 2 && n1 <= 4) return 'месяца';
                return 'месяцев';
            };

            const parseSteamDate = (dateStr) => {
                const numericParts = dateStr.split('.');
                if (numericParts.length === 3) {
                    const day = parseInt(numericParts[0], 10);
                    const month = parseInt(numericParts[1], 10) - 1;
                    const year = parseInt(numericParts[2], 10);
                    return new Date(year, month, day);
                }

                const monthsMap = {
                    'янв': 0,
                    'фев': 1,
                    'мар': 2,
                    'апр': 3,
                    'мая': 4,
                    'июн': 5,
                    'июл': 6,
                    'авг': 7,
                    'сен': 8,
                    'окт': 9,
                    'ноя': 10,
                    'дек': 11
                };

                const cleanedStr = dateStr.replace(/\./g, '');
                const [day, monthNameRaw, year] = cleanedStr.split(' ');
                const monthName = monthNameRaw.substring(0, 3);
                return new Date(parseInt(year), monthsMap[monthName], parseInt(day));
            };

            const fetchOrdateData = async () => {
                const cachedData = GM_getValue(EAORDATE_STORAGE_KEY, null);
                if (cachedData && Date.now() - cachedData.timestamp < CACHE_DURATION) {
                    return cachedData.data;
                }

                return new Promise(resolve => {
                    GM_xmlhttpRequest({
                        method: 'GET',
                        url: EAORDATE_URL,
                        onload: function(response) {
                            try {
                                const data = JSON.parse(response.responseText);
                                GM_setValue(EAORDATE_STORAGE_KEY, {
                                    timestamp: Date.now(),
                                    data: data
                                });
                                resolve(data);
                            } catch (e) {
                                console.error('Error parsing EAOrdate data:', e);
                                resolve(cachedData?.data || []);
                            }
                        },
                        onerror: () => resolve(cachedData?.data || [])
                    });
                });
            };

            const getAppId = () => {
                const match = unsafeWindow.location.pathname.match(/\/app\/(\d+)/);
                return match ? parseInt(match[1]) : null;
            };

            const createInfoBox = (duration, isReleased) => {
                const infoBox = document.createElement('div');
                Object.assign(infoBox.style, {
                    position: 'absolute',
                    top: '-46px',
                    left: '334px',
                    background: isReleased ? 'rgba(103, 193, 245, 0.15)' : 'rgba(245, 166, 35, 0.15)',
                    padding: '6.5px',
                    borderRadius: '3px',
                    border: `1px solid ${isReleased ? '#2A568E' : '#f5a623'}`,
                    fontSize: '12px',
                    color: '#c6d4df',
                    boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',
                    fontFamily: '"Motiva Sans", Arial, sans-serif',
                    zIndex: 3,
                    display: 'inline-block',
                    whiteSpace: 'nowrap'
                });

                let message;
                if (isReleased) {
                    message = duration ?
                        `Вышла спустя ${duration} раннего доступа` :
                        'Игра вышла из раннего доступа (срок неизвестен)';
                } else {
                    message = `В раннем доступе уже ${duration}`;
                }

                infoBox.innerHTML = `
                <div style="display: flex; align-items: center; gap: 8px;">
                    <span style="color: ${isReleased ? '#67c1f5' : '#f5a623'}; font-weight: bold;">
                        ${isReleased ? '➡️' : '⏳'}
                    </span>
                    <span>${message}</span>
                </div>
            `;
                return infoBox;
            };

            const calculateDuration = (startDate, endDate) => {
                let diffMonths = (endDate.getFullYear() - startDate.getFullYear()) * 12 +
                    (endDate.getMonth() - startDate.getMonth());

                if (endDate.getDate() < startDate.getDate()) diffMonths--;

                const years = Math.floor(diffMonths / 12);
                const months = diffMonths % 12;

                const parts = [];
                if (years > 0) parts.push(`${years} ${getYearForm(years)}`);
                if (months > 0) parts.push(`${months} ${getMonthForm(months)}`);

                return parts.length > 0 ? parts.join(' и ') : 'менее месяца';
            };

            const main = async () => {
                const detailsBlock = document.querySelector('#genresAndManufacturer');
                const isStillEarlyAccess = !!document.querySelector('#earlyAccessHeader');
                if (!detailsBlock) return;

                const parseDates = () => {
                    const fullText = detailsBlock.textContent;
                    const dates = {
                        earlyDate: null,
                        releaseDate: null
                    };

                    const earlyMatch = fullText.match(/Дата выпуска в раннем доступе:\s*(\d+\s\S+\s\d{4})/);
                    const releaseMatch = fullText.match(/Дата выхода:\s*(\d+\s\S+\s\d{4})/);

                    if (isStillEarlyAccess && !earlyMatch && releaseMatch) {
                        dates.earlyDate = releaseMatch[1];
                    } else {
                        if (earlyMatch) dates.earlyDate = earlyMatch[1];
                        if (releaseMatch) dates.releaseDate = releaseMatch[1];
                    }
                    return dates;
                };

                const {
                    earlyDate: earlyDateStr,
                    releaseDate: releaseDateStr
                } = parseDates();
                const appid = getAppId();

                if (!earlyDateStr && appid) {
                    const ordateData = await fetchOrdateData();
                    const gameData = ordateData.find(item => item.appid === appid);

                    if (gameData) {
                        try {
                            const ordate = parseSteamDate(gameData.ordate);
                            const releaseDate = releaseDateStr ? parseSteamDate(releaseDateStr) : new Date();

                            if (ordate >= releaseDate) throw new Error('Invalid date order');

                            const duration = calculateDuration(ordate, releaseDate);
                            const infoBox = createInfoBox(duration, true);
                            document.querySelector('.game_header_image_ctn')?.appendChild(infoBox);
                        } catch (e) {
                            const infoBox = createInfoBox(null, true);
                            document.querySelector('.game_header_image_ctn')?.appendChild(infoBox);
                        }
                    }
                    return;
                }

                const earlyDate = earlyDateStr ? parseSteamDate(earlyDateStr) :
                    isStillEarlyAccess ? parseSteamDate(releaseDateStr) : null;
                const releaseDate = releaseDateStr ? parseSteamDate(releaseDateStr) : null;

                if (!earlyDate) return;

                const endDate = isStillEarlyAccess ? new Date() : releaseDate;
                if (!endDate) return;

                try {
                    const duration = calculateDuration(earlyDate, endDate);
                    const infoBox = createInfoBox(duration, !isStillEarlyAccess);
                    document.querySelector('.game_header_image_ctn')?.appendChild(infoBox);
                } catch (e) {
                    console.error('Early access date calculation error:', e);
                }
            };

            main();
        })();
    }

    // Скрипт для страницы игры (Анализатор цен; цена РФ vs рекомендованная; рейтинг цен) | https://store.steampowered.com/app/*
    if (scriptsConfig.RuRegionalPriceAnalyzer && unsafeWindow.location.pathname.includes('/app/')) {
        (function regionalPriceAnalyzer() {
            'use strict';

            let rpa_currentDisplayMode = 'RUB';
            let rpa_hideUsdSwitchWarning = localStorage.getItem('rpa_hide_usd_switch_warning') === 'true';

            const userProvidedRegionsRU = {
                'US': {
                    name: 'Доллар США',
                    code: 1,
                    iso: 'usd'
                },
                'EU': {
                    name: 'Евро',
                    code: 3,
                    iso: 'eur'
                },
                'AR': {
                    name: 'Лат. Ам. - Доллар США',
                    code: 1,
                    iso: 'usd'
                },
                'AU': {
                    name: 'Австралийский доллар',
                    code: 21,
                    iso: 'aud'
                },
                'BR': {
                    name: 'Бразильский реал',
                    code: 7,
                    iso: 'brl'
                },
                'GB': {
                    name: 'Британский фунт',
                    code: 2,
                    iso: 'gbp'
                },
                'CA': {
                    name: 'Канадский доллар',
                    code: 20,
                    iso: 'cad'
                },
                'CL': {
                    name: 'Чилийское песо',
                    code: 25,
                    iso: 'clp'
                },
                'CN': {
                    name: 'Китайский юань',
                    code: 23,
                    iso: 'cny'
                },
                'AZ': {
                    name: 'СНГ - Доллар США',
                    code: 1,
                    iso: 'usd'
                },
                'CO': {
                    name: 'Колумбийское песо',
                    code: 27,
                    iso: 'cop'
                },
                'CR': {
                    name: 'Коста-риканский колон',
                    code: 40,
                    iso: 'crc'
                },
                'HK': {
                    name: 'Гонконгский доллар',
                    code: 29,
                    iso: 'hkd'
                },
                'IN': {
                    name: 'Индийская рупия',
                    code: 24,
                    iso: 'inr'
                },
                'ID': {
                    name: 'Индонезийская рупия',
                    code: 10,
                    iso: 'idr'
                },
                'IL': {
                    name: 'Израильский новый шекель',
                    code: 35,
                    iso: 'ils'
                },
                'JP': {
                    name: 'Японская иена',
                    code: 8,
                    iso: 'jpy'
                },
                'KZ': {
                    name: 'Казахстанский тенге',
                    code: 37,
                    iso: 'kzt'
                },
                'KW': {
                    name: 'Кувейтский динар',
                    code: 38,
                    iso: 'kwd'
                },
                'MY': {
                    name: 'Малазийский ринггит',
                    code: 11,
                    iso: 'myr'
                },
                'MX': {
                    name: 'Мексиканское песо',
                    code: 19,
                    iso: 'mxn'
                },
                'NZ': {
                    name: 'Новозеландский доллар',
                    code: 22,
                    iso: 'nzd'
                },
                'NO': {
                    name: 'Норвежская крона',
                    code: 9,
                    iso: 'nok'
                },
                'PE': {
                    name: 'Перуанский соль',
                    code: 26,
                    iso: 'pen'
                },
                'PH': {
                    name: 'Филиппинское песо',
                    code: 12,
                    iso: 'php'
                },
                'PL': {
                    name: 'Польский злотый',
                    code: 6,
                    iso: 'pln'
                },
                'QA': {
                    name: 'Катарский риал',
                    code: 39,
                    iso: 'qar'
                },
                'RU': {
                    name: 'Российский рубль',
                    code: 5,
                    iso: 'rub'
                },
                'SA': {
                    name: 'Саудовский риал',
                    code: 31,
                    iso: 'sar'
                },
                'SG': {
                    name: 'Сингапурский доллар',
                    code: 13,
                    iso: 'sgd'
                },
                'ZA': {
                    name: 'Южноафриканский рэнд',
                    code: 28,
                    iso: 'zar'
                },
                'PK': {
                    name: 'Юж. Азия - Доллар США',
                    code: 1,
                    iso: 'usd'
                },
                'KR': {
                    name: 'Южнокорейская вона',
                    code: 16,
                    iso: 'krw'
                },
                'CH': {
                    name: 'Швейцарский франк',
                    code: 4,
                    iso: 'chf'
                },
                'TW': {
                    name: 'Тайваньский доллар',
                    code: 30,
                    iso: 'twd'
                },
                'TH': {
                    name: 'Тайский бат',
                    code: 14,
                    iso: 'thb'
                },
                'TR': {
                    name: 'MENA - Доллар США',
                    code: 1,
                    iso: 'usd'
                },
                'AE': {
                    name: 'Дирхам ОАЭ',
                    code: 32,
                    iso: 'aed'
                },
                'UA': {
                    name: 'Украинская гривна',
                    code: 18,
                    iso: 'uah'
                },
                'UY': {
                    name: 'Уругвайское песо',
                    code: 41,
                    iso: 'uyu'
                },
                'VN': {
                    name: 'Вьетнамский донг',
                    code: 15,
                    iso: 'vnd'
                }
            };
            const userProvidedRegionsEN = {
                'US': {
                    name: 'United States Dollar',
                    code: 1,
                    iso: 'usd'
                },
                'EU': {
                    name: 'Euro',
                    code: 3,
                    iso: 'eur'
                },
                'AR': {
                    name: 'Latin America - USD',
                    code: 1,
                    iso: 'usd'
                },
                'AU': {
                    name: 'Australian Dollar',
                    code: 21,
                    iso: 'aud'
                },
                'BR': {
                    name: 'Brazilian Real',
                    code: 7,
                    iso: 'brl'
                },
                'GB': {
                    name: 'British Pound',
                    code: 2,
                    iso: 'gbp'
                },
                'CA': {
                    name: 'Canadian Dollar',
                    code: 20,
                    iso: 'cad'
                },
                'CL': {
                    name: 'Chilean Peso',
                    code: 25,
                    iso: 'clp'
                },
                'CN': {
                    name: 'Chinese Yuan Renminbi',
                    code: 23,
                    iso: 'cny'
                },
                'AZ': {
                    name: 'CIS - USD',
                    code: 1,
                    iso: 'usd'
                },
                'CO': {
                    name: 'Colombian Peso',
                    code: 27,
                    iso: 'cop'
                },
                'CR': {
                    name: 'Costa Rican Colon',
                    code: 40,
                    iso: 'crc'
                },
                'HK': {
                    name: 'Hong Kong Dollar',
                    code: 29,
                    iso: 'hkd'
                },
                'IN': {
                    name: 'Indian Rupee',
                    code: 24,
                    iso: 'inr'
                },
                'ID': {
                    name: 'Indonesian Rupiah',
                    code: 10,
                    iso: 'idr'
                },
                'IL': {
                    name: 'Israeli New Shekel',
                    code: 35,
                    iso: 'ils'
                },
                'JP': {
                    name: 'Japanese Yen',
                    code: 8,
                    iso: 'jpy'
                },
                'KZ': {
                    name: 'Kazakhstani Tenge',
                    code: 37,
                    iso: 'kzt'
                },
                'KW': {
                    name: 'Kuwaiti Dinar',
                    code: 38,
                    iso: 'kwd'
                },
                'MY': {
                    name: 'Malaysian Ringgit',
                    code: 11,
                    iso: 'myr'
                },
                'MX': {
                    name: 'Mexican Peso',
                    code: 19,
                    iso: 'mxn'
                },
                'NZ': {
                    name: 'New Zealand Dollar',
                    code: 22,
                    iso: 'nzd'
                },
                'NO': {
                    name: 'Norwegian Krone',
                    code: 9,
                    iso: 'nok'
                },
                'PE': {
                    name: 'Peruvian Sol',
                    code: 26,
                    iso: 'pen'
                },
                'PH': {
                    name: 'Philippine Peso',
                    code: 12,
                    iso: 'php'
                },
                'PL': {
                    name: 'Polish Zloty',
                    code: 6,
                    iso: 'pln'
                },
                'QA': {
                    name: 'Qatari Riyal',
                    code: 39,
                    iso: 'qar'
                },
                'RU': {
                    name: 'Russian Ruble',
                    code: 5,
                    iso: 'rub'
                },
                'SA': {
                    name: 'Saudi Riyal',
                    code: 31,
                    iso: 'sar'
                },
                'SG': {
                    name: 'Singapore Dollar',
                    code: 13,
                    iso: 'sgd'
                },
                'ZA': {
                    name: 'South African Rand',
                    code: 28,
                    iso: 'zar'
                },
                'PK': {
                    name: 'South Asia - USD',
                    code: 1,
                    iso: 'usd'
                },
                'KR': {
                    name: 'South Korean Won',
                    code: 16,
                    iso: 'krw'
                },
                'CH': {
                    name: 'Swiss Franc',
                    code: 4,
                    iso: 'chf'
                },
                'TW': {
                    name: 'New Taiwan Dollar',
                    code: 30,
                    iso: 'twd'
                },
                'TH': {
                    name: 'Thai Baht',
                    code: 14,
                    iso: 'thb'
                },
                'TR': {
                    name: 'MENA - USD',
                    code: 1,
                    iso: 'usd'
                },
                'AE': {
                    name: 'UAE Dirham',
                    code: 32,
                    iso: 'aed'
                },
                'UA': {
                    name: 'Ukrainian Hryvnia',
                    code: 18,
                    iso: 'uah'
                },
                'UY': {
                    name: 'Uruguayan Peso',
                    code: 41,
                    iso: 'uyu'
                },
                'VN': {
                    name: 'Vietnamese Dong',
                    code: 15,
                    iso: 'vnd'
                }
            };

            const RPA_CONFIG = {
                regions: [],
                currencyApiUrl: 'https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/',
                steamApiUrl: 'https://api.steampowered.com/IStoreBrowseService/GetItems/v1/',
                priorButtonText: '',
                modalTitle: '',
                fetchButtonText: '',
                delayBetweenBatches: 300,
                batchSize: 10,
            };

            function rpa_updateTextsAndRegionNames() {
                const isUSDMode = rpa_currentDisplayMode === 'USD';
                RPA_CONFIG.priorButtonText = isUSDMode ? 'Price Analyzer' : 'Анализатор цен';
                RPA_CONFIG.modalTitle = isUSDMode ? 'Regional Price Analyzer' : 'Анализатор цен';
                RPA_CONFIG.fetchButtonText = isUSDMode ? 'Fetch Data' : 'Сбор данных';

                const sourceRegions = isUSDMode ? userProvidedRegionsEN : userProvidedRegionsRU;
                RPA_CONFIG.regions = Object.entries(sourceRegions).map(([key, value]) => ({
                    cc: key === 'EU' ? 'DE' : key,
                    name: value.name,
                    currencyApiCode: value.iso.toLowerCase(),
                    steamCurrencyId: value.code
                }));

                if (rpa_priorButton) rpa_priorButton.textContent = RPA_CONFIG.priorButtonText;
                const modalTitleEl = rpa_modal ? rpa_modal.querySelector('#rpaHeaderBar h3') : null;
                if (modalTitleEl) modalTitleEl.textContent = RPA_CONFIG.modalTitle;
                const fetchBtnEl = rpa_modal ? rpa_modal.querySelector('#rpaFetchDataButton') : null;
                if (fetchBtnEl) fetchBtnEl.textContent = RPA_CONFIG.fetchButtonText;
                rpa_updateModeToggleButtonText();
            }

            let rpa_exchangeRates = {};
            let rpa_modal = null;
            let rpa_priorButton = null;
            let rpa_currentAppId = null;
            let rpa_currentGameName = '';
            let rpa_progressBarFill = null;
            let rpa_fetchController = null;
            let rpa_modeToggleButton = null;

            function calculateRecommendedRubPrice(pUSD) {
                if (typeof pUSD !== 'number' || isNaN(pUSD)) return null;
                if (pUSD < 0.99) return 42;
                if (pUSD >= 0.99 && pUSD < 1.99) return 42;
                if (pUSD >= 1.99 && pUSD < 2.99) return 82;
                if (pUSD >= 2.99 && pUSD < 3.99) return 125;
                if (pUSD >= 3.99 && pUSD < 4.99) return 165;
                if (pUSD >= 4.99 && pUSD < 5.99) return 200;
                if (pUSD >= 5.99 && pUSD < 6.99) return 240;
                if (pUSD >= 6.99 && pUSD < 7.99) return 280;
                if (pUSD >= 7.99 && pUSD < 8.99) return 320;
                if (pUSD >= 8.99 && pUSD < 9.99) return 350;
                if (pUSD >= 9.99 && pUSD < 10.99) return 385;
                if (pUSD >= 10.99 && pUSD < 11.99) return 420;
                if (pUSD >= 11.99 && pUSD < 12.99) return 460;
                if (pUSD >= 12.99 && pUSD < 13.99) return 490;
                if (pUSD >= 13.99 && pUSD < 14.99) return 520;
                if (pUSD >= 14.99 && pUSD < 15.99) return 550;
                if (pUSD >= 15.99 && pUSD < 16.99) return 590;
                if (pUSD >= 16.99 && pUSD < 17.99) return 620;
                if (pUSD >= 17.99 && pUSD < 18.99) return 650;
                if (pUSD >= 18.99 && pUSD < 19.99) return 680;
                if (pUSD >= 19.99 && pUSD < 22.99) return 710;
                if (pUSD >= 22.99 && pUSD < 27.99) return 880;
                if (pUSD >= 27.99 && pUSD < 32.99) return 1100;
                if (pUSD >= 32.99 && pUSD < 37.99) return 1200;
                if (pUSD >= 37.99 && pUSD < 43.99) return 1300;
                if (pUSD >= 43.99 && pUSD < 47.99) return 1500;
                if (pUSD >= 47.99 && pUSD < 52.99) return 1600;
                if (pUSD >= 52.99 && pUSD < 57.99) return 1750;
                if (pUSD >= 57.99 && pUSD < 63.99) return 1900;
                if (pUSD >= 63.99 && pUSD < 67.99) return 2100;
                if (pUSD >= 67.99 && pUSD < 74.99) return 2250;
                if (pUSD >= 74.99 && pUSD < 79.99) return 2400;
                if (pUSD >= 79.99 && pUSD < 84.99) return 2600;
                if (pUSD >= 84.99 && pUSD < 89.99) return 2700;
                if (pUSD >= 89.99 && pUSD < 99.99) return 2900;
                if (pUSD >= 99.99 && pUSD < 109.99) return 3200;
                if (pUSD >= 109.99 && pUSD < 119.99) return 3550;
                if (pUSD >= 119.99 && pUSD < 129.99) return 3900;
                if (pUSD >= 129.99 && pUSD < 139.99) return 4200;
                if (pUSD >= 139.99 && pUSD < 149.99) return 4500;
                if (pUSD >= 149.99 && pUSD < 199.99) return 4800;
                if (pUSD >= 199.99) return 6500;
                return null;
            }

            function rpa_getAppIdFromUrl() {
                const match = unsafeWindow.location.pathname.match(/\/app\/(\d+)/);
                return match ? match[1] : null;
            }

            async function rpa_fetchExchangeRates(baseCurrency = 'usd', signal) {
                baseCurrency = baseCurrency.toLowerCase();
                if (rpa_exchangeRates[baseCurrency] && Object.keys(rpa_exchangeRates[baseCurrency]).length > 0) {
                    return rpa_exchangeRates[baseCurrency];
                }
                if (baseCurrency === 'rub' && !rpa_exchangeRates['rub']) rpa_exchangeRates['rub'] = {};
                if (baseCurrency === 'rub' && rpa_exchangeRates['rub']['rub'] === 1) return rpa_exchangeRates['rub'];
                if (baseCurrency === 'usd' && !rpa_exchangeRates['usd']) rpa_exchangeRates['usd'] = {};
                if (baseCurrency === 'usd' && rpa_exchangeRates['usd']['usd'] === 1 && Object.keys(rpa_exchangeRates['usd']).length > 1) return rpa_exchangeRates['usd'];

                try {
                    const response = await new Promise((resolve, reject) => {
                        const xhr = GM_xmlhttpRequest({
                            method: "GET",
                            url: `${RPA_CONFIG.currencyApiUrl}${baseCurrency}.json`,
                            timeout: 8000,
                            onload: function(resp) {
                                if (resp.status >= 200 && resp.status < 400) {
                                    try {
                                        resolve(JSON.parse(resp.responseText));
                                    } catch (e) {
                                        reject(new Error(`JSON Parse error for ${baseCurrency}: ${e.message}`));
                                    }
                                } else {
                                    reject(new Error(`Currency API error: ${resp.status} for ${baseCurrency}`));
                                }
                            },
                            onerror: (err) => reject(new Error(`Network error for ${baseCurrency}: ${err}`)),
                            ontimeout: () => reject(new Error(`Currency API timeout for ${baseCurrency}`))
                        });
                        if (signal) {
                            signal.addEventListener('abort', () => {
                                xhr.abort();
                                reject(new DOMException('Request aborted', 'AbortError'));
                            });
                        }
                    });
                    rpa_exchangeRates[baseCurrency] = response[baseCurrency] || {};
                    rpa_exchangeRates[baseCurrency][baseCurrency] = 1;
                    return rpa_exchangeRates[baseCurrency];
                } catch (error) {
                    if (error.name === 'AbortError') {
                        console.log(`[RPA] Exchange rate request for ${baseCurrency} aborted.`);
                    } else {
                        console.error(`[RPA] Error fetching exchange rates for ${baseCurrency}:`, error);
                    }
                    throw error;
                }
            }

            function rpa_getPriceInCents(purchaseOption) {
                if (purchaseOption && purchaseOption.discount_pct > 0 && purchaseOption.original_price_in_cents) {
                    return parseInt(purchaseOption.original_price_in_cents, 10);
                }
                if (purchaseOption && purchaseOption.final_price_in_cents) {
                    return parseInt(purchaseOption.final_price_in_cents, 10);
                }
                return null;
            }

            function rpa_getDisplayFormattedPrice(purchaseOption) {
                if (purchaseOption) {
                    if (purchaseOption.discount_pct > 0 && purchaseOption.formatted_original_price) {
                        return purchaseOption.formatted_original_price;
                    }
                    if (purchaseOption.formatted_final_price) {
                        return purchaseOption.formatted_final_price;
                    }
                }
                return 'N/A';
            }

            async function rpa_fetchItemData(appid, countryCode, signal) {
                const lang = rpa_currentDisplayMode === 'USD' ? 'english' : 'russian';
                const url = `${RPA_CONFIG.steamApiUrl}?input_json=${encodeURIComponent(JSON.stringify({
                    "ids": [{ "appid": parseInt(appid) }],
                    "context": { "country_code": countryCode, "steam_realm": 1, "language": lang },
                    "data_request": { "include_all_purchase_options": true, "include_basic_info": true }
                }))}`;
                return new Promise((resolve, reject) => {
                    const xhr = GM_xmlhttpRequest({
                        method: "GET",
                        url: url,
                        timeout: 15000,
                        onload: function(response) {
                            try {
                                if (response.status >= 200 && response.status < 400) {
                                    const data = JSON.parse(response.responseText);
                                    if (data.response && data.response.store_items && data.response.store_items.length > 0) {
                                        resolve(data.response.store_items[0]);
                                    } else {
                                        resolve(null);
                                    }
                                } else {
                                    reject(new Error(`Steam API error: ${response.status} for ${countryCode}`));
                                }
                            } catch (e) {
                                reject(new Error(`Error parsing Steam API response for ${countryCode}: ${e.message}`));
                            }
                        },
                        onerror: (err) => reject(new Error(`Network error for ${countryCode}: ${err.toString()}`)),
                        ontimeout: () => reject(new Error(`Timeout for ${countryCode}`))
                    });
                    if (signal) {
                        signal.addEventListener('abort', () => {
                            xhr.abort();
                            reject(new DOMException('Request aborted', 'AbortError'));
                        });
                    }
                });
            }

            function rpa_addPriorButton() {
                if (document.getElementById('rpaPriorButton')) return;
                let targetWrapper = document.querySelector('.game_area_purchase_game_wrapper');
                if (!targetWrapper) {
                    return;
                }
                const allPurchaseWrappers = document.querySelectorAll('.game_area_purchase_game_wrapper');
                for (let wrapper of allPurchaseWrappers) {
                    if (wrapper.querySelector('.game_purchase_action .price, .game_purchase_action .discount_block')) {
                        targetWrapper = wrapper;
                        break;
                    }
                }
                rpa_priorButton = document.createElement('button');
                rpa_priorButton.id = 'rpaPriorButton';
                rpa_priorButton.textContent = RPA_CONFIG.priorButtonText;
                rpa_priorButton.className = 'btnv6_blue_hoverfade btn_medium';
                Object.assign(rpa_priorButton.style, {
                    marginRight: '10px',
                    marginBottom: '10px',
                    height: '32px',
                    padding: '0 15px',
                    lineHeight: '32px'
                });
                rpa_priorButton.addEventListener('click', rpa_openModal);
                const buttonContainer = document.createElement('div');
                buttonContainer.appendChild(rpa_priorButton);
                if (targetWrapper.parentNode) {
                    targetWrapper.parentNode.insertBefore(buttonContainer, targetWrapper);
                }
            }

            function rpa_updateModeToggleButtonText() {
                if (!rpa_modeToggleButton) return;
                if (rpa_currentDisplayMode === 'USD') {
                    rpa_modeToggleButton.textContent = 'RUB';
                    rpa_modeToggleButton.title = 'Вернуться в режим рублей?';
                } else {
                    rpa_modeToggleButton.textContent = 'USD';
                    rpa_modeToggleButton.title = 'Переключиться на режим долларов?';
                }
            }

            function rpa_handleModeToggle() {
                if (rpa_currentDisplayMode === 'RUB') {
                    if (rpa_hideUsdSwitchWarning) {
                        rpa_switchToUsdMode();
                    } else {
                        rpa_showUsdSwitchConfirmation();
                    }
                } else {
                    rpa_switchToRubMode();
                }
            }

            function rpa_switchToUsdMode() {
                rpa_currentDisplayMode = 'USD';
                rpa_updateTextsAndRegionNames();
                if (rpa_modal && rpa_modal.style.display === 'flex') {
                    document.getElementById('rpaSummaryDiv').innerHTML = `<p>Click "Fetch Data" to begin.</p>`;
                    document.getElementById('rpaResultsDiv').innerHTML = '';
                    rpa_updateModalStatus('Click "Fetch Data" to start analysis.');
                }
                rpa_updateModeToggleButtonText();
            }

            function rpa_switchToRubMode() {
                rpa_currentDisplayMode = 'RUB';
                rpa_updateTextsAndRegionNames();
                if (rpa_modal && rpa_modal.style.display === 'flex') {
                    document.getElementById('rpaSummaryDiv').innerHTML = '<p>Нажмите "Сбор данных" для начала.</p>';
                    document.getElementById('rpaResultsDiv').innerHTML = '';
                    rpa_updateModalStatus('Нажмите "Сбор данных" для начала анализа.');
                }
                rpa_updateModeToggleButtonText();
            }

            function rpa_showUsdSwitchConfirmation() {
                let existingDialog = document.getElementById('rpaUsdConfirmDialog');
                if (existingDialog) existingDialog.remove();

                const dialog = document.createElement('div');
                dialog.id = 'rpaUsdConfirmDialog';
                Object.assign(dialog.style, {
                    position: 'fixed',
                    top: '50%',
                    left: '50%',
                    transform: 'translate(-50%, -50%)',
                    backgroundColor: '#1b2838',
                    color: '#c6d4df',
                    padding: '25px',
                    borderRadius: '5px',
                    boxShadow: '0 0 20px rgba(0,0,0,0.7)',
                    zIndex: '100005',
                    textAlign: 'left',
                    border: '1px solid #000',
                    maxWidth: '450px'
                });

                const message = document.createElement('p');
                message.innerHTML = 'Вы переходите в режим долларов. Данный режим предназначен для получения цен в долларах США и может быть полезен для оценки ценовой политики при общении с разработчиками/издателями.<br><br>Продолжить?';
                message.style.marginBottom = '20px';
                message.style.lineHeight = '1.6';

                const checkboxContainer = document.createElement('div');
                checkboxContainer.style.marginBottom = '20px';
                const checkbox = document.createElement('input');
                checkbox.type = 'checkbox';
                checkbox.id = 'rpaDontShowAgainUsd';
                checkbox.style.marginRight = '8px';
                const label = document.createElement('label');
                label.htmlFor = 'rpaDontShowAgainUsd';
                label.textContent = 'Больше не показывать это сообщение';
                checkboxContainer.appendChild(checkbox);
                checkboxContainer.appendChild(label);

                const buttonsContainer = document.createElement('div');
                buttonsContainer.style.textAlign = 'right';

                const yesButton = document.createElement('button');
                yesButton.textContent = 'Да';
                Object.assign(yesButton.style, {
                    padding: '8px 15px',
                    marginRight: '10px',
                    backgroundColor: '#76b72a',
                    color: 'white',
                    border: 'none',
                    borderRadius: '3px',
                    cursor: 'pointer'
                });
                yesButton.onclick = () => {
                    if (checkbox.checked) {
                        rpa_hideUsdSwitchWarning = true;
                        localStorage.setItem('rpa_hide_usd_switch_warning', 'true');
                    }
                    rpa_switchToUsdMode();
                    dialog.remove();
                };

                const cancelButton = document.createElement('button');
                cancelButton.textContent = 'Отмена';
                Object.assign(cancelButton.style, {
                    padding: '8px 15px',
                    backgroundColor: '#55606e',
                    color: 'white',
                    border: 'none',
                    borderRadius: '3px',
                    cursor: 'pointer'
                });
                cancelButton.onclick = () => {
                    dialog.remove();
                };

                buttonsContainer.appendChild(yesButton);
                buttonsContainer.appendChild(cancelButton);
                dialog.appendChild(message);
                dialog.appendChild(checkboxContainer);
                dialog.appendChild(buttonsContainer);
                document.body.appendChild(dialog);
            }

            function rpa_createModal() {
                if (document.getElementById('rpaRegionalPriceModal')) return;
                rpa_modal = document.createElement('div');
                rpa_modal.id = 'rpaRegionalPriceModal';
                Object.assign(rpa_modal.style, {
                    position: 'fixed',
                    top: '0',
                    left: '0',
                    width: '100vw',
                    height: '100vh',
                    backgroundColor: 'rgba(21, 33, 45, 0.985)',
                    color: '#c6d4df',
                    zIndex: '100001',
                    display: 'flex',
                    flexDirection: 'column',
                    fontFamily: '"Motiva Sans", Sans-serif, Arial',
                    padding: '0'
                });

                const headerBar = document.createElement('div');
                headerBar.id = 'rpaHeaderBar';
                Object.assign(headerBar.style, {
                    display: 'flex',
                    alignItems: 'center',
                    justifyContent: 'space-between',
                    padding: '10px 20px',
                    backgroundColor: '#17202d',
                    borderBottom: '1px solid #2a3f5a',
                    flexShrink: '0'
                });

                const title = document.createElement('h3');
                title.textContent = RPA_CONFIG.modalTitle;
                Object.assign(title.style, {
                    margin: '0',
                    color: '#67c1f5',
                    fontSize: '18px',
                    fontWeight: '500'
                });

                const gameNameDisplay = document.createElement('p');
                gameNameDisplay.id = 'rpaGameNameDisplay';
                Object.assign(gameNameDisplay.style, {
                    margin: '0 0 0 20px',
                    fontSize: '16px',
                    color: '#e5e5e5',
                    fontWeight: 'bold',
                    flexGrow: '1',
                    textAlign: 'center'
                });

                rpa_modeToggleButton = document.createElement('button');
                Object.assign(rpa_modeToggleButton.style, {
                    background: '#4b6f9c',
                    color: 'white',
                    border: '1px solid #2a3f5a',
                    borderRadius: '3px',
                    padding: '5px 10px',
                    cursor: 'pointer',
                    fontSize: '13px',
                    marginRight: '15px'
                });
                rpa_modeToggleButton.onmouseover = () => rpa_modeToggleButton.style.backgroundColor = '#67c1f5';
                rpa_modeToggleButton.onmouseout = () => rpa_modeToggleButton.style.backgroundColor = '#4b6f9c';
                rpa_modeToggleButton.addEventListener('click', rpa_handleModeToggle);
                rpa_updateModeToggleButtonText();

                const closeButton = document.createElement('button');
                closeButton.innerHTML = '&times;';
                Object.assign(closeButton.style, {
                    background: 'none',
                    border: 'none',
                    color: '#8f98a0',
                    fontSize: '30px',
                    cursor: 'pointer',
                    lineHeight: '1',
                    padding: '0 8px'
                });
                closeButton.onmouseover = () => closeButton.style.color = '#fff';
                closeButton.onmouseout = () => closeButton.style.color = '#8f98a0';
                closeButton.addEventListener('click', rpa_closeModal);

                const rightControls = document.createElement('div');
                rightControls.style.display = 'flex';
                rightControls.style.alignItems = 'center';
                rightControls.appendChild(rpa_modeToggleButton);
                rightControls.appendChild(closeButton);

                headerBar.appendChild(title);
                headerBar.appendChild(gameNameDisplay);
                headerBar.appendChild(rightControls);
                rpa_modal.appendChild(headerBar);

                const controlsBar = document.createElement('div');
                controlsBar.id = 'rpaControlsBar';
                Object.assign(controlsBar.style, {
                    display: 'flex',
                    alignItems: 'center',
                    gap: '15px',
                    padding: '10px 20px',
                    backgroundColor: '#1a2430',
                    borderBottom: '1px solid #23313f',
                    flexShrink: '0'
                });

                const fetchButton = document.createElement('button');
                fetchButton.textContent = RPA_CONFIG.fetchButtonText;
                fetchButton.id = 'rpaFetchDataButton';
                Object.assign(fetchButton.style, {
                    padding: '8px 20px',
                    backgroundColor: '#76b72a',
                    color: 'white',
                    border: '1px solid #5c9e1f',
                    borderRadius: '3px',
                    boxShadow: '0 1px 3px rgba(0,0,0,0.2)',
                    textShadow: '1px 1px 0px rgba(0,0,0,0.3)',
                    fontWeight: '500',
                    cursor: 'pointer',
                    fontSize: '14px',
                    lineHeight: '1.5'
                });
                fetchButton.onmouseover = () => {
                    fetchButton.style.backgroundColor = '#85c83a';
                };
                fetchButton.onmouseout = () => {
                    fetchButton.style.backgroundColor = '#76b72a';
                };
                fetchButton.onmousedown = () => {
                    fetchButton.style.backgroundColor = '#6aa424';
                };
                fetchButton.onmouseup = () => {
                    fetchButton.style.backgroundColor = '#85c83a';
                };
                fetchButton.addEventListener('click', rpa_handleFetchData);
                controlsBar.appendChild(fetchButton);

                const progressBarContainer = document.createElement('div');
                progressBarContainer.id = 'rpaProgressBarContainer';
                Object.assign(progressBarContainer.style, {
                    flexGrow: '1',
                    height: '10px',
                    backgroundColor: '#2a3f5a',
                    borderRadius: '5px',
                    overflow: 'hidden',
                    display: 'none'
                });
                rpa_progressBarFill = document.createElement('div');
                rpa_progressBarFill.id = 'rpaProgressBarFill';
                Object.assign(rpa_progressBarFill.style, {
                    width: '0%',
                    height: '100%',
                    backgroundColor: '#67c1f5',
                    borderRadius: '5px',
                    transition: 'width 0.2s ease-out'
                });
                progressBarContainer.appendChild(rpa_progressBarFill);
                controlsBar.appendChild(progressBarContainer);

                const statusDiv = document.createElement('div');
                statusDiv.id = 'rpaStatusDiv';
                Object.assign(statusDiv.style, {
                    minWidth: '250px',
                    textAlign: 'right',
                    fontSize: '13px',
                    color: '#8f98a0'
                });
                controlsBar.appendChild(statusDiv);
                rpa_modal.appendChild(controlsBar);

                const mainContentWrapper = document.createElement('div');
                mainContentWrapper.id = 'rpaMainContentWrapper';
                Object.assign(mainContentWrapper.style, {
                    display: 'flex',
                    flexGrow: '1',
                    overflow: 'hidden',
                    padding: '15px 20px'
                });

                const leftSidebar = document.createElement('div');
                leftSidebar.id = 'rpaLeftSidebar';
                Object.assign(leftSidebar.style, {
                    width: '280px',
                    flexShrink: '0',
                    paddingRight: '15px',
                    borderRight: '1px solid #23313f',
                    overflowY: 'auto',
                    scrollbarWidth: 'thin',
                    scrollbarColor: '#4b6f9c #1e2c3a'
                });
                leftSidebar.innerHTML = `<style>
                    #rpaLeftSidebar::-webkit-scrollbar { width: 6px; }
                    #rpaLeftSidebar::-webkit-scrollbar-track { background: #1e2c3a; border-radius: 3px; }
                    #rpaLeftSidebar::-webkit-scrollbar-thumb { background-color: #4b6f9c; border-radius: 3px; }
                    #rpaLeftSidebar h4 { color: #67c1f5; font-size: 15px; margin-top: 0; margin-bottom: 8px; border-bottom: 1px solid #2a3f5a; padding-bottom: 5px; }
                    #rpaLeftSidebar .summary-item { margin-bottom: 12px; }
                    #rpaLeftSidebar .summary-label { display: block; font-weight: bold; color: #67c1f5; margin-bottom: 3px; font-size: 13px; }
                    #rpaLeftSidebar .summary-value { display: block; color: #e5e5e5; font-size: 14px; }
                    #rpaLeftSidebar .summary-sub-value { display: block; font-size: 11px; margin-top: 2px; opacity: 0.85; }
                </style>`;
                const summaryDiv = document.createElement('div');
                summaryDiv.id = 'rpaSummaryDiv';
                leftSidebar.appendChild(summaryDiv);
                mainContentWrapper.appendChild(leftSidebar);

                const resultsArea = document.createElement('div');
                resultsArea.id = 'rpaResultsArea';
                Object.assign(resultsArea.style, {
                    flexGrow: '1',
                    overflow: 'auto',
                    paddingLeft: '15px',
                    scrollbarWidth: 'thin',
                    scrollbarColor: '#4b6f9c #1e2c3a'
                });
                resultsArea.innerHTML = `<style>
                    #rpaResultsArea::-webkit-scrollbar { width: 8px; height: 8px; }
                    #rpaResultsArea::-webkit-scrollbar-track { background: #1e2c3a; border-radius: 4px; }
                    #rpaResultsArea::-webkit-scrollbar-thumb { background-color: #4b6f9c; border-radius: 4px; border: 2px solid #1e2c3a; }
                    #rpaResultsArea::-webkit-scrollbar-thumb:hover { background-color: #67c1f5; }
                </style>`;
                const resultsDiv = document.createElement('div');
                resultsDiv.id = 'rpaResultsDiv';
                resultsArea.appendChild(resultsDiv);
                mainContentWrapper.appendChild(resultsArea);

                rpa_modal.appendChild(mainContentWrapper);
                document.body.appendChild(rpa_modal);
                rpa_modal.style.display = 'none';

                const style = document.createElement('style');
                style.textContent = `
                    @keyframes rpa_spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
                    .rpa_spinner { border: 2px solid rgba(255, 255, 255, 0.3); border-radius: 50%; border-top-color: #fff; width: 0.9em; height: 0.9em; animation: rpa_spin 1s linear infinite; display: inline-block; vertical-align: middle; margin-left: 8px; }
                    .rpaSinglePriceTable { width: auto; min-width: 680px; border-collapse: collapse; font-size: 12px; table-layout: fixed; background-color: #1e2c3a; border-radius: 3px; margin-left: 0; }
                    .rpaSinglePriceTable th, .rpaSinglePriceTable td { border: 1px solid #2a3f5a; padding: 6px 8px; text-align: left; }
                    .rpaSinglePriceTable th { background-color: #23313f; color: #a0b1c3; font-weight: 500; position: sticky; top: 0; z-index: 1; }
                    .rpaSinglePriceTable th.col-rank-header { width: 45px; }
                    .rpaSinglePriceTable th.col-region-header { width: 230px; }
                    .rpaSinglePriceTable th.col-local-price-header { width: 110px; }
                    .rpaSinglePriceTable th.col-rub-price-header, .rpaSinglePriceTable th.col-usd-price-header { width: 110px; }
                    .rpaSinglePriceTable th.col-diff-ru-header, .rpaSinglePriceTable th.col-diff-us-header { width: 120px; }
                    .rpaSinglePriceTable td.col-rank { text-align: center; }
                    .rpaSinglePriceTable td.col-region { word-break: break-word; white-space: normal; }
                    .rpaSinglePriceTable td.col-local-price, .rpaSinglePriceTable td.col-rub-price, .rpaSinglePriceTable td.col-usd-price, .rpaSinglePriceTable td.col-diff-ru, .rpaSinglePriceTable td.col-diff-us { text-align: right; white-space: nowrap; }
                    .rpaSinglePriceTable td.col-diff-ru.positive, .rpaSinglePriceTable td.col-diff-us.positive { color: lightgreen; }
                    .rpaSinglePriceTable td.col-diff-ru.negative, .rpaSinglePriceTable td.col-diff-us.negative { color: salmon; }
                    .rpaSinglePriceTable td.col-diff-ru.neutral, .rpaSinglePriceTable td.col-diff-us.neutral { color: #c6d4df; }
                    .rpaSinglePriceTable tr.highlight-ru td, .rpaSinglePriceTable tr.highlight-us td { background-color: rgba(103, 193, 245, 0.15) !important; font-weight: bold; }
                `;
                document.head.appendChild(style);
            }

            function rpa_updateProgressBar(percentage) {
                if (rpa_progressBarFill) {
                    rpa_progressBarFill.style.width = `${Math.min(100, Math.max(0, percentage))}%`;
                }
                const progressBarContainer = document.getElementById('rpaProgressBarContainer');
                if (progressBarContainer) {
                    progressBarContainer.style.display = (percentage > 0 && percentage < 100) ? 'flex' : 'none';
                }
            }

            function rpa_openModal() {
                if (!rpa_modal) rpa_createModal();
                rpa_updateTextsAndRegionNames();
                rpa_currentAppId = rpa_getAppIdFromUrl();
                const initialMsg = rpa_currentDisplayMode === 'USD' ? 'Click "Fetch Data" to begin.' : 'Нажмите "Сбор данных" для начала.';
                const statusMsg = rpa_currentDisplayMode === 'USD' ? 'Click "Fetch Data" to start analysis.' : 'Нажмите "Сбор данных" для начала анализа.';

                if (!rpa_currentAppId) {
                    alert(rpa_currentDisplayMode === 'USD' ? '[RPA] Could not determine AppID of the game.' : '[RPA] Не удалось определить AppID игры.');
                    return;
                }

                const gameTitleElement = document.querySelector('#appHubAppName');
                rpa_currentGameName = gameTitleElement ? gameTitleElement.textContent.trim() : (rpa_currentDisplayMode === 'USD' ? `Game #${rpa_currentAppId}` : `Игра #${rpa_currentAppId}`);
                const gameNameDisplay = document.getElementById('rpaGameNameDisplay');
                if (gameNameDisplay) gameNameDisplay.textContent = rpa_currentGameName;

                rpa_modal.style.display = 'flex';
                document.getElementById('rpaSummaryDiv').innerHTML = `<p>${initialMsg}</p>`;
                document.getElementById('rpaResultsDiv').innerHTML = '';
                rpa_updateModalStatus(statusMsg);
                document.getElementById('rpaFetchDataButton').disabled = false;
                rpa_updateProgressBar(0);
            }

            function rpa_closeModal() {
                if (rpa_fetchController) {
                    rpa_fetchController.abort();
                    rpa_fetchController = null;
                }
                if (rpa_modal) rpa_modal.style.display = 'none';
                const statusMsg = rpa_currentDisplayMode === 'USD' ? 'Ready for new analysis.' : 'Готово к новому анализу.';
                rpa_updateModalStatus(statusMsg);
                rpa_updateProgressBar(0);
            }

            function rpa_updateModalStatus(message, isLoading = false) {
                const statusDiv = document.getElementById('rpaStatusDiv');
                const fetchBtn = document.getElementById('rpaFetchDataButton');
                if (statusDiv) {
                    statusDiv.innerHTML = isLoading ? `${message} <span class="rpa_spinner"></span>` : message;
                }
                if (fetchBtn) {
                    fetchBtn.disabled = isLoading;
                }
            }

            async function rpa_handleFetchData() {
                if (rpa_fetchController) {
                    rpa_fetchController.abort();
                    console.log("[RPA] Previous data fetch aborted.");
                }
                rpa_fetchController = new AbortController();
                const signal = rpa_fetchController.signal;

                rpa_updateProgressBar(0);
                rpa_updateModalStatus(rpa_currentDisplayMode === 'USD' ? 'Initializing...' : 'Инициализация...', true);
                const summaryDiv = document.getElementById('rpaSummaryDiv');
                const resultsDiv = document.getElementById('rpaResultsDiv');
                summaryDiv.innerHTML = `<h4>${rpa_currentDisplayMode === 'USD' ? 'Summary:' : 'Сводная информация:'}</h4>`;
                resultsDiv.innerHTML = '';

                if (!rpa_currentAppId) {
                    rpa_updateModalStatus(rpa_currentDisplayMode === 'USD' ? 'Error: AppID not defined.' : 'Ошибка: AppID не определен.', false);
                    rpa_updateProgressBar(0);
                    return;
                }

                const gameTitleElement = document.querySelector('#appHubAppName');
                rpa_currentGameName = gameTitleElement ? gameTitleElement.textContent.trim() : (rpa_currentDisplayMode === 'USD' ? `Game #${rpa_currentAppId}` : `Игра #${rpa_currentAppId}`);
                const gameNameDisplay = document.getElementById('rpaGameNameDisplay');
                if (gameNameDisplay) gameNameDisplay.textContent = rpa_currentGameName;

                rpa_updateProgressBar(2);

                let usData;
                const usRegionConfig = RPA_CONFIG.regions.find(r => r.cc === 'US');
                if (!usRegionConfig) {
                    rpa_updateModalStatus(rpa_currentDisplayMode === 'USD' ? 'Error: Configuration for US region not found.' : 'Ошибка: Конфигурация для региона США не найдена.', false);
                    rpa_updateProgressBar(0);
                    return;
                }

                try {
                    rpa_updateModalStatus(rpa_currentDisplayMode === 'USD' ? 'Fetching US price...' : 'Запрос цены для США...', true);
                    usData = await rpa_fetchItemData(rpa_currentAppId, usRegionConfig.cc, signal);
                    if (signal.aborted) throw new DOMException('Request aborted', 'AbortError');
                    if (usData && usData.basic_info && usData.basic_info.name) {
                        rpa_currentGameName = usData.basic_info.name;
                        if (gameNameDisplay) gameNameDisplay.textContent = rpa_currentGameName;
                    }
                } catch (error) {
                    if (error.name === 'AbortError') {
                        rpa_updateModalStatus(rpa_currentDisplayMode === 'USD' ? 'Data fetch aborted.' : 'Сбор данных отменен.', false);
                    } else {
                        rpa_updateModalStatus((rpa_currentDisplayMode === 'USD' ? `Error fetching US price: ` : `Ошибка при запросе цены для США: `) + error.message, false);
                    }
                    rpa_updateProgressBar(0);
                    return;
                }

                if (!usData || !usData.best_purchase_option || !usData.best_purchase_option.final_price_in_cents) {
                    let msg = (rpa_currentDisplayMode === 'USD' ? `Game "${rpa_currentGameName}" ` : `Игра "${rpa_currentGameName}" `);
                    const isFreeOrUnavailableUS = (usData && usData.success === 1 && (!usData.best_purchase_option || usData.best_purchase_option.final_price_in_cents === "0" || !usData.best_purchase_option.final_price_in_cents));
                    msg += isFreeOrUnavailableUS ? (rpa_currentDisplayMode === 'USD' ? "is free or not available in the US." : "бесплатна или недоступна в США.") :
                        (rpa_currentDisplayMode === 'USD' ? "is unavailable in the US or has no price." : "недоступна в США или не имеет цены.");
                    msg += (rpa_currentDisplayMode === 'USD' ? " Analysis cannot proceed." : " Анализ невозможен.");
                    rpa_updateModalStatus(msg, false);
                    rpa_updateProgressBar(0);
                    return;
                }

                const basePriceCents = rpa_getPriceInCents(usData.best_purchase_option);
                if (!basePriceCents) {
                    rpa_updateModalStatus(rpa_currentDisplayMode === 'USD' ? 'Could not determine base US price for calculation.' : 'Не удалось определить базовую цену в США для расчета.', false);
                    rpa_updateProgressBar(0);
                    return;
                }
                const baseUsdPrice = parseFloat(basePriceCents) / 100;
                const baseUsdFormattedPrice = rpa_getDisplayFormattedPrice(usData.best_purchase_option);

                rpa_updateProgressBar(5);

                if (rpa_currentDisplayMode === 'USD') {
                    summaryDiv.innerHTML += `<div class="summary-item"><span class="summary-label">Base US Price:</span><span class="summary-value">${baseUsdPrice.toLocaleString('en-US', { style: 'currency', currency: 'USD' })}</span></div>`;
                    try {
                        await rpa_fetchExchangeRates('usd', signal);
                        if (signal.aborted) throw new DOMException('Request aborted', 'AbortError');
                    } catch (e) {
                        if (e.name === 'AbortError') {
                            rpa_updateModalStatus('Data fetch aborted.', false);
                        } else {
                            rpa_updateModalStatus('Error fetching base USD exchange rates.', false);
                        }
                        rpa_updateProgressBar(0);
                        return;
                    }
                } else {
                    summaryDiv.innerHTML += `<div class="summary-item"><span class="summary-label">Базовая цена в США (для расчета):</span><span class="summary-value">$${baseUsdPrice.toFixed(2)}</span></div>`;
                    const recommendedRubPriceVal = calculateRecommendedRubPrice(baseUsdPrice);
                    if (recommendedRubPriceVal === null || typeof recommendedRubPriceVal === 'string') {
                        summaryDiv.innerHTML += `<div class="summary-item"><span class="summary-label">Рекомендуемая цена Steam в РФ:</span><span class="summary-value">${recommendedRubPriceVal || 'Не удалось рассчитать'}</span></div>`;
                    } else {
                        summaryDiv.innerHTML += `<div class="summary-item"><span class="summary-label">Рекомендуемая цена Steam в РФ:</span><span class="summary-value">${recommendedRubPriceVal.toLocaleString('ru-RU')} руб.</span></div>`;
                    }
                    try {
                        await rpa_fetchExchangeRates('rub', signal);
                        if (signal.aborted) throw new DOMException('Request aborted', 'AbortError');
                    } catch (e) {
                        if (e.name === 'AbortError') {
                            rpa_updateModalStatus('Сбор данных отменен.', false);
                        } else {
                            rpa_updateModalStatus('Ошибка загрузки базовых курсов валют.', false);
                        }
                        rpa_updateProgressBar(0);
                        return;
                    }
                }

                const regionalPrices = [];
                let ruActualPriceData = null;
                let ruActualPriceInRub = null;

                if (rpa_currentDisplayMode === 'USD') {
                    regionalPrices.push({
                        regionName: usRegionConfig.name,
                        localPriceFormatted: baseUsdFormattedPrice,
                        priceInUsd: baseUsdPrice,
                        cc: usRegionConfig.cc
                    });
                }

                const otherRegions = RPA_CONFIG.regions.filter(r => rpa_currentDisplayMode === 'USD' ? r.cc !== usRegionConfig.cc : true);
                const totalRegionsToProcess = otherRegions.length;
                let regionsProcessedCount = 0;

                for (let i = 0; i < totalRegionsToProcess; i += RPA_CONFIG.batchSize) {
                    if (signal.aborted) break;
                    const batch = otherRegions.slice(i, i + RPA_CONFIG.batchSize);
                    const batchProgressText = rpa_currentDisplayMode === 'USD' ?
                        `Workspaceing prices: batch ${Math.floor(i/RPA_CONFIG.batchSize)+1}/${Math.ceil(totalRegionsToProcess/RPA_CONFIG.batchSize)}` :
                        `Сбор цен: группа ${Math.floor(i/RPA_CONFIG.batchSize)+1}/${Math.ceil(totalRegionsToProcess/RPA_CONFIG.batchSize)}`;
                    rpa_updateModalStatus(`${batchProgressText} (${batch.map(r=>r.cc).join(', ')})...`, true);

                    const batchPromises = batch.map(region =>
                        rpa_fetchItemData(rpa_currentAppId, region.cc, signal)
                        .then(data => ({
                            region,
                            data
                        }))
                        .catch(error => {
                            if (error.name === 'AbortError') throw error;
                            console.warn(`[RPA] Error for region ${region.name} (${region.cc}): ${error.message}`);
                            return {
                                region,
                                error,
                                data: null
                            };
                        })
                    );

                    try {
                        const batchResults = await Promise.allSettled(batchPromises);
                        if (signal.aborted) throw new DOMException('Request aborted', 'AbortError');

                        for (const result of batchResults) {
                            regionsProcessedCount++;
                            let currentProgress = 5 + Math.round(((regionsProcessedCount + 1) / (totalRegionsToProcess + 1)) * 85);
                            rpa_updateProgressBar(currentProgress);

                            if (result.status === 'fulfilled' && result.value.data) {
                                const {
                                    region,
                                    data: regionData
                                } = result.value;
                                if (regionData && regionData.basic_info && regionData.best_purchase_option) {
                                    const purchaseOption = regionData.best_purchase_option;
                                    let priceInCents = rpa_getPriceInCents(purchaseOption);
                                    let displayFormattedPrice = rpa_getDisplayFormattedPrice(purchaseOption);

                                    if (priceInCents !== null && priceInCents >= 0) {
                                        const localPrice = parseFloat(priceInCents) / 100;

                                        if (rpa_currentDisplayMode === 'USD') {
                                            let priceInUsd = null;
                                            if (region.currencyApiCode.toLowerCase() === 'usd') {
                                                priceInUsd = localPrice;
                                            } else {
                                                try {
                                                    const rates = await rpa_fetchExchangeRates(region.currencyApiCode.toLowerCase(), signal);
                                                    if (signal.aborted) throw new DOMException('Request aborted', 'AbortError');
                                                    if (rates && typeof rates.usd === 'number') {
                                                        priceInUsd = localPrice * rates.usd;
                                                    } else {
                                                        const usdBasedRates = await rpa_fetchExchangeRates('usd', signal);
                                                        if (usdBasedRates && typeof usdBasedRates[region.currencyApiCode.toLowerCase()] === 'number' && usdBasedRates[region.currencyApiCode.toLowerCase()] !== 0) {
                                                            priceInUsd = localPrice / usdBasedRates[region.currencyApiCode.toLowerCase()];
                                                        } else {
                                                            console.warn(`[RPA] USD rate not found for ${region.currencyApiCode}`);
                                                        }
                                                    }
                                                } catch (rateError) {
                                                    if (rateError.name === 'AbortError') throw rateError;
                                                    console.warn(`[RPA] Rate error (USD) for ${region.currencyApiCode}: ${rateError.message}`);
                                                }
                                            }
                                            if (priceInUsd !== null && region.cc !== 'US') {
                                                regionalPrices.push({
                                                    regionName: region.name,
                                                    localPriceFormatted: displayFormattedPrice,
                                                    priceInUsd: priceInUsd,
                                                    cc: region.cc
                                                });
                                            }
                                        } else {
                                            let priceInRub = null;
                                            if (region.currencyApiCode.toLowerCase() === 'rub') {
                                                priceInRub = localPrice;
                                            } else {
                                                try {
                                                    const rates = await rpa_fetchExchangeRates(region.currencyApiCode.toLowerCase(), signal);
                                                    if (signal.aborted) throw new DOMException('Request aborted', 'AbortError');
                                                    if (rates && typeof rates.rub === 'number') {
                                                        priceInRub = localPrice * rates.rub;
                                                    } else {
                                                        console.warn(`[RPA] RUB rate not found for ${region.currencyApiCode}`);
                                                    }
                                                } catch (rateError) {
                                                    if (rateError.name === 'AbortError') throw rateError;
                                                    console.warn(`[RPA] Rate error (RUB) for ${region.currencyApiCode}: ${rateError.message}`);
                                                }
                                            }
                                            if (priceInRub !== null) {
                                                regionalPrices.push({
                                                    regionName: region.name,
                                                    localPriceFormatted: displayFormattedPrice,
                                                    priceInRub: priceInRub,
                                                    cc: region.cc
                                                });
                                            }
                                            if (region.cc === 'RU') {
                                                ruActualPriceData = {
                                                    formatted: displayFormattedPrice,
                                                    rub: priceInRub
                                                };
                                                ruActualPriceInRub = priceInRub;
                                            }
                                            if (region.cc === 'US' && rpa_currentDisplayMode === 'RUB' && !regionalPrices.find(p => p.cc === 'US')) {
                                                regionalPrices.push({
                                                    regionName: region.name,
                                                    localPriceFormatted: displayFormattedPrice,
                                                    priceInRub: priceInRub,
                                                    cc: region.cc
                                                });
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    } catch (batchError) {
                        if (batchError.name === 'AbortError') {
                            rpa_updateModalStatus(rpa_currentDisplayMode === 'USD' ? 'Data fetch aborted.' : 'Сбор данных отменен.', false);
                            rpa_updateProgressBar(0);
                            rpa_fetchController = null;
                            return;
                        }
                        console.error("[RPA] Error processing batch:", batchError);
                    }
                    if (i + RPA_CONFIG.batchSize < totalRegionsToProcess && !signal.aborted) {
                        await new Promise(resolve => setTimeout(resolve, RPA_CONFIG.delayBetweenBatches));
                    }
                    if (signal.aborted) break;
                }
                if (signal.aborted) {
                    rpa_updateModalStatus(rpa_currentDisplayMode === 'USD' ? 'Data fetch aborted.' : 'Сбор данных отменен.', false);
                    rpa_updateProgressBar(0);
                    rpa_fetchController = null;
                    return;
                }

                rpa_updateProgressBar(98);

                if (rpa_currentDisplayMode === 'USD') {
                    if (regionalPrices.length > 0) {
                        regionalPrices.sort((a, b) => a.priceInUsd - b.priceInUsd);
                        const cheapestRegion = regionalPrices[0];
                        const mostExpensiveRegion = regionalPrices[regionalPrices.length - 1];
                        summaryDiv.innerHTML += `<div class="summary-item"><span class="summary-label">Cheapest (USD):</span><span class="summary-value">${cheapestRegion.priceInUsd.toLocaleString('en-US', { style: 'currency', currency: 'USD' })} (${cheapestRegion.regionName})</span></div>`;
                        summaryDiv.innerHTML += `<div class="summary-item"><span class="summary-label">Most Expensive (USD):</span><span class="summary-value">${mostExpensiveRegion.priceInUsd.toLocaleString('en-US', { style: 'currency', currency: 'USD' })} (${mostExpensiveRegion.regionName})</span></div>`;
                        const usEntryIndex = regionalPrices.findIndex(r => r.cc === 'US');
                        if (usEntryIndex !== -1) {
                            summaryDiv.innerHTML += `<div class="summary-item"><span class="summary-label">US Price Rank:</span><span class="summary-value">${usEntryIndex + 1} of ${regionalPrices.length}</span></div>`;
                        }
                        generatePriceTable(regionalPrices, baseUsdPrice, resultsDiv);
                    } else {
                        resultsDiv.innerHTML = `<p style="text-align:center; margin-top:20px; color: #8f98a0;">Could not retrieve regional prices for comparison.</p>`;
                    }
                } else {
                    const ruComparisonDiv = document.createElement('div');
                    ruComparisonDiv.id = 'rpaRuComparison';
                    ruComparisonDiv.style.cssText = "margin-top:10px; padding-top:10px; border-top: 1px solid #2a3f5a;";
                    summaryDiv.appendChild(ruComparisonDiv);
                    const recommendedRubPriceVal = calculateRecommendedRubPrice(baseUsdPrice);

                    if (ruActualPriceData && typeof recommendedRubPriceVal === 'number') {
                        const actualRu = ruActualPriceData.rub;
                        let factPriceValue = "N/A",
                            factPriceSubValue = "",
                            subValueColor = "#c6d4df";
                        if (actualRu !== null) {
                            factPriceValue = `${actualRu.toLocaleString('ru-RU', {minimumFractionDigits: 2, maximumFractionDigits: 2})} руб.`;
                            const diff = actualRu - recommendedRubPriceVal;
                            const diffPercent = recommendedRubPriceVal !== 0 ? (diff / recommendedRubPriceVal) * 100 : (diff > 0 ? Infinity : (actualRu === 0 ? 0 : -Infinity));
                            if (diff < -0.01) {
                                subValueColor = 'lightgreen';
                                factPriceSubValue = `(на ${Math.abs(diff).toLocaleString('ru-RU', {maximumFractionDigits: 2})} руб. / ${Math.abs(diffPercent).toFixed(1)}% ДЕШЕВЛЕ рекомендуемой)`;
                            } else if (diff > 0.01) {
                                subValueColor = 'salmon';
                                factPriceSubValue = `(на ${diff.toLocaleString('ru-RU', {maximumFractionDigits: 2})} руб. / ${diffPercent.toFixed(1)}% ДОРОЖЕ рекомендуемой)`;
                            } else {
                                factPriceSubValue = `(соответствует рекомендуемой)`;
                            }
                        } else {
                            factPriceValue = `<span style="color: orange;">Цена в РФ не найдена/неконвертируема.</span>`;
                        }
                        ruComparisonDiv.innerHTML += `<div class="summary-item"><span class="summary-label">Фактическая цена в РФ:</span><span class="summary-value">${factPriceValue}${factPriceSubValue ? `<span class="summary-sub-value" style="color:${subValueColor};">${factPriceSubValue}</span>` : ''}</span></div>`;
                    } else if (typeof recommendedRubPriceVal === 'number') {
                        ruComparisonDiv.innerHTML += `<div class="summary-item"><span class="summary-label">Фактическая цена в РФ:</span><span class="summary-value" style="color:orange;">Не найдена.</span></div>`;
                    }

                    if (regionalPrices.length > 0) {
                        regionalPrices.sort((a, b) => a.priceInRub - b.priceInRub);
                        let ruRank = -1;
                        if (ruActualPriceInRub !== null) {
                            ruRank = regionalPrices.findIndex(rp => rp.cc === 'RU' && Math.abs(rp.priceInRub - ruActualPriceInRub) < 0.01) + 1;
                            if (ruRank === 0) {
                                const ruEntry = regionalPrices.find(rp => rp.cc === 'RU');
                                if (ruEntry) ruRank = regionalPrices.findIndex(rp => rp.priceInRub >= ruEntry.priceInRub) + 1;
                                if (ruRank === 0 && regionalPrices.length > 0) ruRank = 1;
                            }
                        }
                        let rankText = "Цена РФ отсутствует, мировой ранг не определен.";
                        if (ruRank > 0) {
                            rankText = `${ruRank} из ${regionalPrices.length}`;
                        } else if (ruActualPriceInRub !== null) {
                            rankText = `Не удалось точно определить ранг РФ.`;
                        }
                        ruComparisonDiv.innerHTML += `<div class="summary-item"><span class="summary-label">Место РФ в мировом рейтинге цен:</span><span class="summary-value">${rankText}</span></div>`;
                        generatePriceTable(regionalPrices, ruActualPriceInRub, resultsDiv);
                    } else {
                        resultsDiv.innerHTML = `<p style="text-align:center; margin-top:20px; color: #8f98a0;">Не удалось получить региональные цены для сравнения.</p>`;
                    }
                }

                rpa_updateModalStatus(rpa_currentDisplayMode === 'USD' ? 'Analysis complete.' : 'Анализ завершен.', false);
                rpa_updateProgressBar(100);
                setTimeout(() => rpa_updateProgressBar(0), 2000);
                rpa_fetchController = null;
            }

            function generatePriceTable(prices, comparisonPriceBase, container) {
                container.innerHTML = '';
                const table = document.createElement('table');
                table.className = 'rpaSinglePriceTable';
                const thead = table.createTHead();
                const headerRow = thead.insertRow();

                const isUSDMode = rpa_currentDisplayMode === 'USD';
                const headers = isUSDMode ? [{
                        text: '#',
                        class: 'col-rank-header'
                    }, {
                        text: 'Region (CC)',
                        class: 'col-region-header'
                    },
                    {
                        text: 'Local Price',
                        class: 'col-local-price-header'
                    }, {
                        text: 'Price (USD)',
                        class: 'col-usd-price-header'
                    },
                    {
                        text: 'Diff. vs US (%)',
                        class: 'col-diff-us-header'
                    }
                ] : [{
                        text: '№',
                        class: 'col-rank-header'
                    }, {
                        text: 'Регион (Код страны)',
                        class: 'col-region-header'
                    },
                    {
                        text: 'Цена (лок. вал.)',
                        class: 'col-local-price-header'
                    }, {
                        text: 'Цена (RUB)',
                        class: 'col-rub-price-header'
                    },
                    {
                        text: 'Разница с РФ (%)',
                        class: 'col-diff-ru-header'
                    }
                ];

                headers.forEach(headerInfo => {
                    const th = document.createElement('th');
                    th.textContent = headerInfo.text;
                    th.className = headerInfo.class;
                    headerRow.appendChild(th);
                });

                const tbody = table.createTBody();
                prices.forEach((rp, index) => {
                    const row = tbody.insertRow();
                    const highlightCC = isUSDMode ? 'US' : 'RU';
                    const highlightClass = isUSDMode ? 'highlight-us' : 'highlight-ru';
                    if (rp.cc === highlightCC) {
                        row.classList.add(highlightClass);
                    }

                    row.insertCell().textContent = index + 1;
                    row.cells[0].className = 'col-rank';
                    row.insertCell().textContent = `${rp.regionName} (${rp.cc})`;
                    row.cells[1].className = 'col-region';

                    const priceToDisplay = isUSDMode ? rp.priceInUsd : rp.priceInRub;
                    row.insertCell().textContent = rp.localPriceFormatted || (priceToDisplay === 0 ? (isUSDMode ? 'Free' : 'Бесплатно') : 'N/A');
                    row.cells[2].className = 'col-local-price';

                    const convertedPriceCell = row.insertCell();
                    convertedPriceCell.className = isUSDMode ? 'col-usd-price' : 'col-rub-price';
                    if (priceToDisplay !== null) {
                        convertedPriceCell.textContent = isUSDMode ?
                            priceToDisplay.toLocaleString('en-US', {
                                style: 'currency',
                                currency: 'USD'
                            }) :
                            priceToDisplay.toLocaleString('ru-RU', {
                                maximumFractionDigits: 0
                            }) + ' ₽';
                    } else {
                        convertedPriceCell.textContent = 'N/A';
                    }

                    const diffCell = row.insertCell();
                    diffCell.className = isUSDMode ? 'col-diff-us' : 'col-diff-ru';
                    if (rp.cc === highlightCC) {
                        diffCell.textContent = isUSDMode ? 'Base' : '-';
                        diffCell.classList.add('neutral');
                    } else if (comparisonPriceBase !== null && comparisonPriceBase > 0 && priceToDisplay !== null) {
                        const diffPercent = ((priceToDisplay - comparisonPriceBase) / comparisonPriceBase) * 100;
                        diffCell.textContent = (diffPercent >= 0 ? '+' : '') + diffPercent.toFixed(1) + '%';
                        if (diffPercent < -0.1) diffCell.classList.add('positive');
                        else if (diffPercent > 0.1) diffCell.classList.add('negative');
                        else diffCell.classList.add('neutral');
                    } else if (priceToDisplay === 0 && comparisonPriceBase === 0) {
                        diffCell.textContent = '0%';
                        diffCell.classList.add('neutral');
                    } else {
                        diffCell.textContent = 'N/A';
                        diffCell.classList.add('neutral');
                    }
                });
                container.appendChild(table);
            }

            function rpa_init() {
                rpa_updateTextsAndRegionNames();
                const initLoad = () => {
                    if (document.querySelector('.game_area_purchase_game_wrapper')) {
                        rpa_addPriorButton();
                        rpa_createModal();
                    } else {
                        setTimeout(initLoad, 500);
                    }
                };
                if (document.readyState === 'complete' || document.readyState === 'interactive') {
                    initLoad();
                } else {
                    window.addEventListener('DOMContentLoaded', initLoad);
                }
            }
            rpa_init();
        })();
    }

    // Скрипт для получения дополнительной информации об игре при наведении на неё на странице поиска по каталогу | https://store.steampowered.com/search/
    if (scriptsConfig.catalogInfo && unsafeWindow.location.pathname.includes('/search')) {
        (function() {
            'use strict';

            const ALEXANDER_API_URL = "https://api.steampowered.com/IStoreBrowseService/GetItems/v1";
            const HANNIBAL_WAIT_TIME = 2000;
            const CAESAR_VISIBLE_ELEMENTS_SELECTOR = "a.search_result_row[data-ds-appid]";
            const NAPOLEON_HOVER_ELEMENT_SELECTOR = "a.search_result_row";

            let GENghis_collectedAppIds = new Set();
            let ATTILA_tooltip = null;
            let SALADIN_hoverTimer = null;
            let TAMERLAN_hideTimer = null;

            let RUSSIAN_TRANSLATION_CHECKBOX = null;
            let RUSSIAN_VOICE_CHECKBOX = null;
            let NO_RUSSIAN_CHECKBOX = null;
            const STEAM_TAGS_CACHE_KEY = 'SteamEnhancer_TagsCache_v2';
            const STEAM_TAGS_URL = "https://gist.githubusercontent.com/0wn3dg0d/22a351ff4c65e50a9a8af6da360defad/raw/steamrutagsownd.json";
            const OWNED_APPS_CACHE_KEY = 'SteamEnhancer_OwnedApps';
            const USERDATA_URL = 'https://store.steampowered.com/dynamicstore/userdata/';
            const CACHE_DURATION = 24 * 60 * 60 * 1000;

            async function loadSteamTags() {
                const cached = GM_getValue(STEAM_TAGS_CACHE_KEY, {
                    data: null,
                    timestamp: 0
                });
                const now = Date.now();
                const CACHE_DURATION = 744 * 60 * 60 * 1000;

                if (cached.data && (now - cached.timestamp) < CACHE_DURATION) {
                    return cached.data;
                }

                try {
                    const response = await new Promise((resolve, reject) => {
                        GM_xmlhttpRequest({
                            method: "GET",
                            url: STEAM_TAGS_URL,
                            onload: resolve,
                            onerror: reject
                        });
                    });

                    if (response.status === 200) {
                        const data = JSON.parse(response.responseText);
                        GM_setValue(STEAM_TAGS_CACHE_KEY, {
                            data: data,
                            timestamp: now
                        });
                        return data;
                    }
                } catch (e) {
                    console.error('Ошибка загрузки тегов:', e);
                    return cached.data || {};
                }

                return {};
            }

            async function fetchOwnedApps() {
                const cached = GM_getValue(OWNED_APPS_CACHE_KEY, {
                    data: null,
                    timestamp: 0
                });
                const now = Date.now();

                if (cached.data && (now - cached.timestamp) < CACHE_DURATION) {
                    return cached.data;
                }

                try {
                    const response = await new Promise((resolve, reject) => {
                        GM_xmlhttpRequest({
                            method: "GET",
                            url: USERDATA_URL,
                            onload: resolve,
                            onerror: reject
                        });
                    });

                    if (response.status === 200) {
                        const data = JSON.parse(response.responseText);
                        const ownedApps = data.rgOwnedApps || [];
                        GM_setValue(OWNED_APPS_CACHE_KEY, {
                            data: ownedApps,
                            timestamp: now
                        });
                        return ownedApps;
                    }
                } catch (e) {
                    console.error('Ошибка загрузки списка игр:', e);
                    return cached.data || [];
                }

                return [];
            }

            function fetchGameData(appIds) {
                const inputJson = {
                    ids: Array.from(appIds).map(appid => ({
                        appid
                    })),
                    context: {
                        language: "russian",
                        country_code: "US",
                        steam_realm: 1
                    },
                    data_request: {
                        include_assets: true,
                        include_release: true,
                        include_platforms: true,
                        include_all_purchase_options: true,
                        include_screenshots: true,
                        include_trailers: true,
                        include_ratings: true,
                        include_tag_count: true,
                        include_reviews: true,
                        include_basic_info: true,
                        include_supported_languages: true,
                        include_full_description: true,
                        include_included_items: true,
                        included_item_data_request: {
                            include_assets: true,
                            include_release: true,
                            include_platforms: true,
                            include_all_purchase_options: true,
                            include_screenshots: true,
                            include_trailers: true,
                            include_ratings: true,
                            include_tag_count: true,
                            include_reviews: true,
                            include_basic_info: true,
                            include_supported_languages: true,
                            include_full_description: true,
                            include_included_items: true,
                            include_assets_without_overrides: true,
                            apply_user_filters: false,
                            include_links: true
                        },
                        include_assets_without_overrides: true,
                        apply_user_filters: false,
                        include_links: true
                    }
                };

                GM_xmlhttpRequest({
                    method: "GET",
                    url: `${ALEXANDER_API_URL}?input_json=${encodeURIComponent(JSON.stringify(inputJson))}`,
                    onload: function(response) {
                        const data = JSON.parse(response.responseText);
                        processGameData(data);
                    }
                });
            }

            async function processGameData(data) {
                const ownedApps = await fetchOwnedApps();
                const items = data.response.store_items;
                const dlcFilterActive = document.querySelector('[data-param="your_dlc"] .tab_filter_control')?.classList.contains('checked');

                items.forEach(item => {
                    const appId = item.id;
                    const gameElement = document.querySelector(`a.search_result_row[data-ds-appid="${appId}"]`);
                    if (gameElement) {
                        const gameData = {
                            is_early_access: item.is_early_access,
                            review_count: item.reviews?.summary_filtered?.review_count,
                            percent_positive: item.reviews?.summary_filtered?.percent_positive,
                            short_description: item.basic_info?.short_description,
                            publishers: item.basic_info?.publishers?.map(p => p.name).join(", "),
                            developers: item.basic_info?.developers?.map(d => d.name).join(", "),
                            franchises: item.basic_info?.franchises?.map(f => f.name).join(", "),
                            tagids: item.tagids || [],
                            language_support_russian: item.supported_languages?.find(lang => lang.elanguage === 8),
                            language_support_english: item.supported_languages?.find(lang => lang.elanguage === 0),
                            type: item.type,
                            parent_appid: item.related_items?.parent_appid
                        };

                        gameElement.dataset.gameInfo = JSON.stringify(gameData);
                        applyRussianLanguageFilter(gameElement);

                        if (item.type === 4 && item.related_items?.parent_appid && ownedApps.includes(item.related_items.parent_appid)) {
                            gameElement.classList.add('es_highlighted_dlcforya');
                        }

                        if (dlcFilterActive) {
                            applyDlcFilter(gameElement, true);
                        }
                    }
                });
            }

            function collectAndFetchAppIds() {
                const visibleElements = document.querySelectorAll(CAESAR_VISIBLE_ELEMENTS_SELECTOR);
                const newAppIds = new Set();

                visibleElements.forEach(element => {
                    const appId = element.dataset.dsAppid;
                    if (!GENghis_collectedAppIds.has(appId)) {
                        newAppIds.add(parseInt(appId, 10));
                        GENghis_collectedAppIds.add(appId);
                    }
                });

                if (newAppIds.size > 0) {
                    fetchGameData(newAppIds);
                }
            }

            function handleHover(event) {
                const gameElement = event.target.closest(NAPOLEON_HOVER_ELEMENT_SELECTOR);

                if (gameElement && gameElement.dataset.gameInfo) {
                    clearTimeout(SALADIN_hoverTimer);
                    clearTimeout(TAMERLAN_hideTimer);

                    SALADIN_hoverTimer = setTimeout(() => {
                        const gameData = JSON.parse(gameElement.dataset.gameInfo);
                        displayGameInfo(gameElement, gameData);
                    }, 300);
                } else {
                    clearTimeout(SALADIN_hoverTimer);
                    clearTimeout(TAMERLAN_hideTimer);
                    if (ATTILA_tooltip) {
                        ATTILA_tooltip.style.opacity = 0;
                        setTimeout(() => {
                            ATTILA_tooltip.style.display = 'none';
                        }, 300);
                    }
                }
            }

            function getReviewClassCatalog(percent, totalReviews) {
                if (totalReviews === 0) return 'catalog-no-reviews';
                if (percent >= 70) return 'catalog-positive';
                if (percent >= 40) return 'catalog-mixed';
                if (percent >= 1) return 'catalog-negative';
                return 'catalog-negative';
            }

            async function getTagNames(tagIds) {
                const tagsData = await loadSteamTags();
                return tagIds.slice(0, 5).map(tagId =>
                    tagsData[tagId] || `Тег #${tagId}`
                );
            }

            async function displayGameInfo(element, data) {
                if (!ATTILA_tooltip) {
                    ATTILA_tooltip = document.createElement('div');
                    ATTILA_tooltip.className = 'custom-tooltip';
                    ATTILA_tooltip.innerHTML = '<div class="tooltip-arrow"></div><div class="tooltip-content"></div>';
                    document.body.appendChild(ATTILA_tooltip);
                }

                const tooltipContent = ATTILA_tooltip.querySelector('.tooltip-content');

                let languageSupportRussianText = "Отсутствует";
                let languageSupportRussianClass = 'catalog-language-no';
                if (data.language_support_russian) {
                    languageSupportRussianText = "";
                    if (data.language_support_russian.supported) languageSupportRussianText += "<br>Интерфейс: ✔ ";
                    if (data.language_support_russian.full_audio) languageSupportRussianText += "<br>Озвучка: ✔ ";
                    if (data.language_support_russian.subtitles) languageSupportRussianText += "<br>Субтитры: ✔";
                    if (languageSupportRussianText === "") languageSupportRussianText = "Отсутствует";
                    else languageSupportRussianClass = 'catalog-language-yes';
                }

                let languageSupportEnglishText = "Отсутствует";
                let languageSupportEnglishClass = 'catalog-language-no';
                if (scriptsConfig.toggleEnglishLangInfo && data.language_support_english) {
                    languageSupportEnglishText = "";
                    if (data.language_support_english.supported) languageSupportEnglishText += "<br>Интерфейс: ✔ ";
                    if (data.language_support_english.full_audio) languageSupportEnglishText += "<br>Озвучка: ✔ ";
                    if (data.language_support_english.subtitles) languageSupportEnglishText += "<br>Субтитры: ✔";
                    if (languageSupportEnglishText === "") languageSupportEnglishText = "Отсутствует";
                    else languageSupportEnglishClass = 'catalog-language-yes';
                }

                const reviewClass = getReviewClassCatalog(data.percent_positive, data.review_count);
                const earlyAccessClass = data.is_early_access ? 'catalog-early-access-yes' : 'catalog-early-access-no';
                const tags = await getTagNames(data.tagids || []);
                const tagsHtml = tags.map(tag =>
                    `<div class="custom-tag">${tag}</div>`
                ).join('');

                tooltipContent.innerHTML = `
                    <div style="margin-bottom: 0px;"><strong>Издатели:</strong> <span class="${!data.publishers ? 'catalog-no-reviews' : ''}">${data.publishers || "Нет данных"}</span></div>
                    <div style="margin-bottom: 0px;"><strong>Разработчики:</strong> <span class="${!data.developers ? 'catalog-no-reviews' : ''}">${data.developers || "Нет данных"}</span></div>
                    <div style="margin-bottom: 10px;"><strong>Серия игр:</strong> <span class="${!data.franchises ? 'catalog-no-reviews' : ''}">${data.franchises || "Нет данных"}</span></div>
                    <div style="margin-bottom: 10px;"><strong>Отзывы: </strong><span id="reviewCount">${data.review_count || "0"} </span><span class="${reviewClass}">(${data.percent_positive || "0"}% положительных)</span></div>
                    <div style="margin-bottom: 10px;"><strong>Ранний доступ:</strong> <span class="${earlyAccessClass}">${data.is_early_access ? "Да" : "Нет"}</span></div>
                    <div style="margin-bottom: 10px;"><strong>Русский язык:</strong> <span class="${languageSupportRussianClass}">${languageSupportRussianText}</span></div>
                    ${scriptsConfig.toggleEnglishLangInfo ? `<div style="margin-bottom: 10px;"><strong>Английский язык:</strong> <span class="${languageSupportEnglishClass}">${languageSupportEnglishText}</span></div>` : ''}
                    <div style="margin-bottom: 10px;"><strong>Метки:</strong><br>
                    <div class="custom-tags-container">${tagsHtml}</div></div>
                    <div style="margin-bottom: 10px;"><strong>Описание:</strong> <span class="${!data.short_description ? 'catalog-no-reviews' : ''}">${data.short_description || "Нет данных"}</span></div>
                `;

                ATTILA_tooltip.style.display = 'block';

                const rect = element.getBoundingClientRect();
                const tooltipRect = ATTILA_tooltip.getBoundingClientRect();
                ATTILA_tooltip.style.left = `${rect.left + window.scrollX - tooltipRect.width - 4}px`;
                ATTILA_tooltip.style.top = `${rect.top + window.scrollY - 20}px`;

                ATTILA_tooltip.style.opacity = 0;
                ATTILA_tooltip.style.display = 'block';
                setTimeout(() => {
                    ATTILA_tooltip.style.opacity = 1;
                }, 10);

                element.addEventListener('mouseleave', () => {
                    clearTimeout(TAMERLAN_hideTimer);
                    TAMERLAN_hideTimer = setTimeout(() => {
                        ATTILA_tooltip.style.opacity = 0;
                        setTimeout(() => {
                            ATTILA_tooltip.style.display = 'none';
                        }, 300);
                    }, 200);
                }, {
                    once: true
                });

                element.addEventListener('mouseover', () => {
                    clearTimeout(TAMERLAN_hideTimer);
                });
            }

            function createRussianLanguageFilterBlock() {
                const filterBlock = document.createElement('div');
                filterBlock.className = 'block search_collapse_block';
                filterBlock.innerHTML = `
                    <div data-panel="{&quot;focusable&quot;:true,&quot;clickOnActivate&quot;:true}" class="block_header labs_block_header">
                        <div>Русский перевод</div>
                    </div>
                    <div class="block_content block_content_inner">
                        <div class="tab_filter_control_row" data-param="russian_translation" data-value="__toggle" data-loc="Только текст" data-clientside="0">
                            <span data-panel="{&quot;focusable&quot;:true,&quot;clickOnActivate&quot;:true}" class="tab_filter_control tab_filter_control_include" data-param="russian_translation" data-value="__toggle" data-loc="Только текст" data-clientside="0" data-gpfocus="item">
                                <span>
                                    <span class="tab_filter_control_checkbox"></span>
                                    <span class="tab_filter_control_label">Только текст</span>
                                    <span class="tab_filter_control_count" style="display: none;"></span>
                                </span>
                            </span>
                        </div>
                        <div class="tab_filter_control_row" data-param="russian_voice" data-value="__toggle" data-loc="Озвучка" data-clientside="0">
                            <span data-panel="{&quot;focusable&quot;:true,&quot;clickOnActivate&quot;:true}" class="tab_filter_control tab_filter_control_include" data-param="russian_voice" data-value="__toggle" data-loc="Озвучка" data-clientside="0" data-gpfocus="item">
                                <span>
                                    <span class="tab_filter_control_checkbox"></span>
                                    <span class="tab_filter_control_label">Озвучка</span>
                                    <span class="tab_filter_control_count" style="display: none;"></span>
                                </span>
                            </span>
                        </div>
                        <div class="tab_filter_control_row" data-param="no_russian" data-value="__toggle" data-loc="Без перевода" data-clientside="0">
                            <span data-panel="{&quot;focusable&quot;:true,&quot;clickOnActivate&quot;:true}" class="tab_filter_control tab_filter_control_include" data-param="no_russian" data-value="__toggle" data-loc="Без перевода" data-clientside="0" data-gpfocus="item">
                                <span>
                                    <span class="tab_filter_control_checkbox"></span>
                                    <span class="tab_filter_control_label">Без перевода</span>
                                    <span class="tab_filter_control_count" style="display: none;"></span>
                                </span>
                            </span>
                        </div>
                    </div>
                `;

                const dlcFilterBlock = document.createElement('div');
                dlcFilterBlock.className = 'block search_collapse_block';
                dlcFilterBlock.innerHTML = `
                    <div data-panel="{&quot;focusable&quot;:true,&quot;clickOnActivate&quot;:true}" class="block_header labs_block_header">
                        <div>DLC</div>
                    </div>
                    <div class="block_content block_content_inner">
                        <div class="tab_filter_control_row" data-param="your_dlc" data-value="__toggle" data-loc="Только ваши DLC" data-clientside="0">
                            <span data-panel="{&quot;focusable&quot;:true,&quot;clickOnActivate&quot;:true}" class="tab_filter_control tab_filter_control_include" data-param="your_dlc" data-value="__toggle" data-loc="Только ваши DLC" data-clientside="0" data-gpfocus="item">
                                <span>
                                    <span class="tab_filter_control_checkbox"></span>
                                    <span class="tab_filter_control_label">Только ваши DLC</span>
                                    <span class="tab_filter_control_count" style="display: none;"></span>
                                </span>
                            </span>
                        </div>
                    </div>
                `;

                const priceBlock = document.querySelector('.block.search_collapse_block[data-collapse-name="price"]');
                priceBlock.parentNode.insertBefore(filterBlock, priceBlock.nextSibling);
                priceBlock.parentNode.insertBefore(dlcFilterBlock, filterBlock.nextSibling);

                const translationRow = filterBlock.querySelector('[data-param="russian_translation"]');
                const voiceRow = filterBlock.querySelector('[data-param="russian_voice"]');
                const noRussianRow = filterBlock.querySelector('[data-param="no_russian"]');
                const dlcRow = dlcFilterBlock.querySelector('[data-param="your_dlc"]');

                [translationRow, voiceRow, noRussianRow].forEach(row => {
                    row.addEventListener('click', () => {
                        const control = row.querySelector('.tab_filter_control');
                        const wasChecked = control.classList.contains('checked');

                        [translationRow, voiceRow, noRussianRow].forEach(r => {
                            r.querySelector('.tab_filter_control').classList.remove('checked');
                            r.classList.remove('checked');
                        });

                        if (!wasChecked) {
                            control.classList.add('checked');
                            row.classList.add('checked');
                        }

                        document.querySelectorAll(CAESAR_VISIBLE_ELEMENTS_SELECTOR).forEach(gameElement => {
                            applyRussianLanguageFilter(gameElement);
                        });
                    });
                });

                dlcRow.addEventListener('click', () => {
                    const control = dlcRow.querySelector('.tab_filter_control');
                    const isChecked = !control.classList.contains('checked');

                    control.classList.toggle('checked');
                    dlcRow.classList.toggle('checked');

                    document.querySelectorAll(CAESAR_VISIBLE_ELEMENTS_SELECTOR).forEach(gameElement => {
                        applyDlcFilter(gameElement, isChecked);
                    });
                });
            }

            function applyDlcFilter(gameElement, showOnlyDlc) {
                if (!gameElement.dataset.gameInfo) return;

                const gameData = JSON.parse(gameElement.dataset.gameInfo);
                const isDlcForOwnedGame = gameElement.classList.contains('es_highlighted_dlcforya');

                if (showOnlyDlc) {
                    if (!isDlcForOwnedGame) {
                        animateDisappearance(gameElement);
                    } else {
                        animateAppearance(gameElement);
                    }
                } else {
                    animateAppearance(gameElement);
                }
            }

            function applyRussianLanguageFilter(gameElement) {
                if (!gameElement.dataset.gameInfo) return;

                const gameData = JSON.parse(gameElement.dataset.gameInfo);
                const hasRussianText = gameData.language_support_russian?.supported || gameData.language_support_russian?.subtitles;
                const hasRussianVoice = gameData.language_support_russian?.full_audio;
                const hasAnyRussian = hasRussianText || hasRussianVoice;

                const translationChecked = document.querySelector('[data-param="russian_translation"] .tab_filter_control').classList.contains('checked');
                const voiceChecked = document.querySelector('[data-param="russian_voice"] .tab_filter_control').classList.contains('checked');
                const noRussianChecked = document.querySelector('[data-param="no_russian"] .tab_filter_control').classList.contains('checked');
                const dlcFilterActive = document.querySelector('[data-param="your_dlc"] .tab_filter_control')?.classList.contains('checked');

                if (dlcFilterActive && !gameElement.classList.contains('es_highlighted_dlcforya')) {
                    animateDisappearance(gameElement);
                    return;
                }

                if (translationChecked) {
                    if (!hasRussianText || hasRussianVoice) animateDisappearance(gameElement);
                    else animateAppearance(gameElement);
                } else if (voiceChecked) {
                    if (!hasRussianVoice) animateDisappearance(gameElement);
                    else animateAppearance(gameElement);
                } else if (noRussianChecked) {
                    if (hasAnyRussian) animateDisappearance(gameElement);
                    else animateAppearance(gameElement);
                } else {
                    animateAppearance(gameElement);
                }
            }

            function animateDisappearance(element) {
                element.style.transition = 'opacity 0.5s ease-out, transform 0.5s ease-out';
                element.style.opacity = '0';
                element.style.transform = 'translateX(-100%)';

                setTimeout(() => {
                    element.style.display = 'none';
                }, 500);
            }

            function animateAppearance(element) {
                element.style.display = 'block';
                element.style.opacity = '0';
                element.style.transform = 'translateX(-100%)';
                element.style.transition = 'opacity 0.5s ease-in-out, transform 0.5s ease-in-out';

                setTimeout(() => {
                    element.style.opacity = '1';
                    element.style.transform = 'translateX(0)';
                }, 0);

                setTimeout(() => {
                    element.style.transition = '';
                }, 500);
            }

            function observeNewElements() {
                const observer = new MutationObserver((mutations) => {
                    mutations.forEach(mutation => {
                        if (mutation.type === 'childList') {
                            collectAndFetchAppIds();
                        }
                    });
                });

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

            function initialize() {
                setTimeout(() => {
                    collectAndFetchAppIds();
                    observeNewElements();
                    document.addEventListener('mouseover', handleHover);
                    createRussianLanguageFilterBlock();
                }, HANNIBAL_WAIT_TIME);
            }

            initialize();

            const style = document.createElement('style');
            style.innerHTML = `
                .custom-tooltip {
                    position: absolute;
                    background: linear-gradient(to bottom, #e3eaef, #c7d5e0);
                    color: #30455a;
                    padding: 12px;
                    border-radius: 0px;
                    box-shadow: 0 0 12px #000;
                    font-size: 12px;
                    max-width: 300px;
                    display: none;
                    z-index: 1000;
                    opacity: 0;
                    transition: opacity 0.4s ease-in-out;
                }
                .tooltip-arrow {
                    position: absolute;
                    right: -9px;
                    top: 32px;
                    width: 0;
                    height: 0;
                    border-top: 10px solid transparent;
                    border-bottom: 10px solid transparent;
                    border-left: 10px solid #E1E8ED;
                }
                .catalog-positive {
                    color: #2B80E9;
                }
                .catalog-mixed {
                    color: #997a00;
                }
                .catalog-negative {
                    color: #E53E3E;
                }
                .catalog-no-reviews {
                    color: #929396;
                }
                .catalog-language-yes {
                    color: #2B80E9;
                }
                .catalog-language-no {
                    color: #E53E3E;
                }
                .catalog-early-access-yes {
                    color: #2B80E9;
                }
                .catalog-early-access-no {
                    color: #929396;
                }
                .search_result_row {
                    transition: opacity 0.5s ease-in-out, transform 0.5s ease-in-out;
                }
                .custom-tags-container {
                    display: flex;
                    flex-wrap: wrap;
                    gap: 3px;
                    margin-top: 6px;
                }
                .custom-tag {
                    background-color: #96a3ae;
                    color: #e3eaef;
                    padding: 0 4px;
                    border-radius: 2px;
                    font-size: 11px;
                    line-height: 19px;
                    white-space: nowrap;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    max-width: 200px;
                    box-shadow: none;
                    margin-bottom: 3px;
                }
                .es_highlighted_dlcforya {
                    background: #822dbf linear-gradient(135deg, rgba(0, 0, 0, 0.70) 10%, rgba(0, 0, 0, 0) 100%) !important;
                }
            `;
            document.head.appendChild(style);
        })();
    }

    // Скрипт скрытия игр на странице поиска по каталогу | https://store.steampowered.com/search/
    if (scriptsConfig.catalogHider && unsafeWindow.location.pathname.includes('/search')) {
        (function() {
            "use strict";

            function addBeetles() {
                const scarabLinks = document.querySelectorAll("a.search_result_row:not(.ds_ignored):not(.ds_excluded_by_preferences):not(.ds_wishlist):not(.ds_owned)");
                scarabLinks.forEach(link => {
                    if (link.querySelector(".my-checkbox")) return;
                    const ladybug = document.createElement("input");
                    ladybug.type = "checkbox";
                    ladybug.className = "my-checkbox";
                    ladybug.dataset.aphid = link.dataset.dsAppid;
                    link.insertBefore(ladybug, link.firstChild);

                    ladybug.addEventListener("change", function() {
                        link.style.background = this.checked ? "linear-gradient(to bottom, #381616, #5d1414)" : "";
                    });
                });
            }

            function hideSelectedCrickets() {
                const checkedLadybugs = document.querySelectorAll(".my-checkbox:checked");
                const sessionID = typeof unsafeWindow !== 'undefined' ? unsafeWindow.g_sessionID : window.g_sessionID;

                if (!sessionID) {
                    console.error('[CatalogHider] Не удалось получить g_sessionID!');
                    alert('Не удалось получить ID сессии для скрытия игр. Пожалуйста, убедитесь, что вы авторизованы.');
                    return;
                }

                checkedLadybugs.forEach(ladybug => {
                    const aphid = ladybug.dataset.aphid;
                    const link = document.querySelector(`a[data-ds-appid="${aphid}"]`);
                    if (link) {
                        link.classList.add("ds_ignored", "ds_flagged");
                        ladybug.remove();

                        GM_xmlhttpRequest({
                            method: "POST",
                            url: "https://store.steampowered.com/recommended/ignorerecommendation/",
                            data: `sessionid=${sessionID}&appid=${aphid}&remove=0&snr=1_account_notinterested_`,
                            headers: { "Content-Type": "application/x-www-form-urlencoded" },
                            onload: function(response) {
                                console.log(`[CatalogHider] Игра с appid ${aphid} добавлена в список игнорируемого.`);
                                if (typeof unsafeWindow !== 'undefined' && unsafeWindow.GDynamicStore) {
                                    unsafeWindow.GDynamicStore.InvalidateCache();
                                }
                            },
                            onerror: function(error) {
                                console.error(`[CatalogHider] Ошибка при скрытии игры ${aphid}:`, error);
                            }
                        });
                    }
                });
                setTimeout(updateAntCounter, 500);
            }

            function removeIgnoredDragonflies() {
                const ignoredGames = document.querySelectorAll("a.search_result_row.ds_ignored, a.search_result_row.ds_excluded_by_preferences,a.search_result_row.ds_wishlist");
                ignoredGames.forEach(game => game.remove());
                updateAntCounter();
            }

            function updateAntCounter() {
                const scarabLinks = document.querySelectorAll("a.search_result_row:not(.ds_ignored):not(.ds_excluded_by_preferences):not(.ds_wishlist):not(.ds_owned)");
                const termiteElement = document.querySelector(".game-counter");
                if (termiteElement) {
                    termiteElement.textContent = `Игр осталось: ${scarabLinks.length}`;
                }
            }

            const grasshopperButton = document.createElement("button");
            grasshopperButton.textContent = "Скрыть выбранное";
            grasshopperButton.addEventListener("click", hideSelectedCrickets);
            grasshopperButton.classList.add("my-button", "floating-button");
            document.body.appendChild(grasshopperButton);

            const cockroach = document.createElement("div");
            cockroach.textContent = "Игр осталось: 0";
            cockroach.classList.add("game-counter", "floating-button");
            document.body.appendChild(cockroach);



            GM_addStyle(`
            input[type=checkbox].my-checkbox {
            	-webkit-appearance: none;
            	-moz-appearance: none;
            	appearance: none;
            	border: 6px inset rgba(255, 0, 0, 0.8);
            	border-radius: 50%;
            	width: 42px;
            	height: 42px;
            	outline: none;
            	transition: .15s ease-in-out;
            	vertical-align: middle;
            	position: absolute;
            	left: 0px;
            	top: 50%;
            	transform: translateY(-50%);
            	background-color: rgba(0, 0, 0, 0.0);
            	box-shadow: inset 0 0 0 0 rgba(255, 255, 255, 0.5);
            	cursor: pointer;
            	z-index: 9999;
            }

            input[type=checkbox].my-checkbox:checked {
            	background-color: rgba(0, 0, 0, 0.5);
            	border-color: #b71c1c;
            	box-shadow: inset 0 0 0 12px rgba(255, 0, 0, 0.5);
            }

            input[type=checkbox].my-checkbox:after {
            	content: "";
            	display: block;
            	position: absolute;
            	left: 50%;
            	top: 50%;
            	transform: translate(-50%, -50%) scale(0);
            	width: 25px;
            	height: 25px;
            	border-radius: 50%;
            	background-color: rgba(0, 0, 0, 0.9);
            	opacity: 0.9;
            	box-shadow: 0 0 0 0 #b71c1c;
            	transition: transform .15s ease-in-out, box-shadow .15s ease-in-out;
            }

            input[type=checkbox].my-checkbox:checked:after {
            	transform: translate(-50%, -50%) scale(1);
            	box-shadow: 0 0 0 4px #b71c1c;
            }

            .my-button {
            	margin-right: 10px;
            	padding: 10px 20px;
            	border: none;
            	border-radius: 50px;
            	font-size: 16px;
            	font-weight: 700;
            	color: #fff;
            	background: linear-gradient(to right, #16202D, #1B2838);
            	box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
            	cursor: pointer;
            	font-family: "Roboto", sans-serif;
            	margin-top: 245px;
            }

            .my-button:hover {
            	background: linear-gradient(to right, #0072ff, #00c6ff);
            	box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.3);
            }

            .floating-button {
            	position: fixed;
            	top: -189px;
            	left: 240px;
            	z-index: 1000;
            }

            .game-counter {
            	margin-right: 10px;
            	padding: 10px 20px;
            	border: none;
            	border-radius: 50px;
            	font-size: 16px;
            	font-weight: 700;
            	color: #fff;
            	background: linear-gradient(to right, #16202D, #1B2838);
            	box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
            	font-family: "Roboto", sans-serif;
            	margin-top: 195px;
            }
    `);

            const butterflyObserver = new MutationObserver(mutations => {
                mutations.forEach(mutation => {
                    if (mutation.type === "childList" && mutation.addedNodes.length) {
                        addBeetles();
                        removeIgnoredDragonflies();
                        updateAntCounter();
                    }
                });
            });

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

            addBeetles();
            removeIgnoredDragonflies();
            updateAntCounter();
        })();
    }

    // Скрипт для скрытия новостей в новостном центре: | https://store.steampowered.com/news/
    if (scriptsConfig.newsFilter && unsafeWindow.location.pathname.includes('/news')) {
        (function() {
            'use strict';

            function runNewsMigration() {
                const OLD_STORAGE_KEY = 'hiddenNews';
                const NEW_STORAGE_KEY = 'use_hiddenNewsData_v4';

                const oldDataRaw = localStorage.getItem(OLD_STORAGE_KEY);

                if (!oldDataRaw) {
                    return;
                }

                try {
                    const oldData = JSON.parse(oldDataRaw);
                    if (!Array.isArray(oldData) || oldData.length === 0) {
                        localStorage.removeItem(OLD_STORAGE_KEY);
                        return;
                    }

                    const newData = GM_getValue(NEW_STORAGE_KEY, []);
                    const existingNewIds = new Set(newData.map(item => item.id));
                    const itemsToMigrate = [];

                    for (const oldItem of oldData) {
                        if (!oldItem.link || !oldItem.title) continue;

                        const match = oldItem.link.match(/\/app\/(\d+)\/view\/(\d+)/);
                        if (match && match[1] && match[2]) {
                            const appID = match[1];
                            const newsID = match[2];

                            if (!existingNewIds.has(newsID)) {
                                const newItem = {
                                    id: newsID,
                                    appID: appID,
                                    gameName: "[N/A; 1.9.5]",
                                    newsTitle: oldItem.title,
                                    dateHidden: new Date(oldItem.date).getTime() || Date.now()
                                };
                                itemsToMigrate.push(newItem);
                                existingNewIds.add(newsID);
                            }
                        }
                    }

                    if (itemsToMigrate.length > 0) {
                        const finalData = [...newData, ...itemsToMigrate];
                        GM_setValue(NEW_STORAGE_KEY, finalData);
                    }

                    localStorage.removeItem(OLD_STORAGE_KEY);

                } catch (e) {
                    localStorage.removeItem(OLD_STORAGE_KEY);
                }
            }
            runNewsMigration();

            const HIDDEN_NEWS_GM_KEY = 'use_hiddenNewsData_v4';
            const NEWS_ITEM_SELECTOR = '._398u23KF15gxmeH741ZSyL';
            const NEWS_APP_AREA_SELECTOR = '._3-0KOhYVQX2zIP3z-jCAdu';
            const NEWS_APP_NAME_SELECTOR = '._71phFKOzg8aQlBU1rCA2T';
            const NEWS_LINK_SELECTOR = 'a.Focusable[href^="/news/app/"]';
            const NEWS_TITLE_SELECTOR = '._1M8-Pa3b3WboayCgd5VBJT';
            const NEWS_IMAGE_CONTAINER_SELECTOR = '._3HF9tOy_soo1B_odf1XArk';
            const NEWS_IMAGE_CONTAINER_FALLBACK_SELECTOR = '._2A8sQ35o5MKE0P2B9C0bAn';
            let lastHiddenItems = [];

            GM_addStyle(`
                .use-newsfilter-checkbox-area {
                	position: absolute;
                	top: 0;
                	right: 0;
                	width: 90px;
                	height: 100%;
                	display: flex;
                	align-items: center;
                	justify-content: center;
                	cursor: pointer;
                	z-index: 10;
                	-webkit-tap-highlight-color: transparent;
                }

                .use-newsfilter-checkbox {
                	appearance: none;
                	-webkit-appearance: none;
                	width: 46px;
                	height: 46px;
                	border: 3px solid rgba(102, 192, 244, 0.6);
                	border-radius: 5px;
                	background-color: rgba(27, 40, 56, 0.5);
                	cursor: pointer;
                	transition: all 0.2s ease-in-out;
                	opacity: 0.5;
                	pointer-events: none;
                	display: flex;
                	align-items: center;
                	justify-content: center;
                }

                .use-newsfilter-checkbox-area:hover .use-newsfilter-checkbox {
                	opacity: 1;
                	border-color: #ade0ff;
                	background-color: rgba(27, 40, 56, 0.75);
                }

                .use-newsfilter-checkbox:checked {
                	background-color: rgba(102, 192, 244, 1);
                	border-color: #e1e8ed;
                	opacity: 1;
                }

                .use-newsfilter-checkbox:checked::before {
                	content: '✔';
                	color: #0a121c;
                	font-size: 30px;
                	font-weight: bold;
                }

                .use-newsfilter-newsitem-selected {
                	opacity: 0.45;
                	transition: opacity 0.25s ease-in-out;
                }

                .use-newsfilter-newsitem-selected:hover {
                	opacity: 0.75;
                }

                .use-newsfilter-newsitem-persistently-hidden {
                	opacity: 0.25 !important;
                	border: 1px dashed #4a5562;
                	transition: opacity 0.3s, border 0.3s;
                }

                .use-newsfilter-controls-container {
                	position: fixed;
                	top: 20px;
                	right: 15px;
                	background: rgba(20, 23, 28, 0.92);
                	backdrop-filter: blur(4px);
                	-webkit-backdrop-filter: blur(4px);
                	padding: 8px;
                	border-radius: 4px;
                	z-index: 10001;
                	display: flex;
                	flex-direction: column;
                	gap: 6px;
                	width: 200px;
                }

                .use-newsfilter-button {
                	padding: 7px 12px;
                	background-color: #58a6ff;
                	color: #0d1117;
                	border: none;
                	border-radius: 3px;
                	cursor: pointer;
                	font-size: 13px;
                	font-weight: 500;
                	transition: background-color 0.2s, transform 0.1s;
                	width: 100%;
                	text-align: center;
                	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
                }

                .use-newsfilter-button:hover:not(:disabled) {
                	background-color: #79bbff;
                	transform: translateY(-1px);
                }

                .use-newsfilter-button:active:not(:disabled) {
                	transform: translateY(0px);
                	background-color: #4a90e2;
                }

                .use-newsfilter-button:disabled {
                	background-color: #30363d;
                	color: #6a737d;
                	cursor: not-allowed;
                	box-shadow: none;
                }

                .use-newsfilter-storage-count {
                	color: #99a1a8;
                	font-size: 11px;
                	margin-top: 2px;
                	text-align: center;
                }

                #use-newsfilter-confirm-hide-button:not(:disabled) {
                	background-color: #d9534f;
                	color: white;
                }

                #use-newsfilter-confirm-hide-button:not(:disabled):hover {
                	background-color: #c9302c;
                }

                #use-newsfilter-confirm-hide-button:not(:disabled):active {
                	background-color: #ac2925;
                }

                #use-newsfilter-undo-button {
                	background-color: #f0ad4e;
                	color: #0d1117;
                }

                #use-newsfilter-undo-button:hover:not(:disabled) {
                	background-color: #ec971f;
                }

                #use-newsfilter-manage-panel {
                	position: fixed;
                	top: 50%;
                	left: 50%;
                	transform: translate(-50%, -50%);
                	width: 90%;
                	max-width: 650px;
                	max-height: 75vh;
                	background-color: #171a21;
                	border: 1px solid #4a5562;
                	border-radius: 4px;
                	box-shadow: 0 4px 20px rgba(0, 0, 0, 0.6);
                	z-index: 10002;
                	padding: 15px;
                	display: none;
                	flex-direction: column;
                	color: #c6d4df;
                }

                #use-newsfilter-manage-panel h3 {
                	margin-top: 0;
                	margin-bottom: 10px;
                	color: #67c1f5;
                	text-align: center;
                	font-size: 16px;
                }

                #use-newsfilter-hidden-list {
                	list-style: none;
                	padding: 0;
                	margin: 10px 0;
                	overflow-y: auto;
                	flex-grow: 1;
                	background: rgba(0, 0, 0, 0.15);
                	border-radius: 3px;
                }

                #use-newsfilter-hidden-list li {
                	padding: 7px 10px;
                	border-bottom: 1px solid #232830;
                	display: flex;
                	justify-content: space-between;
                	align-items: center;
                	font-size: 12px;
                }

                #use-newsfilter-hidden-list li:last-child {
                	border-bottom: none;
                }

                #use-newsfilter-hidden-list li .hidden-item-text {
                	flex-grow: 1;
                	margin-right: 10px;
                	overflow: hidden;
                	text-overflow: ellipsis;
                	white-space: nowrap;
                }

                #use-newsfilter-hidden-list li .hidden-item-text .game-name {
                	color: #67c1f5;
                	font-weight: bold;
                }

                #use-newsfilter-hidden-list li .hidden-item-text .news-title {
                	color: #b0b8c0;
                	display: block;
                	font-size: 0.9em;
                	overflow: hidden;
                	text-overflow: ellipsis;
                	white-space: nowrap;
                }

                #use-newsfilter-hidden-list li .hidden-item-text .app-id {
                	color: #76808c;
                	font-size: 0.85em;
                	display: block;
                }

                .use-newsfilter-restore-btn {
                	background-color: #55c655;
                	color: #0d1117;
                	border: none;
                	padding: 3px 7px;
                	font-size: 10px;
                	border-radius: 3px;
                	cursor: pointer;
                	font-weight: 500;
                	flex-shrink: 0;
                }

                .use-newsfilter-restore-btn:hover {
                	background-color: #4CAF50;
                }

                .use-newsfilter-manage-buttons {
                	display: flex;
                	justify-content: space-between;
                	margin-top: 10px;
                	gap: 10px;
                }

                .use-newsfilter-manage-buttons .use-newsfilter-button {
                	font-size: 13px;
                	padding: 7px 12px;
                }

                @keyframes use-newsfilter-fadeout {
                	from {
                		opacity: 1;
                		transform: translateY(0);
                	}

                	to {
                		opacity: 0;
                		transform: translateY(-20px);
                	}
                }

                .use-newsfilter-fading-out {
                	animation: use-newsfilter-fadeout 0.35s forwards ease-out;
                	overflow: hidden;
                }
            `);

            let persistentlyHiddenItems = GM_getValue(HIDDEN_NEWS_GM_KEY, []);
            let showPersistentlyHidden = false;

            function getNewsIdsFromLink(newsItem) {
                const linkElement = newsItem.querySelector(NEWS_LINK_SELECTOR);
                if (linkElement) {
                    const href = linkElement.getAttribute('href');
                    const match = href.match(/\/news\/app\/(\d+)\/view\/(\d+)/);
                    if (match && match[1] && match[2]) {
                        return {
                            appID: match[1],
                            newsID: match[2]
                        };
                    }
                }
                return {
                    appID: null,
                    newsID: null
                };
            }

            function getNewsItemDetails(newsItem) {
                const {
                    appID,
                    newsID
                } = getNewsIdsFromLink(newsItem);
                let gameName = null;
                let newsTitle = newsItem.querySelector(NEWS_TITLE_SELECTOR) ?.textContent.trim() || 'Без заголовка';
                const appArea = newsItem.querySelector(NEWS_APP_AREA_SELECTOR);
                if (appArea) {
                    gameName = appArea.querySelector(NEWS_APP_NAME_SELECTOR) ?.textContent.trim() || null;
                }
                return {
                    appID,
                    newsID,
                    gameName,
                    newsTitle
                };
            }

            function addNewsCheckboxes(newsItems) {
                newsItems.forEach(item => {
                    const {
                        newsID
                    } = getNewsItemDetails(item);
                    const hasExistingCheckboxArea = item.querySelector('.use-newsfilter-checkbox-area');
                    if (newsID && !hasExistingCheckboxArea) {
                        const checkboxArea = document.createElement('div');
                        checkboxArea.className = 'use-newsfilter-checkbox-area';
                        checkboxArea.title = 'Отметить для скрытия';
                        const checkbox = document.createElement('input');
                        checkbox.type = 'checkbox';
                        checkbox.className = 'use-newsfilter-checkbox';
                        checkbox.dataset.newsId = newsID;
                        checkboxArea.appendChild(checkbox);
                        checkboxArea.addEventListener('click', (event) => {
                            event.preventDefault();
                            event.stopPropagation();
                            checkbox.checked = !checkbox.checked;
                            toggleTemporaryHide(item, checkbox.checked);
                        });
                        const imageContainer = item.querySelector(NEWS_IMAGE_CONTAINER_SELECTOR) || item.querySelector(NEWS_IMAGE_CONTAINER_FALLBACK_SELECTOR) || item;
                        if (imageContainer) {
                            if (getComputedStyle(imageContainer).position === 'static') {
                                imageContainer.style.position = 'relative';
                            }
                            imageContainer.appendChild(checkboxArea);
                        }
                        if (persistentlyHiddenItems.some(hidden => hidden.id === newsID)) {
                            applyPersistentHideStyle(item, newsID);
                            checkboxArea.style.display = 'none';
                        }
                    } else if (newsID && hasExistingCheckboxArea) {
                        if (persistentlyHiddenItems.some(hidden => hidden.id === newsID)) {
                            applyPersistentHideStyle(item, newsID);
                            hasExistingCheckboxArea.style.display = 'none';
                        } else {
                            hasExistingCheckboxArea.style.display = 'flex';
                            applyPersistentHideStyle(item, newsID);
                        }
                    }
                });
            }

            function toggleTemporaryHide(newsItem, shouldHide) {
                if (shouldHide) {
                    newsItem.classList.add('use-newsfilter-newsitem-selected');
                } else {
                    newsItem.classList.remove('use-newsfilter-newsitem-selected');
                }
                updateSelectedCount();
            }

            function updateSelectedCount() {
                const selectedItems = document.querySelectorAll(`${NEWS_ITEM_SELECTOR}.use-newsfilter-newsitem-selected`);
                const confirmButton = document.getElementById('use-newsfilter-confirm-hide-button');
                if (confirmButton) {
                    confirmButton.disabled = selectedItems.length === 0;
                    confirmButton.textContent = `Скрыть выбранные (${selectedItems.length})`;
                }
            }

            function updatePersistentHiddenCountDisplay() {
                const countElement = document.getElementById('use-newsfilter-storage-count-span');
                if (countElement) {
                    countElement.textContent = persistentlyHiddenItems.length;
                }
            }

            function createControls() {
                if (document.getElementById('use-newsfilter-controls-container')) return;
                const controlsContainer = document.createElement('div');
                controlsContainer.id = 'use-newsfilter-controls-container';
                controlsContainer.className = 'use-newsfilter-controls-container';
                const confirmHideButton = document.createElement('button');
                confirmHideButton.id = 'use-newsfilter-confirm-hide-button';
                confirmHideButton.className = 'use-newsfilter-button';
                confirmHideButton.textContent = 'Скрыть выбранные (0)';
                confirmHideButton.disabled = true;
                confirmHideButton.title = 'Переместить выбранные новости в список постоянно скрытых';
                confirmHideButton.onclick = confirmAndHideSelectedNews;
                const storageCountDisplay = document.createElement('div');
                storageCountDisplay.className = 'use-newsfilter-storage-count';
                storageCountDisplay.innerHTML = `В хранилище: <span id="use-newsfilter-storage-count-span">${persistentlyHiddenItems.length}</span>`;
                controlsContainer.appendChild(storageCountDisplay);
                const undoButton = document.createElement('button');
                undoButton.id = 'use-newsfilter-undo-button';
                undoButton.className = 'use-newsfilter-button';
                undoButton.textContent = 'Отменить';
                undoButton.style.display = 'none';
                undoButton.title = 'Отменить последнее подтвержденное скрытие';
                undoButton.onclick = undoLastPersistentHide;
                controlsContainer.appendChild(undoButton);
                const togglePersistentlyHiddenButton = document.createElement('button');
                togglePersistentlyHiddenButton.id = 'use-newsfilter-toggle-persistent-button';
                togglePersistentlyHiddenButton.className = 'use-newsfilter-button';
                togglePersistentlyHiddenButton.textContent = showPersistentlyHidden ? 'Спрятать скрытое' : 'Показать скрытое';
                togglePersistentlyHiddenButton.title = 'Показать/скрыть новости из списка постоянно скрытых';
                togglePersistentlyHiddenButton.onclick = toggleShowPersistentlyHidden;
                controlsContainer.appendChild(togglePersistentlyHiddenButton);
                const manageHiddenButton = document.createElement('button');
                manageHiddenButton.id = 'use-newsfilter-manage-button';
                manageHiddenButton.className = 'use-newsfilter-button';
                manageHiddenButton.textContent = 'Хранилище';
                manageHiddenButton.title = 'Просмотреть и восстановить скрытые новости';
                manageHiddenButton.onclick = showManageHiddenPanel;
                controlsContainer.appendChild(manageHiddenButton);
                controlsContainer.appendChild(confirmHideButton);
                document.body.appendChild(controlsContainer);
                createManageHiddenPanel();
            }

            function confirmAndHideSelectedNews() {
                const selectedItems = document.querySelectorAll(`${NEWS_ITEM_SELECTOR}.use-newsfilter-newsitem-selected`);
                if (selectedItems.length === 0) return;
                lastHiddenItems = [];
                const itemsToHideDetails = [];
                selectedItems.forEach(item => {
                    const {
                        appID,
                        newsID,
                        gameName,
                        newsTitle
                    } = getNewsItemDetails(item);
                    if (newsID && !persistentlyHiddenItems.some(h => h.id === newsID)) {
                        const newItemData = {
                            id: newsID,
                            appID: appID,
                            gameName: gameName || "Неизвестная игра",
                            newsTitle: newsTitle,
                            dateHidden: Date.now()
                        };
                        itemsToHideDetails.push(newItemData);
                    }
                    item.classList.add('use-newsfilter-fading-out');
                    item.classList.remove('use-newsfilter-newsitem-selected');
                    const checkboxArea = item.querySelector('.use-newsfilter-checkbox-area');
                    if (checkboxArea) checkboxArea.style.display = 'none';
                    setTimeout(() => {
                        applyPersistentHideStyle(item, newsID);
                        item.classList.remove('use-newsfilter-fading-out');
                    }, 350);
                });
                if (itemsToHideDetails.length > 0) {
                    const newPersistentItems = itemsToHideDetails.filter(newItem =>
                        !persistentlyHiddenItems.some(existingItem => existingItem.id === newItem.id)
                    );
                    persistentlyHiddenItems.push(...newPersistentItems);
                    lastHiddenItems = newPersistentItems;
                    GM_setValue(HIDDEN_NEWS_GM_KEY, persistentlyHiddenItems);
                    updatePersistentHiddenCountDisplay();
                }
                updateSelectedCount();
                const undoButton = document.getElementById('use-newsfilter-undo-button');
                if (undoButton && lastHiddenItems.length > 0) {
                    undoButton.style.display = 'block';
                    setTimeout(() => {
                        undoButton.style.display = 'none';
                    }, 6000);
                }
            }

            function undoLastPersistentHide() {
                if (lastHiddenItems.length === 0) return;
                const idsToRestore = lastHiddenItems.map(item => item.id);
                persistentlyHiddenItems = persistentlyHiddenItems.filter(item => !idsToRestore.includes(item.id));
                GM_setValue(HIDDEN_NEWS_GM_KEY, persistentlyHiddenItems);
                updatePersistentHiddenCountDisplay();
                document.querySelectorAll(NEWS_ITEM_SELECTOR).forEach(itemOnPage => {
                    const {
                        newsID
                    } = getNewsIdsFromLink(itemOnPage);
                    if (newsID && idsToRestore.includes(newsID)) {
                        itemOnPage.style.display = '';
                        itemOnPage.classList.remove('use-newsfilter-newsitem-persistently-hidden', 'use-newsfilter-fading-out');
                        const checkboxArea = itemOnPage.querySelector('.use-newsfilter-checkbox-area');
                        if (checkboxArea) checkboxArea.style.display = 'flex';
                        const checkbox = itemOnPage.querySelector('.use-newsfilter-checkbox');
                        if (checkbox) checkbox.checked = false;
                        toggleTemporaryHide(itemOnPage, false);
                    }
                });
                lastHiddenItems = [];
                document.getElementById('use-newsfilter-undo-button').style.display = 'none';
                if (isManagePanelOpen()) populateHiddenList();
                updateSelectedCount();
            }

            function applyPersistentHideStyle(newsItem, newsID) {
                const isHidden = persistentlyHiddenItems.some(h => h.id === newsID);
                if (isHidden) {
                    newsItem.classList.add('use-newsfilter-newsitem-persistently-hidden');
                    if (!showPersistentlyHidden) {
                        newsItem.style.display = 'none';
                    } else {
                        newsItem.style.display = '';
                    }
                } else {
                    newsItem.classList.remove('use-newsfilter-newsitem-persistently-hidden');
                    newsItem.style.display = '';
                }
            }

            function toggleShowPersistentlyHidden() {
                showPersistentlyHidden = !showPersistentlyHidden;
                const button = document.getElementById('use-newsfilter-toggle-persistent-button');
                if (button) {
                    button.textContent = showPersistentlyHidden ? 'Спрятать скрытое' : 'Показать скрытое';
                }
                document.querySelectorAll(NEWS_ITEM_SELECTOR).forEach(item => {
                    const {
                        newsID
                    } = getNewsIdsFromLink(item);
                    if (newsID) {
                        applyPersistentHideStyle(item, newsID);
                        const checkboxArea = item.querySelector('.use-newsfilter-checkbox-area');
                        if (checkboxArea) {
                            if (persistentlyHiddenItems.some(h => h.id === newsID)) {
                                checkboxArea.style.display = 'none';
                            } else {
                                checkboxArea.style.display = 'flex';
                            }
                        }
                    }
                });
            }

            function applyInitialHide() {
                persistentlyHiddenItems = GM_getValue(HIDDEN_NEWS_GM_KEY, []);
                updatePersistentHiddenCountDisplay();
                const newsItems = document.querySelectorAll(NEWS_ITEM_SELECTOR);
                newsItems.forEach(item => {
                    const {
                        newsID
                    } = getNewsIdsFromLink(item);
                    if (newsID) {
                        applyPersistentHideStyle(item, newsID);
                        const checkboxArea = item.querySelector('.use-newsfilter-checkbox-area');
                        if (checkboxArea) {
                            if (persistentlyHiddenItems.some(h => h.id === newsID)) {
                                checkboxArea.style.display = 'none';
                            } else {
                                checkboxArea.style.display = 'flex';
                            }
                        }
                    }
                });
            }

            function createManageHiddenPanel() {
                if (document.getElementById('use-newsfilter-manage-panel')) return;
                const panel = document.createElement('div');
                panel.id = 'use-newsfilter-manage-panel';
                panel.innerHTML = `
                    <h3>Хранилище скрытых новостей</h3>
                    <p style="font-size:11px; color: #808b96; text-align:center; margin-bottom: 10px;">Новости, ID которых есть в этом списке, не будут отображаться (если не включен режим "Показать скрытое").</p>
                    <ul id="use-newsfilter-hidden-list"></ul>
                    <div class="use-newsfilter-manage-buttons">
                        <button id="use-newsfilter-clear-all-hidden-btn" class="use-newsfilter-button" style="background-color: #c9302c; color: #DCEBF7;">Очистить хранилище</button>
                        <button id="use-newsfilter-close-manage-panel-btn" class="use-newsfilter-button" style="background-color: #4a5562;">Закрыть</button>
                    </div>
                `;
                document.body.appendChild(panel);
                document.getElementById('use-newsfilter-clear-all-hidden-btn').onclick = () => {
                    if (confirm('Вы уверены, что хотите очистить хранилище скрытых новостей? Это действие нельзя будет отменить.')) {
                        clearAllPersistentHiddenNews();
                    }
                };
                document.getElementById('use-newsfilter-close-manage-panel-btn').onclick = hideManageHiddenPanel;
            }

            function showManageHiddenPanel() {
                const panel = document.getElementById('use-newsfilter-manage-panel');
                if (panel) {
                    populateHiddenList();
                    panel.style.display = 'flex';
                }
            }

            function hideManageHiddenPanel() {
                const panel = document.getElementById('use-newsfilter-manage-panel');
                if (panel) {
                    panel.style.display = 'none';
                }
            }

            function isManagePanelOpen() {
                const panel = document.getElementById('use-newsfilter-manage-panel');
                return panel && panel.style.display === 'flex';
            }

            function populateHiddenList() {
                const listElement = document.getElementById('use-newsfilter-hidden-list');
                if (!listElement) return;
                listElement.innerHTML = '';
                if (persistentlyHiddenItems.length === 0) {
                    listElement.innerHTML = '<li style="text-align:center; color:#808b96; padding: 10px;">Хранилище пусто.</li>';
                    return;
                }
                const sortedItems = [...persistentlyHiddenItems].sort((a, b) =>(b.dateHidden || 0) - (a.dateHidden || 0));
                sortedItems.forEach(itemData => {
                    const listItem = document.createElement('li');
                    const textContainer = document.createElement('div');
                    textContainer.className = 'hidden-item-text';
                    const gameNameSpan = document.createElement('span');
                    gameNameSpan.className = 'game-name';
                    gameNameSpan.textContent = itemData.gameName ? `${itemData.gameName}` : 'Игра не указана';
                    const newsTitleSpan = document.createElement('span');
                    newsTitleSpan.className = 'news-title';
                    newsTitleSpan.textContent = itemData.newsTitle || `(Новость без заголовка)`;
                    newsTitleSpan.title = itemData.newsTitle || `Новость для AppID: ${itemData.appID}`;
                    const appIdSpan = document.createElement('span');
                    appIdSpan.className = 'app-id';
                    appIdSpan.textContent = `NewsID: ${itemData.id} (AppID: ${itemData.appID})`;
                    textContainer.appendChild(gameNameSpan);
                    textContainer.appendChild(newsTitleSpan);
                    textContainer.appendChild(appIdSpan);
                    listItem.appendChild(textContainer);
                    const restoreButton = document.createElement('button');
                    restoreButton.className = 'use-newsfilter-restore-btn';
                    restoreButton.textContent = 'Вернуть';
                    restoreButton.title = `Восстановить "${itemData.newsTitle || itemData.id}"`;
                    restoreButton.onclick = () => restoreNewsItem(itemData.id);
                    listItem.appendChild(restoreButton);
                    listElement.appendChild(listItem);
                });
            }

            function restoreNewsItem(newsIDToRestore) {
                persistentlyHiddenItems = persistentlyHiddenItems.filter(item => item.id !== newsIDToRestore);
                GM_setValue(HIDDEN_NEWS_GM_KEY, persistentlyHiddenItems);
                updatePersistentHiddenCountDisplay();
                document.querySelectorAll(NEWS_ITEM_SELECTOR).forEach(itemOnPage => {
                    const {
                        newsID
                    } = getNewsIdsFromLink(itemOnPage);
                    if (newsID === newsIDToRestore) {
                        itemOnPage.style.display = '';
                        itemOnPage.classList.remove('use-newsfilter-newsitem-persistently-hidden');
                        const checkboxArea = itemOnPage.querySelector('.use-newsfilter-checkbox-area');
                        if (checkboxArea) checkboxArea.style.display = 'flex';
                        const checkbox = itemOnPage.querySelector('.use-newsfilter-checkbox');
                        if (checkbox) checkbox.checked = false;
                        toggleTemporaryHide(itemOnPage, false);
                    }
                });
                populateHiddenList();
                updateSelectedCount();
            }

            function clearAllPersistentHiddenNews() {
                persistentlyHiddenItems = [];
                GM_setValue(HIDDEN_NEWS_GM_KEY, []);
                updatePersistentHiddenCountDisplay();
                document.querySelectorAll(NEWS_ITEM_SELECTOR).forEach(item => {
                    item.style.display = '';
                    item.classList.remove('use-newsfilter-newsitem-persistently-hidden', 'use-newsfilter-fading-out');
                    const checkboxArea = item.querySelector('.use-newsfilter-checkbox-area');
                    if (checkboxArea) checkboxArea.style.display = 'flex';
                    const checkbox = item.querySelector('.use-newsfilter-checkbox');
                    if (checkbox) checkbox.checked = false;
                    toggleTemporaryHide(item, false);
                });
                populateHiddenList();
                updateSelectedCount();
            }

            function initNewsFilterEnhanced() {
                applyInitialHide();
                addNewsCheckboxes(document.querySelectorAll(NEWS_ITEM_SELECTOR));
                createControls();
                updateSelectedCount();
            }

            setTimeout(initNewsFilterEnhanced, 1500);

            const newsObserver = new MutationObserver((mutations) => {
                let processNewsItems = false;
                for (const mutation of mutations) {
                    if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                        for (const node of mutation.addedNodes) {
                            if (node.nodeType === Node.ELEMENT_NODE) {
                                processNewsItems = true;
                                break;
                            }
                        }
                    }
                    if (processNewsItems) {
                        break;
                    }
                }
                if (processNewsItems) {
                    setTimeout(() => {
                        const allNewsItems = document.querySelectorAll(NEWS_ITEM_SELECTOR);
                        addNewsCheckboxes(allNewsItems);
                        applyInitialHide();
                    }, 100);
                }
            });

            const newsFeedParentContainer = document.querySelector('div[class*="eventcalendar_EventBlockContainer"]');
            if (newsFeedParentContainer) {
                newsObserver.observe(newsFeedParentContainer, {
                    childList: true,
                    subtree: true
                });
            } else {
                const observeBody = () => newsObserver.observe(document.body, {
                    childList: true,
                    subtree: true
                });
                if (document.readyState === "complete" || document.readyState === "interactive") {
                    observeBody();
                } else {
                    window.addEventListener('DOMContentLoaded', observeBody);
                }
            }
        })();
    }

    // Скрипт для показа годовых и исторических продаж предмета на торговой площадке Steam | https://steamcommunity.com/market/listings/*
    if (scriptsConfig.Kaznachei && unsafeWindow.location.pathname.includes('/market/listings/')) {
        async function fetchSalesInfo() {
            const urlParts = unsafeWindow.location.pathname.split('/');
            const appId = urlParts[3];
            const marketHashName = decodeURIComponent(urlParts[4]);
            const apiUrl = `https://steamcommunity.com/market/pricehistory/?appid=${appId}&market_hash_name=${marketHashName}`;

            try {
                const response = await fetch(apiUrl);
                const data = await response.json();

                if (data.success) {
                    const salesData = data.prices;
                    const yearlySales = {};
                    let totalSales = 0;

                    salesData.forEach(sale => {
                        const date = sale[0];
                        const price = parseFloat(sale[1]);
                        const quantity = parseInt(sale[2]);
                        const year = date.split(' ')[2];

                        const totalForDay = price * quantity;

                        if (!yearlySales[year]) {
                            yearlySales[year] = {
                                total: 0,
                                commission: 0,
                                developerShare: 0,
                                valveShare: 0
                            };
                        }

                        yearlySales[year].total += totalForDay;
                        totalSales += totalForDay;
                    });

                    for (const year in yearlySales) {
                        const commission = yearlySales[year].total * 0.13;
                        const developerShare = commission * 0.6667;
                        const valveShare = commission * 0.3333;

                        yearlySales[year].commission = commission;
                        yearlySales[year].developerShare = developerShare;
                        yearlySales[year].valveShare = valveShare;
                    }

                    displaySalesInfo(yearlySales, totalSales);
                } else {
                    console.error('Не удалось получить информацию о продажах.');
                }
            } catch (error) {
                console.error('Ошибка при получении данных:', error);
            }
        }

        function displaySalesInfo(yearlySales, totalSales) {
            const salesInfoContainer = document.createElement('div');
            salesInfoContainer.style.marginTop = '20px';
            salesInfoContainer.style.padding = '10px';
            salesInfoContainer.style.border = '1px solid #4a4a4a';
            salesInfoContainer.style.backgroundColor = '#1b2838';
            salesInfoContainer.style.borderRadius = '4px';
            salesInfoContainer.style.boxShadow = '0 1px 3px rgba(0, 0, 0, 0.5)';
            salesInfoContainer.style.color = '#c7d5e0';

            const spoilerHeader = document.createElement('div');
            spoilerHeader.style.cursor = 'pointer';
            spoilerHeader.style.padding = '10px';
            spoilerHeader.style.backgroundColor = '#171a21';
            spoilerHeader.style.borderRadius = '4px 4px 0 0';
            spoilerHeader.style.color = '#c7d5e0';
            spoilerHeader.style.fontWeight = 'bold';
            spoilerHeader.style.fontFamily = '"Motiva Sans", sans-serif';
            spoilerHeader.style.fontSize = '16px';
            spoilerHeader.style.display = 'flex';
            spoilerHeader.style.alignItems = 'center';
            spoilerHeader.style.justifyContent = 'space-between';
            spoilerHeader.innerHTML = 'Информация о продажах <span style="font-size: 12px; transform: rotate(0deg); transition: transform 0.3s ease;">&#9660;</span>';

            spoilerHeader.addEventListener('click', () => {
                const content = spoilerHeader.nextElementSibling;
                content.style.display = content.style.display === 'none' ? 'block' : 'none';
                const arrow = spoilerHeader.querySelector('span');
                arrow.style.transform = content.style.display === 'none' ? 'rotate(0deg)' : 'rotate(180deg)';
            });

            const spoilerContent = document.createElement('div');
            spoilerContent.style.display = 'none';
            spoilerContent.style.padding = '10px';
            spoilerContent.style.borderTop = '1px solid #4a4a4a';

            const yearlySalesTable = document.createElement('table');
            yearlySalesTable.style.width = '100%';
            yearlySalesTable.style.borderCollapse = 'collapse';
            yearlySalesTable.style.marginBottom = '20px';
            yearlySalesTable.style.fontFamily = '"Motiva Sans", sans-serif';
            yearlySalesTable.style.fontSize = '14px';

            const yearlySalesHeader = document.createElement('tr');
            yearlySalesHeader.innerHTML = '<th style="padding: 8px; text-align: left; border-bottom: 2px solid #4a4a4a; background-color: #171a21; color: #c7d5e0;">Год</th><th style="padding: 8px; text-align: left; border-bottom: 2px solid #4a4a4a; background-color: #171a21; color: #c7d5e0;">Сумма продаж за год</th><th style="padding: 8px; text-align: left; border-bottom: 2px solid #4a4a4a; background-color: #171a21; color: #c7d5e0;">Ушло разработчику</th><th style="padding: 8px; text-align: left; border-bottom: 2px solid #4a4a4a; background-color: #171a21; color: #c7d5e0;">Ушло Valve</th>';
            yearlySalesTable.appendChild(yearlySalesHeader);

            for (const year in yearlySales) {
                const row = document.createElement('tr');
                row.innerHTML = `<td style="padding: 8px; border-bottom: 1px solid #4a4a4a; background-color: #1b2838; color: #c7d5e0;">${year}</td><td style="padding: 8px; border-bottom: 1px solid #4a4a4a; background-color: #1b2838; color: #c7d5e0;">${yearlySales[year].total.toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} руб.</td><td style="padding: 8px; border-bottom: 1px solid #4a4a4a; background-color: #1b2838; color: #c7d5e0;">${yearlySales[year].developerShare.toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} руб.</td><td style="padding: 8px; border-bottom: 1px solid #4a4a4a; background-color: #1b2838; color: #c7d5e0;">${yearlySales[year].valveShare.toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} руб.</td>`;
                yearlySalesTable.appendChild(row);
            }

            const totalSalesParagraph = document.createElement('p');
            totalSalesParagraph.textContent = `Сумма продаж за всё время: ${totalSales.toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} руб.`;
            totalSalesParagraph.style.fontWeight = 'bold';
            totalSalesParagraph.style.fontSize = '16px';
            totalSalesParagraph.style.color = '#c7d5e0';
            totalSalesParagraph.style.fontFamily = '"Motiva Sans", sans-serif';

            const commission = totalSales * 0.13;
            const developerShare = commission * 0.6667;
            const valveShare = commission * 0.3333;

            const developerShareParagraph = document.createElement('p');
            developerShareParagraph.textContent = `Ушло разработчику: ${developerShare.toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} руб.`;
            developerShareParagraph.style.fontSize = '14px';
            developerShareParagraph.style.color = '#c7d5e0';
            developerShareParagraph.style.fontFamily = '"Motiva Sans", sans-serif';

            const valveShareParagraph = document.createElement('p');
            valveShareParagraph.textContent = `Ушло Valve: ${valveShare.toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} руб.`;
            valveShareParagraph.style.fontSize = '14px';
            valveShareParagraph.style.color = '#c7d5e0';
            valveShareParagraph.style.fontFamily = '"Motiva Sans", sans-serif';

            spoilerContent.appendChild(yearlySalesTable);
            spoilerContent.appendChild(totalSalesParagraph);
            spoilerContent.appendChild(developerShareParagraph);
            spoilerContent.appendChild(valveShareParagraph);

            salesInfoContainer.appendChild(spoilerHeader);
            salesInfoContainer.appendChild(spoilerContent);

            const marketHeaderBg = document.querySelector('.market_header_bg');
            if (marketHeaderBg) {
                marketHeaderBg.parentNode.insertBefore(salesInfoContainer, marketHeaderBg.nextSibling);
            }
        }

        setTimeout(fetchSalesInfo, 100);
    }

    // Скрипт для получения дополнительной информации об игре при наведении на неё на странице вашей активности Steam | https://steamcommunity.com/my/
    if (scriptsConfig.homeInfo && unsafeWindow.location.href.includes('steamcommunity.com') && unsafeWindow.location.pathname.includes('/home')) {
        (function() {
            'use strict';

            const MOREL_API_URL = "https://api.steampowered.com/IStoreBrowseService/GetItems/v1";
            const CHANTERELLE_WAIT_TIME = 2000;
            const PORCINI_VISIBLE_ELEMENTS_SELECTOR = "a[href*='/app/'], a[data-appid]";
            const TRUFFLE_HOVER_ELEMENT_SELECTOR = "a[href*='/app/'], a[data-appid]";

            let SHIITAKE_collectedAppIds = new Set();
            let ENOKI_tooltip = null;
            let MAITAKE_hoverTimer = null;
            let HEN_OF_THE_WOODS_hideTimer = null;

            const MUSHROOM_GAME_DATA = {};

            const STEAM_TAGS_CACHE_KEY = 'SteamEnhancer_TagsCache_v2';
            const STEAM_TAGS_URL = "https://gist.githubusercontent.com/0wn3dg0d/22a351ff4c65e50a9a8af6da360defad/raw/steamrutagsownd.json";

            function fetchGameData(appIds) {
                const inputJson = {
                    ids: Array.from(appIds).map(appid => ({
                        appid
                    })),
                    context: {
                        language: "russian",
                        country_code: "US",
                        steam_realm: 1
                    },
                    data_request: {
                        include_assets: true,
                        include_release: true,
                        include_platforms: true,
                        include_all_purchase_options: true,
                        include_screenshots: true,
                        include_trailers: true,
                        include_ratings: true,
                        include_tag_count: true,
                        include_reviews: true,
                        include_basic_info: true,
                        include_supported_languages: true,
                        include_full_description: true,
                        include_included_items: true,
                        included_item_data_request: {
                            include_assets: true,
                            include_release: true,
                            include_platforms: true,
                            include_all_purchase_options: true,
                            include_screenshots: true,
                            include_trailers: true,
                            include_ratings: true,
                            include_tag_count: true,
                            include_reviews: true,
                            include_basic_info: true,
                            include_supported_languages: true,
                            include_full_description: true,
                            include_included_items: true,
                            include_assets_without_overrides: true,
                            apply_user_filters: false,
                            include_links: true
                        },
                        include_assets_without_overrides: true,
                        apply_user_filters: false,
                        include_links: true
                    }
                };

                GM_xmlhttpRequest({
                    method: "GET",
                    url: `${MOREL_API_URL}?input_json=${encodeURIComponent(JSON.stringify(inputJson))}`,
                    onload: function(response) {
                        const data = JSON.parse(response.responseText);
                        processGameData(data);
                    }
                });
            }

            function processGameData(data) {
                const items = data.response.store_items;
                items.forEach(item => {
                    const appId = item.id;
                    MUSHROOM_GAME_DATA[appId] = {
                        name: item.name,
                        assets: item.assets,
                        is_early_access: item.is_early_access,
                        review_count: item.reviews?.summary_filtered?.review_count,
                        percent_positive: item.reviews?.summary_filtered?.percent_positive,
                        short_description: item.basic_info?.short_description,
                        publishers: item.basic_info?.publishers?.map(p => p.name).join(", "),
                        developers: item.basic_info?.developers?.map(d => d.name).join(", "),
                        franchises: item.basic_info?.franchises?.map(f => f.name).join(", "),
                        tagids: item.tagids || [],
                        language_support_russian: item.supported_languages?.find(lang => lang.elanguage === 8),
                        language_support_english: item.supported_languages?.find(lang => lang.elanguage === 0),
                        release_date: item.release?.steam_release_date ? new Date(item.release.steam_release_date * 1000).toLocaleDateString() : "Нет данных"
                    };
                });
            }

            function collectAndFetchAppIds() {
                const visibleElements = document.querySelectorAll(PORCINI_VISIBLE_ELEMENTS_SELECTOR);
                const newAppIds = new Set();

                visibleElements.forEach(element => {
                    const appId = element.dataset.appid || element.href.match(/app\/(\d+)/)?.[1];
                    if (appId && !SHIITAKE_collectedAppIds.has(appId)) {
                        newAppIds.add(parseInt(appId, 10));
                        SHIITAKE_collectedAppIds.add(appId);
                    }
                });

                if (newAppIds.size > 0) {
                    fetchGameData(newAppIds);
                }
            }

            function handleHover(event) {
                const gameElement = event.target.closest(TRUFFLE_HOVER_ELEMENT_SELECTOR);

                if (gameElement) {
                    const appId = gameElement.dataset.appid || gameElement.href.match(/app\/(\d+)/)?.[1];
                    if (appId && MUSHROOM_GAME_DATA[appId]) {
                        clearTimeout(MAITAKE_hoverTimer);
                        clearTimeout(HEN_OF_THE_WOODS_hideTimer);

                        MAITAKE_hoverTimer = setTimeout(() => {
                            displayGameInfo(gameElement, MUSHROOM_GAME_DATA[appId], appId);
                        }, 300);
                    } else {
                        clearTimeout(MAITAKE_hoverTimer);
                        clearTimeout(HEN_OF_THE_WOODS_hideTimer);
                        if (ENOKI_tooltip) {
                            ENOKI_tooltip.style.opacity = 0;
                            setTimeout(() => {
                                ENOKI_tooltip.style.display = 'none';
                            }, 300);
                        }
                    }
                }
            }

            function getReviewClassCatalog(percent, totalReviews) {
                if (totalReviews === 0) return 'mushroom-no-reviews';
                if (percent >= 70) return 'mushroom-positive';
                if (percent >= 40) return 'mushroom-mixed';
                if (percent >= 1) return 'mushroom-negative';
                return 'mushroom-negative';
            }

            async function loadSteamTags() {
                const cached = GM_getValue(STEAM_TAGS_CACHE_KEY, {
                    data: null,
                    timestamp: 0
                });
                const now = Date.now();
                const CACHE_DURATION = 744 * 60 * 60 * 1000;

                if (cached.data && (now - cached.timestamp) < CACHE_DURATION) {
                    return cached.data;
                }

                try {
                    const response = await new Promise((resolve, reject) => {
                        GM_xmlhttpRequest({
                            method: "GET",
                            url: STEAM_TAGS_URL,
                            onload: resolve,
                            onerror: reject
                        });
                    });

                    if (response.status === 200) {
                        const data = JSON.parse(response.responseText);
                        GM_setValue(STEAM_TAGS_CACHE_KEY, {
                            data: data,
                            timestamp: now
                        });
                        return data;
                    }
                } catch (e) {
                    console.error('Ошибка загрузки тегов:', e);
                    return cached.data || {};
                }

                return {};
            }

            async function displayGameInfo(element, data, appId) {
                if (!ENOKI_tooltip) {
                    ENOKI_tooltip = document.createElement('div');
                    ENOKI_tooltip.className = 'mushroom-tooltip';
                    ENOKI_tooltip.innerHTML = '<div class="tooltip-arrow"></div><div class="tooltip-content"></div>';
                    document.body.appendChild(ENOKI_tooltip);
                }

                const tooltipContent = ENOKI_tooltip.querySelector('.tooltip-content');

                let languageSupportRussianText = "Отсутствует";
                let languageSupportRussianClass = 'mushroom-language-no';
                if (data.language_support_russian) {
                    languageSupportRussianText = "";
                    if (data.language_support_russian.supported) languageSupportRussianText += "<br>Интерфейс: ✔ ";
                    if (data.language_support_russian.full_audio) languageSupportRussianText += "<br>Озвучка: ✔ ";
                    if (data.language_support_russian.subtitles) languageSupportRussianText += "<br>Субтитры: ✔";
                    if (languageSupportRussianText === "") languageSupportRussianText = "Отсутствует";
                    else languageSupportRussianClass = 'mushroom-language-yes';
                }

                let languageSupportEnglishText = "Отсутствует";
                let languageSupportEnglishClass = 'mushroom-language-no';
                if (scriptsConfig.toggleEnglishLangInfo && data.language_support_english) {
                    languageSupportEnglishText = "";
                    if (data.language_support_english.supported) languageSupportEnglishText += "<br>Интерфейс: ✔ ";
                    if (data.language_support_english.full_audio) languageSupportEnglishText += "<br>Озвучка: ✔ ";
                    if (data.language_support_english.subtitles) languageSupportEnglishText += "<br>Субтитры: ✔";
                    if (languageSupportEnglishText === "") languageSupportEnglishText = "Отсутствует";
                    else languageSupportEnglishClass = 'mushroom-language-yes';
                }

                const reviewClass = getReviewClassCatalog(data.percent_positive, data.review_count);
                const earlyAccessClass = data.is_early_access ? 'mushroom-early-access-yes' : 'mushroom-early-access-no';

                const headerUrl = data.assets?.header ? `https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/${appId}/${data.assets.header}` : '';
                const imageHtml = headerUrl ? `<div style="margin-bottom: 10px;"><img src="${headerUrl}" alt="${data.name}" style="width: 50%; height: auto;"></div>` : '';

                async function getTagNames(tagIds) {
                    const tagsData = await loadSteamTags();
                    return tagIds.slice(0, 5).map(tagId =>
                        tagsData[tagId] || `Тег #${tagId}`
                    );
                }

                const tags = await getTagNames(data.tagids || []);
                const tagsHtml = tags.map(tag =>
                    `<div class="mushroom-tag">${tag}</div>`
                ).join('');

                tooltipContent.innerHTML = `
                    <div style="margin-bottom: 10px;"><strong>Название:</strong> ${data.name || "Нет данных"}</div>
                    ${imageHtml}
                    <div style="margin-bottom: 10px;"><strong>Дата выхода:</strong> ${data.release_date}</div>
                    <div style="margin-bottom: 0px;"><strong>Издатели:</strong> <span class="${!data.publishers ? 'mushroom-no-reviews' : ''}">${data.publishers || "Нет данных"}</span></div>
                    <div style="margin-bottom: 0px;"><strong>Разработчики:</strong> <span class="${!data.developers ? 'mushroom-no-reviews' : ''}">${data.developers || "Нет данных"}</span></div>
                    <div style="margin-bottom: 10px;"><strong>Серия игр:</strong> <span class="${!data.franchises ? 'mushroom-no-reviews' : ''}">${data.franchises || "Нет данных"}</span></div>
                    <div style="margin-bottom: 10px;"><strong>Отзывы: </strong><span id="reviewCount">${data.review_count || "0"} </span><span class="${reviewClass}">(${data.percent_positive || "0"}% положительных)</span></div>
                    <div style="margin-bottom: 10px;"><strong>Ранний доступ:</strong> <span class="${earlyAccessClass}">${data.is_early_access ? "Да" : "Нет"}</span></div>
                    <div style="margin-bottom: 10px;"><strong>Русский язык:</strong> <span class="${languageSupportRussianClass}">${languageSupportRussianText}</span></div>
                    ${scriptsConfig.toggleEnglishLangInfo ? `<div style="margin-bottom: 10px;"><strong>Английский язык:</strong> <span class="${languageSupportEnglishClass}">${languageSupportEnglishText}</span></div>` : ''}
                    <div style="margin-bottom: 10px;"><strong>Метки:</strong><br>
                    <div class="mushroom-tags-container">${tagsHtml}</div></div>
                    <div style="margin-bottom: 10px;"><strong>Описание:</strong> <span class="${!data.short_description ? 'mushroom-no-reviews' : ''}">${data.short_description || "Нет данных"}</span></div>
                `;

                ENOKI_tooltip.style.display = 'block';

                const blotterDayElement = document.querySelector('.blotter_day');
                if (blotterDayElement) {
                    const blotterRect = blotterDayElement.getBoundingClientRect();
                    const tooltipRect = ENOKI_tooltip.getBoundingClientRect();

                    ENOKI_tooltip.style.left = `${blotterRect.left - tooltipRect.width - 5}px`;
                    ENOKI_tooltip.style.top = `${element.getBoundingClientRect().top + window.scrollY - 35}px`;
                }

                ENOKI_tooltip.style.opacity = 0;
                ENOKI_tooltip.style.display = 'block';
                setTimeout(() => {
                    ENOKI_tooltip.style.opacity = 1;
                }, 10);

                element.addEventListener('mouseleave', () => {
                    clearTimeout(HEN_OF_THE_WOODS_hideTimer);
                    HEN_OF_THE_WOODS_hideTimer = setTimeout(() => {
                        ENOKI_tooltip.style.opacity = 0;
                        setTimeout(() => {
                            ENOKI_tooltip.style.display = 'none';
                        }, 300);
                    }, 200);
                }, {
                    once: true
                });

                element.addEventListener('mouseover', () => {
                    clearTimeout(HEN_OF_THE_WOODS_hideTimer);
                });
            }

            function observeNewElements() {
                const observer = new MutationObserver((mutations) => {
                    mutations.forEach(mutation => {
                        if (mutation.type === 'childList') {
                            collectAndFetchAppIds();
                        }
                    });
                });

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

            function initialize() {
                setTimeout(() => {
                    collectAndFetchAppIds();
                    observeNewElements();
                    document.addEventListener('mouseover', handleHover);
                }, CHANTERELLE_WAIT_TIME);
            }

            initialize();

            const style = document.createElement('style');
            style.innerHTML = `
                .mushroom-tooltip {
                    position: absolute;
                    background: linear-gradient(to bottom, #e3eaef, #c7d5e0);
                    color: #30455a;
                    padding: 12px;
                    border-radius: 0px;
                    box-shadow: 0 0 12px #000;
                    font-size: 12px;
                    max-width: 300px;
                    display: none;
                    z-index: 1000;
                    opacity: 0;
                    transition: opacity 0.4s ease-in-out;
                }
                .tooltip-arrow {
                    position: absolute;
                    right: -9px;
                    top: 32px;
                    width: 0;
                    height: 0;
                    border-top: 10px solid transparent;
                    border-bottom: 10px solid transparent;
                    border-left: 10px solid #E1E8ED;
                }
                .mushroom-positive {
                    color: #2B80E9;
                }
                .mushroom-mixed {
                    color: #997a00;
                }
                .mushroom-negative {
                    color: #E53E3E;
                }
                .mushroom-no-reviews {
                    color: #929396;
                }
                .mushroom-language-yes {
                    color: #2B80E9;
                }
                .mushroom-language-no {
                    color: #E53E3E;
                }
                .mushroom-early-access-yes {
                    color: #2B80E9;
                }
                .mushroom-early-access-no {
                    color: #929396;
                }
               .mushroom-tags-container {
                   display: flex;
                   flex-wrap: wrap;
                   gap: 3px;
                   margin-top: 6px;
               }
               .mushroom-tag {
                   background-color: #96a3ae;
                   color: #e3eaef;
                   padding: 0 4px;
                   border-radius: 2px;
                   font-size: 11px;
                   line-height: 19px;
                   white-space: nowrap;
                   overflow: hidden;
                   text-overflow: ellipsis;
                   max-width: 200px;
                   box-shadow: none;
                   margin-bottom: 3px;
               }
            `;
            document.head.appendChild(style);
        })();
    }

    //Скрипт для выбора случайной игры из ваших коллекций с помощью Stelicas и рулетки на странице вашей активности Steam | https://steamcommunity.com/my/
    if (scriptsConfig.stelicasRoulette && unsafeWindow.location.href.includes('steamcommunity.com') && unsafeWindow.location.pathname.includes('/home')) {
        (function() {
            'use strict';

            let sr2_games = [];
            let sr2_filteredGames = [];
            let sr2_categories = new Map();
            let sr2_releaseYears = new Map();
            let sr2_tags = new Map();
            let sr2_languageSupportStats = { noRussianOrNoData: 0, subtitlesOrInterfaceOnly: 0, voice: 0 };
            let sr2_spinning = false;
            const SR2_CLONES_COUNT = 7;
            let sr2_modal = null;
            let sr2_currentViewMode = 'roulette';
            let sr2_collectionSelectedGameAppId = null;
            let sr2_toggleViewBtn = null;


            let sr2_activeFilters = {
                categories: ["Все"],
                releaseYears: ["Все"],
                tags: ["Все"],
                language: ["Все"],
                reviewCountMin: null,
                reviewCountMax: null,
                ratingMin: null,
                ratingMax: null
            };

            function sr2_addRouletteBlock() {
                const rightColumn = document.getElementById('friendactivity_right_column');
                const friendsAddBlock = rightColumn ? rightColumn.querySelector('.friends_add_block') : null;

                if (friendsAddBlock && !document.getElementById('sr2_stelicasRouletteBlock')) {
                    const rouletteBlock = document.createElement('div');
                    rouletteBlock.id = 'sr2_stelicasRouletteBlock';
                    rouletteBlock.className = 'friends_add_block panel';
                    rouletteBlock.style.marginTop = '12px';
                    rouletteBlock.style.padding = '10px';

                    const titleDiv = document.createElement('div');
                    titleDiv.className = 'profile_add_friends_title';
                    titleDiv.textContent = 'Рулетка Stelicas';
                    titleDiv.style.marginBottom = '10px';
                    rouletteBlock.appendChild(titleDiv);

                    const rouletteButton = document.createElement('div');
                    rouletteButton.className = 'btn_darkblue_white_innerfade btn_medium_tall';
                    rouletteButton.style.width = '100%';
                    rouletteButton.onclick = sr2_showRouletteModal;

                    const spanInsideButton = document.createElement('span');
                    spanInsideButton.textContent = 'Рулетка Stelicas';
                    rouletteButton.appendChild(spanInsideButton);
                    rouletteBlock.appendChild(rouletteButton);

                    friendsAddBlock.parentNode.insertBefore(rouletteBlock, friendsAddBlock.nextSibling);
                }
            }

            function sr2_showRouletteModal() {
                if (sr2_modal && document.body.contains(sr2_modal)) {
                    sr2_modal.style.display = 'flex';
                    document.body.style.overflow = 'hidden';
                    return;
                }

                sr2_modal = document.createElement('div');
                sr2_modal.id = 'sr2_stelicasRouletteModal';
                sr2_modal.style.cssText = `
                    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
                    background-color: #0D1117; color: #C9D1D9; z-index: 20000;
                    display: flex; flex-direction: column; overflow: hidden;
                    font-family: "Motiva Sans", Arial, sans-serif;
                `;

                const headerPanel = document.createElement('div');
                headerPanel.id = 'sr2_headerPanel';
                headerPanel.innerHTML = `
                    <h2 id="sr2_modalTitle">Рулетка Stelicas</h2>
                    <div id="sr2_headerControls">
                        <button id="sr2_toggleViewBtn" class="sr2_btn sr2_btnIcon" title="Посмотреть подборку" disabled>Посмотреть подборку</button>
                        <button id="sr2_helpBtn" class="sr2_btn sr2_btnIcon" title="Как пользоваться / Репозиторий">?</button>
                        <button id="sr2_closeBtn" class="sr2_btn sr2_btnIcon" title="Закрыть">&times;</button>
                    </div>
                `;
                sr2_modal.appendChild(headerPanel);
                sr2_toggleViewBtn = headerPanel.querySelector('#sr2_toggleViewBtn');


                const mainContainer = document.createElement('div');
                mainContainer.id = 'sr2_mainContainer';

                const leftControlsPanel = document.createElement('div');
                leftControlsPanel.id = 'sr2_leftControlsPanel';
                leftControlsPanel.innerHTML = `
                    <div class="sr2_controlSection">
                        <label for="sr2_csvFileTrigger" class="sr2_label">1. Загрузить данные:</label>
                        <input type="file" id="sr2_csvFile" accept=".csv" style="display:none;">
                        <button id="sr2_csvFileTrigger" class="sr2_btn sr2_btnBlock">Выбрать CSV от Stelicas</button>
                        <span id="sr2_fileNameDisplay" class="sr2_fileName">Файл не выбран</span>
                    </div>

                    <div class="sr2_controlSection">
                        <label class="sr2_label">2. Фильтры:</label>
                        <div class="sr2_filterBlock">
                            <h5 class="sr2_filterTitle">Категории</h5>
                            <div id="sr2_categoryList" class="sr2_filterList" style="max-height: 82px;"></div>
                        </div>
                        <div class="sr2_filterBlock">
                            <h5 class="sr2_filterTitle">Дата выхода</h5>
                            <div id="sr2_releaseYearList" class="sr2_filterList" style="max-height: 82px;"></div>
                        </div>
                        <div class="sr2_filterBlock">
                            <h5 class="sr2_filterTitle">Тэги</h5>
                            <input type="text" id="sr2_tagSearchInput" class="sr2_filterSearchInput" placeholder="Поиск тэга..." style="margin-bottom: 5px;">
                            <div id="sr2_tagList" class="sr2_filterList" style="max-height: 82px;"></div>
                        </div>
                        <div class="sr2_filterBlock">
                            <h5 class="sr2_filterTitle">Русский язык</h5>
                            <div id="sr2_languageList" class="sr2_filterList" style="max-height: 82px;"></div>
                        </div>
                         <div class="sr2_filterBlock">
                            <h5 class="sr2_filterTitle">Количество отзывов</h5>
                            <div class="sr2_inputRange">
                                <input type="number" id="sr2_reviewCountMin" class="sr2_filterInput" placeholder="От">
                                <span class="sr2_inputRangeSeparator">-</span>
                                <input type="number" id="sr2_reviewCountMax" class="sr2_filterInput" placeholder="До">
                            </div>
                        </div>
                        <div class="sr2_filterBlock">
                            <h5 class="sr2_filterTitle">Рейтинг (%)</h5>
                            <div class="sr2_inputRange">
                                <input type="number" id="sr2_ratingMin" class="sr2_filterInput" placeholder="От" min="0" max="100">
                                <span class="sr2_inputRangeSeparator">-</span>
                                <input type="number" id="sr2_ratingMax" class="sr2_filterInput" placeholder="До" min="0" max="100">
                            </div>
                        </div>
                        <div class="sr2_actionButtonsContainer">
                            <button id="sr2_applyFiltersBtn" class="sr2_btn sr2_btnApplyFilters" disabled>Применить фильтры</button>
                            <button id="sr2_resetAllFiltersBtn" class="sr2_btn sr2_btnResetFilters" title="Сбросить фильтры" disabled>
                                <svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6s-2.69 6-6 6s-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8s-3.58-8-8-8Z"/></svg>
                            </button>
                        </div>
                    </div>

                    <div class="sr2_controlSection">
                        <label for="sr2_priorityCheckbox" class="sr2_label sr2_priorityLabel">
                            <input type="checkbox" id="sr2_priorityCheckbox" class="sr2_checkbox">
                            Приоритет по отзывам
                        </label>
                    </div>
                    <div class="sr2_controlSection">
                        <button id="sr2_spinBtn" class="sr2_btn sr2_btnPrimary sr2_btnBlock" disabled>КРУТИТЬ!</button>
                    </div>
                `;
                mainContainer.appendChild(leftControlsPanel);

                const rightContentArea = document.createElement('div');
                rightContentArea.id = 'sr2_rightContentArea';
                rightContentArea.innerHTML = `
                    <div id="sr2_viewFlipper">
                        <div id="sr2_flipper_content">
                            <div id="sr2_rouletteSection" class="sr2_flipper_face">
                                <div id="sr2_rouletteContainer">
                                    <div id="sr2_roulette"></div>
                                    <div id="sr2_selector"></div>
                                </div>
                            </div>
                            <div id="sr2_collectionViewWrapper" class="sr2_flipper_face">
                            </div>
                        </div>
                    </div>
                    <div id="sr2_result" class="sr2_result">
                        <div class="sr2_resultHeader">
                            <div class="sr2_gamePoster"><img id="sr2_resultPoster" src="" alt="Постер"></div>
                            <div class="sr2_gameInfoMain">
                                <h1 id="sr2_resultTitle" class="sr2_gameTitle"></h1>
                                <div id="sr2_resultRating" class="sr2_reviewRating"></div>
                                <a href="#" class="sr2_steamLink" target="_blank" id="sr2_resultSteamLink">
                                    <svg class="sr2_icon" viewBox="0 0 496 512"><path fill="currentColor" d="M496 256c0 137-111.2 248-248.4 248-113.8 0-209.6-76.3-239-180.4l95.2 39.3c6.4 32.1 34.9 56.4 68.9 56.4 39.2 0 71.9-32.4 70.2-73.5l84.5-60.2c52.1 1.3 95.8-40.9 95.8-93.5 0-51.6-42-93.5-93.7-93.5s-93.7 42-93.7 93.5v1.2L176.6 279c-15.5-.9-30.7 3.4-43.5 12.1L0 236.1C10.2 108.4 117.1 8 248.4 8 385.7 8 496 119 496 256zM155.7 384.3l-30.5-12.6a52.79 52.79 0 0 0 27.2 25.8c26.9 11.2 57.8-1.6 69-28.4 5.4-13 5.5-27.3.1-40.3-5.4-13-15.5-23.2-28.5-28.6-12.9-5.4-26.7-5.2-38.9-.6l31.5 13c19.8 8.2 29.2 30.9 20.9 50.7-8.3 19.9-31 29.2-50.8 21zm173.8-129.9c-34.4 0-62.4-28-62.4-62.3s28-62.3 62.4-62.3 62.4 28 62.4 62.3-27.9 62.3-62.4 62.3zm.1-15.6c25.9 0 46.9-21 46.9-46.8 0-25.9-21-46.8-46.9-46.8s-46.9 21-46.9 46.8c.1 25.8 21.1 46.8 46.9 46.8z"/></svg>
                                    Страница в сообществе Steam
                                </a>
                            </div>
                        </div>
                        <div class="sr2_gameContent">
                            <div class="sr2_gameDescriptionSection">
                                <p id="sr2_resultDescription" class="sr2_gameDescription"></p>
                                <div id="sr2_resultTags" class="sr2_gameTags"></div>
                                <a href="#" class="sr2_btn sr2_btnPrimary sr2_launchButton" id="sr2_resultLaunchLink">
                                    <svg class="sr2_icon" viewBox="0 0 448 512"><path fill="currentColor" d="M424.4 214.7L72.4 6.6C43.8-10.3 0 6.1 0 47.9V464c0 37.5 40.7 60.1 72.4 41.3l352-208c31.4-18.5 31.5-64.1 0-82.6z"/></svg>
                                    Запустить игру
                                </a>
                            </div>
                            <div class="sr2_gameDetails">
                                <div class="sr2_detailItem"><div class="sr2_detailLabel">Дата выхода</div><div id="sr2_resultReleaseDate" class="sr2_detailValue"></div></div>
                                <div class="sr2_detailItem"><div class="sr2_detailLabel">Издатель</div><div id="sr2_resultPublisher" class="sr2_detailValue"></div></div>
                                <div class="sr2_detailItem"><div class="sr2_detailLabel">Разработчик</div><div id="sr2_resultDeveloper" class="sr2_detailValue"></div></div>
                                <div class="sr2_detailItem"><div class="sr2_detailLabel">Русский язык</div><div id="sr2_resultLanguages" class="sr2_detailValue"></div></div>
                            </div>
                        </div>
                    </div>
                `;
                mainContainer.appendChild(rightContentArea);
                sr2_modal.appendChild(mainContainer);
                document.body.appendChild(sr2_modal);
                document.body.style.overflow = 'hidden';

                document.getElementById('sr2_toggleViewBtn').onclick = sr2_toggleView;
                document.getElementById('sr2_helpBtn').onclick = sr2_showHelpModal;
                document.getElementById('sr2_closeBtn').onclick = sr2_hideRouletteModal;
                document.getElementById('sr2_csvFileTrigger').onclick = () => document.getElementById('sr2_csvFile').click();
                document.getElementById('sr2_csvFile').onchange = sr2_handleFileSelect;
                document.getElementById('sr2_applyFiltersBtn').onclick = sr2_applyAllFiltersAndRouletteUpdate;
                document.getElementById('sr2_resetAllFiltersBtn').onclick = sr2_confirmResetAllFilters;
                document.getElementById('sr2_spinBtn').onclick = sr2_spin;
                document.getElementById('sr2_tagSearchInput').oninput = sr2_filterTagList;

                ['sr2_reviewCountMin', 'sr2_reviewCountMax', 'sr2_ratingMin', 'sr2_ratingMax'].forEach(id => {
                    const el = document.getElementById(id);
                    if (el) el.oninput = sr2_handleRangeFilterChange;
                });

                sr2_modal._escHandler = (event) => {
                    if (event.key === "Escape") {
                        const helpModal = document.getElementById('sr2_stelicasRouletteHelpModal');
                        if (helpModal && helpModal.style.display !== 'none') {
                            helpModal.remove();
                            if(helpModal._escHandler) document.removeEventListener('keydown', helpModal._escHandler);
                        } else {
                             const confirmModal = document.getElementById('sr2_confirmResetModal');
                             if (confirmModal && confirmModal.style.display !== 'none') {
                                 confirmModal.remove();
                                 if(confirmModal._escHandler) document.removeEventListener('keydown', confirmModal._escHandler);
                             } else {
                                sr2_hideRouletteModal();
                             }
                        }
                    }
                };
                document.addEventListener('keydown', sr2_modal._escHandler);
            }

            function sr2_toggleView() {
                const flipperContent = document.getElementById('sr2_flipper_content');
                const spinBtn = document.getElementById('sr2_spinBtn');
                const resultDiv = document.getElementById('sr2_result');

                if (sr2_currentViewMode === 'roulette') {
                    sr2_currentViewMode = 'collection';
                    sr2_toggleViewBtn.textContent = 'Вернуться к рулетке';
                    sr2_toggleViewBtn.title = 'Вернуться к рулетке';
                    flipperContent.classList.add('flipped');
                    spinBtn.disabled = true;
                    sr2_populateCollectionView();
                    resultDiv.style.display = 'none';
                    sr2_collectionSelectedGameAppId = null;
                } else {
                    sr2_currentViewMode = 'roulette';
                    sr2_toggleViewBtn.textContent = 'Посмотреть подборку';
                    sr2_toggleViewBtn.title = 'Посмотреть подборку';
                    flipperContent.classList.remove('flipped');
                    spinBtn.disabled = sr2_filteredGames.length === 0;
                    resultDiv.style.display = 'none';
                }
            }

            function sr2_populateCollectionView() {
                const collectionViewWrapper = document.getElementById('sr2_collectionViewWrapper');
                if (!collectionViewWrapper) return;
                collectionViewWrapper.innerHTML = '';

                if (sr2_filteredGames.length === 0) {
                    collectionViewWrapper.innerHTML = '<div style="color: #8B949E; text-align: center; width: 100%; padding: 20px; align-self: center;">Нет игр по фильтрам для отображения в подборке.</div>';
                    return;
                }

                sr2_filteredGames.forEach(game => {
                    const card = document.createElement('div');
                    card.className = 'sr2_collectionGameCard';
                    card.dataset.gameId = game.game_id;

                    if (game.Pic) {
                        const img = document.createElement('img');
                        img.src = game.Pic;
                        img.alt = game.name || 'Game Poster';
                        img.loading = 'lazy';
                        img.onerror = function() { this.style.display='none'; card.insertAdjacentHTML('afterbegin', '<div style="height:120px; display:flex; align-items:center; justify-content:center; color:#666;">Нет постера</div>'); };
                        card.appendChild(img);
                    } else {
                         card.insertAdjacentHTML('afterbegin', '<div style="height:120px; display:flex; align-items:center; justify-content:center; color:#666;">Нет постера</div>');
                    }

                    const nameDiv = document.createElement('div');
                    nameDiv.className = 'sr2_collectionGameCardName';
                    nameDiv.textContent = game.name || 'Unnamed Game';
                    card.appendChild(nameDiv);

                    card.onclick = () => sr2_handleCollectionGameClick(game);
                    collectionViewWrapper.appendChild(card);
                });
            }

             function sr2_handleCollectionGameClick(game) {
                const resultDiv = document.getElementById('sr2_result');
                if (sr2_collectionSelectedGameAppId === game.game_id && resultDiv.style.display === 'block') {
                    resultDiv.style.display = 'none';
                    sr2_collectionSelectedGameAppId = null;
                } else {
                    sr2_showResult(game);
                    sr2_collectionSelectedGameAppId = game.game_id;
                }
            }


            function sr2_showHelpModal() {
                const helpModalId = 'sr2_stelicasRouletteHelpModal';
                if (document.getElementById(helpModalId)) {
                    document.getElementById(helpModalId).style.display = 'flex';
                    return;
                }

                const helpModal = document.createElement('div');
                helpModal.id = helpModalId;
                helpModal.style.cssText = `
                    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
                    background-color: rgba(13, 17, 23, 0.85); backdrop-filter: blur(4px);
                    z-index: 20002; display: flex;
                    align-items: center; justify-content: center; padding: 20px;
                `;
                const helpContent = document.createElement('div');
                helpContent.style.cssText = `
                    background-color: #161B22; color: #C9D1D9; padding: 25px;
                    border-radius: 6px; border: 1px solid #30363D; width: 90%; max-width: 700px;
                    box-shadow: 0 8px 30px rgba(0,0,0,0.5); max-height: 85vh; overflow-y: auto;
                    font-family: "Motiva Sans", Arial, sans-serif; font-size: 14px;
                `;
                helpContent.innerHTML = `
                    <h3 style="color: #58A6FF; text-align: center; margin-top:0; margin-bottom: 20px; font-size: 18px;">Рулетка Stelicas - Инструкция</h3>
                    <p>Этот модуль поможет вам случайным образом выбрать игру для прохождения из вашей библиотеки Steam, используя данные, экспортированные из приложения <strong>Stelicas</strong>.</p>
                    <h4>Порядок действий:</h4>
                    <ol style="line-height: 1.6; margin-left: 20px; padding-left: 5px;">
                        <li style="margin-bottom: 0.8em;">
                            <strong>Подготовка CSV-файла:</strong>
                            <ul style="margin-top: 0.5em; margin-left: 15px; list-style-type: disc;">
                                <li style="margin-bottom: 0.3em;">Запустите приложение <a href="https://github.com/0wn3dg0d/Stelicas" target="_blank" style="color:#58A6FF;">Stelicas</a>. <strong>Важно:</strong> клиент Steam должен быть закрыт во время работы Stelicas.</li>
                                <li style="margin-bottom: 0.3em;">В Stelicas введите ваш AccountID (Steam3 ID) и выберите необходимые настройки языка и региона.</li>
                                <li style="margin-bottom: 0.3em;">Нажмите "Start". Программа соберет данные о ваших играх и категориях.</li>
                                <li style="margin-bottom: 0.3em;">После завершения, найдите файл <code>final_data.csv</code> в папке <code>output</code> (рядом с программой Stelicas). Этот файл понадобится для рулетки.</li>
                            </ul>
                        </li>
                        <li style="margin-bottom: 0.8em;"><strong>Загрузка CSV в рулетку:</strong> В левой панели текущего окна нажмите "Выбрать CSV от Stelicas" и укажите путь к файлу <code>final_data.csv</code>.</li>
                        <li style="margin-bottom: 0.8em;">
                            <strong>Выбор фильтров:</strong>
                            <ul style="margin-top: 0.5em; margin-left: 15px; list-style-type: square;">
                                <li><strong>Категории:</strong> Отметьте одну или несколько интересующих вас категорий. Опция "Все" (первая в списке) позволяет отметить или снять все галочки в секции "Категории" одновременно.</li>
                                <li><strong>Дата выхода:</strong> Выберите конкретные годы, "Без даты" или "Все". Опция "Все" также управляет всеми галочками в этой секции. Годы упорядочены от новых к старым.</li>
                                <li><strong>Тэги:</strong> Выберите тэги. Используйте поиск для быстрого нахождения нужного тэга. Тэги отсортированы по популярности. "Все" и "Без тэгов" также доступны, "Все" управляет всеми галочками тэгов.</li>
                                <li><strong>Русский язык:</strong> Укажите требуемый уровень локализации ("Без русского языка", "Русские субтитры/интерфейс", "Русская озвучка") или "Все" (управляет всеми опциями языка).</li>
                                <li><strong>Количество отзывов:</strong> Задайте диапазон (например, от 100 до 10000). Плейсхолдеры показывают доступные мин/макс значения с учётом других фильтров.</li>
                                <li><strong>Рейтинг:</strong> Задайте диапазон в процентах (например, от 70 до 100). Плейсхолдеры также динамические.</li>
                            </ul>
                            После выбора всех фильтров нажмите кнопку "Применить фильтры". Счётчики у фильтров обновляются в реальном времени при изменении других фильтров. Для сброса всех фильтров к состоянию по умолчанию используйте кнопку со значком возврата рядом с "Применить фильтры".
                        </li>
                        <li style="margin-bottom: 0.8em;"><strong>Настройка приоритетов (опционально):</strong> Если активировать опцию "Приоритет по отзывам", игры с более высоким рейтингом и большим количеством обзоров будут иметь больше шансов на выпадение (среди отфильтрованных).</li>
                        <li style="margin-bottom: 0.8em;"><strong>Запуск рулетки:</strong> Нажмите большую кнопку "КРУТИТЬ!".</li>
                        <li style="margin-bottom: 0.8em;">
                            <strong>Просмотр подборки:</strong>
                            <ul style="margin-top: 0.5em; margin-left: 15px; list-style-type: disc;">
                                <li style="margin-bottom: 0.3em;">Вы можете посмотреть игры из текущей подборки (с активным фильтром) с помощью кнопки "Посмотреть подборку" в заголовке модального окна.</li>
                                <li style="margin-bottom: 0.3em;">Нажатие на неё переключит правую панель в режим отображения всех отфильтрованных игр в виде карточек (изображение и название). Кнопка "КРУТИТЬ!" будет неактивна в этом режиме.</li>
                                <li style="margin-bottom: 0.3em;">Щелчок по карточке игры в подборке покажет подробную информацию о ней в блоке ниже (аналогично результату рулетки). Повторный щелчок по той же карточке скроет информацию.</li>
                                <li style="margin-bottom: 0.3em;">Чтобы вернуться к рулетке, нажмите кнопку "Вернуться к рулетке" в заголовке модального окна.</li>
                            </ul>
                        </li>
                    </ol>
                    <p>После остановки рулетки вы увидите подробную информацию о выбранной игре.</p>
                `;
                const closeHelpButton = document.createElement('button');
                closeHelpButton.textContent = 'Понятно';
                closeHelpButton.className = 'sr2_btn sr2_btnPrimary';
                closeHelpButton.style.cssText = 'display: block; margin: 25px auto 0; padding: 10px 25px;';
                closeHelpButton.onclick = () => {
                    helpModal.remove();
                    document.removeEventListener('keydown', helpModal._escHandler);
                };
                helpContent.appendChild(closeHelpButton);
                helpModal.appendChild(helpContent);
                document.body.appendChild(helpModal);

                helpModal._escHandler = (event) => {
                    if (event.key === "Escape") {
                        helpModal.remove();
                        document.removeEventListener('keydown', helpModal._escHandler);
                    }
                };
                document.addEventListener('keydown', helpModal._escHandler);
                helpContent.addEventListener('click', e => e.stopPropagation());
                helpModal.addEventListener('click', function(event) {
                    if (event.target === helpModal) {
                        helpModal.remove();
                        document.removeEventListener('keydown', helpModal._escHandler);
                    }
                });
            }

            function sr2_hideRouletteModal() {
                if (sr2_modal) {
                    sr2_modal.style.display = 'none';
                    document.body.style.overflow = '';
                    if (sr2_modal._escHandler) {
                        document.removeEventListener('keydown', sr2_modal._escHandler);
                        delete sr2_modal._escHandler;
                    }
                }
            }

            function sr2_resetFiltersToDefaultStateAndUI() {
                sr2_activeFilters = {
                    categories: ["Все"], releaseYears: ["Все"], tags: ["Все"], language: ["Все"],
                    reviewCountMin: null, reviewCountMax: null, ratingMin: null, ratingMax: null
                };
                document.getElementById('sr2_reviewCountMin').value = '';
                document.getElementById('sr2_reviewCountMax').value = '';
                document.getElementById('sr2_ratingMin').value = '';
                document.getElementById('sr2_ratingMax').value = '';
                document.getElementById('sr2_tagSearchInput').value = '';
                sr2_filterTagList();


                if (sr2_currentViewMode === 'collection') {
                    sr2_currentViewMode = 'roulette';
                    document.getElementById('sr2_flipper_content').classList.remove('flipped');
                    if(sr2_toggleViewBtn) {
                        sr2_toggleViewBtn.textContent = 'Посмотреть подборку';
                        sr2_toggleViewBtn.title = 'Посмотреть подборку';
                    }
                }

                sr2_updateAllFilterCounts();
                sr2_applyAllFiltersAndRouletteUpdate();
                document.getElementById('sr2_result').style.display = 'none';
                sr2_collectionSelectedGameAppId = null;
            }

            function sr2_handleFileSelect(event) {
                const file = event.target.files[0];
                if (!file) return;
                const fileNameDisplay = document.getElementById('sr2_fileNameDisplay');
                if (fileNameDisplay) fileNameDisplay.textContent = file.name;
                const reader = new FileReader();
                reader.onload = function(e) {
                    sr2_parseCSV(e.target.result);
                    sr2_resetFiltersToDefaultStateAndUI();
                    document.getElementById('sr2_applyFiltersBtn').disabled = false;
                    document.getElementById('sr2_resetAllFiltersBtn').disabled = false;
                    sr2_applyAllFiltersAndRouletteUpdate();
                };
                reader.readAsText(file, 'UTF-8');
            }

            function sr2_parseCSV(data) {
                const rows = data.split(/\r?\n/).slice(1);
                sr2_games = [];
                rows.forEach(row => {
                    if (!row.trim()) return;
                    const fields = row.split('\t');
                    if (fields.length < 17) return;

                    const game = {
                        game_id: fields[0]?.trim(),
                        name: fields[1]?.trim(),
                        categories: fields[2]?.trim().split(';').map(c => c.trim()).filter(c => c),
                        type: fields[3]?.trim(),
                        tags: fields[4]?.trim().split(';').map(t => t.trim()).filter(t => t),
                        release_date: fields[5]?.trim(),
                        review_percentage: parseInt(fields[6]) || 0,
                        review_count: parseInt(fields[7]) || 0,
                        is_free: fields[8]?.trim().toLowerCase() === 'true',
                        is_early_access: fields[9]?.trim().toLowerCase() === 'true',
                        publishers: fields[10]?.trim(),
                        developers: fields[11]?.trim(),
                        franchises: fields[12]?.trim(),
                        short_description: fields[13]?.trim().replace(/^"|"$/g, '').replace(/""/g, '"'),
                        supported_language: fields[14]?.trim(),
                        'Steam-Link': fields[15]?.trim(),
                        Pic: fields[16]?.trim(),
                        parsed_release_year: sr2_parseReleaseYear(fields[5]?.trim()),
                        parsed_language_support: sr2_parseGameLanguageSupport(fields[14]?.trim())
                    };
                    if (game.game_id && game.name) {
                        sr2_games.push(game);
                    }
                });
                sr2_filteredGames = [...sr2_games];
            }

            function sr2_parseReleaseYear(dateStr) {
                if (!dateStr || dateStr.toLowerCase() === 'unknown' || dateStr.toLowerCase() === 'tbd' || dateStr.trim() === '') return 'Без даты';
                const yearMatch = dateStr.match(/\b(\d{4})\b/);
                return yearMatch ? yearMatch[1] : 'Без даты';
            }

            function sr2_parseGameLanguageSupport(langStr) {
                const support = { hasRussian: false, interface: false, subtitles: false, voice: false, raw: langStr, noData: false };
                if (!langStr || typeof langStr !== 'string' || langStr.trim() === '') {
                    support.noData = true; return support;
                }
                const cleaned = langStr.replace(/[{}]/g, '').trim().toLowerCase();
                if (cleaned === 'true') {
                    support.hasRussian = true; support.interface = true; support.subtitles = true; support.voice = true;
                } else if (cleaned === 'false') {
                } else {
                    const parts = cleaned.split(';');
                    if (parts.length === 3) {
                        if (parts[0] === 'true') support.interface = true;
                        if (parts[1] === 'true') support.voice = true;
                        if (parts[2] === 'true') support.subtitles = true;
                        support.hasRussian = support.interface || support.subtitles || support.voice;
                    } else {
                         support.noData = true;
                    }
                }
                return support;
            }

            function sr2_populateFilterList(elementId, itemsMap, type) {
                const listDiv = document.getElementById(elementId);
                if (!listDiv) return;
                listDiv.innerHTML = '';

                const createCheckbox = (value, text, count) => {
                    const label = document.createElement('label');
                    label.className = 'sr2_filterItem';
                    const checkbox = document.createElement('input');
                    checkbox.type = 'checkbox';
                    checkbox.value = value;
                    checkbox.onchange = (event) => {
                        sr2_handleFilterChange(type, event);
                    };
                    label.appendChild(checkbox);
                    label.appendChild(document.createTextNode(` ${text} (${count})`));
                    return label;
                };

                let totalCountForFilterType = sr2_applyCurrentFiltersToGameList(sr2_games, { excludeFilter: type }).length;
                listDiv.appendChild(createCheckbox('Все', 'Все', totalCountForFilterType));

                if (type === 'releaseYears') {
                    listDiv.appendChild(createCheckbox('Без даты', 'Без даты', itemsMap.get('Без даты') || 0));
                    Array.from(itemsMap.keys()).filter(key => key !== 'Без даты').sort((a,b) => b-a).forEach(key => {
                        listDiv.appendChild(createCheckbox(key, key, itemsMap.get(key) || 0));
                    });
                } else if (type === 'tags'){
                    listDiv.appendChild(createCheckbox('Без тэгов', 'Без тэгов', itemsMap.get('Без тэгов') || 0));
                    Array.from(itemsMap.entries())
                        .filter(([key]) => key !== 'Без тэгов')
                        .sort(([, countA], [, countB]) => countB - countA)
                        .forEach(([key, count]) => {
                            listDiv.appendChild(createCheckbox(key, key, count));
                        });
                } else if (type === 'language') {
                    listDiv.appendChild(createCheckbox('noRussianOrNoData', 'Без русского языка', sr2_languageSupportStats.noRussianOrNoData));
                    listDiv.appendChild(createCheckbox('subtitlesOrInterfaceOnly', 'Русские субтитры/интерфейс', sr2_languageSupportStats.subtitlesOrInterfaceOnly));
                    listDiv.appendChild(createCheckbox('voice', 'Русская озвучка', sr2_languageSupportStats.voice));
                } else {
                    Array.from(itemsMap.entries())
                       .sort((a, b) => {
                           if (a[0] === 'Избранное') return -1; if (b[0] === 'Избранное') return 1;
                           return a[0].localeCompare(b[0], 'ru');
                        })
                       .forEach(([key, count]) => {
                           listDiv.appendChild(createCheckbox(key, key, count));
                       });
                }
            }

            function sr2_filterTagList() {
                const searchTerm = document.getElementById('sr2_tagSearchInput').value.toLowerCase();
                const tagListDiv = document.getElementById('sr2_tagList');
                tagListDiv.querySelectorAll('.sr2_filterItem').forEach(item => {
                    const checkbox = item.querySelector('input[type="checkbox"]');
                    if (checkbox.value === "Все" || checkbox.value === "Без тэгов") {
                        item.style.display = 'block'; return;
                    }
                    item.style.display = checkbox.value.toLowerCase().includes(searchTerm) ? 'block' : 'none';
                });
            }

            function sr2_updateAllFilterCounts() {
                const tempFilteredGamesCategories = sr2_applyCurrentFiltersToGameList(sr2_games, { excludeFilter: 'categories'});
                const tempFilteredGamesYears = sr2_applyCurrentFiltersToGameList(sr2_games, { excludeFilter: 'releaseYears'});
                const tempFilteredGamesTags = sr2_applyCurrentFiltersToGameList(sr2_games, { excludeFilter: 'tags'});
                const tempFilteredGamesLang = sr2_applyCurrentFiltersToGameList(sr2_games, { excludeFilter: 'language'});
                const tempFilteredForRanges = sr2_applyCurrentFiltersToGameList(sr2_games, {});

                sr2_calculateCategoryCounts(tempFilteredGamesCategories);
                sr2_calculateReleaseYearCounts(tempFilteredGamesYears);
                sr2_calculateTagCounts(tempFilteredGamesTags);
                sr2_calculateLanguageCounts(tempFilteredGamesLang);

                sr2_populateFilterList('sr2_categoryList', sr2_categories, 'categories');
                sr2_populateFilterList('sr2_releaseYearList', sr2_releaseYears, 'releaseYears');
                sr2_populateFilterList('sr2_tagList', sr2_tags, 'tags');
                sr2_populateFilterList('sr2_languageList', null, 'language');

                sr2_updateRangePlaceholders(tempFilteredForRanges);
                sr2_restoreCheckboxStates();
            }

            function sr2_restoreCheckboxStates() {
                ['categories', 'releaseYears', 'tags', 'language'].forEach(type => {
                    const activeForType = sr2_activeFilters[type];
                    const listDiv = document.getElementById(sr2_getDivIdForFilterType(type));
                    if(!listDiv) return;

                    const allCb = listDiv.querySelector('input[value="Все"]');
                    const specificCheckboxes = Array.from(listDiv.querySelectorAll('input[type="checkbox"]:not([value="Все"])'));

                    if (!activeForType) return;

                    if (activeForType.includes("Все")) {
                        if (allCb) {
                            allCb.checked = true;
                            allCb.indeterminate = false;
                        }
                        specificCheckboxes.forEach(cb => cb.checked = true);
                    } else if (activeForType.length === 0) {
                        if (allCb) {
                            allCb.checked = false;
                            allCb.indeterminate = false;
                        }
                        specificCheckboxes.forEach(cb => cb.checked = false);
                    } else {
                        let allSpecificActuallyChecked = true;
                        let someSpecificActuallyChecked = false;

                        specificCheckboxes.forEach(cb => {
                            if (activeForType.includes(cb.value)) {
                                cb.checked = true;
                                someSpecificActuallyChecked = true;
                            } else {
                                cb.checked = false;
                                allSpecificActuallyChecked = false;
                            }
                        });

                        if (allCb) {
                            if (allSpecificActuallyChecked && specificCheckboxes.length > 0) {
                                allCb.checked = true;
                                allCb.indeterminate = false;
                            } else if (someSpecificActuallyChecked) {
                                allCb.checked = false;
                                allCb.indeterminate = true;
                            } else {
                                allCb.checked = false;
                                allCb.indeterminate = false;
                            }
                        }
                    }
                });
            }

            function sr2_getDivIdForFilterType(type) {
                switch(type) {
                    case 'categories': return 'sr2_categoryList';
                    case 'releaseYears': return 'sr2_releaseYearList';
                    case 'tags': return 'sr2_tagList';
                    case 'language': return 'sr2_languageList';
                    default: return '';
                }
            }

            function sr2_handleFilterChange(filterType, event) {
                const listDiv = document.getElementById(sr2_getDivIdForFilterType(filterType));
                if (!listDiv) return;

                const specificCheckboxes = Array.from(listDiv.querySelectorAll('input[type="checkbox"]:not([value="Все"])'));
                const clickedValue = event.target.value;
                const isChecked = event.target.checked;

                if (clickedValue === "Все") {
                    sr2_activeFilters[filterType] = isChecked ? ["Все"] : [];
                } else {
                    const selectedValues = [];
                    specificCheckboxes.forEach(cb => {
                        if (cb.value === clickedValue) {
                            if (isChecked) selectedValues.push(cb.value);
                        } else {
                            if (cb.checked) selectedValues.push(cb.value);
                        }
                    });

                    if (selectedValues.length === specificCheckboxes.length && specificCheckboxes.length > 0) {
                        sr2_activeFilters[filterType] = ["Все"];
                    } else if (selectedValues.length === 0) {
                         sr2_activeFilters[filterType] = [];
                    } else {
                        sr2_activeFilters[filterType] = selectedValues;
                    }
                }
                sr2_updateAllFilterCounts();
            }

            function sr2_handleRangeFilterChange() {
                sr2_activeFilters.reviewCountMin = document.getElementById('sr2_reviewCountMin').value === '' ? null : parseInt(document.getElementById('sr2_reviewCountMin').value);
                sr2_activeFilters.reviewCountMax = document.getElementById('sr2_reviewCountMax').value === '' ? null : parseInt(document.getElementById('sr2_reviewCountMax').value);
                sr2_activeFilters.ratingMin = document.getElementById('sr2_ratingMin').value === '' ? null : parseInt(document.getElementById('sr2_ratingMin').value);
                sr2_activeFilters.ratingMax = document.getElementById('sr2_ratingMax').value === '' ? null : parseInt(document.getElementById('sr2_ratingMax').value);
                sr2_updateAllFilterCounts();
            }

             function sr2_confirmResetAllFilters() {
                 const confirmModalId = 'sr2_confirmResetModal';
                 if (document.getElementById(confirmModalId)) return;

                 const confirmModal = document.createElement('div');
                 confirmModal.id = confirmModalId;
                 confirmModal.className = 'sr2_confirmModal';
                 confirmModal.innerHTML = `
                    <div class="sr2_confirmModalContent">
                        <h4>Сбросить фильтры</h4>
                        <p>Вы уверены, что хотите сбросить все фильтры к значениям по умолчанию?</p>
                        <div class="sr2_confirmModalActions">
                            <button id="sr2_confirmResetYes" class="sr2_btn sr2_btnPrimary">Да</button>
                            <button id="sr2_confirmResetNo" class="sr2_btn">Нет</button>
                        </div>
                    </div>
                 `;
                document.body.appendChild(confirmModal);

                document.getElementById('sr2_confirmResetYes').onclick = () => {
                    sr2_resetFiltersToDefaultStateAndUI();
                    confirmModal.remove();
                    if(confirmModal._escHandler) document.removeEventListener('keydown', confirmModal._escHandler);
                };
                document.getElementById('sr2_confirmResetNo').onclick = () => {
                    confirmModal.remove();
                     if(confirmModal._escHandler) document.removeEventListener('keydown', confirmModal._escHandler);
                };
                confirmModal._escHandler = (event) => {
                    if (event.key === "Escape") {
                        confirmModal.remove();
                        document.removeEventListener('keydown', confirmModal._escHandler);
                    }
                };
                document.addEventListener('keydown', confirmModal._escHandler);
                confirmModal.querySelector('.sr2_confirmModalContent').addEventListener('click', e => e.stopPropagation());
                confirmModal.addEventListener('click', (event) => {
                    if(event.target === confirmModal) {
                        confirmModal.remove();
                        if(confirmModal._escHandler) document.removeEventListener('keydown', confirmModal._escHandler);
                    }
                });
            }

            function sr2_calculateCategoryCounts(gamesToCount) {
                sr2_categories.clear();
                const tempCategories = new Map();
                gamesToCount.forEach(game => {
                    game.categories.forEach(cat => {
                        if (cat) tempCategories.set(cat, (tempCategories.get(cat) || 0) + 1);
                    });
                });
                 const sortedCategoriesArray = Array.from(tempCategories.entries()).sort((a, b) => {
                    const [catA] = a; const [catB] = b;
                    if (catA === 'Избранное') return -1; if (catB === 'Избранное') return 1;
                    return catA.localeCompare(catB, 'ru');
                });
                sr2_categories = new Map(sortedCategoriesArray);
            }

            function sr2_calculateReleaseYearCounts(gamesToCount) {
                sr2_releaseYears.clear();
                let noDateCount = 0;
                gamesToCount.forEach(game => {
                    const year = game.parsed_release_year;
                    if (year === 'Без даты') {
                        noDateCount++;
                    } else if (year) {
                        sr2_releaseYears.set(year, (sr2_releaseYears.get(year) || 0) + 1);
                    }
                });
                if(noDateCount > 0 || gamesToCount.some(g => g.parsed_release_year === 'Без даты') || sr2_releaseYears.size === 0 && gamesToCount.length > 0) {
                     sr2_releaseYears.set('Без даты', noDateCount);
                }
            }

            function sr2_calculateTagCounts(gamesToCount) {
                sr2_tags.clear();
                let noTagCount = 0;
                gamesToCount.forEach(game => {
                    if (game.tags && game.tags.length > 0) {
                        game.tags.forEach(tag => {
                            if (tag) sr2_tags.set(tag, (sr2_tags.get(tag) || 0) + 1);
                        });
                    } else {
                        noTagCount++;
                    }
                });
                 if(noTagCount > 0 || gamesToCount.some(g => !g.tags || g.tags.length === 0) || sr2_tags.size === 0 && gamesToCount.length > 0) {
                    sr2_tags.set('Без тэгов', noTagCount);
                }
            }

            function sr2_calculateLanguageCounts(gamesToCount) {
                sr2_languageSupportStats = { noRussianOrNoData: 0, subtitlesOrInterfaceOnly: 0, voice: 0 };
                gamesToCount.forEach(game => {
                    const lang = game.parsed_language_support;
                    if (lang) {
                        if (lang.voice) {
                            sr2_languageSupportStats.voice++;
                        } else if (lang.interface || lang.subtitles) {
                            sr2_languageSupportStats.subtitlesOrInterfaceOnly++;
                        } else {
                            sr2_languageSupportStats.noRussianOrNoData++;
                        }
                    } else {
                         sr2_languageSupportStats.noRussianOrNoData++;
                    }
                });
            }

            function sr2_updateRangePlaceholders(gamesToUpdateFrom) {
                let minReviews = Infinity, maxReviews = 0, minRating = 101, maxRating = -1;
                const validGamesForStats = gamesToUpdateFrom.filter(game => game.review_count > 0 || game.review_percentage > 0);

                if (validGamesForStats.length > 0) {
                    validGamesForStats.forEach(game => {
                        minReviews = Math.min(minReviews, game.review_count);
                        maxReviews = Math.max(maxReviews, game.review_count);
                        if (game.review_count > 0) {
                           minRating = Math.min(minRating, game.review_percentage);
                           maxRating = Math.max(maxRating, game.review_percentage);
                        }
                    });
                } else {
                    minReviews = 0; maxReviews = 0; minRating = 0; maxRating = 100;
                }
                minReviews = minReviews === Infinity ? 0 : minReviews;
                minRating = minRating === 101 ? 0 : minRating;
                maxRating = maxRating === -1 ? 100 : maxRating;

                document.getElementById('sr2_reviewCountMin').placeholder = `От ${minReviews}`;
                document.getElementById('sr2_reviewCountMax').placeholder = `До ${maxReviews}`;
                document.getElementById('sr2_ratingMin').placeholder = `От ${minRating}`;
                document.getElementById('sr2_ratingMax').placeholder = `До ${maxRating}`;
            }

            function sr2_gamePassesOtherFilters(game, options) {
                const { excludeFilter } = options || {};

                if (excludeFilter !== 'categories' && !sr2_activeFilters.categories.includes("Все")) {
                    if (sr2_activeFilters.categories.length === 0) return false;
                    if (!sr2_activeFilters.categories.some(cat => game.categories.includes(cat))) return false;
                }
                if (excludeFilter !== 'releaseYears' && !sr2_activeFilters.releaseYears.includes("Все")) {
                    if (sr2_activeFilters.releaseYears.length === 0) return false;
                    let yearMatch = false;
                    if (sr2_activeFilters.releaseYears.includes('Без даты') && game.parsed_release_year === 'Без даты') yearMatch = true;
                    if (!yearMatch && sr2_activeFilters.releaseYears.includes(game.parsed_release_year)) yearMatch = true;
                    if (!yearMatch) return false;
                }
                if (excludeFilter !== 'tags' && !sr2_activeFilters.tags.includes("Все")) {
                    if (sr2_activeFilters.tags.length === 0) return false;
                    let tagMatch = false;
                    const hasGameTags = game.tags && game.tags.length > 0;
                    if (sr2_activeFilters.tags.includes('Без тэгов') && !hasGameTags) tagMatch = true;
                    if (!tagMatch && hasGameTags && sr2_activeFilters.tags.some(tag => game.tags.includes(tag))) tagMatch = true;
                    if (!tagMatch) return false;
                }
                if (excludeFilter !== 'language' && !sr2_activeFilters.language.includes("Все")) {
                    if (sr2_activeFilters.language.length === 0) return false;
                    let langMatch = false;
                    const langSup = game.parsed_language_support;
                    if (sr2_activeFilters.language.includes('noRussianOrNoData') && (!langSup.hasRussian || langSup.noData)) langMatch = true;
                    if (!langMatch && sr2_activeFilters.language.includes('subtitlesOrInterfaceOnly') && (langSup.interface || langSup.subtitles) && !langSup.voice) langMatch = true;
                    if (!langMatch && sr2_activeFilters.language.includes('voice') && langSup.voice) langMatch = true;
                    if (!langMatch) return false;
                }
                if (excludeFilter !== 'reviewCount') {
                    if (sr2_activeFilters.reviewCountMin !== null && game.review_count < sr2_activeFilters.reviewCountMin) return false;
                    if (sr2_activeFilters.reviewCountMax !== null && game.review_count > sr2_activeFilters.reviewCountMax) return false;
                }
                if (excludeFilter !== 'rating') {
                    if (sr2_activeFilters.ratingMin !== null && game.review_percentage < sr2_activeFilters.ratingMin) return false;
                    if (sr2_activeFilters.ratingMax !== null && game.review_percentage > sr2_activeFilters.ratingMax) return false;
                }
                return true;
            }

            function sr2_applyCurrentFiltersToGameList(baseGameList, options) {
                 return baseGameList.filter(game => sr2_gamePassesOtherFilters(game, options));
            }

            function sr2_applyAllFiltersAndRouletteUpdate() {
                sr2_filteredGames = sr2_applyCurrentFiltersToGameList(sr2_games, {});
                const spinBtn = document.getElementById('sr2_spinBtn');
                const resultDiv = document.getElementById('sr2_result');

                if (sr2_currentViewMode === 'roulette') {
                    spinBtn.disabled = sr2_filteredGames.length === 0;
                } else {
                    spinBtn.disabled = true;
                    sr2_populateCollectionView();
                }

                if(sr2_toggleViewBtn) sr2_toggleViewBtn.disabled = sr2_filteredGames.length === 0;

                sr2_updateRoulette();
                resultDiv.style.display = 'none';
                sr2_collectionSelectedGameAppId = null;
            }


            function sr2_updateRoulette() {
                const roulette = document.getElementById('sr2_roulette');
                if (!roulette || !roulette.parentElement) return;
                roulette.innerHTML = '';
                if (sr2_filteredGames.length === 0) {
                    roulette.innerHTML = '<div class="sr2_gameItem" style="width: 100%; text-align: center; color: #8B949E; height:100%; display:flex; align-items:center; justify-content:center;">Нет игр по фильтрам</div>';
                    roulette.style.width = '100%';
                    return;
                }
                const fragment = document.createDocumentFragment();
                const itemActualWidth = 164;

                for (let i = 0; i < SR2_CLONES_COUNT; i++) {
                    sr2_filteredGames.forEach(game => {
                        const div = document.createElement('div');
                        div.className = 'sr2_gameItem';
                        if (game.Pic) {
                            const img = document.createElement('img');
                            img.src = game.Pic;
                            img.alt = game.name;
                            img.loading = 'lazy';
                            img.onerror = function() { this.style.display='none'; div.textContent = game.name || game.game_id; };
                            div.appendChild(img);
                        } else {
                            div.textContent = game.name || game.game_id;
                        }
                        fragment.appendChild(div);
                    });
                }
                roulette.appendChild(fragment);
                roulette.style.transform = 'translateX(0)';
                 if (sr2_filteredGames.length > 0) {
                      roulette.style.width = `${itemActualWidth * sr2_filteredGames.length * SR2_CLONES_COUNT}px`;
                 } else {
                      roulette.style.width = '100%';
                 }
            }

            function sr2_spin() {
                if (sr2_spinning || !sr2_filteredGames.length || sr2_currentViewMode === 'collection') return;
                sr2_spinning = true;
                document.getElementById('sr2_result').style.display = 'none';
                sr2_collectionSelectedGameAppId = null;
                const roulette = document.getElementById('sr2_roulette');
                const itemActualWidth = 164;
                const originalCount = sr2_filteredGames.length;
                if (originalCount === 0) { sr2_spinning = false; return; }

                let targetIndex;
                const usePriorities = document.getElementById('sr2_priorityCheckbox').checked;

                if (usePriorities && originalCount > 0) {
                    const weights = sr2_filteredGames.map(game => {
                        const percent = game.review_percentage || 0;
                        const count = game.review_count || 0;
                        return Math.max(1, (percent/100) * Math.log1p(count));
                    });
                    const totalWeight = weights.reduce((sum, w) => sum + w, 0);
                    if (totalWeight > 0) {
                        const normalized = weights.map(w => w / totalWeight);
                        const random = Math.random();
                        let cumulative = 0;
                        for (let i = 0; i < normalized.length; i++) {
                            cumulative += normalized[i];
                            if (random <= cumulative) { targetIndex = i; break; }
                        }
                        targetIndex = (targetIndex === undefined) ? Math.floor(Math.random() * originalCount) : targetIndex;
                    } else {
                        targetIndex = Math.floor(Math.random() * originalCount);
                    }
                } else {
                    targetIndex = Math.floor(Math.random() * originalCount);
                }

                const clonesBeforeTarget = Math.floor(SR2_CLONES_COUNT / 2);
                const targetCloneIndex = clonesBeforeTarget * originalCount + targetIndex;
                const rouletteContainer = document.getElementById('sr2_rouletteContainer');
                const targetPosition = targetCloneIndex * itemActualWidth - (rouletteContainer.offsetWidth / 2) + (itemActualWidth / 2);

                let currentTranslateX = 0;
                const transformValue = roulette.style.transform;
                if (transformValue && transformValue.startsWith('translateX(')) {
                    currentTranslateX = parseFloat(transformValue.replace('translateX(', '').replace('px)', ''));
                }
                const startPosition = -currentTranslateX;

                const startTime = performance.now();
                const duration = Math.max(3000, Math.min(7000, originalCount * 100));

                function animate(timestamp) {
                    const elapsed = timestamp - startTime;
                    const progress = Math.min(elapsed / duration, 1);
                    const easedProgress = 1 - Math.pow(1 - progress, 4);

                    const currentX = startPosition + (targetPosition - startPosition) * easedProgress;
                    roulette.style.transform = `translateX(-${currentX}px)`;

                    if (progress < 1) {
                        requestAnimationFrame(animate);
                    } else {
                        roulette.style.transition = 'none';
                        roulette.style.transform = `translateX(-${targetPosition}px)`;
                        setTimeout(() => { roulette.style.transition = ''; }, 50);
                        sr2_spinning = false;
                        sr2_showResult(sr2_filteredGames[targetIndex]);
                    }
                }
                requestAnimationFrame(animate);
            }

            function sr2_showResult(game) {
                const resultDiv = document.getElementById('sr2_result');
                if (!resultDiv || !game) { return; }
                const steamLink = game['Steam-Link'] || `https://store.steampowered.com/app/${game.game_id}/`;
                const launchLink = `steam://run/${game.game_id}`;
                const posterImg = document.getElementById('sr2_resultPoster');
                posterImg.src = game.Pic || ''; posterImg.alt = game.name || 'Постер игры';
                posterImg.style.display = game.Pic ? 'block' : 'none';
                document.getElementById('sr2_resultTitle').textContent = game.name || 'Без названия';
                document.getElementById('sr2_resultSteamLink').href = steamLink;
                document.getElementById('sr2_resultLaunchLink').href = launchLink;
                const ratingElem = document.getElementById('sr2_resultRating');
                let ratingClass = '';
                if (game.review_percentage) {
                    const percent = game.review_percentage;
                    if (percent >= 70) ratingClass = 'positive';
                    else if (percent >= 40) ratingClass = 'mixed';
                    else if (percent > 0) ratingClass = 'negative';
                    else ratingClass = '';
                    ratingElem.innerHTML = percent > 0 ?
                        `<span>${percent}%</span><span> (${game.review_count || 0} отзывов)</span>` :
                        'Нет оценок';
                    ratingElem.className = `sr2_reviewRating ${ratingClass}`;
                } else {
                    ratingElem.textContent = 'Нет оценок';
                    ratingElem.className = 'sr2_reviewRating';
                }
                document.getElementById('sr2_resultDescription').textContent = game.short_description || 'Описание отсутствует.';
                const tagsContainer = document.getElementById('sr2_resultTags');
                tagsContainer.innerHTML = '';
                if (game.tags) {
                    game.tags.slice(0, 12).forEach(tag => {
                        if (tag.trim()) {
                            const span = document.createElement('span');
                            span.className = 'sr2_tag'; span.textContent = tag.trim();
                            tagsContainer.appendChild(span);
                        }
                    });
                }
                document.getElementById('sr2_resultReleaseDate').textContent = game.release_date || 'Неизвестно';
                document.getElementById('sr2_resultPublisher').textContent = game.publishers || 'Не указан';
                document.getElementById('sr2_resultDeveloper').textContent = game.developers || 'Не указан';
                document.getElementById('sr2_resultLanguages').textContent = sr2_formatDisplayLanguage(game.parsed_language_support);
                resultDiv.style.display = 'block';
                setTimeout(() => {
                    resultDiv.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
                }, 100);
            }

            function sr2_formatDisplayLanguage(parsedSupport) {
                if (!parsedSupport) return 'Нет данных';
                if (parsedSupport.voice) return 'Полная локализация';
                if (parsedSupport.interface && parsedSupport.subtitles) return 'Интерфейс + Субтитры';
                if (parsedSupport.interface) return 'Только интерфейс';
                if (parsedSupport.subtitles) return 'Только субтитры';
                if (parsedSupport.noData) return 'Нет данных';
                return 'Без русского языка';
            }

            function sr2_addModalStyles() {
                const styleId = 'sr2-modal-styles';
                if (document.getElementById(styleId)) return;
                const style = document.createElement('style');
                style.id = styleId;
                style.textContent = `
                        #sr2_stelicasRouletteModal * {
                        	box-sizing: border-box;
                        }

                        #sr2_stelicasRouletteModal {
                        	background-color: #0D1117;
                        	color: #C9D1D9;
                        }

                        #sr2_headerPanel {
                        	display: flex;
                        	justify-content: space-between;
                        	align-items: center;
                        	padding: 10px 20px;
                        	background-color: #0B0F13;
                        	border-bottom: 1px solid #21262D;
                        	flex-shrink: 0;
                        }

                        #sr2_modalTitle {
                        	margin: 0;
                        	color: #58A6FF;
                        	font-size: 22px;
                        	font-weight: 500;
                        	font-family: Arial;
                        	font-weight: bold;
                        }

                        #sr2_headerControls {
                        	display: flex;
                        	gap: 10px;
                        }

                        .sr2_btn {
                        	background-color: #21262D;
                        	color: #C9D1D9;
                        	border: 1px solid #30363D;
                        	padding: 8px 15px;
                        	border-radius: 6px;
                        	cursor: pointer;
                        	font-size: 11px;
                        	font-weight: 500;
                        	transition: background-color 0.2s, border-color 0.2s;
                        	font-family: "Motiva Sans", Arial, sans-serif;
                        }

                        .sr2_btn:hover:not(:disabled) {
                        	background-color: #30363D;
                        	border-color: #8B949E;
                        }

                        .sr2_btn:disabled {
                        	background-color: #21262D;
                        	color: #6a737d;
                        	cursor: not-allowed;
                        	opacity: 0.7;
                        }

                        .sr2_btnIcon {
                        	padding: 6px 10px;
                        	font-size: 16px;
                        	line-height: 1;
                        }

                        #sr2_toggleViewBtn {
                        	font-size: 11px;
                        }

                        #sr2_closeBtn {
                        	font-size: 22px;
                        	padding: 4px 10px;
                        	background-color: transparent;
                        	border: none;
                        	color: #8B949E;
                        }

                        #sr2_closeBtn:hover {
                        	color: #C9D1D9;
                        	background-color: rgba(139, 148, 158, 0.1);
                        }

                        .sr2_btnPrimary {
                        	background-color: #238636;
                        	border-color: #2ea043;
                        	color: #ffffff;
                        	font-weight: bold;
                        }

                        .sr2_btnPrimary:hover:not(:disabled) {
                        	background-color: #2ea043;
                        	border-color: #3fb950;
                        }

                        .sr2_btnBlock {
                        	display: block;
                        	width: 100%;
                        	margin-top: 8px;
                        }

                        .sr2_actionButtonsContainer {
                        	display: flex;
                        	gap: 8px;
                        	margin-top: 10px;
                        }

                        .sr2_btnApplyFilters {
                        	flex-grow: 3;
                        }

                        .sr2_btnResetFilters {
                        	flex-grow: 1;
                        	padding: 8px 10px;
                        	display: flex;
                        	align-items: center;
                        	justify-content: center;
                        }

                        #sr2_mainContainer {
                        	display: flex;
                        	flex-grow: 1;
                        	overflow: hidden;
                        }

                        #sr2_leftControlsPanel {
                        	width: 300px;
                        	padding: 15px;
                        	background-color: #161B22;
                        	border-right: 1px solid #21262D;
                        	display: flex;
                        	flex-direction: column;
                        	gap: 10px;
                        	overflow-y: auto;
                        	flex-shrink: 0;
                        }

                        #sr2_leftControlsPanel::-webkit-scrollbar {
                        	width: 6px;
                        }

                        #sr2_leftControlsPanel::-webkit-scrollbar-track {
                        	background: #0D1117;
                        	border-radius: 3px;
                        }

                        #sr2_leftControlsPanel::-webkit-scrollbar-thumb {
                        	background-color: #30363D;
                        	border-radius: 3px;
                        	border: 1px solid #0D1117;
                        }

                        #sr2_leftControlsPanel::-webkit-scrollbar-thumb:hover {
                        	background-color: #58A6FF;
                        }

                        .sr2_controlSection {
                        	padding-bottom: 8px;
                        	border-bottom: 1px solid #21262D;
                        }

                        .sr2_controlSection:last-child {
                        	border-bottom: none;
                        	padding-bottom: 0;
                        }

                        .sr2_label {
                        	display: block;
                        	margin-bottom: 6px;
                        	color: #8B949E;
                        	font-size: 13px;
                        	font-weight: 500;
                        }

                        .sr2_fileName {
                        	color: #58A6FF;
                        	font-size: 12px;
                        	margin-top: 6px;
                        	display: block;
                        	word-break: break-all;
                        }

                        .sr2_filterBlock {
                        	margin-bottom: 8px;
                        }

                        .sr2_filterTitle {
                        	font-size: 13px;
                        	color: #58A6FF;
                        	margin: 0 0 4px 0;
                        	font-weight: 500;
                        }

                        .sr2_filterList {
                        	border: 1px solid #30363D;
                        	padding: 6px;
                        	border-radius: 4px;
                        	background-color: #0D1117;
                        	overflow-y: auto;
                        }

                        .sr2_filterItem {
                        	display: block;
                        	margin-bottom: 4px;
                        	color: #C9D1D9;
                        	font-size: 12px;
                        	cursor: pointer;
                        }

                        .sr2_filterItem input[type="checkbox"] {
                        	margin-right: 6px;
                        	accent-color: #58A6FF;
                        	vertical-align: middle;
                        	width: 14px;
                        	height: 14px;
                        }

                        .sr2_filterSearchInput {
                        	width: calc(100% - 12px);
                        	padding: 4px 6px;
                        	font-size: 12px;
                        	background-color: #0D1117;
                        	border: 1px solid #30363D;
                        	color: #C9D1D9;
                        	border-radius: 3px;
                        	margin: 0 auto 5px auto;
                        	display: block;
                        }

                        .sr2_inputRange {
                        	display: flex;
                        	gap: 5px;
                        	align-items: center;
                        }

                        .sr2_filterInput {
                        	width: calc(50% - 10px);
                        	padding: 4px 6px;
                        	font-size: 12px;
                        	background-color: #0D1117;
                        	border: 1px solid #30363D;
                        	color: #C9D1D9;
                        	border-radius: 3px;
                        	text-align: center;
                        }

                        .sr2_inputRangeSeparator {
                        	color: #8B949E;
                        }

                        .sr2_priorityLabel {
                        	display: flex;
                        	align-items: center;
                        	font-size: 14px;
                        	color: #C9D1D9;
                        	cursor: pointer;
                        	margin-top: 2px;
                        }

                        .sr2_checkbox {
                        	margin-right: 8px;
                        	width: 16px;
                        	height: 16px;
                        	accent-color: #58A6FF;
                        	cursor: pointer;
                        	background-color: #0D1117;
                        	border: 1px solid #30363D;
                        	border-radius: 3px;
                        }

                        #sr2_rightContentArea {
                        	flex-grow: 1;
                        	padding: 20px;
                        	overflow-y: auto;
                        	overflow-x: hidden;
                        	display: flex;
                        	flex-direction: column;
                        }

                        #sr2_rightContentArea::-webkit-scrollbar {
                        	width: 8px;
                        }

                        #sr2_rightContentArea::-webkit-scrollbar-track {
                        	background: #0D1117;
                        	border-radius: 4px;
                        }

                        #sr2_rightContentArea::-webkit-scrollbar-thumb {
                        	background-color: #30363D;
                        	border-radius: 4px;
                        	border: 2px solid #0D1117;
                        }

                        #sr2_rightContentArea::-webkit-scrollbar-thumb:hover {
                        	background-color: #58A6FF;
                        }

                        #sr2_viewFlipper {
                        	min-height: 200px;
                        	position: relative;
                        	perspective: 1000px;
                        	margin-bottom: 20px;
                        	flex-grow: 1;
                        	display: flex;
                        }

                        #sr2_flipper_content {
                        	width: 100%;
                        	height: 100%;
                        	transform-style: preserve-3d;
                        	transition: transform 0.7s cubic-bezier(0.4, 0.0, 0.2, 1);
                        }

                        #sr2_flipper_content.flipped {
                        	transform: rotateY(180deg);
                        }

                        .sr2_flipper_face {
                        	position: absolute;
                        	top: 0;
                        	left: 0;
                        	width: 100%;
                        	height: 100%;
                        	backface-visibility: hidden;
                        	display: flex;
                        	flex-direction: column;
                        	border-radius: 8px;
                        	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
                        	background-color: #0B0F13;
                        	overflow: hidden;
                        }

                        #sr2_rouletteSection {
                        	align-items: center;
                        	justify-content: flex-start;
                        	padding-top: 15px;
                        	padding-bottom: 15px;
                        }

                        #sr2_rouletteContainer {
                        	width: 90%;
                        	position: relative;
                        	overflow: hidden;
                        	height: 170px;
                        	border: 1px solid #30363D;
                        	border-radius: 6px;
                        	background: #0D1117;
                        	box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.7);
                        }

                        #sr2_roulette {
                        	display: flex;
                        	height: 100%;
                        	position: relative;
                        }

                        .sr2_gameItem {
                        	min-width: 164px;
                        	width: 164px;
                        	height: 100%;
                        	display: flex;
                        	align-items: center;
                        	justify-content: center;
                        	border-right: 1px solid #21262D;
                        	padding: 8px;
                        	background-color: #161B22;
                        	color: #8B949E;
                        	text-align: center;
                        	font-size: 12px;
                        }

                        .sr2_gameItem img {
                        	max-width: 100%;
                        	max-height: 100%;
                        	object-fit: contain;
                        	border-radius: 4px;
                        }

                        #sr2_selector {
                        	position: absolute;
                        	left: 50%;
                        	top: -5px;
                        	bottom: -5px;
                        	width: 4px;
                        	background: #f9826c;
                        	transform: translateX(-50%);
                        	box-shadow: 0 0 10px 3px #f9826c;
                        	border-radius: 2px;
                        	animation: sr2_pulse 1.3s infinite ease-in-out;
                        }

                        @keyframes sr2_pulse {

                        	0%,
                        	100% {
                        		opacity: 1;
                        		transform: translateX(-50%) scaleY(1.05);
                        	}

                        	50% {
                        		opacity: 0.7;
                        		transform: translateX(-50%) scaleY(1);
                        	}
                        }

                        #sr2_collectionViewWrapper {
                        	transform: rotateY(180deg);
                        	padding: 15px;
                        	overflow-y: auto;
                        	display: grid;
                        	grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
                        	gap: 15px;
                        	align-content: flex-start;
                        }

                        .sr2_collectionGameCard {
                        	background-color: #161B22;
                        	border: 1px solid #30363D;
                        	border-radius: 6px;
                        	padding: 10px;
                        	cursor: pointer;
                        	text-align: center;
                        	transition: transform 0.2s, box-shadow 0.2s;
                        	display: flex;
                        	flex-direction: column;
                        	align-items: center;
                        	justify-content: flex-start;
                        	min-height: 180px;
                        }

                        .sr2_collectionGameCard:hover {
                        	transform: translateY(-5px);
                        	box-shadow: 0 8px 15px rgba(0, 0, 0, 0.3);
                        }

                        .sr2_collectionGameCard img {
                        	width: 100%;
                        	height: 120px;
                        	object-fit: cover;
                        	border-radius: 4px;
                        	margin-bottom: 8px;
                        }

                        .sr2_collectionGameCardName {
                        	font-size: 13px;
                        	color: #C9D1D9;
                        	word-break: break-word;
                        	display: -webkit-box;
                        	-webkit-line-clamp: 2;
                        	-webkit-box-orient: vertical;
                        	overflow: hidden;
                        	text-overflow: ellipsis;
                        	margin-top: auto;
                        }

                        .sr2_result {
                        	margin-top: 15px;
                        	background: #161B22;
                        	border-radius: 8px;
                        	padding: 25px;
                        	display: none;
                        	border: 1px solid #30363D;
                        	box-shadow: 0 5px 20px rgba(0, 0, 0, 0.5);
                        	flex-shrink: 0;
                        	max-height: calc(100vh - 400px);
                        	overflow-y: auto;
                        }

                        .sr2_resultHeader {
                        	display: flex;
                        	align-items: flex-start;
                        	gap: 25px;
                        	margin-bottom: 25px;
                        }

                        .sr2_gamePoster {
                        	width: 100%;
                        	max-width: 320px;
                        	border-radius: 6px;
                        	overflow: hidden;
                        	box-shadow: 0 3px 10px rgba(0, 0, 0, 0.5);
                        	align-self: flex-start;
                        	border: 1px solid #21262D;
                        }

                        .sr2_gamePoster img {
                        	width: 100%;
                        	height: auto;
                        	display: block;
                        }

                        .sr2_gameInfoMain {
                        	flex-grow: 1;
                        }

                        .sr2_gameTitle {
                        	font-size: 26px;
                        	color: #C9D1D9;
                        	margin: 0 0 12px 0;
                        	font-weight: 600;
                        	line-height: 1.2;
                        }

                        .sr2_reviewRating {
                        	display: inline-flex;
                        	align-items: center;
                        	gap: 8px;
                        	background: rgba(0, 0, 0, 0.3);
                        	color: #C9D1D9;
                        	padding: 6px 12px;
                        	border-radius: 6px;
                        	font-size: 14px;
                        	margin-bottom: 15px;
                        	border: 1px solid #30363D;
                        }

                        .sr2_reviewRating.positive {
                        	background: rgba(35, 134, 54, 0.2);
                        	color: #56d364;
                        	border-color: rgba(56, 139, 253, 0.3);
                        }

                        .sr2_reviewRating.mixed {
                        	background: rgba(187, 128, 9, 0.2);
                        	color: #e3b341;
                        	border-color: rgba(187, 128, 9, 0.4);
                        }

                        .sr2_reviewRating.negative {
                        	background: rgba(248, 81, 73, 0.15);
                        	color: #f85149;
                        	border-color: rgba(248, 81, 73, 0.3);
                        }

                        .sr2_steamLink {
                        	display: inline-flex;
                        	align-items: center;
                        	gap: 8px;
                        	color: #58A6FF;
                        	text-decoration: none;
                        	font-size: 14px;
                        	margin-top: 10px;
                        	padding: 9px 14px;
                        	border: 1px solid #388BFD;
                        	border-radius: 6px;
                        	transition: background-color 0.2s, color 0.2s;
                        	font-weight: 500;
                        }

                        .sr2_steamLink:hover {
                        	background-color: #388BFD;
                        	color: #ffffff;
                        }

                        .sr2_icon {
                        	width: 15px;
                        	height: 15px;
                        	margin-right: 6px;
                        }

                        .sr2_gameContent {
                        	display: grid;
                        	grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
                        	gap: 25px;
                        	margin-top: 20px;
                        }

                        .sr2_gameDescription {
                        	line-height: 1.6;
                        	font-size: 14px;
                        	color: #8B949E;
                        	margin-bottom: 20px;
                        	max-height: 150px;
                        	overflow-y: auto;
                        	padding-right: 8px;
                        }

                        .sr2_gameDescription::-webkit-scrollbar {
                        	width: 6px;
                        }

                        .sr2_gameDescription::-webkit-scrollbar-track {
                        	background: #0D1117;
                        	border-radius: 3px;
                        }

                        .sr2_gameDescription::-webkit-scrollbar-thumb {
                        	background: #30363D;
                        	border-radius: 3px;
                        }

                        .sr2_gameTags {
                        	display: flex;
                        	flex-wrap: wrap;
                        	gap: 8px;
                        	margin-bottom: 20px;
                        }

                        .sr2_tag {
                        	background: rgba(88, 166, 255, 0.1);
                        	color: #58A6FF;
                        	padding: 5px 10px;
                        	border-radius: 15px;
                        	font-size: 12px;
                        	border: 1px solid rgba(88, 166, 255, 0.2);
                        }

                        .sr2_launchButton {
                        	display: inline-flex;
                        	align-items: center;
                        	gap: 10px;
                        	padding: 12px 25px;
                        	text-decoration: none;
                        	margin-top: 15px;
                        	font-weight: 600;
                        	font-size: 16px;
                        }

                        .sr2_gameDetails {
                        	background: #0D1117;
                        	padding: 20px;
                        	border-radius: 6px;
                        	border: 1px solid #21262D;
                        }

                        .sr2_detailItem {
                        	margin-bottom: 14px;
                        	padding-bottom: 14px;
                        	border-bottom: 1px solid #21262D;
                        }

                        .sr2_detailItem:last-child {
                        	border-bottom: none;
                        	margin-bottom: 0;
                        	padding-bottom: 0;
                        }

                        .sr2_detailLabel {
                        	color: #58A6FF;
                        	font-size: 13px;
                        	margin-bottom: 5px;
                        	display: block;
                        	font-weight: 500;
                        	text-transform: uppercase;
                        	letter-spacing: 0.5px;
                        }

                        .sr2_detailValue {
                        	color: #C9D1D9;
                        	font-size: 14px;
                        }

                        .sr2_confirmModal {
                        	position: fixed;
                        	top: 0;
                        	left: 0;
                        	width: 100%;
                        	height: 100%;
                        	background-color: rgba(0, 0, 0, 0.7);
                        	z-index: 20003;
                        	display: flex;
                        	align-items: center;
                        	justify-content: center;
                        }

                        .sr2_confirmModalContent {
                        	background-color: #161B22;
                        	padding: 20px;
                        	border-radius: 6px;
                        	border: 1px solid #30363D;
                        	text-align: center;
                        }

                        .sr2_confirmModalContent h4 {
                        	margin-top: 0;
                        	margin-bottom: 15px;
                        	color: #C9D1D9;
                        }

                        .sr2_confirmModalContent p {
                        	margin-bottom: 20px;
                        	font-size: 14px;
                        }

                        .sr2_confirmModalActions button {
                        	margin: 0 5px;
                        }

                        @media (max-width: 900px) {
                        	#sr2_mainContainer {
                        		flex-direction: column;
                        	}

                        	#sr2_leftControlsPanel {
                        		width: 100%;
                        		border-right: none;
                        		border-bottom: 1px solid #21262D;
                        		max-height: 40vh;
                        		overflow-y: auto;
                        	}

                        	#sr2_rightContentArea {
                        		padding-top: 10px;
                        		flex-grow: 1;
                        	}

                        	.sr2_gameContent {
                        		grid-template-columns: 1fr;
                        	}

                        	#sr2_viewFlipper {
                        		min-height: 250px;
                        	}
                        }

                        @media (max-width: 600px) {
                        	#sr2_headerPanel {
                        		padding: 10px 15px;
                        	}

                        	#sr2_modalTitle {
                        		font-size: 18px;
                        	}

                        	#sr2_leftControlsPanel,
                        	#sr2_rightContentArea {
                        		padding: 15px;
                        	}

                        	.sr2_resultHeader {
                        		flex-direction: column;
                        		align-items: center;
                        	}

                        	.sr2_gamePoster {
                        		max-width: 100%;
                        	}

                        	.sr2_result {
                        		max-height: calc(100vh - 350px);
                        	}

                        	#sr2_viewFlipper {
                        		min-height: 200px;
                        	}
                        }

                        #sr2_stelicasRouletteHelpModal {
                        	background-color: rgba(13, 17, 23, 0.9);
                        	backdrop-filter: blur(5px);
                        }

                        #sr2_stelicasRouletteHelpModal>div {
                        	background-color: #161B22;
                        	color: #C9D1D9;
                        	border: 1px solid #30363D;
                        	box-shadow: 0 8px 30px rgba(0, 0, 0, 0.6);
                        }

                        #sr2_stelicasRouletteHelpModal h3 {
                        	color: #58A6FF;
                        }

                        #sr2_stelicasRouletteHelpModal a {
                        	color: #58A6FF;
                        }

                        #sr2_stelicasRouletteHelpModal button.sr2_btnPrimary {
                        	background-color: #238636;
                        	border-color: #2ea043;
                        	color: #ffffff;
                        }

                        #sr2_stelicasRouletteHelpModal button.sr2_btnPrimary:hover:not(:disabled) {
                        	background-color: #2ea043;
                        	border-color: #3fb950;
                        }
                `;
                document.head.appendChild(style);
            }

            sr2_addModalStyles();
            sr2_addRouletteBlock();

        })();
    }

    // Скрипт "Наблюдатель": Отслеживание изменений дат/статуса игр (вишлист/библиотека) и показ календаря релизов
    if (scriptsConfig.Sledilka) {
        (function() {
            'use strict';

            function runDataMigration() {
                const MIGRATION_FLAG = 'USE_Sledilka_migrated_v2_from_wishlistTracker';
                if (GM_getValue(MIGRATION_FLAG, false)) {
                    return;
                }

                const OLD_KEYS = {
                    NOTIFICATIONS: 'USE_Wishlist_notifications',
                    GAME_DATA: 'USE_Wishlist_gameData',
                    LAST_UPDATE: 'USE_Wishlist_lastUpdate'
                };

                const NEW_KEYS = {
                    NOTIFICATIONS: 'USE_Sledilka_notifications',
                    WISHLIST_GAME_DATA: 'USE_Sledilka_wishlistGameData',
                    LAST_UPDATE_WISHLIST: 'USE_Sledilka_lastUpdateWishlist'
                };

                const oldGameData = GM_getValue(OLD_KEYS.GAME_DATA);
                const newGameData = GM_getValue(NEW_KEYS.WISHLIST_GAME_DATA);

                if (oldGameData !== undefined && newGameData !== undefined) {
                    GM_deleteValue(OLD_KEYS.GAME_DATA);
                    GM_deleteValue(OLD_KEYS.NOTIFICATIONS);
                    GM_deleteValue(OLD_KEYS.LAST_UPDATE);
                    GM_setValue(MIGRATION_FLAG, true);
                    return;
                }

                if (oldGameData !== undefined && newGameData === undefined) {
                    const oldNotifications = GM_getValue(OLD_KEYS.NOTIFICATIONS);
                    const oldLastUpdate = GM_getValue(OLD_KEYS.LAST_UPDATE);

                    GM_setValue(NEW_KEYS.WISHLIST_GAME_DATA, oldGameData);

                    if (oldNotifications !== undefined && Array.isArray(oldNotifications)) {
                        const migratedNotifications = oldNotifications.map(n => {
                            let newNotif = { ...n };
                            if (newNotif.hasOwnProperty('wtread')) {
                                newNotif.read = newNotif.wtread;
                                delete newNotif.wtread;
                            } else {
                                newNotif.read = false;
                            }
                            if (!newNotif.source) {
                                newNotif.source = 'wishlist';
                            }
                            return newNotif;
                        });
                        GM_setValue(NEW_KEYS.NOTIFICATIONS, migratedNotifications);
                    }
                    if (oldLastUpdate !== undefined) {
                        GM_setValue(NEW_KEYS.LAST_UPDATE_WISHLIST, oldLastUpdate);
                    }

                    GM_deleteValue(OLD_KEYS.GAME_DATA);
                    GM_deleteValue(OLD_KEYS.NOTIFICATIONS);
                    GM_deleteValue(OLD_KEYS.LAST_UPDATE);

                    GM_setValue(MIGRATION_FLAG, true);
                    return;
                }
                GM_setValue(MIGRATION_FLAG, true);
            }
            runDataMigration();

            const SLEDILKA_PREFIX = 'USE_Sledilka_';
            const STORAGE_KEYS = {
                LAST_UPDATE_WISHLIST: SLEDILKA_PREFIX + 'lastUpdateWishlist',
                LAST_UPDATE_LIBRARY: SLEDILKA_PREFIX + 'lastUpdateLibrary',
                NOTIFICATIONS: SLEDILKA_PREFIX + 'notifications',
                WISHLIST_GAME_DATA: SLEDILKA_PREFIX + 'wishlistGameData',
                OWNED_APPS_DATA: SLEDILKA_PREFIX + 'ownedAppsData',
                OWNED_CHECKED_V2: SLEDILKA_PREFIX + 'ownedCheckedV2',
                UPDATE_SETTINGS: SLEDILKA_PREFIX + 'updateSettings'
            };

            const calendarIcon = `<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M19 4h-1V2h-2v2H8V2H6v2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM5 20V10h14v10H5zM9 14H7v-2h2v2zm4 0h-2v-2h2v2zm4 0h-2v-2h2v2zm-8 4H7v-2h2v2zm4 0h-2v-2h2v2zm4 0h-2v-2h2v2z"/></svg>`;
            const storageIcon = `<svg width="20" height="20" version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" xml:space="preserve"><style type="text/css">.st0_sledilka_storage{fill:#C6D4DF;}</style><g><path class="st0_sledilka_storage" d="M0,17.067V153.6h512V17.067H0z M110.933,110.925h-51.2v-51.2h51.2V110.925z"/><path class="st0_sledilka_storage" d="M0,324.267h512V187.733H0V324.267z M59.733,230.391h51.2v51.2h-51.2V230.391z"/><path class="st0_sledilka_storage" d="M0,494.933h512V358.4H0V494.933z M59.733,401.058h51.2v51.2h-51.2V401.058z"/></g></svg>`;
            const settingsIcon = `<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23-.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"/></svg>`;
            const envelopeIcons = {
                unread: `<svg width="20" height="16" viewBox="0 0 32 32" fill="#67c1f5" xmlns="http://www.w3.org/2000/svg"><path d="M16.015 18.861l-4.072-3.343-8.862 10.463h25.876l-8.863-10.567-4.079 3.447zM29.926 6.019h-27.815l13.908 11.698 13.907-11.698zM20.705 14.887l9.291 11.084v-18.952l-9.291 7.868zM2.004 7.019v18.952l9.291-11.084-9.291-7.868z"/></svg>`,
                read: `<svg width="20" height="16" viewBox="0 0 32 32" fill="#8f98a0" xmlns="http://www.w3.org/2000/svg"><path d="M20.139 18.934l9.787-7.999-13.926-9.833-13.89 9.833 9.824 8.032 8.205-0.033zM12.36 19.936l-9.279 10.962h25.876l-9.363-10.9-7.234-0.062zM20.705 19.803l9.291 11.084v-18.952l-9.291 7.868zM2.004 11.935v18.952l9.291-11.084-9.291-7.868z"/></svg>`
            };

            const BATCH_SIZE = 200;
            const MILLISECONDS_IN_HOUR = 60 * 60 * 1000;
            const API_RETRY_DELAY = 3000;
            const MAX_API_RETRIES = 2;

            let notifications = GM_getValue(STORAGE_KEYS.NOTIFICATIONS, []);
            let isPanelOpen = false;
            let updateInProgress = false;
            let positionCheckInterval;
            let mutationObserver;

            function runOneTimeMigration() {
                if (GM_getValue('USE_Sledilka_ownedChecked') !== undefined) {
                    GM_deleteValue('USE_Sledilka_ownedChecked');
                }
                if (GM_getValue('USE_Sledilka_lastUpdate') !== undefined) {
                    GM_deleteValue('USE_Sledilka_lastUpdate');
                }
            }
            runOneTimeMigration();

            GM_addStyle(`
                .sledilka-container {
                    position: absolute;
                    visibility: hidden;
                    z-index: 999;
                    background-color: rgba(23, 26, 33, 0.9);
                    border-radius: 3px;
                    color: #c7d5e0;
                    font-family: "Motiva Sans", Sans-serif;
                    font-size: 13px;
                    line-height: 1.2;
                }

                .sledilka-button {
                    color: #c6d4df;
                    background: rgba(103, 193, 245, 0.1);
                    padding: 7px 12px;
                    border-radius: 2px;
                    cursor: pointer;
                    font-size: 13px;
                    display: flex;
                    align-items: center;
                    gap: 8px;
                    transition: all 0.2s ease;
                    user-select: none;
                    -webkit-user-select: none;
                    -moz-user-select: none;
                    -ms-user-select: none;
                }

                .sledilka-button:hover {
                    background: rgba(103, 193, 245, 0.2);
                }

                .sledilka-notification-badge {
                    background: #67c1f5;
                    color: #1b2838;
                    border-radius: 3px;
                    padding: 3px 6px;
                    font-size: 14px;
                    font-weight: bold;
                    min-width: 20px;
                    text-align: center;
                    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
                }

                .sledilka-status-indicator-group {
                    display: flex;
                    gap: 4px;
                }

                .sledilka-status-indicator {
                    background: #4a5562;
                    color: #c6d4df;
                    border-radius: 3px;
                    padding: 3px 6px;
                    font-size: 12px;
                    font-weight: bold;
                    min-width: 40px;
                    text-align: center;
                    transition: all 0.3s ease;
                    cursor: help;
                }

                .status-ok {
                    background: #4a5562;
                }

                .status-warning {
                    background: #4a5562;
                }

                .status-alert1 {
                    background: #665c3a;
                    color: #ffd700;
                }

                .status-alert2 {
                    background: #804d4d;
                    color: #ffb3b3;
                }

                .status-critical {
                    background: #e60000;
                    color: #fff;
                }

                .status-unknown {
                    background: #1b2838;
                    color: #8f98a0;
                }

                .sledilka-panel {
                    position: fixed;
                    right: 132px;
                    top: 50px;
                    background: #1b2838;
                    border: 1px solid #67c1f5;
                    width: 550px;
                    max-height: 70vh;
                    overflow-y: auto;
                    z-index: 9999;
                    box-shadow: 0 0 15px rgba(0, 0, 0, 0.5);
                    display: none;
                    flex-direction: column;
                }

                .sledilka-panel-header {
                    padding: 12px 15px;
                    background: #171a21;
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    flex-shrink: 0;
                    border-bottom: 1px solid #2a475e;
                }

                .sledilka-panel-title {
                    font-size: 16px;
                    font-weight: 500;
                    color: #67c1f5;
                }

                .sledilka-panel-controls {
                    display: flex;
                    gap: 5px;
                    align-items: center;
                }

                .sledilka-panel-controls button {
                    background: rgba(30, 45, 60, 0.7);
                    border: none;
                    color: #c6d4df;
                    padding: 6px 10px;
                    cursor: pointer;
                    border-radius: 2px;
                    font-size: 12px;
                    font-weight: 400;
                    text-transform: uppercase;
                    letter-spacing: 0.5px;
                    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
                    transition: background 0.2s ease, box-shadow 0.2s ease;
                    display: inline-flex;
                    align-items: center;
                    gap: 4px;
                }

                .sledilka-panel-controls button:hover:not(:disabled) {
                    background: rgba(40, 60, 80, 0.9);
                    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.4);
                }

                .sledilka-panel-controls button:active:not(:disabled) {
                    background: rgba(30, 45, 60, 0.6);
                    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
                    transform: translateY(1px);
                }

                .sledilka-panel-controls button:disabled {
                    opacity: 0.5;
                    cursor: not-allowed;
                }

                .sledilka-panel-controls button svg {
                    width: 16px;
                    height: 16px;
                }

                .sledilka-settings-container {
                    position: relative;
                }

                .sledilka-settings-btn {
                    padding: 6px;
                }

                .sledilka-settings-dropdown {
                    display: none;
                    position: fixed;
                    background-color: #171a21;
                    border: 1px solid #2a475e;
                    border-radius: 3px;
                    padding: 10px;
                    z-index: 10000;
                    width: 250px;
                    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
                }

                .sledilka-settings-dropdown label {
                    display: block;
                    margin-bottom: 5px;
                    color: #c6d4df;
                    font-size: 13px;
                    cursor: pointer;
                }

                .sledilka-settings-dropdown label.disabled {
                    color: #5c626a;
                    cursor: default;
                }

                .sledilka-settings-dropdown input {
                    margin-right: 5px;
                    vertical-align: middle;
                    accent-color: #67c1f5;
                }

                #sledilkaLibrarySubSettings {
                    padding-left: 20px;
                    margin-top: 5px;
                    border-top: 1px solid #2a475e;
                    padding-top: 5px;
                }

                .sledilka-panel-content {
                    flex-grow: 1;
                    overflow-y: auto;
                    scrollbar-width: thin;
                    scrollbar-color: #4b6f9c #1b2838;
                }

                .sledilka-panel-content::-webkit-scrollbar {
                    width: 6px;
                }

                .sledilka-panel-content::-webkit-scrollbar-track {
                    background: #1b2838;
                }

                .sledilka-panel-content::-webkit-scrollbar-thumb {
                    background-color: #4b6f9c;
                    border-radius: 3px;
                }

                .sledilka-notification-item {
                    padding: 12px 15px;
                    border-bottom: 1px solid #2a475e;
                    position: relative;
                    transition: opacity 0.3s;
                }

                .sledilka-notification-content {
                    display: flex;
                    gap: 12px;
                }

                .sledilka-notification-image {
                    width: 80px;
                    height: 45px;
                    object-fit: cover;
                    flex-shrink: 0;
                    border-radius: 2px;
                }

                .sledilka-notification-text {
                    flex-grow: 1;
                    padding-right: 30px;
                    font-size: 13px;
                }

                .sledilka-notification-game-title {
                    color: #66c0f4;
                    font-weight: bold;
                    text-decoration: none;
                    display: block;
                    margin-bottom: 4px;
                    font-size: 14px;
                }

                .sledilka-notification-type {
                    font-size: 11px;
                    color: #8f98a0;
                    margin-bottom: 4px;
                    text-transform: uppercase;
                }

                .sledilka-notification-details {
                    color: #c6d4df;
                    margin-bottom: 4px;
                    line-height: 1.4;
                }

                .sledilka-notification-timestamp {
                    font-size: 11px;
                    color: #556772;
                }

                .sledilka-notification-unread {
                    background: rgba(102, 192, 244, 0.1);
                }

                .sledilka-notification-controls {
                    position: absolute;
                    right: 10px;
                    top: 10px;
                    display: flex;
                    gap: 8px;
                }

                .sledilka-notification-control {
                    cursor: pointer;
                    width: 18px;
                    height: 18px;
                    opacity: 0.7;
                    transition: opacity 0.2s;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                }

                .sledilka-notification-control:hover {
                    opacity: 1;
                }

                .sledilka-delete-btn {
                    color: #6C7781;
                    font-size: 16px;
                    font-weight: bold;
                    line-height: 1;
                    transition: color 0.2s ease, transform 0.1s ease;
                }

                .sledilka-delete-btn:hover {
                    color: #8F98A0;
                }

                .sledilka-delete-btn:active {
                    color: #800000;
                    transform: scale(0.9);
                }

                .sledilka-loading-indicator,
                .sledilka-error-indicator {
                    color: #67c1f5;
                    text-align: center;
                    padding: 10px;
                    font-size: 13px;
                }

                .sledilka-error-indicator {
                    color: #ff4747;
                }

                .sledilka-progress-bar {
                    height: 4px;
                    background-color: #2a475e;
                    width: 100%;
                    margin-top: -1px;
                }

                .sledilka-progress-bar-inner {
                    height: 100%;
                    width: 0%;
                    background-color: #67c1f5;
                    transition: width 0.3s ease;
                }

                .calendar-wtmodal.active {
                    display: flex;
                    flex-direction: column;
                }

                .calendar-wtmodal {
                    position: fixed;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    width: 80%;
                    height: 80vh;
                    background: #1b2838;
                    border: 1px solid #67c1f5;
                    box-shadow: 0 0 30px rgba(0, 0, 0, 0.7);
                    z-index: 100000;
                    display: none;
                    padding: 20px;
                    overflow: hidden;
                }

                .calendar-header {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    padding-bottom: 15px;
                    border-bottom: 1px solid #2a475e;
                    margin-bottom: 15px;
                }

                .calendar-title {
                    color: #67c1f5;
                    font-size: 25px;
                }

                .calendar-close {
                    cursor: pointer;
                    color: #8f98a0;
                    font-size: 54px;
                    padding: 5px;
                }

                .calendar-close:hover {
                    color: #67c1f5;
                }

                .calendar-content {
                    flex-grow: 1;
                    overflow-y: auto;
                    padding-right: 10px;
                    scrollbar-width: thin;
                    scrollbar-color: #4b6f9c #1b2838;
                }

                .calendar-content::-webkit-scrollbar {
                    width: 6px;
                }

                .calendar-content::-webkit-scrollbar-track {
                    background: #1b2838;
                }

                .calendar-content::-webkit-scrollbar-thumb {
                    background-color: #4b6f9c;
                    border-radius: 3px;
                }

                .calendar-month {
                    margin-bottom: 30px;
                }

                .month-header {
                    color: #67c1f5;
                    font-size: 24px;
                    margin-bottom: 15px;
                }

                .calendar-grid {
                    display: grid;
                    grid-template-columns: repeat(7, 1fr);
                    gap: 2px;
                    font-size: 14px;
                    font-weight: 500;
                }

                .calendar-grid>div:not(.calendar-day) {
                    padding: 10px 0;
                    background: #1b2838;
                    color: #67c1f5;
                    border-bottom: 2px solid #67c1f5;
                    text-transform: uppercase;
                    text-align: center;
                }

                .calendar-day {
                    background: #2a475e;
                    min-height: 69px;
                    padding: 20px 5px 5px 5px;
                    position: relative;
                    display: flex;
                    flex-direction: column;
                    gap: 3px;
                }

                .day-number {
                    position: absolute;
                    top: 3px;
                    right: 5px;
                    color: #8f98a0;
                    font-size: 14px;
                    z-index: 100003
                }

                .calendar-game {
                    display: flex;
                    position: relative;
                    padding-bottom: 8px;
                    align-items: center;
                    margin: 5px 0;
                    padding: 5px;
                    background: rgba(42, 71, 94, 0.5);
                    border-radius: 3px;
                    transition: background 0.2s;
                    text-decoration: none !important;
                    color: inherit;
                }

                .calendar-game:not(:last-child)::after {
                    content: "";
                    position: absolute;
                    bottom: -7px;
                    left: 0;
                    right: 0;
                    height: 1px;
                    background: linear-gradient(90deg, transparent 0%, rgba(103, 193, 245, 0.3) 20%, rgba(103, 193, 245, 0.4) 50%, rgba(103, 193, 245, 0.3) 80%, transparent 100%);
                    margin-top: 8px;
                }

                .calendar-game-approximate .calendar-game-title {
                    color: #FFD580 !important;
                    opacity: 0.9;
                }

                .calendar-game:hover {
                    background: rgba(67, 103, 133, 0.5);
                }

                .calendar-game-image {
                    width: 100px;
                    height: 45px;
                    object-fit: cover;
                    margin-right: 10px;
                    flex-shrink: 0;
                    border-radius: 2px;
                }

                .calendar-game-title {
                    color: #c6d4df;
                    font-size: 13px;
                    line-height: 1.2;
                }

                .load-more-months {
                    text-align: center;
                    padding: 15px;
                }

                .load-more-btn {
                    background: rgba(103, 193, 245, 0.1);
                    color: #67c1f5;
                    border: none;
                    padding: 10px 20px;
                    cursor: pointer;
                    border-radius: 3px;
                }

                .load-more-btn:hover {
                    background: rgba(103, 193, 245, 0.2);
                }

                .wt-tooltip {
                    display: flex !important;
                    position: relative;
                }

                .wt-tooltip .wt-tooltiptext {
                    visibility: hidden;
                    width: 220px;
                    background-color: #171a21;
                    color: #c6d4df;
                    text-align: center;
                    border-radius: 3px;
                    padding: 12px;
                    position: absolute;
                    z-index: 1;
                    left: 100%;
                    margin-left: 2px;
                    opacity: 0;
                    transition: opacity 0.3s;
                    border: 1px solid #67c1f5;
                }

                .wt-tooltip:hover .wt-tooltiptext {
                    visibility: visible;
                    opacity: 1;
                }

                .sledilka-storage-modal {
                    display: none;
                    position: fixed;
                    z-index: 100001;
                    left: 0;
                    top: 0;
                    width: 100%;
                    height: 100%;
                    overflow: auto;
                    background-color: rgba(0, 0, 0, 0.7);
                    backdrop-filter: blur(3px);
                }

                .sledilka-storage-modal-content {
                    background-color: #1f2c3a;
                    margin: 15% auto;
                    padding: 25px;
                    border: 1px solid #67c1f5;
                    width: 80%;
                    max-width: 500px;
                    border-radius: 5px;
                    text-align: center;
                    position: relative;
                }

                .sledilka-storage-modal-close {
                    color: #aaa;
                    position: absolute;
                    top: 10px;
                    right: 15px;
                    font-size: 28px;
                    font-weight: bold;
                    cursor: pointer;
                }

                .sledilka-storage-modal-close:hover {
                    color: #fff;
                }

                .sledilka-storage-modal h3 {
                    margin-top: 0;
                    color: #67c1f5;
                    font-size: 18px;
                    margin-bottom: 20px;
                }

                .sledilka-storage-modal button {
                    background-color: #4a5562;
                    color: #c6d4df;
                    border: 1px solid #67c1f5;
                    padding: 12px 20px;
                    margin: 10px;
                    cursor: pointer;
                    border-radius: 3px;
                    font-size: 14px;
                    transition: background-color 0.2s;
                    min-width: 200px;
                }

                .sledilka-storage-modal button:hover {
                    background-color: #5a6978;
                }
                `);

                function retryPositionCheck() {
                    if (positionCheckInterval) clearInterval(positionCheckInterval);
                    positionCheckInterval = setInterval(createSledilkaUI.positionButtonSafely, 300);
                    setTimeout(() => {
                        if (positionCheckInterval) clearInterval(positionCheckInterval);
                    }, 10000);
                }

                function stopPositionTracking() {
                    if (positionCheckInterval) {
                        clearInterval(positionCheckInterval);
                        positionCheckInterval = null;
                    }
                }

                function setupMutationObserver(target) {
                    if (mutationObserver) mutationObserver.disconnect();
                    mutationObserver = new MutationObserver((mutations) => {
                        let needsUpdate = mutations.some(mutation => {
                            return mutation.type === 'attributes' ||
                                mutation.addedNodes.length > 0 ||
                                mutation.removedNodes.length > 0;
                        });
                        if (needsUpdate) {
                            if (typeof createSledilkaUI.positionButtonSafely === 'function') {
                                createSledilkaUI.positionButtonSafely();
                            }
                        }
                    });
                    if (target) {
                        mutationObserver.observe(target, {
                            childList: true,
                            subtree: true,
                            attributes: true,
                            attributeFilter: ['style', 'class']
                        });
                    }
                }

                function createSledilkaUI() {
                    const initialGlobalActionsContainer = document.getElementById('global_actions');
                    if (!initialGlobalActionsContainer) { return; }
                    const initialAvatarLink = initialGlobalActionsContainer.querySelector('a.user_avatar');
                    if (!initialAvatarLink) { return; }
                    if (document.querySelector('.sledilka-container')) { return; }

                    const updateSettings = GM_getValue(STORAGE_KEYS.UPDATE_SETTINGS, {
                        wishlist: true,
                        library: true,
                        recheckRussian: true,
                        recheckPartial: false
                    });

                    const container = $(`
                        <div class="sledilka-container">
                            <div class="sledilka-button">
                                <span>Наблюдатель</span>
                                <div class="sledilka-status-indicator-group">
                                     <div class="sledilka-status-indicator sledilka-status-wishlist status-unknown" title="Время обновления списка желаемого">Ж:??</div>
                                     <div class="sledilka-status-indicator sledilka-status-library status-unknown" title="Время обновления библиотеки">Б:??</div>
                                </div>
                                <div class="sledilka-notification-badge">${getUnreadCount()}</div>
                            </div>
                            <div class="sledilka-panel">
                                 <div class="sledilka-panel-header">
                                    <div class="sledilka-panel-title">Уведомления</div>
                                    <div class="sledilka-panel-controls">
                                        <div class="sledilka-settings-container">
                                            <button class="sledilka-settings-btn" title="Настройки обновления">${settingsIcon}</button>
                                            <div class="sledilka-settings-dropdown">
                                                <label><input type="checkbox" id="sledilkaUpdateWishlist" ${updateSettings.wishlist ? 'checked' : ''}> Список желаемого</label>
                                                <label><input type="checkbox" id="sledilkaUpdateLibrary" ${updateSettings.library ? 'checked' : ''}> Библиотека</label>
                                                <div id="sledilkaLibrarySubSettings">
                                                    <label><input type="checkbox" id="sledilkaRecheckRussian" ${updateSettings.recheckRussian ? 'checked' : ''}> Перепроверять игры с русским</label>
                                                    <label id="sledilkaRecheckPartialLabel"><input type="checkbox" id="sledilkaRecheckPartial" ${updateSettings.recheckPartial ? 'checked' : ''}> ...только без полной локализации</label>
                                                </div>
                                            </div>
                                        </div>
                                        <button class="sledilka-refresh-btn">⟳ Обновить</button>
                                        <button class="sledilka-clear-btn">× Очистить</button>
                                        <button class="sledilka-calendar-btn">${calendarIcon}</button>
                                        <button class="sledilka-storage-btn">${storageIcon}</button>
                                    </div>
                                </div>
                                 <div class="sledilka-progress-bar"><div class="sledilka-progress-bar-inner"></div></div>
                                 <div class="sledilka-panel-content"></div>
                            </div>
                        </div>`);
                    initialGlobalActionsContainer.appendChild(container[0]);

                    function positionButtonSafely() {
                        const currentGlobalActionsContainer = document.getElementById('global_actions');
                        if (!currentGlobalActionsContainer || !container[0] || !container[0].isConnected) { stopPositionTracking(); return; }
                        const currentAvatarLink = currentGlobalActionsContainer.querySelector('a.user_avatar');
                        if (!currentAvatarLink) { retryPositionCheck(); return; }
                        const isVisible = (element) => {
                            if (!element) return false;
                            const rect = element.getBoundingClientRect();
                            return !(rect.width === 0 && rect.height === 0 && element.offsetWidth === 0 && element.offsetHeight === 0);
                        };
                        if (!isVisible(currentAvatarLink)) { retryPositionCheck(); return; }
                        const avatarRect = currentAvatarLink.getBoundingClientRect();
                        const globalActionsRect = currentGlobalActionsContainer.getBoundingClientRect();
                        const sledilkaViewportTop = avatarRect.top;
                        const sledilkaViewportLeft = avatarRect.right + 45;
                        const sledilkaContainerTop = sledilkaViewportTop - globalActionsRect.top;
                        const sledilkaContainerLeft = sledilkaViewportLeft - globalActionsRect.left;
                        container.css({ top: sledilkaContainerTop + 'px', left: sledilkaContainerLeft + 'px', visibility: 'visible' });
                        setTimeout(() => {
                            if (container[0] && container[0].isConnected && currentAvatarLink && currentAvatarLink.isConnected) {
                                const postRect = container[0].getBoundingClientRect();
                                const liveAvatarRect = currentAvatarLink.getBoundingClientRect();
                                if (postRect.left < liveAvatarRect.right) {
                                    container.css('left', (sledilkaContainerLeft + 50) + 'px');
                                }
                            }
                        }, 100);
                        stopPositionTracking();
                        setupMutationObserver(currentGlobalActionsContainer);
                    }
                    createSledilkaUI.positionButtonSafely = positionButtonSafely;
                    setTimeout(positionButtonSafely, 700);

                    const panel = container.find('.sledilka-panel');
                    container.find('.sledilka-button').on('click', function(e) { e.stopPropagation(); togglePanel(); });
                    container.find('.sledilka-refresh-btn').on('click', (e) => { e.stopPropagation(); if (!updateInProgress) updateData(); });
                    container.find('.sledilka-clear-btn').on('click', (e) => {
                        e.stopPropagation();
                        if (confirm("Вы уверены, что хотите очистить ВСЕ уведомления?")) {
                            notifications = [];
                            GM_setValue(STORAGE_KEYS.NOTIFICATIONS, notifications);
                            updateNotificationPanel();
                            updateBadge();
                            showInfoIndicator("Все уведомления очищены.");
                        }
                    });
                    container.find('.sledilka-calendar-btn').on('click', (e) => { e.stopPropagation(); showCalendarModal(); });
                    container.find('.sledilka-storage-btn').on('click', (e) => { e.stopPropagation(); showStorageModal(); });

                    const settingsBtn = container.find('.sledilka-settings-btn');
                    const settingsDropdown = container.find('.sledilka-settings-dropdown');
                    const libCheck = $('#sledilkaUpdateLibrary');
                    const recheckRuCheck = $('#sledilkaRecheckRussian');
                    const recheckPartialCheck = $('#sledilkaRecheckPartial');
                    const recheckPartialLabel = $('#sledilkaRecheckPartialLabel');
                    const libSubSettings = $('#sledilkaLibrarySubSettings');

                    function toggleSubSettings() {
                        const libIsChecked = libCheck.is(':checked');
                        libSubSettings.toggle(libIsChecked);
                        if (!libIsChecked) {
                            recheckRuCheck.prop('disabled', true);
                            recheckPartialCheck.prop('disabled', true);
                            recheckPartialLabel.addClass('disabled');
                        } else {
                            recheckRuCheck.prop('disabled', false);
                            togglePartialRecheckOption();
                        }
                    }

                    function togglePartialRecheckOption() {
                        const recheckRuIsChecked = recheckRuCheck.is(':checked');
                        if (recheckRuIsChecked || !libCheck.is(':checked')) {
                            recheckPartialCheck.prop('disabled', true);
                            recheckPartialCheck.prop('checked', false);
                            recheckPartialLabel.addClass('disabled');
                        } else {
                            recheckPartialCheck.prop('disabled', false);
                            recheckPartialLabel.removeClass('disabled');
                        }
                    }

                    settingsBtn.on('click', function(e) {
                        e.stopPropagation();
                        if (settingsDropdown.is(':visible')) {
                            settingsDropdown.hide();
                        } else {
                            const btnRect = this.getBoundingClientRect();
                            const dropdownWidth = settingsDropdown.outerWidth();
                            settingsDropdown.css({
                                top: (btnRect.bottom + 5) + 'px',
                                left: (btnRect.right - dropdownWidth) + 'px'
                            }).show();
                        }
                    });

                    settingsDropdown.on('click', function(e) {
                        e.stopPropagation();
                    });

                    $('#sledilkaUpdateWishlist, #sledilkaUpdateLibrary, #sledilkaRecheckRussian, #sledilkaRecheckPartial').on('change', function() {
                        toggleSubSettings();
                        const newSettings = {
                            wishlist: $('#sledilkaUpdateWishlist').is(':checked'),
                            library: $('#sledilkaUpdateLibrary').is(':checked'),
                            recheckRussian: $('#sledilkaRecheckRussian').is(':checked'),
                            recheckPartial: $('#sledilkaRecheckPartial').is(':checked')
                        };
                        GM_setValue(STORAGE_KEYS.UPDATE_SETTINGS, newSettings);
                    });

                    toggleSubSettings();

                    updateNotificationPanel();
                    $(document).on('click', (e) => {
                         const $target = $(e.target);
                         if (isPanelOpen && panel.is(":visible")) {
                             if (!$target.closest('.sledilka-container').length) {
                                 togglePanel(false);
                             }
                         }
                         if(settingsDropdown.is(':visible')) {
                             if (!$target.closest('.sledilka-settings-container').length) {
                                 settingsDropdown.hide();
                             }
                         }
                    });
                }

                function togglePanel() {
                    updateStatusIndicator();
                    const panel = $('.sledilka-panel');
                    panel.toggle();
                    isPanelOpen = !isPanelOpen;
                    if (isPanelOpen) {
                        panel.css('display', 'flex');
                        updateBadge();
                        updateNotificationPanel();
                    }
                }

                function showLoadingIndicator(message = "Обновление данных...") {
                    const panelContent = $('.sledilka-panel-content');
                    panelContent.find('.sledilka-loading-indicator, .sledilka-error-indicator').remove();
                    panelContent.prepend($(`<div class="sledilka-loading-indicator">${message} <span class="spinner"></span></div>`));
                }

                function removeLoadingIndicator() {
                    $('.sledilka-panel-content .sledilka-loading-indicator').remove();
                }

                function showErrorIndicator(message) {
                    const panelContent = $('.sledilka-panel-content');
                    panelContent.find('.sledilka-loading-indicator, .sledilka-error-indicator').remove();
                    const error = $(`<div class="sledilka-error-indicator">${message}</div>`);
                    panelContent.prepend(error);
                    setTimeout(() => error.remove(), 8000);
                }

                function showInfoIndicator(message) {
                    const panelContent = $('.sledilka-panel-content');
                    panelContent.find('.sledilka-loading-indicator, .sledilka-error-indicator').remove();
                    const info = $(`<div class="sledilka-loading-indicator" style="color: #67c1f5;">${message}</div>`);
                    panelContent.prepend(info);
                    setTimeout(() => info.remove(), 4000);
                }

                function updateProgressBar(percentage) {
                    const progressBar = $('.sledilka-progress-bar');
                    const progressBarInner = progressBar.find('.sledilka-progress-bar-inner');
                    if (percentage > 0 && percentage <= 100) {
                        progressBar.show();
                        progressBarInner.css('width', `${percentage}%`);
                    } else {
                        progressBar.hide();
                        progressBarInner.css('width', '0%');
                    }
                }

                function getNotificationType(notification) {
                    if (notification.source === 'wishlist') {
                         if ('oldDate' in notification) return 'wishlist_date';
                         if (notification.changeType === 'ea_status') return 'wishlist_ea';
                         if (notification.changeType === 'ru_lang') return 'wishlist_ru';
                    }
                    if (notification.source === 'library') {
                         if (notification.changeType === 'ea_status') return 'owned_ea';
                         if (notification.changeType === 'ru_lang') return 'owned_ru';
                    }
                    if ('oldDate' in notification) return 'wishlist_date';
                    if (notification.changeType === 'ea_status') return 'owned_ea';
                    if (notification.changeType === 'ru_lang') return 'owned_ru';
                    return 'unknown';
                }

                function getNotificationTitle(type) {
                     switch (type) {
                        case 'wishlist_date': return 'Желаемое (Дата выхода)';
                        case 'wishlist_ea': return 'Желаемое (Ранний доступ)';
                        case 'wishlist_ru': return 'Желаемое (Русский язык)';
                        case 'owned_ea': return 'Библиотека (Ранний доступ)';
                        case 'owned_ru': return 'Библиотека (Русский язык)';
                        default: return 'Уведомление';
                    }
                }

                function getNotificationDetailsHTML(notification, type) {
                    if (type.endsWith('_ru')) {
                        const changeDetails = notification.ruChangeDetails;
                        if (!changeDetails) return 'Изменение в локализации.';

                        const added = [], removed = [];
                        const langMap = { supported: 'Интерфейс', full_audio: 'Озвучка', subtitles: 'Субтитры' };

                        for (const key in changeDetails.added) { if (changeDetails.added[key]) added.push(langMap[key]); }
                        for (const key in changeDetails.removed) { if (changeDetails.removed[key]) removed.push(langMap[key]); }

                        const oldHasAny = Object.values(changeDetails.oldState).some(v => v);
                        const newHasAny = Object.values(changeDetails.newState).some(v => v);

                        let parts = [];
                        if (added.length > 0 && removed.length > 0) {
                            parts.push(`Изменения в локализации:<br><b>Добавлено:</b> ${added.join(', ')}<br><b>Убрано:</b> ${removed.join(', ')}`);
                        } else if (added.length > 0) {
                            if (oldHasAny) {
                                 parts.push(`К русскому языку добавлено:<br><b>${added.join(' + ')}</b>`);
                            } else {
                                 parts.push(`Появился русский язык:<br><b>${added.join(' + ')}</b>`);
                            }
                        } else if (removed.length > 0) {
                            if (newHasAny) {
                                 parts.push(`Локализация урезана:<br><b>Убрано: ${removed.join(', ')}</b>`);
                            } else {
                                 parts.push(`<b>Русский язык удален из игры.</b>`);
                            }
                        }
                        return parts.join('<br>');

                    } else {
                         switch (type) {
                            case 'wishlist_date':
                                return `Дата выхода изменилась:<br>
                                             <span class="old-date">${formatDate(notification.oldDate)}</span> →
                                             <span class="new-date">${formatDate(notification.newDate)}</span>`;
                            case 'wishlist_ea':
                            case 'owned_ea':
                                return `Игра вышла из раннего доступа!`;
                            default:
                                return 'Детали неизвестны';
                        }
                    }
                }

                function updateNotificationPanel() {
                    const panelContent = $('.sledilka-panel-content');
                    if (!panelContent.length) return;
                    panelContent.find('.sledilka-notification-item, .sledilka-loading-indicator, .sledilka-error-indicator').remove();
                    $('.sledilka-panel-title').text(`Уведомления (${notifications.length})`);
                    notifications.sort((a, b) => {
                        if (a.read === b.read) {
                            return b.timestamp - a.timestamp;
                        }
                        return a.read ? 1 : -1;
                    });
                    if (notifications.length === 0) {
                        panelContent.append('<div class="sledilka-loading-indicator" style="color: #8f98a0;">Нет новых уведомлений</div>');
                        return;
                    }
                    notifications.slice(0, 5000).forEach((notification, index) => {
                        const notificationType = getNotificationType(notification);
                        const imageUrl = notification.header ?
                            `https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/${notification.appid}/${notification.header}` :
                            `https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/${notification.appid}/header.jpg`;
                        const item = $(`
                            <div class="sledilka-notification-item ${notification.read ? '' : 'sledilka-notification-unread'}" data-index="${index}">
                                <div class="sledilka-notification-controls">
                                    <div class="sledilka-toggle-read-btn sledilka-notification-control" title="${notification.read ? 'Пометить как непрочитанное' : 'Пометить как прочитанное'}">
                                        ${notification.read ? envelopeIcons.read : envelopeIcons.unread}
                                    </div>
                                    <div class="sledilka-delete-btn sledilka-notification-control" title="Удалить уведомление">X</div>
                                </div>
                                <div class="sledilka-notification-content">
                                    <a href="https://store.steampowered.com/app/${notification.appid}" target="_blank">
                                        <img src="${imageUrl}"
                                             class="sledilka-notification-image" loading="lazy"
                                             onerror="this.onerror=null; this.src='https://via.placeholder.com/80x45?text=No+Img'; this.style.objectFit='contain';">
                                    </a>
                                    <div class="sledilka-notification-text">
                                        <div class="sledilka-notification-type">${getNotificationTitle(notificationType)}</div>
                                        <a href="https://store.steampowered.com/app/${notification.appid}"
                                           class="sledilka-notification-game-title" target="_blank">
                                            ${notification.name || `Игра #${notification.appid}`}
                                        </a>
                                        <div class="sledilka-notification-details">
                                            ${getNotificationDetailsHTML(notification, notificationType)}
                                        </div>
                                        <div class="sledilka-notification-timestamp">
                                            Обнаружено: ${new Date(notification.timestamp).toLocaleString()}
                                        </div>
                                    </div>
                                </div>
                            </div>
                        `);
                        item.find('.sledilka-delete-btn').on('click', (e) => {
                            e.stopPropagation();
                            const itemIndex = parseInt($(e.target).closest('.sledilka-notification-item').data('index'));
                            if (!isNaN(itemIndex) && itemIndex >= 0 && itemIndex < notifications.length) {
                                notifications.splice(itemIndex, 1);
                                GM_setValue(STORAGE_KEYS.NOTIFICATIONS, notifications);
                                item.fadeOut(300, () => {
                                    updateNotificationPanel();
                                    updateBadge();
                                });
                            } else {
                                console.error("Ошибка удаления: неверный индекс", itemIndex);
                            }
                        });
                        item.find('.sledilka-toggle-read-btn').on('click', (e) => {
                            e.stopPropagation();
                            const itemIndex = parseInt($(e.target).closest('.sledilka-notification-item').data('index'));
                            if (!isNaN(itemIndex) && itemIndex >= 0 && itemIndex < notifications.length) {
                                notifications[itemIndex].read = !notifications[itemIndex].read;
                                GM_setValue(STORAGE_KEYS.NOTIFICATIONS, notifications);
                                item.toggleClass('sledilka-notification-unread', !notifications[itemIndex].read);
                                $(e.currentTarget).html(notifications[itemIndex].read ? envelopeIcons.read : envelopeIcons.unread);
                                $(e.currentTarget).attr('title', notifications[itemIndex].read ? 'Пометить как непрочитанное' : 'Пометить как прочитанное');
                                updateBadge();
                            } else {
                                console.error("Ошибка чтения/нечтения: неверный индекс", itemIndex);
                            }
                        });
                        panelContent.append(item);
                    });
                }

                function formatDate(dateInfo) {
                    if (!dateInfo || dateInfo.value === 'Не указана') return 'Не указано';
                    const value = dateInfo.value;
                    const displayType = dateInfo.displayType;
                    if (typeof value === 'string' && isNaN(value)) {
                        return value;
                    }
                    const ts = formatTimestamp(value);
                    if (typeof ts === 'string') return ts;
                    const date = new Date(ts * 1000);
                    const monthNames = ["январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь"];
                    const quarter = Math.floor(date.getMonth() / 3) + 1;
                    if (displayType) {
                        switch (displayType) {
                            case 'date_month':
                                return `${monthNames[date.getMonth()]} ${date.getFullYear()}`;
                            case 'date_quarter':
                                return `Q${quarter} ${date.getFullYear()}`;
                            case 'date_year':
                                return `${date.getFullYear()}`;
                            case 'date_full':
                            default:
                                return date.toLocaleDateString('ru-RU', {
                                    day: 'numeric',
                                    month: 'long',
                                    year: 'numeric'
                                });
                        }
                    }
                    return date.toLocaleDateString('ru-RU', {
                        day: 'numeric',
                        month: 'long',
                        year: 'numeric'
                    });
                }

                function formatTimestamp(ts) {
                    if (!ts) return ts;
                    if (typeof ts === 'string') {
                        if (/^\d{4}-\d{2}-\d{2}$/.test(ts)) {
                            return Math.floor(new Date(ts).getTime() / 1000);
                        }
                        return ts;
                    }
                    return typeof ts === 'number' ? ts : parseInt(ts, 10);
                }

                function updateStatusIndicator() {
                     const updateTime = (key, selector, prefix) => {
                        const lastUpdate = GM_getValue(key, 0);
                        const indicator = $(selector);
                        indicator.removeClass('status-ok status-warning status-alert1 status-alert2 status-critical status-unknown');
                        if (!lastUpdate) {
                            indicator.text(`${prefix}:??`).addClass('status-unknown').attr('title', 'Данные ни разу не обновлялись');
                            return;
                        }
                        const hoursPassed = (Date.now() - lastUpdate) / MILLISECONDS_IN_HOUR;
                        const days = Math.floor(hoursPassed / 24);
                        const hours = Math.floor(hoursPassed % 24);
                        indicator.attr('title', `Данные не обновлялись: ${days} д. и ${hours} ч.`);

                        if (hoursPassed < 12) indicator.text(`${prefix}:OK`).addClass('status-ok');
                        else if (hoursPassed < 24) indicator.text(`${prefix}:OK?`).addClass('status-warning');
                        else if (hoursPassed < 48) indicator.text(`${prefix}:!`).addClass('status-alert1');
                        else if (hoursPassed < 72) indicator.text(`${prefix}:!!`).addClass('status-alert2');
                        else indicator.text(`${prefix}:!!!`).addClass('status-critical');
                    };

                    updateTime(STORAGE_KEYS.LAST_UPDATE_WISHLIST, '.sledilka-status-wishlist', 'Ж');
                    updateTime(STORAGE_KEYS.LAST_UPDATE_LIBRARY, '.sledilka-status-library', 'Б');
                }

                function updateBadge() {
                    $('.sledilka-notification-badge').text(getUnreadCount());
                }

                function getUnreadCount() {
                    return notifications.filter(n => !n.read).length;
                }

                async function getUserData() {
                    return new Promise(resolve => {
                        GM_xmlhttpRequest({
                            method: 'GET',
                            url: 'https://store.steampowered.com/dynamicstore/userdata/?_t=' + Date.now(),
                            onload: function(response) {
                                try {
                                    const data = JSON.parse(response.responseText);
                                    resolve({
                                        wishlist: data.rgWishlist || [],
                                        owned: data.rgOwnedApps || []
                                    });
                                } catch (e) {
                                    console.error("Ошибка парсинга UserData:", e);
                                    resolve({
                                        wishlist: [],
                                        owned: []
                                    });
                                }
                            },
                            onerror: function(error) {
                                console.error("Ошибка запроса UserData:", error);
                                resolve({
                                    wishlist: [],
                                    owned: []
                                });
                            }
                        });
                    });
                }

                async function fetchGameDetails(appIds, includeLanguages = false) {
                    if (!appIds || appIds.length === 0) return [];
                    const batches = [];
                    for (let i = 0; i < appIds.length; i += BATCH_SIZE) {
                        batches.push(appIds.slice(i, i + BATCH_SIZE));
                    }
                    const allDetails = [];
                    for (const batch of batches) {
                        const details = await fetchBatchDetails(batch, includeLanguages);
                        allDetails.push(...details);
                        await new Promise(resolve => setTimeout(resolve, 500));
                    }
                    return allDetails;
                }

                async function fetchBatchDetails(appIds, includeLanguages = false, retries = MAX_API_RETRIES) {
                    const requestData = {
                        ids: appIds.map(appid => ({
                            appid
                        })),
                        context: {
                            language: 'russian',
                            country_code: 'RU',
                            steam_realm: 1
                        },
                        data_request: {
                            include_assets: true,
                            include_release: true,
                            include_basic_info: true
                        }
                    };
                    if (includeLanguages) {
                        requestData.data_request.include_supported_languages = true;
                    }
                    try {
                        return await new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: 'GET',
                                url: `https://api.steampowered.com/IStoreBrowseService/GetItems/v1?input_json=${encodeURIComponent(JSON.stringify(requestData))}`,
                                timeout: 15000,
                                onload: function(response) {
                                    try {
                                        if (response.status >= 200 && response.status < 400) {
                                            const data = JSON.parse(response.responseText);
                                            resolve(data.response?.store_items || []);
                                        } else {
                                            console.warn(`API Request Failed (Status: ${response.status}) for batch:`, appIds);
                                            reject(new Error(`API Status ${response.status}`));
                                        }
                                    } catch (e) {
                                        console.error('Error parsing response:', e, response.responseText);
                                        reject(new Error('Parse Error'));
                                    }
                                },
                                onerror: (error) => {
                                    console.error('API Request Network Error:', error);
                                    reject(new Error('Network Error'));
                                },
                                ontimeout: () => {
                                    console.warn('API Request Timeout for batch:', appIds);
                                    reject(new Error('Timeout'));
                                }
                            });
                        });
                    } catch (error) {
                        if (retries > 0) {
                            console.log(`Retrying API request for batch (Retries left: ${retries})...`);
                            await new Promise(resolve => setTimeout(resolve, API_RETRY_DELAY));
                            return fetchBatchDetails(appIds, includeLanguages, retries - 1);
                        } else {
                            console.error(`API request failed after multiple retries for batch:`, appIds, error);
                            showErrorIndicator(`Ошибка API Steam после ${MAX_API_RETRIES+1} попыток.`);
                            return [];
                        }
                    }
                }

                function getWishlistReleaseInfo(releaseData) {
                    if (!releaseData) return {
                        date: 'Не указана',
                        type: 'unknown',
                        displayType: null
                    };
                    const displayType = releaseData.coming_soon_display || null;
                    if (releaseData.steam_release_date) return {
                        date: releaseData.steam_release_date,
                        type: 'date',
                        displayType: displayType
                    };
                    if (releaseData.custom_release_date_message) return {
                        date: releaseData.custom_release_date_message,
                        type: 'custom',
                        displayType: null
                    };
                    return {
                        date: 'Не указана',
                        type: 'unknown',
                        displayType: null
                    };
                }

                function getOwnedGameInfo(gameDetails) {
                    if (!gameDetails) return {
                        is_early_access: false,
                        ru_support: {
                            supported: false,
                            full_audio: false,
                            subtitles: false
                        }
                    };
                    const is_early_access = gameDetails.release?.is_early_access ?? false;
                    let ru_support = {
                        supported: false,
                        full_audio: false,
                        subtitles: false
                    };
                    const russianLangData = gameDetails.supported_languages?.find(lang => lang.elanguage === 8);
                    if (russianLangData) {
                        ru_support = {
                            supported: russianLangData.supported || false,
                            full_audio: russianLangData.full_audio || false,
                            subtitles: russianLangData.subtitles || false
                        };
                    }
                    return {
                        is_early_access,
                        ru_support
                    };
                }

                function compareOwnedGameInfo(oldInfo, newInfo) {
                    const changes = [];
                    if (oldInfo.is_early_access && !newInfo.is_early_access) {
                        changes.push({ type: 'ea_status', old: oldInfo.is_early_access, new: newInfo.is_early_access });
                    }

                    const oldSupport = oldInfo.ru_support || { supported: false, full_audio: false, subtitles: false };
                    const newSupport = newInfo.ru_support;

                    const added = {
                        supported: !oldSupport.supported && newSupport.supported,
                        full_audio: !oldSupport.full_audio && newSupport.full_audio,
                        subtitles: !oldSupport.subtitles && newSupport.subtitles
                    };
                    const removed = {
                        supported: oldSupport.supported && !newSupport.supported,
                        full_audio: oldSupport.full_audio && !newSupport.full_audio,
                        subtitles: oldSupport.subtitles && !newSupport.subtitles
                    };

                    const hasAdded = Object.values(added).some(v => v);
                    const hasRemoved = Object.values(removed).some(v => v);

                    if (hasAdded || hasRemoved) {
                        changes.push({
                            type: 'ru_lang',
                            details: {
                                oldState: oldSupport,
                                newState: newSupport,
                                added,
                                removed
                            }
                        });
                    }

                    return changes;
                }

                async function updateData() {
                    if (updateInProgress) {
                        showInfoIndicator("Обновление уже выполняется...");
                        return;
                    }
                    updateInProgress = true;
                    $('.sledilka-refresh-btn').prop('disabled', true);
                    const refreshBtnText = $('.sledilka-refresh-btn').contents().filter(function() { return this.nodeType === 3; });
                    if (refreshBtnText.length) refreshBtnText[0].nodeValue = ' Обновить...';

                    const updateSettings = GM_getValue(STORAGE_KEYS.UPDATE_SETTINGS, {
                        wishlist: true,
                        library: true,
                        recheckRussian: true,
                        recheckPartial: false
                    });
                    if (!updateSettings.wishlist && !updateSettings.library) {
                        showInfoIndicator("Не выбрано, что обновлять. Проверьте настройки (⚙️).");
                        updateInProgress = false;
                        $('.sledilka-refresh-btn').prop('disabled', false);
                        if(refreshBtnText.length) refreshBtnText[0].nodeValue = ' Обновить';
                        return;
                    }

                    showLoadingIndicator("Получение списков игр...");
                    updateProgressBar(1);
                    try {
                        const {
                            wishlist: currentWishlistAppIds,
                            owned: currentOwnedAppIds
                        } = await getUserData();
                        let allNewNotifications = [];

                        if(updateSettings.wishlist) {
                            const wishlistPreviousData = GM_getValue(STORAGE_KEYS.WISHLIST_GAME_DATA, {});
                            const currentWishlistDataToSave = { ...wishlistPreviousData };
                            const currentWishlistAppIdSet = new Set(currentWishlistAppIds);

                            const previouslyTrackedAppIds = Object.keys(wishlistPreviousData).map(id => parseInt(id, 10));
                            const removedAppIds = previouslyTrackedAppIds.filter(appid => !currentWishlistAppIdSet.has(appid));
                            removedAppIds.forEach(appid => {
                                delete currentWishlistDataToSave[String(appid)];
                            });

                            showLoadingIndicator(`Загрузка данных для ${currentWishlistAppIds.length} игр из желаемого...`);
                            updateProgressBar(5);

                            if (currentWishlistAppIds.length > 0) {
                                const wishlistDetails = await fetchGameDetails(currentWishlistAppIds, true);
                                updateProgressBar(25);

                                wishlistDetails.forEach(game => {
                                    if (!game || !game.appid) return;
                                    const appid = game.appid;
                                    const prevGame = wishlistPreviousData[appid];
                                    const currentRelease = getWishlistReleaseInfo(game.release);
                                    const currentGameInfo = getOwnedGameInfo(game);

                                    currentWishlistDataToSave[appid] = {
                                        name: game.name,
                                        rawRelease: game.release,
                                        releaseInfo: currentRelease,
                                        header: game.assets?.header || null,
                                        is_early_access: currentGameInfo.is_early_access,
                                        ru_support: currentGameInfo.ru_support
                                    };

                                    if (prevGame) {
                                        if (currentRelease.date !== prevGame.releaseInfo?.date || currentRelease.type !== prevGame.releaseInfo?.type || currentRelease.displayType !== prevGame.releaseInfo?.displayType) {
                                            allNewNotifications.push({ source: 'wishlist', appid: appid, name: game.name, header: game.assets?.header, oldDate: prevGame.releaseInfo ? { value: prevGame.releaseInfo.date, displayType: prevGame.releaseInfo.displayType } : { value: 'Не указана', displayType: null }, newDate: { value: currentRelease.date, displayType: currentRelease.displayType }, timestamp: Date.now(), read: false });
                                        }

                                        const hadOldStatusData = prevGame.hasOwnProperty('is_early_access') && prevGame.hasOwnProperty('ru_support');
                                        if (hadOldStatusData) {
                                            const oldGameInfo = { is_early_access: prevGame.is_early_access, ru_support: prevGame.ru_support };
                                            const statusChanges = compareOwnedGameInfo(oldGameInfo, currentGameInfo);
                                            statusChanges.forEach(change => {
                                                allNewNotifications.push({ source: 'wishlist', changeType: change.type, appid: appid, name: game.name, header: game.assets?.header, ruChangeDetails: change.type === 'ru_lang' ? change.details : undefined, timestamp: Date.now(), read: false });
                                            });
                                        }
                                    }
                                });
                            }
                            GM_setValue(STORAGE_KEYS.WISHLIST_GAME_DATA, currentWishlistDataToSave);
                            GM_setValue(STORAGE_KEYS.LAST_UPDATE_WISHLIST, Date.now());
                        }

                        if(updateSettings.library) {
                            const ownedPreviousData = GM_getValue(STORAGE_KEYS.OWNED_APPS_DATA, {});
                            const ownedCheckedSet = new Set(GM_getValue(STORAGE_KEYS.OWNED_CHECKED_V2, []));
                            const currentOwnedDataToSave = { ...ownedPreviousData };

                            let appsToCheckInLibrary = currentOwnedAppIds.filter(appid => !ownedCheckedSet.has(appid));

                            if (!updateSettings.recheckRussian) {
                                appsToCheckInLibrary = appsToCheckInLibrary.filter(appid => {
                                    const prevData = ownedPreviousData[appid];
                                    if (!prevData || !prevData.ru_support) {
                                        return true;
                                    }

                                    const hasFullSupport = prevData.ru_support.supported && prevData.ru_support.full_audio && prevData.ru_support.subtitles;
                                    const hasAnySupport = prevData.ru_support.supported || prevData.ru_support.full_audio || prevData.ru_support.subtitles;

                                    if (updateSettings.recheckPartial) {
                                        return !hasFullSupport;
                                    } else {
                                        return !hasAnySupport;
                                    }
                                });
                            }

                            const totalOwnedToCheck = appsToCheckInLibrary.length;
                            showLoadingIndicator(`Проверка ${totalOwnedToCheck} игр из библиотеки...`);

                            if (totalOwnedToCheck > 0) {
                                for (let i = 0; i < totalOwnedToCheck; i += BATCH_SIZE) {
                                    const batch = appsToCheckInLibrary.slice(i, i + BATCH_SIZE);
                                    const progress = 50 + Math.round(((i) / (totalOwnedToCheck || 1)) * 50);
                                    updateProgressBar(progress);
                                    showLoadingIndicator(`Проверка библиотеки... (${i}/${totalOwnedToCheck})`);
                                    const details = await fetchGameDetails(batch, true);
                                    details.forEach(game => {
                                        if (!game || !game.appid) return;
                                        const appid = game.appid;
                                        if (game.type !== 0 || game.visible === false) { ownedCheckedSet.add(appid); delete currentOwnedDataToSave[appid]; return; }
                                        const name = game.name || ownedPreviousData[appid]?.name || `Игра #${appid}`;
                                        if (!name || name.trim() === '' || name === `Игра #${appid}`) { ownedCheckedSet.add(appid); delete currentOwnedDataToSave[appid]; return; }

                                        const prevGameData = ownedPreviousData[appid];
                                        const currentGameInfo = getOwnedGameInfo(game);
                                        currentOwnedDataToSave[appid] = { name: name, ...currentGameInfo };

                                        if (prevGameData) {
                                            const hadOldStatusData = prevGameData.hasOwnProperty('is_early_access') && prevGameData.hasOwnProperty('ru_support');
                                            if(hadOldStatusData) {
                                                const detectedChanges = compareOwnedGameInfo(prevGameData, currentGameInfo);
                                                detectedChanges.forEach(change => allNewNotifications.push({ source: 'library', changeType: change.type, appid: appid, name: name, header: game.assets?.header, ruChangeDetails: change.type === 'ru_lang' ? change.details : undefined, timestamp: Date.now(), read: false }));
                                            }
                                        }
                                    });
                                }
                            }
                            const currentOwnedAppIdSet = new Set(currentOwnedAppIds);
                            const previouslyTrackedAppIds = Object.keys(ownedPreviousData).map(id => parseInt(id, 10));
                            const removedAppIds = previouslyTrackedAppIds.filter(appid => !currentOwnedAppIdSet.has(appid));
                            removedAppIds.forEach(appid => { delete currentOwnedDataToSave[appid]; ownedCheckedSet.delete(appid); });

                            GM_setValue(STORAGE_KEYS.OWNED_APPS_DATA, currentOwnedDataToSave);
                            GM_setValue(STORAGE_KEYS.OWNED_CHECKED_V2, Array.from(ownedCheckedSet));
                            GM_setValue(STORAGE_KEYS.LAST_UPDATE_LIBRARY, Date.now());
                        }

                        if (allNewNotifications.length > 0) {
                            notifications = [...allNewNotifications, ...notifications];
                            notifications.sort((a, b) => b.timestamp - a.timestamp);
                            notifications = notifications.slice(0, 500);
                            GM_setValue(STORAGE_KEYS.NOTIFICATIONS, notifications);
                        }

                        removeLoadingIndicator();
                        updateNotificationPanel();
                        updateBadge();
                        updateStatusIndicator();
                        updateProgressBar(100);
                        showInfoIndicator(`Обновление завершено. Новых уведомлений: ${allNewNotifications.length}.`);
                    } catch (e) {
                        console.error('Ошибка при обновлении данных:', e);
                        showErrorIndicator(`Ошибка обновления: ${e.message || 'Неизвестная ошибка'}`);
                        updateStatusIndicator();
                    } finally {
                        updateInProgress = false;
                         $('.sledilka-refresh-btn').prop('disabled', false);
                        if(refreshBtnText.length) refreshBtnText[0].nodeValue = ' Обновить';
                        setTimeout(() => updateProgressBar(0), 500);
                    }
                }

                function showCalendarModal() {
                    const gameData = GM_getValue(STORAGE_KEYS.WISHLIST_GAME_DATA, {});
                    const monthsData = getGamesByMonths(gameData);
                    const wtmodal = $(`
                         <div class="calendar-wtmodal">
                             <div class="calendar-header"> <div class="calendar-title">Календарь релизов (${Object.keys(gameData).length} игр в списке)</div> <div class="calendar-close">×</div> </div>
                             <div class="calendar-content"></div>
                         </div>`);
                    const clickHandler = (e) => {
                        if (!$(e.target).closest('.calendar-wtmodal').length) {
                            wtmodal.remove();
                            $(document).off('click', clickHandler);
                        }
                    };
                    wtmodal.find('.calendar-close').click((e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        wtmodal.remove();
                        $(document).off('click', clickHandler);
                    });
                    wtmodal.click(e => e.stopPropagation());
                    $(document).on('click', clickHandler);
                    $('body').append(wtmodal);
                    wtmodal.addClass('active');
                    let visibleMonths = 3;
                    const renderCalendar = () => {
                        const visibleData = monthsData.slice(0, visibleMonths);
                        const content = wtmodal.find('.calendar-content').empty();
                        if (monthsData.length === 0) {
                            content.append('<div style="text-align:center; padding: 30px; color: #8f98a0;">Нет игр с датой выхода в будущем в вашем списке желаемого.</div>');
                            return;
                        }
                        visibleData.forEach(({
                            month,
                            year,
                            games
                        }) => {
                            const monthDate = new Date(year, month);
                            const monthName = monthDate.toLocaleString('ru-RU', {
                                month: 'long'
                            });
                            const daysInMonth = new Date(year, month + 1, 0).getDate();
                            const firstDay = new Date(year, month, 1).getDay();
                            const adjustedFirstDay = firstDay === 0 ? 6 : firstDay - 1;
                            const monthBlock = $(`<div class="calendar-month"> <div class="month-header">${monthName} ${year}</div> <div class="calendar-grid"></div> </div>`);
                            const grid = monthBlock.find('.calendar-grid');
                            grid.append('<div>Пн</div><div>Вт</div><div>Ср</div><div>Чт</div><div>Пт</div><div>Сб</div><div>Вс</div>');
                            for (let i = 0; i < adjustedFirstDay; i++) {
                                grid.append('<div class="calendar-day"></div>');
                            }
                            for (let day = 1; day <= daysInMonth; day++) {
                                const dayGames = games.filter(g => {
                                    const releaseDate = new Date(g.releaseInfo.date * 1000);
                                    return releaseDate.getDate() === day && releaseDate.getMonth() === month && releaseDate.getFullYear() === year;
                                });
                                const dayElement = $(`<div class="calendar-day"> <div class="day-number">${day}</div> </div>`);
                                dayGames.sort((a, b) => a.name.localeCompare(b.name)).forEach(game => {
                                    const isApproximate = ['date_month', 'date_quarter', 'date_year'].includes(game.releaseInfo.displayType);
                                    const imageUrl = game.header ? `https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/${game.appid}/${game.header}` : `https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/${game.appid}/header.jpg`;
                                    const gameElement = $(`<a href="https://store.steampowered.com/app/${game.appid}" target="_blank" class="calendar-game ${isApproximate ? 'calendar-game-approximate wt-tooltip' : ''}"> <img src="${imageUrl}" class="calendar-game-image" loading="lazy" onerror="this.onerror=null; this.src='https://via.placeholder.com/100x45?text=No+Img'; this.style.objectFit='contain';"> <div class="calendar-game-title">${game.name}</div> ${isApproximate ? `<div class="wt-tooltiptext">Приблизительная дата: ${getApproximateDateText(game.releaseInfo)}</div>` : ''} </a>`);
                                    dayElement.append(gameElement);
                                });
                                grid.append(dayElement);
                            }
                            content.append(monthBlock);
                        });
                        if (visibleMonths < monthsData.length) {
                            content.append(`<div class="load-more-months"> <button class="load-more-btn">Показать ещё 3 месяца</button> </div>`);
                            content.find('.load-more-btn').click(() => {
                                visibleMonths += 3;
                                renderCalendar();
                            });
                        }
                    };
                    renderCalendar();
                }

                function getGamesByMonths(gameData) {
                    const now = new Date();
                    const currentYear = now.getFullYear();
                    const currentMonth = now.getMonth();
                    const games = Object.entries(gameData).map(([appid, game]) => ({
                            appid: parseInt(appid),
                            ...game,
                            releaseDate: game.releaseInfo?.date && typeof game.releaseInfo.date === 'number' ? new Date(game.releaseInfo.date * 1000) : null
                        }))
                        .filter(g => g.releaseDate).filter(g => {
                            const releaseYear = g.releaseDate.getFullYear();
                            const releaseMonth = g.releaseDate.getMonth();
                            return (releaseYear > currentYear) || (releaseYear === currentYear && releaseMonth >= currentMonth);
                        });
                    const monthMap = games.reduce((acc, game) => {
                        const year = game.releaseDate.getFullYear();
                        const month = game.releaseDate.getMonth();
                        const key = `${year}-${month}`;
                        if (!acc[key]) {
                            acc[key] = {
                                year,
                                month,
                                games: []
                            };
                        }
                        acc[key].games.push(game);
                        return acc;
                    }, {});
                    return Object.values(monthMap).sort((a, b) => a.year === b.year ? a.month - b.month : a.year - b.year);
                }

                function getApproximateDateText(releaseInfo) {
                    const date = new Date(releaseInfo.date * 1000);
                    const quarter = Math.floor(date.getMonth() / 3) + 1;
                    switch (releaseInfo.displayType) {
                        case 'date_month':
                            return date.toLocaleString('ru-RU', {
                                month: 'long',
                                year: 'numeric'
                            });
                        case 'date_quarter':
                            return `Q${quarter} ${date.getFullYear()}`;
                        case 'date_year':
                            return date.getFullYear().toString();
                        default:
                            return date.toLocaleDateString('ru-RU');
                    }
                }

                function showStorageModal() {
                    const modalHtml = `
                                  <div id="sledilkaStorageModal" class="sledilka-storage-modal">
                                      <div class="sledilka-storage-modal-content">
                                          <span id="sledilkaStorageCloseBtn" class="sledilka-storage-modal-close" title="Закрыть">&times;</span>
                                          <h3>Управление хранилищем</h3>
                                          <button id="clearWishlistDataBtn">Очистить данные из списка желаемого</button>
                                          <br>
                                          <button id="clearOwnedDataBtn">Очистить данные из библиотеки</button>
                                      </div>
                                  </div>`;
                    if ($('#sledilkaStorageModal').length === 0) {
                        $('body').append(modalHtml);
                    }
                    const modal = $('#sledilkaStorageModal');
                    modal.show();
                    $('#sledilkaStorageCloseBtn').off('click').on('click', () => modal.hide());
                    modal.off('click').on('click', (event) => {
                        if ($(event.target).is(modal)) {
                            modal.hide();
                        }
                    });
                    $('#clearWishlistDataBtn').off('click').on('click', () => {
                        if (confirm("Вы уверены, что хотите удалить сохраненные данные для Списка желаемого?\nЭто приведет к повторному сканированию при следующем обновлении.")) {
                            GM_deleteValue(STORAGE_KEYS.WISHLIST_GAME_DATA);
                            notifications = notifications.filter(n => !n.source || n.source !== 'wishlist');
                            GM_setValue(STORAGE_KEYS.NOTIFICATIONS, notifications);
                            alert("Данные списка желаемого очищены.");
                            modal.hide();
                            updateNotificationPanel();
                            updateBadge();
                        }
                    });
                    $('#clearOwnedDataBtn').off('click').on('click', () => {
                        if (confirm("Вы уверены, что хотите удалить сохраненные данные для Библиотеки?\nЭто приведет к ПОЛНОМУ ПОВТОРНОМУ сканированию вашей библиотеки при следующем обновлении, что может занять время.")) {
                            GM_deleteValue(STORAGE_KEYS.OWNED_APPS_DATA);
                            GM_deleteValue(STORAGE_KEYS.OWNED_CHECKED_V2);
                            alert("Данные Библиотеки очищены. Потребуется повторное сканирование.");
                            modal.hide();
                        }
                    });
                }

                function initialize() {
                    createSledilkaUI();
                    updateStatusIndicator();
                    setupMutationObserver(document.getElementById('global_actions'));
                }
                if (typeof $ !== 'undefined') {
                    $(document).ready(initialize);
                } else {
                    const checkJQuery = setInterval(() => {
                        if (typeof $ !== 'undefined') {
                            clearInterval(checkJQuery);
                            $(document).ready(initialize);
                        }
                    }, 100);
                }
            })();
        }

    // Скрипт для проверки возможности отправки подарка из списка желаемого друзьям в других странах | https://steamcommunity.com/my/wishlist/*
    if (scriptsConfig.wishlistGiftHelper && unsafeWindow.location.pathname.includes('/wishlist/')) {
        (function() {
            'use strict';

            const WGH_API_URL = "https://api.steampowered.com/IStoreBrowseService/GetItems/v1";
            const WGH_CURRENCY_API_URL = 'https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/';
            const WGH_BATCH_SIZE = 200;
            const WGH_INITIAL_DELAY_MS = 500;
            const WGH_REQUEST_TIMEOUT_MS = 20000;
            const WGH_GIFT_PRICE_DIFF_THRESHOLD = 0.10;
            const WGH_IMAGE_BASE_URL = 'https://shared.fastly.steamstatic.com/store_item_assets/steam/apps/';
            const WGH_COUNTRY_CURRENCY_MAP = {
                'AU': {
                    name: 'Австралийский доллар',
                    code: 21,
                    iso: 'aud'
                },
                'BR': {
                    name: 'Бразильский реал',
                    code: 7,
                    iso: 'brl'
                },
                'GB': {
                    name: 'Британский фунт',
                    code: 2,
                    iso: 'gbp'
                },
                'VN': {
                    name: 'Вьетнамский донг',
                    code: 15,
                    iso: 'vnd'
                },
                'HK': {
                    name: 'Гонконгский доллар',
                    code: 29,
                    iso: 'hkd'
                },
                'AE': {
                    name: 'Дирхам ОАЭ',
                    code: 32,
                    iso: 'aed'
                },
                'US': {
                    name: 'Доллар США',
                    code: 1,
                    iso: 'usd'
                },
                'EU': {
                    name: 'Евро',
                    code: 3,
                    iso: 'eur'
                },
                'IL': {
                    name: 'Израильский новый шекель',
                    code: 35,
                    iso: 'ils'
                },
                'IN': {
                    name: 'Индийская рупия',
                    code: 24,
                    iso: 'inr'
                },
                'ID': {
                    name: 'Индонезийская рупия',
                    code: 10,
                    iso: 'idr'
                },
                'KZ': {
                    name: 'Казахстанский тенге',
                    code: 37,
                    iso: 'kzt'
                },
                'CA': {
                    name: 'Канадский доллар',
                    code: 20,
                    iso: 'cad'
                },
                'QA': {
                    name: 'Катарский риал',
                    code: 39,
                    iso: 'qar'
                },
                'CN': {
                    name: 'Китайский юань',
                    code: 23,
                    iso: 'cny'
                },
                'CO': {
                    name: 'Колумбийское песо',
                    code: 27,
                    iso: 'cop'
                },
                'CR': {
                    name: 'Коста-риканский колон',
                    code: 40,
                    iso: 'crc'
                },
                'KW': {
                    name: 'Кувейтский динар',
                    code: 38,
                    iso: 'kwd'
                },
                'AR': {
                    name: 'Лат. Ам. - Доллар США',
                    code: 1,
                    iso: 'usd'
                },
                'MY': {
                    name: 'Малазийский ринггит',
                    code: 11,
                    iso: 'myr'
                },
                'TR': {
                    name: 'MENA - Доллар США',
                    code: 1,
                    iso: 'usd'
                },
                'MX': {
                    name: 'Мексиканское песо',
                    code: 19,
                    iso: 'mxn'
                },
                'NZ': {
                    name: 'Новозеландский доллар',
                    code: 22,
                    iso: 'nzd'
                },
                'NO': {
                    name: 'Норвежская крона',
                    code: 9,
                    iso: 'nok'
                },
                'PE': {
                    name: 'Перуанский соль',
                    code: 26,
                    iso: 'pen'
                },
                'PL': {
                    name: 'Польский злотый',
                    code: 6,
                    iso: 'pln'
                },
                'RU': {
                    name: 'Российский рубль',
                    code: 5,
                    iso: 'rub'
                },
                'SA': {
                    name: 'Саудовский риал',
                    code: 31,
                    iso: 'sar'
                },
                'SG': {
                    name: 'Сингапурский доллар',
                    code: 13,
                    iso: 'sgd'
                },
                'AZ': {
                    name: 'СНГ - Доллар США',
                    code: 1,
                    iso: 'usd'
                },
                'TW': {
                    name: 'Тайваньский доллар',
                    code: 30,
                    iso: 'twd'
                },
                'TH': {
                    name: 'Тайский бат',
                    code: 14,
                    iso: 'thb'
                },
                'UA': {
                    name: 'Украинская гривна',
                    code: 18,
                    iso: 'uah'
                },
                'UY': {
                    name: 'Уругвайское песо',
                    code: 41,
                    iso: 'uyu'
                },
                'PH': {
                    name: 'Филиппинское песо',
                    code: 12,
                    iso: 'php'
                },
                'CL': {
                    name: 'Чилийское песо',
                    code: 25,
                    iso: 'clp'
                },
                'CH': {
                    name: 'Швейцарский франк',
                    code: 4,
                    iso: 'chf'
                },
                'PK': {
                    name: 'Юж. Азия - Доллар США',
                    code: 1,
                    iso: 'usd'
                },
                'ZA': {
                    name: 'Южноафриканский рэнд',
                    code: 28,
                    iso: 'zar'
                },
                'KR': {
                    name: 'Южнокорейская вона',
                    code: 16,
                    iso: 'krw'
                },
                'JP': {
                    name: 'Японская иена',
                    code: 8,
                    iso: 'jpy'
                }
            };
            const WGH_CURRENCY_CODE_TO_COUNTRY = Object.fromEntries(Object.entries(WGH_COUNTRY_CURRENCY_MAP).map(([country, data]) => [data.code, country]));
            const WGH_CURRENCY_CODE_TO_ISO = Object.fromEntries(Object.entries(WGH_COUNTRY_CURRENCY_MAP).map(([_, data]) => [data.code, data.iso]));
            const WGH_DEFAULT_SORT = { field: 'price', direction: 'asc' };
            const WGH_TAGS_CACHE_KEY = 'SteamEnhancer_TagsCache_v2_wgh';
            const WGH_TAGS_URL = "https://gist.githubusercontent.com/0wn3dg0d/22a351ff4c65e50a9a8af6da360defad/raw/steamrutagsownd.json";
            const WGH_FILTER_STORAGE_KEY = 'wgh_filters_v1';
            const WGH_FILTER_DEBOUNCE_MS = 400;

            function debounce(func, wait) {
                let timeout;
                return function executedFunction(...args) {
                    const later = () => {
                        clearTimeout(timeout);
                        func(...args);
                    };
                    clearTimeout(timeout);
                    timeout = setTimeout(later, wait);
                };
            }

            function wgh_getCustomReviewDescription(percent, count) {
                if (count === 0) return 'Нет обзоров';
                if (percent === null || typeof percent === 'undefined') return 'Нет обзоров';
                if (percent >= 95) return 'Крайне положительные';
                if (percent >= 80) return 'Очень положительные';
                if (percent >= 70) return 'В основном положительные';
                if (percent >= 40) return 'Смешанные';
                if (percent >= 20) return 'В основном отрицательные';
                if (percent >= 6)  return 'Очень отрицательные';
                return 'Крайне отрицательные';
            }

            function calculateRecommendedRubPrice(pUSD) {
                if (typeof pUSD !== 'number' || isNaN(pUSD)) return null;
                if (pUSD < 0.99) return 42;
                if (pUSD >= 0.99 && pUSD < 1.99) return 42;
                if (pUSD >= 1.99 && pUSD < 2.99) return 82;
                if (pUSD >= 2.99 && pUSD < 3.99) return 125;
                if (pUSD >= 3.99 && pUSD < 4.99) return 165;
                if (pUSD >= 4.99 && pUSD < 5.99) return 200;
                if (pUSD >= 5.99 && pUSD < 6.99) return 240;
                if (pUSD >= 6.99 && pUSD < 7.99) return 280;
                if (pUSD >= 7.99 && pUSD < 8.99) return 320;
                if (pUSD >= 8.99 && pUSD < 9.99) return 350;
                if (pUSD >= 9.99 && pUSD < 10.99) return 385;
                if (pUSD >= 10.99 && pUSD < 11.99) return 420;
                if (pUSD >= 11.99 && pUSD < 12.99) return 460;
                if (pUSD >= 12.99 && pUSD < 13.99) return 490;
                if (pUSD >= 13.99 && pUSD < 14.99) return 520;
                if (pUSD >= 14.99 && pUSD < 15.99) return 550;
                if (pUSD >= 15.99 && pUSD < 16.99) return 590;
                if (pUSD >= 16.99 && pUSD < 17.99) return 620;
                if (pUSD >= 17.99 && pUSD < 18.99) return 650;
                if (pUSD >= 18.99 && pUSD < 19.99) return 680;
                if (pUSD >= 19.99 && pUSD < 22.99) return 710;
                if (pUSD >= 22.99 && pUSD < 27.99) return 880;
                if (pUSD >= 27.99 && pUSD < 32.99) return 1100;
                if (pUSD >= 32.99 && pUSD < 37.99) return 1200;
                if (pUSD >= 37.99 && pUSD < 43.99) return 1300;
                if (pUSD >= 43.99 && pUSD < 47.99) return 1500;
                if (pUSD >= 47.99 && pUSD < 52.99) return 1600;
                if (pUSD >= 52.99 && pUSD < 57.99) return 1750;
                if (pUSD >= 57.99 && pUSD < 63.99) return 1900;
                if (pUSD >= 63.99 && pUSD < 67.99) return 2100;
                if (pUSD >= 67.99 && pUSD < 74.99) return 2250;
                if (pUSD >= 74.99 && pUSD < 79.99) return 2400;
                if (pUSD >= 79.99 && pUSD < 84.99) return 2600;
                if (pUSD >= 84.99 && pUSD < 89.99) return 2700;
                if (pUSD >= 89.99 && pUSD < 99.99) return 2900;
                if (pUSD >= 99.99 && pUSD < 109.99) return 3200;
                if (pUSD >= 109.99 && pUSD < 119.99) return 3550;
                if (pUSD >= 119.99 && pUSD < 129.99) return 3900;
                if (pUSD >= 129.99 && pUSD < 139.99) return 4200;
                if (pUSD >= 139.99 && pUSD < 149.99) return 4500;
                if (pUSD >= 149.99 && pUSD < 199.99) return 4800;
                if (pUSD >= 199.99) return 6500;
                return null;
            }

            let wgh_allAppIds = [];
            let wgh_gameDataStore = {};
            let wgh_currentResults = [];
            let wgh_currentUserCountryCode = 'RU';
            let wgh_currentUserCurrencyCode = 5;
            let wgh_currentUserISOCurrencyCode = 'RUB';
            let wgh_currentSort = { ...WGH_DEFAULT_SORT };
            let wgh_currentFriendCountryCode = null;
            let wgh_exchangeRates = null;
            let wgh_giftModeActive = false;
            let wgh_showGiftableOnly = false;
            let wgh_modal, wgh_closeBtn, wgh_analyzeBtn;
            let wgh_resultsContainer, wgh_resultsDiv, wgh_statusDiv, wgh_progressBar;
            let wgh_sortButtonsContainer;
            let wgh_giftModeContainer, wgh_giftIconBtn, wgh_friendRegionSelect, wgh_fetchFriendPricesBtn, wgh_giftProgressBar, wgh_giftableFilterCheckbox;
            let wgh_myRegionDisplay;
            let wgh_filterToggleBtn, wgh_filterAccordionContainer;
            let wgh_currentFilters = GM_getValue(WGH_FILTER_STORAGE_KEY, {});

            async function wgh_loadSteamTags() {
                const cached = GM_getValue(WGH_TAGS_CACHE_KEY, { data: null, timestamp: 0 });
                const now = Date.now();
                const CACHE_DURATION = 744 * 60 * 60 * 1000;
                if (cached.data && (now - cached.timestamp) < CACHE_DURATION) return cached.data;
                try {
                    const response = await new Promise((resolve, reject) => GM_xmlhttpRequest({ method: "GET", url: WGH_TAGS_URL, onload: resolve, onerror: reject }));
                    if (response.status === 200) {
                        const data = JSON.parse(response.responseText);
                        GM_setValue(WGH_TAGS_CACHE_KEY, { data: data, timestamp: now });
                        return data;
                    }
                } catch (e) { console.error('[WGH] Ошибка загрузки тегов:', e); return cached.data || {}; }
                return {};
            }

            function wgh_addAnalyzeButton() {
                const titleBlock = document.querySelector('div.jfAmlCmNzHQ-');
                if (!titleBlock || document.getElementById('wghAnalyzeButton')) return;
                wgh_analyzeBtn = document.createElement('button');
                wgh_analyzeBtn.id = 'wghAnalyzeButton';
                wgh_analyzeBtn.title = 'Помощник подарков';
                wgh_analyzeBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>`;
                Object.assign(wgh_analyzeBtn.style, { marginLeft: '15px', background: 'rgba(103, 193, 245, 0.1)', border: '1px solid rgba(103, 193, 245, 0.3)', color: '#67c1f5', borderRadius: '3px', cursor: 'pointer', padding: '5px 8px', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', verticalAlign: 'middle' });
                wgh_analyzeBtn.onmouseover = () => { wgh_analyzeBtn.style.background = 'rgba(103, 193, 245, 0.2)'; };
                wgh_analyzeBtn.onmouseout = () => { wgh_analyzeBtn.style.background = 'rgba(103, 193, 245, 0.1)'; };
                wgh_analyzeBtn.onclick = wgh_showModal;
                const h2Title = titleBlock.querySelector('h2');
                if (h2Title) { h2Title.style.display = 'inline-block'; h2Title.after(wgh_analyzeBtn); }
                else { titleBlock.appendChild(wgh_analyzeBtn); }
            }

            function wgh_createFilterAccordion() {
                wgh_filterAccordionContainer = document.createElement('div');
                wgh_filterAccordionContainer.id = 'wghFilterAccordionContainer';
                wgh_filterAccordionContainer.className = 'wghAccordionContainer';

                const rrcFilterHtml = wgh_currentUserCountryCode === 'RU' ? `
                    <div class="wghFilterGroup">
                        <label class="wghFilterLabel">Фильтр по РРЦ</label>
                        <div class="wghRadioGroup">
                            <label><input type="radio" name="wghRrcFilter" value="any" checked>Все</label>
                            <label><input type="radio" name="wghRrcFilter" value="lower">Дешевле РРЦ</label>
                            <label><input type="radio" name="wghRrcFilter" value="equal">Равно РРЦ</label>
                            <label><input type="radio" name="wghRrcFilter" value="higher">Дороже РРЦ</label>
                        </div>
                    </div>` : '';

                wgh_filterAccordionContainer.innerHTML = `
                    <div class="wghFilterGrid">
                        <div class="wghFilterGroup">
                            <label class="wghFilterLabel"><input type="checkbox" id="wghFilterDiscounted"> Только со скидками</label>
                            <label class="wghFilterLabel"><input type="checkbox" id="wghFilterNoPrice"> Скрыть без цены</label>
                        </div>
                        <div class="wghFilterGroup">
                            <label class="wghFilterLabel">Кол-во обзоров</label>
                            <div class="wghRangeInput"><input type="number" id="wghFilterReviewCountMin" placeholder="От"><input type="number" id="wghFilterReviewCountMax" placeholder="До"></div>
                        </div>
                        <div class="wghFilterGroup">
                            <label class="wghFilterLabel">Рейтинг обзоров (%)</label>
                            <div class="wghRangeInput"><input type="number" id="wghFilterRatingMin" placeholder="От"><input type="number" id="wghFilterRatingMax" placeholder="До"></div>
                        </div>
                        <div class="wghFilterGroup">
                            <label class="wghFilterLabel">Цена</label>
                            <div class="wghRangeInput"><input type="number" id="wghFilterPriceMin" placeholder="От"><input type="number" id="wghFilterPriceMax" placeholder="До"></div>
                        </div>
                        <div class="wghFilterGroup">
                            <label class="wghFilterLabel">Скидка (%)</label>
                            <div class="wghRangeInput"><input type="number" id="wghFilterDiscountMin" placeholder="От"><input type="number" id="wghFilterDiscountMax" placeholder="До"></div>
                        </div>
                        <div class="wghFilterGroup">
                            <label class="wghFilterLabel">Дата выхода</label>
                            <div class="wghRangeInput"><input type="date" id="wghFilterDateMin"><input type="date" id="wghFilterDateMax"></div>
                        </div>
                         <div class="wghFilterGroup">
                            <label class="wghFilterLabel">Русский язык</label>
                            <div class="wghRadioGroup">
                                <label><input type="radio" name="wghLangFilter" value="any" checked>Все</label>
                                <label><input type="radio" name="wghLangFilter" value="text_only">Только текст</label>
                                <label><input type="radio" name="wghLangFilter" value="voice">Озвучка</label>
                                <label><input type="radio" name="wghLangFilter" value="none">Без перевода</label>
                            </div>
                        </div>
                        <div class="wghFilterGroup">
                            <label class="wghFilterLabel">Ранний доступ</label>
                            <div class="wghRadioGroup">
                                <label><input type="radio" name="wghEaFilter" value="any" checked>Все</label>
                                <label><input type="radio" name="wghEaFilter" value="early_access">Только</label>
                                <label><input type="radio" name="wghEaFilter" value="released">Без</label>
                            </div>
                        </div>
                        ${rrcFilterHtml}
                    </div>
                    <button id="wghResetFilters" class="wghBtn">Сбросить фильтры</button>
                `;
            }

            function wgh_createModal() {
                if (document.getElementById('wghModal')) return;
                wgh_modal = document.createElement('div');
                wgh_modal.id = 'wghModal';
                wgh_modal.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(20, 20, 25, 0.95); backdrop-filter: blur(3px); z-index: 9999; display: none; color: #c6d4df; font-family: "Motiva Sans", Sans-serif, Arial; overflow: hidden; `;
                const container = document.createElement('div');
                container.id = 'wghContainer';
                container.style.cssText = `height: 100%; display: flex; flex-direction: column; padding: 15px;`;
                const header = document.createElement('div');
                header.id = 'wghHeader';
                header.style.cssText = `display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding-bottom: 10px; border-bottom: 1px solid #3a4f6a; margin-bottom: 10px; flex-shrink: 0; padding-right: 45px;`;
                const collectBtn = document.createElement('button');
                collectBtn.textContent = 'Собрать данные';
                collectBtn.id = 'wghCollectBtn';
                collectBtn.className = 'wghBtn wghPrimaryBtn';
                collectBtn.onclick = wgh_collectData;
                header.appendChild(collectBtn);
                wgh_statusDiv = document.createElement('div');
                wgh_statusDiv.id = 'wghStatus';
                wgh_statusDiv.style.cssText = `flex-grow: 1; text-align: center; font-size: 14px; color: #aaa; min-height: 36px; display: flex; align-items: center; justify-content: center;`;
                header.appendChild(wgh_statusDiv);

                wgh_filterToggleBtn = document.createElement('button');
                wgh_filterToggleBtn.id = 'wghFilterToggleBtn';
                wgh_filterToggleBtn.className = 'wghBtn';
                wgh_filterToggleBtn.title = 'Фильтры';
                wgh_filterToggleBtn.innerHTML = '🛠️';
                wgh_filterToggleBtn.onclick = () => { wgh_filterAccordionContainer.style.display = wgh_filterAccordionContainer.style.display === 'none' ? 'block' : 'none'; };
                header.appendChild(wgh_filterToggleBtn);

                wgh_sortButtonsContainer = document.createElement('div');
                wgh_sortButtonsContainer.id = 'wghSortButtons';
                wgh_sortButtonsContainer.style.cssText = `display: flex; gap: 5px; align-items: center; margin-left: auto;`;
                header.appendChild(wgh_sortButtonsContainer);
                wgh_giftIconBtn = document.createElement('button');
                wgh_giftIconBtn.id = 'wghGiftModeBtn';
                wgh_giftIconBtn.className = 'wghBtn';
                wgh_giftIconBtn.title = 'Режим помощника подарков';
                wgh_giftIconBtn.innerHTML = '🎁';
                wgh_giftIconBtn.onclick = wgh_toggleGiftMode;
                header.appendChild(wgh_giftIconBtn);
                container.appendChild(header);

                wgh_giftModeContainer = document.createElement('div');
                wgh_giftModeContainer.id = 'wghGiftAccordionContainer';
                wgh_giftModeContainer.className = 'wghAccordionContainer';

                wgh_createFilterAccordion();

                container.appendChild(wgh_filterAccordionContainer);
                container.appendChild(wgh_giftModeContainer);

                wgh_resultsContainer = document.createElement('div');
                wgh_resultsContainer.id = 'wghResultsContainer';
                wgh_resultsContainer.style.cssText = ` flex-grow: 1; overflow-y: auto; overflow-x: hidden; scrollbar-color: #4b6f9c #17202d; scrollbar-width: thin; padding-right: 5px; `;
                wgh_resultsContainer.innerHTML = `<style> #wghResultsContainer::-webkit-scrollbar { width: 8px; } #wghResultsContainer::-webkit-scrollbar-track { background: #17202d; border-radius: 4px; } #wghResultsContainer::-webkit-scrollbar-thumb { background-color: #4b6f9c; border-radius: 4px; border: 2px solid #17202d; } #wghResultsContainer::-webkit-scrollbar-thumb:hover { background-color: #67c1f5; } </style>`;
                wgh_resultsDiv = document.createElement('div');
                wgh_resultsDiv.id = 'wghResults';
                wgh_resultsDiv.style.cssText = ` display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 15px; padding-top: 5px; `;
                wgh_resultsContainer.appendChild(wgh_resultsDiv);
                container.appendChild(wgh_resultsContainer);
                wgh_progressBar = wgh_createProgressBar('wghMainProgress');
                container.appendChild(wgh_progressBar);
                wgh_giftProgressBar = wgh_createProgressBar('wghGiftProgress');
                container.appendChild(wgh_giftProgressBar);
                wgh_closeBtn = document.createElement('button');
                wgh_closeBtn.id = 'wghCloseBtn';
                wgh_closeBtn.innerHTML = '&times;';
                wgh_closeBtn.onclick = wgh_hideModal;
                wgh_closeBtn.style.cssText = ` position: absolute; top: 10px; right: 15px; font-size: 30px; color: #aaa; background: none; border: none; cursor: pointer; line-height: 1; z-index: 10002; padding: 5px; transition: color 0.2s, transform 0.2s; `;
                wgh_closeBtn.onmouseover = () => { wgh_closeBtn.style.color = '#fff'; wgh_closeBtn.style.transform = 'scale(1.1)'; };
                wgh_closeBtn.onmouseout = () => { wgh_closeBtn.style.color = '#aaa'; wgh_closeBtn.style.transform = 'scale(1)'; };
                wgh_modal.appendChild(wgh_closeBtn);
                wgh_modal.appendChild(container);
                document.body.appendChild(wgh_modal);
                wgh_createSortButtons();
                wgh_createGiftAccordion();
                wgh_updateSortButtonsState();
                wgh_setupFilterEventListeners();

                function handleEsc(event) {
                    if (event.key === 'Escape') {
                        const descModal = document.getElementById('wghDescriptionModal');
                        if (descModal) { descModal.remove(); }
                        else { wgh_hideModal(); }
                    }
                }
                document.addEventListener('keydown', handleEsc);
                wgh_modal._escHandler = handleEsc;
            }

            function wgh_showModal() {
                if (!wgh_modal) wgh_createModal();
                wgh_updateStatus('Нажмите "Собрать данные" для анализа списка желаемого.');
                wgh_resultsDiv.innerHTML = '';
                wgh_gameDataStore = {};
                wgh_hideGiftMode(true);
                wgh_filterAccordionContainer.style.display = 'none';
                wgh_hideProgressBar(wgh_progressBar);
                wgh_hideProgressBar(wgh_giftProgressBar);
                document.body.style.overflow = 'hidden';
                wgh_modal.style.display = 'block';
            }

            function wgh_hideModal() {
                if (wgh_modal) {
                    wgh_modal.style.display = 'none';
                    if (wgh_modal._escHandler) {
                        document.removeEventListener('keydown', wgh_modal._escHandler);
                        delete wgh_modal._escHandler;
                    }
                }
                document.body.style.overflow = '';
            }

            function wgh_updateStatus(message, isLoading = false) {
                if (wgh_statusDiv) {
                    wgh_statusDiv.innerHTML = message + (isLoading ? ' <span class="wghSpinner"></span>' : '');
                }
                const collectBtn = document.getElementById('wghCollectBtn');
                if (collectBtn) collectBtn.disabled = isLoading;
                if (wgh_fetchFriendPricesBtn) wgh_fetchFriendPricesBtn.disabled = isLoading;
            }

            const debouncedFilterApplication = debounce(() => {
                wgh_applyFilters();
                wgh_updateFilterPlaceholders();
            }, WGH_FILTER_DEBOUNCE_MS);

            function wgh_setupFilterEventListeners() {
                const inputs = ['wghFilterReviewCountMin', 'wghFilterReviewCountMax', 'wghFilterRatingMin', 'wghFilterRatingMax', 'wghFilterPriceMin', 'wghFilterPriceMax', 'wghFilterDiscountMin', 'wghFilterDiscountMax', 'wghFilterDateMin', 'wghFilterDateMax'];
                inputs.forEach(id => document.getElementById(id)?.addEventListener('input', debouncedFilterApplication));

                const checkboxes = ['wghFilterDiscounted', 'wghFilterNoPrice'];
                checkboxes.forEach(id => document.getElementById(id)?.addEventListener('change', debouncedFilterApplication));

                document.querySelectorAll('input[name="wghLangFilter"]').forEach(radio => radio.addEventListener('change', debouncedFilterApplication));
                document.querySelectorAll('input[name="wghEaFilter"]').forEach(radio => radio.addEventListener('change', debouncedFilterApplication));

                document.getElementById('wghResetFilters')?.addEventListener('click', () => {
                    document.querySelectorAll('#wghFilterAccordionContainer input').forEach(input => {
                        if (input.type === 'checkbox') input.checked = false;
                        if (input.type === 'number' || input.type === 'date') input.value = '';
                        if (input.type === 'radio' && input.value === 'any') input.checked = true;
                    });
                    debouncedFilterApplication();
                });
                document.querySelectorAll('input[name="wghRrcFilter"]').forEach(radio => radio.addEventListener('change', debouncedFilterApplication));
            }

            function wgh_applyFilters() {
                 if (!wgh_resultsDiv) return;

                 const getVal = (id) => document.getElementById(id)?.value || null;
                 const getNum = (id) => { const v = getVal(id); return v ? parseFloat(v) : null; };
                 const getChecked = (id) => document.getElementById(id)?.checked || false;
                 const getRadio = (name) => document.querySelector(`input[name="${name}"]:checked`)?.value || 'any';

                 const filters = {
                     onlyDiscount: getChecked('wghFilterDiscounted'),
                     hideNoPrice: getChecked('wghFilterNoPrice'),
                     reviewCountMin: getNum('wghFilterReviewCountMin'),
                     reviewCountMax: getNum('wghFilterReviewCountMax'),
                     ratingMin: getNum('wghFilterRatingMin'),
                     ratingMax: getNum('wghFilterRatingMax'),
                     priceMin: getNum('wghFilterPriceMin'),
                     priceMax: getNum('wghFilterPriceMax'),
                     discountMin: getNum('wghFilterDiscountMin'),
                     discountMax: getNum('wghFilterDiscountMax'),
                     dateMin: getVal('wghFilterDateMin') ? new Date(getVal('wghFilterDateMin')).getTime() : null,
                     dateMax: getVal('wghFilterDateMax') ? new Date(getVal('wghFilterDateMax')).getTime() : null,
                     lang: getRadio('wghLangFilter'),
                     ea: getRadio('wghEaFilter'),
                     rrc: getRadio('wghRrcFilter')
                 };

                 GM_setValue(WGH_FILTER_STORAGE_KEY, filters);

                 const cards = document.querySelectorAll('.wghGameCard');
                 const visibleGamesData = [];

                 cards.forEach(card => {
                     const appid = card.dataset.appid;
                     const gameData = wgh_gameDataStore[appid]?.myData;
                     if (!gameData) {
                         card.style.display = 'none';
                         return;
                     }

                     let isVisible = true;

                     if (filters.onlyDiscount && (!gameData.priceData || gameData.priceData.discountPercent <= 0)) isVisible = false;
                     if (isVisible && filters.hideNoPrice && (!gameData.priceData || gameData.priceData.finalCents === null)) isVisible = false;
                     if (isVisible && filters.reviewCountMin !== null && gameData.reviewCount < filters.reviewCountMin) isVisible = false;
                     if (isVisible && filters.reviewCountMax !== null && gameData.reviewCount > filters.reviewCountMax) isVisible = false;
                     if (isVisible && filters.ratingMin !== null && gameData.reviewPercent < filters.ratingMin) isVisible = false;
                     if (isVisible && filters.ratingMax !== null && gameData.reviewPercent > filters.ratingMax) isVisible = false;

                     if (isVisible && gameData.priceData) {
                         const price = gameData.priceData.finalCents / 100;
                         if (filters.priceMin !== null && price < filters.priceMin) isVisible = false;
                         if (isVisible && filters.priceMax !== null && price > filters.priceMax) isVisible = false;
                     }

                     if (isVisible && gameData.priceData) {
                          const discount = gameData.priceData.discountPercent || 0;
                         if (filters.discountMin !== null && discount < filters.discountMin) isVisible = false;
                         if (isVisible && filters.discountMax !== null && discount > filters.discountMax) isVisible = false;
                     }

                     if (isVisible && gameData.releaseDateTimestamp) {
                         const itemDate = gameData.releaseDateTimestamp * 1000;
                         if (filters.dateMin && itemDate < filters.dateMin) isVisible = false;
                         if (isVisible && filters.dateMax && itemDate > filters.dateMax) isVisible = false;
                     }

                     if (isVisible && filters.lang !== 'any') {
                        const langSupport = gameData.language_support_russian || {};
                        const hasVoice = langSupport.full_audio;
                        const hasText = langSupport.supported || langSupport.subtitles;
                        if (filters.lang === 'text_only' && (!hasText || hasVoice)) isVisible = false;
                        if (filters.lang === 'voice' && !hasVoice) isVisible = false;
                        if (filters.lang === 'none' && (hasText || hasVoice)) isVisible = false;
                     }

                     if (isVisible && filters.ea !== 'any') {
                         if (filters.ea === 'early_access' && !gameData.is_early_access) isVisible = false;
                         if (filters.ea === 'released' && gameData.is_early_access) isVisible = false;
                     }

                     if (isVisible && filters.rrc !== 'any') {
                         const rrcStatus = gameData.rrcInfo?.status;
                         if (!rrcStatus || rrcStatus !== filters.rrc) {
                             isVisible = false;
                         }
                     }

                     if (isVisible && wgh_showGiftableOnly) {
                        const isGiftableByPrice = card.dataset.giftablePrice === 'true';
                        const canGiftByApi = card.dataset.canGiftApi === 'true';
                        if (!isGiftableByPrice || !canGiftByApi) {
                            isVisible = false;
                        }
                     }

                     card.style.display = isVisible ? 'flex' : 'none';
                     if(isVisible) {
                        visibleGamesData.push(gameData);
                     }
                 });

                 wgh_updateFilterPlaceholders(visibleGamesData);
            }

            function wgh_updateFilterPlaceholders() {
                const filteredGames = Object.values(wgh_gameDataStore).filter(game => {
                    const card = document.querySelector(`.wghGameCard[data-appid="${game.myData.appid}"]`);
                    return card && card.style.display !== 'none';
                }).map(game => game.myData);

                if (filteredGames.length === 0) {
                     ['wghFilterReviewCountMin', 'wghFilterReviewCountMax', 'wghFilterRatingMin', 'wghFilterRatingMax', 'wghFilterPriceMin', 'wghFilterPriceMax', 'wghFilterDiscountMin', 'wghFilterDiscountMax'].forEach(id => {
                        const el = document.getElementById(id);
                        if (el) el.placeholder = 'N/A';
                     });
                     return;
                }

                const stats = {
                    minReviews: Infinity, maxReviews: 0, minRating: 101, maxRating: 0,
                    minPrice: Infinity, maxPrice: 0, minDiscount: 101, maxDiscount: 0
                };

                filteredGames.forEach(item => {
                    if (item.reviewCount > 0) {
                        stats.minReviews = Math.min(stats.minReviews, item.reviewCount);
                    }
                    stats.maxReviews = Math.max(stats.maxReviews, item.reviewCount);

                    if (item.reviewCount > 0) {
                        stats.minRating = Math.min(stats.minRating, item.reviewPercent);
                        stats.maxRating = Math.max(stats.maxRating, item.reviewPercent);
                    }
                    if (item.priceData && item.priceData.finalCents !== null) {
                        const price = item.priceData.finalCents / 100;
                        stats.minPrice = Math.min(stats.minPrice, price);
                        stats.maxPrice = Math.max(stats.maxPrice, price);
                    }
                    if (item.priceData && item.priceData.discountPercent > 0) {
                        stats.minDiscount = Math.min(stats.minDiscount, item.priceData.discountPercent);
                        stats.maxDiscount = Math.max(stats.maxDiscount, item.priceData.discountPercent);
                    }
                });

                const setPlaceholder = (id, prefix, value, fallback = 'N/A') => {
                    const el = document.getElementById(id);
                    if (el) {
                        if (value !== Infinity && value !== -Infinity && value !== 101) {
                             el.placeholder = `${prefix} ${Math.round(value)}`;
                        } else {
                             el.placeholder = fallback;
                        }
                    }
                };

                setPlaceholder('wghFilterReviewCountMin', 'От', stats.minReviews);
                setPlaceholder('wghFilterReviewCountMax', 'До', stats.maxReviews);
                setPlaceholder('wghFilterRatingMin', 'От', stats.minRating === 101 ? 0 : stats.minRating);
                setPlaceholder('wghFilterRatingMax', 'До', stats.maxRating);
                setPlaceholder('wghFilterPriceMin', 'От', stats.minPrice);
                setPlaceholder('wghFilterPriceMax', 'До', stats.maxPrice);
                setPlaceholder('wghFilterDiscountMin', 'От', stats.minDiscount === 101 ? 0 : stats.minDiscount);
                setPlaceholder('wghFilterDiscountMax', 'До', stats.maxDiscount);
            }

            async function wgh_collectData() {
                wgh_updateStatus('Извлечение AppID...', true);
                wgh_resultsDiv.innerHTML = '';
                wgh_gameDataStore = {};
                wgh_hideGiftMode(true);
                wgh_showProgressBar(wgh_progressBar, 0);

                try {
                    wgh_allAppIds = await wgh_extractAppIdsFromPage();
                    if (!wgh_allAppIds || wgh_allAppIds.length === 0) {
                        wgh_updateStatus('Не удалось найти игры в списке желаемого.');
                        wgh_hideProgressBar(wgh_progressBar);
                        return;
                    }
                    const totalGames = wgh_allAppIds.length;
                    const totalBatches = Math.ceil(totalGames / WGH_BATCH_SIZE);
                    wgh_updateStatus(`Найдено ${totalGames} игр. Запрос данных для вашего региона... (0/${totalBatches})`, true);

                    for (let i = 0; i < totalGames; i += WGH_BATCH_SIZE) {
                        const batch = wgh_allAppIds.slice(i, i + WGH_BATCH_SIZE);
                        const batchData = await wgh_fetchBatchGameData(batch, wgh_currentUserCountryCode);
                        wgh_processBatchData(batchData, 'myData');
                        const progress = ((i + batch.length) / totalGames) * (wgh_currentUserCountryCode === 'RU' ? 50 : 100);
                        wgh_updateProgressBar(wgh_progressBar, progress);
                        wgh_updateStatus(`Запрос данных для вашего региона... (${Math.ceil((i + batch.length)/WGH_BATCH_SIZE)}/${totalBatches})`, true);
                        await new Promise(res => setTimeout(res, 200));
                    }

                    if (wgh_currentUserCountryCode === 'RU') {
                        wgh_updateStatus(`Запрос данных из US для анализа РРЦ... (0/${totalBatches})`, true);
                        for (let i = 0; i < totalGames; i += WGH_BATCH_SIZE) {
                            const batch = wgh_allAppIds.slice(i, i + WGH_BATCH_SIZE);
                            const usBatchData = await wgh_fetchBatchGameData(batch, 'US');
                            wgh_processBatchData(usBatchData, 'usData');
                            const progress = 50 + (((i + batch.length) / totalGames) * 50);
                            wgh_updateProgressBar(wgh_progressBar, progress);
                            wgh_updateStatus(`Запрос данных из US... (${Math.ceil((i + batch.length)/WGH_BATCH_SIZE)}/${totalBatches})`, true);
                            await new Promise(res => setTimeout(res, 200));
                        }
                        wgh_processRrcData();
                    }

                    wgh_updateStatus(`Данные для ${Object.keys(wgh_gameDataStore).length} игр получены.`);
                    wgh_applySort(wgh_currentSort.field, wgh_currentSort.direction);
                    await wgh_renderResults();
                    wgh_hideProgressBar(wgh_progressBar);
                    wgh_updateFilterPlaceholders();

                } catch (error) {
                    wgh_updateStatus(`Ошибка при сборе данных: ${error.message}`);
                    console.error('[WGH] Ошибка сбора данных:', error);
                    wgh_hideProgressBar(wgh_progressBar);
                }
            }

            function wgh_processRrcData() {
                if (wgh_currentUserCountryCode !== 'RU') return;

                for (const appid in wgh_gameDataStore) {
                    const game = wgh_gameDataStore[appid];
                    if (game.myData && game.usData && game.myData.priceData && game.usData.priceData) {
                        const usPriceCents = game.usData.priceData.originalCents ?? game.usData.priceData.finalCents;
                        const ruPriceCents = game.myData.priceData.originalCents ?? game.myData.priceData.finalCents;

                        if (usPriceCents !== null && ruPriceCents !== null) {
                            const pUSD = usPriceCents / 100;
                            const actualRubPrice = ruPriceCents / 100;
                            const recommendedRubPrice = calculateRecommendedRubPrice(pUSD);

                            if (recommendedRubPrice !== null) {
                                const diff = actualRubPrice - recommendedRubPrice;
                                const diffPercent = recommendedRubPrice !== 0 ? (diff / recommendedRubPrice) * 100 : (diff > 0 ? Infinity : -Infinity);

                                let status = 'equal';
                                if (diffPercent > 1) status = 'higher';
                                if (diffPercent < -1) status = 'lower';

                                game.myData.rrcInfo = {
                                    status: status,
                                    diff: diff,
                                    diffPercent: diffPercent,
                                    recommended: recommendedRubPrice
                                };
                            }
                        }
                    }
                }
            }

            async function wgh_extractAppIdsFromPage() {
                let appIds = [];
                if (typeof unsafeWindow !== 'undefined' && unsafeWindow.SSR && unsafeWindow.SSR.renderContext && typeof unsafeWindow.SSR.renderContext.queryData === 'string') {
                    try {
                        const queryData = JSON.parse(unsafeWindow.SSR.renderContext.queryData);
                        if (queryData && Array.isArray(queryData.queries)) {
                            const wishlistQuery = queryData.queries.find(q =>
                                q && Array.isArray(q.queryKey) && q.queryKey[0] === 'WishlistSortedFiltered'
                            );
                            if (wishlistQuery && wishlistQuery.state && wishlistQuery.state.data && Array.isArray(wishlistQuery.state.data.items)) {
                                appIds = wishlistQuery.state.data.items.map(item => item.appid);
                            }
                        }
                    } catch (e) {
                        console.error("[WGH] Ошибка при разборе данных SSR:", e);
                    }
                }
                if (appIds.length === 0 && typeof unsafeWindow.g_rgWishlistData !== 'undefined' && Array.isArray(unsafeWindow.g_rgWishlistData)) {
                    console.warn("[WGH] Используется резервный метод g_rgWishlistData.");
                    appIds = unsafeWindow.g_rgWishlistData.map(item => item.appid).filter(id => id);
                }
                if (appIds.length === 0) {
                    throw new Error("Не удалось извлечь AppID. Возможно, структура страницы изменилась или список желаемого пуст.");
                }
                return [...new Set(appIds)];
            }

            function wgh_detectUserRegion() {
                let found = false;
                if (typeof unsafeWindow?.SSR?.renderContext?.queryData === 'string') {
                    try {
                        const queryData = JSON.parse(unsafeWindow.SSR.renderContext.queryData);
                        const walletInfoQuery = queryData?.queries?.find(q => q?.queryKey?.[0] === 'CurrentUserWalletDetails');
                        const walletInfoInSSR = walletInfoQuery?.state?.data;

                        if (walletInfoInSSR?.has_wallet && walletInfoInSSR?.currency_code && walletInfoInSSR?.wallet_country_code) {
                            wgh_currentUserCurrencyCode = walletInfoInSSR.currency_code;
                            wgh_currentUserCountryCode = walletInfoInSSR.wallet_country_code;
                            wgh_currentUserISOCurrencyCode = WGH_CURRENCY_CODE_TO_ISO[wgh_currentUserCurrencyCode] || null;
                            if (wgh_currentUserCountryCode && wgh_currentUserISOCurrencyCode) {
                                found = true;
                                console.log(`[WGH] Регион успешно определен через SSR/Wallet: ${wgh_currentUserCountryCode}`);
                            }
                        }
                    } catch(e) {
                        console.error('[WGH] Ошибка при разборе SSR для определения региона:', e);
                    }
                }
                if (!found && typeof unsafeWindow?.Config?.COUNTRY === 'string') {
                    const countryCode = unsafeWindow.Config.COUNTRY;
                    const currencyInfo = Object.entries(WGH_COUNTRY_CURRENCY_MAP).find(([key, data]) => key === countryCode);
                    if (currencyInfo) {
                        wgh_currentUserCountryCode = currencyInfo[0];
                        wgh_currentUserCurrencyCode = currencyInfo[1].code;
                        wgh_currentUserISOCurrencyCode = currencyInfo[1].iso;
                        found = true;
                        console.log(`[WGH] Регион определен через резервный метод window.Config: ${wgh_currentUserCountryCode}`);
                    }
                }
                if (!found && typeof unsafeWindow.g_rgWalletInfo !== 'undefined' && unsafeWindow.g_rgWalletInfo.wallet_currency) {
                    console.warn("[WGH] Используется самый старый резервный метод g_rgWalletInfo.");
                    wgh_currentUserCurrencyCode = unsafeWindow.g_rgWalletInfo.wallet_currency;
                    wgh_currentUserCountryCode = WGH_CURRENCY_CODE_TO_COUNTRY[wgh_currentUserCurrencyCode] || null;
                    wgh_currentUserISOCurrencyCode = WGH_CURRENCY_CODE_TO_ISO[wgh_currentUserCurrencyCode] || null;
                    if (wgh_currentUserCountryCode && wgh_currentUserISOCurrencyCode) {
                        found = true;
                    }
                }
                if (!found) {
                    console.warn('[WGH] Не удалось определить регион пользователя, используется значение по умолчанию: RU/RUB.');
                    wgh_currentUserCountryCode = 'RU';
                    wgh_currentUserCurrencyCode = 5;
                    wgh_currentUserISOCurrencyCode = 'RUB';
                }
                if (wgh_myRegionDisplay) {
                    wgh_myRegionDisplay.textContent = `${wgh_currentUserCountryCode || '??'} (${wgh_currentUserISOCurrencyCode || '???'})`;
                }
            }

            async function wgh_fetchBatchGameData(appIdsBatch, countryCode) {
                const inputJson = {
                    ids: appIdsBatch.map(appid => ({ appid })),
                    context: {
                        language: "russian",
                        country_code: countryCode || 'RU',
                        steam_realm: 1
                    },
                    data_request: {
                        include_assets: true,
                        include_release: true,
                        include_platforms: true,
                        include_all_purchase_options: true,
                        include_screenshots: true,
                        include_trailers: true,
                        include_ratings: true,
                        include_tag_count: true,
                        include_reviews: true,
                        include_basic_info: true,
                        include_supported_languages: true,
                        include_full_description: true,
                        include_included_items: true,
                        included_item_data_request: {
                            include_assets: true,
                            include_release: true,
                            include_platforms: true,
                            include_all_purchase_options: true,
                            include_screenshots: true,
                            include_trailers: true,
                            include_ratings: true,
                            include_tag_count: true,
                            include_reviews: true,
                            include_basic_info: true,
                            include_supported_languages: true,
                            include_full_description: true,
                            include_included_items: true,
                            include_assets_without_overrides: true,
                            apply_user_filters: false,
                            include_links: true
                        },
                        include_assets_without_overrides: true,
                        apply_user_filters: false,
                        include_links: true
                    }
                };
                return new Promise((resolve, reject) => {
                    GM_xmlhttpRequest({
                        method: "GET",
                        url: `${WGH_API_URL}?input_json=${encodeURIComponent(JSON.stringify(inputJson))}`,
                        timeout: WGH_REQUEST_TIMEOUT_MS,
                        onload: function(response) {
                            try {
                                if (response.status >= 200 && response.status < 400) {
                                    const data = JSON.parse(response.responseText);
                                    if (data?.response?.store_items) {
                                        resolve(data.response.store_items);
                                    } else {
                                        console.warn(`[WGH] API вернул успех, но нет store_items для batch: ${appIdsBatch.join(',')}`, data);
                                        resolve([]);
                                    }
                                } else {
                                    reject(new Error(`HTTP статус ${response.status} для батча`));
                                }
                            } catch (e) {
                                reject(new Error(`Ошибка парсинга JSON: ${e.message}`));
                            }
                        },
                        onerror: (error) => reject(new Error(`Сетевая ошибка: ${error?.finalUrl || WGH_API_URL}`)),
                        ontimeout: () => reject(new Error('Таймаут запроса к Steam API'))
                    });
                });
            }

            function wgh_processBatchData(batchData, dataType = 'myData') {
                if (!Array.isArray(batchData)) return;
                batchData.forEach(item => {
                    if (!item || !item.id || item.success !== 1) return;
                    const appid = item.id;
                    if (!wgh_gameDataStore[appid]) {
                        wgh_gameDataStore[appid] = { myData: null, friendData: null };
                    }
                    const headerFileName = item.assets?.header;
                    const imageUrl = headerFileName ? `${WGH_IMAGE_BASE_URL}${item.id}/${headerFileName}` : `${WGH_IMAGE_BASE_URL}${item.id}/header.jpg`;
                    const extractedData = {
                        appid: item.appid,
                        name: item.name,
                        type: item.type,
                        imageUrl: imageUrl,
                        releaseDateTimestamp: item.release?.steam_release_date || null,
                        reviewScore: item.reviews?.summary_filtered?.review_score || 0,
                        reviewPercent: item.reviews?.summary_filtered?.percent_positive || 0,
                        reviewCount: item.reviews?.summary_filtered?.review_count || 0,
                        reviewDesc: item.reviews?.summary_filtered?.review_score_label || '',
                        platforms: {
                            windows: item.platforms?.windows || false,
                            mac: item.platforms?.mac || false,
                            linux: item.platforms?.steamos_linux || false,
                        },
                        canGift: item.best_purchase_option?.user_can_purchase_as_gift || false,
                        priceData: null,
                        publishers: item.basic_info?.publishers?.map(p => p.name).join(", "),
                        developers: item.basic_info?.developers?.map(d => d.name).join(", "),
                        franchises: item.basic_info?.franchises?.map(f => f.name).join(", "),
                        is_early_access: item.release?.is_early_access,
                        tagids: item.tagids || [],
                        short_description: item.basic_info?.short_description,
                        language_support_russian: item.supported_languages?.find(lang => lang.elanguage === 8)
                    };
                    const purchaseOption = item.best_purchase_option;
                    if (purchaseOption) {
                        extractedData.priceData = {
                            formattedFinal: purchaseOption.formatted_final_price || 'N/A',
                            finalCents: purchaseOption.final_price_in_cents ? parseInt(purchaseOption.final_price_in_cents, 10) : null,
                            formattedOriginal: purchaseOption.formatted_original_price || null,
                            originalCents: purchaseOption.original_price_in_cents ? parseInt(purchaseOption.original_price_in_cents, 10) : null,
                            discountPercent: purchaseOption.discount_pct || 0
                        };
                    }
                    wgh_gameDataStore[appid][dataType] = extractedData;
                });
            }

            async function wgh_renderResults() {
                if (!wgh_resultsDiv) return;
                wgh_resultsDiv.innerHTML = '';
                const fragment = document.createDocumentFragment();
                const sortedAppIds = Object.keys(wgh_gameDataStore);
                sortedAppIds.sort((idA, idB) => {
                    const a = wgh_gameDataStore[idA]?.myData;
                    const b = wgh_gameDataStore[idB]?.myData;
                    return wgh_compareItems(a, b, wgh_currentSort.field, wgh_currentSort.direction);
                });
                const tagsData = await wgh_loadSteamTags();
                sortedAppIds.forEach(appid => {
                    const game = wgh_gameDataStore[appid];
                    if (game && game.myData) {
                        fragment.appendChild(wgh_createGameCard(appid, game, tagsData));
                    }
                });
                wgh_resultsDiv.appendChild(fragment);
                wgh_applyFilters();
            }

            function wgh_showDescriptionModal(title, description) {
                const modalId = 'wghDescriptionModal';
                let modal = document.getElementById(modalId);
                if (modal) modal.remove();

                modal = document.createElement('div');
                modal.id = modalId;
                modal.style.cssText = `
                    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
                    background-color: rgba(0,0,0,0.7); display: flex; align-items: center;
                    justify-content: center; z-index: 10001;
                `;

                const content = document.createElement('div');
                content.style.cssText = `
                    background-color: #1b2838; color: #c6d4df; padding: 25px;
                    border-radius: 5px; max-width: 600px; width: 90%; max-height: 80vh;
                    overflow-y: auto; border: 1px solid #4b6f9c; position: relative;
                `;

                const closeBtn = document.createElement('button');
                closeBtn.innerHTML = '&times;';
                closeBtn.style.cssText = `
                    position: absolute; top: 10px; right: 15px; background: none; border: none;
                    color: #aaa; font-size: 28px; cursor: pointer;
                `;
                closeBtn.onclick = () => modal.remove();

                const titleEl = document.createElement('h3');
                titleEl.textContent = title;
                titleEl.style.cssText = `color: #67c1f5; margin-top: 0;`;

                const descEl = document.createElement('p');
                descEl.innerHTML = description || 'Описание отсутствует.';
                descEl.style.lineHeight = '1.6';

                content.appendChild(closeBtn);
                content.appendChild(titleEl);
                content.appendChild(descEl);
                modal.appendChild(content);
                document.body.appendChild(modal);

                modal.addEventListener('click', (e) => {
                    if (e.target === modal) {
                        modal.remove();
                    }
                });
            }

            function wgh_createGameCard(appid, game, tagsData) {
                const myData = game.myData;
                const friendData = game.friendData;
                const card = document.createElement('div');
                card.className = 'wghGameCard';
                card.dataset.appid = appid;
                card.dataset.giftablePrice = 'unknown';
                card.dataset.canGiftApi = myData.canGift ? 'true' : 'false';

                const reviewClass = wgh_getReviewClass(myData.reviewPercent, myData.reviewCount);
                const releaseDateStr = myData.releaseDateTimestamp ? new Date(myData.releaseDateTimestamp * 1000).toLocaleDateString('ru-RU') : 'Неизвестно';

                let friendPriceStr = '';
                let priceDiffStr = '';
                let priceDiffClass = '';

                if (wgh_giftModeActive && friendData?.priceData && myData?.priceData && wgh_exchangeRates) {
                    const friendCents = friendData.priceData.finalCents;
                    const myCents = myData.priceData.finalCents;
                    if (friendCents !== null && myCents !== null) {
                        const friendPriceInMyCurrency = wgh_convertCurrency(friendCents / 100, wgh_currentFriendCountryCode, wgh_currentUserCountryCode);
                        if (friendPriceInMyCurrency !== null) {
                            const myPrice = myCents / 100;
                            const diff = friendPriceInMyCurrency - myPrice;
                            const diffPercent = myPrice > 0 ? diff / myPrice : (diff > 0 ? Infinity : -Infinity);
                            friendPriceStr = `Цена друга: ${friendPriceInMyCurrency.toLocaleString('ru-RU', { style: 'currency', currency: wgh_currentUserISOCurrencyCode, minimumFractionDigits: 0, maximumFractionDigits: 2 })}`;
                            if (Math.abs(diffPercent) <= WGH_GIFT_PRICE_DIFF_THRESHOLD) {
                                priceDiffClass = 'wghPriceDiffGood';
                                card.dataset.giftablePrice = 'true';
                            } else {
                                priceDiffClass = 'wghPriceDiffBad';
                                card.dataset.giftablePrice = 'false';
                            }
                            priceDiffStr = `Разница: ${diff > 0 ? '+' : ''}${diff.toLocaleString('ru-RU', { style: 'currency', currency: wgh_currentUserISOCurrencyCode, minimumFractionDigits: 0, maximumFractionDigits: 2 })} (${diffPercent === Infinity || diffPercent === -Infinity ? '∞' : (diffPercent * 100).toFixed(0)}%)`;
                        } else {
                            friendPriceStr = 'Цена друга: Ошибка конв.';
                            card.dataset.giftablePrice = 'false';
                        }
                    } else {
                        friendPriceStr = 'Цена друга: N/A';
                        card.dataset.giftablePrice = 'false';
                    }
                } else if (wgh_giftModeActive) {
                    friendPriceStr = 'Цена друга: ...';
                    card.dataset.giftablePrice = 'false';
                }

                const tagsHtml = myData.tagids.slice(0, 5).map(tagId =>
                    `<div class="wghTag">${tagsData[tagId] || `Тег #${tagId}`}</div>`
                ).join('');

                let languageSupportRussianText = "Отсутствует";
                if (myData.language_support_russian) {
                    let tempLangText = "";
                    if (myData.language_support_russian.supported) tempLangText += "Интерфейс, ";
                    if (myData.language_support_russian.full_audio) tempLangText += "Озвучка, ";
                    if (myData.language_support_russian.subtitles) tempLangText += "Субтитры, ";
                    if (tempLangText) {
                        languageSupportRussianText = tempLangText.slice(0, -2);
                    }
                }

                let rrcInfoHtml = '';
                if (myData.rrcInfo) {
                    const { status, diff, diffPercent, recommended } = myData.rrcInfo;
                    const textMap = { 'lower': '< РРЦ', 'equal': '= РРЦ', 'higher': '> РРЦ' };
                    const diffText = `${diff > 0 ? '+' : ''}${diff.toFixed(0)} ₽ (${diffPercent.toFixed(0)}%)`;
                    const recommendedPriceText = ` | ${recommended.toLocaleString('ru-RU')} ₽`;

                    rrcInfoHtml = `<div class="wghRrcInfo wghRrc-${status}">
                        <span class="wghRrcStatus">${textMap[status]}${recommendedPriceText}</span>
                        <span class="wghRrcDiff">${diffText}</span>
                    </div>`;
                }

                const descButton = document.createElement('button');
                descButton.textContent = 'Описание';
                descButton.className = 'wghDescButton';
                descButton.onclick = (e) => {
                    e.preventDefault();
                    e.stopPropagation();
                    wgh_showDescriptionModal(myData.name, myData.short_description);
                };

                card.innerHTML = `
                    <a href="https://store.steampowered.com/app/${appid}" target="_blank" class="wghCardLink">
                        <div class="wghCardImageWrapper">
                            <img src="${myData.imageUrl}" alt="${myData.name}" loading="lazy" onerror="this.onerror=null;this.src='https://via.placeholder.com/292x136?text=No+Image';">
                            ${myData.priceData?.discountPercent > 0 ? `<div class="wghCardDiscountBadge">-${myData.priceData.discountPercent}%</div>` : ''}
                        </div>
                    </a>
                    <div class="wghCardContent">
                        <a href="https://store.steampowered.com/app/${appid}" target="_blank" class="wghCardTitle" title="${myData.name}">${myData.name}</a>
                        <div class="wghCardPrice">
                            ${myData.priceData?.formattedOriginal ? `<span class="wghOriginalPrice">${myData.priceData.formattedOriginal}</span>` : ''}
                            <span class="wghCurrentPrice">${myData.priceData?.formattedFinal || 'N/A'}</span>
                        </div>
                        ${rrcInfoHtml}
                        <div class="wghCardReviews ${reviewClass}" title="${myData.reviewCount.toLocaleString('ru-RU')} отзывов">${wgh_getCustomReviewDescription(myData.reviewPercent, myData.reviewCount)} (${myData.reviewPercent}%) | ${myData.reviewCount.toLocaleString('ru-RU')}</div>
                        <div class="wghCardInfoGrid">
                            <div class="wghCardInfoItem"><strong>Издатель:</strong> <span>${myData.publishers || 'N/A'}</span></div>
                            <div class="wghCardInfoItem"><strong>Разработчик:</strong> <span>${myData.developers || 'N/A'}</span></div>
                            <div class="wghCardInfoItem"><strong>Серия:</strong> <span>${myData.franchises || 'N/A'}</span></div>
                            <div class="wghCardInfoItem"><strong>Ранний доступ:</strong> <span>${myData.is_early_access ? 'Да' : 'Нет'}</span></div>
                            <div class="wghCardInfoItem"><strong>Дата выхода:</strong> <span>${releaseDateStr}</span></div>
                            <div class="wghCardInfoItem"><strong>Русский язык:</strong> <span>${languageSupportRussianText}</span></div>
                        </div>
                        <div class="wghTagsContainer">${tagsHtml}</div>
                        <div class="wghCardFooter">
                            ${myData.canGift ? '' : '<div class="wghCannotGift">Нельзя подарить</div>'}
                            ${friendPriceStr ? `<div class="wghFriendPrice">${friendPriceStr}</div>` : ''}
                            ${priceDiffStr ? `<div class="wghPriceDiff ${priceDiffClass}">${priceDiffStr}</div>` : ''}
                        </div>
                    </div>`;

                card.querySelector('.wghCardFooter').prepend(descButton);
                return card;
            }

            function wgh_getReviewClass(percent, count) {
                if (count === 0) return 'wghReviewNone';
                if (percent >= 70) return 'wghReviewPositive';
                if (percent >= 40) return 'wghReviewMixed';
                return 'wghReviewNegative';
            }

            function wgh_createSortButtons() {
                if (!wgh_sortButtonsContainer) return;
                wgh_sortButtonsContainer.innerHTML = '';
                const createBtn = (field, text) => {
                    const btn = document.createElement('button');
                    btn.className = 'wghBtn sortBtn';
                    btn.dataset.sort = field;
                    btn.textContent = text;
                    btn.onclick = () => wgh_handleSort(field);
                    wgh_sortButtonsContainer.appendChild(btn);
                    return btn;
                };
                createBtn('price', 'Цена');
                createBtn('discountPercent', '% Скидки');
                createBtn('name', 'Название');
                createBtn('releaseDateTimestamp', 'Дата выхода');
                createBtn('reviewPercent', '% Отзывов');
            }

            function wgh_handleSort(field) {
                const defaultDirections = {
                    price: 'asc',
                    discountPercent: 'desc',
                    name: 'asc',
                    releaseDateTimestamp: 'desc',
                    reviewPercent: 'desc'
                };
                let newDirection;
                if (wgh_currentSort.field === field) {
                    newDirection = wgh_currentSort.direction === 'asc' ? 'desc' : 'asc';
                } else {
                    newDirection = defaultDirections[field] || 'asc';
                }
                wgh_currentSort.field = field;
                wgh_currentSort.direction = newDirection;
                wgh_applySort(field, newDirection);
                wgh_renderResults();
                wgh_updateSortButtonsState();
            }

            function wgh_applySort(field, direction) {
                wgh_currentSort = { field, direction };
            }

            function wgh_compareItems(a, b, field, direction) {
                if (!a && !b) return 0;
                if (!a) return direction === 'asc' ? 1 : -1;
                if (!b) return direction === 'asc' ? -1 : 1;
                const dirMultiplier = direction === 'asc' ? 1 : -1;
                let valA, valB;
                switch (field) {
                    case 'price':
                        valA = a.priceData?.finalCents ?? (direction === 'asc' ? Infinity : -Infinity);
                        valB = b.priceData?.finalCents ?? (direction === 'asc' ? Infinity : -Infinity);
                        break;
                    case 'discountPercent':
                        valA = a.priceData?.discountPercent ?? -1;
                        valB = b.priceData?.discountPercent ?? -1;
                        break;
                    case 'name':
                        valA = a.name?.toLowerCase() || '';
                        valB = b.name?.toLowerCase() || '';
                        return valA.localeCompare(valB) * dirMultiplier;
                    case 'releaseDateTimestamp':
                        valA = a.releaseDateTimestamp ?? (direction === 'asc' ? Infinity : 0);
                        valB = b.releaseDateTimestamp ?? (direction === 'asc' ? Infinity : 0);
                        break;
                    case 'reviewPercent':
                        valA = a.reviewPercent ?? -1;
                        valB = b.reviewPercent ?? -1;
                        break;
                    default:
                        return 0;
                }
                let comparisonResult = 0;
                const fallbackAsc = Infinity;
                const fallbackDesc = -Infinity;
                if (valA === null || valA === undefined || isNaN(valA) || valA === Infinity || valA === -Infinity) valA = direction === 'asc' ? fallbackAsc : fallbackDesc;
                if (valB === null || valB === undefined || isNaN(valB) || valB === Infinity || valB === -Infinity) valB = direction === 'asc' ? fallbackAsc : fallbackDesc;
                if (valA < valB) comparisonResult = -1;
                else if (valA > valB) comparisonResult = 1;
                else comparisonResult = 0;
                comparisonResult *= dirMultiplier;
                if (comparisonResult === 0 && field !== 'price') {
                    const priceA = a.priceData?.finalCents ?? Infinity;
                    const priceB = b.priceData?.finalCents ?? Infinity;
                    if (priceA < priceB) return -1;
                    if (priceA > priceB) return 1;
                }
                if (comparisonResult === 0 && field !== 'name') {
                    return (a.name?.toLowerCase() || '').localeCompare(b.name?.toLowerCase() || '');
                }
                return comparisonResult;
            }

            function wgh_updateSortButtonsState() {
                if (!wgh_sortButtonsContainer) return;
                const buttons = wgh_sortButtonsContainer.querySelectorAll('.sortBtn');
                buttons.forEach(btn => {
                    const btnField = btn.dataset.sort;
                    const baseText = btn.textContent.replace(/ [▲▼]$/, '');
                    if (btnField === wgh_currentSort.field) {
                        const arrow = wgh_currentSort.direction === 'asc' ? ' ▲' : ' ▼';
                        btn.classList.add('active');
                        btn.textContent = baseText + arrow;
                    } else {
                        btn.classList.remove('active');
                        btn.textContent = baseText;
                    }
                });
            }

            function wgh_createGiftAccordion() {
                if (!wgh_giftModeContainer) return;
                wgh_giftModeContainer.innerHTML = '';
                const accordionContent = document.createElement('div');
                accordionContent.id = 'wghGiftAccordionContent';
                accordionContent.className = 'wghAccordionContent';
                const myRegionDiv = document.createElement('div');
                myRegionDiv.innerHTML = `Ваш регион: <strong id="wghMyRegionDisplay">${wgh_currentUserCountryCode || '??'} (${wgh_currentUserISOCurrencyCode || '???'})</strong>`;
                myRegionDiv.style.marginRight = '15px';
                accordionContent.appendChild(myRegionDiv);
                wgh_myRegionDisplay = myRegionDiv.querySelector('strong');
                const friendRegionLabel = document.createElement('label');
                friendRegionLabel.textContent = 'Регион друга: ';
                friendRegionLabel.style.marginRight = '5px';
                accordionContent.appendChild(friendRegionLabel);
                wgh_friendRegionSelect = document.createElement('select');
                wgh_friendRegionSelect.id = 'wghFriendRegionSelect';
                wgh_friendRegionSelect.className = 'wghSelect';
                wgh_friendRegionSelect.innerHTML = '<option value="">-- Выберите --</option>';
                Object.entries(WGH_COUNTRY_CURRENCY_MAP).sort(([, a], [, b]) => a.name.localeCompare(b.name)).forEach(([code, data]) => {
                    if (code !== wgh_currentUserCountryCode) {
                        const option = document.createElement('option');
                        option.value = code;
                        option.textContent = `${data.name} (${code})`;
                        wgh_friendRegionSelect.appendChild(option);
                    }
                });
                accordionContent.appendChild(wgh_friendRegionSelect);
                wgh_fetchFriendPricesBtn = document.createElement('button');
                wgh_fetchFriendPricesBtn.id = 'wghFetchFriendPricesBtn';
                wgh_fetchFriendPricesBtn.className = 'wghBtn wghPrimaryBtn';
                wgh_fetchFriendPricesBtn.textContent = 'Узнать цены';
                wgh_fetchFriendPricesBtn.onclick = wgh_fetchFriendData;
                accordionContent.appendChild(wgh_fetchFriendPricesBtn);
                const giftFilterDiv = document.createElement('div');
                giftFilterDiv.style.marginLeft = 'auto';
                giftFilterDiv.innerHTML = ` <label title="Показать только игры с разницей цен +/- ${WGH_GIFT_PRICE_DIFF_THRESHOLD * 100}% и возможностью покупки в подарок"> <input type="checkbox" id="wghGiftableFilterCheckbox"> Можно подарить </label> `;
                wgh_giftableFilterCheckbox = giftFilterDiv.querySelector('input');
                wgh_giftableFilterCheckbox.onchange = wgh_handleGiftableFilterChange;
                accordionContent.appendChild(giftFilterDiv);
                wgh_giftModeContainer.appendChild(accordionContent);
            }

            function wgh_toggleGiftMode() {
                wgh_giftModeActive = !wgh_giftModeActive;
                wgh_giftModeContainer.style.display = wgh_giftModeActive ? 'block' : 'none';
                if (wgh_giftIconBtn) wgh_giftIconBtn.classList.toggle('active', wgh_giftModeActive);
                if (!wgh_giftModeActive) {
                    wgh_hideGiftMode(true);
                }
                wgh_renderResults();
            }

            function wgh_hideGiftMode(resetSelection = false) {
                wgh_giftModeActive = false;
                wgh_currentFriendCountryCode = null;
                wgh_showGiftableOnly = false;
                if (wgh_giftModeContainer) wgh_giftModeContainer.style.display = 'none';
                if (wgh_giftIconBtn) wgh_giftIconBtn.classList.remove('active');
                if (resetSelection && wgh_friendRegionSelect) wgh_friendRegionSelect.value = '';
                if (wgh_giftableFilterCheckbox) wgh_giftableFilterCheckbox.checked = false;
                wgh_hideProgressBar(wgh_giftProgressBar);
                Object.values(wgh_gameDataStore).forEach(game => game.friendData = null);
                wgh_renderResults();
            }

            async function wgh_fetchFriendData() {
                wgh_currentFriendCountryCode = wgh_friendRegionSelect.value;
                if (!wgh_currentFriendCountryCode) {
                    wgh_updateStatus('Выберите регион друга.');
                    return;
                }
                if (wgh_allAppIds.length === 0) {
                    wgh_updateStatus('Сначала соберите данные для своего списка желаемого.');
                    return;
                }
                wgh_updateStatus(`Запрос цен для региона ${wgh_currentFriendCountryCode}... (0/${Math.ceil(wgh_allAppIds.length / WGH_BATCH_SIZE)})`, true);
                wgh_showProgressBar(wgh_giftProgressBar, 0);
                Object.values(wgh_gameDataStore).forEach(game => game.friendData = null);
                wgh_exchangeRates = null;
                try {
                    const friendCurrencyInfo = WGH_COUNTRY_CURRENCY_MAP[wgh_currentFriendCountryCode];
                    const myCurrencyInfo = WGH_COUNTRY_CURRENCY_MAP[wgh_currentUserCountryCode];
                    if (friendCurrencyInfo && myCurrencyInfo && friendCurrencyInfo.code !== myCurrencyInfo.code) {
                        wgh_updateStatus(`Получение курса валют...`, true);
                        try {
                            wgh_exchangeRates = await wgh_fetchExchangeRates(friendCurrencyInfo.iso);
                        } catch (rateError) {
                            wgh_updateStatus(`Ошибка получения курса валют: ${rateError.message}. Сравнение цен будет неточным.`);
                            console.error("[WGH] Ошибка курса валют:", rateError);
                            await new Promise(res => setTimeout(res, 2000));
                            wgh_exchangeRates = {};
                        }
                    } else {
                        wgh_exchangeRates = {};
                    }
                    const totalBatches = Math.ceil(wgh_allAppIds.length / WGH_BATCH_SIZE);
                    let processedBatches = 0;
                    wgh_updateStatus(`Запрос цен для региона ${wgh_currentFriendCountryCode}... (0/${totalBatches})`, true);
                    for (let i = 0; i < wgh_allAppIds.length; i += WGH_BATCH_SIZE) {
                        const batch = wgh_allAppIds.slice(i, i + WGH_BATCH_SIZE);
                        const batchData = await wgh_fetchBatchGameData(batch, wgh_currentFriendCountryCode);
                        wgh_processBatchData(batchData, 'friendData');
                        processedBatches++;
                        const progress = (processedBatches / totalBatches) * 100;
                        wgh_updateProgressBar(wgh_giftProgressBar, progress);
                        wgh_updateStatus(`Запрос цен для региона ${wgh_currentFriendCountryCode}... (${processedBatches}/${totalBatches})`, true);
                        await new Promise(res => setTimeout(res, 200));
                    }
                    wgh_updateStatus(`Цены для региона ${wgh_currentFriendCountryCode} получены.`);
                    wgh_renderResults();
                    wgh_hideProgressBar(wgh_giftProgressBar);
                } catch (error) {
                    wgh_updateStatus(`Ошибка при получении цен друга: ${error.message}`);
                    console.error('[WGH] Ошибка получения цен друга:', error);
                    wgh_hideProgressBar(wgh_giftProgressBar);
                    wgh_renderResults();
                }
            }

            async function wgh_fetchExchangeRates(baseCurrencyIso) {
                if (!baseCurrencyIso) throw new Error("Base currency ISO code not provided");
                const apiUrl = `${WGH_CURRENCY_API_URL}${baseCurrencyIso.toLowerCase()}.json`;
                return new Promise((resolve, reject) => {
                    GM_xmlhttpRequest({
                        method: "GET",
                        url: apiUrl,
                        responseType: 'json',
                        timeout: WGH_REQUEST_TIMEOUT_MS / 2,
                        onload: (response) => {
                            if (response.status >= 200 && response.status < 400 && response.response) {
                                const rates = response.response[baseCurrencyIso.toLowerCase()];
                                if (rates && typeof rates === 'object') {
                                    resolve(rates);
                                } else {
                                    reject(new Error(`Курсы для ${baseCurrencyIso} не найдены в ответе API`));
                                }
                            } else {
                                reject(new Error(`Ошибка API валют: статус ${response.status}`));
                            }
                        },
                        onerror: (error) => reject(new Error('Сетевая ошибка API валют')),
                        ontimeout: () => reject(new Error('Таймаут запроса API валют'))
                    });
                });
            }

            function wgh_convertCurrency(amount, fromCountryCode, toCountryCode) {
                if (fromCountryCode === toCountryCode) return amount;
                if (!wgh_exchangeRates) {
                    console.warn('[WGH] Exchange rates not loaded for conversion');
                    return null;
                }
                const fromCurrencyInfo = WGH_COUNTRY_CURRENCY_MAP[fromCountryCode];
                const toCurrencyInfo = WGH_COUNTRY_CURRENCY_MAP[toCountryCode];
                if (!fromCurrencyInfo || !toCurrencyInfo) {
                    console.warn('[WGH] Unknown country code for conversion', fromCountryCode, toCountryCode);
                    return null;
                }
                if (fromCurrencyInfo.code === toCurrencyInfo.code) {
                    return amount;
                }
                const toCurrencyKey = toCurrencyInfo.iso?.toLowerCase();
                if (!toCurrencyKey) {
                    console.warn('[WGH] Unknown target ISO currency code for conversion', toCountryCode);
                    return null;
                }
                if (wgh_exchangeRates[toCurrencyKey] === undefined || wgh_exchangeRates[toCurrencyKey] === null) {
                    console.warn(`[WGH] Exchange rate to ${toCurrencyKey} not available`);
                    return null;
                }
                const rate = wgh_exchangeRates[toCurrencyKey];
                return parseFloat((amount * rate).toFixed(2));
            }

            function wgh_handleGiftableFilterChange() {
                wgh_showGiftableOnly = wgh_giftableFilterCheckbox.checked;
                wgh_applyFilters();
            }

            function wgh_applyGiftFilter() {
                if (!wgh_giftModeActive) {
                    document.querySelectorAll('.wghGameCard').forEach(card => {
                        card.style.display = 'flex';
                    });
                    return;
                }
                const cards = document.querySelectorAll('.wghGameCard');
                cards.forEach(card => {
                    const isGiftableByPrice = card.dataset.giftablePrice === 'true';
                    const canGiftByApi = card.dataset.canGiftApi === 'true';
                    if (wgh_showGiftableOnly) {
                        if (isGiftableByPrice && canGiftByApi) {
                            card.style.display = 'flex';
                        } else {
                            card.style.display = 'none';
                            card.classList.add('wgh-filtered-out');
                        }
                    } else {
                        card.style.display = 'flex';
                        card.classList.remove('wgh-filtered-out');
                    }
                });
            }

            function wgh_createProgressBar(id) {
                const barContainer = document.createElement('div');
                barContainer.id = id;
                barContainer.style.cssText = ` width: 80%; max-width: 600px; height: 10px; background-color: #3a4f6a; border-radius: 5px; overflow: hidden; margin: 10px auto; display: none; flex-shrink: 0; `;
                const barFill = document.createElement('div');
                barFill.className = 'wghProgressBarFill';
                barFill.style.cssText = ` width: 0%; height: 100%; background-color: #67c1f5; border-radius: 5px; transition: width 0.3s ease-out; `;
                barContainer.appendChild(barFill);
                return barContainer;
            }

            function wgh_showProgressBar(barElement, initialProgress = 0) {
                if (!barElement) return;
                const fill = barElement.querySelector('.wghProgressBarFill');
                fill.style.width = `${initialProgress}%`;
                barElement.style.display = 'block';
            }

            function wgh_updateProgressBar(barElement, progress) {
                if (!barElement) return;
                const fill = barElement.querySelector('.wghProgressBarFill');
                fill.style.width = `${Math.min(100, Math.max(0, progress))}%`;
            }

            function wgh_hideProgressBar(barElement) {
                if (!barElement) return;
                barElement.style.display = 'none';
            }

            function wgh_addStyles() {
                GM_addStyle(`
                        .wghBtn {
                        	padding: 8px 14px;
                        	font-size: 14px;
                        	color: #c6d4df;
                        	border: 1px solid #4b6f9c;
                        	border-radius: 3px;
                        	cursor: pointer;
                        	white-space: nowrap;
                        	height: 36px;
                        	display: inline-flex;
                        	align-items: center;
                        	justify-content: center;
                        	flex-shrink: 0;
                        	background-color: rgba(42, 71, 94, 0.8);
                        	transition: background-color 0.2s, border-color 0.2s;
                        	text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.4);
                        }

                        .wghBtn:hover:not(:disabled) {
                        	background-color: rgba(67, 103, 133, 0.9);
                        	border-color: #67c1f5;
                        }

                        .wghBtn:disabled {
                        	opacity: 0.6;
                        	cursor: default;
                        }

                        .wghPrimaryBtn {
                        	background-color: rgba(77, 136, 255, 0.8);
                        	border-color: #4D88FF;
                        }

                        .wghPrimaryBtn:hover:not(:disabled) {
                        	background-color: rgba(51, 102, 204, 0.9);
                        }

                        .wghBtn.sortBtn.active {
                        	background-color: rgba(0, 123, 255, 0.8);
                        	border-color: #007bff;
                        }

                        .wghBtn.sortBtn.active:hover {
                        	background-color: rgba(0, 86, 179, 0.9);
                        }

                        #wghGiftModeBtn.active,
                        #wghFilterToggleBtn.active {
                        	background-color: rgba(0, 123, 255, 0.8);
                        	border-color: #007bff;
                        }

                        .wghSelect {
                        	margin-left: 5px;
                        	background-color: #333;
                        	color: #eee;
                        	border: 1px solid #555;
                        	border-radius: 4px;
                        	height: 36px;
                        	padding: 0 8px;
                        	font-size: 14px;
                        	cursor: pointer;
                        	flex-shrink: 0;
                        	outline: none;
                        	max-width: 200px;
                        }

                        .wghSelect:focus {
                        	border-color: #67c1f5;
                        }

                        .wghGameCard {
                        	background-color: rgba(42, 46, 51, 0.85);
                        	border-radius: 6px;
                        	padding: 10px;
                        	display: flex;
                        	flex-direction: column;
                        	transition: transform 0.2s ease, box-shadow 0.2s ease;
                        	box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
                        	color: #c6d4df;
                        	font-size: 13px;
                        	border: 1px solid #333941;
                        	min-height: 500px;
                        }

                        .wghGameCard:hover {
                        	transform: translateY(-2px);
                        	box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
                        	border-color: #4b6f9c;
                        }

                        .wghCardLink {
                        	text-decoration: none;
                        	color: inherit;
                        	display: block;
                        }

                        .wghCardImageWrapper {
                        	position: relative;
                        	width: 100%;
                        	aspect-ratio: 292 / 136;
                        	margin-bottom: 8px;
                        	background-color: #111;
                        	border-radius: 4px;
                        	overflow: hidden;
                        	display: flex;
                        	align-items: center;
                        	justify-content: center;
                        	border: 1px solid #333941;
                        }

                        .wghCardImageWrapper img {
                        	display: block;
                        	max-width: 100%;
                        	max-height: 100%;
                        	width: 100%;
                        	height: 100%;
                        	object-fit: cover;
                        	border-radius: 4px;
                        }

                        .wghCardDiscountBadge {
                        	position: absolute;
                        	bottom: 5px;
                        	right: 5px;
                        	background-color: #e2004b;
                        	color: white;
                        	padding: 2px 6px;
                        	font-size: 12px;
                        	border-radius: 3px;
                        	font-weight: 600;
                        	z-index: 1;
                        }

                        .wghCardContent {
                        	flex-grow: 1;
                        	display: flex;
                        	flex-direction: column;
                        }

                        .wghCardTitle {
                        	font-size: 16px;
                        	font-weight: 500;
                        	line-height: 1.3;
                        	height: 2.6em;
                        	overflow: hidden;
                        	text-overflow: ellipsis;
                        	margin-bottom: 5px;
                        	color: #e5e5e5;
                        	display: -webkit-box;
                        	-webkit-line-clamp: 2;
                        	-webkit-box-orient: vertical;
                        	text-decoration: none;
                        }

                        .wghCardTitle:hover {
                        	color: #fff;
                        }

                        .wghCardPrice {
                        	display: flex;
                        	align-items: baseline;
                        	gap: 8px;
                        	margin-bottom: 8px;
                        	min-height: 22px;
                        }

                        .wghCurrentPrice {
                        	font-size: 18px;
                        	font-weight: 600;
                        	color: #a4d007;
                        }

                        .wghOriginalPrice {
                        	font-size: 14px;
                        	color: #8f98a0;
                        	text-decoration: line-through;
                        }

                        .wghCardReviews {
                        	font-size: 13px;
                        	margin-bottom: 8px;
                        }

                        .wghReviewPositive {
                        	color: #66c0f4;
                        }

                        .wghReviewMixed {
                        	color: #a38b51;
                        }

                        .wghReviewNegative {
                        	color: #c44c2c;
                        }

                        .wghReviewNone {
                        	color: #8f98a0;
                        }

                        .wghCardInfoGrid {
                        	display: grid;
                        	grid-template-columns: 1fr;
                        	gap: 5px;
                        	font-size: 12px;
                        	color: #8f98a0;
                        	margin-bottom: 8px;
                        }

                        .wghCardInfoItem {
                        	white-space: nowrap;
                        	overflow: hidden;
                        	text-overflow: ellipsis;
                        	line-height: 1.4;
                        }

                        .wghCardInfoItem span {
                        	color: #c6d4df;
                        }

                        .wghTagsContainer {
                        	display: flex;
                        	flex-wrap: wrap;
                        	gap: 5px;
                        	margin-bottom: 10px;
                        }

                        .wghTag {
                        	background-color: rgba(103, 193, 245, 0.15);
                        	color: #8f98a0;
                        	padding: 3px 7px;
                        	border-radius: 3px;
                        	font-size: 12px;
                        }

                        .wghDescButton {
                        	background: #4b6f9c;
                        	color: white;
                        	border: none;
                        	padding: 6px 12px;
                        	border-radius: 3px;
                        	cursor: pointer;
                        	font-size: 13px;
                        	margin-top: 10px;
                        	width: 100%;
                        }

                        .wghDescButton:hover {
                        	background: #67c1f5;
                        }

                        .wghCardFooter {
                        	margin-top: auto;
                        	padding-top: 10px;
                        	border-top: 1px solid #3a4f6a;
                        }

                        .wghCannotGift {
                        	font-size: 12px;
                        	color: #ff8080;
                        	font-style: italic;
                        	margin-top: 5px;
                        }

                        .wghFriendPrice {
                        	font-size: 13px;
                        	color: #b0e0e6;
                        	margin-top: 5px;
                        }

                        .wghPriceDiff {
                        	font-size: 13px;
                        	font-weight: bold;
                        	margin-top: 2px;
                        }

                        .wghPriceDiffGood {
                        	color: #77dd77;
                        }

                        .wghPriceDiffBad {
                        	color: #ff6961;
                        }

                        @keyframes wghSpin {
                        	0% {
                        		transform: rotate(0deg);
                        	}

                        	100% {
                        		transform: rotate(360deg);
                        	}
                        }

                        .wghSpinner {
                        	border: 2px solid rgba(255, 255, 255, 0.3);
                        	border-radius: 50%;
                        	border-top-color: #fff;
                        	width: 1em;
                        	height: 1em;
                        	animation: wghSpin 1s linear infinite;
                        	display: inline-block;
                        	vertical-align: middle;
                        	margin-left: 8px;
                        }

                        .wghAccordionContainer {
                        	display: none;
                        	padding: 10px 0;
                        	border-bottom: 1px solid #3a4f6a;
                        	margin-bottom: 10px;
                        	flex-shrink: 0;
                        }

                        .wghAccordionContent,
                        .wghFilterGrid {
                        	padding: 10px;
                        	border: 1px solid #3a4f6a;
                        	border-radius: 4px;
                        	background-color: rgba(42, 71, 94, 0.2);
                        }

                        .wghAccordionContent {
                        	display: flex;
                        	flex-wrap: wrap;
                        	gap: 10px;
                        	align-items: center;
                        }

                        .wghFilterGrid {
                        	display: grid;
                        	grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
                        	margin-bottom: 10px;
                        }

                        .wghFilterGroup {
                        	display: flex;
                        	flex-direction: column;
                        	gap: 5px;
                        }

                        .wghFilterLabel {
                        	font-size: 13px;
                        	color: #c6d4df;
                        	margin-bottom: 3px;
                        }

                        .wghRangeInput {
                        	display: block;
                        }

                        .wghRangeInput input {
                        	width: 100%;
                        	margin-bottom: 5px;
                        }

                        .wghRangeInput input:last-child {
                        	margin-bottom: 0;
                        }

                        .wghRangeInput input {
                        	width: 50%;
                        	padding: 5px;
                        	background: #17202d;
                        	border: 1px solid #3a4f6a;
                        	color: #c6d4df;
                        	border-radius: 3px;
                        }

                        .wghRadioGroup,
                        .wghFilterCheckbox {
                        	display: flex;
                        	flex-direction: column;
                        	gap: 3px;
                        	font-size: 13px;
                        }

                        #wghResetFilters {
                        	margin-top: 10px;
                        }

                        .wghGameCard.wgh-filtered-out {
                        	display: none !important;
                        }

                        .wghRrcInfo {
                        	display: flex;
                        	justify-content: space-between;
                        	align-items: center;
                        	padding: 4px 8px;
                        	border-radius: 3px;
                        	margin-bottom: 8px;
                        	font-size: 13px;
                        }

                        .wghRrcStatus {
                        	font-weight: bold;
                        }

                        .wghRrcDiff {
                        	font-size: 12px;
                        }

                        .wghRrc-lower {
                        	background-color: rgba(102, 192, 244, 0.2);
                        	border: 1px solid rgba(102, 192, 244, 0.4);
                        	color: #c6d4df;
                        }

                        .wghRrc-equal {
                        	background-color: rgba(92, 184, 92, 0.2);
                        	border: 1px solid rgba(92, 184, 92, 0.4);
                        	color: #dff0d8;
                        }

                        .wghRrc-higher {
                        	background-color: rgba(217, 83, 79, 0.2);
                        	border: 1px solid rgba(217, 83, 79, 0.4);
                        	color: #f2dede;
                        }

                        .wghRrc-lower .wghRrcStatus {
                        	color: #d1e5fa;
                        }

                        .wghRrc-equal .wghRrcStatus {
                        	color: #c0ef15;
                        }

                        .wghRrc-higher .wghRrcStatus {
                        	color: #f2dede;
                        }

                        @media (max-width: 1600px) {
                        	#wghResults {
                        		grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
                        	}
                        }

                        @media (max-width: 1300px) {
                        	#wghResults {
                        		grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
                        	}
                        }

                        @media (max-width: 900px) {
                        	#wghResults {
                        		grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
                        	}
                        }

                        @media (max-width: 700px) {
                        	#wghResults {
                        		grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
                        	}

                        	#wghHeader {
                        		flex-direction: column;
                        		align-items: stretch;
                        	}

                        	#wghSortButtons {
                        		justify-content: space-around;
                        		margin-left: 0;
                        		margin-top: 5px;
                        		width: 100%;
                        		order: 3;
                        	}

                        	#wghGiftAccordionContent {
                        		flex-direction: column;
                        		align-items: flex-start;
                        	}

                        	#wghGiftAccordionContent label {
                        		margin-bottom: 5px;
                        	}

                        	#wghGiftAccordionContent #wghFriendRegionSelect,
                        	#wghGiftAccordionContent #wghFetchFriendPricesBtn {
                        		width: 100%;
                        		margin-bottom: 10px;
                        	}

                        	#wghGiftAccordionContent div[style*='margin-left: auto'] {
                        		width: 100%;
                        		margin-left: 0 !important;
                        		text-align: center;
                        	}

                        	#wghHeader>.wghBtn:first-child {
                        		order: 1;
                        		width: 100%;
                        		margin-bottom: 5px;
                        	}

                        	#wghGiftModeBtn,
                        	#wghFilterToggleBtn {
                        		order: 2;
                        		align-self: flex-end;
                        		margin-bottom: 5px;
                        	}

                        	#wghStatus {
                        		order: 0;
                        		text-align: center;
                        		justify-content: center;
                        		margin-bottom: 5px;
                        	}
                        }
                `);
            }

            function wgh_initialize() {
                wgh_detectUserRegion();
                wgh_addStyles();
                wgh_addAnalyzeButton();
            }

            setTimeout(wgh_initialize, WGH_INITIAL_DELAY_MS);

        })();
    }

    // Скрипт для проверки возможности отправки подарка со страницы игры друзьям в других странах | https://store.steampowered.com/app/*
    if (scriptsConfig.pageGiftHelper && unsafeWindow.location.pathname.includes('/app/')) {
        (function() {
            'use strict';

            const PGH_API_URL = "https://api.steampowered.com/IStoreBrowseService/GetItems/v1";
            const PGH_CURRENCY_API_URL = 'https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/';
            const PGH_REQUEST_TIMEOUT_MS = 15000;
            const PGH_GIFT_PRICE_DIFF_THRESHOLD = 0.10;
            const PGH_COUNTRY_CURRENCY_MAP = {
                'US': {
                    name: 'U.S. Dollar',
                    code: 1,
                    iso: 'usd'
                },
                'EU': {
                    name: 'Euro',
                    code: 3,
                    iso: 'eur'
                },
                'AR': {
                    name: 'LATAM - U.S. Dollar',
                    code: 1,
                    iso: 'usd'
                },
                'AU': {
                    name: 'Australian Dollar',
                    code: 21,
                    iso: 'aud'
                },
                'BR': {
                    name: 'Brazilian Real',
                    code: 7,
                    iso: 'brl'
                },
                'GB': {
                    name: 'British Pound',
                    code: 2,
                    iso: 'gbp'
                },
                'CA': {
                    name: 'Canadian Dollar',
                    code: 20,
                    iso: 'cad'
                },
                'CL': {
                    name: 'Chilean Peso',
                    code: 25,
                    iso: 'clp'
                },
                'CN': {
                    name: 'Chinese Yuan',
                    code: 23,
                    iso: 'cny'
                },
                'AZ': {
                    name: 'CIS - U.S. Dollar',
                    code: 1,
                    iso: 'usd'
                },
                'CO': {
                    name: 'Colombian Peso',
                    code: 27,
                    iso: 'cop'
                },
                'CR': {
                    name: 'Costa Rican Colon',
                    code: 40,
                    iso: 'crc'
                },
                'HK': {
                    name: 'Hong Kong Dollar',
                    code: 29,
                    iso: 'hkd'
                },
                'IN': {
                    name: 'Indian Rupee',
                    code: 24,
                    iso: 'inr'
                },
                'ID': {
                    name: 'Indonesian Rupiah',
                    code: 10,
                    iso: 'idr'
                },
                'IL': {
                    name: 'Israeli New Shekel',
                    code: 35,
                    iso: 'ils'
                },
                'JP': {
                    name: 'Japanese Yen',
                    code: 8,
                    iso: 'jpy'
                },
                'KZ': {
                    name: 'Kazakhstani Tenge',
                    code: 37,
                    iso: 'kzt'
                },
                'KW': {
                    name: 'Kuwaiti Dinar',
                    code: 38,
                    iso: 'kwd'
                },
                'MY': {
                    name: 'Malaysian Ringgit',
                    code: 11,
                    iso: 'myr'
                },
                'MX': {
                    name: 'Mexican Peso',
                    code: 19,
                    iso: 'mxn'
                },
                'NZ': {
                    name: 'New Zealand Dollar',
                    code: 22,
                    iso: 'nzd'
                },
                'NO': {
                    name: 'Norwegian Krone',
                    code: 9,
                    iso: 'nok'
                },
                'PE': {
                    name: 'Peruvian Sol',
                    code: 26,
                    iso: 'pen'
                },
                'PH': {
                    name: 'Philippine Peso',
                    code: 12,
                    iso: 'php'
                },
                'PL': {
                    name: 'Polish Zloty',
                    code: 6,
                    iso: 'pln'
                },
                'QA': {
                    name: 'Qatari Riyal',
                    code: 39,
                    iso: 'qar'
                },
                'RU': {
                    name: 'Russian Ruble',
                    code: 5,
                    iso: 'rub'
                },
                'SA': {
                    name: 'Saudi Riyal',
                    code: 31,
                    iso: 'sar'
                },
                'SG': {
                    name: 'Singapore Dollar',
                    code: 13,
                    iso: 'sgd'
                },
                'ZA': {
                    name: 'South African Rand',
                    code: 28,
                    iso: 'zar'
                },
                'PK': {
                    name: 'South Asia - USD',
                    code: 1,
                    iso: 'usd'
                },
                'KR': {
                    name: 'South Korean Won',
                    code: 16,
                    iso: 'krw'
                },
                'CH': {
                    name: 'Swiss Franc',
                    code: 4,
                    iso: 'chf'
                },
                'TW': {
                    name: 'Taiwan Dollar',
                    code: 30,
                    iso: 'twd'
                },
                'TH': {
                    name: 'Thai Baht',
                    code: 14,
                    iso: 'thb'
                },
                'TR': {
                    name: 'MENA - U.S. Dollar',
                    code: 1,
                    iso: 'usd'
                },
                'AE': {
                    name: 'U.A.E. Dirham',
                    code: 32,
                    iso: 'aed'
                },
                'UA': {
                    name: 'Ukrainian Hryvnia',
                    code: 18,
                    iso: 'uah'
                },
                'UY': {
                    name: 'Uruguayan Peso',
                    code: 41,
                    iso: 'uyu'
                },
                'VN': {
                    name: 'Vietnamese Dong',
                    code: 15,
                    iso: 'vnd'
                }
            };

            const PGH_ISO_TO_COUNTRY = Object.fromEntries(Object.entries(PGH_COUNTRY_CURRENCY_MAP).map(([country, data]) => [data.iso, country]));
            const PGH_ISO_TO_CODE = Object.fromEntries(Object.entries(PGH_COUNTRY_CURRENCY_MAP).map(([_, data]) => [data.iso, data.code]));

            let pgh_modal = null;
            let pgh_resultDiv = null;
            let pgh_fetchBtn = null;
            let pgh_regionSelect = null;
            let pgh_currentAppId = null;
            let pgh_currentUserPrice = null;
            let pgh_currentUserCurrencyISO = null;
            let pgh_exchangeRates = null;

            function pgh_addStyles() {
                GM_addStyle(`
                    .pgh_button {
                        margin-left: 3px;
                    }
                    #pghModal {
                        position: fixed;
                        top: 50%;
                        left: 50%;
                        transform: translate(-50%, -50%);
                        background-color: #1b2838;
                        color: #c6d4df;
                        padding: 20px;
                        border-radius: 5px;
                        border: 1px solid #67c1f5;
                        box-shadow: 0 5px 25px rgba(0, 0, 0, 0.7);
                        z-index: 10001;
                        display: none;
                        width: 400px;
                        font-family: "Motiva Sans", Sans-serif, Arial;
                    }
                    #pghModal h3 {
                        margin-top: 0;
                        margin-bottom: 15px;
                        color: #67c1f5;
                        text-align: center;
                        font-weight: 500;
                        font-size: 16px;
                    }
                    #pghModal label {
                        display: block;
                        margin-bottom: 5px;
                        font-size: 14px;
                    }
                    #pghRegionSelect {
                        width: 100%;
                        padding: 8px 10px;
                        margin-bottom: 15px;
                        background-color: #2a3f5a;
                        border: 1px solid #567d9c;
                        color: #ebebeb;
                        border-radius: 3px;
                        font-size: 14px;
                        cursor: pointer;
                        outline: none;
                    }
                    #pghRegionSelect:focus {
                        border-color: #67c1f5;
                        background-color: #314b6a;
                    }
                    #pghRegionSelect option {
                       background-color: #1b2838;
                       color: #c6d4df;
                    }
                     #pghFetchBtn {
                        display: block;
                        width: 100%;
                        padding: 10px;
                        background-color: #67c1f5;
                        color: #1b2838;
                        border: none;
                        border-radius: 3px;
                        cursor: pointer;
                        font-size: 15px;
                        font-weight: bold;
                        transition: background-color 0.2s;
                        margin-bottom: 15px;
                     }
                     #pghFetchBtn:hover:not(:disabled) {
                        background-color: #8ad3f7;
                     }
                     #pghFetchBtn:disabled {
                         background-color: #556772;
                         cursor: default;
                     }
                     #pghResult {
                        margin-top: 15px;
                        padding-top: 15px;
                        border-top: 1px solid #3a4f6a;
                        font-size: 13px;
                        line-height: 1.5;
                     }
                     .pgh_status_loading {
                         text-align: center;
                         color: #8f98a0;
                     }
                     .pgh_status_error {
                         color: #ff6961;
                         font-weight: bold;
                     }
                     .pgh_result_block {
                         padding: 10px;
                         border-radius: 3px;
                         margin-top: 10px;
                         text-align: center;
                         font-weight: bold;
                         font-size: 15px;
                     }
                     .pgh_result_giftable {
                         background-color: rgba(119, 221, 119, 0.2);
                         border: 1px solid #77dd77;
                         color: #dff0d8;
                     }
                     .pgh_result_not_giftable {
                         background-color: rgba(255, 105, 97, 0.2);
                         border: 1px solid #ff6961;
                         color: #f2dede;
                     }
                    #pghCloseBtn {
                        position: absolute;
                        top: 8px;
                        right: 10px;
                        font-size: 24px;
                        color: #8f98a0;
                        background: none;
                        border: none;
                        cursor: pointer;
                        line-height: 1;
                         padding: 0 5px;
                    }
                     #pghCloseBtn:hover {
                        color: #ffffff;
                     }
                `);
            }

            function pgh_parsePrice(priceStr) {
                if (typeof priceStr !== 'string' && typeof priceStr !== 'number') return null;
                const cleaned = String(priceStr).replace(/[^0-9.,]/g, '').replace(',', '.');
                const price = parseFloat(cleaned);
                return isNaN(price) ? null : price;
            }

            function pgh_getCurrentGameInfo() {
                const appIdMatch = unsafeWindow.location.pathname.match(/\/app\/(\d+)/);
                pgh_currentAppId = appIdMatch ? appIdMatch[1] : null;

                const priceMeta = document.querySelector('meta[itemprop="price"]');
                const currencyMeta = document.querySelector('meta[itemprop="priceCurrency"]');

                pgh_currentUserPrice = priceMeta ? pgh_parsePrice(priceMeta.content) : null;
                pgh_currentUserCurrencyISO = currencyMeta ? currencyMeta.content.toLowerCase() : null;

                if (pgh_currentUserPrice === null || pgh_currentUserPrice === 0) {
                    const purchaseBlock = document.querySelector('.game_purchase_action .price[data-price-final], .discount_block .discount_final_price[data-price-final]');
                    if (purchaseBlock) {
                        pgh_currentUserPrice = pgh_parsePrice(purchaseBlock.dataset.priceFinal) / 100;
                    } else {
                         const simplePrice = document.querySelector('.game_purchase_action .price:not([data-price-final])');
                         if(simplePrice) {
                              pgh_currentUserPrice = pgh_parsePrice(simplePrice.textContent.trim());
                         }
                    }
                }

                 if (!pgh_currentUserCurrencyISO) {
                    console.warn("[PGH] Не удалось определить валюту пользователя со страницы. Используем RUB по умолчанию.");
                    pgh_currentUserCurrencyISO = 'rub';
                 }

                return pgh_currentAppId && pgh_currentUserPrice !== null && pgh_currentUserCurrencyISO;
            }

            function pgh_showModal() {
                if (!pgh_getCurrentGameInfo()) {
                    alert("Не удалось получить информацию об игре и цене на этой странице.");
                    return;
                }

                if (!pgh_modal) {
                    pgh_modal = document.createElement('div');
                    pgh_modal.id = 'pghModal';
                    pgh_modal.innerHTML = `
                        <button id="pghCloseBtn" title="Закрыть">&times;</button>
                        <h3>Проверить возможность подарка</h3>
                        <label for="pghRegionSelect">Регион друга:</label>
                        <select id="pghRegionSelect">
                            <option value="">-- Выберите регион друга --</option>
                            ${Object.entries(PGH_COUNTRY_CURRENCY_MAP)
                                .sort(([, a], [, b]) => a.name.localeCompare(b.name))
                                .map(([code, data]) => `<option value="${code}">${data.name} (${code})</option>`)
                                .join('')}
                        </select>
                        <button id="pghFetchBtn" disabled>Узнать</button>
                        <div id="pghResult"></div>
                    `;
                    document.body.appendChild(pgh_modal);

                    pgh_resultDiv = document.getElementById('pghResult');
                    pgh_fetchBtn = document.getElementById('pghFetchBtn');
                    pgh_regionSelect = document.getElementById('pghRegionSelect');

                    document.getElementById('pghCloseBtn').addEventListener('click', pgh_hideModal);
                    pgh_fetchBtn.addEventListener('click', pgh_fetchAndComparePrices);
                    pgh_regionSelect.addEventListener('change', () => {
                        pgh_fetchBtn.disabled = !pgh_regionSelect.value;
                    });

                     pgh_modal._outsideClickListener = (event) => {
                         if (!pgh_modal.contains(event.target) && pgh_modal.style.display === 'block') {
                             pgh_hideModal();
                         }
                     };
                     document.addEventListener('click', pgh_modal._outsideClickListener, true);

                     pgh_modal._escListener = (event) => {
                         if (event.key === 'Escape' && pgh_modal.style.display === 'block') {
                             pgh_hideModal();
                         }
                     };
                     document.addEventListener('keydown', pgh_modal._escListener);

                }

                pgh_regionSelect.value = "";
                pgh_fetchBtn.disabled = true;
                pgh_resultDiv.innerHTML = "";
                pgh_modal.style.display = 'block';
            }

            function pgh_hideModal() {
                if (pgh_modal) {
                    pgh_modal.style.display = 'none';
                     if (pgh_modal._outsideClickListener) {
                         document.removeEventListener('click', pgh_modal._outsideClickListener, true);
                     }
                      if (pgh_modal._escListener) {
                          document.removeEventListener('keydown', pgh_modal._escListener);
                      }
                }
            }

            async function pgh_fetchFriendPrice(appId, friendCountryCode) {
                const friendCurrencyInfo = PGH_COUNTRY_CURRENCY_MAP[friendCountryCode];
                if (!friendCurrencyInfo) {
                    throw new Error("Неизвестный код страны друга.");
                }

                const inputJson = {
                    ids: [{ appid: parseInt(appId) }],
                    context: {
                        language: "russian",
                        country_code: friendCountryCode,
                        steam_realm: 1
                    },
                    data_request: {
                        include_basic_info: true,
                        include_all_purchase_options: true
                    }
                };

                return new Promise((resolve, reject) => {
                    GM_xmlhttpRequest({
                        method: "GET",
                        url: `${PGH_API_URL}?input_json=${encodeURIComponent(JSON.stringify(inputJson))}`,
                        timeout: PGH_REQUEST_TIMEOUT_MS,
                        responseType: 'json',
                        onload: function(response) {
                            if (response.status >= 200 && response.status < 400 && response.response) {
                                const itemData = response.response.response?.store_items?.[0];
                                if (itemData?.success === 1 && itemData?.best_purchase_option) {
                                    const priceData = itemData.best_purchase_option;
                                    const friendPriceCents = priceData.final_price_in_cents ? parseInt(priceData.final_price_in_cents, 10) : null;
                                    const canGift = priceData.user_can_purchase_as_gift || false;

                                    if (friendPriceCents !== null) {
                                        resolve({
                                            price: friendPriceCents / 100,
                                            currencyISO: friendCurrencyInfo.iso,
                                            formatted: priceData.formatted_final_price || 'N/A',
                                            canGift: canGift
                                        });
                                    } else {
                                        resolve({
                                            price: 0,
                                            currencyISO: friendCurrencyInfo.iso,
                                            formatted: priceData.formatted_final_price || 'Бесплатно',
                                            canGift: canGift
                                         });
                                    }
                                } else if (itemData?.success === 1 && !itemData?.best_purchase_option){
                                    reject(new Error(`Игра недоступна для покупки в регионе ${friendCountryCode}.`));
                                }
                                else {
                                    reject(new Error("Не удалось получить данные о цене в регионе друга. Возможно, игра не найдена или недоступна."));
                                }
                            } else {
                                reject(new Error(`Ошибка API Steam: Статус ${response.status}`));
                            }
                        },
                        onerror: (error) => reject(new Error('Сетевая ошибка при запросе цены друга')),
                        ontimeout: () => reject(new Error('Таймаут при запросе цены друга'))
                    });
                });
            }

            async function pgh_fetchExchangeRates(baseCurrencyIso) {
                if (pgh_exchangeRates && pgh_exchangeRates[baseCurrencyIso]) {
                    return pgh_exchangeRates[baseCurrencyIso];
                }

                const apiUrl = `${PGH_CURRENCY_API_URL}${baseCurrencyIso.toLowerCase()}.json`;
                return new Promise((resolve, reject) => {
                    GM_xmlhttpRequest({
                        method: "GET",
                        url: apiUrl,
                        responseType: 'json',
                        timeout: PGH_REQUEST_TIMEOUT_MS / 2,
                        onload: (response) => {
                            if (response.status >= 200 && response.status < 400 && response.response) {
                                const rates = response.response[baseCurrencyIso.toLowerCase()];
                                if (rates && typeof rates === 'object') {
                                    if (!pgh_exchangeRates) pgh_exchangeRates = {};
                                    pgh_exchangeRates[baseCurrencyIso] = rates;
                                    resolve(rates);
                                } else {
                                    reject(new Error(`Курсы для ${baseCurrencyIso} не найдены в ответе API`));
                                }
                            } else {
                                reject(new Error(`Ошибка API валют: статус ${response.status}`));
                            }
                        },
                        onerror: (error) => reject(new Error('Сетевая ошибка API валют')),
                        ontimeout: () => reject(new Error('Таймаут запроса API валют'))
                    });
                });
            }

            async function pgh_fetchAndComparePrices() {
                const selectedRegion = pgh_regionSelect.value;
                if (!selectedRegion) return;

                pgh_resultDiv.innerHTML = '<div class="pgh_status_loading">Загрузка данных...</div>';
                pgh_fetchBtn.disabled = true;
                pgh_regionSelect.disabled = true;

                try {
                    const friendPriceData = await pgh_fetchFriendPrice(pgh_currentAppId, selectedRegion);
                    const friendPrice = friendPriceData.price;
                    const friendCurrencyISO = friendPriceData.currencyISO;
                    const canFriendReceiveGift = friendPriceData.canGift;

                    let friendPriceInUserCurrency = friendPrice;
                    let exchangeRateUsed = null;

                    if (pgh_currentUserCurrencyISO !== friendCurrencyISO) {
                        try {
                            const rates = await pgh_fetchExchangeRates(friendCurrencyISO);
                            const rate = rates[pgh_currentUserCurrencyISO];
                            if (rate === undefined || rate === null) {
                                throw new Error(`Нет курса для ${pgh_currentUserCurrencyISO.toUpperCase()}`);
                            }
                            friendPriceInUserCurrency = parseFloat((friendPrice * rate).toFixed(2));
                            exchangeRateUsed = rate;
                        } catch (rateError) {
                            console.error("[PGH] Ошибка получения/использования курса:", rateError);
                            pgh_resultDiv.innerHTML = `<div class="pgh_status_error">Ошибка конвертации валют: ${rateError.message}. Сравнение невозможно.</div>`;
                            return;
                        }
                    }

                    const userPrice = pgh_currentUserPrice;
                    const priceDifference = friendPriceInUserCurrency - userPrice;
                    const priceDifferencePercent = userPrice > 0 ? (priceDifference / userPrice) : (priceDifference > 0 ? Infinity : -Infinity);

                    const isWithinThreshold = Math.abs(priceDifferencePercent) <= PGH_GIFT_PRICE_DIFF_THRESHOLD;
                    const canGift = isWithinThreshold && canFriendReceiveGift;

                    let resultHTML = `
                        Ваша цена: ${userPrice.toLocaleString('ru-RU', { style: 'currency', currency: pgh_currentUserCurrencyISO.toUpperCase(), minimumFractionDigits: 0, maximumFractionDigits: 2 })}<br>
                        Цена друга: ${friendPrice.toLocaleString('ru-RU', { style: 'currency', currency: friendCurrencyISO.toUpperCase(), minimumFractionDigits: 0, maximumFractionDigits: 2 })}
                    `;

                    if (pgh_currentUserCurrencyISO !== friendCurrencyISO && exchangeRateUsed !== null) {
                         resultHTML += ` ≈ ${friendPriceInUserCurrency.toLocaleString('ru-RU', { style: 'currency', currency: pgh_currentUserCurrencyISO.toUpperCase(), minimumFractionDigits: 0, maximumFractionDigits: 2 })}`;
                         resultHTML += ` <small>(курс ≈ ${exchangeRateUsed.toFixed(4)})</small>`;
                    }
                     resultHTML += `<br>`;

                    if (userPrice > 0) {
                         resultHTML += `Разница: ${priceDifference > 0 ? '+' : ''}${priceDifference.toLocaleString('ru-RU', { style: 'currency', currency: pgh_currentUserCurrencyISO.toUpperCase(), minimumFractionDigits: 0, maximumFractionDigits: 2 })}`;
                         resultHTML += ` (${priceDifferencePercent === Infinity || priceDifferencePercent === -Infinity ? 'N/A' : (priceDifferencePercent * 100).toFixed(0)}%)`;
                     } else {
                        resultHTML += `Разница: N/A (ваша цена 0)`;
                     }

                     const resultClass = canGift ? 'pgh_result_giftable' : 'pgh_result_not_giftable';
                     const resultText = canGift ? '~Можно подарить~' : '~Нельзя подарить~';

                     resultHTML += `<div class="pgh_result_block ${resultClass}">${resultText}</div>`;

                     if (!canFriendReceiveGift && isWithinThreshold) {
                        resultHTML += `<small>Примечание: Steam не разрешает покупку этой игры в подарок для данного региона, несмотря на подходящую разницу цен.</small>`;
                     } else if (!isWithinThreshold) {
                         resultHTML += `<small>Примечание: Разница цен (${(priceDifferencePercent * 100).toFixed(0)}%) превышает допустимый порог Steam (${(PGH_GIFT_PRICE_DIFF_THRESHOLD * 100)}%).</small>`;
                     }

                    pgh_resultDiv.innerHTML = resultHTML;

                } catch (error) {
                    console.error("[PGH] Ошибка при получении/сравнении цен:", error);
                    pgh_resultDiv.innerHTML = `<div class="pgh_status_error">Ошибка: ${error.message}</div>`;
                } finally {
                     pgh_fetchBtn.disabled = !pgh_regionSelect.value;
                     pgh_regionSelect.disabled = false;
                }
            }

            function pgh_addGiftButton() {
                const targetArea = document.querySelector('.game_area_purchase_section .game_area_purchase_game_wrapper .game_purchase_action, #add_to_cart > .btn_addtocart > span');
                const referenceButtonContainer = targetArea?.closest('.game_purchase_action') || document.getElementById('add_to_cart');

                 if (!referenceButtonContainer) {
                    console.warn('[PGH] Не найден контейнер для кнопки подарка.');
                    const smButton = document.querySelector('.salesMaster_button');
                    if (smButton) {
                        if (smButton.parentElement.querySelector('.pgh_button')) return;
                         const giftButton = pgh_createButtonElement();
                         smButton.insertAdjacentElement('afterend', giftButton);
                         console.log('[PGH] Кнопка подарка добавлена после SalesMaster.');
                    } else {
                          console.warn('[PGH] SalesMaster кнопка тоже не найдена.');
                     }
                    return;
                 }

                if (referenceButtonContainer.parentElement.querySelector('.pgh_button')) return;

                const giftButton = pgh_createButtonElement();

                referenceButtonContainer.parentNode.insertBefore(giftButton, referenceButtonContainer);
                 console.log('[PGH] Кнопка подарка добавлена.');
            }

            function pgh_createButtonElement() {
                const giftButtonContainer = document.createElement('div');
                giftButtonContainer.className = 'pgh_button queue_control_button';
                giftButtonContainer.style.marginLeft = '3px';

                const giftButton = document.createElement('div');
                giftButton.className = 'btnv6_blue_hoverfade btn_medium';
                giftButton.style.cssText = 'height: 32px; padding: 0 0; font-size: 18px; display: flex; align-items: center; justify-content: center;';
                giftButton.title = 'Проверить возможность подарка другу';
                giftButton.innerHTML = '<span>GIFT</span>';
                giftButton.addEventListener('click', (e) => {
                    e.preventDefault();
                    e.stopPropagation();
                    pgh_showModal();
                });

                giftButtonContainer.appendChild(giftButton);
                return giftButtonContainer;
            }

            function pgh_initialize() {
                pgh_addStyles();
                setTimeout(pgh_addGiftButton, 700);

                const observer = new MutationObserver((mutations) => {
                     mutations.forEach((mutation) => {
                         if (mutation.addedNodes.length > 0) {
                              if (document.querySelector('.game_area_purchase_section .game_area_purchase_game_wrapper') && !document.querySelector('.pgh_button')) {
                                   pgh_addGiftButton();
                              }
                         }
                     });
                 });

                 const mainPage = document.querySelector('#game_area_purchase');
                 if (mainPage) {
                     observer.observe(mainPage, { childList: true, subtree: true });
                 }
            }

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

        })();
    }

    // Скрипт для страницы игры (salesMaster; %; агрегатор цен из разных магазинов) | https://store.steampowered.com/app/*
    if (scriptsConfig.salesMaster && unsafeWindow.location.pathname.includes('/app/')) {
        (function() {
            'use strict';

            // --- Конфигурация SalesMaster (SM) ---
            const SM_STORAGE_PREFIX = 'salesMaster_v1_';
            const SM_EXCLUSION_STORAGE_KEY = SM_STORAGE_PREFIX + 'exclusions';
            const SM_FILTER_STORAGE_KEY = SM_STORAGE_PREFIX + 'filters';
            const SM_SORT_STORAGE_KEY = SM_STORAGE_PREFIX + 'sort';
            const SM_FILTER_DEBOUNCE_MS = 500;
            const SM_REQUEST_TIMEOUT_MS = 15000; // 15 секунд на запрос к магазину

            // --- Глобальные переменные SM ---
            let sm_currentResults = [];
            let sm_stores = {};
            let sm_activeRequests = 0;
            let sm_currentSort = GM_getValue(SM_SORT_STORAGE_KEY, {
                field: 'price',
                direction: 'asc'
            });
            let sm_exclusionKeywords = GM_getValue(SM_EXCLUSION_STORAGE_KEY, []);
            let sm_currentFilters = GM_getValue(SM_FILTER_STORAGE_KEY, {
                priceMin: '',
                priceMax: '',
                discountPercentMin: '',
                discountPercentMax: '',
                discountAmountMin: '',
                discountAmountMax: '',
                hasDiscount: false,
                stores: {}
            });
            let sm_filterDebounceTimeout;

            // --- Переменные для конвертации валют ---
            const SM_CURRENCY_MODE_STORAGE_KEY = SM_STORAGE_PREFIX + 'currencyMode';
            let sm_currentCurrencyMode = GM_getValue(SM_CURRENCY_MODE_STORAGE_KEY, 'RUB');
            let sm_exchangeRates = {};

            // --- DOM Элементы SM ---
            let sm_modal, sm_closeBtn, sm_searchBtn;
            let sm_resultsContainer, sm_resultsDiv, sm_statusDiv;
            let sm_filtersPanel, sm_exclusionTagsDiv, sm_exclusionTagsListDiv, sm_excludeInput, sm_addExcludeBtn;
            let sm_sortButtonsContainer;
            let sm_filterStoreCheckboxesContainer;

            // --- Вспомогательные функции SM ---
            function sm_parsePrice(priceStr) {
                if (!priceStr) return null;
                const cleaned = String(priceStr).replace(/[^0-9.,]/g, '').replace(',', '.');
                const price = parseFloat(cleaned);
                return isNaN(price) ? null : price;
            }

            function sm_parsePercent(percentStr) {
                if (!percentStr) return null;
                const cleaned = String(percentStr).replace(/[^\d.]/g, '');
                const percent = parseFloat(cleaned);
                return isNaN(percent) ? null : percent;
            }

            // Эта функция определяет валюту и приводит цену к рублям
            async function sm_processItemCurrency(itemData, priceString) {
                if (!priceString || typeof priceString !== 'string') {
                    itemData.currency = 'RUB'; // По умолчанию считаем рубли
                    return itemData;
                }

                if (priceString.includes('$') || itemData.currency?.toUpperCase() === 'USD' || itemData.currency?.toUpperCase() === 'CIS') {
                    itemData.currency = 'USD';
                    const usdToRubRate = sm_exchangeRates?.usd?.rub;
                    if (usdToRubRate) {
                        itemData.currentPrice = itemData.currentPrice * usdToRubRate;
                    } else {
                        // Если курс USD->RUB не загружен, пробуем обратный курс
                        const rubToUsdRate = sm_exchangeRates?.rub?.usd;
                        if(rubToUsdRate) {
                             itemData.currentPrice = itemData.currentPrice / rubToUsdRate;
                        } else {
                            sm_logError(itemData.storeName, 'Нет курсов для конвертации USD в RUB');
                            return null; // Не можем обработать цену
                        }
                    }
                } else if (priceString.includes('₸') || itemData.currency?.toUpperCase() === 'KZT') {
                    itemData.currency = 'KZT';
                    const kztToRubRate = sm_exchangeRates?.kzt?.rub;
                     if (kztToRubRate) {
                        itemData.currentPrice = itemData.currentPrice * kztToRubRate;
                    } else {
                         sm_logError(itemData.storeName, 'Нет курсов для конвертации KZT в RUB');
                         return null;
                    }
                }
                else {
                    itemData.currency = 'RUB'; // Если нет символов, считаем, что это рубли
                }
                 // После конвертации все цены в рублях
                itemData.currency = 'RUB';
                return itemData;
            }

            function sm_calculateMissingValues(item) {
                const price = item.currentPrice;
                let original = item.originalPrice;
                let percent = item.discountPercent;
                let amount = item.discountAmount;

                if (price === null) return item;

                // 1. Есть цена и процент -> считаем оригинал и сумму скидки
                if (price !== null && percent !== null && original === null) {
                    if (percent > 0 && percent < 100) {
                        original = price / (1 - percent / 100);
                    } else {
                        original = price;
                    }
                }

                // 2. Есть цена и оригинал -> считаем процент и сумму скидки
                if (price !== null && original !== null && percent === null && original > price) {
                    percent = ((original - price) / original) * 100;
                } else if (price !== null && original !== null && percent === null && original <= price) {
                    percent = 0;
                }

                // 3. Есть цена и сумма скидки -> считаем оригинал и процент
                if (price !== null && amount !== null && original === null) {
                    original = price + amount;
                }
                if (price !== null && amount !== null && percent === null && original !== null && original > 0) {
                    percent = (amount / original) * 100;
                }

                // 4. Всегда считаем сумму скидки, если есть цена и оригинал
                if (price !== null && original !== null && amount === null && original > price) {
                    amount = original - price;
                } else if (price !== null && original !== null && amount === null && original <= price) {
                    amount = 0;
                }

                item.originalPrice = original !== null ? parseFloat(original.toFixed(2)) : null;
                item.discountPercent = percent !== null ? parseFloat(percent.toFixed(1)) : null;
                item.discountAmount = amount !== null ? parseFloat(amount.toFixed(2)) : null;

                if (item.discountPercent !== null && item.discountPercent <= 0) {
                    item.discountPercent = 0;
                    item.discountAmount = 0;
                    if (item.originalPrice === null && item.currentPrice !== null) {
                        item.originalPrice = item.currentPrice;
                    }
                }
                if (item.originalPrice === null && item.currentPrice !== null) {
                    item.originalPrice = item.currentPrice;
                    item.discountPercent = 0;
                    item.discountAmount = 0;
                }


                return item;
            }

            function sm_getSteamGameName() {
                const appNameElement = document.querySelector('#appHubAppName');
                return appNameElement ? appNameElement.textContent.trim() : '';
            }

            function sm_logError(storeName, message, error = null) {
                console.error(`[SalesMaster][${storeName}] ${message}`, error || '');
            }

            function sm_debounce(func, wait) {
                let timeout;
                return function executedFunction(...args) {
                    const later = () => {
                        clearTimeout(timeout);
                        func(...args);
                    };
                    clearTimeout(timeout);
                    timeout = setTimeout(later, wait);
                };
            }

            // --- Функция для получения курсов валют ---
            async function sm_fetchExchangeRates(baseCurrency) {
                const lowerBase = baseCurrency.toLowerCase();
                if (sm_exchangeRates[lowerBase] && Object.keys(sm_exchangeRates[lowerBase]).length > 0) {
                    return sm_exchangeRates[lowerBase];
                }

                const apiUrl = `https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/${lowerBase}.json`;
                return new Promise((resolve, reject) => {
                    GM_xmlhttpRequest({
                        method: "GET",
                        url: apiUrl,
                        responseType: 'json',
                        timeout: SM_REQUEST_TIMEOUT_MS / 2,
                        onload: (response) => {
                            if (response.status >= 200 && response.status < 400 && response.response) {
                                const rates = response.response[lowerBase];
                                if (rates && typeof rates === 'object') {
                                    sm_exchangeRates[lowerBase] = rates;
                                    resolve(rates);
                                } else {
                                    reject(new Error(`Не найдены курсы для ${baseCurrency} в ответе API`));
                                }
                            } else {
                                reject(new Error(`Ошибка API валют: статус ${response.status}`));
                            }
                        },
                        onerror: (error) => reject(new Error('Сетевая ошибка API валют')),
                        ontimeout: () => reject(new Error('Таймаут запроса API валют'))
                    });
                });
            }

            // --- Создание UI SalesMaster ---

            function sm_updateCurrencyToggleButton() {
                const toggleBtn = document.getElementById('smCurrencyToggleBtn');
                if (!toggleBtn) return;
                if (sm_currentCurrencyMode === 'USD') {
                    toggleBtn.textContent = 'RUB';
                    toggleBtn.title = 'Переключиться на рубли';
                } else {
                    toggleBtn.textContent = 'USD';
                    toggleBtn.title = 'Переключиться на доллары США';
                }
            }

            function sm_showUsdSwitchConfirmation() {
                const hideWarning = GM_getValue('salesMaster_hideUsdWarning', false);
                if (hideWarning) {
                    sm_switchToUsdMode();
                    return;
                }

                const dialog = document.createElement('div');
                dialog.id = 'smUsdConfirmDialog';
                Object.assign(dialog.style, {
                    position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)',
                    backgroundColor: '#1f2c3a', color: '#c6d4df', padding: '25px', borderRadius: '5px',
                    boxShadow: '0 0 20px rgba(0,0,0,0.7)', zIndex: '10005', textAlign: 'left',
                    border: '1px solid #FFB300', maxWidth: '450px'
                });
                dialog.innerHTML = `
                    <h4 style="margin-top:0; color:#FFB300;">Переключение в режим USD</h4>
                    <p style="margin-bottom:20px; line-height:1.6;">Цены из всех магазинов будут конвертированы и отображены в долларах США (USD). Это может быть полезно для сравнения цен в международном контексте.<br><br>Продолжить?</p>
                    <div style="margin-bottom: 20px;"><label><input type="checkbox" id="smDontShowAgainUsd" style="margin-right:8px;">Больше не показывать</label></div>
                    <div style="text-align:right;">
                        <button id="smConfirmYes" class="salesMasterBtn" style="background-color:#FFB300; color:#1b2838; margin-right:10px;">Да</button>
                        <button id="smConfirmNo" class="salesMasterBtn">Отмена</button>
                    </div>
                `;
                document.body.appendChild(dialog);

                document.getElementById('smConfirmYes').onclick = () => {
                    if (document.getElementById('smDontShowAgainUsd').checked) {
                        GM_setValue('salesMaster_hideUsdWarning', true);
                    }
                    sm_switchToUsdMode();
                    dialog.remove();
                };
                document.getElementById('smConfirmNo').onclick = () => dialog.remove();
            }

            function sm_switchToUsdMode() {
                sm_currentCurrencyMode = 'USD';
                GM_setValue(SM_CURRENCY_MODE_STORAGE_KEY, 'USD');
                sm_updateCurrencyToggleButton();
                sm_applySort(sm_currentSort.field, sm_currentSort.direction);
                sm_renderResults();
                sm_updateFilterPlaceholders();
                sm_applyFilters();
                sm_updateSortButtonsState();
            }

            function sm_switchToRubMode() {
                sm_currentCurrencyMode = 'RUB';
                GM_setValue(SM_CURRENCY_MODE_STORAGE_KEY, 'RUB');
                sm_updateCurrencyToggleButton();
                sm_applySort(sm_currentSort.field, sm_currentSort.direction);
                sm_renderResults();
                sm_updateFilterPlaceholders();
                sm_applyFilters();
                sm_updateSortButtonsState();
            }

            function sm_handleCurrencyToggle() {
                if (sm_currentCurrencyMode === 'RUB') {
                    sm_showUsdSwitchConfirmation();
                } else {
                    sm_switchToRubMode();
                }
            }

            function sm_createModal() {
                const existingModal = document.querySelector('#salesMasterModal');
                if (existingModal) existingModal.remove();

                sm_modal = document.createElement('div');
                sm_modal.id = 'salesMasterModal';

                const container = document.createElement('div');
                container.id = 'salesMasterContainer';

                const header = document.createElement('div');
                header.id = 'salesMasterHeader';

                // --- Левая часть шапки ---
                sm_searchBtn = document.createElement('button');
                sm_searchBtn.textContent = 'Обновить %';
                sm_searchBtn.id = 'salesMasterSearchGoBtn';
                sm_searchBtn.className = 'salesMasterBtn';
                sm_searchBtn.title = 'Запросить цены с магазинов';
                sm_searchBtn.onclick = sm_triggerSearch;
                header.appendChild(sm_searchBtn);

                const headerStatusDiv = document.createElement('div');
                headerStatusDiv.id = 'salesMasterHeaderStatus';
                header.appendChild(headerStatusDiv);

                // --- Разделитель ---
                const spacer = document.createElement('div');
                spacer.style.flexGrow = '1';
                header.appendChild(spacer);

                // --- Правая часть шапки ---
                const rightControls = document.createElement('div');
                rightControls.style.display = 'flex';
                rightControls.style.alignItems = 'center';
                rightControls.style.gap = '10px';

                const insertTitleBtn = document.createElement('button');
                insertTitleBtn.id = 'smInsertTitleBtn';
                insertTitleBtn.className = 'salesMasterBtn smInsertTitleBtn';
                insertTitleBtn.textContent = 'Подставить название >';
                insertTitleBtn.title = 'Подставить название текущей игры в фильтр';
                insertTitleBtn.onclick = () => {
                    const gameName = sm_getSteamGameName();
                    const filterInput = document.getElementById('smTitleFilterInput');
                    if (gameName && filterInput) {
                        filterInput.value = gameName;
                        sm_applyFilters();
                        filterInput.focus();
                    }
                };
                rightControls.appendChild(insertTitleBtn);

                const titleFilterInput = document.createElement('input');
                titleFilterInput.type = 'text';
                titleFilterInput.id = 'smTitleFilterInput';
                titleFilterInput.placeholder = 'Фильтр по названию (слова через ;)';
                titleFilterInput.addEventListener('input', sm_debounce(sm_applyFilters, SM_FILTER_DEBOUNCE_MS));
                rightControls.appendChild(titleFilterInput);

                const currencyToggleBtn = document.createElement('button');
                currencyToggleBtn.id = 'smCurrencyToggleBtn';
                currencyToggleBtn.className = 'salesMasterBtn';
                currencyToggleBtn.onclick = sm_handleCurrencyToggle;
                rightControls.appendChild(currencyToggleBtn);

                sm_sortButtonsContainer = document.createElement('div');
                sm_sortButtonsContainer.id = 'salesMasterSortButtons';
                rightControls.appendChild(sm_sortButtonsContainer);

                const resetSortBtn = document.createElement('button');
                resetSortBtn.id = 'salesMasterResetSortBtn';
                resetSortBtn.className = 'salesMasterBtn';
                resetSortBtn.title = 'Сбросить сортировку (По Цене)';
                resetSortBtn.innerHTML = `<svg viewBox="0 0 24 24"><path fill="currentColor" d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6s-2.69 6-6 6s-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8s-3.58-8-8-8Z"/></svg>`;
                resetSortBtn.onclick = () => sm_resetSort(true);
                sm_sortButtonsContainer.appendChild(resetSortBtn);

                sm_createSortButton('price', 'Цена');
                sm_createSortButton('discountPercent', '% Скидки');
                sm_createSortButton('discountAmount', 'Скидка');
                sm_createSortButton('name', 'Название');

                header.appendChild(rightControls);
                container.appendChild(header);

                sm_resultsContainer = document.createElement('div');
                sm_resultsContainer.id = 'salesMasterResultsContainer';
                sm_resultsContainer.style.paddingTop = '0';
                sm_resultsDiv = document.createElement('div');
                sm_resultsDiv.id = 'salesMasterResults';
                sm_resultsContainer.appendChild(sm_resultsDiv);
                container.appendChild(sm_resultsContainer);
                sm_filtersPanel = document.createElement('div');
                sm_filtersPanel.id = 'salesMasterFiltersPanel';
                sm_filtersPanel.innerHTML = `
                    <div class="smFilterGroup"><h4>Цена, ${sm_getCurrencySymbol()} ${sm_createResetButtonHTML('price')}</h4><div class="smFilterRangeInputs"><input type="number" id="smFilterPriceMin" placeholder="от" min="0"><input type="number" id="smFilterPriceMax" placeholder="до" min="0"></div></div>
                    <div class="smFilterGroup"><h4>Скидка, % ${sm_createResetButtonHTML('discountPercent')}</h4><div class="smFilterRangeInputs"><input type="number" id="smFilterDiscountPercentMin" placeholder="от" min="0" max="100"><input type="number" id="smFilterDiscountPercentMax" placeholder="до" min="0" max="100"></div></div>
                    <div class="smFilterGroup"><h4>Скидка, ${sm_getCurrencySymbol()} ${sm_createResetButtonHTML('discountAmount')}</h4><div class="smFilterRangeInputs"><input type="number" id="smFilterDiscountAmountMin" placeholder="от" min="0"><input type="number" id="smFilterDiscountAmountMax" placeholder="до" min="0"></div></div>
                    <div class="smFilterGroup"><h4>Опции ${sm_createResetButtonHTML('options')}</h4><div class="smFilterCheckbox"><label><input type="checkbox" id="smFilterHasDiscount"> Только со скидкой</label></div></div>
                    <div class="smFilterGroup">
                        <h4>Магазины ${sm_createResetButtonHTML('stores')}</h4>
                        <div class="smStoreSelectAllControls">
                            <span class="smStoreSelectAllLink" id="smSelectAllStores">Отметить всё</span>
                            <span class="smStoreSelectSeparator">|</span>
                            <span class="smStoreSelectAllLink" id="smDeselectAllStores">Снять всё</span>
                        </div>
                        <div id="smFilterStoreCheckboxes"></div>
                    </div>
                    <button id="smResetAllFiltersBtn" class="salesMasterBtn">Сбросить все фильтры</button>
                `;
                sm_modal.appendChild(sm_filtersPanel);
                sm_exclusionTagsDiv = document.createElement('div');
                sm_exclusionTagsDiv.id = 'salesMasterExclusionTags';
                const exclusionInputGroup = document.createElement('div');
                exclusionInputGroup.className = 'smExclusionInputGroup';
                sm_excludeInput = document.createElement('input');
                sm_excludeInput.type = 'text';
                sm_excludeInput.id = 'salesMasterExcludeInput';
                sm_excludeInput.placeholder = 'Исключить слово';
                sm_excludeInput.onkeydown = (e) => { if (e.key === 'Enter') sm_addExclusionKeyword(); };
                sm_addExcludeBtn = document.createElement('button');
                sm_addExcludeBtn.id = 'salesMasterAddExcludeBtn';
                sm_addExcludeBtn.innerHTML = `<svg viewBox="0 0 20 20"><path fill="currentColor" d="M10 2.5a.75.75 0 0 1 .75.75v6h6a.75.75 0 0 1 0 1.5h-6v6a.75.75 0 0 1-1.5 0v-6h-6a.75.75 0 0 1 0-1.5h6v-6a.75.75 0 0 1 .75-.75Z" /></svg>`;
                sm_addExcludeBtn.onclick = sm_addExclusionKeyword;
                exclusionInputGroup.appendChild(sm_excludeInput);
                exclusionInputGroup.appendChild(sm_addExcludeBtn);
                sm_exclusionTagsDiv.appendChild(exclusionInputGroup);
                const exclusionActionsDiv = document.createElement('div');
                exclusionActionsDiv.className = 'smExclusionActions';
                const exportBtn = document.createElement('button');
                exportBtn.id = 'smExportExclusionsBtn';
                exportBtn.className = 'salesMasterBtn smExclusionActionBtn';
                exportBtn.title = 'Экспорт списка исключений';
                exportBtn.innerHTML = '←'
                exportBtn.onclick = sm_exportExclusions;
                exclusionActionsDiv.appendChild(exportBtn);
                const importBtn = document.createElement('button');
                importBtn.id = 'smImportExclusionsBtn';
                importBtn.className = 'salesMasterBtn smExclusionActionBtn';
                importBtn.title = 'Импорт списка исключений';
                importBtn.innerHTML = '→';
                importBtn.onclick = sm_showImportModal;
                exclusionActionsDiv.appendChild(importBtn);
                sm_exclusionTagsDiv.appendChild(exclusionActionsDiv);
                sm_exclusionTagsListDiv = document.createElement('div');
                sm_exclusionTagsListDiv.id = 'salesMasterExclusionTagsList';
                sm_exclusionTagsDiv.appendChild(sm_exclusionTagsListDiv);
                sm_modal.appendChild(sm_exclusionTagsDiv);
                sm_closeBtn = document.createElement('button');
                sm_closeBtn.id = 'salesMasterCloseBtn';
                sm_closeBtn.innerHTML = '&times;';
                sm_closeBtn.onclick = sm_hideModal;
                sm_modal.appendChild(sm_closeBtn);
                sm_modal.appendChild(container);
                document.body.appendChild(sm_modal);

                document.getElementById('smSelectAllStores')?.addEventListener('click', sm_selectAllStores);
                document.getElementById('smDeselectAllStores')?.addEventListener('click', sm_deselectAllStores);

                sm_setupFilterEventListeners();
                sm_applyLoadedFiltersToUI();
                sm_renderExclusionTags();
                sm_renderStoreCheckboxes();
                sm_updateSortButtonsState();
                sm_positionSidePanels();

                function handleEsc(event) {
                    if (event.key === 'Escape') {
                        const importModal = document.getElementById('smImportModal');
                        if (importModal) { importModal.remove(); }
                        else { sm_hideModal(); }
                    }
                }
                document.addEventListener('keydown', handleEsc);
                sm_modal._escHandler = handleEsc;
            }

            function sm_exportExclusions() {
                const keywordsString = sm_exclusionKeywords.join(',');
                if (!keywordsString) {
                    alert('Список исключений пуст.');
                    return;
                }
                try {
                    navigator.clipboard.writeText(keywordsString).then(() => {
                        const exportBtn = document.getElementById('smExportExclusionsBtn');
                        if (exportBtn) {
                            const originalContent = exportBtn.innerHTML;
                            exportBtn.innerHTML = 'Скопировано!';
                            exportBtn.disabled = true;
                            setTimeout(() => {
                                exportBtn.innerHTML = originalContent;
                                exportBtn.disabled = false;
                            }, 1500);
                        }
                    }, (err) => {
                        console.error('[SalesMaster] Не удалось скопировать в буфер обмена:', err);
                        prompt('Не удалось скопировать автоматически. Скопируйте вручную:', keywordsString);
                    });
                } catch (err) {
                    console.error('[SalesMaster] Ошибка доступа к буферу обмена:', err);
                    prompt('Не удалось скопировать автоматически. Скопируйте вручную:', keywordsString);
                }
            }

            function sm_showImportModal() {
                const existingModal = document.getElementById('smImportModal');
                if (existingModal) existingModal.remove();

                const importModal = document.createElement('div');
                importModal.id = 'smImportModal';
                importModal.innerHTML = `
                    <div class="smImportModalContent">
                        <h4>Импорт списка исключений</h4>
                        <p>Вставьте список слов, разделенных запятыми:</p>
                        <textarea id="smImportTextarea" rows="6"></textarea>
                        <div class="smImportModalActions">
                            <button id="smImportAcceptBtn" class="salesMasterBtn">Принять</button>
                            <button id="smImportCancelBtn" class="salesMasterBtn">Отмена</button>
                        </div>
                    </div>
                `;
                document.body.appendChild(importModal);

                document.getElementById('smImportAcceptBtn').onclick = sm_handleImport;
                document.getElementById('smImportCancelBtn').onclick = () => importModal.remove();
                document.getElementById('smImportTextarea').focus();
            }

            function sm_handleImport() {
                const textarea = document.getElementById('smImportTextarea');
                const importModal = document.getElementById('smImportModal');
                if (!textarea || !importModal) return;

                const text = textarea.value.trim();
                if (text) {
                    const importedKeywords = text.split(',')
                                               .map(k => k.trim().toLowerCase())
                                               .filter(k => k.length > 0);
                    sm_exclusionKeywords = [...new Set(importedKeywords)];
                    GM_setValue(SM_EXCLUSION_STORAGE_KEY, sm_exclusionKeywords);
                    sm_renderExclusionTags();
                    sm_applyFilters();
                    console.log('[SalesMaster] Список исключений импортирован.');
                } else {
                    alert("Поле ввода пустое. Импорт не выполнен.");
                }
                importModal.remove();
            }

            function sm_highlightErrorStores() {
                if (!sm_filterStoreCheckboxesContainer) return;

                sm_storeModules.filter(store => store && store.id).forEach(store => {
                    const checkboxContainer = sm_filterStoreCheckboxesContainer.querySelector(`#smStoreFilter-${store.id}`)?.closest('.smFilterCheckbox');
                    if (checkboxContainer) {
                        const storeStatus = sm_stores[store.id]?.status;
                        if (storeStatus === 'error') {
                            checkboxContainer.classList.add('sm-store-error');
                        } else {
                            checkboxContainer.classList.remove('sm-store-error');
                        }
                    }
                });
            }

            // --- Функции для управления выбором магазинов ---
            function sm_selectAllStores() {
                const storeCheckboxes = document.querySelectorAll('#smFilterStoreCheckboxes input[type="checkbox"]');
                if (!storeCheckboxes || storeCheckboxes.length === 0) return;

                let changed = false;
                storeCheckboxes.forEach(cb => {
                    if (!cb.checked) {
                        cb.checked = true;
                        if (cb.dataset.storeId) {
                            sm_currentFilters.stores[cb.dataset.storeId] = true;
                        }
                        changed = true;
                    }
                });

                if (changed) {
                    GM_setValue(SM_FILTER_STORAGE_KEY, sm_currentFilters);
                    sm_applyFilters();
                }
            }

            function sm_deselectAllStores() {
                const storeCheckboxes = document.querySelectorAll('#smFilterStoreCheckboxes input[type="checkbox"]');
                 if (!storeCheckboxes || storeCheckboxes.length === 0) return;

                let changed = false;
                storeCheckboxes.forEach(cb => {
                    if (cb.checked) {
                        cb.checked = false;
                         if (cb.dataset.storeId) {
                            sm_currentFilters.stores[cb.dataset.storeId] = false;
                        }
                        changed = true;
                    }
                });

                if (changed) {
                    GM_setValue(SM_FILTER_STORAGE_KEY, sm_currentFilters);
                    sm_applyFilters();
                }
            }

            function sm_positionSidePanels() {
                requestAnimationFrame(() => {
                    const header = document.getElementById('salesMasterHeader');
                    const resultsContainer = document.getElementById('salesMasterResultsContainer');
                    if (!header || !resultsContainer || !sm_filtersPanel || !sm_exclusionTagsDiv) return;

                    const headerRect = header.getBoundingClientRect();
                    const headerHeight = header.offsetHeight;
                    const topOffset = headerRect.top + headerHeight + 15;
                    const bottomOffset = 20;
                    const availableHeight = `calc(100vh - ${topOffset}px - ${bottomOffset}px)`;

                    sm_filtersPanel.style.position = 'fixed';
                    sm_filtersPanel.style.left = `15px`;
                    sm_filtersPanel.style.top = `${topOffset}px`;
                    sm_filtersPanel.style.maxHeight = availableHeight;
                    sm_filtersPanel.style.visibility = 'visible';

                    sm_exclusionTagsDiv.style.position = 'fixed';
                    sm_exclusionTagsDiv.style.right = `15px`;
                    sm_exclusionTagsDiv.style.top = `${topOffset}px`;
                    sm_exclusionTagsDiv.style.maxHeight = availableHeight;
                    sm_exclusionTagsDiv.style.visibility = 'visible';

                    const filterPanelWidth = sm_filtersPanel.offsetWidth;
                    const exclusionPanelWidth = sm_exclusionTagsDiv.offsetWidth;
                    const contentSidePadding = 25;

                    header.style.paddingLeft = `${filterPanelWidth + contentSidePadding}px`;
                    header.style.paddingRight = `${exclusionPanelWidth + contentSidePadding}px`;

                    resultsContainer.style.paddingLeft = `${filterPanelWidth + contentSidePadding}px`;
                    resultsContainer.style.paddingRight = `${exclusionPanelWidth + contentSidePadding}px`;
                    resultsContainer.style.paddingTop = `0`;
                    resultsContainer.style.paddingBottom = `20px`;
                    resultsContainer.style.height = `calc(100% - ${headerHeight}px)`;
                    resultsContainer.style.overflowY = 'auto';
                    resultsContainer.style.scrollbarColor = '#4b6f9c #17202d';
                    resultsContainer.style.scrollbarWidth = 'thin';


                });
            }

            function sm_createSortButton(field, text) {
                const btn = document.createElement('button');
                btn.className = 'salesMasterBtn sortBtn';
                btn.dataset.sort = field;
                btn.textContent = text;
                btn.onclick = () => sm_handleSort(field);
                sm_sortButtonsContainer.appendChild(btn);
            }

            function sm_createResetButtonHTML(filterKey) {
                return `<button class="smFilterResetBtn" title="Сбросить фильтр" data-filter-key="${filterKey}"><svg viewBox="0 0 24 24"><path fill="currentColor" d="M13 3a9 9 0 0 0-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42A8.954 8.954 0 0 0 13 21a9 9 0 0 0 0-18zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"></path></svg></button>`;
            }

            function sm_renderStoreCheckboxes() {
                sm_filterStoreCheckboxesContainer = document.getElementById('smFilterStoreCheckboxes');
                if (!sm_filterStoreCheckboxesContainer) return;
                sm_filterStoreCheckboxesContainer.innerHTML = '';

                sm_storeModules.filter(store => store && typeof store.id === 'string').forEach(store => {
                    const div = document.createElement('div');
                    div.className = 'smFilterCheckbox';
                    const label = document.createElement('label');
                    const checkbox = document.createElement('input');
                    checkbox.type = 'checkbox';
                    checkbox.id = `smStoreFilter-${store.id}`;
                    checkbox.dataset.storeId = store.id;
                    checkbox.checked = sm_currentFilters.stores[store.id] !== false;
                    checkbox.addEventListener('change', sm_handleStoreFilterChange);

                    label.appendChild(checkbox);
                    label.appendChild(document.createTextNode(` ${store.name}`));
                    div.appendChild(label);
                    sm_filterStoreCheckboxesContainer.appendChild(div);
                });
            }

            function sm_handleStoreFilterChange(event) {
                const storeId = event.target.dataset.storeId;
                const isChecked = event.target.checked;
                sm_currentFilters.stores[storeId] = isChecked;
                GM_setValue(SM_FILTER_STORAGE_KEY, sm_currentFilters);
                sm_applyFilters();
            }


            async function sm_showModal() {
                if (!sm_modal) sm_createModal();

                try {
                    sm_updateStatus('Загрузка курсов валют...', true);
                    await sm_fetchExchangeRates('rub');
                    sm_updateStatus('Нажмите "Обновить %" для поиска цен...');
                } catch (e) {
                    sm_updateStatus('Ошибка загрузки курсов валют!', false);
                    console.error("[SalesMaster] Не удалось загрузить курсы валют при открытии модального окна:", e);
                }

                if (sm_currentResults.length > 0 || sm_resultsDiv.innerHTML !== '') {
                    sm_resultsDiv.innerHTML = '';
                    sm_currentResults = [];
                }
                const titleFilterInput = document.getElementById('smTitleFilterInput');
                if (titleFilterInput) titleFilterInput.value = '';

                document.body.style.overflow = 'hidden';
                sm_modal.style.display = 'block';
                sm_modal.scrollTop = 0;

                sm_renderExclusionTags();
                sm_applyLoadedFiltersToUI();
                sm_updateSortButtonsState();
                sm_renderStoreCheckboxes();
                sm_positionSidePanels();
                sm_updateCurrencyToggleButton();

                sm_applyFilters();
                if (scriptsConfig.salesMasterAutoSearch) {
                   sm_triggerSearch();
                }
            }

            function sm_hideModal() {
                if (sm_modal) {
                    sm_modal.style.display = 'none';
                    if (sm_modal._escHandler) {
                        document.removeEventListener('keydown', sm_modal._escHandler);
                        delete sm_modal._escHandler;
                    }
                }
                document.body.style.overflow = '';
            }

            // --- Обновление статуса ---
            function sm_updateStatus(message, isLoading = false) {
                const headerStatusDiv = document.getElementById('salesMasterHeaderStatus');
                if (headerStatusDiv) {
                    headerStatusDiv.innerHTML = message + (isLoading ? ' <span class="spinner"></span>' : '');
                }
                if (sm_searchBtn) {
                    if (isLoading) {
                        sm_searchBtn.disabled = true;
                    } else {
                        sm_searchBtn.disabled = false;
                        sm_searchBtn.textContent = 'Обновить %';
                    }
                }
            }

            // --- Запуск поиска ---
            async function sm_triggerSearch() {
                try {
                    sm_updateStatus('Загрузка курсов валют...', true);
                    await Promise.all([
                        sm_fetchExchangeRates('usd'),
                        sm_fetchExchangeRates('kzt')
                    ]);
                } catch(e) {
                    sm_logError("Core", "Не удалось загрузить все необходимые курсы валют", e);
                }

                const gameName = sm_getSteamGameName();
                if (!gameName) {
                    sm_updateStatus('Не удалось определить название игры на странице Steam.');
                    return;
                }

                const titleFilterInput = document.getElementById('smTitleFilterInput');
                if (titleFilterInput) titleFilterInput.value = '';

                sm_currentResults = [];
                sm_resultsDiv.innerHTML = '';
                sm_stores = {};
                sm_highlightErrorStores();
                sm_updateStatus(`Поиск "${gameName}"...`, true);
                sm_activeRequests = 0;


                const promises = [];
                let totalStoresToCheck = 0;

                sm_storeModules.filter(m => m && typeof m.fetch === 'function').forEach(storeModule => {
                    if (sm_currentFilters.stores[storeModule.id] !== false) {
                        totalStoresToCheck++;
                        sm_activeRequests++;
                        sm_stores[storeModule.id] = {
                            name: storeModule.name,
                            status: 'pending',
                            error: null
                        };
                        promises.push(
                            storeModule.fetch(gameName)
                            .then(results => {
                                sm_stores[storeModule.id].status = 'success';
                                return results;
                            })
                            .catch(error => {
                                sm_stores[storeModule.id].status = 'error';
                                sm_stores[storeModule.id].error = error.message || 'Неизвестная ошибка';
                                sm_logError(storeModule.name, `Ошибка при запросе: ${sm_stores[storeModule.id].error}`, error);
                                return [];
                            })
                            .finally(() => {
                                sm_activeRequests--;
                                sm_updateLoadingProgress(totalStoresToCheck);
                            })
                        );
                    } else {
                        sm_stores[storeModule.id] = {
                            name: storeModule.name,
                            status: 'skipped',
                            error: null
                        };
                    }
                });

                if (promises.length === 0) {
                    sm_updateStatus('Нет активных магазинов для поиска.');
                    return;
                }

                const resultsArrays = await Promise.all(promises);

                sm_currentResults = resultsArrays.flat();

                if (scriptsConfig.salesMasterAutoInsertTitle) {
                    const gameName = sm_getSteamGameName();
                    const filterInput = document.getElementById('smTitleFilterInput');
                    if (gameName && filterInput) {
                        filterInput.value = gameName;
                    }
                }

                sm_updateLoadingProgress(totalStoresToCheck);
                if (sm_currentResults.length > 0) {
                    sm_applySort(sm_currentSort.field, sm_currentSort.direction);
                    sm_renderResults();
                    sm_updateFilterPlaceholders();
                } else {
                    sm_applyFilters();
                }
            }

            function sm_updateLoadingProgress(totalStores) {
                const completedStores = Object.values(sm_stores).filter(s => s.status !== 'pending').length;
                const skippedStores = Object.values(sm_stores).filter(s => s.status === 'skipped').length;
                const successStores = Object.values(sm_stores).filter(s => s.status === 'success').length;
                const errorStores = Object.values(sm_stores).filter(s => s.status === 'error');

                const searchedCompletedCount = completedStores - skippedStores;

                if (sm_activeRequests > 0) {
                    sm_updateStatus(`Загрузка... (${searchedCompletedCount}/${totalStores})`, true);
                } else {
                    let statusMessage = '';
                    if (sm_currentResults.length > 0) {
                        statusMessage = `Найдено ${sm_currentResults.length} предложений. `;
                    } else {
                         const gameName = sm_getSteamGameName();
                        if (gameName) {
                           statusMessage = `Предложений не найдено. `;
                        } else {
                           statusMessage = `Введите запрос или обновите для поиска.`;
                        }
                    }
                    if (errorStores.length > 0) {
                        statusMessage += `Ошибки в магазинах: ${errorStores.map(s => s.name).join(', ')}.`;
                    }
                    if (sm_currentResults.length === 0 && errorStores.length === 0 && sm_activeRequests === 0 && sm_getSteamGameName()) {
                         statusMessage = `По запросу "${sm_getSteamGameName()}" ничего не найдено в выбранных магазинах.`;
                    }

                    sm_updateStatus(statusMessage.trim(), false);
                    sm_highlightErrorStores();

                    const anyFilterActive = (parseFloat(sm_currentFilters.priceMin) || 0) > 0 || (parseFloat(sm_currentFilters.priceMax) || Infinity) < Infinity ||
                                            (parseFloat(sm_currentFilters.discountPercentMin) || 0) > 0 || (parseFloat(sm_currentFilters.discountPercentMax) || 100) < 100 ||
                                            (parseFloat(sm_currentFilters.discountAmountMin) || 0) > 0 || (parseFloat(sm_currentFilters.discountAmountMax) || Infinity) < Infinity ||
                                            sm_currentFilters.hasDiscount || sm_exclusionKeywords.length > 0 ||
                                            Object.values(sm_currentFilters.stores).some(v => v === false) ||
                                            (document.getElementById('smTitleFilterInput')?.value.trim() || '').length > 0;
                    const visibleItems = sm_resultsDiv.querySelectorAll('.salesMasterItem:not(.hidden-by-filter)').length;

                    if (visibleItems === 0 && sm_currentResults.length > 0 && anyFilterActive) {
                        const statusDivInHeader = document.getElementById('salesMasterHeaderStatus');
                        if (statusDivInHeader) {
                            let currentStatus = statusDivInHeader.textContent.replace(' Нет товаров, соответствующих фильтрам.', '');
                            statusDivInHeader.textContent = currentStatus.trim() + ' Нет товаров, соответствующих фильтрам.';
                        }
                    }
                }
            }

            // --- Сортировка ---
            function sm_handleSort(field) {
                const defaultDirections = {
                    price: 'asc',
                    discountPercent: 'desc',
                    discountAmount: 'desc',
                    name: 'asc'
                };
                let newDirection;

                if (sm_currentSort.field === field) {
                    newDirection = sm_currentSort.direction === 'asc' ? 'desc' : 'asc';
                } else {
                    newDirection = defaultDirections[field] || 'asc';
                }

                sm_currentSort.field = field;
                sm_currentSort.direction = newDirection;
                GM_setValue(SM_SORT_STORAGE_KEY, sm_currentSort);

                sm_applySort(field, newDirection);
                sm_renderResults();
                sm_updateSortButtonsState();
            }

            function sm_applySort(field, direction) {
                const dirMultiplier = direction === 'asc' ? 1 : -1;

                sm_currentResults.sort((a, b) => {
                    let valA, valB;

                    switch (field) {
                        case 'price':
                            valA = a.currentPrice ?? (direction === 'asc' ? Infinity : -Infinity);
                            valB = b.currentPrice ?? (direction === 'asc' ? Infinity : -Infinity);
                            break;
                        case 'discountPercent':
                            valA = a.discountPercent ?? -1;
                            valB = b.discountPercent ?? -1;
                            break;
                        case 'discountAmount':
                            const amountA = a.discountAmount;
                            const amountB = b.discountAmount;
                            if (amountA === null && amountB === null) valA = valB = 0;
                            else if (amountA === null) valA = direction === 'desc' ? -Infinity : Infinity;
                            else if (amountB === null) valB = direction === 'desc' ? -Infinity : Infinity;
                            else {
                                valA = amountA;
                                valB = amountB;
                            }
                            break;
                        case 'name':
                            valA = a.productName?.toLowerCase() || '';
                            valB = b.productName?.toLowerCase() || '';
                            return valA.localeCompare(valB) * dirMultiplier;
                        default:
                            return 0;
                    }

                    let comparisonResult = 0;
                    if (valA < valB) comparisonResult = -1;
                    else if (valA > valB) comparisonResult = 1;

                    comparisonResult *= dirMultiplier;

                    if (comparisonResult === 0 && field !== 'price') {
                        const priceA = a.currentPrice ?? Infinity;
                        const priceB = b.currentPrice ?? Infinity;
                        if (priceA < priceB) return -1;
                        if (priceA > priceB) return 1;
                    }
                    if (comparisonResult === 0 && field !== 'name') {
                        return (a.productName?.toLowerCase() || '').localeCompare(b.productName?.toLowerCase() || '');
                    }


                    return comparisonResult;
                });
            }

            function sm_updateSortButtonsState() {
                if (!sm_sortButtonsContainer) return;
                const buttons = sm_sortButtonsContainer.querySelectorAll('.sortBtn');

                buttons.forEach(btn => {
                    const btnField = btn.dataset.sort;
                    let baseText = '';

                    switch (btnField) {
                        case 'price':
                            baseText = 'Цена';
                            break;
                        case 'discountPercent':
                            baseText = '% Скидки';
                            break;
                        case 'discountAmount':
                            baseText = `Скидка ${sm_getCurrencySymbol()}`;
                            break;
                        case 'name':
                            baseText = 'Название';
                            break;
                    }

                    if (btnField === sm_currentSort.field) {
                        const arrow = sm_currentSort.direction === 'asc' ? ' ▲' : ' ▼';
                        btn.classList.add('active');
                        btn.textContent = baseText + arrow;
                    } else {
                        btn.classList.remove('active');
                        btn.textContent = baseText;
                    }
                });

                const resetBtn = sm_sortButtonsContainer.querySelector('#salesMasterResetSortBtn');
                if (resetBtn) {
                    if (sm_currentSort.field === 'price' && sm_currentSort.direction === 'asc') {
                        resetBtn.classList.add('active');
                    } else {
                        resetBtn.classList.remove('active');
                    }
                }
            }

            function sm_resetSort(render = true) {
                sm_currentSort = {
                    field: 'price',
                    direction: 'asc'
                };
                GM_setValue(SM_SORT_STORAGE_KEY, sm_currentSort);
                sm_updateSortButtonsState();
                if (render) {
                    sm_applySort(sm_currentSort.field, sm_currentSort.direction);
                    sm_renderResults();
                }
            }

            // --- Управление фильтрами ---
            function sm_getFilterStorageKey(key) {
                return `${SM_FILTER_STORAGE_KEY}_${key}`;
            }

            function sm_saveFilter(key, value) {
                sm_currentFilters[key] = value;
                GM_setValue(SM_FILTER_STORAGE_KEY, sm_currentFilters);
            }

            function sm_applyLoadedFiltersToUI() {
                if (!sm_filtersPanel) return;
                document.getElementById('smFilterPriceMin').value = sm_currentFilters.priceMin || '';
                document.getElementById('smFilterPriceMax').value = sm_currentFilters.priceMax || '';
                document.getElementById('smFilterDiscountPercentMin').value = sm_currentFilters.discountPercentMin || '';
                document.getElementById('smFilterDiscountPercentMax').value = sm_currentFilters.discountPercentMax || '';
                document.getElementById('smFilterDiscountAmountMin').value = sm_currentFilters.discountAmountMin || '';
                document.getElementById('smFilterDiscountAmountMax').value = sm_currentFilters.discountAmountMax || '';
                document.getElementById('smFilterHasDiscount').checked = sm_currentFilters.hasDiscount || false;

                if (sm_filterStoreCheckboxesContainer) {
                    sm_filterStoreCheckboxesContainer.querySelectorAll('input[type="checkbox"]').forEach(cb => {
                        const storeId = cb.dataset.storeId;
                        cb.checked = sm_currentFilters.stores[storeId] !== false;
                    });
                }

                sm_updateFilterPlaceholders();
            }

            function sm_setupFilterEventListeners() {
                if (!sm_filtersPanel) return;
                const debouncedApply = sm_debounce(sm_applyFilters, SM_FILTER_DEBOUNCE_MS);

                ['smFilterPriceMin', 'smFilterPriceMax', 'smFilterDiscountPercentMin', 'smFilterDiscountPercentMax', 'smFilterDiscountAmountMin', 'smFilterDiscountAmountMax'].forEach(id => {
                    const input = document.getElementById(id);
                    const filterKey = id.replace('smFilter', '').charAt(0).toLowerCase() + id.replace('smFilter', '').slice(1);
                    if (input) {
                        input.addEventListener('input', (e) => {
                            sm_saveFilter(filterKey, e.target.value);
                            debouncedApply();
                        });
                    }
                });

                const hasDiscountCheckbox = document.getElementById('smFilterHasDiscount');
                if (hasDiscountCheckbox) {
                    hasDiscountCheckbox.addEventListener('change', (e) => {
                        sm_saveFilter('hasDiscount', e.target.checked);
                        sm_applyFilters();
                    });
                }

                const resetAllBtn = document.getElementById('smResetAllFiltersBtn');
                if (resetAllBtn) resetAllBtn.addEventListener('click', () => sm_resetAllFilters(true));

                sm_filtersPanel.querySelectorAll('.smFilterResetBtn').forEach(btn => {
                    btn.addEventListener('click', (event) => sm_handleFilterReset(event));
                });

            }

            function sm_handleFilterReset(event) {
                const filterKey = event.currentTarget.dataset.filterKey;
                sm_resetFilterByKey(filterKey, true);
            }

            function sm_resetFilterByKey(key, apply = true) {
                const defaults = {
                    priceMin: '',
                    priceMax: '',
                    discountPercentMin: '',
                    discountPercentMax: '',
                    discountAmountMin: '',
                    discountAmountMax: '',
                    hasDiscount: false,
                    stores: {}
                };
                switch (key) {
                    case 'price':
                        sm_saveFilter('priceMin', defaults.priceMin);
                        if (document.getElementById('smFilterPriceMin')) document.getElementById('smFilterPriceMin').value = defaults.priceMin;
                        sm_saveFilter('priceMax', defaults.priceMax);
                        if (document.getElementById('smFilterPriceMax')) document.getElementById('smFilterPriceMax').value = defaults.priceMax;
                        break;
                    case 'discountPercent':
                        sm_saveFilter('discountPercentMin', defaults.discountPercentMin);
                        if (document.getElementById('smFilterDiscountPercentMin')) document.getElementById('smFilterDiscountPercentMin').value = defaults.discountPercentMin;
                        sm_saveFilter('discountPercentMax', defaults.discountPercentMax);
                        if (document.getElementById('smFilterDiscountPercentMax')) document.getElementById('smFilterDiscountPercentMax').value = defaults.discountPercentMax;
                        break;
                    case 'discountAmount':
                        sm_saveFilter('discountAmountMin', defaults.discountAmountMin);
                        if (document.getElementById('smFilterDiscountAmountMin')) document.getElementById('smFilterDiscountAmountMin').value = defaults.discountAmountMin;
                        sm_saveFilter('discountAmountMax', defaults.discountAmountMax);
                        if (document.getElementById('smFilterDiscountAmountMax')) document.getElementById('smFilterDiscountAmountMax').value = defaults.discountAmountMax;
                        break;
                    case 'options':
                        sm_saveFilter('hasDiscount', defaults.hasDiscount);
                        if (document.getElementById('smFilterHasDiscount')) document.getElementById('smFilterHasDiscount').checked = defaults.hasDiscount;
                        break;
                    case 'stores':
                        const storeCheckboxes = document.querySelectorAll('#smFilterStoreCheckboxes input[type="checkbox"]');
                        let updatedStores = {};
                        storeCheckboxes.forEach(cb => {
                            cb.checked = true;
                            updatedStores[cb.dataset.storeId] = true;
                        });
                        sm_currentFilters.stores = updatedStores;
                        GM_setValue(SM_FILTER_STORAGE_KEY, sm_currentFilters);
                        break;
                }
                if (apply) sm_applyFilters();
            }

            function sm_resetAllFilters(apply = true) {
                const filterKeys = ['price', 'discountPercent', 'discountAmount', 'options', 'stores'];
                filterKeys.forEach(key => sm_resetFilterByKey(key, false));
                if (apply) sm_applyFilters();
            }

            function sm_getCurrencySymbol() {
                return sm_currentCurrencyMode === 'USD' ? '$' : '₽';
            }

            function sm_updateFilterPlaceholders() {
                if (!sm_filtersPanel) return;
                const currencySymbol = sm_getCurrencySymbol();
                const resultsToScan = sm_currentResults || [];

                const priceHeader = sm_filtersPanel.querySelector('.smFilterGroup h4:first-child');
                if (priceHeader) priceHeader.innerHTML = `Цена, ${currencySymbol} ${sm_createResetButtonHTML('price')}`;
                const amountHeader = sm_filtersPanel.querySelector('.smFilterGroup:nth-child(3) h4');
                if (amountHeader) amountHeader.innerHTML = `Скидка, ${currencySymbol} ${sm_createResetButtonHTML('discountAmount')}`;
                sm_filtersPanel.querySelectorAll('.smFilterResetBtn').forEach(btn => {
                    btn.removeEventListener('click', sm_handleFilterReset);
                    btn.addEventListener('click', sm_handleFilterReset);
                });

                if (resultsToScan.length === 0) {
                    ['smFilterPriceMin', 'smFilterPriceMax', 'smFilterDiscountPercentMin', 'smFilterDiscountPercentMax', 'smFilterDiscountAmountMin', 'smFilterDiscountAmountMax'].forEach(id => {
                        const el = document.getElementById(id);
                        if (el) el.placeholder = '-';
                    });
                    return;
                }

                let minPrice = Infinity, maxPrice = -Infinity;
                let minDiscountPercent = 101, maxDiscountPercent = -1;
                let minDiscountAmount = Infinity, maxDiscountAmount = -Infinity;
                const rubToUsdRate = sm_exchangeRates?.rub?.usd || null;
                const isUsdMode = sm_currentCurrencyMode === 'USD';

                resultsToScan.forEach(item => {
                    let currentPrice = item.currentPrice;
                    let discountAmount = item.discountAmount;

                    if(isUsdMode && rubToUsdRate) {
                        if (currentPrice !== null) currentPrice *= rubToUsdRate;
                        if (discountAmount !== null) discountAmount *= rubToUsdRate;
                    }

                    if (currentPrice !== null) {
                        if (currentPrice < minPrice) minPrice = currentPrice;
                        if (currentPrice > maxPrice) maxPrice = currentPrice;
                    }
                    if (item.discountPercent !== null) {
                        if (item.discountPercent < minDiscountPercent) minDiscountPercent = item.discountPercent;
                        if (item.discountPercent > maxDiscountPercent) maxDiscountPercent = item.discountPercent;
                    }
                    if (discountAmount !== null) {
                        if (discountAmount < minDiscountAmount) minDiscountAmount = discountAmount;
                        if (discountAmount > maxDiscountAmount) maxDiscountAmount = discountAmount;
                    }
                });

                const setPlaceholder = (id, prefix, value, suffix = '', formatFn = Math.round) => {
                    const el = document.getElementById(id);
                    if (el) {
                        el.placeholder = (value === Infinity || value === -Infinity || value === 101 || value === -1) ? '-' : `${prefix} ${formatFn(value)}${suffix}`;
                    }
                };

                setPlaceholder('smFilterPriceMin', 'от', minPrice, '', Math.floor);
                setPlaceholder('smFilterPriceMax', 'до', maxPrice, '', Math.ceil);
                setPlaceholder('smFilterDiscountPercentMin', 'от', minDiscountPercent, '%', v => Math.max(0, Math.floor(v)));
                setPlaceholder('smFilterDiscountPercentMax', 'до', maxDiscountPercent, '%', v => Math.min(100, Math.ceil(v)));
                setPlaceholder('smFilterDiscountAmountMin', 'от', minDiscountAmount, '', Math.floor);
                setPlaceholder('smFilterDiscountAmountMax', 'до', maxDiscountAmount, '', Math.ceil);
            }

            function sm_applyFilters() {
                if (!sm_resultsDiv || !sm_currentResults) return;

                // Получаем фильтр по названию из поля ввода
                const titleFilterInput = document.getElementById('smTitleFilterInput');
                const rawTitleFilterText = titleFilterInput ? titleFilterInput.value.trim() : '';
                // Разбиваем на отдельные слова/фразы по ";" и приводим к нижнему регистру
                const titleFilterTerms = rawTitleFilterText
                    .split(';')
                    .map(term => term.trim().toLowerCase())
                    .filter(term => term.length > 0);

                // Получаем ключевые слова для исключения и фильтры
                const keywords = sm_exclusionKeywords.map(k => k.toLowerCase());
                const pMin = parseFloat(sm_currentFilters.priceMin) || 0;
                const pMax = parseFloat(sm_currentFilters.priceMax) || Infinity;
                const dpMin = parseFloat(sm_currentFilters.discountPercentMin) || 0;
                const dpMax = parseFloat(sm_currentFilters.discountPercentMax) || 100;
                const daMin = parseFloat(sm_currentFilters.discountAmountMin) || 0;
                const daMax = parseFloat(sm_currentFilters.discountAmountMax) || Infinity;
                const hasDiscountFilter = sm_currentFilters.hasDiscount || false;
                const activeStoreFilters = sm_currentFilters.stores;

                let visibleCount = 0;
                const items = sm_resultsDiv.querySelectorAll('.salesMasterItem');

                items.forEach(itemElement => {
                     const index = Array.from(sm_resultsDiv.children).indexOf(itemElement);
                     if (index < 0 || index >= sm_currentResults.length) {
                          itemElement.classList.add('hidden-by-filter');
                          return;
                     }
                     const itemData = sm_currentResults[index];
                     if (!itemData) {
                          itemElement.classList.add('hidden-by-filter');
                          return;
                     }

                    const titleElement = itemElement.querySelector('.sm-title');
                    const itemTitle = titleElement ? titleElement.textContent.trim().toLowerCase() : '';

                    let hideByTitleFilter = false;
                    if (titleFilterTerms.length > 0 && !titleFilterTerms.some(term => itemTitle.includes(term))) {
                        hideByTitleFilter = true;
                    }

                    let shouldHide = false;

                    // 1. Фильтр по магазину
                    if (activeStoreFilters[itemData.storeId] === false) {
                        shouldHide = true;
                    }

                    // 2. Фильтр по ключевым словам (исключения)
                    if (!shouldHide && keywords.length > 0) {
                        let textToSearch = itemTitle;

                        if (itemData.storeId === 'platimarket' && itemData.sellerName) {
                            textToSearch += ' ' + itemData.sellerName.toLowerCase();
                        }
                        if (keywords.some(keyword => textToSearch.includes(keyword))) {
                            shouldHide = true;
                        }
                    }

                    // 3. Фильтр по цене
                    if (!shouldHide && itemData.currentPrice !== null) {
                        if (itemData.currentPrice < pMin || itemData.currentPrice > pMax) {
                            shouldHide = true;
                        }
                    } else if (!shouldHide && itemData.currentPrice === null && (pMin > 0 || pMax < Infinity)) {
                         if (!(pMin === 0 && pMax === Infinity)) {
                           shouldHide = true;
                         }
                    }

                    // 4. Фильтр по % скидки
                    if (!shouldHide) {
                        const discountP = itemData.discountPercent ?? 0;
                        if (discountP < dpMin || discountP > dpMax) {
                            shouldHide = true;
                        }
                    }

                    // 5. Фильтр по сумме скидки
                    if (!shouldHide) {
                        const discountA = itemData.discountAmount ?? 0;
                        if (discountA < daMin || discountA > daMax) {
                            shouldHide = true;
                        }
                    }

                    // 6. Фильтр "Только со скидкой"
                    if (!shouldHide && hasDiscountFilter) {
                        if (!itemData.discountPercent || itemData.discountPercent <= 0) {
                            shouldHide = true;
                        }
                    }

                    // Применяем класс скрытия, если сработал любой фильтр ИЛИ фильтр по названию
                    if (shouldHide || hideByTitleFilter) {
                        itemElement.classList.add('hidden-by-filter');
                    } else {
                        itemElement.classList.remove('hidden-by-filter');
                        visibleCount++;
                    }
                });

                // Обновляем статус в шапке
                const totalLoadedCount = sm_currentResults.length;
                const anyFilterActive = pMin > 0 || pMax < Infinity || dpMin > 0 || dpMax < 100 || daMin > 0 || daMax < Infinity || hasDiscountFilter || keywords.length > 0 || Object.values(activeStoreFilters).some(v => v === false) || titleFilterTerms.length > 0;
                const errorStoresCount = Object.values(sm_stores).filter(s => s.status === 'error').length;

                let statusMessage = '';
                if (sm_activeRequests === 0) {
                    if (totalLoadedCount > 0) {
                        if (anyFilterActive) {
                            statusMessage = `Показано ${visibleCount} из ${totalLoadedCount} предложений. `;
                        } else {
                            statusMessage = `Найдено ${totalLoadedCount} предложений. `;
                        }
                    } else {
                         const gameName = sm_getSteamGameName();
                        if (gameName) {
                           statusMessage = `Предложений не найдено. `;
                        } else {
                           statusMessage = `Введите запрос или обновите для поиска.`;
                        }
                    }
                    if (errorStoresCount > 0) {
                        statusMessage += `(${errorStoresCount} маг. с ошибками).`;
                    }
                    sm_updateStatus(statusMessage.trim(), false);
                } else {
                }

                if (visibleCount === 0 && totalLoadedCount > 0 && anyFilterActive && sm_activeRequests === 0) {
                    const statusDivInHeader = document.getElementById('salesMasterHeaderStatus');
                    if (statusDivInHeader) {
                        let currentStatus = statusDivInHeader.textContent.replace(' Нет товаров, соответствующих фильтрам.', '');
                        statusDivInHeader.textContent = currentStatus.trim() + ' Нет товаров, соответствующих фильтрам.';
                    }
                }
            }


            // --- Фильтрация исключений ---
            function sm_addExclusionKeyword() {
                const keyword = sm_excludeInput.value.trim().toLowerCase();
                if (keyword && !sm_exclusionKeywords.includes(keyword)) {
                    sm_exclusionKeywords.push(keyword);
                    GM_setValue(SM_EXCLUSION_STORAGE_KEY, sm_exclusionKeywords);
                    sm_excludeInput.value = '';
                    sm_renderExclusionTags();
                    sm_applyFilters();
                }
            }

            function sm_removeExclusionKeyword(keywordToRemove) {
                sm_exclusionKeywords = sm_exclusionKeywords.filter(k => k !== keywordToRemove);
                GM_setValue(SM_EXCLUSION_STORAGE_KEY, sm_exclusionKeywords);
                sm_renderExclusionTags();
                sm_applyFilters();
            }

            function sm_renderExclusionTags() {
                if (!sm_exclusionTagsListDiv) return;
                sm_exclusionTagsListDiv.innerHTML = '';
                sm_exclusionKeywords.forEach(keyword => {
                    const tag = document.createElement('span');
                    tag.className = 'smExclusionTag';
                    tag.textContent = keyword;
                    tag.title = `Удалить "${keyword}"`;
                    tag.onclick = () => sm_removeExclusionKeyword(keyword);
                    sm_exclusionTagsListDiv.appendChild(tag);
                });
            }

           // --- Рендеринг результатов ---
            function sm_renderResults() {
                if (!sm_resultsDiv) return;
                sm_resultsDiv.innerHTML = '';
                if (sm_currentResults.length === 0 && sm_activeRequests === 0) {
                    sm_applyFilters();
                    return;
                }

                const fragment = document.createDocumentFragment();
                const isUsdMode = sm_currentCurrencyMode === 'USD';
                const rubToUsdRate = sm_exchangeRates['rub']?.usd || null;

                if (isUsdMode && !rubToUsdRate) {
                    sm_updateStatus('Не удалось загрузить курс RUB/USD для конвертации.', false);
                }

                sm_currentResults.forEach(item => {
                    const itemDiv = document.createElement('div');
                    itemDiv.className = 'salesMasterItem';
                    itemDiv.dataset.store = item.storeId;

                    if (item.storeId === 'steam_current_page') {
                        itemDiv.classList.add('steam-page-offer');
                    }

                    const link = document.createElement('a');
                    link.href = item.productUrl || item.storeUrl || '#';
                    link.target = '_blank';
                    link.rel = 'noopener noreferrer nofollow';

                    const imageWrapper = document.createElement('div');
                    imageWrapper.className = 'sm-card-image-wrapper';
                    const img = document.createElement('img');
                    let imgSrc = item.imageUrl;
                    if (imgSrc && !imgSrc.startsWith('http') && !imgSrc.startsWith('//')) {
                        try {
                            const storeBaseUrl = new URL(item.storeUrl || sm_storeModules.find(s => s.id === item.storeId)?.baseUrl || unsafeWindow.location.origin);
                            imgSrc = new URL(imgSrc, storeBaseUrl.origin).href;
                        } catch (e) {
                            imgSrc = 'https://via.placeholder.com/150x80?text=No+Image';
                        }
                    } else if (!imgSrc) {
                        imgSrc = 'https://via.placeholder.com/150x80?text=No+Image';
                    }
                    img.src = imgSrc;
                    img.alt = item.productName || 'Изображение товара';
                    img.loading = 'lazy';
                    img.onerror = function() {
                        this.onerror = null; this.src = 'https://via.placeholder.com/150x80?text=Load+Error'; this.style.objectFit = 'contain';
                    };
                    imageWrapper.appendChild(img);
                    link.appendChild(imageWrapper);

                    const priceDiv = document.createElement('div');
                    priceDiv.className = 'sm-price-container';
                    const currentPriceSpan = document.createElement('span');
                    currentPriceSpan.className = 'sm-current-price';

                    if (isUsdMode) {
                        if (item.currentPrice !== null && rubToUsdRate) {
                            const usdPrice = item.currentPrice * rubToUsdRate;
                            currentPriceSpan.textContent = `$${usdPrice.toFixed(2)}`;
                        } else {
                            currentPriceSpan.textContent = item.currentPrice === null ? 'Нет цены' : 'Нет курса';
                        }
                    } else {
                        currentPriceSpan.textContent = item.currentPrice !== null ? `${parseFloat(item.currentPrice).toFixed(0).toLocaleString('ru-RU')} ₽` : 'Нет цены';
                    }
                    priceDiv.appendChild(currentPriceSpan);

                    if (item.discountPercent && item.discountPercent > 0) {
                        const discountBadge = document.createElement('span');
                        discountBadge.className = 'sm-discount-badge';
                        discountBadge.textContent = `-${Math.round(item.discountPercent)}%`;
                        priceDiv.appendChild(discountBadge);
                        if (item.originalPrice !== null) {
                            const originalPriceSpan = document.createElement('span');
                            originalPriceSpan.className = 'sm-original-price';
                            if (isUsdMode && rubToUsdRate) {
                                const usdOriginalPrice = item.originalPrice * rubToUsdRate;
                                originalPriceSpan.textContent = `$${usdOriginalPrice.toFixed(2)}`;
                            } else {
                                originalPriceSpan.textContent = `${parseFloat(item.originalPrice).toFixed(0).toLocaleString('ru-RU')} ₽`;
                            }
                            priceDiv.appendChild(originalPriceSpan);
                        }
                    }
                    link.appendChild(priceDiv);

                    const titleDiv = document.createElement('div');
                    titleDiv.className = 'sm-title';
                    titleDiv.textContent = item.productName || 'Без названия';
                    titleDiv.title = item.productName || 'Без названия';
                    link.appendChild(titleDiv);

                    const storeInfoContainer = document.createElement('div');
                    storeInfoContainer.className = 'sm-store-info-container';
                    const storeDiv = document.createElement('div');
                    storeDiv.className = 'sm-store-name';
                    storeDiv.textContent = item.storeName || 'Неизвестный магазин';
                    storeDiv.title = `Магазин: ${item.storeName}`;
                    storeInfoContainer.appendChild(storeDiv);

                    if (item.storeId === 'platimarket' && item.sellerId && item.sellerName) {
                        const sellerLink = document.createElement('a');
                        sellerLink.className = 'sm-seller-link';
                        sellerLink.textContent = `Продавец: ${item.sellerName}`;
                        sellerLink.title = `Перейти к продавцу: ${item.sellerName}`;
                        try {
                            const safeSellerName = encodeURIComponent(item.sellerName.replace(/[^a-zA-Z0-9_\-.~]/g, '-')).replace(/%2F/g, '/');
                            sellerLink.href = `https://plati.market/seller/${safeSellerName}/${item.sellerId}`;
                            sellerLink.target = '_blank';
                            sellerLink.rel = 'noopener noreferrer nofollow';
                            sellerLink.onclick = (e) => { e.stopPropagation(); };
                            storeInfoContainer.appendChild(sellerLink);
                        } catch (e) {
                             const sellerText = document.createElement('div'); sellerText.className = 'sm-seller-link no-link'; sellerText.textContent = `Продавец: ${item.sellerName}`; storeInfoContainer.appendChild(sellerText);
                        }
                    } else if (item.storeId === 'ggsel' && item.sellerId && item.sellerName) {
                        const sellerLink = document.createElement('a');
                        sellerLink.className = 'sm-seller-link';
                        sellerLink.textContent = `Продавец: ${item.sellerName}`;
                        sellerLink.title = `Перейти к продавцу: ${item.sellerName}`;
                        sellerLink.href = `https://ggsel.net/sellers/${item.sellerId}`;
                        sellerLink.target = '_blank';
                        sellerLink.rel = 'noopener noreferrer nofollow';
                        sellerLink.onclick = (e) => { e.stopPropagation(); };
                        storeInfoContainer.appendChild(sellerLink);
                    }
                    link.appendChild(storeInfoContainer);

                    const buyButtonDiv = document.createElement('div');
                    buyButtonDiv.className = 'sm-buyButton';
                    buyButtonDiv.textContent = 'Перейти';
                    link.appendChild(buyButtonDiv);

                    itemDiv.appendChild(link);
                    fragment.appendChild(itemDiv);
                });

                sm_resultsDiv.appendChild(fragment);
                sm_applyFilters();
            }

            // --- Добавление кнопки SalesMaster ---
            function sm_addSalesMasterButton() {
                const actionsContainer = document.querySelector('#queueActionsCtn');
                // Ищем кнопку Plati как ориентир
                const referenceButton = actionsContainer?.querySelector('.plati_price_button, .vgt_price_button');
                const ignoreButtonContainer = actionsContainer?.querySelector('#ignoreBtn');

                if (!actionsContainer || (!referenceButton && !ignoreButtonContainer)) {
                    // Если нет ни Plati ни Ignore, попробуем вставить просто в actionsContainer
                    if (!actionsContainer) {
                        console.warn('SalesMaster Button: Could not find actions container.');
                        return;
                    }
                    console.warn('SalesMaster Button: Could not find reference button, appending to container.');
                }
                if (actionsContainer.querySelector('.salesMaster_button')) return;

                const smContainer = document.createElement('div');
                smContainer.className = 'salesMaster_button queue_control_button';
                smContainer.style.marginLeft = '3px';

                smContainer.innerHTML = `<div class="btnv6_blue_hoverfade btn_medium" style="height: 32px; padding: 0 5px; font-size: 18px; font-weight: bold;" title="Поиск скидок в других магазинах"><span>%</span></div>`;
                smContainer.querySelector('div').addEventListener('click', (e) => {
                    e.preventDefault();
                    e.stopPropagation();
                    sm_showModal();
                });

                // Логика вставки: после Plati, или после Ignore, или в конец actionsContainer
                if (referenceButton) {
                    referenceButton.insertAdjacentElement('afterend', smContainer);
                } else if (ignoreButtonContainer) {
                    ignoreButtonContainer.insertAdjacentElement('afterend', smContainer);
                } else if (actionsContainer) {
                    actionsContainer.appendChild(smContainer);
                }
            }

            // --- Стили SalesMaster ---
            function sm_addStyles() {
                GM_addStyle(`
                #salesMasterModal {
                	position: fixed;
                	top: 0;
                	left: 0;
                	width: 100%;
                	height: 100%;
                	background-color: rgba(20, 20, 25, 0.9);
                	backdrop-filter: blur(3px);
                	z-index: 9999;
                	display: none;
                	color: #c6d4df;
                	font-family: "Motiva Sans", Sans-serif, Arial;
                }

                #salesMasterModal * {
                	box-sizing: border-box;
                }

                #salesMasterContainer {
                	padding-top: 0;
                	height: 100%;
                	display: flex;
                	flex-direction: column;
                }

                #salesMasterCloseBtn {
                	position: fixed;
                	top: 15px;
                	right: 20px;
                	font-size: 35px;
                	color: #aaa;
                	background: none;
                	border: none;
                	cursor: pointer;
                	line-height: 1;
                	z-index: 10002;
                	padding: 5px;
                	transition: color 0.2s, transform 0.2s;
                }

                #salesMasterCloseBtn:hover {
                	color: #fff;
                	transform: scale(1.1);
                }

                /* --- Шапка --- */
                #salesMasterHeader {
                	display: flex;
                	align-items: center;
                	gap: 10px;
                	flex-wrap: wrap;
                	position: relative;
                	z-index: 1001;
                	background-color: rgba(27, 40, 56, 0.95);
                	backdrop-filter: blur(5px);
                	padding: 10px 15px;
                	border-bottom: 1px solid #3a4f6a;
                	border-radius: 0;
                	margin-left: 0;
                	margin-right: 0;
                	transition: padding-left 0.2s ease-out, padding-right 0.2s ease-out;
                	flex-shrink: 0;
                }

                #salesMasterHeaderStatus {
                	text-align: left;
                	font-size: 14px;
                	color: #aaa;
                	padding: 0 10px 0 0;
                	white-space: nowrap;
                	overflow: hidden;
                	text-overflow: ellipsis;
                	display: flex;
                	align-items: center;
                	justify-content: flex-start;
                	min-height: 36px;
                	flex-shrink: 0;
                }

                #salesMasterHeaderStatus .spinner {
                	margin-left: 8px;
                }

                #smTitleFilterInput {
                	width: 250px;
                	height: 36px;
                	padding: 6px 12px;
                	font-size: 14px;
                	background-color: rgba(10, 10, 15, 0.7);
                	border: 1px solid #3a4f6a;
                	color: #c6d4df;
                	border-radius: 3px;
                	outline: none;
                	box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
                	margin-left: 5px;
                	flex-shrink: 0;
                }

                #smTitleFilterInput:focus {
                	border-color: #67c1f5;
                	background-color: rgba(0, 0, 0, 0.8);
                }

                #smTitleFilterInput::placeholder {
                	color: #777;
                	font-style: italic;
                	font-size: 13px;
                }

                .smInsertTitleBtn {
                	padding: 0 10px;
                	font-size: 12px;
                }

                #salesMasterSortButtons {
                	display: flex;
                	gap: 5px;
                	align-items: center;
                	margin-left: 10px;
                }

                /* --- Кнопки --- */
                .salesMasterBtn {
                	padding: 0 12px;
                	font-size: 13px;
                	color: #c6d4df;
                	border: 1px solid #4b6f9c;
                	border-radius: 3px;
                	cursor: pointer;
                	white-space: nowrap;
                	height: 36px;
                	display: inline-flex;
                	align-items: center;
                	justify-content: center;
                	flex-shrink: 0;
                	background-color: rgba(42, 71, 94, 0.8);
                	transition: background-color 0.2s, border-color 0.2s;
                	text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.4);
                }

                .salesMasterBtn:hover:not(:disabled) {
                	background-color: rgba(67, 103, 133, 0.9);
                	border-color: #67c1f5;
                }

                .salesMasterBtn:disabled {
                	opacity: 0.6;
                	cursor: default;
                	background-color: rgba(42, 71, 94, 0.5);
                	border-color: #3a4f6a;
                }

                #salesMasterSearchGoBtn {
                	background-color: rgba(77, 136, 255, 0.8);
                	border-color: #4D88FF;
                }

                #salesMasterSearchGoBtn:hover:not(:disabled) {
                	background-color: rgba(51, 102, 204, 0.9);
                }

                .salesMasterBtn.sortBtn.active {
                	background-color: rgba(0, 123, 255, 0.8);
                	border-color: #007bff;
                }

                .salesMasterBtn.sortBtn.active:hover {
                	background-color: rgba(0, 86, 179, 0.9);
                }

                .sortBtn span {
                	margin-left: 5px;
                	font-size: 12px;
                	line-height: 1;
                }

                #salesMasterResetSortBtn {
                	background-color: rgba(119, 119, 119, 0.8);
                	border-color: #777;
                	padding: 0 8px;
                }

                #salesMasterResetSortBtn:hover {
                	background-color: rgba(136, 136, 136, 0.9);
                }

                #salesMasterResetSortBtn svg {
                	width: 14px;
                	height: 14px;
                	fill: currentColor;
                }

                #salesMasterResetSortBtn.active {
                	background-color: rgba(0, 123, 255, 0.8);
                	border-color: #007bff;
                }

                /* --- Боковые панели ("плавающие") --- */
                #salesMasterFiltersPanel,
                #salesMasterExclusionTags {
                	position: fixed;
                	top: 60px;
                	max-height: calc(100vh - 80px);
                	overflow-y: auto;
                	z-index: 1000;
                	padding: 15px;
                	scrollbar-width: thin;
                	scrollbar-color: #555 #2a2a30;
                	background-color: transparent;
                	backdrop-filter: none;
                	border-radius: 6px;
                	box-shadow: none;
                	border: none;
                	transition: top 0.2s ease-in-out, max-height 0.2s ease-in-out;
                	visibility: hidden;
                }

                #salesMasterFiltersPanel::before,
                #salesMasterExclusionTags::before {
                	content: '';
                	position: absolute;
                	top: 0;
                	left: 0;
                	right: 0;
                	bottom: 0;
                	background-color: rgba(23, 26, 33, 0.85);
                	backdrop-filter: blur(4px);
                	border-radius: 6px;
                	z-index: -1;
                }

                #salesMasterFiltersPanel::-webkit-scrollbar,
                #salesMasterExclusionTags::-webkit-scrollbar {
                	width: 5px;
                }

                #salesMasterFiltersPanel::-webkit-scrollbar-track,
                #salesMasterExclusionTags::-webkit-scrollbar-track {
                	background: rgba(42, 42, 48, 0.5);
                	border-radius: 3px;
                }

                #salesMasterFiltersPanel::-webkit-scrollbar-thumb,
                #salesMasterExclusionTags::-webkit-scrollbar-thumb {
                	background-color: rgba(85, 85, 85, 0.7);
                	border-radius: 3px;
                }

                #salesMasterFiltersPanel {
                	left: 15px;
                	width: 240px;
                }

                #salesMasterExclusionTags {
                	right: 15px;
                	width: 260px;
                }

                .smFilterGroup {
                	margin-bottom: 20px;
                }

                .smFilterGroup h4 {
                	font-size: 15px;
                	color: #67c1f5;
                	margin-bottom: 10px;
                	padding-bottom: 5px;
                	display: flex;
                	justify-content: space-between;
                	align-items: center;
                	font-weight: 500;
                	border-bottom: 1px solid #3a4f6a;
                }

                .smFilterResetBtn {
                	font-size: 12px;
                	color: #8f98a0;
                	background: none;
                	border: none;
                	cursor: pointer;
                	padding: 0 3px;
                	line-height: 1;
                }

                .smFilterResetBtn:hover {
                	color: #c6d4df;
                }

                .smFilterResetBtn svg {
                	width: 14px;
                	height: 14px;
                	vertical-align: middle;
                	fill: currentColor;
                }

                .smFilterRangeInputs {
                	display: flex;
                	gap: 8px;
                	align-items: center;
                }

                .smFilterRangeInputs input[type="number"] {
                	width: calc(50% - 4px);
                	padding: 8px 10px;
                	font-size: 14px;
                	background-color: rgba(10, 10, 15, 0.7);
                	border: 1px solid #3a4f6a;
                	color: #c6d4df;
                	border-radius: 3px;
                	height: 34px;
                	text-align: center;
                	-moz-appearance: textfield;
                	box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
                	outline: none;
                }

                .smFilterRangeInputs input[type="number"]:focus {
                	border-color: #67c1f5;
                	background-color: rgba(0, 0, 0, 0.8);
                }

                .smFilterRangeInputs input[type="number"]::-webkit-outer-spin-button,
                .smFilterRangeInputs input[type="number"]::-webkit-inner-spin-button {
                	-webkit-appearance: none;
                	margin: 0;
                }

                .smFilterRangeInputs input[type="number"]::placeholder {
                	color: #777;
                	font-size: 12px;
                	text-align: center;
                }

                .smFilterCheckbox {
                	margin-bottom: 10px;
                }

                .smFilterCheckbox label {
                	display: flex;
                	align-items: center;
                	font-size: 14px;
                	cursor: pointer;
                	color: #c6d4df;
                }

                .smFilterCheckbox input[type="checkbox"] {
                	margin-right: 8px;
                	width: 18px;
                	height: 18px;
                	accent-color: #67c1f5;
                	cursor: pointer;
                	flex-shrink: 0;
                }

                .smFilterCheckbox.sm-store-error label {
                	background-color: rgba(139, 0, 0, 0.35);
                	border: 1px solid rgba(255, 100, 100, 0.3);
                	border-radius: 3px;
                	padding: 1px 4px;
                	margin: -1px -4px;
            	}

                #smFilterStoreCheckboxes {
                	max-height: 315px;
                	padding-right: 5px;
                	overflow-y: auto;
                }

                #smResetAllFiltersBtn {
                	width: 100%;
                	margin-top: 15px;
                	padding: 10px 15px;
                	height: auto;
                	font-size: 14px;
                	background-color: rgba(108, 117, 125, 0.6);
                	border: 1px solid #5a6268;
                	text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.4);
                	color: #c6d4df;
                }

                #smResetAllFiltersBtn:hover {
                	background-color: rgba(90, 98, 104, 0.8);
                	border-color: #8f98a0;
                }

                .smExclusionInputGroup {
                	display: flex;
                	align-items: stretch;
                	border: 1px solid #3a4f6a;
                	border-radius: 4px;
                	background-color: rgba(10, 10, 15, 0.7);
                	overflow: hidden;
                	height: 36px;
                	flex-shrink: 0;
                	box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
                	margin-bottom: 10px;
                }

                #salesMasterExcludeInput {
                	padding: 6px 12px;
                	font-size: 14px;
                	background-color: transparent;
                	border: none;
                	color: #c6d4df;
                	outline: none;
                	border-radius: 0;
                	flex-grow: 1;
                	width: auto;
                	height: auto;
                }

                #salesMasterExcludeInput:focus {
                	box-shadow: none;
                }

                #salesMasterAddExcludeBtn {
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    width: 36px;
                    background-color: #4b6f9c;
                    border: none;
                    border-left: 1px solid #3a4f6a;
                    cursor: pointer;
                    border-radius: 0;
                    color: #c6d4df;
                    height: auto;
                }

                #salesMasterAddExcludeBtn:hover {
                	background-color: #67c1f5;
                	color: #fff;
                }

                #salesMasterAddExcludeBtn svg {
                	width: 16px;
                	height: 16px;
                	fill: currentColor;
                }

                #salesMasterExclusionTagsList {
                	display: flex;
                	flex-direction: row;
                	flex-wrap: wrap;
                	align-content: flex-start;
                	gap: 10px;
                	overflow-y: auto;
                	flex-grow: 1;
                }

                .smExclusionTag {
                	display: inline-block;
                	background-color: rgba(75, 111, 156, 0.7);
                	color: #c6d4df;
                	padding: 6px 12px;
                	border-radius: 15px;
                	font-size: 14px;
                	cursor: pointer;
                	transition: background-color 0.2s;
                	border: 1px solid #4b6f9c;
                	white-space: nowrap;
                	text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
                }

                .smExclusionTag:hover {
                	background-color: rgba(220, 53, 69, 0.8);
                	border-color: rgba(255, 80, 90, 0.9);
                	color: #fff;
                }

                .smExclusionTag::after {
                	content: ' ×';
                	font-weight: bold;
                	margin-left: 4px;
                	font-size: 12px;
                }

                .smExclusionActions {
                    display: flex;
                    justify-content: flex-end;
                    gap: 8px;
                    margin-top: 10px;
                    margin-bottom: 10px;
                    padding-bottom: 10px;
                    border-bottom: 1px solid #3a4f6a;
                }

                .smExclusionActionBtn {
                    padding: 0 8px;
                    height: 30px;
                    width: 40px;
                    background-color: rgba(75, 111, 156, 0.7);
                    border-color: #4b6f9c;
                    font-size: 14px;
                    font-weight: bold;
                    line-height: 1;
                }

                #smImportModal {
                    position: fixed;
                    top: 0;
                    left: 0;
                    width: 100%;
                    height: 100%;
                    background-color: rgba(0, 0, 0, 0.7);
                    z-index: 10003;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                }

                .smImportModalContent {
                    background-color: #1b2838;
                    padding: 25px;
                    border-radius: 5px;
                    border: 1px solid #67c1f5;
                    width: 90%;
                    max-width: 500px;
                    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
                }

                .smImportModalContent h4 {
                    margin-top: 0;
                    margin-bottom: 15px;
                    color: #67c1f5;
                    font-size: 16px;
                    text-align: center;
                }
                 .smImportModalContent p {
                    margin-bottom: 10px;
                    font-size: 14px;
                    color: #c6d4df;
                 }

                #smImportTextarea {
                    width: 100%;
                    padding: 10px;
                    font-size: 14px;
                    background-color: rgba(10, 10, 15, 0.7);
                	border: 1px solid #3a4f6a;
                	color: #c6d4df;
                	border-radius: 3px;
                    margin-bottom: 20px;
                    min-height: 100px;
                    resize: vertical;
                    outline: none;
                }
                #smImportTextarea:focus {
                    border-color: #67c1f5;
                }


                .smImportModalActions {
                    display: flex;
                    justify-content: flex-end;
                    gap: 10px;
                }

                 .smImportModalActions .salesMasterBtn {
                    padding: 8px 20px;
                    height: auto;
                    font-size: 14px;
                 }

                #smImportAcceptBtn {
                     background-color: rgba(77, 136, 255, 0.8);
                	 border-color: #4D88FF;
                }
                #smImportAcceptBtn:hover {
                    background-color: rgba(51, 102, 204, 0.9);
                }
                #smImportCancelBtn {
                    background-color: rgba(108, 117, 125, 0.6);
                	border: 1px solid #5a6268;
                }
                 #smImportCancelBtn:hover {
                	background-color: rgba(90, 98, 104, 0.8);
                	border-color: #8f98a0;
                }

                #salesMasterExclusionTagsList {
                    margin-top: 0;
                }


                /* --- Контейнер и статус результатов --- */
                #salesMasterResultsContainer {
                	position: relative;
                	flex-grow: 1;
                	padding-top: 15px;
                	transition: padding-left 0.2s ease-out, padding-right 0.2s ease-out;
                	overflow-y: auto;
                	scrollbar-color: #4b6f9c #17202d;
                	scrollbar-width: thin;
                }

                #salesMasterResultsContainer::-webkit-scrollbar {
                	width: 8px;
                }

                #salesMasterResultsContainer::-webkit-scrollbar-track {
                	background: #17202d;
                	border-radius: 4px;
                }

                #salesMasterResultsContainer::-webkit-scrollbar-thumb {
                	background-color: #4b6f9c;
                	border-radius: 4px;
                	border: 2px solid #17202d;
                }

                #salesMasterResultsContainer::-webkit-scrollbar-thumb:hover {
                	background-color: #67c1f5;
                }

                #salesMasterResultsStatus {
                	display: none !important;
                }

                #salesMasterResults {
                	display: grid;
                	grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
                	gap: 20px;
                	padding-top: 15px;
                	padding-bottom: 20px;
                }

                /* --- Класс для скрытия по фильтру названий --- */
                .salesMasterItem.hidden-by-filter {
                	display: none !important;
                }

                /* --- Карточка товара --- */
                .salesMasterItem {
                	background-color: rgba(42, 46, 51, 0.85);
                	backdrop-filter: blur(4px);
                	border-radius: 4px;
                	padding: 15px;
                	display: flex;
                	flex-direction: column;
                	transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
                	box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
                	position: relative;
                	color: #c6d4df;
                	font-size: 14px;
                	min-height: 380px;
                	border: 1px solid #333941;
                }

                .salesMasterItem:hover {
                	transform: translateY(-3px);
                	box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
                	background-color: rgba(50, 55, 61, 0.9);
                	border-color: #67c1f5;
                }

                .salesMasterItem a {
                	text-decoration: none;
                	color: inherit;
                	display: flex;
                	flex-direction: column;
                	height: 100%;
                }

                /* --- Стили для выделения предложений со страницы Steam --- */
                .salesMasterItem.steam-page-offer {
                    background-color: #202c24;
                    border: 1px solid #354f3a;
                    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.4);
                    color: #c6d4df;
                    transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
                }

                /* Кнопка в приглушенном зеленом стиле, похожем на стандартную синюю */
                .salesMasterItem.steam-page-offer .sm-buyButton {
                     background-color: #5c9d4f;
                     color: #1a2f1f;
                     font-weight: 600;
                     border: none;
                     transition: background-color 0.2s, color 0.2s;
                }
                 .salesMasterItem.steam-page-offer .sm-buyButton:hover {
                     background-color: #6ebf5f;
                     color: #0f1a0f;
                }

                .salesMasterItem.steam-page-offer:hover {
                    background-color: #304035;
                    border-color: #4a784d;
                    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
                    transform: translateY(-3px);
                }



                .sm-card-image-wrapper {
                	position: relative;
                	width: 100%;
                	aspect-ratio: 16 / 9;
                	margin-bottom: 12px;
                	background-color: #111;
                	border-radius: 3px;
                	overflow: hidden;
                	display: flex;
                	align-items: center;
                	justify-content: center;
                	border: 1px solid #333941;
                }

                .sm-card-image-wrapper img {
                	display: block;
                	max-width: 100%;
                	max-height: 100%;
                	width: auto;
                	height: auto;
                	object-fit: contain;
                	border-radius: 3px;
                }

                .sm-price-container {
                	display: flex;
                	flex-wrap: wrap;
                	align-items: baseline;
                	gap: 5px 10px;
                	margin-bottom: 10px;
                	min-height: 26px;
                }

                .sm-current-price {
                	font-size: 18px;
                	font-weight: 700;
                	color: #66c0f4;
                	line-height: 1;
                }

                .sm-original-price {
                	font-size: 14px;
                	color: #8f98a0;
                	text-decoration: line-through;
                	line-height: 1;
                }

                .sm-discount-badge {
                	background-color: #e2004b;
                	color: white;
                	padding: 3px 7px;
                	font-size: 13px;
                	border-radius: 3px;
                	font-weight: 600;
                	line-height: 1;
                }

                .sm-title {
                	font-size: 15px;
                	font-weight: 500;
                	line-height: 1.4;
                	height: 4.2em;
                	overflow: hidden;
                	text-overflow: ellipsis;
                	margin-bottom: 10px;
                	color: #e5e5e5;
                	display: -webkit-box;
                	-webkit-line-clamp: 3;
                	-webkit-box-orient: vertical;
                }

                /* --- Контейнер для магазина/продавца --- */
                .sm-store-info-container {
                    margin-top: auto;
                    padding-top: 10px;
                    text-align: right;
                    display: flex;
                    flex-direction: column;
                    align-items: flex-end;
                    gap: 3px;
                }

                /* --- Стиль названия магазина --- */
                .sm-store-name {
                    font-size: 12px;
                    color: #8f98a0;
                    text-align: right;
                }

                /* --- Стили для управления выбором магазинов --- */
                .smStoreSelectAllControls {
                    margin-top: -5px;
                    margin-bottom: 10px;
                    padding-top: 5px;
                    border-bottom: 1px solid #3a4f6a;
                    text-align: center;
                }

                .smStoreSelectAllLink {
                    font-size: 12px;
                    color: #8f98a0;
                    cursor: pointer;
                    text-decoration: none;
                    transition: color 0.2s;
                    padding: 0 5px;
                }

                .smStoreSelectAllLink:hover {
                    color: #c6d4df;
                    text-decoration: underline;
                }

                .smStoreSelectSeparator {
                    color: #5a6268;
                    margin: 0 3px;
                    font-size: 12px;
                }

                /* --- Стиль ссылки продавца --- */
                .sm-seller-link {
                    font-size: 12px;
                    color: #8f98a0;
                    text-align: right;
                    display: block;
                    white-space: nowrap;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    text-decoration: none;
                    transition: color 0.2s;
                 }
                 .sm-seller-link:not(.no-link):hover {
                    color: #c6d4df;
                    text-decoration: underline;
                 }

                .sm-buyButton {
                	display: block;
                	text-align: center;
                	padding: 10px;
                	margin-top: 12px;
                	background-color: #67c1f5;
                	color: #1b2838;
                	border-radius: 3px;
                	font-size: 14px;
                	font-weight: 600;
                	transition: background-color 0.2s, color 0.2s;
                	margin-top: auto;
                	border: none;
                }

                .sm-buyButton:hover {
                	background-color: #8ad3f7;
                	color: #0e141b;
                }

                /* --- Адаптивность SM --- */
                @media (max-width: 1400px) {
                	#salesMasterResults {
                		grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
                	}
                }

                @media (max-width: 1100px) {
                	#salesMasterResults {
                		grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
                	}

                	#smTitleFilterInput {
                		max-width: 200px;
                	}
                }

                @media (max-width: 850px) {

                	#salesMasterFiltersPanel,
                	#salesMasterExclusionTags {
                		display: none;
                	}

                	#salesMasterHeader,
                	#salesMasterResultsContainer {
                		padding-left: 15px;
                		padding-right: 15px;
                	}

                	#salesMasterResults {
                		grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
                	}

                	#salesMasterHeader {
                		justify-content: space-between;
                	}

                	#smTitleFilterInput {
                		max-width: 180px;
                		margin-left: 5px;
                		margin-right: 5px;
                	}

                	.smInsertTitleBtn {
                		display: none;
                	}

                }

                @media (max-width: 600px) {
                	#salesMasterContainer {
                		width: 95%;
                		margin: 10px auto;
                		min-height: calc(100vh - 20px);
                	}

                	#salesMasterHeader {
                		flex-direction: column;
                		align-items: stretch;
                		padding-bottom: 5px;
                	}

                	#salesMasterHeaderStatus {
                		order: -2;
                		min-height: 25px;
                		padding: 5px 0;
                		font-size: 13px;
                		max-width: 100%;
                		text-align: center;
                		justify-content: center;
                		margin-bottom: 5px;
                	}

                	#smTitleFilterInput {
                		order: -1;
                		max-width: 100%;
                		margin: 0 0 10px 0;
                	}

                	.smInsertTitleBtn {
                		display: block;
                		order: -1;
                		margin: 0 0 5px 0;
                		width: 100%;
                	}

                	/* Показываем кнопку подстановки и делаем на всю ширину */
                	#salesMasterSortButtons {
                		width: 100%;
                		justify-content: space-around;
                		margin-top: 5px;
                		margin-left: 0;
                	}

                	.salesMasterBtn {
                		flex-grow: 1;
                		font-size: 13px;
                		padding: 8px 5px;
                		height: 36px;
                	}

                	#salesMasterResetSortBtn {
                		flex-grow: 0;
                		width: auto;
                		padding: 0 8px;
                	}

                	#salesMasterResults {
                		grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
                		gap: 10px;
                	}

                	.salesMasterItem {
                		min-height: 320px;
                		font-size: 13px;
                	}

                	.sm-current-price {
                		font-size: 15px;
                	}

                	.sm-title {
                		font-size: 13px;
                		height: 3.9em;
                		-webkit-line-clamp: 3;
                	}

                	.sm-store-name {
                		font-size: 11px;
                	}

                	.sm-buyButton {
                		font-size: 13px;
                		padding: 8px;
                	}
                }

                /* --- Кнопка % на странице --- */
                .salesMaster_button .btnv6_blue_hoverfade {
                	margin: 0;
                	padding: 0 10px;
                	font-size: 18px;
                	display: flex;
                	align-items: center;
                	justify-content: center;
                	transition: filter 0.2s;
                }

                .salesMaster_button .btnv6_blue_hoverfade:hover {
                	filter: brightness(1.1);
                }

                /* Спиннер */
                @keyframes salesMasterSpin {
                	0% {
                		transform: rotate(0deg);
                	}

                	100% {
                		transform: rotate(360deg);
                	}
                }

                .spinner {
                	border: 2px solid rgba(255, 255, 255, 0.3);
                	border-radius: 50%;
                	border-top-color: #fff;
                	width: 1em;
                	height: 1em;
                	animation: salesMasterSpin 1s linear infinite;
                	display: inline-block;
                	vertical-align: middle;
                	margin-left: 5px;
                	line-height: 1;
                }
            `);
            }

            // --- Модули магазинов ---
            const sm_storeModules = [

                { // --- Модуль Steam ---
                    id: 'steam_current_page',
                    name: 'Steam',
                    baseUrl: 'https://store.steampowered.com',
                    searchUrlTemplate: '',
                    isEnabled: true,
                    fetch: async function(query) {
                        const storeModule = this;
                        const results = [];
                        const currencySymbol = sm_getCurrencySymbol();

                        const currencyMeta = document.querySelector('meta[itemprop="priceCurrency"]');
                        const pageCurrency = currencyMeta ? currencyMeta.content.toUpperCase() : 'RUB';

                        let exchangeRate = 1.0;

                        if (pageCurrency !== 'RUB') {
                            try {
                                const rates = await sm_fetchExchangeRates(pageCurrency);
                                if (rates && rates['rub']) {
                                    exchangeRate = parseFloat(rates['rub']);
                                    if (isNaN(exchangeRate) || exchangeRate <= 0) {
                                        sm_logError(storeModule.name, `Invalid exchange rate for ${pageCurrency} -> RUB: ${rates['rub']}`);
                                        exchangeRate = 1.0;
                                    }
                                } else {
                                    sm_logError(storeModule.name, `Could not get RUB rate for ${pageCurrency}`);
                                }
                            } catch (error) {
                                sm_logError(storeModule.name, `Error fetching exchange rates for ${pageCurrency}: ${error.message}`, error);
                            }
                        }

                        const headerImageElement = document.querySelector('#gameHeaderImageCtn img.game_header_image_full');
                        const mainImageUrl = headerImageElement ? headerImageElement.src : null;

                        const purchaseWrappers = document.querySelectorAll('.game_area_purchase_game_wrapper');

                        purchaseWrappers.forEach(wrapper => {
                            try {
                                const gamePurchaseDiv = wrapper.querySelector('.game_area_purchase_game, .game_area_purchase_game_dropdown_subscription');
                                if (!gamePurchaseDiv) return;

                                const titleElement = gamePurchaseDiv.querySelector('[id^="game_area_purchase_section_add_to_cart_title_"], [id^="bundle_purchase_label_"]');
                                let productName = null;
                                if (titleElement) {
                                    let cleanedText = titleElement.textContent.trim();
                                    cleanedText = cleanedText.replace(/^(Купить|Buy)[\s\u00A0]+/, '');
                                    cleanedText = cleanedText.replace(/\s*(—\s*НАБОР|BUNDLE)\s*\(\?\)\s*$/, '');
                                    productName = cleanedText.trim();
                                }

                                if (!productName) return;

                                let currentPrice = null;
                                let originalPrice = null;
                                let discountPercent = 0;
                                let imageUrl = mainImageUrl;

                                const priceSimpleElement = gamePurchaseDiv.querySelector('.game_purchase_price.price[data-price-final]');
                                const discountBlockElement = gamePurchaseDiv.querySelector('.discount_block.game_purchase_discount');

                                if (discountBlockElement) {
                                    const finalPriceText = discountBlockElement.querySelector('.discount_final_price')?.textContent;
                                    const originalPriceText = discountBlockElement.querySelector('.discount_original_price')?.textContent;
                                    const discountPercentText = discountBlockElement.querySelector('.discount_pct')?.textContent;
                                    const dataPriceFinal = discountBlockElement.dataset.priceFinal;
                                    const dataDiscount = discountBlockElement.dataset.discount;
                                    const dataBundleDiscount = discountBlockElement.dataset.bundlediscount;

                                    if (finalPriceText) {
                                        currentPrice = sm_parsePrice(finalPriceText);
                                    } else if (dataPriceFinal) {
                                        currentPrice = parseFloat(dataPriceFinal) / 100;
                                        if (isNaN(currentPrice)) currentPrice = null;
                                    }

                                    if (originalPriceText) {
                                        originalPrice = sm_parsePrice(originalPriceText);
                                    }

                                    if (discountPercentText) {
                                        discountPercent = sm_parsePercent(discountPercentText) || 0;
                                    } else if (dataDiscount) {
                                        discountPercent = parseFloat(dataDiscount) || 0;
                                    }

                                    if (discountPercent === 0 && dataBundleDiscount) {
                                        const bundleDiscountVal = parseFloat(dataBundleDiscount);
                                        if (bundleDiscountVal > 0) {
                                            discountPercent = bundleDiscountVal;
                                            if (originalPrice === null && currentPrice !== null) {
                                                originalPrice = currentPrice / (1 - discountPercent / 100);
                                            }
                                        }
                                    }

                                } else if (priceSimpleElement) {
                                    const dataPriceFinal = priceSimpleElement.dataset.priceFinal;
                                    if (dataPriceFinal) {
                                        currentPrice = parseFloat(dataPriceFinal) / 100;
                                        if (isNaN(currentPrice)) currentPrice = null;
                                    } else {
                                        currentPrice = sm_parsePrice(priceSimpleElement.textContent);
                                    }
                                    originalPrice = currentPrice;
                                    discountPercent = 0;
                                }

                                if (currentPrice !== null) {
                                    const finalCurrentPrice = parseFloat((currentPrice * exchangeRate).toFixed(2));
                                    const finalOriginalPrice = originalPrice !== null ? parseFloat((originalPrice * exchangeRate).toFixed(2)) : null;
                                    const effectiveOriginalPrice = (finalOriginalPrice === null || isNaN(finalOriginalPrice)) ? finalCurrentPrice : finalOriginalPrice;

                                    let data = {
                                        storeId: storeModule.id,
                                        storeName: storeModule.name,
                                        storeUrl: storeModule.baseUrl,
                                        productName: productName,
                                        productUrl: unsafeWindow.location.href,
                                        imageUrl: imageUrl,
                                        currentPrice: finalCurrentPrice,
                                        originalPrice: effectiveOriginalPrice,
                                        discountPercent: discountPercent > 0 ? discountPercent : null,
                                        discountAmount: null,
                                        currency: 'RUB',
                                        isAvailable: true
                                    };

                                    results.push(sm_calculateMissingValues(data));
                                }

                            } catch (e) {
                                sm_logError(storeModule.name, `Error parsing purchase block for "${productName || 'unnamed element'}"`, e);
                            }
                        });

                        return results;
                    }
                },

                { // --- Модуль SteamBuy ---
                    id: 'steambuy',
                    name: 'SteamBuy',
                    baseUrl: 'https://steambuy.com',
                    searchUrlTemplate: 'https://steambuy.com/ajax/_get.php?a=search&q={query}',
                    isEnabled: true,
                    fetch: async function(query) {
                        const searchUrl = this.searchUrlTemplate.replace('{query}', encodeURIComponent(query));
                        return new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: searchUrl,
                                responseType: 'json',
                                headers: {
                                    'Accept': 'application/json, text/javascript, */*; q=0.01',
                                    'X-Requested-With': 'XMLHttpRequest'
                                },
                                timeout: SM_REQUEST_TIMEOUT_MS,
                                onload: (response) => {
                                    if (response.status >= 200 && response.status < 400 && response.response) {
                                        const data = response.response;
                                        if (data.status === 'success' && typeof data.html === 'string') {
                                            resolve(this.parseHtml(data.html, this));
                                        } else if (data.status === 'false' && data.message && data.message.includes("ничего не найдено")) {
                                            resolve([]);
                                        } else if (data.status === 'empty') {
                                            resolve([]);
                                        } else if (data.status === 'success' && !data.html) {
                                            resolve([]);
                                        } else {
                                            reject(new Error(`API вернул неожиданный ответ: Статус ${data.status}, Сообщение: ${data.message || 'Нет сообщения'}`));
                                        }
                                    } else {
                                        reject(new Error(`HTTP статус ${response.status}`));
                                    }
                                },
                                onerror: (error) => reject(new Error('Сетевая ошибка')),
                                ontimeout: () => reject(new Error('Таймаут запроса'))
                            });
                        });
                    },
                    parseHtml: function(htmlString, storeModule) {
                        const results = [];
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');
                        const items = doc.querySelectorAll('.search-result__item');

                        items.forEach(item => {
                            try {
                                const linkElement = item.querySelector('.search-result__link');
                                const imgElement = item.querySelector('.search-result__img img');
                                const titleElement = item.querySelector('.search-result__title');
                                const priceElement = item.querySelector('.search-result__cost');
                                const discountElement = item.querySelector('.search-result__discount');

                                const productName = titleElement?.textContent?.trim() || null;
                                const productUrlRaw = linkElement?.getAttribute('href') || null;
                                const currentPriceText = priceElement?.innerHTML.replace(/<span[^>]*>.*<\/span>/i, '').replace('р', '').trim();
                                const currentPrice = sm_parsePrice(currentPriceText);

                                let discountPercent = 0;
                                const discountText = discountElement?.textContent?.trim();
                                if (discountText && discountText !== '&nbsp;') {
                                    const parsedPercent = sm_parsePercent(discountText);
                                    if (parsedPercent !== null) {
                                        discountPercent = parsedPercent;
                                    }
                                }

                                const imageUrl = imgElement?.getAttribute('src') || null;

                                if (productName && productUrlRaw && currentPrice !== null) {
                                    const fullProductUrl = productUrlRaw.startsWith('/') ? storeModule.baseUrl + productUrlRaw : productUrlRaw;
                                    const productUrl = fullProductUrl + '?partner=234029';

                                    let data = {
                                        storeId: storeModule.id,
                                        storeName: storeModule.name,
                                        storeUrl: storeModule.baseUrl,
                                        productName: productName,
                                        productUrl: productUrl,
                                        imageUrl: imageUrl,
                                        currentPrice: currentPrice,
                                        originalPrice: null,
                                        discountPercent: discountPercent,
                                        discountAmount: null,
                                        currency: 'RUB',
                                        isAvailable: true
                                    };
                                    results.push(sm_calculateMissingValues(data));
                                } else {}
                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента из AJAX HTML', e);
                            }
                        });
                        return results;
                    }
                }, // --- Конец модуля SteamBuy ---

                { // --- Модуль Playo ---
                    id: 'playo',
                    name: 'Playo',
                    baseUrl: 'https://playo.ru',
                    searchUrlTemplate: 'https://playo.ru/search/{query}/?search={query}',
                    isEnabled: true,
                    fetch: async function(query) {
                        const urlEncodedQuery = encodeURIComponent(query).replace(/%20/g, '+');
                        const pathEncodedQuery = encodeURIComponent(query);
                        const searchUrl = this.searchUrlTemplate
                            .replace('{query}', pathEncodedQuery)
                            .replace('{query}', urlEncodedQuery);

                        return new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: searchUrl,
                                timeout: SM_REQUEST_TIMEOUT_MS,
                                onload: (response) => {
                                    if (response.status >= 200 && response.status < 400) {
                                        resolve(this.parseHtml(response.responseText, this));
                                    } else {
                                        reject(new Error(`HTTP статус ${response.status}`));
                                    }
                                },
                                onerror: (error) => reject(new Error('Сетевая ошибка')),
                                ontimeout: () => reject(new Error('Таймаут запроса'))
                            });
                        });
                    },
                    parseHtml: function(htmlString, storeModule) {
                        const results = [];
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');
                        const items = doc.querySelectorAll('.preview_list .preview_it');

                        items.forEach(item => {
                            try {
                                const linkElement = item.querySelector('a.link_preview');
                                const imgElement = item.querySelector('.img_prev img');
                                const titleElement = item.querySelector('.inf');
                                const priceElement = item.querySelector('.price');
                                const oldPriceElement = item.querySelector('.old_price');
                                const discountPercentElement = item.querySelector('.gmlst_dscnt_lbl');
                                const discountAmountElement = item.querySelector('.gmlst_dsnt_val_text');

                                const productUrlRaw = linkElement ? linkElement.getAttribute('href') : null;
                                const imageUrlRaw = imgElement ? imgElement.getAttribute('src') : null;
                                let productName = null;
                                if (titleElement) {
                                    const clonedTitle = titleElement.cloneNode(true);
                                    const economySpan = clonedTitle.querySelector('.gmlst_dsnt_val_text');
                                    if (economySpan) economySpan.remove();
                                    productName = clonedTitle.textContent.replace(/\s+/g, ' ').trim();
                                }

                                const currentPrice = priceElement ? sm_parsePrice(priceElement.textContent) : null;
                                const originalPrice = oldPriceElement ? sm_parsePrice(oldPriceElement.textContent) : null;
                                const discountPercent = discountPercentElement ? sm_parsePercent(discountPercentElement.textContent) : null;
                                const discountAmount = discountAmountElement ? sm_parsePrice(discountAmountElement.textContent) : null;

                                if (productName && productUrlRaw && currentPrice !== null) {
                                    const fullProductUrl = productUrlRaw.startsWith('/') ? storeModule.baseUrl + productUrlRaw : productUrlRaw;
                                    const productUrl = fullProductUrl + '?s=n3j6y08f';
                                    const imageUrl = imageUrlRaw.startsWith('/') ? storeModule.baseUrl + imageUrlRaw : imageUrlRaw;

                                    let data = {
                                        storeId: storeModule.id,
                                        storeName: storeModule.name,
                                        storeUrl: storeModule.baseUrl,
                                        productName: productName,
                                        productUrl: productUrl,
                                        imageUrl: imageUrl,
                                        currentPrice: currentPrice,
                                        originalPrice: originalPrice,
                                        discountPercent: discountPercent,
                                        discountAmount: discountAmount,
                                        currency: 'RUB',
                                        isAvailable: true
                                    };
                                    results.push(sm_calculateMissingValues(data));
                                }
                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента', e);
                            }
                        });
                        return results;
                    }
                },

                { // --- Модуль SteamPay ---
                    id: 'steampay',
                    name: 'SteamPay',
                    baseUrl: 'https://steampay.com',
                    searchUrlTemplate: 'https://steampay.com/search?q={query}',
                    isEnabled: true,
                    fetch: async function(query) {
                        const searchUrl = this.searchUrlTemplate.replace('{query}', encodeURIComponent(query));
                        return new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: searchUrl,
                                timeout: SM_REQUEST_TIMEOUT_MS,
                                onload: (response) => {
                                    if (response.status >= 200 && response.status < 400) {
                                        resolve(this.parseHtml(response.responseText, this));
                                    } else {
                                        reject(new Error(`HTTP статус ${response.status}`));
                                    }
                                },
                                onerror: (error) => reject(new Error('Сетевая ошибка')),
                                ontimeout: () => reject(new Error('Таймаут запроса'))
                            });
                        });
                    },
                    parseHtml: async function(htmlString, storeModule) {
                        const results = [];
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');
                        const items = doc.querySelectorAll('.catalog-item');

                        await sm_fetchExchangeRates('usd').catch(e => sm_logError(storeModule.name, "Не удалось загрузить курсы USD", e));

                        for (const item of items) {
                            try {
                                const priceSpanElement = item.querySelector('.catalog-item__price-span');
                                const currentPriceText = priceSpanElement?.textContent?.trim();
                                const currentPrice = sm_parsePrice(currentPriceText);
                                if (currentPrice === null) continue;

                                const nameElement = item.querySelector('.catalog-item__name');
                                let productName = null;
                                if (nameElement) {
                                    const nameClone = nameElement.cloneNode(true);
                                    nameClone.querySelector('.catalog-item__info')?.remove();
                                    productName = nameClone.textContent?.trim();
                                }

                                const productUrl = item?.getAttribute('href');
                                const imageUrl = item.querySelector('.catalog-item__img img')?.getAttribute('src');
                                const discountPercent = sm_parsePercent(item.querySelector('.catalog-item__discount')?.textContent);

                                if (productName && productUrl) {
                                    let data = {
                                        storeId: storeModule.id,
                                        storeName: storeModule.name,
                                        storeUrl: storeModule.baseUrl,
                                        productName: productName,
                                        productUrl: productUrl.startsWith('/') ? storeModule.baseUrl + productUrl : productUrl,
                                        imageUrl: imageUrl?.startsWith('/') ? storeModule.baseUrl + imageUrl : imageUrl,
                                        currentPrice: currentPrice,
                                        originalPrice: null,
                                        discountPercent: discountPercent,
                                        discountAmount: null,
                                        currency: 'RUB',
                                        isAvailable: true
                                    };

                                    const processedData = await sm_processItemCurrency(data, currentPriceText);
                                    if (processedData) {
                                       results.push(sm_calculateMissingValues(processedData));
                                    }
                                }
                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента', e);
                            }
                        }
                        return results;
                    }
                }, // --- Конец модуля SteamPay ---

                { // --- Модуль Gabestore ---
                    id: 'gabestore',
                    name: 'Gabestore',
                    baseUrl: 'https://gabestore.ru',
                    searchUrlTemplate: 'https://gabestore.ru/result?ProductFilter%5Bsearch%5D={query}',
                    isEnabled: true,
                    fetch: async function(query) {
                        const searchUrl = this.searchUrlTemplate.replace('{query}', encodeURIComponent(query));
                        return new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: searchUrl,
                                timeout: SM_REQUEST_TIMEOUT_MS,
                                onload: (response) => {
                                    if (response.status >= 200 && response.status < 400) {
                                        resolve(this.parseHtml(response.responseText, this));
                                    } else {
                                        reject(new Error(`HTTP статус ${response.status}`));
                                    }
                                },
                                onerror: (error) => reject(new Error('Сетевая ошибка')),
                                ontimeout: () => reject(new Error('Таймаут запроса'))
                            });
                        });
                    },
                    parseHtml: function(htmlString, storeModule) {
                        const results = [];
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');
                        const itemsContainer = doc.querySelector('.js-load-container');
                        const items = itemsContainer ? itemsContainer.querySelectorAll('.shop-item') : [];

                        items.forEach(item => {
                            try {
                                const nameLinkElement = item.querySelector('a.shop-item__name');
                                const imageLinkElement = item.querySelector('a.shop-item__image');
                                const imgElement = imageLinkElement?.querySelector('img');
                                const priceElement = item.querySelector('.shop-item__price-current');
                                const discountElement = item.querySelector('.shop-item__price-discount');

                                const productName = nameLinkElement?.textContent?.trim();
                                const productUrlRaw = nameLinkElement?.getAttribute('href') || imageLinkElement?.getAttribute('href');
                                const imageUrl = imgElement?.getAttribute('src');
                                const currentPrice = priceElement ? sm_parsePrice(priceElement.textContent) : null;
                                const discountPercent = discountElement ? sm_parsePercent(discountElement.textContent) : 0;

                                if (!productName || !productUrlRaw || currentPrice === null) {
                                    return;
                                }

                                const fullOriginalUrl = productUrlRaw.startsWith('/') ? storeModule.baseUrl + productUrlRaw : productUrlRaw;
                                const referralPrefix = 'https://codeaven.com/g/om6s6jfc50c1442ace4b215ab801b9/?erid=2bL9aMPo2e49hMef4peVT3sy3u&ulp=';
                                const productUrl = referralPrefix + encodeURIComponent(fullOriginalUrl);

                                let data = {
                                    storeId: storeModule.id,
                                    storeName: storeModule.name,
                                    storeUrl: storeModule.baseUrl,
                                    productName: productName,
                                    productUrl: productUrl,
                                    imageUrl: imageUrl,
                                    currentPrice: currentPrice,
                                    originalPrice: null,
                                    discountPercent: discountPercent,
                                    discountAmount: null,
                                    currency: 'RUB',
                                    isAvailable: !item.querySelector('.btn--empty-item')
                                };

                                if (data.isAvailable) {
                                    results.push(sm_calculateMissingValues(data));
                                }

                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента', e);
                            }
                        });
                        return results;
                    }
                }, // --- Конец модуля Gabestore ---

                { // --- Модуль GamerBase ---
                    id: 'gamerbase',
                    name: 'GamersBase',
                    baseUrl: 'https://gamersbase.store',
                    searchUrlTemplate: 'https://gamersbase.store/ru/search/?isFullTextSearch=true&searchQuery={query}',
                    isEnabled: true,
                    fetch: async function(query) {
                        const storeModule = this;
                        const searchUrl = storeModule.searchUrlTemplate.replace('{query}', encodeURIComponent(query));
                        return new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: searchUrl,
                                timeout: SM_REQUEST_TIMEOUT_MS,
                                onload: (response) => {
                                    if (response.status >= 200 && response.status < 400) {
                                        resolve(storeModule.parseHtml(response.responseText, storeModule));
                                    } else {
                                        reject(new Error(`[Fallback] HTTP статус ${response.status}`));
                                    }
                                },
                                onerror: (error) => reject(new Error('[Fallback] Сетевая ошибка')),
                                ontimeout: () => reject(new Error('[Fallback] Таймаут запроса'))
                            });
                        });
                    },
                    parseHtml: async function(htmlString, storeModule) {
                        const results = [];
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');
                        const items = doc.querySelectorAll('.js-products-container .ui.cover');

                        await sm_fetchExchangeRates('usd').catch(e => sm_logError(storeModule.name, "Не удалось загрузить курсы USD", e));
                        await sm_fetchExchangeRates('kzt').catch(e => sm_logError(storeModule.name, "Не удалось загрузить курсы KZT", e));


                        for (const item of items) {
                            try {
                                const linkElement = item.querySelector('a.cover-holder');
                                const buyButton = item.querySelector('.js-add-product');
                                const productDataJson = linkElement?.dataset.product || buyButton?.dataset.product;
                                if (!productDataJson) continue;

                                const productData = JSON.parse(productDataJson);
                                if (!productData?.name || !productData?.priceData) continue;

                                const productName = productData.name;
                                const productUrlRaw = linkElement?.getAttribute('href');
                                const imageUrl = item.querySelector('.image img')?.getAttribute('src');
                                const currentPrice = sm_parsePrice(productData.priceData.actualPriceFormatted);
                                const originalPrice = sm_parsePrice(productData.priceData.standardPriceFormatted);
                                const discountPercent = productData.priceData.discountPercent || 0;
                                const currency = productData.priceData.currency || 'RUB';
                                const isAvailable = item.querySelector('.js-add-product.available-true') !== null;

                                if (productName && productUrlRaw && currentPrice !== null && isAvailable) {
                                    let fullOriginalUrl = productUrlRaw.startsWith('/') ? storeModule.baseUrl + productUrlRaw : productUrlRaw;
                                    const urlObject = new URL(fullOriginalUrl);
                                    if (urlObject.pathname.startsWith('/ru/')) {
                                        urlObject.pathname = urlObject.pathname.substring(3);
                                        fullOriginalUrl = urlObject.toString();
                                    }
                                    const referralPrefix = 'https://lsuix.com/g/nzstwno2sac1442ace4bb0de1ddd64/?erid=2bL9aMPo2e49hMef4pfVDVxtYh&ulp=';
                                    const productUrl = referralPrefix + encodeURIComponent(fullOriginalUrl);

                                    let data = {
                                        storeId: storeModule.id, storeName: storeModule.name, storeUrl: storeModule.baseUrl,
                                        productName: productName, productUrl: productUrl, imageUrl: imageUrl,
                                        currentPrice: currentPrice, originalPrice: originalPrice, discountPercent: discountPercent,
                                        discountAmount: null, currency: currency, // Передаем оригинальную валюту
                                        isAvailable: true
                                    };

                                    const processedData = await sm_processItemCurrency(data, productData.priceData.actualPriceFormatted);
                                    if(processedData) {
                                        results.push(sm_calculateMissingValues(processedData));
                                    }
                                }
                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента или JSON в data-product', e);
                            }
                        }
                        return results;
                    }
                }, // --- Конец модуля GamerBase ---

                { // --- Модуль Igromagaz ---
                    id: 'igromagaz',
                    name: 'Igromagaz',
                    baseUrl: 'https://www.igromagaz.ru',
                    searchUrlTemplate: 'https://www.igromagaz.ru/search/?q={query}&quantity_in=Y',
                    isEnabled: true,
                    fetch: async function(query) {
                        const searchUrl = this.searchUrlTemplate.replace('{query}', encodeURIComponent(query));
                        return new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: searchUrl,
                                timeout: SM_REQUEST_TIMEOUT_MS,
                                onload: (response) => {
                                    if (response.status >= 200 && response.status < 400) {
                                        resolve(this.parseHtml(response.responseText, this));
                                    } else {
                                        reject(new Error(`HTTP статус ${response.status}`));
                                    }
                                },
                                onerror: (error) => reject(new Error('Сетевая ошибка')),
                                ontimeout: () => reject(new Error('Таймаут запроса'))
                            });
                        });
                    },
                    parseHtml: function(htmlString, storeModule) {
                        const results = [];
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');
                        const items = doc.querySelectorAll('.product-card');

                        items.forEach(item => {
                            try {
                                const notAvailableElement = item.querySelector('.product-availability--not-available');
                                const notifyButton = item.querySelector('.button-notify-js');
                                if (notAvailableElement || notifyButton) {
                                    return;
                                }

                                const titleLinkElement = item.querySelector('a.product-title');
                                const imageLinkElement = item.querySelector('a.product-img');
                                const imgElement = imageLinkElement?.querySelector('img');
                                const priceElement = item.querySelector('.product-price__standart');
                                const oldPriceElement = item.querySelector('.product-price__fail');
                                const discountElement = item.querySelector('.sale-label');

                                const productName = titleLinkElement?.textContent?.trim();
                                const productUrl = titleLinkElement?.getAttribute('href') || imageLinkElement?.getAttribute('href');
                                const imageUrl = imgElement?.getAttribute('src');
                                const currentPrice = priceElement ? sm_parsePrice(priceElement.textContent) : null;
                                const originalPrice = oldPriceElement ? sm_parsePrice(oldPriceElement.textContent) : null;
                                const discountPercent = discountElement ? sm_parsePercent(discountElement.textContent) : null;

                                if (!productName || !productUrl || currentPrice === null) {
                                    return;
                                }

                                let data = {
                                    storeId: storeModule.id,
                                    storeName: storeModule.name,
                                    storeUrl: storeModule.baseUrl,
                                    productName: productName,
                                    productUrl: productUrl.startsWith('/') ? storeModule.baseUrl + productUrl : productUrl,
                                    imageUrl: imageUrl?.startsWith('/') ? storeModule.baseUrl + imageUrl : imageUrl,
                                    currentPrice: currentPrice,
                                    originalPrice: originalPrice,
                                    discountPercent: discountPercent,
                                    discountAmount: null,
                                    currency: 'RUB',
                                    isAvailable: true
                                };
                                results.push(sm_calculateMissingValues(data));
                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента', e);
                            }
                        });
                        return results;
                    }
                }, // --- Конец модуля Igromagaz ---

                { // --- Модуль GamesForFarm ---
                    id: 'gamesforfarm',
                    name: 'GamesForFarm',
                    baseUrl: 'https://gamesforfarm.com',
                    searchUrlTemplate: 'https://gamesforfarm.com/?search={query}',
                    isEnabled: true,
                    fetch: async function(query) {
                        const searchUrl = this.searchUrlTemplate.replace('{query}', encodeURIComponent(query));
                        return new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: searchUrl,
                                timeout: SM_REQUEST_TIMEOUT_MS,
                                onload: (response) => {
                                    if (response.status >= 200 && response.status < 400) {
                                        resolve(this.parseHtml(response.responseText, this));
                                    } else {
                                        reject(new Error(`HTTP статус ${response.status}`));
                                    }
                                },
                                onerror: (error) => reject(new Error('Сетевая ошибка')),
                                ontimeout: () => reject(new Error('Таймаут запроса'))
                            });
                        });
                    },
                    parseHtml: function(htmlString, storeModule) {
                        const results = [];
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');
                        const container = doc.querySelector('#gamesCatalog');
                        if (!container) return results;

                        const items = container.querySelectorAll('.product__item');

                        items.forEach(item => {
                            try {
                                const linkElement = item.querySelector('.product__box-title a');
                                const imgElement = item.querySelector('.product__box-image img');
                                const priceElement = item.querySelector('.product__box-price');
                                const discountElement = item.querySelector('.product__box-prop.prop--discount');

                                let currentPrice = null;
                                if (priceElement) {
                                    const priceClone = priceElement.cloneNode(true);
                                    const currencySpan = priceClone.querySelector('span.sc-ru3bl');
                                    if (currencySpan) currencySpan.remove();
                                    currentPrice = sm_parsePrice(priceClone.textContent);
                                }

                                const productName = linkElement?.textContent?.trim();
                                const productUrl = linkElement?.getAttribute('href');
                                const imageUrl = imgElement?.dataset.src || imgElement?.getAttribute('src');
                                const discountPercent = discountElement ? sm_parsePercent(discountElement.textContent) : 0;

                                if (!productName || !productUrl || currentPrice === null) {
                                    return;
                                }

                                let data = {
                                    storeId: storeModule.id,
                                    storeName: storeModule.name,
                                    storeUrl: storeModule.baseUrl,
                                    productName: productName,
                                    productUrl: productUrl.startsWith('/') ? storeModule.baseUrl + productUrl : productUrl,
                                    imageUrl: imageUrl,
                                    currentPrice: currentPrice,
                                    originalPrice: null,
                                    discountPercent: discountPercent,
                                    discountAmount: null,
                                    currency: 'RUB',
                                    isAvailable: true
                                };
                                results.push(sm_calculateMissingValues(data));
                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента', e);
                            }
                        });
                        return results;
                    }
                }, // --- Конец модуля GamesForFarm ---

                { // --- Модуль Gamazavr ---
                    id: 'gamazavr',
                    name: 'Gamazavr',
                    baseUrl: 'https://gamazavr.ru',
                    searchUrlTemplate: 'https://gamazavr.ru/search/?query={query}',
                    isEnabled: true,
                    fetch: async function(query) {
                        const searchUrl = this.searchUrlTemplate.replace('{query}', encodeURIComponent(query));
                        return new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: searchUrl,
                                timeout: SM_REQUEST_TIMEOUT_MS,
                                onload: (response) => {
                                    if (response.status >= 200 && response.status < 400) {
                                        resolve(this.parseHtml(response.responseText, this));
                                    } else {
                                        reject(new Error(`HTTP статус ${response.status}`));
                                    }
                                },
                                onerror: (error) => reject(new Error('Сетевая ошибка')),
                                ontimeout: () => reject(new Error('Таймаут запроса'))
                            });
                        });
                    },
                    parseHtml: function(htmlString, storeModule) {
                        const results = [];
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');
                        const container = doc.querySelector('.productsList');
                        if (!container) {
                            return results;
                        }

                        const items = container.querySelectorAll('.item');

                        items.forEach(item => {
                            try {
                                const descriptionLink = item.querySelector('.description a');
                                const imageLink = item.querySelector('a.img');
                                const imgElement = imageLink?.querySelector('img');
                                const priceElement = item.querySelector('.price');
                                const currentPriceElement = priceElement?.querySelector('b');
                                const originalPriceElement = priceElement?.querySelector('s');

                                const productName = descriptionLink?.querySelector('b')?.textContent?.trim();
                                const productUrlRaw = descriptionLink?.getAttribute('href');
                                const imageUrlRaw = imgElement?.getAttribute('src');

                                const currentPrice = currentPriceElement ? sm_parsePrice(currentPriceElement.textContent) : null;
                                const originalPrice = originalPriceElement ? sm_parsePrice(originalPriceElement.textContent) : null;

                                if (!productName || !productUrlRaw || currentPrice === null) {
                                    return;
                                }

                                const fullProductUrl = productUrlRaw.startsWith('/') ? storeModule.baseUrl + productUrlRaw : productUrlRaw;
                                const productUrl = fullProductUrl + '?partner=8293ebf587779da6';
                                const imageUrl = imageUrlRaw?.startsWith('/') ? storeModule.baseUrl + imageUrlRaw : imageUrlRaw;

                                let data = {
                                    storeId: storeModule.id,
                                    storeName: storeModule.name,
                                    storeUrl: storeModule.baseUrl,
                                    productName: productName,
                                    productUrl: productUrl,
                                    imageUrl: imageUrl,
                                    currentPrice: currentPrice,
                                    originalPrice: originalPrice,
                                    discountPercent: null,
                                    discountAmount: null,
                                    currency: 'RUB',
                                    isAvailable: true
                                };
                                results.push(sm_calculateMissingValues(data));

                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента Gamazavr', e);
                            }
                        });
                        return results;
                    }
                }, // --- Конец модуля Gamazavr ---

                { // --- Модуль GameRay ---
                    id: 'gameray',
                    name: 'GameRay',
                    baseUrl: 'https://gameray.ru',
                    searchUrlTemplate: 'https://gameray.ru/search/index.php?q={query}',
                    isEnabled: true,
                    fetch: async function(query) {
                        const searchUrl = this.searchUrlTemplate.replace('{query}', encodeURIComponent(query));
                        let initialResults = [];

                        // --- Шаг 1: Получаем список игр со страницы поиска ---
                        try {
                            const response = await new Promise((resolve, reject) => {
                                GM_xmlhttpRequest({
                                    method: "GET",
                                    url: searchUrl,
                                    timeout: SM_REQUEST_TIMEOUT_MS,
                                    onload: resolve,
                                    onerror: reject,
                                    ontimeout: () => reject(new Error('Таймаут запроса (поиск)')),
                                });
                            });

                            if (response.status >= 200 && response.status < 400) {
                                initialResults = this.parseSearchPage(response.responseText, this);
                            } else {
                                throw new Error(`HTTP статус ${response.status} (поиск)`);
                            }
                        } catch (error) {
                            sm_logError(this.name, `Ошибка на шаге 1 (поиск): ${error.message}`, error);
                            return [];
                        }

                        if (initialResults.length === 0) {
                            return [];
                        }

                        // --- Шаг 2: Запрашиваем каждую страницу товара для деталей ---
                        const detailPromises = initialResults.map(initialData =>
                            new Promise(async (resolve) => {
                                try {
                                    const productResponse = await new Promise((resolveFetch, rejectFetch) => {
                                        GM_xmlhttpRequest({
                                            method: "GET",
                                            url: initialData.fullProductUrl,
                                            timeout: SM_REQUEST_TIMEOUT_MS,
                                            onload: resolveFetch,
                                            onerror: rejectFetch,
                                            ontimeout: () => rejectFetch(new Error(`Таймаут запроса (${initialData.productName})`)),
                                        });
                                    });

                                    if (productResponse.status >= 200 && productResponse.status < 400) {
                                        resolve(this.parseProductPage(productResponse.responseText, initialData, this));
                                    } else {
                                        sm_logError(this.name, `Ошибка загрузки страницы товара ${initialData.productName} (Статус: ${productResponse.status})`);
                                        resolve(null);
                                    }
                                } catch (error) {
                                    sm_logError(this.name, `Ошибка загрузки страницы товара ${initialData.productName}: ${error.message}`, error);
                                    resolve(null);
                                }
                            })
                        );

                        const detailedResults = await Promise.allSettled(detailPromises);

                        const finalResults = detailedResults
                            .filter(result => result.status === 'fulfilled' && result.value !== null)
                            .map(result => result.value);

                        return finalResults;
                    },

                    parseSearchPage: function(htmlString, storeModule) {
                        const results = [];
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');
                        const container = doc.querySelector('.search-page') || doc.body;
                        const items = container.querySelectorAll('a.ec-clicker');

                        items.forEach(item => {
                            try {
                                const productName = item.dataset.name?.trim();
                                const productUrlRaw = item.getAttribute('href');
                                const imgElement = item.querySelector('img');
                                const imageUrlRaw = imgElement?.getAttribute('src');

                                if (productName && productUrlRaw && imageUrlRaw) {
                                    const fullProductUrl = productUrlRaw.startsWith('/') ? storeModule.baseUrl + productUrlRaw : productUrlRaw;
                                    const imageUrl = imageUrlRaw.startsWith('/') ? storeModule.baseUrl + imageUrlRaw : imageUrlRaw;

                                    results.push({
                                        productName: productName,
                                        fullProductUrl: fullProductUrl,
                                        imageUrl: imageUrl
                                    });
                                }
                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента на странице поиска', e);
                            }
                        });
                        return results;
                    },

                    parseProductPage: function(htmlString, initialData, storeModule) {
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');

                        const pricingBlock = doc.querySelector('div.pricing');
                        if (!pricingBlock) {
                            sm_logError(storeModule.name, `Блок .pricing не найден для: ${initialData.productName}`);
                            return null;
                        }

                        const buyButton = pricingBlock.querySelector('a.buy-button');
                        const isAvailable = buyButton !== null;

                        if (!isAvailable) {
                            return null;
                        }

                        const priceElement = pricingBlock.querySelector('strong.price span[itemprop="price"]');
                        const originalPriceElement = pricingBlock.querySelector('strike.price_old');

                        const currentPrice = priceElement ? sm_parsePrice(priceElement.textContent) : null;
                        const originalPrice = originalPriceElement ? sm_parsePrice(originalPriceElement.textContent) : null;

                        if (currentPrice === null) {
                            sm_logError(storeModule.name, `Не найдена цена в блоке .pricing для: ${initialData.productName}`);
                            return null;
                        }

                        const productUrlWithRef = initialData.fullProductUrl + '?partner=93';

                        let finalData = {
                            storeId: storeModule.id,
                            storeName: storeModule.name,
                            storeUrl: storeModule.baseUrl,
                            productName: initialData.productName,
                            productUrl: productUrlWithRef,
                            imageUrl: initialData.imageUrl,
                            currentPrice: currentPrice,
                            originalPrice: originalPrice,
                            discountPercent: null,
                            discountAmount: null,
                            currency: 'RUB',
                            isAvailable: isAvailable
                        };

                        return sm_calculateMissingValues(finalData);
                    }
                }, // --- Конец модуля GameRay ---

                { // --- Модуль Kupikod ---
                        id: 'kupikod',
                        name: 'KupiKod',
                        baseUrl: 'https://kupikod.com',
                        apiGamesUrlTemplate: 'https://explorer.kupikod.com/backend/api/games?name={query}',
                        apiShopUrlTemplate: 'https://explorer.kupikod.com/backend/api/shop/products-list?name={query}',
                        isEnabled: true,
                        // Список суффиксов регионов для исключения (в нижнем регистре)
                        excludedRegionSuffixes: [
                            '-eu', '-us', '-arg', '-tr', '-no-ru-no-rb', '-no-ru-no-cis',
                            '-no-ru', '-euus', '-cis', '-uk', '-in', '-eg'
                        ],
                        // Список ключевых слов платформ для исключения (в нижнем регистре)
                        excludedPlatformKeywords: [
                            '-xbox-', '-origin-', '-uplay-', '-gog-', '-rockstar-',
                            '-battlestate-', '-nintendo-'
                        ],
                        fetch: async function(query) {
                            const storeModule = this;
                            const encodedQuery = encodeURIComponent(query);
                            const gamesUrl = storeModule.apiGamesUrlTemplate.replace('{query}', encodedQuery);
                            const shopUrl = storeModule.apiShopUrlTemplate.replace('{query}', encodedQuery);

                            const fetchPromise = (url) => new Promise((resolve, reject) => {
                                GM_xmlhttpRequest({
                                    method: "GET",
                                    url: url,
                                    responseType: 'json',
                                    timeout: SM_REQUEST_TIMEOUT_MS,
                                    onload: (response) => {
                                        if (response.status >= 200 && response.status < 400 && response.response) {
                                            resolve(response.response);
                                        } else {
                                            sm_logError(storeModule.name, `HTTP статус ${response.status} для ${url}`);
                                            resolve(null);
                                        }
                                    },
                                    onerror: (error) => {
                                         sm_logError(storeModule.name, `Сетевая ошибка для ${url}`, error);
                                         resolve(null);
                                    },
                                    ontimeout: () => {
                                         sm_logError(storeModule.name, `Таймаут запроса для ${url}`);
                                         resolve(null);
                                    }
                                });
                            });

                            const [gamesResult, shopResult] = await Promise.allSettled([
                                fetchPromise(gamesUrl),
                                fetchPromise(shopUrl)
                            ]);

                            let finalResults = [];

                            if (gamesResult.status === 'fulfilled' && gamesResult.value?.data) {
                                try {
                                    finalResults = finalResults.concat(storeModule.parseGamesApi(gamesResult.value.data, storeModule));
                                } catch(e) {
                                     sm_logError(storeModule.name, 'Ошибка парсинга ответа Games API', e);
                                }
                            } else if (gamesResult.status === 'rejected') {
                            }

                            if (shopResult.status === 'fulfilled' && shopResult.value?.data) {
                                 try {
                                    finalResults = finalResults.concat(storeModule.parseShopApi(shopResult.value.data, storeModule));
                                 } catch(e) {
                                     sm_logError(storeModule.name, 'Ошибка парсинга ответа Shop API', e);
                                 }
                            } else if (shopResult.status === 'rejected') {
                            }

                            return finalResults;
                        },

                        // Парсер для ответа от /api/games (Steam-гифты)
                        parseGamesApi: function(items, storeModule) {
                            const results = [];
                            if (!Array.isArray(items)) {
                                 sm_logError(storeModule.name, 'Games API response data is not an array', items);
                                 return results;
                            }

                            const referralBase = "https://yknhc.com/g/lfofiog4lqc1442ace4b294cb5928a/";
                            const referralParams = "?erid=2bL9aMPo2e49hMef4phUQVF5W8&ulp=";

                            items.forEach(item => {
                                try {
                                    const productName = item.name?.trim();
                                    const slug = item.slug;
                                    const currentPrice = sm_parsePrice(item.min_price?.rub ?? null);
                                    const originalPriceRaw = sm_parsePrice(item.min_old_price?.rub ?? null);
                                    const originalPrice = (originalPriceRaw !== null && currentPrice !== null && originalPriceRaw > currentPrice) ? originalPriceRaw : null;
                                    const imageUrl = item.external_data?.header_image;

                                    if (!productName || !slug || currentPrice === null || !imageUrl) {
                                        return;
                                    }

                                    const originalProductUrl = `https://steam.kupikod.com/ru-ru/games/${slug}`;
                                    const productUrl = referralBase + referralParams + encodeURIComponent(originalProductUrl);

                                    let data = {
                                        storeId: storeModule.id,
                                        storeName: storeModule.name + " (Гифты)",
                                        storeUrl: "https://steam.kupikod.com/",
                                        productName: productName,
                                        productUrl: productUrl,
                                        imageUrl: imageUrl,
                                        currentPrice: currentPrice,
                                        originalPrice: originalPrice,
                                        discountPercent: null,
                                        discountAmount: null,
                                        currency: 'RUB',
                                        isAvailable: true
                                    };
                                    results.push(sm_calculateMissingValues(data));
                                } catch (e) {
                                    sm_logError(storeModule.name, 'Ошибка парсинга элемента Games API', e);
                                }
                            });
                            return results;
                        },

                        // Парсер для ответа от /api/shop/products-list (Ключи)
                        parseShopApi: function(items, storeModule) {
                            const results = [];
                            if (!Array.isArray(items)) {
                                sm_logError(storeModule.name, 'Shop API response data is not an array', items);
                                return results;
                            }

                            const referralBase = "https://yknhc.com/g/lfofiog4lqc1442ace4b294cb5928a/";
                            const referralParams = "?erid=2bL9aMPo2e49hMef4phUQVF5W8&ulp=";

                            items.forEach(item => {
                                try {
                                    const productName = item.h1_title?.trim();
                                    const slug = item.slug?.toLowerCase();
                                    const currentPrice = sm_parsePrice(item.price ?? null);
                                    const originalPriceRaw = sm_parsePrice(item.old_price ?? null);
                                    const originalPrice = (originalPriceRaw !== null && originalPriceRaw > 0 && currentPrice !== null && originalPriceRaw > currentPrice) ? originalPriceRaw : null;
                                    const imageUrl = item.picture_url;

                                    if (!imageUrl || typeof imageUrl !== 'string' || imageUrl.includes('/apps//')) {
                                         return;
                                    }

                                    if (!productName || !slug || currentPrice === null) {
                                        return;
                                    }

                                    if (storeModule.excludedRegionSuffixes.some(suffix => slug.endsWith(suffix))) {
                                         return;
                                    }
                                     if (storeModule.excludedPlatformKeywords.some(keyword => slug.includes(keyword))) {
                                         return;
                                    }

                                    const originalProductUrl = `${storeModule.baseUrl}/shop/${item.slug}`;
                                    const productUrl = referralBase + referralParams + encodeURIComponent(originalProductUrl);

                                    let data = {
                                        storeId: storeModule.id,
                                        storeName: storeModule.name + " (Ключи)",
                                        storeUrl: storeModule.baseUrl,
                                        productName: productName,
                                        productUrl: productUrl,
                                        imageUrl: imageUrl,
                                        currentPrice: currentPrice,
                                        originalPrice: originalPrice,
                                        discountPercent: null,
                                        discountAmount: null,
                                        currency: 'RUB',
                                        isAvailable: true
                                    };
                                    results.push(sm_calculateMissingValues(data));
                                } catch (e) {
                                    sm_logError(storeModule.name, 'Ошибка парсинга элемента Shop API', e);
                                }
                            });
                            return results;
                        }
                    }, // --- Конец модуля Kupikod ---

                { // --- Модуль KeysForGamers ---
                    id: 'keysforgamers',
                    name: 'KeysForGamers',
                    baseUrl: 'https://keysforgamers.com',
                    apiUrl: 'https://keysforgamers.com/ru/product/search',
                    isEnabled: true,
                    fetch: async function(query) {
                        const storeModule = this;
                        let searchQuery = query;

                        const containsCyrillic = /[а-яё]/i.test(query);
                        if (containsCyrillic) {
                            sm_logError(storeModule.name, `Обнаружена кириллица в запросе "${query}". Пытаемся получить английское название...`);
                            const steamAppIdMatch = unsafeWindow.location.pathname.match(/\/app\/(\d+)/);

                            if (steamAppIdMatch && steamAppIdMatch[1]) {
                                const currentAppId = steamAppIdMatch[1];
                                const apiUrl = `https://store.steampowered.com/api/appdetails?appids=${currentAppId}&l=english`;

                                try {
                                    const response = await new Promise((resolve, reject) => {
                                        GM_xmlhttpRequest({
                                            method: "GET",
                                            url: apiUrl,
                                            responseType: 'json',
                                            timeout: SM_REQUEST_TIMEOUT_MS,
                                            onload: resolve,
                                            onerror: reject,
                                            ontimeout: () => reject(new Error('Таймаут запроса к Steam API (AppDetails)')),
                                        });
                                    });

                                    if (response.status === 200 && response.response && response.response[currentAppId]?.success) {
                                        const englishName = response.response[currentAppId]?.data?.name;
                                        if (englishName && englishName.trim()) {
                                            searchQuery = englishName.trim();
                                            sm_logError(storeModule.name, `Используем английское название для поиска: "${searchQuery}"`);
                                        } else {
                                            sm_logError(storeModule.name, `Steam API вернул успех, но английское имя не найдено для AppID ${currentAppId}. Используем оригинальный запрос.`);
                                        }
                                    } else {
                                        sm_logError(storeModule.name, `Запрос к Steam API не удался или неверный ответ для AppID ${currentAppId} (Status: ${response.status}). Используем оригинальный запрос.`);
                                    }
                                } catch (error) {
                                    sm_logError(storeModule.name, `Ошибка при получении английского названия из Steam API: ${error.message}. Используем оригинальный запрос.`, error);
                                }
                            } else {
                                sm_logError(storeModule.name, 'Не удалось получить Steam AppID со страницы для запроса английского названия. Используем оригинальный запрос.');
                            }
                        }


                        let csrfToken = '';

                        try {
                            const mainPageResponse = await new Promise((resolve, reject) => {
                                GM_xmlhttpRequest({
                                    method: "GET",
                                    url: storeModule.baseUrl + '/ru/',
                                    timeout: SM_REQUEST_TIMEOUT_MS,
                                    onload: resolve,
                                    onerror: reject,
                                    ontimeout: () => reject(new Error('Таймаут запроса (CSRF)')),
                                });
                            });
                            if (mainPageResponse.status >= 200 && mainPageResponse.status < 400) {
                                const parser = new DOMParser();
                                const doc = parser.parseFromString(mainPageResponse.responseText, 'text/html');
                                const csrfMetaTag = doc.querySelector('meta[name="csrf-token"]');
                                if (!csrfMetaTag) throw new Error('Мета-тег csrf-token не найден!');
                                csrfToken = csrfMetaTag.getAttribute('content');
                                if (!csrfToken) throw new Error('Не удалось получить значение csrf-token!');
                            } else {
                                throw new Error(`HTTP статус ${mainPageResponse.status} при получении CSRF`);
                            }

                        } catch (error) {
                            sm_logError(storeModule.name, `Ошибка получения CSRF токена: ${error.message}`, error);
                            throw error;
                        }

                        let allItems = [];
                        let currentPage = 1;
                        let totalPages = 1;

                        do {
                            const requestPayload = {
                                productTypes: [{ value: "6", id: "category-6" }],
                                regionData: [
                                    { value: "1", id: "region-1" },
                                    { value: "85", id: "region-85" },
                                    { value: "6", id: "region-6" }
                                ],
                                searchData: [{ value: searchQuery, id: "product-search" }],
                                sortData: [{ value: "4", id: "search_sort" }],
                                priceRange: [{ value: ["0.00", "99999.00"], id: ["min_price", "max_price"] }],
                                page: currentPage,
                                perPage: 24,
                                switchData: [],
                                marketplaceData: [],
                                otherTypesData: [],
                                hashData: [],
                                showMorePages: 0,
                                isMinPriceChanged: false,
                                isMaxPriceChanged: true,
                                minPriceValue: 0,
                                maxPriceValue: 99999.00
                            };
                            const requestHeaders = {
                                'Accept': 'application/json, text/plain, */*',
                                'Content-Type': 'application/json',
                                'X-Csrf-Token': csrfToken,
                                'X-Requested-With': 'XMLHttpRequest'
                            };

                            try {
                                const response = await new Promise((resolve, reject) => {
                                    GM_xmlhttpRequest({
                                        method: "POST",
                                        url: storeModule.apiUrl,
                                        headers: requestHeaders,
                                        data: JSON.stringify(requestPayload),
                                        responseType: 'json',
                                        timeout: SM_REQUEST_TIMEOUT_MS,
                                        onload: resolve,
                                        onerror: reject,
                                        ontimeout: () => reject(new Error(`Таймаут запроса (page: ${currentPage})`)),
                                    });
                                });

                                if (response.status >= 200 && response.status < 400 && response.response) {
                                    const data = response.response;
                                    if (data.catalogBody && typeof data.catalogBody === 'string') {
                                        const pageItems = storeModule.parseKFGHtml(data.catalogBody, storeModule);
                                        allItems = allItems.concat(pageItems);
                                    }
                                    totalPages = data.pages ?? totalPages;
                                    if (data.pages === undefined && currentPage === 1) totalPages = 1;
                                } else {
                                    throw new Error(`HTTP статус ${response.status} (page: ${currentPage})`);
                                }

                            } catch (error) {
                                sm_logError(storeModule.name, `Ошибка загрузки страницы ${currentPage}: ${error.message}`, error);
                                throw error;
                            }

                            currentPage++;
                            if (currentPage <= totalPages) await new Promise(res => setTimeout(res, 150));

                        } while (currentPage <= totalPages);

                        return allItems;
                    },
                    parseKFGHtml: function(htmlString, storeModule) {
                        const items = [];
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');
                        const productElements = doc.querySelectorAll('.items-list .product-item');

                        productElements.forEach(element => {
                            try {
                                const titleElement = element.querySelector('.catalog-card__item-title');
                                const priceElement = element.querySelector('.catalog-card__price');
                                const linkElement = element.querySelector('.catalog-card__img-link, .product-card__link, .catalog-card__item-title a');
                                const imgElement = element.querySelector('.catalog-card__img img, .product-card img');

                                const productName = titleElement?.textContent?.trim();
                                const priceText = priceElement?.textContent?.trim();
                                const productUrlRaw = linkElement?.getAttribute('href');
                                const imageUrlRaw = imgElement?.getAttribute('src');

                                if (!productName || !priceText || !productUrlRaw || !imageUrlRaw) {
                                    return;
                                }

                                const cleanedPriceText = priceText.replace(/[₽$,]/g, '');
                                const currentPrice = sm_parsePrice(cleanedPriceText);

                                if (currentPrice === null) {
                                    sm_logError(storeModule.name, `Не удалось распарсить очищенную цену: ${cleanedPriceText}`, element.innerHTML);
                                    return;
                                }

                                const productUrl = productUrlRaw.startsWith('/') ? storeModule.baseUrl + productUrlRaw : productUrlRaw;
                                const imageUrl = imageUrlRaw.startsWith('/') ? storeModule.baseUrl + imageUrlRaw : imageUrlRaw;

                                let data = {
                                    storeId: storeModule.id,
                                    storeName: storeModule.name,
                                    storeUrl: storeModule.baseUrl,
                                    productName: productName,
                                    productUrl: productUrl,
                                    imageUrl: imageUrl,
                                    currentPrice: currentPrice,
                                    originalPrice: null,
                                    discountPercent: null,
                                    discountAmount: null,
                                    currency: 'RUB',
                                    isAvailable: true
                                };

                                items.push(data);

                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга HTML элемента KeysForGamers', e);
                            }
                        });
                        return items;
                    }
                }, // --- Конец модуля KeysForGamers ---

                { // --- Модуль Zaka-zaka ---
                    id: 'zakazaka',
                    name: 'Zaka-zaka',
                    baseUrl: 'https://zaka-zaka.com',
                    searchUrlTemplate: 'https://zaka-zaka.com/search/ask/{query}/sort/price.asc',
                    isEnabled: true,
                    fetch: async function(query) {
                        const searchUrl = this.searchUrlTemplate.replace('{query}', encodeURIComponent(query));
                        return new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: searchUrl,
                                timeout: SM_REQUEST_TIMEOUT_MS,
                                onload: (response) => {
                                    if (response.status >= 200 && response.status < 400) {
                                        resolve(this.parseHtml(response.responseText, this));
                                    } else {
                                        reject(new Error(`HTTP статус ${response.status}`));
                                    }
                                },
                                onerror: (error) => reject(new Error('Сетевая ошибка')),
                                ontimeout: () => reject(new Error('Таймаут запроса'))
                            });
                        });
                    },
                    parseHtml: function(htmlString, storeModule) {
                        const results = [];
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(htmlString, 'text/html');
                        const items = doc.querySelectorAll('.search-results .game-block');

                        items.forEach(item => {
                            try {
                                const linkElement = item;
                                const imageDiv = item.querySelector('.game-block-image');
                                const nameElement = item.querySelector('.game-block-name');
                                const priceElement = item.querySelector('.game-block-price');
                                const discountElement = item.querySelector('.game-block-discount');
                                const discountAmountElement = item.querySelector('.game-block-discount-sum');

                                const productName = nameElement?.textContent?.trim();
                                const productUrlRaw = linkElement?.getAttribute('href');
                                const currentPrice = priceElement ? sm_parsePrice(priceElement.textContent) : null;
                                const discountPercent = discountElement ? sm_parsePercent(discountElement.textContent) : 0;
                                const discountAmount = discountAmountElement ? Math.abs(sm_parsePrice(discountAmountElement.textContent) ?? 0) : null;

                                let imageUrl = null;
                                if (imageDiv?.style?.backgroundImage) {
                                    const match = imageDiv.style.backgroundImage.match(/url\("?(.+?)"?\)/);
                                    if (match && match[1]) {
                                        imageUrl = match[1].startsWith('/') ? storeModule.baseUrl + match[1] : match[1];
                                    }
                                }

                                if (!productName || !productUrlRaw || currentPrice === null) {
                                    return;
                                }

                                const fullOriginalUrl = productUrlRaw.startsWith('/') ? storeModule.baseUrl + productUrlRaw : productUrlRaw;
                                const referralPrefix = 'https://bednari.com/g/momptkjep9c1442ace4b02770293ab/?erid=2bL9aMPo2e49hMef4pgUXYbxvv&ulp=';
                                const productUrl = referralPrefix + encodeURIComponent(fullOriginalUrl);

                                let data = {
                                    storeId: storeModule.id,
                                    storeName: storeModule.name,
                                    storeUrl: storeModule.baseUrl,
                                    productName: productName,
                                    productUrl: productUrl,
                                    imageUrl: imageUrl,
                                    currentPrice: currentPrice,
                                    originalPrice: null,
                                    discountPercent: discountPercent,
                                    discountAmount: discountAmount,
                                    currency: 'RUB',
                                    isAvailable: true
                                };
                                results.push(sm_calculateMissingValues(data));
                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента', e);
                            }
                        });
                        return results;
                    }
                }, // --- Конец модуля Zaka-zaka ---

                { // --- Модуль Buka ---
                    id: 'buka',
                    name: 'Buka',
                    baseUrl: 'https://shop.buka.ru',
                    apiUrl: 'https://shop.buka.ru/api/f/v2/search/get-page',
                    isEnabled: true,
                    fetch: async function(query) {
                        let allItems = [];
                        let pageIndex = 0;
                        let hasNext = true;
                        const storeModule = this;

                        async function fetchBukaPage(currentIndex) {
                            const requestPayload = {
                                pageIndex: currentIndex,
                                filter: {
                                    term: query,
                                    area_id: 100001,
                                    channel: "WEB"
                                }
                            };
                            const requestHeaders = {
                                'Accept': '*/*',
                                'Content-Type': 'application/json'
                            };

                            try {
                                const response = await new Promise((resolve, reject) => {
                                    GM_xmlhttpRequest({
                                        method: "POST",
                                        url: storeModule.apiUrl,
                                        headers: requestHeaders,
                                        data: JSON.stringify(requestPayload),
                                        responseType: 'json',
                                        timeout: SM_REQUEST_TIMEOUT_MS,
                                        onload: resolve,
                                        onerror: reject,
                                        ontimeout: () => reject(new Error(`Таймаут запроса (pageIndex: ${currentIndex})`)),
                                    });
                                });

                                if (response.status >= 200 && response.status < 400 && response.response) {
                                    const data = response.response;
                                    const pageInfo = data.page;

                                    if (pageInfo && Array.isArray(pageInfo.rows)) {
                                        const processedItems = pageInfo.rows
                                            .map(item => storeModule.parseApiItem(item, storeModule))
                                            .filter(item => item !== null);

                                        allItems = allItems.concat(processedItems);
                                    }

                                    hasNext = pageInfo?.hasNext ?? false;
                                    if (hasNext) {
                                        await fetchBukaPage(currentIndex + 1);
                                    }

                                } else {
                                    throw new Error(`HTTP статус ${response.status} (pageIndex: ${currentIndex})`);
                                }
                            } catch (error) {
                                sm_logError(storeModule.name, `Ошибка загрузки страницы ${currentIndex}: ${error.message}`, error);
                                hasNext = false;
                            }
                        }

                        await fetchBukaPage(pageIndex);

                        return allItems;
                    },

                    parseApiItem: function(item, storeModule) {
                        try {
                            // --- Фильтрация ---
                            // 1. Проверяем тип (нужен цифровой, обычно type: 3)
                            if (item.type !== 3) return null;

                            // 2. Проверяем платформу (нужен PC)
                            const platformFilter = item.filters?.find(f => f.field === 'platform');
                            const isPC = platformFilter?.values?.some(v => v.title === 'PC');
                            if (!isPC) return null;

                            // 3. Проверяем статус продажи (доступен или предзаказ)
                            const saleState = item.saleState;
                            if (saleState !== 'available' && saleState !== 'pre-order') {
                                return null;
                            }

                            const productName = item.title?.trim();
                            const productUrlRaw = item.alias ? `/item/${item.alias}` : null;
                            const imageUrl = item.img;

                            const currentPrice = item.price?.actual ? sm_parsePrice(item.price.actual) : null;
                            const originalPrice = item.price?.old ? sm_parsePrice(item.price.old) : (currentPrice !== null ? currentPrice : null);
                            const discountPercent = item.price?.discount ? parseFloat(item.price.discount) : 0;

                            if (!productName || !productUrlRaw || !imageUrl || currentPrice === null) {
                                sm_logError(storeModule.name, 'Недостаточно данных в API ответе для элемента', item);
                                return null;
                            }

                            const fullProductUrl = storeModule.baseUrl + productUrlRaw;
                            const productUrlWithRef = fullProductUrl + '?ref=zoneofgames';

                            let data = {
                                storeId: storeModule.id,
                                storeName: storeModule.name,
                                storeUrl: storeModule.baseUrl,
                                productName: productName,
                                productUrl: productUrlWithRef,
                                imageUrl: imageUrl,
                                currentPrice: currentPrice,
                                originalPrice: originalPrice === currentPrice ? null : originalPrice,
                                discountPercent: discountPercent > 0 ? discountPercent : null,
                                discountAmount: null,
                                currency: 'RUB',
                                isAvailable: true
                            };

                            return sm_calculateMissingValues(data);

                        } catch (e) {
                            sm_logError(storeModule.name, 'Ошибка парсинга элемента API Buka', e);
                            return null;
                        }
                    }
                },

                { // --- Модуль GGSEL ---
                    id: 'ggsel',
                    name: 'GGSEL',
                    baseUrl: 'https://ggsel.net',
                    apiUrl: 'https://api4.ggsel.com/elastic/goods/query',
                    isEnabled: true,
                    fetch: async function(query) {
                        let allItems = [];
                        let searchAfter = [];
                        const limit = 60;
                        let hasMore = true;
                        let fetchedCount = 0;
                        const maxFetches = 5;
                        let fetchAttempts = 0;
                        const storeModule = this;

                        async function fetchGGSELPage(currentIndex) {
                            fetchAttempts++;
                            const requestPayload = {
                                search_term: query,
                                limit: limit,
                                search_after: searchAfter,
                                is_preorders: false,
                                with_filters: true,
                                with_categories: false,
                                sort: "sortByPriceUp",
                                content_type_ids: [48, 2],
                                with_forbidden: false,
                                min_price: "",
                                max_price: "",
                                currency: "wmr",
                                lang: "ru",
                                platforms: ["Steam"]
                            };
                            const requestHeaders = {
                                'Accept': 'application/json, text/plain, */*',
                                'Content-Type': 'application/json'
                            };

                            try {
                                const response = await new Promise((resolve, reject) => {
                                    GM_xmlhttpRequest({
                                        method: "POST",
                                        url: storeModule.apiUrl,
                                        headers: requestHeaders,
                                        data: JSON.stringify(requestPayload),
                                        responseType: 'json',
                                        timeout: SM_REQUEST_TIMEOUT_MS,
                                        onload: resolve,
                                        onerror: reject,
                                        ontimeout: () => reject(new Error(`Таймаут запроса (pageIndex: ${currentIndex})`)),
                                    });
                                });

                                if (response.status >= 200 && response.status < 400 && response.response?.data) {
                                    const data = response.response.data;
                                    if (data.items && Array.isArray(data.items)) {
                                        const processedItems = data.items
                                            .map(item => storeModule.parseApiItem(item, storeModule))
                                            .filter(item => item !== null);

                                        allItems = allItems.concat(processedItems);
                                        fetchedCount += data.items.length;

                                        if (data.items.length < limit || !data.last_sort || fetchedCount >= (data.total ?? fetchedCount)) {
                                            hasMore = false;
                                        } else {
                                            searchAfter = data.last_sort;
                                        }
                                    } else {
                                        hasMore = false;
                                    }
                                } else {
                                    throw new Error(`HTTP статус ${response.status} (pageIndex: ${currentIndex})`);
                                }
                            } catch (error) {
                                sm_logError(storeModule.name, `Ошибка загрузки страницы ${currentIndex}: ${error.message}`, error);
                                hasMore = false;
                            }

                            if (hasMore && fetchAttempts < maxFetches) {
                                 await new Promise(res => setTimeout(res, 150));
                                 await fetchGGSELPage(currentIndex + 1);
                             }
                        }

                        await fetchGGSELPage(0);

                        if (fetchAttempts >= maxFetches && hasMore) {
                             sm_logError(storeModule.name, `Достигнут лимит запросов пагинации (${maxFetches}). Возможно, показаны не все результаты.`);
                        }

                        return allItems;
                    },

                    parseApiItem: function(item, storeModule) {
                        try {
                            if (item.forbidden_type !== 0 || item.hidden_from_search || item.hidden_from_parents) {
                                return null;
                            }
                            if (item.content_type_id !== 48 && item.content_type_id !== 2) {
                                return null;
                            }

                            const productName = item.name?.trim();
                            const productUrlRaw = `${storeModule.baseUrl}/catalog/product/${item.id_goods}`;
                            const productUrl = `${productUrlRaw}?ai=234029`;

                            const imageUrl = item.images ? `https://img.ggsel.ru/${item.id_goods}/original/250x250/${item.images}` : null;

                            const currentPrice = item.price_wmr ? sm_parsePrice(item.price_wmr) : null;
                            const potentialOriginalPrice = item.category_discount ? sm_parsePrice(item.category_discount) : null;
                            const originalPrice = (potentialOriginalPrice && currentPrice !== null && potentialOriginalPrice > currentPrice) ? potentialOriginalPrice : null;

                            const sellerId = item.id_seller;
                            const sellerName = item.seller_name;

                            if (!productName || currentPrice === null || !imageUrl) {
                                sm_logError(storeModule.name, 'Недостаточно данных в элементе API GGSEL (после проверок)', item);
                                return null;
                            }

                            let data = {
                                storeId: storeModule.id,
                                storeName: storeModule.name,
                                storeUrl: storeModule.baseUrl,
                                productName: productName,
                                productUrl: productUrl,
                                imageUrl: imageUrl,
                                currentPrice: currentPrice,
                                originalPrice: originalPrice,
                                discountPercent: null,
                                discountAmount: null,
                                currency: 'RUB',
                                isAvailable: true,
                                sellerId: sellerId,
                                sellerName: sellerName
                            };

                            return sm_calculateMissingValues(data);

                        } catch (e) {
                            sm_logError(storeModule.name, 'Ошибка парсинга элемента API GGSEL', e);
                            return null;
                        }
                    }
                }, // --- Конец модуля GGSEL ---

                { // --- Модуль Plati.Market ---
                    id: 'platimarket',
                    name: 'Plati.Market',
                    baseUrl: 'https://plati.market',
                    apiUrlBase: 'https://api.digiseller.com/api/products/search2',
                    isEnabled: true,
                    fetch: async function(query) {
                        const MAX_RESULTS_PER_REQUEST = 500;

                        // --- Шаг 1: Узнаем общее количество товаров ---
                        const initialUrl = `${this.apiUrlBase}?query=${encodeURIComponent(query)}&searchmode=10&sortmode=2&pagesize=1`;
                        let totalItems = 0;

                        try {
                            const initialResponse = await new Promise((resolve, reject) => {
                                GM_xmlhttpRequest({
                                    method: "GET",
                                    url: initialUrl,
                                    responseType: 'json',
                                    timeout: SM_REQUEST_TIMEOUT_MS,
                                    onload: (response) => {
                                        if (response.status >= 200 && response.status < 400 && response.response?.result?.total !== undefined) {
                                            resolve(response.response);
                                        } else {
                                            sm_logError(this.name, `Не удалось получить total_pages. Status: ${response.status}`, response);
                                            reject(new Error(`API Error: Status ${response.status}`));
                                        }
                                    },
                                    onerror: (error) => reject(new Error('Сетевая ошибка (initial request)')),
                                    ontimeout: () => reject(new Error('Таймаут запроса (initial request)'))
                                });
                            });
                            totalItems = parseInt(initialResponse.result.total, 10);
                        } catch (error) {
                            sm_logError(this.name, 'Ошибка на шаге 1 (получение total)', error);
                            return [];
                        }

                        if (totalItems === 0) {
                            return [];
                        }

                        // --- Шаг 2: Запрашиваем все (или до MAX_RESULTS_PER_REQUEST) товары ---
                        const resultsToFetch = Math.min(totalItems, MAX_RESULTS_PER_REQUEST);
                        if (resultsToFetch <= 0) return [];

                        const finalUrl = `${this.apiUrlBase}?query=${encodeURIComponent(query)}&searchmode=10&sortmode=2&pagesize=${resultsToFetch}`;

                        try {
                            const finalResponse = await new Promise((resolve, reject) => {
                                GM_xmlhttpRequest({
                                    method: "GET",
                                    url: finalUrl,
                                    responseType: 'json',
                                    timeout: SM_REQUEST_TIMEOUT_MS * 2,
                                    onload: (response) => {
                                        if (response.status >= 200 && response.status < 400 && response.response?.items?.item) {
                                            resolve(response.response);
                                        } else {
                                            sm_logError(this.name, `Не удалось получить items. Status: ${response.status}`, response);
                                            reject(new Error(`API Error: Status ${response.status}`));
                                        }
                                    },
                                    onerror: (error) => reject(new Error('Сетевая ошибка (final request)')),
                                    ontimeout: () => reject(new Error('Таймаут запроса (final request)'))
                                });
                            });

                            return this.parseApiResponse(finalResponse.items.item, this);

                        } catch (error) {
                            sm_logError(this.name, 'Ошибка на шаге 2 (получение items)', error);
                            return [];
                        }
                    },
                    parseApiResponse: function(items, storeModule) {
                        const results = [];
                        if (!Array.isArray(items)) {
                            sm_logError(storeModule.name, 'Ответ API не содержит массив items', items);
                            return results;
                        }

                        items.forEach(item => {
                            try {
                                const productName = item.name;
                                const productUrlRaw = item.url;
                                const currentPrice = sm_parsePrice(item.price_rur);
                                const currency = 'RUB';
                                const sellerId = item.seller_id;
                                const sellerName = item.seller_name;

                                if (!productName || !productUrlRaw || currentPrice === null) {
                                    return;
                                }

                                const productUrl = productUrlRaw + '?ai=234029';

                                const imageUrl = `https://graph.digiseller.ru/img.ashx?id_d=${item.id}&w=150&h=80`;

                                let data = {
                                    storeId: storeModule.id,
                                    storeName: storeModule.name,
                                    storeUrl: storeModule.baseUrl,
                                    productName: productName,
                                    productUrl: productUrl,
                                    imageUrl: imageUrl,
                                    currentPrice: currentPrice,
                                    originalPrice: currentPrice,
                                    discountPercent: 0,
                                    discountAmount: 0,
                                    currency: currency,
                                    isAvailable: true,
                                    sellerId: sellerId,
                                    sellerName: sellerName
                                };
                                results.push(sm_calculateMissingValues(data));
                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента API', e);
                            }
                        });
                        return results;
                    }
                }, // --- Конец модуля Plati.Market ---
                { // --- Модуль Rushbe ---
                    id: 'rushbe',
                    name: 'Rushbe',
                    baseUrl: 'https://rushbe.ru',
                    searchUrlTemplate: 'https://rushbe.ru/gateway/api/game-center/games/catalog/search',
                    isEnabled: true,
                    fetch: async function(query) {
                        const storeModule = this;
                        const searchUrl = this.searchUrlTemplate;

                        const requestPayload = {
                            filter: query
                        };

                        const requestHeaders = {
                            'accept': 'application/json, text/plain, */*',
                            'content-type': 'application/json;charset=UTF-8',
                        };

                        return new Promise((resolve, reject) => {
                            GM_xmlhttpRequest({
                                method: "POST",
                                url: searchUrl,
                                headers: requestHeaders,
                                data: JSON.stringify(requestPayload),
                                responseType: 'json',
                                timeout: SM_REQUEST_TIMEOUT_MS,
                                onload: (response) => {
                                    if (response.status >= 200 && response.status < 400 && response.response) {
                                        resolve(this.parseApiResponse(response.response, storeModule));
                                    } else {
                                        reject(new Error(`HTTP статус ${response.status}`));
                                    }
                                },
                                onerror: (error) => reject(new Error('Сетевая ошибка')),
                                ontimeout: () => reject(new Error('Таймаут запроса'))
                            });
                        });
                    },
                    parseApiResponse: function(items, storeModule) {
                        const results = [];
                        if (!Array.isArray(items)) {
                            sm_logError(storeModule.name, 'Ответ API не является массивом', items);
                            return results;
                        }

                        items.forEach(item => {
                            try {
                                if (item.outOfStock === true) {
                                    return;
                                }
                                const isSteamGame = item.activations?.some(act => act.code === 'steam');
                                if (!isSteamGame) {
                                    return;
                                }

                                const productName = item.gameName?.trim();
                                const productUrlRaw = item.link ? `/games/${item.link}` : null;
                                const imageUrlRaw = item.horizontalCover?.preview;
                                const currentPrice = sm_parsePrice(item.priceWithSale);
                                const originalPrice = sm_parsePrice(item.priceWithoutSale);
                                const discountPercent = item.sale || 0;

                                if (!productName || !productUrlRaw || currentPrice === null) {
                                    return;
                                }

                                if (item.hasDlc && !productName.toLowerCase().includes('dlc') && !productName.toLowerCase().includes('pack')) {
                                }

                                const productUrl = storeModule.baseUrl + productUrlRaw;
                                const imageUrl = imageUrlRaw ? storeModule.baseUrl + imageUrlRaw : null;

                                let data = {
                                    storeId: storeModule.id,
                                    storeName: storeModule.name,
                                    storeUrl: storeModule.baseUrl,
                                    productName: productName,
                                    productUrl: productUrl,
                                    imageUrl: imageUrl,
                                    currentPrice: currentPrice,
                                    originalPrice: (originalPrice && originalPrice > currentPrice) ? originalPrice : currentPrice,
                                    discountPercent: discountPercent > 0 ? discountPercent : null,
                                    discountAmount: null,
                                    currency: 'RUB',
                                    isAvailable: true
                                };

                                results.push(sm_calculateMissingValues(data));

                            } catch (e) {
                                sm_logError(storeModule.name, 'Ошибка парсинга элемента API', e);
                            }
                        });
                        return results;
                    }
                }

                // --- Сюда другие модули ---
            ];

            // --- Инициализация модуля SalesMaster ---
            sm_addStyles();
            const steamAppIdCheckSM = unsafeWindow.location.pathname.match(/\/app\/(\d+)/);
            if (steamAppIdCheckSM && steamAppIdCheckSM[1]) {
                setTimeout(sm_addSalesMasterButton, 500);
                sm_currentFilters = GM_getValue(SM_FILTER_STORAGE_KEY, {
                    priceMin: '',
                    priceMax: '',
                    discountPercentMin: '',
                    discountPercentMax: '',
                    discountAmountMin: '',
                    discountAmountMax: '',
                    hasDiscount: false,
                    stores: Object.fromEntries(sm_storeModules.map(s => [s.id, true]))
                });
                sm_storeModules.forEach(store => {
                    if (!(store.id in sm_currentFilters.stores)) {
                        sm_currentFilters.stores[store.id] = true;
                    }
                });

            }

        })();
    }

    // Скрипт для страницы игры (Plati; отображение цен с Plati.Market) | https://store.steampowered.com/app/*
    if (scriptsConfig.platiSales && unsafeWindow.location.pathname.includes('/app/')) {
        (function() {
            'use strict';

            // --- Конфигурация PlatiSearch (PS) ---
            const PS_API_BASE_URL = 'https://api.digiseller.com/api/products/search2';
            const PS_SUGGEST_API_URL = 'https://plati.market/api/suggest.ashx';
            const PS_IMAGE_DOMAIN = 'digiseller.mycdn.ink';
            const PS_RESULTS_PER_PAGE_CHECK = 1;
            const PS_DEFAULT_SORT_MODE = 2;
            const PS_SUGGEST_DEBOUNCE_MS = 300;
            const PS_FILTER_DEBOUNCE_MS = 500;
            const PS_FILTER_STORAGE_PREFIX = 'platiSalesFilter_v1_';
            const PS_EXCLUSION_STORAGE_KEY = 'platiSalesExclusions_v1_';
            const PS_LAST_SORT_STORAGE_KEY = 'platiSalesLastSort_v1_';
            const PS_CURRENCY_STORAGE_KEY = 'platiSalesCurrency_v1_';
            const PS_FILTER_PANEL_WIDTH = 230;
            const PS_EXCLUSION_PANEL_WIDTH = 250;
            const PS_SIDE_PANEL_HORIZONTAL_PADDING = 20;
            const PS_CONTENT_PADDING_BUFFER = 15;
            const PS_CONTENT_PADDING_LEFT = PS_FILTER_PANEL_WIDTH + PS_SIDE_PANEL_HORIZONTAL_PADDING + PS_CONTENT_PADDING_BUFFER;
            const PS_CONTENT_PADDING_RIGHT = PS_EXCLUSION_PANEL_WIDTH + PS_SIDE_PANEL_HORIZONTAL_PADDING + PS_CONTENT_PADDING_BUFFER;
            const PS_HEADER_APPROX_HEIGHT = 65;
            const PS_TOP_OFFSET_FOR_SIDE_PANELS = PS_HEADER_APPROX_HEIGHT + 25;
            const PS_BOTTOM_OFFSET_FOR_SIDE_PANELS = 20;
            const PS_ADV_SORT_CONTAINER_WIDTH = 230;
            const NEW_ITEM_THRESHOLD_DAYS = 7;

            // --- Глобальные переменные ---
            let ps_currentResults = [];
            let ps_currentSort = GM_getValue(PS_LAST_SORT_STORAGE_KEY, { field: 'relevance', direction: 'asc' });
            let ps_currentCurrency = GM_getValue(PS_CURRENCY_STORAGE_KEY, 'RUR');
            let ps_firstSortClick = {};
            ['price', 'sales', 'relevance', 'name', 'date_create', 'discount', 'seller_rating', 'review_ratio', 'good_reviews', 'bad_reviews', 'returns'].forEach(field => {
                ps_firstSortClick[field] = ps_currentSort.field !== field;
            });
            let ps_exclusionKeywords = GM_getValue(PS_EXCLUSION_STORAGE_KEY, []);
            let ps_currentFilters = ps_loadFilters();
            let ps_suggestDebounceTimeout;
            let ps_filterDebounceTimeout;
            let ps_advSortMenuTimeout;

            // --- DOM Элементы ---
            let ps_modal, ps_closeBtn, ps_searchInput, ps_searchBtn, ps_sortPriceBtn, ps_sortSalesBtn, ps_advSortBtnContainer, ps_advSortBtn, ps_advSortMenu, ps_currencySelect, ps_resetSortBtn;
            let ps_resultsContainer, ps_resultsDiv, ps_statusDiv, ps_excludeInput, ps_addExcludeBtn, ps_exclusionTagsDiv;
            let ps_suggestionsDiv;
            let ps_filtersPanel;
            let ps_filterPriceMin, ps_filterPriceMax, ps_filterSalesMin, ps_filterSalesMax, ps_filterRatingMin, ps_filterRatingMax;
            let ps_filterHideBadReviews, ps_filterHideReturns, ps_filterOnlyDiscount;
            let ps_filterDateSelect;
            let ps_resetAllFiltersBtn;
            let ps_exclusionTagsListDiv;

            // --- Описания сортировок ---
             const ps_advancedSorts = {
                 'price':        { name: 'По цене',          defaultDir: 'asc' },
                 'sales':        { name: 'По продажам',      defaultDir: 'desc'},
                 'relevance':    { name: 'По релевантности', defaultDir: 'asc' },
                 'name':         { name: 'По названию',      defaultDir: 'asc'  },
                 'date_create':  { name: 'По дате добавления', defaultDir: 'desc' },
                 'discount':     { name: 'По % в скид. системе', defaultDir: 'desc' },
                 'seller_rating':{ name: 'По рейтингу продавца', defaultDir: 'desc' },
                 'review_ratio': { name: 'По соотношению отзывов', defaultDir: 'desc' },
                 'good_reviews': { name: 'По кол-ву хор. отзывов', defaultDir: 'desc' },
                 'bad_reviews':  { name: 'По кол-ву плох. отзывов', defaultDir: 'asc'  },
                 'returns':      { name: 'По кол-ву возвратов', defaultDir: 'asc'  }
            };
            const ps_advSortOrder = ['name', 'date_create', 'discount', 'seller_rating', 'review_ratio', 'good_reviews', 'bad_reviews', 'returns'];
            const ps_dateFilterOptions = {
                 'all': 'За все время', '1d': 'За сутки', '2d': 'За 2 дня', '1w': 'За неделю', '1m': 'За месяц', '6m': 'За полгода', '1y': 'За год', '5y': 'За 5 лет', '10y': 'За 10 лет',
            };

            // --- Вспомогательные функции ---
            function formatPrice(priceStr) {
                if (!priceStr) return 0;
                return parseFloat(String(priceStr).replace(/[^\d,.]/g, '').replace(',', '.')) || 0;
            }
            function formatSales(salesStr) {
                if (!salesStr) return 0;
                return parseInt(String(salesStr).replace(/\D/g, ''), 10) || 0;
            }
             function parseSellerRating(ratingStr) {
                 if (!ratingStr) return 0;
                 return parseFloat(String(ratingStr).replace(',', '.')) || 0;
             }
             function calculateReviewRatio(item) {
                 const good = parseInt(item.cnt_good_responses || '0', 10);
                 const bad = parseInt(item.cnt_bad_responses || '0', 10);
                 const total = good + bad;
                 return total > 0 ? (good / total) : -1;
             }
             function parseDate(dateStr) {
                 if (!dateStr) return 0;
                 const parts = dateStr.split(' ');
                 if (parts.length !== 2) return 0;
                 const dateParts = parts[0].split('.');
                 const timeParts = parts[1].split(':');
                 if (dateParts.length !== 3 || timeParts.length !== 3) return 0;
                 try { return new Date(Date.UTC(dateParts[2], dateParts[1] - 1, dateParts[0], timeParts[0], timeParts[1], timeParts[2])).getTime(); }
                 catch (e) { return 0; }
             }
            function formatDateString(timestamp) {
                if (!timestamp || timestamp === 0) return 'N/A';
                try {
                    const date = new Date(timestamp);
                    const day = String(date.getUTCDate()).padStart(2, '0');
                    const month = String(date.getUTCMonth() + 1).padStart(2, '0');
                    const year = String(date.getUTCFullYear()).slice(-2);
                    return `${day}.${month}.${year}`;
                } catch (e) { return 'N/A'; }
            }
             function getPriceInSelectedCurrency(item, currency) {
                 let price = 0;
                 switch (currency) {
                     case 'USD': price = formatPrice(item.price_usd); break;
                     case 'EUR': price = formatPrice(item.price_eur); break;
                     case 'UAH': price = formatPrice(item.price_uah); break;
                     case 'RUR': default: price = formatPrice(item.price_rur); break;
                 }
                 if (price <= 0 && currency !== 'RUR') price = formatPrice(item.price_rur);
                 if (price <= 0 && currency !== 'USD') price = formatPrice(item.price_usd);
                 if (price <= 0 && currency !== 'EUR') price = formatPrice(item.price_eur);
                 return price > 0 ? price : Infinity;
             }
            function debounce(func, wait) {
                let timeout;
                return function executedFunction(...args) {
                    const later = () => { clearTimeout(timeout); func(...args); };
                    clearTimeout(timeout);
                    timeout = setTimeout(later, wait);
                };
            }
            function getSteamGameName() {
                 const appNameElement = document.querySelector('#appHubAppName');
                 return appNameElement ? appNameElement.textContent.trim() : '';
            }

            function ps_exportExclusions() {
                const keywordsString = ps_exclusionKeywords.join(',');
                if (!keywordsString) {
                    alert('Список исключений пуст.');
                    return;
                }
                try {
                    navigator.clipboard.writeText(keywordsString).then(() => {
                        const exportBtn = document.getElementById('psExportExclusionsBtn');
                        if (exportBtn) {
                            const originalContent = exportBtn.innerHTML;
                            exportBtn.innerHTML = 'Скопировано!';
                            exportBtn.disabled = true;
                            setTimeout(() => {
                                exportBtn.innerHTML = originalContent;
                                exportBtn.disabled = false;
                            }, 1500);
                        }
                    }, (err) => {
                        console.error('[PlatiSearch] Не удалось скопировать в буфер обмена:', err);
                        prompt('Не удалось скопировать автоматически. Скопируйте вручную:', keywordsString);
                    });
                } catch (err) {
                    console.error('[PlatiSearch] Ошибка доступа к буферу обмена:', err);
                    prompt('Не удалось скопировать автоматически. Скопируйте вручную:', keywordsString);
                }
            }

            function ps_showImportModal() {
                const existingModal = document.getElementById('psImportModal');
                if (existingModal) existingModal.remove();

                const importModal = document.createElement('div');
                importModal.id = 'psImportModal';
                importModal.innerHTML = `
                    <div class="psImportModalContent">
                        <h4>Импорт списка исключений</h4>
                        <p>Вставьте список слов, разделенных запятыми:</p>
                        <textarea id="psImportTextarea" rows="6"></textarea>
                        <div class="psImportModalActions">
                            <button id="psImportAcceptBtn" class="platiSearchBtn">Принять</button>
                            <button id="psImportCancelBtn" class="platiSearchBtn">Отмена</button>
                        </div>
                    </div>
                `;
                document.body.appendChild(importModal);

                document.getElementById('psImportAcceptBtn').onclick = ps_handleImport;
                document.getElementById('psImportCancelBtn').onclick = () => importModal.remove();
                document.getElementById('psImportTextarea').focus();
            }

            function ps_handleImport() {
                const textarea = document.getElementById('psImportTextarea');
                const importModal = document.getElementById('psImportModal');
                if (!textarea || !importModal) return;

                const text = textarea.value.trim();
                if (text) {
                    const importedKeywords = text.split(',')
                                               .map(k => k.trim().toLowerCase())
                                               .filter(k => k.length > 0);
                    ps_exclusionKeywords = [...new Set(importedKeywords)];
                    GM_setValue(PS_EXCLUSION_STORAGE_KEY, ps_exclusionKeywords);
                    ps_renderExclusionTags();
                    ps_applyFilters();
                    console.log('[PlatiSearch] Список исключений импортирован.');
                } else {
                    alert("Поле ввода пустое. Импорт не выполнен.");
                }
                importModal.remove();
            }

            // --- Создание UI ---
            function createPlatiModal() {
                 const existingModal = document.querySelector('#platiSearchModal');
                 if (existingModal) existingModal.remove();

                 ps_modal = document.createElement('div');
                 ps_modal.id = 'platiSearchModal';

                 const container = document.createElement('div');
                 container.id = 'platiSearchContainer';

                 const header = document.createElement('div');
                 header.id = 'platiSearchHeader';

                 const searchInputContainer = document.createElement('div');
                 searchInputContainer.className = 'platiSearchInputContainer';
                 ps_searchInput = document.createElement('input');
                 ps_searchInput.id = 'platiSearchInput';
                 ps_searchInput.type = 'text';
                 ps_searchInput.placeholder = 'Введите название игры или товара...';
                 ps_searchInput.autocomplete = 'off';
                 ps_searchInput.onkeydown = (e) => { if (e.key === 'Enter') ps_triggerSearch(); };
                 ps_searchInput.oninput = () => {
                     clearTimeout(ps_suggestDebounceTimeout);
                     ps_suggestDebounceTimeout = setTimeout(() => ps_fetchSuggestions(ps_searchInput.value), PS_SUGGEST_DEBOUNCE_MS);
                 };
                 ps_searchInput.onblur = () => { setTimeout(() => { if (ps_suggestionsDiv) ps_suggestionsDiv.style.display = 'none'; }, 150); };

                 ps_suggestionsDiv = document.createElement('div');
                 ps_suggestionsDiv.id = 'platiSearchSuggestions';
                 searchInputContainer.appendChild(ps_searchInput);
                 searchInputContainer.appendChild(ps_suggestionsDiv);
                 header.appendChild(searchInputContainer);

                 ps_searchBtn = document.createElement('button');
                 ps_searchBtn.textContent = 'Найти';
                 ps_searchBtn.id = 'platiSearchGoBtn';
                 ps_searchBtn.className = 'platiSearchBtn';
                 ps_searchBtn.onclick = ps_triggerSearch;
                 header.appendChild(ps_searchBtn);

                 ps_resetSortBtn = document.createElement('button');
                 ps_resetSortBtn.id = 'platiResetSortBtn';
                 ps_resetSortBtn.className = 'platiSearchBtn';
                 ps_resetSortBtn.title = 'Сбросить сортировку (Релевантность)';
                 ps_resetSortBtn.innerHTML = `<svg viewBox="0 0 24 24"><path fill="currentColor" d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6s-2.69 6-6 6s-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8s-3.58-8-8-8Z"/></svg>`;
                 ps_resetSortBtn.onclick = () => ps_resetSort(true);
                 header.appendChild(ps_resetSortBtn);

                 ps_sortPriceBtn = document.createElement('button');
                 ps_sortPriceBtn.className = 'platiSearchBtn sortBtn';
                 ps_sortPriceBtn.dataset.sort = 'price';
                 ps_sortPriceBtn.onclick = () => ps_handleSort('price');
                 header.appendChild(ps_sortPriceBtn);

                 ps_sortSalesBtn = document.createElement('button');
                 ps_sortSalesBtn.className = 'platiSearchBtn sortBtn';
                 ps_sortSalesBtn.dataset.sort = 'sales';
                 ps_sortSalesBtn.onclick = () => ps_handleSort('sales');
                 header.appendChild(ps_sortSalesBtn);

                 ps_advSortBtnContainer = document.createElement('div');
                 ps_advSortBtnContainer.id = 'platiSearchAdvSortBtnContainer';
                 ps_advSortBtn = document.createElement('button');
                 ps_advSortBtn.id = 'platiSearchAdvSortBtn';
                 ps_advSortBtn.className = 'platiSearchBtn sortBtn';
                 ps_advSortBtnContainer.appendChild(ps_advSortBtn);
                 ps_advSortMenu = document.createElement('div');
                 ps_advSortMenu.id = 'platiSearchAdvSortMenu';
                 ps_advSortOrder.forEach(key => {
                     const sortInfo = ps_advancedSorts[key];
                     const menuItem = document.createElement('div');
                     menuItem.className = 'platiSearchSortMenuItem';
                     menuItem.dataset.sort = key;
                     menuItem.innerHTML = `${sortInfo.name} <span class="sortArrow"></span>`;
                     menuItem.onclick = () => ps_handleSort(key);
                     ps_advSortMenu.appendChild(menuItem);
                 });
                 ps_advSortBtnContainer.appendChild(ps_advSortMenu);
                 header.appendChild(ps_advSortBtnContainer);

                 ps_currencySelect = document.createElement('select');
                 ps_currencySelect.id = 'platiSearchCurrencySelect';
                 ['RUR', 'USD', 'EUR', 'UAH'].forEach(curr => {
                     const option = document.createElement('option');
                     option.value = curr; option.textContent = curr;
                     if (curr === ps_currentCurrency) option.selected = true;
                     ps_currencySelect.appendChild(option);
                 });
                 ps_currencySelect.onchange = ps_handleCurrencyChange;
                 header.appendChild(ps_currencySelect);

                 container.appendChild(header);

                 ps_resultsContainer = document.createElement('div');
                 ps_resultsContainer.id = 'platiSearchResultsContainer';
                 ps_statusDiv = document.createElement('div');
                 ps_statusDiv.id = 'platiSearchResultsStatus';
                 ps_resultsDiv = document.createElement('div');
                 ps_resultsDiv.id = 'platiSearchResults';
                 ps_resultsContainer.appendChild(ps_statusDiv);
                 ps_resultsContainer.appendChild(ps_resultsDiv);
                 container.appendChild(ps_resultsContainer);
                 ps_modal.appendChild(container);

                 ps_filtersPanel = document.createElement('div');
                 ps_filtersPanel.id = 'platiSearchFiltersPanel';
                 ps_filtersPanel.innerHTML = `
                    <div class="filterGroup"> <h4>Цена (${ps_currentCurrency}) ${ps_createResetButtonHTML('price')}</h4> <div class="filterRangeInputs"> <input type="number" id="psFilterPriceMin" placeholder="от" min="0"> <input type="number" id="psFilterPriceMax" placeholder="до" min="0"> </div> </div>
                    <div class="filterGroup"> <h4>Продажи ${ps_createResetButtonHTML('sales')}</h4> <div class="filterRangeInputs"> <input type="number" id="psFilterSalesMin" placeholder="от" min="0"> <input type="number" id="psFilterSalesMax" placeholder="до" min="0"> </div> </div>
                    <div class="filterGroup"> <h4>Рейтинг продавца ${ps_createResetButtonHTML('rating')}</h4> <div class="filterRangeInputs"> <input type="number" id="psFilterRatingMin" placeholder="от" step="0.1" min="0"> <input type="number" id="psFilterRatingMax" placeholder="до" step="0.1" min="0"> </div> </div>
                    <div class="filterGroup"> <h4>Опции ${ps_createResetButtonHTML('options')}</h4> <div class="filterCheckbox"> <label><input type="checkbox" id="psFilterHideBadReviews"> Скрыть с плох. отзывами</label> </div> <div class="filterCheckbox"> <label><input type="checkbox" id="psFilterHideReturns"> Скрыть с возвратами</label> </div> <div class="filterCheckbox"> <label><input type="checkbox" id="psFilterOnlyDiscount"> Участие в скидках</label> </div> </div>
                    <div class="filterGroup"> <h4>Дата добавления ${ps_createResetButtonHTML('date')}</h4> <div class="filterSelect"> <select id="psFilterDateSelect"> ${Object.entries(ps_dateFilterOptions).map(([key, text]) => `<option value="${key}">${text}</option>`).join('')} </select> </div> </div>
                    <button id="psResetAllFiltersBtn" class="platiSearchBtn">Сбросить все фильтры</button>
                 `;
                 ps_modal.appendChild(ps_filtersPanel);

                 ps_exclusionTagsDiv = document.createElement('div');
                 ps_exclusionTagsDiv.id = 'platiSearchExclusionTags';
                 const exclusionInputGroup = document.createElement('div');
                 exclusionInputGroup.className = 'exclusionInputGroup';
                 ps_excludeInput = document.createElement('input');
                 ps_excludeInput.type = 'text';
                 ps_excludeInput.id = 'platiSearchExcludeInput';
                 ps_excludeInput.placeholder = 'Исключить слово';
                 ps_excludeInput.onkeydown = (e) => { if (e.key === 'Enter') ps_addFilterKeyword(); };
                 ps_addExcludeBtn = document.createElement('button');
                 ps_addExcludeBtn.id = 'platiSearchAddExcludeBtn';
                 ps_addExcludeBtn.innerHTML = `<svg viewBox="0 0 20 20"><path d="M10 2.5a.75.75 0 0 1 .75.75v6h6a.75.75 0 0 1 0 1.5h-6v6a.75.75 0 0 1-1.5 0v-6h-6a.75.75 0 0 1 0-1.5h6v-6a.75.75 0 0 1 .75-.75Z" /></svg>`;
                 ps_addExcludeBtn.onclick = ps_addFilterKeyword;
                 exclusionInputGroup.appendChild(ps_excludeInput);
                 exclusionInputGroup.appendChild(ps_addExcludeBtn);
                 ps_exclusionTagsDiv.appendChild(exclusionInputGroup);

                 const exclusionActionsDiv = document.createElement('div');
                 exclusionActionsDiv.className = 'psExclusionActions';

                 const exportBtn = document.createElement('button');
                 exportBtn.id = 'psExportExclusionsBtn';
                 exportBtn.className = 'platiSearchBtn psExclusionActionBtn';
                 exportBtn.title = 'Экспорт списка исключений';
                 exportBtn.innerHTML = '←'
                 exportBtn.onclick = ps_exportExclusions;
                 exclusionActionsDiv.appendChild(exportBtn);

                 const importBtn = document.createElement('button');
                 importBtn.id = 'psImportExclusionsBtn';
                 importBtn.className = 'platiSearchBtn psExclusionActionBtn';
                 importBtn.title = 'Импорт списка исключений';
                 importBtn.innerHTML = '→';
                 importBtn.onclick = ps_showImportModal;
                 exclusionActionsDiv.appendChild(importBtn);

                 ps_exclusionTagsDiv.appendChild(exclusionActionsDiv);

                 ps_exclusionTagsListDiv = document.createElement('div');
                 ps_exclusionTagsListDiv.id = 'platiExclusionTagsList';
                 ps_exclusionTagsDiv.appendChild(ps_exclusionTagsListDiv);
                 ps_modal.appendChild(ps_exclusionTagsDiv);

                 ps_closeBtn = document.createElement('button');
                 ps_closeBtn.id = 'platiSearchCloseBtn';
                 ps_closeBtn.innerHTML = '&times;';
                 ps_closeBtn.onclick = hidePlatiModal;
                 ps_modal.appendChild(ps_closeBtn);

                 document.body.appendChild(ps_modal);

                 // Назначение переменных элементам UI
                 ps_filterPriceMin = document.getElementById('psFilterPriceMin');
                 ps_filterPriceMax = document.getElementById('psFilterPriceMax');
                 ps_filterSalesMin = document.getElementById('psFilterSalesMin');
                 ps_filterSalesMax = document.getElementById('psFilterSalesMax');
                 ps_filterRatingMin = document.getElementById('psFilterRatingMin');
                 ps_filterRatingMax = document.getElementById('psFilterRatingMax');
                 ps_filterHideBadReviews = document.getElementById('psFilterHideBadReviews');
                 ps_filterHideReturns = document.getElementById('psFilterHideReturns');
                 ps_filterOnlyDiscount = document.getElementById('psFilterOnlyDiscount');
                 ps_filterDateSelect = document.getElementById('psFilterDateSelect');
                 ps_resetAllFiltersBtn = document.getElementById('psResetAllFiltersBtn');

                 ps_addFilterEventListeners();
                 applyLoadedFiltersToUI();
                 ps_updateSortButtonsState();

                 function handleEsc(event) {
                     if (event.key === 'Escape') {
                         const importModal = document.getElementById('psImportModal');
                         if (importModal) {
                             importModal.remove();
                         } else {
                             hidePlatiModal();
                         }
                     }
                 }
                 document.addEventListener('keydown', handleEsc);
                 ps_modal._escHandler = handleEsc;
            }

            function ps_createResetButtonHTML(filterKey) {
                 return `<button class="filterResetBtn" title="Сбросить фильтр" data-filter-key="${filterKey}"><svg viewBox="0 0 24 24"><path d="M13 3a9 9 0 0 0-9 9H1l3.89 3.89.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42A8.954 8.954 0 0 0 13 21a9 9 0 0 0 0-18zm-1 5v5l4.28 2.54.72-1.21-3.5-2.08V8H12z"></path></svg></button>`;
            }

            // --- Управление модальным окном ---
            function showPlatiModal() {
                 if (!ps_modal) createPlatiModal();
                 const gameName = getSteamGameName();
                 if (gameName && !ps_searchInput.value) { ps_searchInput.value = gameName; }

                 document.body.style.overflow = 'hidden';
                 ps_modal.style.display = 'block';
                 ps_modal.scrollTop = 0;

                 ps_renderExclusionTags();
                 applyLoadedFiltersToUI();
                 ps_updateFilterPlaceholders();
                 ps_updateSortButtonsState();

                 requestAnimationFrame(() => {
                    const header = document.getElementById('platiSearchHeader');
                    const headerRect = header ? header.getBoundingClientRect() : { bottom: PS_TOP_OFFSET_FOR_SIDE_PANELS };
                    const newTopOffset = headerRect.bottom + 5;
                    const availableHeight = `calc(100vh - ${newTopOffset}px - ${PS_BOTTOM_OFFSET_FOR_SIDE_PANELS}px)`;
                    if (ps_filtersPanel) { ps_filtersPanel.style.top = `${newTopOffset}px`; ps_filtersPanel.style.maxHeight = availableHeight;}
                    if (ps_exclusionTagsDiv) { ps_exclusionTagsDiv.style.top = `${newTopOffset}px`; ps_exclusionTagsDiv.style.maxHeight = availableHeight; }
                 });

                 if (ps_searchInput.value.trim()) { ps_triggerSearch(); }
                 else { ps_updateStatus('Введите запрос для поиска.'); }
            }
            function hidePlatiModal() {
                 if (ps_modal) {
                     ps_modal.style.display = 'none';
                     if (ps_suggestionsDiv) ps_suggestionsDiv.style.display = 'none';
                      if (ps_modal._escHandler) { document.removeEventListener('keydown', ps_modal._escHandler); delete ps_modal._escHandler; }
                 }
                 document.body.style.overflow = '';
            }

            // --- Обновление статуса ---
            function ps_updateStatus(message, isLoading = false) {
                if (ps_statusDiv) {
                    ps_statusDiv.innerHTML = message + (isLoading ? ' <span class="spinner"></span>' : '');
                    ps_statusDiv.style.display = 'block';
                    if(ps_currentResults.length === 0 && message && !isLoading) {
                        ps_resultsDiv.innerHTML = '';
                    }
                }
            }

            // --- Запуск поиска ---
            function ps_triggerSearch() {
                const query = ps_searchInput.value.trim();
                if (ps_suggestionsDiv) ps_suggestionsDiv.style.display = 'none';
                if (!query) {
                    ps_updateStatus('Пожалуйста, введите запрос.');
                    ps_currentResults = []; ps_renderResults(); return;
                }
                ps_currentResults = [];
                ps_resetSort(false);
                applyLoadedFiltersToUI();
                ps_renderResults();
                ps_updateStatus('Получение общего количества товаров...', true);
                ps_fetchTotalCount(query);
            }

            // --- Функции подсказок ---
            function ps_fetchSuggestions(query) {
                 const trimmedQuery = query.trim();
                 if (trimmedQuery.length < 2) {
                     if (ps_suggestionsDiv) { ps_suggestionsDiv.innerHTML = ''; ps_suggestionsDiv.style.display = 'none'; } return;
                 }
                 const params = new URLSearchParams({ q: trimmedQuery, v: 2 });
                 try { if (typeof plang !== 'undefined') params.append('lang', plang); if (typeof clientgeo !== 'undefined') params.append('geo', clientgeo); }
                 catch (e) { console.warn("PlatiSearch: Could not get plang/clientgeo for suggestions."); }

                 GM_xmlhttpRequest({
                     method: "GET", url: `${PS_SUGGEST_API_URL}?${params.toString()}`, timeout: 5000,
                     onload: function(response) {
                         try { ps_renderSuggestions(JSON.parse(response.responseText)); }
                         catch (e) { if (ps_suggestionsDiv) { ps_suggestionsDiv.innerHTML = ''; ps_suggestionsDiv.style.display = 'none'; } }
                     },
                     onerror: function(error) { if (ps_suggestionsDiv) { ps_suggestionsDiv.innerHTML = ''; ps_suggestionsDiv.style.display = 'none'; } },
                     ontimeout: function() { if (ps_suggestionsDiv) { ps_suggestionsDiv.innerHTML = ''; ps_suggestionsDiv.style.display = 'none'; } }
                 });
            }
            function ps_renderSuggestions(suggestions) {
                 if (!ps_suggestionsDiv) return;
                 if (!suggestions || !Array.isArray(suggestions) || suggestions.length === 0) {
                     ps_suggestionsDiv.innerHTML = ''; ps_suggestionsDiv.style.display = 'none'; return;
                 }
                 ps_suggestionsDiv.innerHTML = '';
                 let addedSuggestions = 0;
                 suggestions.forEach(suggestion => {
                     if (suggestion && suggestion.name && (suggestion.type === "Товары" || suggestion.type === "Search" || suggestion.type === "Игры")) {
                         const item = document.createElement('div');
                         item.className = 'suggestionItem';
                         item.textContent = suggestion.name;
                         item.onmousedown = (e) => {
                             e.preventDefault(); ps_searchInput.value = suggestion.name;
                             ps_suggestionsDiv.style.display = 'none'; ps_triggerSearch();
                         };
                         ps_suggestionsDiv.appendChild(item);
                         addedSuggestions++;
                     }
                 });
                 ps_suggestionsDiv.style.display = addedSuggestions > 0 ? 'block' : 'none';
            }

            // --- Запросы API ---
            function ps_fetchTotalCount(query) {
                 const params = new URLSearchParams({
                     query: query, searchmode: 10, sortmode: PS_DEFAULT_SORT_MODE,
                     pagesize: PS_RESULTS_PER_PAGE_CHECK, pagenum: 1, owner: 1,
                     details: 1, checkhidesales: 1, host: 'plati.market'
                 });
                 GM_xmlhttpRequest({
                     method: "GET", url: `${PS_API_BASE_URL}?${params.toString()}`, timeout: 15000, responseType: 'json',
                     onload: function(response) {
                         if (response.status >= 200 && response.status < 400 && response.response) {
                             const data = response.response;
                             if (data?.result?.total > 0) {
                                 const total = data.result.total;
                                 ps_updateStatus(`Найдено ${total} товаров. Загрузка...`, true);
                                 ps_fetchAllResults(query, total, PS_DEFAULT_SORT_MODE);
                             } else {
                                 ps_updateStatus(`По запросу "${query}" ничего не найдено.`);
                                 ps_currentResults = []; ps_renderResults(); ps_updateFilterPlaceholders(); ps_applyFilters();
                             }
                         } else { ps_updateStatus(`Ошибка получения общего количества товаров (Статус: ${response.status})`); }
                     },
                     onerror: function(error) { ps_updateStatus('Ошибка сети при получении общего количества товаров.'); },
                     ontimeout: function() { ps_updateStatus('Время ожидания ответа от сервера (количество) истекло.'); }
                 });
            }
            function ps_fetchAllResults(query, total, sortMode) {
                 const MAX_PAGE_SIZE = 1000;
                 const effectivePageSize = Math.min(total, MAX_PAGE_SIZE);
                 if (total > MAX_PAGE_SIZE) ps_updateStatus(`Найдено ${total} товаров. Загрузка первых ${MAX_PAGE_SIZE}...`, true);

                 const params = new URLSearchParams({
                     query: query, searchmode: 10, sortmode: sortMode, pagesize: effectivePageSize,
                     pagenum: 1, owner: 1, details: 1, checkhidesales: 1, host: 'plati.market'
                 });
                 GM_xmlhttpRequest({
                     method: "GET", url: `${PS_API_BASE_URL}?${params.toString()}`, timeout: 90000, responseType: 'json',
                     onload: function(response) {
                          if (!document.body.contains(ps_modal)) return;

                         if (response.status >= 200 && response.status < 400 && response.response) {
                             const data = response.response;
                             if (data?.items?.item && Array.isArray(data.items.item)) {
                                 ps_currentResults = data.items.item.map((item, index) => ({ ...item, originalIndex: index }));
                                 const loadedCount = ps_currentResults.length;
                                 ps_updateStatus(`Загружено ${loadedCount}${total > loadedCount ? ` из ${total}` : ''} товаров.`);
                                 ps_applySort(ps_currentSort.field, ps_currentSort.direction);
                                 ps_renderResults();
                                 ps_updateFilterPlaceholders();
                                 ps_applyFilters();
                             } else {
                                 ps_updateStatus(`Ошибка загрузки товаров: неверный формат ответа API.`);
                                 ps_currentResults = []; ps_renderResults(); ps_updateFilterPlaceholders(); ps_applyFilters();
                             }
                         } else { ps_updateStatus(`Ошибка загрузки товаров (Статус: ${response.status})`); }
                     },
                     onerror: function(error) { if (document.body.contains(ps_modal)) ps_updateStatus('Ошибка сети при загрузке товаров.'); },
                     ontimeout: function() { if (document.body.contains(ps_modal)) ps_updateStatus('Время ожидания ответа от сервера (товары) истекло.'); }
                 });
            }

            // --- Сортировка ---
             function ps_handleSort(field) {
                 let newDirection;
                 const sortInfo = ps_advancedSorts[field];
                 if (!sortInfo) return;

                 let currentDir = (ps_currentSort.field === field) ? ps_currentSort.direction : sortInfo.defaultDir;

                 if (ps_firstSortClick[field] || ps_currentSort.field !== field) {
                     newDirection = sortInfo.defaultDir;
                 } else {
                     newDirection = currentDir === 'desc' ? 'asc' : 'desc';
                 }

                 Object.keys(ps_firstSortClick).forEach(key => {
                     ps_firstSortClick[key] = (key !== field);
                 });
                 ps_firstSortClick[field] = false;

                 ps_currentSort.field = field;
                 ps_currentSort.direction = newDirection;
                 GM_setValue(PS_LAST_SORT_STORAGE_KEY, ps_currentSort);

                 ps_applySort(field, newDirection);
                 ps_renderResults();
                 ps_updateSortButtonsState();
             }

             function ps_updateSortButtonsState() {
                 const activeField = ps_currentSort.field;
                 const activeDirection = ps_currentSort.direction;

                  $(ps_sortPriceBtn).add(ps_sortSalesBtn).each(function() {
                     const $btn = $(this);
                     const btnField = $btn.data('sort');
                     const baseText = (btnField === 'price') ? 'Цена' : 'Продажи';
                     if (btnField === activeField) {
                         const arrow = activeDirection === 'asc' ? ' ▲' : ' ▼';
                         $btn.addClass('active').text(baseText + arrow).attr('data-dir', activeDirection);
                     } else {
                         const defaultDir = ps_advancedSorts[btnField].defaultDir;
                         const defaultArrow = defaultDir === 'asc' ? ' ▲' : ' ▼';
                         $btn.removeClass('active').text(baseText + defaultArrow).attr('data-dir', defaultDir);
                     }
                 });

                 let advBtnText = 'Доп. сорт.';
                 const $advButton = $(ps_advSortBtn);
                 const isAdvSortActive = ps_advancedSorts[activeField] && activeField !== 'price' && activeField !== 'sales' && activeField !== 'relevance';

                 if (isAdvSortActive) {
                     $advButton.addClass('active');
                     const arrow = activeDirection === 'asc' ? ' ▲' : ' ▼';
                     advBtnText = `${ps_advancedSorts[activeField].name}${arrow}`;
                 } else {
                     $advButton.removeClass('active');
                 }
                 $advButton.text(advBtnText);

                 $('#platiSearchAdvSortMenu .platiSearchSortMenuItem').each(function() {
                     const $item = $(this);
                     const itemField = $item.data('sort');
                     const baseText = ps_advancedSorts[itemField].name;
                     if (itemField === activeField) {
                         const arrow = activeDirection === 'asc' ? ' ▲' : ' ▼';
                         $item.addClass('active').html(`${baseText} <span class="sortArrow">${arrow}</span>`).attr('data-dir', activeDirection);
                     } else {
                         const defaultDir = ps_advancedSorts[itemField].defaultDir;
                         const defaultArrow = defaultDir === 'asc' ? ' ▲' : ' ▼';
                         $item.removeClass('active').html(`${baseText} <span class="sortArrow">${defaultArrow}</span>`).attr('data-dir', defaultDir);
                     }
                 });

                 if (activeField === 'relevance') {
                     $(ps_resetSortBtn).addClass('active');
                 } else {
                      $(ps_resetSortBtn).removeClass('active');
                 }
             }

            function ps_resetSort(render = true) {
                 ps_currentSort = { field: 'relevance', direction: 'asc' };
                 ps_firstSortClick = {
                     price: true, sales: true, relevance: false, name: true, date_create: true, discount: true,
                     seller_rating: true, review_ratio: true, good_reviews: true, bad_reviews: true, returns: true
                 };
                 GM_setValue(PS_LAST_SORT_STORAGE_KEY, ps_currentSort);
                 ps_updateSortButtonsState();

                 if (render) {
                     ps_applySort(ps_currentSort.field, ps_currentSort.direction);
                     ps_renderResults();
                 }
             }

            function ps_applySort(field, direction) {
                 const dirMultiplier = direction === 'asc' ? 1 : -1;
                 const selectedCurrency = ps_currencySelect ? ps_currencySelect.value.toUpperCase() : 'RUR';
                 ps_currentResults.sort((a, b) => {
                     let valA, valB;
                     const nameA = (a.name || '').toLowerCase();
                     const nameB = (b.name || '').toLowerCase();
                     const finalPriceA = getPriceInSelectedCurrency(a, selectedCurrency);
                     const finalPriceB = getPriceInSelectedCurrency(b, selectedCurrency);
                     let comparisonResult = 0;
                     switch (field) {
                         case 'price':         valA = finalPriceA; valB = finalPriceB; break;
                         case 'sales':         valA = formatSales(a.cnt_sell); valB = formatSales(b.cnt_sell); break;
                         case 'name':          comparisonResult = nameA.localeCompare(nameB) * dirMultiplier; break;
                         case 'date_create':   valA = parseDate(a.date_create); valB = parseDate(b.date_create); break;
                         case 'discount':      valA = parseInt(a.discount || '0', 10); valB = parseInt(b.discount || '0', 10); break;
                         case 'seller_rating': valA = parseSellerRating(a.seller_rating); valB = parseSellerRating(b.seller_rating); break;
                         case 'review_ratio':  valA = calculateReviewRatio(a); valB = calculateReviewRatio(b); break;
                         case 'good_reviews':  valA = parseInt(a.cnt_good_responses || '0', 10); valB = parseInt(b.cnt_good_responses || '0', 10); break;
                         case 'bad_reviews':   valA = parseInt(a.cnt_bad_responses || '0', 10); valB = parseInt(b.cnt_bad_responses || '0', 10); break;
                         case 'returns':       valA = parseInt(a.cnt_return || '0', 10); valB = parseInt(b.cnt_return || '0', 10); break;
                         case 'relevance':     valA = a.originalIndex; valB = b.originalIndex; break;
                         default: return 0;
                     }
                     if (field !== 'name') {
                         const fallbackAsc = Infinity; const fallbackDesc = -Infinity;
                         if (valA === null || valA === undefined || isNaN(valA) || valA === Infinity || valA === -Infinity) valA = direction === 'asc' ? fallbackAsc : fallbackDesc;
                         if (valB === null || valB === undefined || isNaN(valB) || valB === Infinity || valB === -Infinity) valB = direction === 'asc' ? fallbackAsc : fallbackDesc;
                         if (valA < valB) comparisonResult = -1; else if (valA > valB) comparisonResult = 1; else comparisonResult = 0;
                         comparisonResult *= dirMultiplier;
                     }
                     if (comparisonResult === 0) {
                         if (field !== 'name') { let nameCompare = nameA.localeCompare(nameB); if (nameCompare !== 0) return nameCompare; }
                         if (field !== 'price') { if (finalPriceA < finalPriceB) return -1; if (finalPriceA > finalPriceB) return 1; }
                         if (field !== 'relevance') { return a.originalIndex - b.originalIndex; }
                     }
                     return comparisonResult;
                 });
            }

            // --- Управление фильтрами ---
            function ps_getFilterStorageKey(key) {
                return `${PS_FILTER_STORAGE_PREFIX}${key}`;
            }

            function ps_loadFilters() {
                const defaults = {
                    priceMin: '',
                    priceMax: '',
                    salesMin: '',
                    salesMax: '',
                    ratingMin: '',
                    ratingMax: '',
                    hideBadReviews: false,
                    hideReturns: false,
                    onlyDiscount: false,
                    date: 'all'
                };
                let loaded = {};
                for (const key in defaults) {
                    loaded[key] = GM_getValue(ps_getFilterStorageKey(key), defaults[key]);
                }
                return loaded;
            }

            function ps_saveFilter(key, value) {
                ps_currentFilters[key] = value;
                GM_setValue(ps_getFilterStorageKey(key), value);
            }

            function applyLoadedFiltersToUI() {
                if (!ps_filtersPanel) return;
                ps_filterPriceMin.value = ps_currentFilters.priceMin;
                ps_filterPriceMax.value = ps_currentFilters.priceMax;
                ps_filterSalesMin.value = ps_currentFilters.salesMin;
                ps_filterSalesMax.value = ps_currentFilters.salesMax;
                ps_filterRatingMin.value = ps_currentFilters.ratingMin;
                ps_filterRatingMax.value = ps_currentFilters.ratingMax;
                ps_filterHideBadReviews.checked = ps_currentFilters.hideBadReviews;
                ps_filterHideReturns.checked = ps_currentFilters.hideReturns;
                ps_filterOnlyDiscount.checked = ps_currentFilters.onlyDiscount;
                ps_filterDateSelect.value = ps_currentFilters.date;
                const priceHeader = ps_filtersPanel.querySelector('.filterGroup h4');
                if (priceHeader && priceHeader.textContent.includes('Цена')) {
                    priceHeader.innerHTML = `Цена (${ps_currentCurrency}) ${ps_createResetButtonHTML('price')}`;
                    const resetButton = priceHeader.querySelector('.filterResetBtn');
                    if (resetButton) resetButton.onclick = ps_handleFilterReset;
                }
            }

            function ps_addFilterEventListeners() {
                if (!ps_filtersPanel) return;
                const debouncedApply = debounce(ps_applyFilters, PS_FILTER_DEBOUNCE_MS);
                ps_filterPriceMin.addEventListener('input', (e) => {
                    ps_saveFilter('priceMin', e.target.value);
                    debouncedApply();
                });
                ps_filterPriceMax.addEventListener('input', (e) => {
                    ps_saveFilter('priceMax', e.target.value);
                    debouncedApply();
                });
                ps_filterSalesMin.addEventListener('input', (e) => {
                    ps_saveFilter('salesMin', e.target.value);
                    debouncedApply();
                });
                ps_filterSalesMax.addEventListener('input', (e) => {
                    ps_saveFilter('salesMax', e.target.value);
                    debouncedApply();
                });
                ps_filterRatingMin.addEventListener('input', (e) => {
                    ps_saveFilter('ratingMin', e.target.value);
                    debouncedApply();
                });
                ps_filterRatingMax.addEventListener('input', (e) => {
                    ps_saveFilter('ratingMax', e.target.value);
                    debouncedApply();
                });
                ps_filterHideBadReviews.addEventListener('change', (e) => {
                    ps_saveFilter('hideBadReviews', e.target.checked);
                    ps_applyFilters();
                });
                ps_filterHideReturns.addEventListener('change', (e) => {
                    ps_saveFilter('hideReturns', e.target.checked);
                    ps_applyFilters();
                });
                ps_filterOnlyDiscount.addEventListener('change', (e) => {
                    ps_saveFilter('onlyDiscount', e.target.checked);
                    ps_applyFilters();
                });
                ps_filterDateSelect.addEventListener('change', (e) => {
                    ps_saveFilter('date', e.target.value);
                    ps_applyFilters();
                });
                ps_resetAllFiltersBtn.addEventListener('click', () => ps_resetAllFilters(true));
                ps_filtersPanel.querySelectorAll('.filterResetBtn').forEach(btn => {
                    btn.onclick = ps_handleFilterReset;
                });
            }

            function ps_handleFilterReset(event) {
                ps_resetFilterByKey(event.currentTarget.dataset.filterKey, true);
            }

            function ps_resetFilterByKey(key, apply = true) {
                switch (key) {
                    case 'price':
                        ps_saveFilter('priceMin', '');
                        if (ps_filterPriceMin) ps_filterPriceMin.value = '';
                        ps_saveFilter('priceMax', '');
                        if (ps_filterPriceMax) ps_filterPriceMax.value = '';
                        break;
                    case 'sales':
                        ps_saveFilter('salesMin', '');
                        if (ps_filterSalesMin) ps_filterSalesMin.value = '';
                        ps_saveFilter('salesMax', '');
                        if (ps_filterSalesMax) ps_filterSalesMax.value = '';
                        break;
                    case 'rating':
                        ps_saveFilter('ratingMin', '');
                        if (ps_filterRatingMin) ps_filterRatingMin.value = '';
                        ps_saveFilter('ratingMax', '');
                        if (ps_filterRatingMax) ps_filterRatingMax.value = '';
                        break;
                    case 'options':
                        ps_saveFilter('hideBadReviews', false);
                        if (ps_filterHideBadReviews) ps_filterHideBadReviews.checked = false;
                        ps_saveFilter('hideReturns', false);
                        if (ps_filterHideReturns) ps_filterHideReturns.checked = false;
                        ps_saveFilter('onlyDiscount', false);
                        if (ps_filterOnlyDiscount) ps_filterOnlyDiscount.checked = false;
                        break;
                    case 'date':
                        ps_saveFilter('date', 'all');
                        if (ps_filterDateSelect) ps_filterDateSelect.value = 'all';
                        break;
                }
                if (apply) ps_applyFilters();
            }

            function ps_resetAllFilters(apply = true) {
                const filterKeys = ['price', 'sales', 'rating', 'options', 'date'];
                filterKeys.forEach(key => ps_resetFilterByKey(key, false));
                if (apply) ps_applyFilters();
            }

            function ps_updateFilterPlaceholders() {
                if (!ps_filtersPanel || !ps_currentResults || ps_currentResults.length === 0) {
                    $('#psFilterPriceMin, #psFilterPriceMax, #psFilterSalesMin, #psFilterSalesMax, #psFilterRatingMin, #psFilterRatingMax').attr('placeholder', '-');
                    return;
                }
                let minPrice = Infinity,
                    maxPrice = -Infinity,
                    minSales = Infinity,
                    maxSales = -Infinity,
                    minRating = Infinity,
                    maxRating = -Infinity;
                const selectedCurrency = ps_currencySelect ? ps_currencySelect.value.toUpperCase() : 'RUR';
                ps_currentResults.forEach(item => {
                    const price = getPriceInSelectedCurrency(item, selectedCurrency);
                    const sales = formatSales(item.cnt_sell);
                    const rating = parseSellerRating(item.seller_rating);
                    if (price !== Infinity && price < minPrice) minPrice = price;
                    if (price !== Infinity && price > maxPrice) maxPrice = price;
                    if (sales < minSales) minSales = sales;
                    if (sales > maxSales) maxSales = sales;
                    if (rating > 0 && rating < minRating) minRating = rating;
                    if (rating > maxRating) maxRating = rating;
                });
                if (minRating === Infinity) minRating = 0;
                if (ps_filterPriceMin) ps_filterPriceMin.placeholder = minPrice === Infinity ? '-' : `от ${Math.floor(minPrice)}`;
                if (ps_filterPriceMax) ps_filterPriceMax.placeholder = maxPrice === -Infinity ? '-' : `до ${Math.ceil(maxPrice)}`;
                if (ps_filterSalesMin) ps_filterSalesMin.placeholder = minSales === Infinity ? '-' : `от ${minSales}`;
                if (ps_filterSalesMax) ps_filterSalesMax.placeholder = maxSales === -Infinity ? '-' : `до ${maxSales}`;
                if (ps_filterRatingMin) ps_filterRatingMin.placeholder = minRating === Infinity ? '-' : `от ${minRating.toFixed(1)}`;
                if (ps_filterRatingMax) ps_filterRatingMax.placeholder = maxRating === -Infinity ? '-' : `до ${maxRating.toFixed(1)}`;
            }

            function ps_getDateThreshold(periodKey) {
                const now = Date.now();
                let threshold = 0;
                const dayMs = 86400000;
                switch (periodKey) {
                    case '1d':
                        threshold = now - 1 * dayMs;
                        break;
                    case '2d':
                        threshold = now - 2 * dayMs;
                        break;
                    case '1w':
                        threshold = now - 7 * dayMs;
                        break;
                    case '1m':
                        threshold = now - 30 * dayMs;
                        break;
                    case '6m':
                        threshold = now - 182 * dayMs;
                        break;
                    case '1y':
                        threshold = now - 365 * dayMs;
                        break;
                    case '5y':
                        threshold = now - 5 * 365 * dayMs;
                        break;
                    case '10y':
                        threshold = now - 10 * 365 * dayMs;
                        break;
                    default:
                        threshold = 0;
                        break;
                }
                return threshold;
            }

            function ps_applyFilters() {
                if (!ps_resultsDiv || !ps_currentResults) return;
                const keywords = ps_exclusionKeywords.map(k => k.toLowerCase());
                const pMin = parseFloat(ps_currentFilters.priceMin) || 0;
                const pMax = parseFloat(ps_currentFilters.priceMax) || Infinity;
                const sMin = parseInt(ps_currentFilters.salesMin, 10) || 0;
                const sMax = parseInt(ps_currentFilters.salesMax, 10) || Infinity;
                const rMin = parseFloat(ps_currentFilters.ratingMin) || 0;
                const rMax = parseFloat(ps_currentFilters.ratingMax) || Infinity;
                const hideBad = ps_currentFilters.hideBadReviews;
                const hideRet = ps_currentFilters.hideReturns;
                const onlyDisc = ps_currentFilters.onlyDiscount;
                const datePeriod = ps_currentFilters.date;
                const dateThreshold = ps_getDateThreshold(datePeriod);
                const selectedCurrency = ps_currencySelect ? ps_currencySelect.value.toUpperCase() : 'RUR';
                let visibleCount = 0;
                const items = ps_resultsDiv.querySelectorAll('.platiSearchItem');
                items.forEach(itemElement => {
                    const itemId = itemElement.dataset.id;
                    const itemData = ps_currentResults.find(r => r.id === itemId);
                    if (!itemData) {
                        itemElement.classList.add('hidden-by-filter');
                        return;
                    }
                    let shouldHide = false;
                    if (!shouldHide && keywords.length > 0) {
                        const title = (itemData.name || '').toLowerCase();
                        const seller = (itemData.seller_name || '').toLowerCase();
                        if (keywords.some(keyword => (title + ' ' + seller).includes(keyword))) {
                            shouldHide = true;
                        }
                    }
                    if (!shouldHide) {
                        const price = getPriceInSelectedCurrency(itemData, selectedCurrency);
                        if (price < pMin || price > pMax) {
                            shouldHide = true;
                        }
                    }
                    if (!shouldHide) {
                        const sales = formatSales(itemData.cnt_sell);
                        if (sales < sMin || sales > sMax) {
                            shouldHide = true;
                        }
                    }
                    if (!shouldHide) {
                        const rating = parseSellerRating(itemData.seller_rating);
                        if ((rating === 0 && (rMin > 0 || rMax < Infinity)) || rating < rMin || rating > rMax) {
                            shouldHide = true;
                        }
                    }
                    if (!shouldHide && hideBad) {
                        if (parseInt(itemData.cnt_bad_responses || '0', 10) > 0) {
                            shouldHide = true;
                        }
                    }
                    if (!shouldHide && hideRet) {
                        if (parseInt(itemData.cnt_return || '0', 10) > 0) {
                            shouldHide = true;
                        }
                    }
                    if (!shouldHide && onlyDisc) {
                        if (parseInt(itemData.discount || '0', 10) <= 0) {
                            shouldHide = true;
                        }
                    }
                    if (!shouldHide && dateThreshold > 0) {
                        const itemDate = parseDate(itemData.date_create);
                        if (!itemDate || itemDate < dateThreshold) {
                            shouldHide = true;
                        }
                    }
                    if (shouldHide) {
                        itemElement.classList.add('hidden-by-filter');
                    } else {
                        itemElement.classList.remove('hidden-by-filter');
                        visibleCount++;
                    }
                });
                const totalLoadedCount = ps_currentResults.length;
                const anyFilterActive = pMin > 0 || pMax < Infinity || sMin > 0 || sMax < Infinity || rMin > 0 || rMax < Infinity || hideBad || hideRet || onlyDisc || datePeriod !== 'all' || keywords.length > 0;
                if (totalLoadedCount > 0) {
                    if (anyFilterActive) {
                        ps_updateStatus(`Показано ${visibleCount} из ${totalLoadedCount} товаров (фильтры/исключения применены).`);
                    } else {
                        ps_updateStatus(`Загружено ${totalLoadedCount} товаров.`);
                    }
                } else if (ps_searchInput && ps_searchInput.value.trim()) {} else {
                    ps_updateStatus(`Введите запрос для поиска.`);
                }
                if (visibleCount === 0 && totalLoadedCount > 0 && anyFilterActive) {
                    ps_statusDiv.textContent += ' Нет товаров, соответствующих критериям.';
                    ps_statusDiv.style.display = 'block';
                } else if (totalLoadedCount === 0 && ps_searchInput && ps_searchInput.value.trim()) {
                    ps_statusDiv.style.display = 'block';
                }
            }

            // --- Фильтрация исключений ---
            function ps_addFilterKeyword() {
                const keyword = ps_excludeInput.value.trim().toLowerCase();
                if (keyword && !ps_exclusionKeywords.includes(keyword)) {
                    ps_exclusionKeywords.push(keyword);
                    GM_setValue(PS_EXCLUSION_STORAGE_KEY, ps_exclusionKeywords);
                    ps_excludeInput.value = '';
                    ps_renderExclusionTags();
                    ps_applyFilters();
                }
            }

            function ps_removeFilterKeyword(keywordToRemove) {
                ps_exclusionKeywords = ps_exclusionKeywords.filter(k => k !== keywordToRemove);
                GM_setValue(PS_EXCLUSION_STORAGE_KEY, ps_exclusionKeywords);
                ps_renderExclusionTags();
                ps_applyFilters();
            }

            function ps_renderExclusionTags() {
                if (!ps_exclusionTagsListDiv) return;
                ps_exclusionTagsListDiv.innerHTML = '';
                ps_exclusionKeywords.forEach(keyword => {
                    const tag = document.createElement('span');
                    tag.className = 'exclusionTag';
                    tag.textContent = keyword;
                    tag.title = `Удалить "${keyword}"`;
                    tag.onclick = () => ps_removeFilterKeyword(keyword);
                    ps_exclusionTagsListDiv.appendChild(tag);
                });
            }

            // --- Рендеринг результатов ---
             function ps_renderResults() {
                 if (!ps_resultsDiv) return;
                 ps_resultsDiv.innerHTML = '';
                 if (ps_currentResults.length === 0) {
                     ps_applyFilters();
                     return;
                 }

                 const fragment = document.createDocumentFragment();
                 const now = Date.now();
                 const thresholdTime = now - NEW_ITEM_THRESHOLD_DAYS * 24 * 60 * 60 * 1000;
                 const selectedCurrency = ps_currencySelect ? ps_currencySelect.value.toUpperCase() : 'RUR';

                 ps_currentResults.forEach(item => {
                     const itemDiv = document.createElement('div');
                     itemDiv.className = 'platiSearchItem';
                     itemDiv.dataset.id = item.id;
                     const link = document.createElement('a');

                     const baseUrl = item.url || `https://plati.market/itm/${item.id}`;
                     link.href = baseUrl + '?ai=234029';

                     link.target = '_blank';
                     link.rel = 'noopener noreferrer nofollow';
                     const imageWrapper = document.createElement('div');
                     imageWrapper.className = 'card-image-wrapper';
                     const img = document.createElement('img');
                     const imgSrc = `https://${PS_IMAGE_DOMAIN}/imgwebp.ashx?id_d=${item.id}&w=164&h=164&dc=${item.ticks_last_change || Date.now()}`;
                     img.src = imgSrc;
                     img.alt = item.name || 'Изображение товара';
                     img.loading = 'lazy';
                     img.onerror = function() {
                         this.onerror = null;
                         this.src = 'https://plati.market/images/logo-plati.png';
                         this.style.objectFit = 'contain';
                     };
                     imageWrapper.appendChild(img);
                     const itemDate = parseDate(item.date_create);
                     if (itemDate && itemDate > thresholdTime) {
                         const newBadge = document.createElement('span');
                         newBadge.className = 'newItemBadge';
                         newBadge.textContent = 'New';
                         imageWrapper.appendChild(newBadge);
                     }
                     link.appendChild(imageWrapper);
                     const priceDiv = document.createElement('div');
                     priceDiv.className = 'price';
                     let displayPrice = getPriceInSelectedCurrency(item, selectedCurrency);
                     let currencySymbol;
                     switch (selectedCurrency) {
                         case 'USD':
                             currencySymbol = '$';
                             break;
                         case 'EUR':
                             currencySymbol = '€';
                             break;
                         case 'UAH':
                             currencySymbol = '₴';
                             break;
                         default:
                             currencySymbol = '₽';
                             break;
                     }
                     priceDiv.textContent = displayPrice !== Infinity ? `${displayPrice.toLocaleString('ru-RU', {minimumFractionDigits: 0, maximumFractionDigits: 2})} ${currencySymbol}` : 'Нет цены';
                     priceDiv.title = `Цена в ${selectedCurrency}`;
                     link.appendChild(priceDiv);
                     const titleDiv = document.createElement('div');
                     titleDiv.className = 'title';
                     titleDiv.textContent = item.name || 'Без названия';
                     titleDiv.title = item.name || 'Без названия';
                     link.appendChild(titleDiv);
                     const infoContainer = document.createElement('div');
                     infoContainer.className = 'cardInfoContainer';
                     const infoRow1 = document.createElement('div');
                     infoRow1.className = 'cardInfoRow1';
                     const infoRow2 = document.createElement('div');
                     infoRow2.className = 'cardInfoRow2';
                     const ratingVal = parseSellerRating(item.seller_rating);
                     const goodRev = parseInt(item.cnt_good_responses || '0');
                     const badRev = parseInt(item.cnt_bad_responses || '0');
                     const returns = parseInt(item.cnt_return || '0');
                     let salesCount = formatSales(item.cnt_sell);
                     infoRow1.innerHTML = `<span title="Рейтинг продавца">Рейт: ${ratingVal > 0 ? ratingVal.toLocaleString('ru-RU', {maximumFractionDigits: 0}) : 'N/A'}</span><span title="Отзывы (Хорошие/Плохие)">Отз: <span class="reviewsGood">${goodRev}</span>${badRev > 0 ? '/<span class="reviewsBad">' + badRev + '</span>' : ''}</span><span title="Возвраты">Возв: ${returns}</span>`;
                     infoRow2.innerHTML = `<span class="sales" title="Продажи">Прод: ${salesCount > 0 ? salesCount.toLocaleString('ru-RU') : '0'}</span><span class="dateAdded" title="Дата добавления">Доб: ${formatDateString(itemDate)}</span>`;
                     infoContainer.appendChild(infoRow1);
                     infoContainer.appendChild(infoRow2);
                     const sellerLink = document.createElement('a');
                     sellerLink.className = 'sellerLink';
                     sellerLink.textContent = `Продавец: ${item.seller_name || 'N/A'}`;
                     sellerLink.title = `Перейти к продавцу: ${item.seller_name || 'N/A'}`;
                     if (item.seller_id && item.seller_name) {
                         const safeSellerName = encodeURIComponent(item.seller_name.replace(/[^a-zA-Z0-9_\-.~]/g, '-')).replace(/%2F/g, '/');
                         sellerLink.href = `https://plati.market/seller/${safeSellerName}/${item.seller_id}/`;
                         sellerLink.target = '_blank';
                         sellerLink.rel = 'noopener noreferrer nofollow';
                         sellerLink.onclick = (e) => {
                             e.stopPropagation();
                         };
                     } else {
                         sellerLink.style.pointerEvents = 'none';
                     }
                     infoContainer.appendChild(sellerLink);
                     link.appendChild(infoContainer);
                     const buyButtonDiv = document.createElement('div');
                     buyButtonDiv.className = 'buyButton';
                     buyButtonDiv.textContent = 'Перейти';
                     link.appendChild(buyButtonDiv);
                     itemDiv.appendChild(link);
                     fragment.appendChild(itemDiv);
                 });
                 ps_resultsDiv.appendChild(fragment);
                 ps_applyFilters();
             }

            // --- Обработчики UI ---
            function ps_handleCurrencyChange() {
                ps_currentCurrency = ps_currencySelect.value.toUpperCase();
                GM_setValue(PS_CURRENCY_STORAGE_KEY, ps_currentCurrency);
                applyLoadedFiltersToUI();
                ps_updateFilterPlaceholders();
                if (ps_currentSort.field === 'price') {
                    ps_applySort(ps_currentSort.field, ps_currentSort.direction);
                }
                ps_renderResults();
            }

            // --- Добавление кнопки Plati ---
            function addPlatiButton() {
                const actionsContainer = document.querySelector('#queueActionsCtn');

                if (!actionsContainer || actionsContainer.querySelector('.plati_price_button')) {
                    return;
                }

                const ignoreButtonContainer = actionsContainer.querySelector('#ignoreBtn');

                const platiContainer = document.createElement('div');
                platiContainer.className = 'plati_price_button queue_control_button';
                platiContainer.style.marginLeft = '3px';
                platiContainer.innerHTML = `<div class="btnv6_blue_hoverfade btn_medium" style="height: 32px; padding: 0 5px;" title="Найти на Plati.Market"><span>Plati</span></div>`;
                platiContainer.querySelector('div').addEventListener('click', (e) => {
                    e.preventDefault();
                    e.stopPropagation();
                    showPlatiModal();
                });

                if (ignoreButtonContainer) {
                    ignoreButtonContainer.insertAdjacentElement('afterend', platiContainer);
                } else {
                    actionsContainer.appendChild(platiContainer);
                }
            }

            // --- Стили ---
             function addPlatiStyles() {
                 GM_addStyle(`
                    /* Стили спиннера */
                    @keyframes platiSpin {
                    	0% {
                    		transform: rotate(0deg);
                    	}

                    	100% {
                    		transform: rotate(360deg);
                    	}
                    }

                    .spinner {
                    	border: 3px solid rgba(255, 255, 255, 0.3);
                    	border-radius: 50%;
                    	border-top-color: #fff;
                    	width: 1em;
                    	height: 1em;
                    	animation: platiSpin 1s linear infinite;
                    	display: inline-block;
                    	vertical-align: middle;
                    	margin-left: 5px;
                    }

                    .platiSearchBtn .spinner {
                    	width: 0.8em;
                    	height: 0.8em;
                    	border-width: 2px;
                    }

                    /* Стили модального окна */
                    #platiSearchModal {
                    	position: fixed;
                    	top: 0;
                    	left: 0;
                    	width: 100%;
                    	height: 100%;
                    	background-color: rgba(20, 20, 25, 0.98);
                    	z-index: 9999;
                    	display: none;
                    	color: #eee;
                    	font-family: "Motiva Sans", Sans-serif, Arial;
                    	overflow-y: auto;
                    	scrollbar-color: #67c1f5 #17202d;
                    	scrollbar-width: thin;
                    }

                    #platiSearchModal::-webkit-scrollbar {
                    	width: 8px;
                    }

                    #platiSearchModal::-webkit-scrollbar-track {
                    	background: #17202d;
                    	border-radius: 4px;
                    }

                    #platiSearchModal::-webkit-scrollbar-thumb {
                    	background-color: #4b6f9c;
                    	border-radius: 4px;
                    	border: 2px solid #17202d;
                    }

                    #platiSearchModal::-webkit-scrollbar-thumb:hover {
                    	background-color: #67c1f5;
                    }

                    #platiSearchModal * {
                    	box-sizing: border-box;
                    }

                    #platiSearchContainer {
                    	max-width: 1350px;
                    	margin: 0 auto;
                    	padding: 15px ${PS_SIDE_PANEL_HORIZONTAL_PADDING}px;
                    	position: relative;
                    	min-height: 100%;
                    }

                    #platiSearchCloseBtn {
                    	position: fixed;
                    	top: 15px;
                    	right: 20px;
                    	font-size: 35px;
                    	color: #aaa;
                    	background: none;
                    	border: none;
                    	cursor: pointer;
                    	line-height: 1;
                    	z-index: 10002;
                    	padding: 5px;
                    	transition: color 0.2s, transform 0.2s;
                    }

                    #platiSearchCloseBtn:hover {
                    	color: #fff;
                    	transform: scale(1.1);
                    }

                    /* Шапка */
                    #platiSearchHeader {
                    	display: flex;
                    	align-items: center;
                    	gap: 10px;
                    	margin-bottom: 15px;
                    	flex-wrap: wrap;
                    	position: relative;
                    	z-index: 5;
                    	border-bottom: 1px solid #444;
                    	padding-bottom: 15px;
                    	padding-left: ${PS_CONTENT_PADDING_LEFT}px;
                    	padding-right: ${PS_CONTENT_PADDING_RIGHT}px;
                    	margin-left: -${PS_CONTENT_PADDING_LEFT}px;
                    	margin-right: -${PS_CONTENT_PADDING_RIGHT}px;
                    	flex-shrink: 0;
                    }

                    .platiSearchInputContainer {
                    	position: relative;
                    	flex-grow: 0.7;
                    	min-width: 200px;
                    	flex-basis: 350px;
                    }

                    #platiSearchInput {
                    	width: 100%;
                    	padding: 10px 15px;
                    	font-size: 16px;
                    	background-color: #333;
                    	border: 1px solid #555;
                    	color: #eee;
                    	border-radius: 4px;
                    	height: 40px;
                    	outline: none;
                    }

                    #platiSearchInput:focus {
                    	border-color: #67c1f5;
                    }

                    #platiSearchSuggestions {
                    	position: absolute;
                    	top: 100%;
                    	left: 0;
                    	right: 0;
                    	background-color: #3a3a40;
                    	border: 1px solid #555;
                    	border-top: none;
                    	border-radius: 0 0 4px 4px;
                    	max-height: 300px;
                    	overflow-y: auto;
                    	z-index: 10000;
                    	display: none;
                    }

                    .suggestionItem {
                    	padding: 8px 15px;
                    	cursor: pointer;
                    	color: #eee;
                    	font-size: 14px;
                    	border-bottom: 1px solid #4a4a50;
                    }

                    .suggestionItem:last-child {
                    	border-bottom: none;
                    }

                    .suggestionItem:hover {
                    	background-color: #4a4a55;
                    }

                    /* Кнопки в шапке */
                    .platiSearchBtn {
                    	padding: 10px 15px;
                    	font-size: 14px;
                    	color: white;
                    	border: none;
                    	border-radius: 4px;
                    	cursor: pointer;
                    	white-space: nowrap;
                    	height: 40px;
                    	display: inline-flex;
                    	align-items: center;
                    	justify-content: center;
                    	flex-shrink: 0;
                    	background-color: #555;
                    	transition: background-color 0.2s;
                    }

                    .platiSearchBtn:hover:not(:disabled) {
                    	background-color: #666;
                    }

                    .platiSearchBtn:disabled {
                    	opacity: 0.6;
                    	cursor: default;
                    }

                    #platiSearchGoBtn {
                    	background-color: #4D88FF;
                    }

                    #platiSearchGoBtn:hover {
                    	background-color: #3366CC;
                    }

                    .platiSearchBtn.sortBtn.active {
                    	background-color: #007bff;
                    }

                    .platiSearchBtn.sortBtn.active:hover {
                    	background-color: #0056b3;
                    }

                    #platiResetSortBtn {
                    	background-color: #777;
                    	margin-right: 5px;
                    	padding: 0 10px;
                    }

                    #platiResetSortBtn:hover {
                    	background-color: #888;
                    }

                    #platiResetSortBtn svg {
                    	width: 16px;
                    	height: 16px;
                    	fill: currentColor;
                    }

                    #platiResetSortBtn.active {
                    	background-color: #007bff;
                    }

                    #platiSearchAdvSortBtnContainer {
                    	position: relative;
                    	flex-shrink: 0;
                    	width: ${PS_ADV_SORT_CONTAINER_WIDTH}px;
                    	display: flex;
                    	justify-content: center;
                    }

                    #platiSearchAdvSortBtn {
                    	width: 100%;
                    	justify-content: center;
                    	overflow: hidden;
                    	text-overflow: ellipsis;
                    }

                    #platiSearchCurrencySelect {
                    	margin-left: 10px;
                    	background-color: #333;
                    	color: #eee;
                    	border: 1px solid #555;
                    	border-radius: 4px;
                    	height: 40px;
                    	padding: 0 8px;
                    	font-size: 14px;
                    	cursor: pointer;
                    	flex-shrink: 0;
                    	outline: none;
                    }

                    #platiSearchCurrencySelect:focus {
                    	border-color: #67c1f5;
                    }

                    /* Меню доп сортировки */
                    #platiSearchAdvSortMenu {
                    	display: none;
                    	position: absolute;
                    	top: 100%;
                    	left: 0;
                    	background-color: #3a3a40;
                    	border: 1px solid #555;
                    	border-radius: 4px;
                    	min-width: 100%;
                    	z-index: 10001;
                    	padding: 5px 0;
                    	box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
                    }

                    #platiSearchAdvSortBtnContainer:hover #platiSearchAdvSortMenu {
                    	display: block;
                    }

                    .platiSearchSortMenuItem {
                    	display: block;
                    	padding: 8px 15px;
                    	color: #eee;
                    	font-size: 14px;
                    	cursor: pointer;
                    	white-space: nowrap;
                    	transition: background-color 0.1s;
                    }

                    .platiSearchSortMenuItem:hover {
                    	background-color: #4a4a55;
                    }

                    .platiSearchSortMenuItem.active {
                    	background-color: #007bff;
                    	color: white;
                    }

                    .platiSearchSortMenuItem .sortArrow {
                    	display: inline-block;
                    	margin-left: 5px;
                    	font-size: 12px;
                    }

                    /* Боковые панели */
                    #platiSearchFiltersPanel,
                    #platiSearchExclusionTags {
                    	position: fixed;
                    	top: ${PS_TOP_OFFSET_FOR_SIDE_PANELS}px;
                    	max-height: calc(100vh - ${PS_TOP_OFFSET_FOR_SIDE_PANELS}px - ${PS_BOTTOM_OFFSET_FOR_SIDE_PANELS}px);
                    	overflow-y: auto;
                    	z-index: 1000;
                    	padding: 10px;
                    	padding-right: 15px;
                    	scrollbar-width: thin;
                    	scrollbar-color: #555 #2a2a30;
                    	background-color: transparent;
                    	transition: top 0.2s ease-in-out;
                    }

                    #platiSearchFiltersPanel::-webkit-scrollbar,
                    #platiSearchExclusionTags::-webkit-scrollbar {
                    	width: 5px;
                    }

                    #platiSearchFiltersPanel::-webkit-scrollbar-track,
                    #platiSearchExclusionTags::-webkit-scrollbar-track {
                    	background: rgba(42, 42, 48, 0.5);
                    	border-radius: 3px;
                    }

                    #platiSearchFiltersPanel::-webkit-scrollbar-thumb,
                    #platiSearchExclusionTags::-webkit-scrollbar-thumb {
                    	background-color: rgba(85, 85, 85, 0.7);
                    	border-radius: 3px;
                    }

                    #platiSearchFiltersPanel {
                    	left: ${PS_SIDE_PANEL_HORIZONTAL_PADDING}px;
                    	width: ${PS_FILTER_PANEL_WIDTH}px;
                    }

                    #platiSearchExclusionTags {
                    	right: ${PS_SIDE_PANEL_HORIZONTAL_PADDING}px;
                    	width: ${PS_EXCLUSION_PANEL_WIDTH}px;
                    	display: flex;
                    	flex-direction: column;
                    	gap: 10px;
                    }

                    /* Фильтры */
                    .filterGroup {
                    	margin-bottom: 18px;
                    }

                    .filterGroup h4 {
                    	font-size: 15px;
                    	color: #ddd;
                    	margin-bottom: 8px;
                    	padding-bottom: 4px;
                    	display: flex;
                    	justify-content: space-between;
                    	align-items: center;
                    	text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.7);
                    	font-weight: 500;
                    }

                    .filterResetBtn {
                    	font-size: 12px;
                    	color: #aaa;
                    	background: none;
                    	border: none;
                    	cursor: pointer;
                    	padding: 0 3px;
                    	line-height: 1;
                    }

                    .filterResetBtn:hover {
                    	color: #fff;
                    }

                    .filterResetBtn svg {
                    	width: 14px;
                    	height: 14px;
                    	vertical-align: middle;
                    	fill: currentColor;
                    }

                    .filterRangeInputs {
                    	display: flex;
                    	gap: 8px;
                    	align-items: center;
                    }

                    .filterRangeInputs input[type="number"] {
                    	width: calc(50% - 4px);
                    	padding: 6px 8px;
                    	font-size: 13px;
                    	background-color: rgba(51, 51, 51, 0.85);
                    	border: 1px solid #666;
                    	color: #eee;
                    	border-radius: 3px;
                    	height: 30px;
                    	text-align: center;
                    	-moz-appearance: textfield;
                    	box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
                    	outline: none;
                    }

                    .filterRangeInputs input[type="number"]:focus {
                    	border-color: #67c1f5;
                    }

                    .filterRangeInputs input[type="number"]::-webkit-outer-spin-button,
                    .filterRangeInputs input[type="number"]::-webkit-inner-spin-button {
                    	-webkit-appearance: none;
                    	margin: 0;
                    }

                    .filterRangeInputs input[type="number"]::placeholder {
                    	color: #999;
                    	font-size: 11px;
                    	text-align: center;
                    }

                    .filterCheckbox {
                    	margin-bottom: 8px;
                    }

                    .filterCheckbox label {
                    	display: flex;
                    	align-items: center;
                    	font-size: 14px;
                    	cursor: pointer;
                    	color: #ccc;
                    	text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.7);
                    }

                    .filterCheckbox input[type="checkbox"] {
                    	margin-right: 8px;
                    	width: 16px;
                    	height: 16px;
                    	accent-color: #007bff;
                    	cursor: pointer;
                    	flex-shrink: 0;
                    }

                    .filterSelect select {
                    	width: 100%;
                    	padding: 6px 8px;
                    	font-size: 13px;
                    	background-color: rgba(51, 51, 51, 0.85);
                    	border: 1px solid #666;
                    	color: #eee;
                    	border-radius: 3px;
                    	height: 30px;
                    	box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
                    	outline: none;
                    }

                    .filterSelect select:focus {
                    	border-color: #67c1f5;
                    }

                    #psResetAllFiltersBtn {
                    	width: 100%;
                    	margin-top: 10px;
                    	padding: 8px 10px;
                    	height: auto;
                    	background-color: rgba(108, 117, 125, 0.8);
                    	border: 1px solid #888;
                    	text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.4);
                    }

                    #psResetAllFiltersBtn:hover {
                    	background-color: rgba(90, 98, 104, 0.9);
                    }

                    /* Исключения */
                    .exclusionInputGroup {
                    	display: flex;
                    	align-items: stretch;
                    	border: 1px solid #555;
                    	border-radius: 4px;
                    	background-color: rgba(51, 51, 51, 0.85);
                    	overflow: hidden;
                    	height: 34px;
                    	flex-shrink: 0;
                    	box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
                    }

                    .exclusionInputGroup #platiSearchExcludeInput {
                    	padding: 6px 10px;
                    	font-size: 13px;
                    	background-color: transparent;
                    	border: none;
                    	color: #eee;
                    	outline: none;
                    	border-radius: 0;
                    	flex-grow: 1;
                    	width: auto;
                    	height: auto;
                    }

                    .exclusionInputGroup #platiSearchExcludeInput:focus {
                    	box-shadow: none;
                    }

                    .exclusionInputGroup #platiSearchAddExcludeBtn {
                    	display: flex;
                    	align-items: center;
                    	justify-content: center;
                    	padding: 0 10px;
                    	background-color: #555;
                    	border: none;
                    	border-left: 1px solid #555;
                    	cursor: pointer;
                    	border-radius: 0;
                    	color: #eee;
                    	height: auto;
                    }

                    .exclusionInputGroup #platiSearchAddExcludeBtn:hover {
                    	background-color: #666;
                    }

                    .exclusionInputGroup #platiSearchAddExcludeBtn svg {
                    	width: 16px;
                    	height: 16px;
                    	fill: currentColor;
                    }

                    #platiExclusionTagsList {
                    	display: flex;
                    	flex-direction: row;
                    	flex-wrap: wrap;
                    	align-content: flex-start;
                    	gap: 8px;
                    	overflow-y: auto;
                    	flex-grow: 1;
                    }

                    .exclusionTag {
                    	display: inline-block;
                    	background-color: rgba(70, 70, 80, 0.9);
                    	color: #ddd;
                    	padding: 5px 10px;
                    	border-radius: 15px;
                    	font-size: 13px;
                    	cursor: pointer;
                    	transition: background-color 0.2s;
                    	border: 1px solid rgba(100, 100, 110, 0.9);
                    	white-space: nowrap;
                    	text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
                    }

                    .exclusionTag:hover {
                    	background-color: rgba(220, 53, 69, 0.9);
                    	border-color: rgba(200, 40, 50, 0.95);
                    	color: #fff;
                    }

                    .exclusionTag::after {
                    	content: ' ×';
                    	font-weight: bold;
                    	margin-left: 4px;
                    }

                    /* Результаты */
                    #platiSearchResultsContainer {
                    	position: relative;
                    	padding-left: ${PS_CONTENT_PADDING_LEFT}px;
                    	padding-right: ${PS_CONTENT_PADDING_RIGHT}px;
                    	margin-left: -${PS_CONTENT_PADDING_LEFT}px;
                    	margin-right: -${PS_CONTENT_PADDING_RIGHT}px;
                    }

                    #platiSearchResultsStatus {
                    	width: 100%;
                    	text-align: center;
                    	font-size: 18px;
                    	color: #aaa;
                    	padding: 50px 0;
                    	display: none;
                    	min-height: 100px;
                    	display: flex;
                    	align-items: center;
                    	justify-content: center;
                    	flex-direction: column;
                    }

                    #platiSearchResults {
                    	display: flex;
                    	flex-wrap: wrap;
                    	gap: 15px;
                    	justify-content: flex-start;
                    	padding-top: 10px;
                    }

                    /* Карточка товара */
                    .platiSearchItem {
                    	background-color: #2a2a30;
                    	border-radius: 8px;
                    	padding: 10px;
                    	width: calc(20% - 12px);
                    	min-width: 170px;
                    	display: flex;
                    	flex-direction: column;
                    	transition: transform 0.2s ease, box-shadow 0.2s ease;
                    	box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
                    	position: relative;
                    	color: #ccc;
                    	font-size: 13px;
                    	min-height: 340px;
                    	border: 1px solid transparent;
                    }

                    .platiSearchItem:hover {
                    	transform: translateY(-3px);
                    	box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);
                    	border-color: #4b6f9c;
                    }

                    .platiSearchItem.hidden-by-filter {
                    	display: none !important;
                    }

                    .platiSearchItem a {
                    	text-decoration: none;
                    	color: inherit;
                    	display: flex;
                    	flex-direction: column;
                    	height: 100%;
                    }

                    .platiSearchItem .card-image-wrapper {
                    	position: relative;
                    	width: 100%;
                    	aspect-ratio: 1 / 1;
                    	margin-bottom: 8px;
                    	background-color: #444;
                    	border-radius: 6px;
                    	overflow: hidden;
                    }

                    .platiSearchItem img {
                    	position: absolute;
                    	top: 0;
                    	left: 0;
                    	width: 100%;
                    	height: 100%;
                    	object-fit: cover;
                    	border-radius: 6px;
                    }

                    .newItemBadge {
                    	position: absolute;
                    	top: 4px;
                    	left: 4px;
                    	background-color: #f54848;
                    	color: white;
                    	padding: 1px 5px;
                    	font-size: 10px;
                    	border-radius: 3px;
                    	font-weight: bold;
                    	z-index: 1;
                    	text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
                    }

                    .platiSearchItem .price {
                    	font-size: 16px;
                    	font-weight: 700;
                    	color: #a4d007;
                    	margin-bottom: 5px;
                    }

                    .platiSearchItem .title {
                    	font-size: 13px;
                    	font-weight: 500;
                    	line-height: 1.3;
                    	height: 3.9em;
                    	overflow: hidden;
                    	text-overflow: ellipsis;
                    	margin-bottom: 6px;
                    	color: #eee;
                    	display: -webkit-box;
                    	-webkit-line-clamp: 3;
                    	-webkit-box-orient: vertical;
                    }

                    .cardInfoContainer {
                    	margin-top: auto;
                    	padding-top: 6px;
                    }

                    .cardInfoRow1,
                    .cardInfoRow2 {
                    	display: flex;
                    	justify-content: space-between;
                    	flex-wrap: nowrap;
                    	gap: 8px;
                    	font-size: 12px;
                    	color: #bbb;
                    	margin-bottom: 4px;
                    }

                    .cardInfoRow1 span,
                    .cardInfoRow2 span {
                    	white-space: nowrap;
                    	overflow: hidden;
                    	text-overflow: ellipsis;
                    	flex-shrink: 1;
                    }

                    .cardInfoRow1 span:first-child,
                    .cardInfoRow2 span:first-child {
                    	flex-shrink: 0;
                    	margin-right: auto;
                    }

                    .reviewsGood {
                    	color: #6cff5c;
                    	font-weight: bold;
                    }

                    .reviewsBad {
                    	color: #f54848;
                    	margin-left: 2px;
                    	font-weight: bold;
                    }

                    .sales {
                    	font-weight: bold;
                    	color: #eee;
                    }

                    .sellerLink {
                    	display: block;
                    	font-size: 12px;
                    	color: #bbb;
                    	text-decoration: none;
                    	margin-bottom: 4px;
                    	white-space: nowrap;
                    	overflow: hidden;
                    	text-overflow: ellipsis;
                    	transition: color 0.2s;
                    }

                    .sellerLink:hover {
                    	color: #ddd;
                    	text-decoration: underline;
                    }

                    .platiSearchItem .buyButton {
                    	display: block;
                    	text-align: center;
                    	padding: 8px;
                    	margin-top: 8px;
                    	background-color: #007bff;
                    	color: white;
                    	border-radius: 4px;
                    	font-size: 13px;
                    	font-weight: 600;
                    	transition: background-color 0.2s;
                    }

                    .platiSearchItem .buyButton:hover {
                    	background-color: #0056b3;
                    }

                    /* Адаптивность */
                    @media (max-width: 1650px) {
                    	.platiSearchItem {
                    		width: calc(20% - 12px);
                    	}
                    }

                    @media (max-width: 1400px) {
                    	.platiSearchItem {
                    		width: calc(25% - 12px);
                    	}
                    }

                    @media (max-width: 1100px) {
                    	.platiSearchItem {
                    		width: calc(33.33% - 10px);
                    	}
                    }

                    @media (max-width: 850px) {

                    	#platiSearchFiltersPanel,
                    	#platiSearchExclusionTags {
                    		display: none;
                    	}

                    	#platiSearchHeader,
                    	#platiSearchResultsContainer {
                    		padding-left: 15px;
                    		padding-right: 15px;
                    		margin-left: 0;
                    		margin-right: 0;
                    	}

                    	.platiSearchItem {
                    		width: calc(50% - 8px);
                    	}

                    	#platiSearchHeader {
                    		justify-content: center;
                    	}
                    }

                    @media (max-width: 600px) {
                    	.platiSearchItem {
                    		width: 100%;
                    		min-height: auto;
                    	}

                    	#platiSearchHeader {
                    		gap: 5px;
                    	}

                    	.platiSearchInputContainer {
                    		flex-basis: 100%;
                    		order: -1;
                    	}

                    	.platiSearchBtn,
                    	#platiSearchCurrencySelect,
                    	#platiSearchAdvSortBtnContainer {
                    		width: calc(33.3% - 4px);
                    		font-size: 13px;
                    		padding: 8px 5px;
                    		height: 36px;
                    	}

                    	#platiSearchAdvSortBtnContainer {
                    		width: calc(33.3% - 4px);
                    	}

                    	#platiSearchAdvSortBtn {
                    		width: 100%;
                    	}

                    	#platiSearchAdvSortMenu {
                    		min-width: 200px;
                    		left: 50%;
                    		transform: translateX(-50%);
                    	}

                    	#platiResetSortBtn {
                    		width: auto;
                    		padding: 0 8px;
                    	}
                    }

                    /* Стили для кнопки Plati на странице Steam */
                    .plati_price_button .btnv6_blue_hoverfade {
                    	margin: 0;
                    	padding: 0 15px;
                    	font-size: 15px;
                    	display: flex;
                    	align-items: center;
                    	transition: filter 0.2s;
                    }

                    .plati_price_button .btnv6_blue_hoverfade:hover {
                    	filter: brightness(1.1);
                    }

                    .psExclusionActions {
                        display: flex;
                        justify-content: flex-end;
                        gap: 8px;
                        margin-top: 10px;
                        padding-bottom: 10px;
                        border-bottom: 1px solid #444;
                    }

                    .psExclusionActionBtn {
                        padding: 0 8px;
                        height: 30px;
                        width: 40px;
                        background-color: #555;
                        border-color: #666;
                        font-size: 14px;
                        font-weight: bold;
                        line-height: 1;
                    }

                    #psImportModal {
                        position: fixed;
                        top: 0;
                        left: 0;
                        width: 100%;
                        height: 100%;
                        background-color: rgba(0, 0, 0, 0.7);
                        z-index: 10003;
                        display: flex;
                        align-items: center;
                        justify-content: center;
                    }

                    .psImportModalContent {
                        background-color: #2a2a30;
                        padding: 25px;
                        border-radius: 5px;
                        border: 1px solid #007bff;
                        width: 90%;
                        max-width: 500px;
                        box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
                    }

                    .psImportModalContent h4 {
                        margin-top: 0;
                        margin-bottom: 15px;
                        color: #eee;
                        font-size: 16px;
                        text-align: center;
                    }
                     .psImportModalContent p {
                        margin-bottom: 10px;
                        font-size: 14px;
                        color: #ccc;
                     }

                    #psImportTextarea {
                        width: 100%;
                        padding: 10px;
                        font-size: 14px;
                        background-color: #333;
                        border: 1px solid #555;
                        color: #eee;
                        border-radius: 4px;
                        margin-bottom: 20px;
                        min-height: 100px;
                        resize: vertical;
                        outline: none;
                    }
                    #psImportTextarea:focus {
                        border-color: #67c1f5;
                    }

                    .psImportModalActions {
                        display: flex;
                        justify-content: flex-end;
                        gap: 10px;
                    }

                     .psImportModalActions .platiSearchBtn {
                        padding: 8px 20px;
                        height: auto;
                        font-size: 14px;
                     }

                    #psImportAcceptBtn {
                         background-color: #4D88FF;
                    }
                    #psImportAcceptBtn:hover {
                        background-color: #3366CC;
                    }
                    #psImportCancelBtn {
                        background-color: #777;
                    }
                     #psImportCancelBtn:hover {
                        background-color: #888;
                    }

                    #platiExclusionTagsList {
                        margin-top: 0;
                    }
                 `);
             }

            addPlatiStyles();
            const steamAppIdCheck = unsafeWindow.location.pathname.match(/\/app\/(\d+)/);
            if (steamAppIdCheck && steamAppIdCheck[1]) {
                addPlatiButton();
            }

        })();
    }

    }
})();