Ultimate Steam Enhancer

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

// ==UserScript==
// @name         Ultimate Steam Enhancer
// @namespace    https://store.steampowered.com/
// @version      1.9.4
// @description  Добавляет множество функций для улучшения взаимодействия с магазином и сообществом (Полный список на странице скрипта)
// @author       0wn3df1x
// @license      MIT
// @require      https://code.jquery.com/jquery-3.6.0.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
// @connect      zoneofgames.ru
// @connect      raw.githubusercontent.com
// @connect      gist.githubusercontent.com
// @connect      store.steampowered.com
// @connect      api.steampowered.com
// @connect      steamcommunity.com
// @connect      shared.cloudflare.steamstatic.com
// @connect      umadb.ro
// @connect      api.github.com
// @connect      howlongtobeat.com
// @connect      vgtimes.ru
// ==/UserScript==

(function() {
    'use strict';

    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/*
        vgtSales: true, // Скрипт для страницы игры (VGT; отображения цен из агрегатора VGTimes) | 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/
        wishlistTracker: true, // Скрипт для получения уведомлений об изменении дат выхода игр из вашего списка желаемого Steam и показа календаря с датами | https://steamcommunity.com/my/wishlist/
        // Дополнительные настройки
        autoExpandHltb: false, // Автоматически раскрывать спойлер HLTB
        autoLoadReviews: false, // Автоматически загружать дополнительные обзоры
        toggleEnglishLangInfo: false // Отображает данные об английском языке в дополнительной информации при поиске по каталогу и в активности (функция для переводчиков)
    };


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

            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}`;
                    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 lime = document.createElement('div');
                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 settings = {
                showTotalReviews: true,
                showNonChineseReviews: true,
                showRussianReviews: true
            };

            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,
                    onload: function(response) {
                        let data = JSON.parse(response.responseText);
                        callback(data);
                    }
                });
            }

            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,
                    onload: function(response) {
                        let data = JSON.parse(response.responseText);
                        callback(data.html);
                    }
                });
            }

            function addStyles() {
                GM_addStyle(`
        .additional-reviews {
            margin-top: 10px;
        }
        .additional-reviews .user_reviews_summary_row {
            display: flex;
            line-height: 16px;
            cursor: pointer;
            margin-bottom: 5px;
        }
        .additional-reviews .subtitle {
            flex: 1;
            color: #556772;
            font-size: 12px;
        }
        .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;
        }
        .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.8);
        }
        .ofxmodal-content {
            background-color: #1b2838;
            margin: 10% auto;
            padding: 20px;
            border: 1px solid #888;
            width: 80%;
            max-width: 800px;
            color: #c6d4df;
            position: relative;
            max-height: 80vh;
            overflow-y: auto;
        }
        .ofxclose {
            color: #aaa;
            position: sticky;
            top: 0;
            float: right;
            font-size: 28px;
            font-weight: bold;
            cursor: pointer;
            background: rgba(0,0,0,0.8);
            padding: 5px 10px;
            border-radius: 5px;
            transition: color 0.2s ease, background 0.2s ease, transform 0.2s ease;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
        }
        .ofxclose:hover {
            color: #fff;
            background: #e64a4a;
            transform: scale(1.1);
        }
        .ofxclose:active {
            background: #c43c3c;
            transform: scale(0.95);
        }
        .refresh-button {
            position: left;
            top: 10px;
            right: 50px;
            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;
        }
        .refresh-button:hover {
            background: #45b0e6;
            color: #fff;
        }
        .refresh-button:active {
            background: #329cd4;
            transform: translateY(1px);
        }
    `);
            }

            function formatNumber(number) {
                return number.toLocaleString('en-US');
            }

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

            function addLoadButton() {
                let reviewsContainer = document.querySelector('.user_reviews');
                if (reviewsContainer) {
                    let additionalReviews = document.createElement('div');
                    additionalReviews.className = 'additional-reviews';

                    additionalReviews.innerHTML = `
            <div class="user_reviews_summary_row" id="load-reviews-button">
                <div class="subtitle column all">Доп. обзоры:</div>
                <div class="summary column">
                    <span class="game_review_summary no_reviews">Загрузить</span>
                </div>
            </div>
        `;

                    reviewsContainer.appendChild(additionalReviews);

                    document.getElementById('load-reviews-button').addEventListener('click', function() {
                        loadAdditionalReviews();
                    });

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

            function loadAdditionalReviews() {
                let appid = window.location.pathname.match(/\/app\/(\d+)/)[1];
                let languages = [];
                let data = {};

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

                if (settings.showTotalReviews || settings.showNonChineseReviews) {
                    languages.push('all');
                }
                if (settings.showNonChineseReviews) {
                    languages.push('schinese');
                }
                if (settings.showRussianReviews) {
                    languages.push('russian');
                }

                languages.forEach(language => {
                    fetchReviews(appid, language, (response) => {
                        data[language] = response;
                        if (Object.keys(data).length === languages.length) {
                            displayAdditionalReviews(data['all'], data['schinese'], data['russian']);

                            if (loadButton) {
                                loadButton.querySelector('.game_review_summary').textContent = 'Загрузить';
                            }
                        }
                    });
                });
            }

            function displayAdditionalReviews(allData, schineseData, russianData) {
                let allReviews = allData ? allData.query_summary : null;
                let schineseReviews = schineseData ? schineseData.query_summary : null;
                let russianReviews = russianData ? russianData.query_summary : null;

                let additionalReviews = document.querySelector('.additional-reviews');
                if (additionalReviews) {
                    additionalReviews.innerHTML = '';

                    if (settings.showTotalReviews && allReviews) {
                        let allPercent = allReviews.total_reviews > 0 ? Math.round((allReviews.total_positive / allReviews.total_reviews) * 100) : 0;
                        let allClass = getReviewClass(allPercent, allReviews.total_reviews);
                        additionalReviews.innerHTML += `
                <div class="user_reviews_summary_row">
                    <div class="subtitle column all">Тотальные:</div>
                    <div class="summary column">
                        <span class="game_review_summary ${allClass}">${allPercent}% из ${formatNumber(allReviews.total_reviews)} положительные</span>
                    </div>
                </div>
            `;
                    }

                    if (settings.showNonChineseReviews && allReviews && schineseReviews) {
                        let schintotalrev = allReviews.total_reviews - schineseReviews.total_reviews;
                        let schintotapos = allReviews.total_positive - schineseReviews.total_positive;
                        let schinpercent = schintotalrev > 0 ? Math.round((schintotapos / schintotalrev) * 100) : 0;
                        let schinClass = getReviewClass(schinpercent, schintotalrev);
                        additionalReviews.innerHTML += `
                <div class="user_reviews_summary_row">
                    <div class="subtitle column all">Безкитайские:</div>
                    <div class="summary column">
                        <span class="game_review_summary ${schinClass}">${schinpercent}% из ${formatNumber(schintotalrev)} положительные</span>
                    </div>
                </div>
            `;
                    }

                    if (settings.showRussianReviews && russianReviews) {
                        let rustotalrev = russianReviews.total_reviews;
                        let ruspositive = russianReviews.total_positive;
                        let ruspercent = rustotalrev > 0 ? Math.round((ruspositive / rustotalrev) * 100) : 0;
                        let rusClass = getReviewClass(ruspercent, rustotalrev);
                        additionalReviews.innerHTML += `
                <div class="user_reviews_summary_row" id="russian-reviews-row">
                    <div class="subtitle column all">Русские:</div>
                    <div class="summary column">
                        <span class="game_review_summary ${rusClass}">${ruspercent}% из ${formatNumber(rustotalrev)} положительные</span>
                    </div>
                </div>
            `;

                        document.getElementById('russian-reviews-row').addEventListener('click', function() {
                            openModal();
                        });
                    }
                }
            }

            function openModal() {
                let ofxmodal = document.createElement('div');
                ofxmodal.className = 'ofxmodal';
                ofxmodal.innerHTML = `
        <div class="ofxmodal-content">
            <span class="ofxclose">×</span>
            <button class="refresh-button" id="refresh-reviews">Загрузить актуальные</button>
            <div id="reviews-container"></div>
        </div>
    `;
                document.body.appendChild(ofxmodal);

                ofxmodal.querySelector('.ofxclose').addEventListener('click', function() {
                    ofxmodal.style.display = 'none';
                });

                ofxmodal.querySelector('#refresh-reviews').addEventListener('click', function() {
                    refreshReviews(ofxmodal);
                });

                ofxmodal.style.display = 'block';

                loadReviews(ofxmodal, 'all');
            }

            function refreshReviews(ofxmodal) {
                ofxmodal.querySelector('#reviews-container').innerHTML = '';
                loadReviews(ofxmodal, 'recent');
            }

            function loadReviews(ofxmodal, filter) {
                fetchRussianReviewsHTML(window.location.pathname.match(/\/app\/(\d+)/)[1], filter, function(html) {
                    ofxmodal.querySelector('#reviews-container').innerHTML = html;
                    ofxmodal.querySelector('#LoadMoreReviewsall')?.remove();
                    ofxmodal.querySelector('#LoadMoreReviewsrecent')?.remove();
                });
            }

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

            main();
        })();
    }

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

            let triangle = document.createElement('div');
            triangle.className = 'triangle-down';
            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';
            hltbBlock.appendChild(triangle);

            let title = document.createElement('div');
            title.style.fontSize = '12px';
            title.style.fontWeight = 'bold';
            title.style.color = '#67c1f5';
            title.style.marginBottom = '10px';
            title.textContent = 'HLTB';
            title.style.cursor = 'pointer';
            hltbBlock.appendChild(title);

            let content = document.createElement('div');
            content.style.fontSize = '14px';
            content.style.color = '#c6d4df';
            content.style.display = 'none';
            content.style.whiteSpace = 'auto';
            content.style.padding = '0 0';
            hltbBlock.appendChild(content);

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

                if (scriptsConfig.gamePage && russianIndicators) {
                    hltbBlock.style.top = `${russianIndicators.offsetTop + russianIndicators.offsetHeight + 16}px`;
                } else {
                    hltbBlock.style.top = '0px';
                }

                hltbBlock.style.left = '334px';
            };

            const initHltbObservers = () => {
                if (scriptsConfig.gamePage) {
                    const indicatorsObserver = new MutationObserver(() => {
                        updateHltbPosition();
                    });

                    const indicators = document.querySelector('#gameHeaderImageCtn > div[style*="position: absolute; top: -10px; left: calc(100% + 10px);"]');
                    if (indicators) {
                        indicatorsObserver.observe(indicators, {
                            attributes: true,
                            childList: true,
                            subtree: true
                        });
                    }
                }

                const generalObserver = new MutationObserver((mutations) => {
                    mutations.forEach(mutation => {
                        if (mutation.type === 'childList') {
                            updateHltbPosition();
                        }
                    });
                });

                generalObserver.observe(document.querySelector('#gameHeaderImageCtn'), {
                    childList: true,
                    subtree: true
                });
            };

            document.querySelector('#gameHeaderImageCtn').appendChild(hltbBlock);
            initHltbObservers();
            updateHltbPosition();


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

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

    // Скрипт для страницы игры (Время друзей & Достижения) | https://store.steampowered.com/app/*
    if (window.location.pathname.includes('/app/') && scriptsConfig.friendsPlaytime) {
        (async function() {
            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 loadFriendsData();
                        const achievementsData = await loadAchievementsData();
                        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 loadFriendsData() {
                try {
                    const friendsLink = document.querySelector('.recommendation_reasons a[href*="friendsthatplay"]');
                    if (!friendsLink) return [];

                    const response = await new Promise((resolve, reject) => {
                        GM_xmlhttpRequest({
                            method: "GET",
                            url: friendsLink.href,
                            onload: resolve,
                            onerror: reject,
                            timeout: 5000
                        });
                    });

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

                    return Array.from(doc.querySelectorAll('.friendBlockContent'))
                        .map(block => {
                            const timeText = block.querySelector('.friendSmallText')?.textContent;
                            const hoursMatch = timeText?.match(/(\d+[,.]?\d*)\s*ч/);
                            return {
                                name: block.firstChild.textContent.trim(),
                                hours: hoursMatch ? parseFloat(hoursMatch[1].replace(',', '.')) : 0,
                                profile: block.closest('.friendBlock').querySelector('a').href
                            };
                        })
                        .filter(f => f.hours > 0);

                } catch (error) {
                    return [];
                }
            }

            async function loadAchievementsData() {
                try {
                    const appIdMatch = window.location.pathname.match(/\/app\/(\d+)/);
                    if (!appIdMatch) return {
                        hasAchievements: false,
                        error: 'Не найден App ID'
                    };

                    const appId = appIdMatch[1];
                    const achievementsUrl = `https://steamcommunity.com/stats/${appId}/achievements/`;

                    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 => {
                            const text = el.textContent.trim();
                            return parseFloat(text.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);

            document.querySelector('#gameHeaderImageCtn').appendChild(statsBlock);

            if (scriptsConfig.autoExpandFriends) {
                toggleBlock();
            }
        })();
    }

    // Скрипт для страницы игры (Ранний доступ) | 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 = window.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();
        })();
    }

    // Скрипт для получения дополнительной информации об игре при наведении на неё на странице поиска по каталогу | https://store.steampowered.com/search/
    if (scriptsConfig.catalogInfo && window.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; // 24 часа

            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 && window.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");
                checkedLadybugs.forEach(ladybug => {
                    const link = document.querySelector(`a[data-ds-appid="${ladybug.dataset.aphid}"]`);
                    if (link) {
                        link.classList.add("ds_ignored", "ds_flagged");
                        ladybug.remove();
                        jQuery.ajax({
                            url: "https://store.steampowered.com/recommended/ignorerecommendation/",
                            type: "POST",
                            data: {
                                sessionid: g_sessionID,
                                appid: ladybug.dataset.aphid,
                                remove: 0,
                                snr: "1_account_notinterested_",
                            },
                            success: () => {
                                console.log(`Game with appid ${ladybug.dataset.aphid} added to the ignore list`);
                                GDynamicStore.InvalidateCache();
                            },
                        });
                    }
                });
                updateAntCounter();
            }

            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] {
        -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]: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]: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]: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 && window.location.pathname.includes('/news')) {
        (function() {
            'use strict';

            const stromboliStyle = `
      .etna-checkbox {
        position: absolute;
        top: 50%;
        right: 10px;
        width: 60px;
        height: 60px;
        border-radius: 50%;
        border: 2px solid #66c0f4;
        background-color: rgba(27, 40, 56, 0.7);
        cursor: pointer;
        z-index: 1000;
        transform: translateY(-50%);
        opacity: 0.5;
      }
      .etna-checkbox:checked {
        background-color: rgba(102, 192, 244, 0.8);
      }
      .vesuvius-hide-button {
        position: fixed;
        top: 20px;
        right: 20px;
        padding: 15px 30px;
        background-color: #66c0f4;
        color: #fff;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        z-index: 1000;
        font-size: 18px;
        transition: background-color 0.3s, box-shadow 0.3s;
      }

      .vesuvius-hide-button:hover {
        background-color: #4a90e2;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
      }
    `;

            const krakatoaStyleElement = document.createElement('style');
            krakatoaStyleElement.innerHTML = stromboliStyle;
            document.head.appendChild(krakatoaStyleElement);

            function addEtnaCheckboxes(newsItems) {
                newsItems.forEach(item => {
                    const fujiNewsLink = item.querySelector('a.Focusable[href^="/news/app/"]');
                    if (fujiNewsLink && !item.querySelector('.etna-checkbox')) {
                        const rainierCheckbox = document.createElement('input');
                        rainierCheckbox.type = 'checkbox';
                        rainierCheckbox.className = 'etna-checkbox';
                        rainierCheckbox.addEventListener('click', (event) => {
                            event.stopPropagation();
                        });
                        const kilimanjaroOverlayDiv = item.querySelector('._3HF9tOy_soo1B_odf1XArk');
                        if (kilimanjaroOverlayDiv) {
                            kilimanjaroOverlayDiv.style.position = 'relative';
                            kilimanjaroOverlayDiv.appendChild(rainierCheckbox);
                        }
                    }
                });
            }

            function addVesuviusHideButton() {
                const vesuviusHideButton = document.createElement('button');
                vesuviusHideButton.className = 'vesuvius-hide-button';
                vesuviusHideButton.textContent = 'Скрыть';
                vesuviusHideButton.onclick = hideSelectedNews;
                document.body.appendChild(vesuviusHideButton);
            }

            function hideSelectedNews() {
                const maunaLoaCheckboxes = document.querySelectorAll('.etna-checkbox:checked');
                maunaLoaCheckboxes.forEach(maunaLoaCheckbox => {
                    const newsItem = maunaLoaCheckbox.closest('._398u23KF15gxmeH741ZSyL');
                    const fujiNewsLink = newsItem.querySelector('a.Focusable[href^="/news/app/"]').getAttribute('href');
                    const shishaldinNewsTitle = newsItem.querySelector('._1M8-Pa3b3WboayCgd5VBJT').textContent;
                    const bakerNewsDate = new Date().toISOString();

                    const hiddenNews = JSON.parse(localStorage.getItem('hiddenNews') || '[]');
                    hiddenNews.push({
                        link: fujiNewsLink,
                        title: shishaldinNewsTitle,
                        date: bakerNewsDate
                    });
                    localStorage.setItem('hiddenNews', JSON.stringify(hiddenNews));

                    newsItem.remove();
                });
            }

            function removeHiddenNews() {
                const hiddenNews = JSON.parse(localStorage.getItem('hiddenNews') || '[]');
                hiddenNews.forEach(news => {
                    const newsItem = document.querySelector(`a[href="${news.link}"]`)?.closest('._398u23KF15gxmeH741ZSyL');
                    if (newsItem) {
                        newsItem.remove();
                    }
                });
            }

            function init() {
                removeHiddenNews();
                addEtnaCheckboxes(document.querySelectorAll('._398u23KF15gxmeH741ZSyL'));
                addVesuviusHideButton();
            }

            setTimeout(init, 1000);

            const erebusObserver = new MutationObserver((mutations) => {
                mutations.forEach(mutation => {
                    if (mutation.type === 'childList') {
                        const newNewsItems = document.querySelectorAll('._398u23KF15gxmeH741ZSyL');
                        addEtnaCheckboxes(newNewsItems);
                        removeHiddenNews();
                    }
                });
            });

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

        })();
    }

    // Скрипт для показа годовых и исторических продаж предмета на торговой площадке Steam | https://steamcommunity.com/market/listings/*
    if (scriptsConfig.Kaznachei && window.location.pathname.includes('/market/listings/')) {
        async function fetchSalesInfo() {
            const urlParts = window.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
    if (scriptsConfig.homeInfo && window.location.href.includes('steamcommunity.com') && window.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,
                        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';

                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>
                <div style="margin-bottom: 10px;"><img src="https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/${appId}/header.jpg" alt="${data.name}" style="width: 50%; height: auto;"></div>
                <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);
        })();
    }

    // Скрипт для страницы игры (ZOG; получение сведений о наличии русификаторов) | https://store.steampowered.com/app/*
    if (window.location.pathname.includes('/app/') && scriptsConfig.zogInfo) {
        (async function() {
            const ZOG_CACHE_KEY = 'ZoGRusekiEdrit';
            const ZOG_DATA_URL = 'https://gist.githubusercontent.com/0wn3dg0d/7baa8d9f42b0304fe303e903d44d2ada/raw/zogrusbase.json';

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

            let hltbBlock = null;
            let hltbObserver = null;
            let zogMap = null;
            let zogNameMap = null;

            const updatePosition = () => {
                hltbBlock = document.querySelector('#gameHeaderImageCtn > div[style*="background: rgba(27, 40, 56, 0.95)"]');

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

                if (hltbBlock && scriptsConfig.hltbData) {
                    zogBlock.style.top = `${hltbBlock.offsetTop + hltbBlock.offsetHeight + 16}px`;
                } else if (russianIndicators && scriptsConfig.gamePage) {
                    zogBlock.style.top = `${russianIndicators.offsetTop + russianIndicators.offsetHeight + 16}px`;
                } else {
                    const headerImage = document.querySelector('#gameHeaderImageCtn');
                    if (headerImage) {
                        zogBlock.style.top = `${0}px`;
                    }
                }

                zogBlock.style.left = '334px';
                zogBlock.style.zIndex = '2';
            };

            const initObservers = () => {
                if (scriptsConfig.hltbData) {
                    hltbBlock = document.querySelector('#gameHeaderImageCtn > div[style*="background: rgba(27, 40, 56, 0.95)"]');
                    if (hltbBlock && !hltbObserver) {
                        hltbObserver = new ResizeObserver(updatePosition);
                        hltbObserver.observe(hltbBlock);
                        hltbBlock.addEventListener('transitionend', updatePosition);
                    }
                }

                if (scriptsConfig.gamePage) {
                    const russianObserver = new MutationObserver((mutations) => {
                        mutations.forEach(mutation => {
                            if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
                                updatePosition();
                            }
                        });
                    });

                    const indicators = document.querySelector('#gameHeaderImageCtn > div[style*="position: absolute; top: -10px; left: calc(100% + 10px);"]');
                    if (indicators) {
                        russianObserver.observe(indicators, {
                            attributes: true,
                            attributeFilter: ['style']
                        });
                    }
                }

                const generalObserver = new MutationObserver((mutations) => {
                    mutations.forEach(mutation => {
                        if (mutation.type === 'childList') {
                            updatePosition();
                            initObservers();
                        }
                    });
                });

                generalObserver.observe(document.querySelector('#gameHeaderImageCtn'), {
                    childList: true,
                    subtree: true
                });
            };

            async function loadZogData() {
                const cached = GM_getValue(ZOG_CACHE_KEY);
                const lastUpdated = cached?.lastUpdated || '';

                try {
                    const metaResponse = await new Promise((resolve, reject) => {
                        GM_xmlhttpRequest({
                            method: 'GET',
                            url: 'https://api.github.com/gists/7baa8d9f42b0304fe303e903d44d2ada',
                            onload: resolve,
                            onerror: reject
                        });
                    });

                    const metaData = JSON.parse(metaResponse.responseText);

                    const newLastUpdated = metaData.updated_at;

                    if (newLastUpdated === lastUpdated) {
                        return cached.data;
                    }

                    const dataResponse = await new Promise((resolve, reject) => {
                        GM_xmlhttpRequest({
                            method: 'GET',
                            url: ZOG_DATA_URL,
                            onload: resolve,
                            onerror: reject
                        });
                    });

                    const newData = JSON.parse(dataResponse.responseText);

                    GM_setValue(ZOG_CACHE_KEY, {
                        lastUpdated: newLastUpdated,
                        data: newData,
                        timestamp: Date.now()
                    });

                    return newData;
                } catch (error) {
                    console.error('Ошибка загрузки данных ZOG:', error);
                    return cached?.data || [];
                }
            }

            async function initZogData() {
                try {
                    const data = await loadZogData();
                    zogMap = new Map(data.map(item => [item.app_id, item]));
                    zogNameMap = new Map(data.map(item => [
                        item.title
                        ?.normalize("NFD").replace(/[\u0300-\u036f]/g, "")
                        .replace(/[^a-zа-яё0-9 _'\-!]/gi, '')
                        .toLowerCase(),
                        item
                    ]));
                } catch (e) {
                    console.error('Ошибка инициализации данных ZOG:', e);
                    content.textContent = 'Ошибка загрузки базы';
                }
            }

            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 = createArrow();

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

            initObservers();
            updatePosition();
            await initZogData();

            title.onclick = () => toggleBlock(arrow);
            arrow.onclick = () => toggleBlock(arrow);

            async function toggleBlock(arrowElement) {
                if (content.style.display === 'none') {
                    await expandBlock(arrowElement);
                } else {
                    collapseBlock(arrowElement);
                }
            }

            async function expandBlock(arrowElement) {
                if (!zogMap || !zogNameMap) {
                    console.error('Данные ZOG не инициализированы');
                    return;
                }

                zogBlock.style.transition = 'width 0.3s ease, height 0.3s ease';
                zogBlock.style.width = '300px';
                zogBlock.style.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(resolve => requestAnimationFrame(resolve));

                const appId = getAppId();
                let entry = zogMap.get(appId);

                if (!entry) {
                    const gameName = getGameName()
                        .normalize("NFD").replace(/[\u0300-\u036f]/g, "")
                        .replace(/[^a-zа-яё0-9 _'\-!]/gi, '')
                        .toLowerCase();

                    content.textContent = 'Ищем углубленно...';
                    await new Promise(resolve => requestAnimationFrame(resolve));

                    entry = zogNameMap.get(gameName);

                    if (!entry && /[а-яё]/i.test(gameName)) {
                        content.textContent = 'Запрашиваем англ. название...';
                        await new Promise(resolve => requestAnimationFrame(resolve));

                        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) {
                                    const cleanEnglishName = englishName
                                        .normalize("NFD").replace(/[\u0300-\u036f]/g, "")
                                        .replace(/[^a-zа-яё0-9 _'\-!]/gi, '')
                                        .toLowerCase();

                                    content.textContent = 'Проверяем англ. название...';
                                    await new Promise(resolve => requestAnimationFrame(resolve));

                                    entry = zogNameMap.get(cleanEnglishName);

                                    if (!entry) {
                                        content.textContent = 'Проверяем возможные совпадения...';
                                        await new Promise(resolve => requestAnimationFrame(resolve));

                                        const possibleMatches = findPossibleMatches(cleanEnglishName, Array.from(zogNameMap.values()));
                                        if (possibleMatches.length > 0) {
                                            renderPossibleMatches(possibleMatches);
                                            zogBlock.style.height = `${content.scrollHeight + 30}px`;
                                            updatePosition();
                                            return;
                                        }
                                    }
                                }
                            }
                        } catch (error) {
                            console.error('Ошибка при запросе к Steam API:', error);
                        }
                    }
                }

                if (!entry) {
                    content.textContent = 'Проверяем возможные совпадения...';
                    await new Promise(resolve => requestAnimationFrame(resolve));
                    const possibleMatches = findPossibleMatches(getGameName(), Array.from(zogNameMap.values()));
                    if (possibleMatches.length > 0) {
                        renderPossibleMatches(possibleMatches);
                        zogBlock.style.height = `${content.scrollHeight + 30}px`;
                        updatePosition();
                        return;
                    }
                }

                renderContent(entry);
                zogBlock.style.height = `${content.scrollHeight + 30}px`;
                updatePosition();
            }

            function nextFrame() {
                return new Promise(resolve => requestAnimationFrame(resolve));
            }

            function collapseBlock(arrowElement) {
                zogBlock.style.transition = 'width 0.3s ease, height 0.3s ease';
                zogBlock.style.width = '30px';
                zogBlock.style.height = '30px';

                arrowElement.style.transform = 'translateX(-50%) rotate(0deg)';

                content.style.display = 'none';
                updatePosition();
            }

            function renderContent(entry) {
                content.innerHTML = '';

                if (!entry) {
                    content.textContent = 'Игра не найдена в базе ZOG';
                    return;
                }

                const titleLink = document.createElement('a');
                titleLink.href = `https://www.zoneofgames.ru/games/${entry.id}.html`;
                titleLink.target = '_blank';
                titleLink.textContent = entry.title || 'Без названия';
                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';

                if (entry.localizations?.length > 0) {
                    entry.localizations.forEach(loc => {
                        const li = document.createElement('li');
                        li.style.marginBottom = '8px';

                        const link = document.createElement('a');
                        link.href = loc.link;
                        link.target = '_blank';
                        link.textContent = `${loc.name} ${loc.size || ''}`;
                        link.style.color = '#c6d4df';
                        link.style.wordBreak = 'break-word';
                        link.style.textDecoration = 'none';

                        li.appendChild(link);
                        list.appendChild(li);
                    });
                } else {
                    list.textContent = 'Русификаторы отсутствуют';
                    list.style.color = '#999';
                }

                content.appendChild(list);
            }

            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 = `https://www.zoneofgames.ru/games/${match.id}.html`;
                    link.target = '_blank';
                    link.textContent = `${match.title} (${match.percentage}%)`;
                    link.style.color = '#c6d4df';
                    link.style.wordBreak = 'break-word';
                    link.style.textDecoration = 'none';
                    link.onclick = () => {
                        renderContent(match);
                        zogBlock.style.height = `${content.scrollHeight + 30}px`;
                        updatePosition();
                        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);
                    zogBlock.style.height = `${content.scrollHeight + 30}px`;
                    updatePosition();
                    return false;
                };

                noMatch.appendChild(noMatchLink);
                list.appendChild(noMatch);

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

                        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 createArrow() {
                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%)'
                });
                return arrow;
            }

            function getAppId() {
                return window.location.pathname.split('/')[2];
            }

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

    // Скрипт для получения уведомлений об изменении дат выхода игр из вашего списка желаемого Steam и показа календаря с датами | https://steamcommunity.com/my/wishlist/
    if (scriptsConfig.wishlistTracker) {
        (function() {
            'use strict';

            const STORAGE_PREFIX = 'USE_Wishlist_';
            const STORAGE_KEYS = {
                NOTIFICATIONS: STORAGE_PREFIX + 'notifications',
                GAME_DATA: STORAGE_PREFIX + 'gameData',
                LAST_UPDATE: STORAGE_PREFIX + 'lastUpdate'
            };

            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 BATCH_SIZE = 200;
            const MILLISECONDS_IN_HOUR = 60 * 60 * 1000;
            let notifications = GM_getValue(STORAGE_KEYS.NOTIFICATIONS, []);
            let isPanelOpen = false;

            GM_addStyle(`
            .wishlist-tracker-container {
				position: absolute;
				right: 180px;
				top: 6px;
				z-index: 999;
			}

			.wishlist-tracker-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: 4px;
				align-items: center;
				transition: all 0.2s ease;
			}

			.wishlist-tracker-button:hover {
				background: rgba(103, 193, 245, 0.2);
			}

			.notification-badge {
				background: #67c1f5;
				color: #1b2838;
				border-radius: 3px;
				padding: 3px 6px;
				font-size: 14px;
				font-weight: bold;
				margin-left: 8px;
				min-width: 20px;
				text-align: center;
				box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
			}

			.status-indicator {
			    background: #4a5562;
			    color: #c6d4df;
			    border-radius: 3px;
			    padding: 3px 6px;
			    font-size: 12px;
			    font-weight: bold;
			    margin-left: 5px;
			    min-width: 30px;
			    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; }

			.wishlist-tracker-panel {
				position: fixed;
				right: 132px;
				top: 50px;
				background: #1b2838;
				border: 1px solid #67c1f5;
				width: 500px;
				max-height: 500px;
                min-width: 460px;
				overflow-y: auto;
				z-index: 9999;
				box-shadow: 0 0 15px rgba(0, 0, 0, 0.5);
				display: none;
			}

			.wt-panel-header {
				padding: 15px;
				background: #171a21;
				display: flex;
				justify-content: space-between;
				align-items: center;
			}

			.panel-title {
				font-size: 17px;
				font-weight: 500;
				color: #67c1f5;
			}


            .panel-controls {
                display: flex;

            }

            .panel-controls button {
                background: rgba(30, 45, 60, 0.7);
                border: none;
                color: #c6d4df;
                padding: 8px 14px;
                cursor: pointer;
                margin-left: 5px;
                border-radius: 2px;
                font-weight: 400;
                text-transform: uppercase;
                letter-spacing: 0.5px;
                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
                transition: background 0.2s ease, box-shadow 0.2s ease;
            }

            .panel-controls button:hover {
                background: rgba(40, 60, 80, 0.9);
                box-shadow: 0 3px 6px rgba(0, 0, 0, 0.4);
            }

            .panel-controls button:active {
                background: rgba(30, 45, 60, 0.6);
                box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
            }

			.calendar-btn {
			    padding: 8px 10px !important;
			    display: flex;
			    align-items: center;
			}

			.wt-notification-item {
				padding: 15px;
				border-bottom: 1px solid #2a475e;
				position: relative;
				transition: opacity 0.3s;
			}

			.notification-content {
				display: flex;
				gap: 15px;
			}

			.notification-image {
				width: 80px;
				height: 45px;
				object-fit: cover;
			}

			.notification-text {
				flex-grow: 1;
				padding-right: 25px;
			}

			.notification-game-title {
				color: #66c0f4;
				font-weight: bold;
				text-decoration: none;
				display: block;
				margin-bottom: 5px;
			}

			.notification-date {
				font-size: 12px;
				color: #8f98a0;
			}

			.notification-dates {
				color: #c6d4df;
				font-size: 13px;
			}

			.wtunread {
				background: rgba(102, 192, 244, 0.15);
			}

			.notification-controls {
				position: absolute;
				right: 10px;
				top: 10px;
				display: flex;
				gap: 8px;
			}

			.notification-control {
				cursor: pointer;
				width: 18px;
				height: 18px;
				opacity: 0.7;
				transition: opacity 0.2s;
			}

			.notification-control:hover {
				opacity: 1;
			}

			.delete-btn {
			  width: 20px;
			  height: 20px;
			  display: flex;
			  align-items: center;
			  justify-content: center;
			  color: #6C7781;
			  font-size: 16px;
			  font-weight: bold;
			  line-height: 1;
			  border: none;
			  cursor: pointer;
			  transition: color 0.2s ease, transform 0.1s ease;
			}

			.delete-btn:hover {
			  color: #8F98A0;
			}

			.delete-btn:active {
			  color: #800000;
			  transform: scale(0.9);
			}

			.loading-indicator {
				color: #67c1f5;
				text-align: center;
				padding: 10px;
			}

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

			.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 0 16px 0;
			    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;
			}

			.calendar-game-title {
			    color: #c6d4df;
			    font-size: 13px;
			}


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

			`);

            const envelopeIcons = {
                wtunread: `<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>`,
                wtread: `<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>`
            };

            function createNotificationUI() {
                const container = $(`
    <div class="wishlist-tracker-container">
        <div class="wishlist-tracker-button">
            <span>Отслеживание вишлиста</span>
            <div class="status-indicator status-unknown">??</div>
            <div class="notification-badge">${getUnreadCount()}</div>
        </div>
                <div class="wishlist-tracker-panel">
                    <div class="wt-panel-header">
                        <div class="panel-title">Уведомлений: (${notifications.length})</div>
                        <div class="panel-controls">
                            <button class="refresh-btn">⟳ Обновить</button>
                            <button class="clear-btn">× Очистить</button>
                            <button class="calendar-btn">${calendarIcon}</button>
                        </div>
                    </div>
                </div>
            </div>
        `);

                const panel = container.find('.wishlist-tracker-panel');
                const button = container.find('.wishlist-tracker-button');

                button.click(function(e) {
                    e.stopPropagation();
                    togglePanel();
                });

                container.find('.refresh-btn').click((e) => {
                    e.stopPropagation();
                    updateData();
                });

                container.find('.clear-btn').click(() => {
                    notifications = [];
                    GM_setValue(STORAGE_KEYS.NOTIFICATIONS, notifications);
                    updateNotificationPanel();
                    updateBadge();
                });
                container.find('.calendar-btn').click((e) => {
                    e.stopPropagation();
                    showCalendarModal();
                });

                if (window.self === window.top) {
                    document.body.appendChild(container[0]);
                }
                updateNotificationPanel();

                $(document).click(() => {
                    if (isPanelOpen) {
                        panel.hide();
                        isPanelOpen = false;
                    }
                });
            }

            function showLoadingIndicator() {
                const panel = $('.wishlist-tracker-panel');
                panel.find('.loading-indicator').remove();
                const loading = $(`<div class="loading-indicator">Обновление данных...</div>`);
                panel.append(loading);
            }

            function togglePanel() {
                updateStatusIndicator();
                const panel = $('.wishlist-tracker-panel');
                panel.toggle();
                isPanelOpen = !isPanelOpen;
                if (isPanelOpen) {
                    panel.css('display', 'block');
                }
            }

            function updateNotificationPanel() {
                const panel = $('.wishlist-tracker-panel');
                panel.find('.wt-notification-item, .loading-indicator').remove();
                panel.find('.panel-title').text(`Уведомлений: (${notifications.length})`);

                notifications.slice(0, 5000).forEach((notification, index) => {
                    const item = $(`
            <div class="wt-notification-item ${notification.wtread ? '' : 'wtunread'}">
                <div class="notification-controls">
                    <div class="toggle-wtread-btn notification-control">
                        ${notification.wtread ? envelopeIcons.wtread : envelopeIcons.wtunread}
                    </div>
                    <div class="delete-btn notification-control">X</div>
                </div>
                <div class="notification-content">
                    <a href="https://store.steampowered.com/app/${notification.appid}" target="_blank">
                        <img src="https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/${notification.appid}/header.jpg"
                             class="notification-image">
                    </a>
                    <div class="notification-text">
                        <a href="https://store.steampowered.com/app/${notification.appid}"
                           class="notification-game-title" target="_blank">
                            ${notification.name}
                        </a>
                        <div class="notification-dates">
                            Дата выхода изменилась:<br>
                            <span class="old-date">${formatDate(notification.oldDate)}</span> →
                            <span class="new-date">${formatDate(notification.newDate)}</span>
                        </div>
                        <div class="notification-date">
                            Обнаружено: ${new Date(notification.timestamp).toLocaleString()}
                        </div>
                    </div>
                </div>
            </div>
        `);

                    item.find('.delete-btn').click((e) => {
                        e.stopPropagation();
                        notifications = notifications.filter((_, i) => i !== index);
                        GM_setValue(STORAGE_KEYS.NOTIFICATIONS, notifications);
                        item.fadeOut(300, () => {
                            updateNotificationPanel();
                            updateBadge();
                        });
                    });

                    item.find('.toggle-wtread-btn').click((e) => {
                        e.stopPropagation();
                        notifications[index].wtread = !notifications[index].wtread;
                        GM_setValue(STORAGE_KEYS.NOTIFICATIONS, notifications);
                        item.toggleClass('wtunread', !notifications[index].wtread);
                        item.find('.toggle-wtread-btn').html(notifications[index].wtread ? envelopeIcons.wtread : envelopeIcons.wtunread);
                        updateBadge();
                    });

                    panel.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);
                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 updateStatusIndicator() {
                const lastUpdate = GM_getValue(STORAGE_KEYS.LAST_UPDATE, 0);
                const hoursPassed = (Date.now() - lastUpdate) / MILLISECONDS_IN_HOUR;
                const indicator = $('.status-indicator');
                const days = Math.floor(hoursPassed / 24);
                const hours = Math.floor(hoursPassed % 24);

                indicator.attr('title', `Данные не обновлялись: ${days} д. и ${hours} ч.`);

                if (!lastUpdate) {
                    indicator.text('-').removeClass().addClass('status-indicator status-unknown');
                    return;
                }

                if (hoursPassed < 12) {
                    indicator.text('OK').removeClass().addClass('status-indicator status-ok');
                } else if (hoursPassed < 24) {
                    indicator.text('OK?').removeClass().addClass('status-indicator status-warning');
                } else if (hoursPassed < 48) {
                    indicator.text('!').removeClass().addClass('status-indicator status-alert1');
                } else if (hoursPassed < 72) {
                    indicator.text('!!').removeClass().addClass('status-indicator status-alert2');
                } else if (hoursPassed < 96) {
                    indicator.text('!!!').removeClass().addClass('status-indicator status-critical');
                } else {
                    indicator.text('???').removeClass().addClass('status-indicator status-critical');
                }
            }

            function updateBadge() {
                $('.notification-badge').text(getUnreadCount());
            }

            function getUnreadCount() {
                return notifications.filter(n => !n.wtread).length;
            }


            async function fetchWishlistAppIds() {
                return new Promise(resolve => {
                    GM_xmlhttpRequest({
                        method: 'GET',
                        url: 'https://store.steampowered.com/dynamicstore/userdata/',
                        onload: function(response) {
                            const data = JSON.parse(response.responseText);
                            resolve(data.rgWishlist || []);
                        }
                    });
                });
            }

            async function fetchGameDetails(appIds) {
                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);
                    allDetails.push(...details);
                    await new Promise(resolve => setTimeout(resolve, 1000));
                }

                return allDetails;
            }

            async function fetchBatchDetails(appIds) {
                const requestData = {
                    ids: appIds.map(appid => ({
                        appid
                    })),
                    context: {
                        language: 'russian',
                        country_code: 'RU',
                        steam_realm: 1
                    },
                    data_request: {
                        include_release: true,
                        include_basic_info: true
                    }
                };

                return new Promise(resolve => {
                    GM_xmlhttpRequest({
                        method: 'GET',
                        url: `https://api.steampowered.com/IStoreBrowseService/GetItems/v1?input_json=${encodeURIComponent(JSON.stringify(requestData))}`,
                        onload: function(response) {
                            try {
                                const data = JSON.parse(response.responseText);
                                resolve(data.response?.store_items || []);
                            } catch (e) {
                                console.error('Error parsing response:', e);
                                resolve([]);
                            }
                        }
                    });
                });
            }

            function checkForChanges(currentData) {
                const previousData = GM_getValue(STORAGE_KEYS.GAME_DATA, {});
                const changes = [];

                currentData.forEach(game => {
                    const prevGame = previousData[game.appid];
                    const currentRelease = getReleaseInfo(game.release);
                    const prevRelease = prevGame ? getReleaseInfo(prevGame.rawRelease) : null;

                    if (prevGame && (
                            currentRelease.date !== prevRelease?.date ||
                            currentRelease.type !== prevRelease?.type ||
                            currentRelease.displayType !== prevRelease?.displayType
                        )) {
                        changes.push({
                            appid: game.appid,
                            name: game.name,
                            oldDate: {
                                value: prevRelease?.date || 'Не указана',
                                displayType: prevRelease?.displayType
                            },
                            newDate: {
                                value: currentRelease.date,
                                displayType: currentRelease.displayType
                            },
                            timestamp: Date.now(),
                            wtread: false
                        });
                    }
                });

                const newGameData = currentData.reduce((acc, game) => {
                    acc[game.appid] = {
                        name: game.name,
                        rawRelease: game.release,
                        releaseInfo: getReleaseInfo(game.release)
                    };
                    return acc;
                }, {});

                GM_setValue(STORAGE_KEYS.GAME_DATA, {
                    ...previousData,
                    ...newGameData
                });

                if (changes.length > 0) {
                    notifications = [...changes, ...notifications];
                    GM_setValue(STORAGE_KEYS.NOTIFICATIONS, notifications);
                    updateNotificationPanel();
                    updateBadge();
                }

                $('.wishlist-tracker-panel .loading-indicator').remove();
            }

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

            async function updateData() {
                try {
                    showLoadingIndicator();
                    const indicator = $('.status-indicator');
                    indicator.text('...').removeClass().addClass('status-indicator status-unknown');
                    const appIds = await fetchWishlistAppIds();
                    const gameDetails = await fetchGameDetails(appIds);
                    checkForChanges(gameDetails);
                    GM_setValue(STORAGE_KEYS.LAST_UPDATE, Date.now());
                    updateStatusIndicator();
                } catch (e) {
                    console.error('Update error:', e);
                    showErrorIndicator();
                    updateStatusIndicator();
                } finally {
                    $('.wishlist-tracker-panel .loading-indicator').remove();
                }
            }

            function showErrorIndicator() {
                const panel = $('.wishlist-tracker-panel');
                const error = $(`
            <div class="wt-notification-item" style="color: #ff4747;">
                Ошибка при обновлении данных
            </div>
        `);
                panel.prepend(error);
                setTimeout(() => error.remove(), 5000);
            }

            function showCalendarModal() {
                const gameData = GM_getValue(STORAGE_KEYS.GAME_DATA, {});
                const monthsData = getGamesByMonths(gameData);

                const wtmodal = $(`
        <div class="calendar-wtmodal">
            <div class="calendar-header">
                <div class="calendar-title">Календарь релизов (${monthsData.length} месяцев)</div>
                <div class="calendar-close">×</div>
            </div>
            <div class="calendar-content"></div>
        </div>
    `);

                const clickHandler = (e) => {
                    if (!$(e.target).closest('.calendar-wtmodal').length) {
                        e.preventDefault();
                        e.stopPropagation();
                        e.stopImmediatePropagation();

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

                    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 gameElement = $(`
    <a href="https://store.steampowered.com/app/${game.appid}"
       target="_blank"
       class="calendar-game ${isApproximate ? 'calendar-game-approximate wt-tooltip' : ''}">
        <img src="https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/${game.appid}/header.jpg"
             class="calendar-game-image">
        <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();
                        });
                    }
                };

                wtmodal.addClass('active');
                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 initialize() {
                createNotificationUI();
                updateStatusIndicator();
            }

            $(document).ready(initialize);
        })();
    }

    // Скрипт для страницы игры (VGT; отображения цен из агрегатора VGTimes) | https://store.steampowered.com/app/*
    if (scriptsConfig.vgtSales && window.location.pathname.includes('/app/')) {
        (function() {
            'use strict';

            const VGT_DATA_URL = 'https://gist.githubusercontent.com/0wn3dg0d/2644d328cca76b74c57804c7303b8606/raw/vgtstulex.json';
            const VGT_API_URL = 'https://vgtimes.ru/engine/modules/games/shops_table.php';
            const ITEMS_PER_PAGE = 40;
            let vgtDataMap = new Map();
            let vgtSteamMap = new Map();
            let vgtNameMap = new Map();

            function addVGTButton() {
                const actionsContainer = document.querySelector('#queueActionsCtn');
                if (!actionsContainer) return;

                const vgtContainer = document.createElement('div');
                vgtContainer.className = 'vgt_price_button';
                vgtContainer.innerHTML = `
                <div class="btnv6_blue_hoverfade btn_medium">
                    <span>Цены (VGT)</span>
                </div>
            `;

                vgtContainer.querySelector('div').addEventListener('click', (e) => {
                    e.preventDefault();
                    openVGTModal();
                });

                actionsContainer.appendChild(vgtContainer);
            }

            async function openVGTModal() {
                const vgtModal = createModal();
                document.body.appendChild(vgtModal);
                showLoading(vgtModal);
                setupModalEvents(vgtModal);

                try {
                    await loadVGTData();
                    const appId = getAppId();
                    const gameData = await findGameData(appId);

                    if (!gameData) {
                        showError(vgtModal, 'Игра не найдена в базе VGTimes');
                        return;
                    }

                    initModalContent(vgtModal, gameData);
                    await loadPrices(gameData['data-id'], vgtModal, 0);
                } catch (error) {
                    showError(vgtModal, 'Ошибка загрузки данных');
                    console.error('VGT Error:', error);
                }
            }

            async function loadVGTData() {
                const data = await fetchJson(VGT_DATA_URL);
                vgtDataMap = new Map(Object.entries(data));

                vgtSteamMap = new Map();
                vgtNameMap = new Map();
                for (const [key, value] of Object.entries(data)) {
                    if (value.steam !== null) {
                        vgtSteamMap.set(String(value.steam), value);
                    }
                    const normalized = normalizeName(value.title);
                    vgtNameMap.set(normalized, value);
                }
            }

            async function findGameData(appId) {
                if (vgtSteamMap.has(appId)) {
                    return vgtSteamMap.get(appId);
                }

                const gameName = getGameName();
                const normalized = normalizeName(gameName);

                if (vgtNameMap.has(normalized)) return vgtNameMap.get(normalized);

                const possibleMatches = findPossibleMatches(gameName, Array.from(vgtDataMap.values()));
                if (possibleMatches.length === 0) return null;

                const selectedGame = await showGameSelection(possibleMatches);
                return selectedGame;
            }

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

            function findPossibleMatches(gameName, games) {
                const cleanGameName = normalizeName(gameName);

                return games
                    .map(game => {
                        const cleanTitle = normalizeName(game.title);
                        const similarity = calculateSimilarity(cleanGameName, cleanTitle);
                        return {
                            ...game,
                            similarity
                        };
                    })
                    .filter(game => game.similarity > 50)
                    .sort((a, b) => b.similarity - a.similarity)
                    .slice(0, 5);
            }

            function calculateSimilarity(a, b) {
                const maxLen = Math.max(a.length, b.length);
                if (maxLen === 0) return 0;
                const distance = levenshteinDistance(a, b);
                return Math.round((1 - distance / maxLen) * 100);
            }

            function levenshteinDistance(a, b) {
                const matrix = Array.from({
                        length: a.length + 1
                    }, (_, i) =>
                    Array.from({
                            length: b.length + 1
                        }, (_, j) =>
                        i === 0 ? j : j === 0 ? i : 0));

                for (let i = 1; i <= a.length; i++) {
                    for (let j = 1; j <= b.length; j++) {
                        const cost = a[i - 1] === b[j - 1] ? 0 : 1;
                        matrix[i][j] = Math.min(
                            matrix[i - 1][j] + 1,
                            matrix[i][j - 1] + 1,
                            matrix[i - 1][j - 1] + cost
                        );
                    }
                }
                return matrix[a.length][b.length];
            }

            async function showGameSelection(games) {
                return new Promise(resolve => {
                    const modal = document.querySelector('.vgt_modal');
                    const content = modal.querySelector('.vgt_content');

                    content.innerHTML = `
            <div class="vgt_selection">
                <h3>Выберите игру:</h3>
                <div class="vgt_games_list">
                    ${games.map(game => `
                        <div class="vgt_game_item" data-id="${game['data-id']}">
                            <div class="vgt_game_title">${game.title}</div>
                            <div class="vgt_game_similar">Совпадение: ${game.similarity}%</div>
                        </div>
                    `).join('')}
                </div>
                <div class="vgt_selection_buttons">
                    <button class="vgt_cancel_btn">Ничего не подходит</button>
                </div>
            </div>
        `;

                    modal.querySelectorAll('.vgt_game_item').forEach(item => {
                        item.addEventListener('click', () => {
                            const selectedId = item.dataset.id;
                            const selectedGame = vgtDataMap.get(selectedId);
                            content.innerHTML = '';
                            resolve(selectedGame);
                        });
                    });

                    modal.querySelector('.vgt_cancel_btn').addEventListener('click', () => {
                        content.innerHTML = '';
                        resolve(null);
                    });
                });
            }

            function createModal() {
                const modal = document.createElement('div');
                modal.className = 'vgt_modal';
                modal.innerHTML = `
                <div class="vgt_modal-overlay"></div>
                <div class="vgt_modal-content">
                    <span class="vgt_close">&times;</span>
                    <div class="vgt_header"></div>
                    <div class="vgt_content"></div>
                </div>
            `;
                return modal;
            }

            function initModalContent(modal, gameData) {
                const header = modal.querySelector('.vgt_header');
                header.innerHTML = `<h2><a href="${gameData.url}" target="_blank">${gameData.title}</a></h2>`;
            }

            function setupModalEvents(modal) {
                modal.querySelector('.vgt_modal-overlay').addEventListener('click', () => modal.remove());

                const closeBtn = modal.querySelector('.vgt_close');
                closeBtn.addEventListener('mouseenter', () => closeBtn.style.color = '#67c1f5');
                closeBtn.addEventListener('mouseleave', () => closeBtn.style.color = '#aaa');
                closeBtn.onclick = () => modal.remove();
            }


            async function loadPrices(dataId, modal, skip) {
                const content = modal.querySelector('.vgt_content');
                content.innerHTML = '<div class="vgt_loading">Загрузка цен...</div>';

                try {
                    const params = new URLSearchParams({
                        skin: 'vgtimes',
                        id: dataId,
                        skip: skip,
                        sort: 'rele',
                        shop: 'all',
                        payment_method: 'all',
                        platform: 'all',
                        custom_filter: ''
                    });

                    const response = await postRequest(VGT_API_URL, params.toString());
                    const data = JSON.parse(response.responseText);

                    if (data.offercount === 0 || data.result.includes('notf gp_lb')) {
                        content.innerHTML = '<div class="vgt_error">Информация о ценах отсутствует в базе VGTimes.</div>';
                        return;
                    }

                    const tempDiv = document.createElement('div');
                    tempDiv.innerHTML = data.result;

                    if (tempDiv.querySelector('.notf.gp_lb')) {
                        content.innerHTML = '<div class="vgt_error">Информация о ценах отсутствует в базе VGTimes.</div>';
                        return;
                    }

                    tempDiv.querySelectorAll('.int, .s_rating, .s_reviews, .boosted, .s_promocodes, .promocode').forEach(el => el.remove());

                    processElements(tempDiv);

                    const shops = groupByShops(tempDiv);
                    const sortedShops = sortShops(shops);

                    content.innerHTML = generateShopColumns(sortedShops);

                    addExpandHandlers(content);

                    if (data.offercount > skip + ITEMS_PER_PAGE) {
                        const loadMoreBtn = document.createElement('button');
                        loadMoreBtn.className = 'vgt_load_more';
                        loadMoreBtn.textContent = 'Загрузить ещё';
                        loadMoreBtn.onclick = () => loadPrices(dataId, modal, skip + ITEMS_PER_PAGE);
                        content.appendChild(loadMoreBtn);
                    }

                } catch (error) {
                    content.innerHTML = '<div class="vgt_error">Ошибка загрузки цен</div>';
                }
            }

            function processElements(container) {
                container.querySelectorAll('img').forEach(img => img.remove());

                container.querySelectorAll('a').forEach(link => {
                    let href = link.getAttribute('href');

                    try {
                        if (href.startsWith('/')) {
                            href = 'https://vgtimes.ru' + href;
                        }

                        if (href.includes('/shop_redirect')) {
                            const urlObj = new URL(href);
                            const realUrl = urlObj.searchParams.get('url');
                            if (realUrl) {
                                href = decodeURIComponent(realUrl)
                                    .replace(/(https?:\/\/)?store\.steampowered\.com\/?/i, '')
                                    .replace(/^\/+/g, '');

                                const cleanUrl = href.split('?')[0];
                                href = cleanUrl.startsWith('http') ? cleanUrl : `https://${cleanUrl}`;
                            }
                        }

                        if (link.classList.contains('shopm')) {
                            const shopPath = new URL(href).pathname;
                            href = `https://vgtimes.ru${shopPath}`;
                        }

                        link.href = href;

                    } catch (e) {
                        console.error('URL processing error:', e);
                        link.href = '#';
                    }

                    link.removeAttribute('style');
                });
            }

            function groupByShops(container) {
                const shopsMap = new Map();

                container.querySelectorAll('.products_search_par').forEach(item => {
                    const shopElement = item.querySelector('.shopm');
                    if (!shopElement) return;

                    const shopName = shopElement.textContent.trim();
                    if (!shopsMap.has(shopName)) {
                        shopsMap.set(shopName, {
                            name: shopName,
                            items: [],
                            minPrice: Infinity,
                            url: shopElement.href
                        });
                    }

                    const priceElement = item.querySelector('.aprice');
                    let price = parsePrice(priceElement.textContent);

                    const shopData = shopsMap.get(shopName);
                    shopData.items.push(item);
                    if (price < shopData.minPrice) shopData.minPrice = price;
                });

                return Array.from(shopsMap.values());
            }

            function parsePrice(priceText) {
                if (priceText.toLowerCase() === 'бесплатно') return 0;
                const number = priceText.replace(/[^0-9,]/g, '').replace(',', '.');
                return parseFloat(number) || Infinity;
            }

            function sortShops(shops) {
                return shops.sort((a, b) => a.minPrice - b.minPrice);
            }

            function generateShopColumns(shops) {
                return `
                <div class="vgt_columns">
                    ${shops.map(shop => `
                        <div class="vgt_shop_column">
                            <div class="vgt_shop_header">
                                <a href="${shop.url}" target="_blank">${shop.name}</a>
                            </div>
                            <div class="vgt_shop_items">
                                ${shop.items.slice(0, 3).map(item => generateItemHtml(item)).join('')}
                            </div>
                            ${shop.items.length > 3 ? `
                                <div class="vgt_shop_expand" data-shop="${shop.name}" data-expanded="false">
                                    <div class="vgt_expand_content" style="display: none;">
                                        ${shop.items.slice(3).map(item => generateItemHtml(item)).join('')}
                                    </div>
                                    <div class="vgt_expand_toggle">...</div>
                                </div>
                            ` : ''}
                        </div>
                    `).join('')}
                </div>
            `;
            }

            function generateItemHtml(item) {
                const title = item.querySelector('.title').textContent.trim();
                const priceElement = item.querySelector('.aprice');
                const oldPriceElement = item.querySelector('.oldprice');
                const discountElement = item.querySelector('.percent');
                const link = item.querySelector('a.f_click').href;

                return `
                <div class="vgt_shop_item">
                    <a href="${link}" target="_blank" class="vgt_item_link">
                        <div class="vgt_item_title">${title}</div>
                        <div class="vgt_prices">
                            ${oldPriceElement ? `<span class="vgt_oldprice">${oldPriceElement.textContent}</span>` : ''}
                            <span class="vgt_aprice">${priceElement.textContent}</span>
                            ${discountElement ? `<span class="vgt_percent">${discountElement.textContent}</span>` : ''}
                        </div>
                    </a>
                </div>
            `;
            }

            function addExpandHandlers(content) {
                content.querySelectorAll('.vgt_shop_expand').forEach(expand => {
                    expand.querySelector('.vgt_expand_toggle').addEventListener('click', () => {
                        const isExpanded = expand.dataset.expanded === 'true';
                        expand.dataset.expanded = !isExpanded;
                        expand.querySelector('.vgt_expand_content').style.display = isExpanded ? 'none' : 'block';
                        expand.querySelector('.vgt_expand_toggle').textContent = isExpanded ? '...' : '▲';
                    });
                });
            }

            function getAppId() {
                return window.location.pathname.split('/')[2];
            }

            function getGameName() {
                return document.querySelector('.apphub_AppName')?.textContent || '';
            }

            function fetchJson(url) {
                return new Promise((resolve, reject) => {
                    GM_xmlhttpRequest({
                        method: 'GET',
                        url: url,
                        onload: (r) => resolve(JSON.parse(r.responseText)),
                        onerror: reject
                    });
                });
            }

            function postRequest(url, body) {
                return new Promise((resolve, reject) => {
                    GM_xmlhttpRequest({
                        method: 'POST',
                        url: url,
                        headers: {
                            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                            'X-Requested-With': 'XMLHttpRequest'
                        },
                        data: body,
                        onload: resolve,
                        onerror: reject
                    });
                });
            }

            function showLoading(modal) {
                modal.querySelector('.vgt_content').innerHTML = '<div class="vgt_loading">Загрузка...</div>';
            }

            function showError(modal, message) {
                modal.querySelector('.vgt_content').innerHTML = `<div class="vgt_error">${message}</div>`;
            }

            GM_addStyle(`
            .vgt_modal {
                display: block;
                position: fixed;
                z-index: 10000;
                left: 0;
                top: 0;
                width: 100%;
                height: 100%;
            }

            .vgt_modal-overlay {
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0,0,0,0.8);
            }

            .vgt_modal-content {
                background: #1b2838;
                margin: 5% auto;
                padding: 20px;
                border: 1px solid #67c1f5;
                width: 90%;
                max-width: 1200px;
                color: #c6d4df;
                position: relative;
                max-height: 80vh;
                overflow-y: auto;
                z-index: 10001;
            }

            .vgt_columns {
                display: grid;
                grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
                gap: 20px;
                margin-top: 20px;
            }

            .vgt_shop_column {
                background: #16202d;
                border-radius: 4px;
                padding: 15px;
                border: 1px solid #2a475e;
            }

            .vgt_shop_header {
                font-weight: bold;
                font-size: 16px;
                margin-bottom: 15px;
                padding-bottom: 10px;
                border-bottom: 1px solid #67c1f5;
            }

            .vgt_shop_header a {
                color: #67c1f5 !important;
                text-decoration: none;
            }

            .vgt_shop_item {
                margin: 10px 0;
                padding: 10px;
                background: rgba(27, 40, 56, 0.7);
                border-radius: 3px;
            }

            .vgt_item_title {
                font-size: 14px;
                margin-bottom: 5px;
                line-height: 1.3;
            }

            .vgt_prices {
                display: flex;
                align-items: center;
                gap: 8px;
                flex-wrap: wrap;
            }

            .vgt_aprice {
                color: #5ba32b;
                font-weight: bold;
                font-size: 15px;
            }

            .vgt_oldprice {
                text-decoration: line-through;
                opacity: 0.6;
                font-size: 13px;
            }

            .vgt_percent {
                color: #67c1f5;
                font-size: 13px;
            }

            .vgt_shop_expand {
                text-align: center;
                margin-top: 10px;
                cursor: pointer;
            }

            .vgt_expand_toggle {
                color: #67c1f5;
                font-weight: bold;
                padding: 5px;
                transition: opacity 0.2s;
            }

            .vgt_expand_toggle:hover {
                opacity: 0.8;
            }

            .vgt_load_more {
                background: #67c1f5;
                color: #1b2838;
                border: none;
                padding: 10px 20px;
                margin: 20px auto 0;
                display: block;
                cursor: pointer;
                border-radius: 3px;
                transition: background 0.2s;
            }

            .vgt_load_more:hover {
                background: #4fa0d1;
            }

            .vgt_close {
                color: #aaa;
                position: absolute;
                right: 20px;
                top: 10px;
                font-size: 28px;
                cursor: pointer;
                transition: color 0.2s;
            }

            .vgt_close:hover {
                color: #67c1f5;
            }

            .vgt_loading, .vgt_error {
                text-align: center;
                padding: 20px;
                font-size: 16px;
            }

            .vgt_price_button {
                position: absolute;
                left: 50%;
                transform: translateX(18px) translateY(-36px);
                z-index: 500;
                margin: 0 !important;
                padding: 0 !important;
            }

            .vgt_price_button .btnv6_blue_hoverfade {
                margin: 0;
                padding: 0 15px;
                font-size: 15px;
                height: 32px;
            }

            .vgt_selection {
                padding: 20px;
                text-align: center;
            }

            .vgt_games_list {
                display: grid;
                gap: 10px;
                margin-top: 15px;
            }

            .vgt_game_item {
                padding: 15px;
                background: #16202d;
                border-radius: 4px;
                cursor: pointer;
                transition: background 0.2s;
            }

            .vgt_game_item:hover {
                background: #1b2838;
            }

            .vgt_game_title {
                color: #67c1f5;
                font-weight: bold;
                margin-bottom: 5px;
            }

            .vgt_game_similar {
                color: #8f98a0;
                font-size: 12px;
            }

            .vgt_selection_buttons {
                margin-top: 20px;
                text-align: center;
            }

            .vgt_cancel_btn {
                background: #a34d4d;
                color: #fff;
                border: none;
                padding: 8px 20px;
                cursor: pointer;
                border-radius: 3px;
                transition: background 0.2s;
            }

            .vgt_cancel_btn:hover {
                background: #c25555;
            }
        `);

            addVGTButton();
        })();
    }

})();