Digitual

एक फंक्शन जो तुम्हाला कोणत्याही वेबपेजवर प्रतीबंधांपेक्षा जाऊ देतो

// ==UserScript==
// @name         Digitual
// @name:en      Digitual
// @name:es      Digitual
// @name:fr      Digitual
// @name:de      Digitual
// @name:it      Digitual
// @name:pt      Digitual
// @name:nl      Digitual
// @name:ru      Digitual
// @name:zh-CN   Digitual
// @name:ja      Digitual
// @name:ko      Digitual
// @name:hi      Digitual
// @name:ar      Digitual
// @name:vi      Digitual
// @name:tr      Digitual
// @name:pl      Digitual
// @name:uk      Digitual
// @name:el      Digitual
// @name:sv      Digitual
// @name:da      Digitual
// @name:no      Digitual
// @name:fi      Digitual
// @name:hu      Digitual
// @name:cs      Digitual
// @name:ro      Digitual
// @name:th      Digitual
// @name:id      Digitual
// @name:he      Digitual
// @name:fa      Digitual
// @name:bn      Digitual
// @name:ta      Digitual
// @name:ur      Digitual
// @name:pa      Digitual
// @name:ms      Digitual
// @name:te      Digitual
// @name:ml      Digitual
// @name:gu      Digitual
// @name:kn      Digitual
// @name:mr      Digitual
// @name:or      Digitual
// @name:sa      Digitual
// @name:mk      Digitual
// @name:bg      Digitual
// @name:hr      Digitual
// @name:sr      Digitual
// @name:sk      Digitual
// @name:sl      Digitual
// @name:lt      Digitual
// @name:lv      Digitual
// @name:et      Digitual
// @name:ca      Digitual
// @name:eu      Digitual
// @name:gl      Digitual
// @namespace    https://yomboxggt.neocities.org/Digitual
// @version      1.5
// @description  Una funcion que te permite acceder a cualquier pagina web sin ninguna renstriccion
// @description:en      A function that allows you to access any webpage without any restrictions
// @description:es      Una función que te permite acceder a cualquier página web sin ninguna restricción
// @description:fr      Une fonction qui vous permet d'accéder à n'importe quelle page web sans aucune restriction
// @description:de      Eine Funktion, die Ihnen den Zugriff auf jede Webseite ohne Einschränkungen ermöglicht
// @description:it      Una funzione che ti permette di accedere a qualsiasi pagina web senza alcuna restrizione
// @description:pt      Uma função que permite que você acesse qualquer página da web sem nenhuma restrição
// @description:nl      Een functie die u toelaat om toegang te krijgen tot elke website zonder beperkingen
// @description:ru      Функция, которая позволяет вам получить доступ к любой веб-странице без ограничений
// @description:zh-CN    允许您无限制地访问任何网页的函数
// @description:ja      制限なしでどのウェブページにもアクセスできる機能
// @description:ko      제한 없이 모든 웹 페이지에 접근할 수 있는 기능
// @description:hi      एक फ़ंक्शन जो आपको किसी भी वेब पेज पर बिना किसी रोक-टोक के पहुंचने देता है
// @description:ar      دالة تتيح لك الوصول إلى أي صفحة ويب دون أي قيود
// @description:vi      Một chức năng cho phép bạn truy cập bất kỳ trang web nào mà không có bất kỳ hạn chế nào
// @description:tr      Herhangi bir kısıtlama olmadan herhangi bir web sayfasına erişmenizi sağlayan bir fonksiyon
// @description:pl      Funkcja, która pozwala na dostęp do dowolnej strony internetowej bez żadnych ograniczeń
// @description:uk      Функція, яка дозволяє вам отримати доступ до будь-якої веб-сторінки без обмежень
// @description:el      Μια λειτουργία που σας επιτρέπει να προσπελάσετε οποιαδήποτε ιστοσελίδα χωρίς περιορισμούς
// @description:sv      En funktion som låter dig komma åt vilken hemsida som helst utan några restriktioner
// @description:da      En funktion, der gør det muligt at få adgang til enhver hjemmeside uden begrænsninger
// @description:no      En funksjon som lar deg få tilgang til hvilken som helst nettsted uten noen restriksjoner
// @description:fi      Toiminto, joka antaa sinulle pääsyn mihin tahansa verkkosivulle ilman rajoituksia
// @description:hu      Egy olyan funkció, amely lehetővé teszi bármely weblap elérését korlátozás nélkül
// @description:cs      Funkce, která vám umožňuje přístup k libovolné webové stránce bez jakýchkoliv omezení
// @description:ro      O funcție care vă permite să accesați orice pagină web fără restricții
// @description:th      ฟังก์ชันที่อนุญาตให้เข้าถึงเว็บเพจใดๆ ได้โดยไม่มีข้อจำกัดใดๆ
// @description:id      Fungsi yang memungkinkan Anda mengakses halaman web apa pun tanpa batasan
// @description:he      פונקציה המאפשרת לך לגשת לכל דף אינטרנט ללא כל הגבלה
// @description:fa      یک تابع که به شما اجازه می‌دهد تا به هر صفحه وب بدون هیچ قید و شرط دسترسی داشته باشید
// @description:bn      একটি ফাংশন যা আপনাকে কোনও ওয়েব পেজে প্রবেশ করতে দেয় কোনও বিধিনিষেধ ছাড়াই
// @description:ta      ஒரு செயல்பாடு அதனை உங்களுக்கு அனைத்து இணையதளங்களையும் எந்த விதமான கட்டுப்பாடுகளும் இல்லாமல் அணுக அனுமதிக்கிறது
// @description:ur      ایک ایسا فنکشن جو آپ کو کسی بھی ویب پیج پر کوئی تحریموں کے بغیر رسائی فراہم کرتا ہے
// @description:pa      ਇੱਕ ਫੰਕਸ਼ਨ ਜੋ ਤੁਹਾਡੇ ਲਈ ਕਿਸੇ ਵੀ ਵੈੱਬ ਪੇਜ ਤੱਕ ਪਹੁੰਚ ਬਿਨਾ ਕਿਸੇ ਵੀ ਪਾਬੰਦੀ ਵਾਲੇ ਦਿੱਤੀ ਹੈ
// @description:ms      Sebuah fungsi yang membenarkan anda mengakses laman web mana sahaja tanpa sebarang had
// @description:te      ఒక ఫంక్షన్ ఎటువంటి పరిమితులే లేకుండా ఏ వెబ్ పేజీకి కానీ చేరడానికి అనుమతిస్తుంది
// @description:ml      ഒരു ഫങ്ക്ഷൻ അതിന്റെ വഴി എല്ലാ വെബ് പേജുകളിലേക്കും പരിമിതികൾ ഒന്നുമില്ലാതെ പ്രവേശിക്കാനും അനുവദിക്കുന്നു
// @description:gu      એક ફંક્શન જે તમને કોઈ પણ વેબ પેજ પર જોવા માટે બંધો વગર મુજબ કરે છે
// @description:kn      ಒಂದು ಫಂಕ್ಷನ್ ಇದು ಯಾವುದೇ ಪರಿಸ್ಥಿತಿಗಳಿಲ್ಲದೆ ಯಾವುದೇ ವೆಬ್ ಪೇಜ್ಗೆ ಪ್ರವೇಶವನ್ನು ನೀಡುತ್ತದೆ
// @description:mr      एक फंक्शन जो तुम्हाला कोणत्याही वेबपेजवर प्रतीबंधांपेक्षा जाऊ देतो
// @description:or      ଏକ ଫଂକ୍ସନ ଯିଏ ତୁମେ କୌଣସି ଉପରି ବିନା ସମସ୍ୟା ପରିବର୍ତ୍ତନ କରିପାରିବ
// @description:sa      एक फ़ंक्शन जो आपको किसी भी वेब पेज तक बिना किसी प्रतिबंध के पहुंचने देता है
// @description:mk      Функција која ви овозможува пристап до секоја веб-страница без никакви ограничувања
// @description:bg      Функция, която ви позволява да достъпвате всяка уеб страница без никакви ограничения
// @description:hr      Funkcija koja vam omogućuje pristup bilo kojoj web stranici bez ikakvih ograničenja
// @description:sr      Функција која вам омогућава приступ било којој веб страници без икаквих ограничења
// @description:sk      Funkcia, ktorá vám umožňuje prístup k libovolnej webovej stránke bez akýchkoľvek obmedzení
// @description:sl      Funkcija, ki vam omogoča dostop do katere koli spletne strani brez katerih koli omejitev
// @description:lt      Funkcija, leidžianti prieiti prie bet kurio tinklalapio be jokios ribos
// @description:lv      Funkcija, kas ļauj atvērt jebkuru mājaslapu bez jebkādiem ierobežojumiem
// @description:et      Funktsioon, mis võimaldab ligipääsu igale veebilehele ilma piiranguteta
// @description:ca      Una funció que us permet accedir a qualsevol pàgina web sense cap restricció
// @description:eu      Funtzio bat web orri batera edozein sarbide-baldintzarik, web-orrian sarbide-baldintzarik, web-orrian sarbide-baldintzarik
// @description:gl      Unha función que lle permite acceder a calquera páxina web sen restricións
// @author       KaitoNeko
// @match        *://*/*
// @icon         https://i.ibb.co/s9z93NfZ/1744413593841.png
// @license      MPL-2.0
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_openInTab
// @grant        GM_registerMenuCommand
// @grant        GM_notification
// @grant        GM_download
// @grant        GM_getTab
// @grant        GM_saveTab
// @grant        GM_getTabs
// @grant        GM_deleteValue
// @grant        GM_info
// @grant        unsafeWindow
// @grant        GM_setClipboard
// @grant        GM.xmlHttpRequest
// @grant        GM.registerMenuCommand
// @grant        GM.notification
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM.addStyle
// @grant        GM.openInTab
// @grant        GM.deleteValue
// @grant        GM.info
// @grant        GM.setClipboard
// @require      https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.4/gsap.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js
// @connect      *
// @run-at       document-start
// @noframes
// ==/UserScript==

(function() {
    'use strict';

    const config = {
        version: "1.5",
        debugMode: false,
        bypassMethods: {
            paywalls: true,
            regionBlocks: true,
            adBlocks: true,
            cookieWalls: true,
            antiAdBlock: true,
            scrollLocks: true,
            inspectElement: true,
            rightClick: true,
            textSelection: true,
            loginWalls: true,
            rateLimits: true,
            downloadBlocks: true,
            clipboardBlocks: true,
            printBlocks: true,
            devToolsBlocks: true
        },
        stealthMode: {
            enabled: true,
            level: "aggressive",
            hideExtensions: true,
            fakeUserAgent: true,
            fakeScreenResolution: true,
            fakeTimeZone: true,
            fakeGeolocation: true,
            fakeIP: true,
            fakeWebRTC: true,
            fakeFonts: true,
            fakeCanvas: true,
            fakeAudioContext: true,
            fakeWebGL: true
        },
        performanceMode: {
            enabled: true,
            removeAds: true,
            removeTrackers: true,
            disableAnimations: false,
            blockThirdParty: true,
            lazyLoadImages: false,
            disableWebFonts: false
        },
        uiConfig: {
            enabled: true,
            position: "bottom-right",
            theme: "dark",
            animations: true,
            showNotifications: true,
            compactMode: false
        },
        autoBypass: true,
        advancedMode: false,
        learningMode: true,
        customRules: [],
        injectionPoints: [
            'document-start',
            'document-body',
            'document-end',
            'document-idle'
        ],
        proxyServers: [
            "https://api.allorigins.win/raw?url=",
            "https://api.codetabs.com/v1/proxy?quest=",
            "https://corsproxy.io/?", // Añade la URL directamente después del ?
            // "https://cors-anywhere.herokuapp.com/", // A menudo inestable o con límites
            // "https://proxy.cors.sh/", // Puede requerir API key para uso intensivo
        ],
        updateURL: "https://api.github.com/repos/KaitoNeko/digitual/contents/updates.json",
        rulesRepository: "https://api.github.com/repos/KaitoNeko/digitual-rules/contents/rules",
        feedbackURL: "https://api.digitual.tech/v1/feedback",
        analyticsURL: "https://api.digitual.tech/v1/analytics",
        maxRetryAttempts: 3,
        retryDelay: 1000,
        requestTimeout: 5000,
        cacheTTL: 3600000
    };

    const DEBUG_PREFIX = "%c[DIGITUAL]%c";
    const DEBUG_STYLE = "color: white; background: linear-gradient(90deg, #ff5555, #ff3385); padding: 2px 5px; border-radius: 3px;";
    const LOCAL_STORAGE_KEY = "digitual_ultra_settings_v7";
    const SESSION_CACHE = {
        rules: {},
        selectors: {},
        sitePatterns: {},
        performanceMetrics: {},
        resourceUsage: {},
        networkRequests: [],
        elementCounts: {},
        memoryUsage: {},
        timingMetrics: {}
    };
    const DOM_OBSERVERS = [];
    const PERFORMANCE_MARKS = {};
    const CRYPTO_KEYS = {
        primary: "4a7d1ed414474e4033ac29ccb8653d9b",
        secondary: "7f3b8c9a2e5d1f6c0b4e8a2d5f9c3e7",
        backup: "e6c5d4b3a2f1e0d9c8b7a6d5e4f3c2d1"
    };
    const ERROR_CODES = {
        PAYWALL_BYPASS_FAILED: 1001,
        REGION_BYPASS_FAILED: 1002,
        ADBLOCK_DETECTED: 1003,
        CONFIG_LOAD_FAILED: 1004,
        RULE_LOAD_FAILED: 1005,
        NETWORK_ERROR: 1006,
        SECURITY_ERROR: 1007,
        PERFORMANCE_ISSUE: 1008,
        COMPATIBILITY_WARNING: 1009,
        UPDATE_ERROR: 1010
    };
    const EVENT_TYPES = {
        PAYWALL_DETECTED: "paywall_detected",
        REGION_BLOCK_DETECTED: "region_block_detected",
        ADBLOCK_WARNING: "adblock_warning",
        ELEMENT_UNLOCKED: "element_unlocked",
        CONTENT_ACCESSED: "content_accessed",
        CONFIG_CHANGED: "config_changed",
        RULE_APPLIED: "rule_applied",
        ERROR_OCCURRED: "error_occurred",
        PERFORMANCE_METRIC: "performance_metric",
        RESOURCE_USAGE: "resource_usage"
    };
    const HTTP_HEADERS = {
        FAKE_HEADERS: {
            "X-Forwarded-For": "203.0.113.42",
            "X-Real-IP": "203.0.113.42",
            "CF-Connecting-IP": "203.0.113.42",
            "Client-IP": "203.0.113.42",
            "Via": "1.1 digitual-proxy"
        },
        CORS_HEADERS: {
            "Origin": "https://digitual.tech",
            "Referer": "https://digitual.tech/",
            "Sec-Fetch-Dest": "document",
            "Sec-Fetch-Mode": "navigate",
            "Sec-Fetch-Site": "cross-site"
        }
    };
    const SUPPORTED_SITES = {
        paywalls: [
            "medium.com", "bloomberg.com", "washingtonpost.com", "nytimes.com", "ft.com",
            "wsj.com", "theatlantic.com", "quora.com", "forbes.com", "statista.com",
            "businessinsider.com", "telegraph.co.uk", "newsweek.com", "scientificamerican.com",
            "nationalgeographic.com", "technologyreview.com", "wired.com", "newyorker.com",
            "economist.com", "harvard.edu", "stanford.edu", "mit.edu", "nature.com",
            "sciencemag.org", "jstor.org", "springer.com", "elsevier.com", "ieee.org",
            "acm.org", "researchgate.net", "ssrn.com", "arxiv.org", "tandfonline.com"
        ],
        regionBlocks: [
            "netflix.com", "hulu.com", "bbc.co.uk", "abc.net.au", "channel4.com",
            "crunchyroll.com", "disneyplus.com", "hbo.com", "peacocktv.com", "paramountplus.com",
            "amazon.com", "primevideo.com", "youtube.com", "twitch.tv", "dailymotion.com",
            "vimeo.com", "youku.com", "bilibili.com", "iq.com", "viu.com",
            "mytvsuper.com", "nowtv.com", "sky.com", "zattoo.com", "pluto.tv",
            "tubitv.com", "sling.com", "fubo.tv", "philo.com", "atttvnow.com"
        ],
        adBlocks: [
            "twitch.tv", "youtube.com", "dailymotion.com", "facebook.com", "instagram.com",
            "twitter.com", "reddit.com", "9gag.com", "pinterest.com", "tumblr.com",
            "vk.com", "weibo.com", "qq.com", "baidu.com", "naver.com",
            "daum.net", "yahoo.com", "aol.com", "msn.com", "outlook.com",
            "mail.ru", "ok.ru", "live.com", "bing.com", "duckduckgo.com"
        ],
        loginWalls: [
            "linkedin.com", "quora.com", "pinterest.com", "reddit.com", "medium.com",
            "researchgate.net", "academia.edu", "scribd.com", "slideshare.net", "issuu.com",
            "change.org", "patreon.com", "kickstarter.com", "indiegogo.com", "gofundme.com",
            "producthunt.com", "angel.co", "crunchbase.com", "glassdoor.com", "indeed.com"
        ]
    };

    const RuleEngine = {
        rules: {},
        selectors: {},
        patterns: {},
        customSelectors: [],
        dynamicRules: [],
        siteSpecificRules: {},
        rulePriorities: {},
        ruleCategories: {},
        ruleDependencies: {},
        ruleConditions: {},
        ruleActions: {},
        ruleExceptions: {},

        init: function() {
            this.loadDefaultRules();
            this.loadCustomRules();
            this.loadDynamicRules();
            this.compileSelectors();
            this.analyzeDOM();
        },

        loadDefaultRules: function() {
            this.rules = {
                paywall: {
                    selectors: [
                        '.paywall', '.overlay', '.modal', '.gate', '.premium',
                        '.membership', '.subscribe', '.blocked', '.locked',
                        '.restricted', '[class*="pay"]', '[class*="wall"]',
                        '[class*="gate"]', '[class*="modal"]', '[class*="overlay"]'
                    ],
                    actions: ['remove', 'hide', 'unlock'],
                    priority: 1,
                    category: 'content'
                },
                regionBlock: {
                    selectors: [
                        '.geoblock', '.region-restricted', '.not-available',
                        '.unavailable', '.location-warning', '[class*="geo"]',
                        '[class*="region"]', '[class*="country"]'
                    ],
                    actions: ['bypass', 'proxy'],
                    priority: 2,
                    category: 'access'
                },
                adBlock: {
                    selectors: [
                        '[id*="ad"]', '[class*="ad"]', 'iframe[src*="ads"]',
                        'iframe[src*="doubleclick"]', 'iframe[src*="adservice"]'
                    ],
                    actions: ['remove', 'block'],
                    priority: 3,
                    category: 'performance'
                },
                cookieWall: {
                    selectors: [
                        '.cookie', '.gdpr', '.privacy', '.consent',
                        '[class*="cookie"]', '[class*="gdpr"]',
                        '[class*="privacy"]', '[class*="consent"]'
                    ],
                    actions: ['remove', 'accept-all'],
                    priority: 2,
                    category: 'privacy'
                },
                scrollLock: {
                    selectors: [
                        'body[style*="overflow:hidden"]',
                        'html[style*="overflow:hidden"]',
                        '[class*="scroll-lock"]',
                        '[class*="noscroll"]'
                    ],
                    actions: ['unlock', 'override-style'],
                    priority: 1,
                    category: 'usability'
                }
            };

            this.patterns = {
                paywall: [
                    /paywall/i,
                    /premium-content/i,
                    /subscribe-to-read/i,
                    /member-exclusive/i
                ],
                regionBlock: [
                    /not-available-in-your-region/i,
                    /geoblocked/i,
                    /country-restricted/i,
                    /content-unavailable/i
                ],
                adBlock: [
                    /advertisement/i,
                    /adserver/i,
                    /doubleclick/i,
                    /googleads/i
                ]
            };
        },

        loadCustomRules: function() {
            try {
                const savedRules = GM_getValue('digitual_custom_rules');
                if (savedRules) {
                    const decrypted = this.decryptRules(savedRules);
                    this.customSelectors = decrypted.selectors || [];
                    this.siteSpecificRules = decrypted.siteRules || {};
                    Utils.debug.log("Reglas personalizadas cargadas:", decrypted);
                }
            } catch (e) {
                Utils.debug.error("Error al cargar reglas personalizadas:", e);
            }
        },

        loadDynamicRules: function() {
            this.fetchRemoteRules()
                .then(rules => {
                    this.dynamicRules = rules;
                    Utils.debug.log("Reglas dinámicas cargadas:", rules.length);
                })
                .catch(e => {
                    Utils.debug.error("Error al cargar reglas dinámicas:", e);
                });
        },

        fetchRemoteRules: async function() {
            try {
                const response = await Utils.network.fetch(config.rulesRepository, {
                    headers: {
                        "Accept": "application/vnd.github.v3.raw",
                        "User-Agent": "Digitual-Rules-Engine"
                    },
                    timeout: config.requestTimeout
                });

                if (response && response.status === 200) {
                    return JSON.parse(response.responseText);
                }
                return [];
            } catch (e) {
                Utils.debug.error(`Failed to fetch remote rules: ${e.message}`, e);
                return [];
            }
        },

        compileSelectors: function() {
            this.selectors = {
                paywall: this.rules.paywall.selectors.concat(this.customSelectors),
                regionBlock: this.rules.regionBlock.selectors,
                adBlock: this.rules.adBlock.selectors,
                cookieWall: this.rules.cookieWall.selectors,
                scrollLock: this.rules.scrollLock.selectors
            };

            const currentHost = window.location.hostname;
            if (this.siteSpecificRules[currentHost]) {
                for (const [type, selectors] of Object.entries(this.siteSpecificRules[currentHost])) {
                    if (this.selectors[type]) {
                        this.selectors[type] = this.selectors[type].concat(selectors);
                    }
                }
            }

            if (this.dynamicRules.length > 0) {
                this.dynamicRules.forEach(rule => {
                    if (this.selectors[rule.type]) {
                        this.selectors[rule.type].push(rule.selector);
                    }
                });
            }
        },

        analyzeDOM: function() {
            const html = document.documentElement.outerHTML;
            const classes = document.documentElement.className;
            const ids = Array.from(document.querySelectorAll('[id]')).map(el => el.id);

            this.detectedTypes = [];
            for (const [type, patterns] of Object.entries(this.patterns)) {
                if (patterns.some(pattern =>
                    pattern.test(html) ||
                    pattern.test(classes) ||
                    ids.some(id => pattern.test(id))
                )) {
                    this.detectedTypes.push(type);
                }
            }

            Utils.debug.log("Tipos de bloqueo detectados:", this.detectedTypes);
        },

        applyRules: function(types = null) {
            const rulesToApply = types || this.detectedTypes;
            let elementsProcessed = 0;

            rulesToApply.forEach(type => {
                if (this.selectors[type]) {
                    this.selectors[type].forEach(selector => {
                        try {
                            const elements = document.querySelectorAll(selector);
                            elements.forEach(element => {
                                this.processElement(element, type);
                                elementsProcessed++;
                            });
                        } catch (e) {
                            Utils.debug.error(`Error al aplicar selector ${selector}:`, e);
                        }
                    });
                }
            });

            Utils.debug.log(`Elementos procesados: ${elementsProcessed}`);
            return elementsProcessed;
        },

        processElement: function(element, type) {
            switch (type) {
                case 'paywall':
                    this.handlePaywall(element);
                    break;
                case 'regionBlock':
                    this.handleRegionBlock(element);
                    break;
                case 'adBlock':
                    this.handleAdBlock(element);
                    break;
                case 'cookieWall':
                    this.handleCookieWall(element);
                    break;
                case 'scrollLock':
                    this.handleScrollLock(element);
                    break;
                default:
                    this.handleGenericBlock(element);
            }
        },

        handlePaywall: function(element) {
            if (element.parentNode) {
                element.parentNode.removeChild(element);
                Utils.debug.log(`Paywall eliminado: ${element.tagName}`);
                this.trackEvent(EVENT_TYPES.ELEMENT_UNLOCKED, {
                    type: 'paywall',
                    element: element.tagName,
                    method: 'remove'
                });
            }
        },

        handleRegionBlock: function(element) {
            element.style.display = 'none';
            Utils.debug.log(`Bloqueo regional oculto: ${element.tagName}`);
            this.trackEvent(EVENT_TYPES.ELEMENT_UNLOCKED, {
                type: 'regionBlock',
                element: element.tagName,
                method: 'hide'
            });
        },

        handleAdBlock: function(element) {
            if (element.tagName === 'IFRAME') {
                element.src = '';
            }
            element.remove();
            Utils.debug.log(`Anuncio eliminado: ${element.tagName}`);
            this.trackEvent(EVENT_TYPES.ELEMENT_UNLOCKED, {
                type: 'adBlock',
                element: element.tagName,
                method: 'remove'
            });
        },

        handleCookieWall: function(element) {
            const acceptAll = element.querySelector('[onclick*="accept"], [class*="accept"]');
            if (acceptAll) {
                acceptAll.click();
                Utils.debug.log(`Cookie wall aceptado: ${element.tagName}`);
                this.trackEvent(EVENT_TYPES.ELEMENT_UNLOCKED, {
                    type: 'cookieWall',
                    element: element.tagName,
                    method: 'accept'
                });
            } else {
                element.remove();
                Utils.debug.log(`Cookie wall eliminado: ${element.tagName}`);
                this.trackEvent(EVENT_TYPES.ELEMENT_UNLOCKED, {
                    type: 'cookieWall',
                    element: element.tagName,
                    method: 'remove'
                });
            }
        },

        handleScrollLock: function(element) {
            if (element === document.body || element === document.documentElement) {
                element.style.overflow = 'auto';
                Utils.debug.log(`Scroll desbloqueado: ${element.tagName}`);
                this.trackEvent(EVENT_TYPES.ELEMENT_UNLOCKED, {
                    type: 'scrollLock',
                    element: element.tagName,
                    method: 'style-override'
                });
            }
        },

        handleGenericBlock: function(element) {
            element.remove();
            Utils.debug.log(`Elemento bloqueado eliminado: ${element.tagName}`);
            this.trackEvent(EVENT_TYPES.ELEMENT_UNLOCKED, {
                type: 'generic',
                element: element.tagName,
                method: 'remove'
            });
        },

        addCustomRule: function(site, type, selector) {
            if (!this.siteSpecificRules[site]) {
                this.siteSpecificRules[site] = {};
            }
            if (!this.siteSpecificRules[site][type]) {
                this.siteSpecificRules[site][type] = [];
            }
            this.siteSpecificRules[site][type].push(selector);
            this.saveCustomRules();
            this.compileSelectors();
        },

        saveCustomRules: function() {
            const rulesToSave = {
                selectors: this.customSelectors,
                siteRules: this.siteSpecificRules
            };
            const encrypted = this.encryptRules(rulesToSave);
            GM_setValue('digitual_custom_rules', encrypted);
        },

        encryptRules: function(rules) {
            try {
                return CryptoJS.AES.encrypt(
                    JSON.stringify(rules),
                    CRYPTO_KEYS.primary
                ).toString();
            } catch (e) {
                Utils.debug.error("Error al encriptar reglas:", e);
                return JSON.stringify(rules);
            }
        },

        decryptRules: function(encrypted) {
            try {
                const bytes = CryptoJS.AES.decrypt(encrypted, CRYPTO_KEYS.primary);
                return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
            } catch (e) {
                Utils.debug.error("Error al desencriptar reglas:", e);
                try {
                    return JSON.parse(encrypted); // Fallback si no estaba encriptado
                } catch (parseError) {
                    Utils.debug.error("Error al parsear reglas (fallback):", parseError);
                    return { selectors: [], siteRules: {} };
                }
            }
        },

        trackEvent: function(type, data) {
            SESSION_CACHE.events = SESSION_CACHE.events || [];
            SESSION_CACHE.events.push({
                timestamp: Date.now(),
                type,
                data
            });
        }
    };

    const Utils = {
        debug: {
            log: function(message, data = null) {
                if (config.debugMode) {
                    console.log(DEBUG_PREFIX + " " + message, DEBUG_STYLE, "", data !== null ? data : "");
                    PERFORMANCE_MARKS[`log_${Date.now()}`] = performance.now();
                }
            },

            warn: function(message, data = null) {
                if (config.debugMode) {
                    console.warn(DEBUG_PREFIX + " " + message, DEBUG_STYLE, "", data !== null ? data : "");
                }
            },

            error: function(message, data = null) {
                console.error(DEBUG_PREFIX + " " + message, DEBUG_STYLE, "", data !== null ? data : "");
                RuleEngine.trackEvent(EVENT_TYPES.ERROR_OCCURRED, { message, data, stack: new Error().stack });
            },

            table: function(data) {
                if (config.debugMode && console.table) {
                    console.table(data);
                }
            },

            time: function(label) {
                if (config.debugMode) {
                    console.time(label);
                }
            },

            timeEnd: function(label) {
                if (config.debugMode) {
                    console.timeEnd(label);
                }
            },

            trace: function(message) {
                if (config.debugMode) {
                    console.trace(DEBUG_PREFIX + " " + message, DEBUG_STYLE);
                }
            }
        },

        dom: {
            remove: function(selector) {
                document.querySelectorAll(selector).forEach(el => {
                    if (el.parentNode) el.parentNode.removeChild(el);
                    Utils.debug.log(`Elemento eliminado: ${selector}`);
                });
            },

            hide: function(selector) {
                document.querySelectorAll(selector).forEach(el => {
                    el.style.display = 'none';
                    Utils.debug.log(`Elemento oculto: ${selector}`);
                });
            },

            show: function(selector) {
                document.querySelectorAll(selector).forEach(el => {
                    el.style.display = '';
                    Utils.debug.log(`Elemento mostrado: ${selector}`);
                });
            },

            overrideStyles: function(selector, styles) {
                document.querySelectorAll(selector).forEach(el => {
                    Object.assign(el.style, styles);
                    Utils.debug.log(`Estilos anulados para: ${selector}`, styles);
                });
            },

            addStyles: function(css) {
                const style = document.createElement('style');
                style.textContent = css;
                (document.head || document.documentElement).appendChild(style);
                Utils.debug.log(`Estilos añadidos: ${css.substring(0, 50)}...`);
            },

            removeEventListeners: function(element, type) {
                const el = element || document;
                const listeners = this.getEventListeners(el);
                if (listeners[type]) {
                    listeners[type].forEach(listener => {
                        el.removeEventListener(type, listener.listener, listener.useCapture);
                    });
                    Utils.debug.log(`Listeners de ${type} eliminados`);
                }
            },

            getEventListeners: function(element) {
                const listeners = {};
                const allEvents = [
                    'click', 'mousedown', 'mouseup', 'mousemove', 'mouseover',
                    'mouseout', 'mouseenter', 'mouseleave', 'contextmenu',
                    'keydown', 'keypress', 'keyup', 'blur', 'focus',
                    'change', 'submit', 'reset', 'select', 'scroll'
                ];

                allEvents.forEach(type => {
                    listeners[type] = [];
                    const handler = element[`on${type}`];
                    if (typeof handler === 'function') {
                        listeners[type].push({
                            listener: handler,
                            useCapture: false
                        });
                    }
                });
                return listeners;
            },

            disableAllEventListeners: function() {
                const events = [
                    'scroll', 'mousedown', 'mouseup', 'click', 'dblclick',
                    'mousemove', 'mouseover', 'mouseout', 'mouseenter',
                    'mouseleave', 'contextmenu', 'keydown', 'keypress',
                    'keyup', 'blur', 'focus', 'change', 'submit', 'reset',
                    'select', 'dragstart', 'dragend', 'dragover', 'drop'
                ];

                events.forEach(type => {
                    this.removeEventListeners(document, type);
                    this.removeEventListeners(window, type);
                });

                Utils.debug.log("Todos los event listeners deshabilitados (intentado)");
            },

            enableTextSelection: function() {
                if (!config.bypassMethods.textSelection) return;

                const styles = `
                    * {
                        user-select: auto !important;
                        -webkit-user-select: auto !important;
                        -moz-user-select: auto !important;
                        -ms-user-select: auto !important;
                    }
                `;
                this.addStyles(styles);
                document.onselectstart = null;
                document.onmousedown = null;
                document.onmouseup = null;
                Utils.debug.log("Selección de texto habilitada");
            },

            enableRightClick: function() {
                if (!config.bypassMethods.rightClick) return;
                document.oncontextmenu = null;
                const styles = `
                    * {
                        pointer-events: auto !important;
                    }
                `;
                this.addStyles(styles);
                const scripts = document.querySelectorAll('script');
                scripts.forEach(script => {
                    if (script.textContent.includes('contextmenu') ||
                        script.textContent.includes('oncontextmenu') ||
                        script.textContent.includes('rightclick')) {
                        if (script.parentNode) script.parentNode.removeChild(script);
                    }
                });
                Utils.debug.log("Clic derecho habilitado");
            },

            enableInspectElement: function() {
                if (!config.bypassMethods.inspectElement) return;
                document.onkeydown = null;
                window.onkeydown = null;
                const scripts = document.querySelectorAll('script');
                scripts.forEach(script => {
                    if (script.textContent.includes('devtool') ||
                        script.textContent.includes('debugger') ||
                        script.textContent.includes('F12') ||
                        script.textContent.includes('Ctrl+Shift+I') ||
                        script.textContent.includes('contextmenu')) {
                        if (script.parentNode) script.parentNode.removeChild(script);
                    }
                });
                const inlineHandlers = document.querySelectorAll('[onkeydown]');
                inlineHandlers.forEach(el => {
                    el.removeAttribute('onkeydown');
                });
                Utils.debug.log("Inspección de elementos habilitada");
            }
        },

        network: {
            fetchWithProxy: async function(url, options = {}) {
                const proxyUrlBase = this.getRandomProxy();
                if (!proxyUrlBase) {
                    Utils.debug.warn("No hay servidores proxy configurados o disponibles. Intentando conexión directa.");
                    return this.fetch(url, options);
                }

                const proxyUrl = proxyUrlBase + encodeURIComponent(url);
                Utils.debug.log(`Intentando fetch con proxy: ${proxyUrlBase}...`);
                try {
                    const response = await this.fetch(proxyUrl, options);
                    Utils.debug.log(`Fetch con proxy exitoso para: ${url.substring(0,50)}...`);
                    return response;
                } catch (e) {
                    Utils.debug.error("Error al usar proxy, intentando directo", e);
                    return this.fetch(url, options);
                }
            },

            fetch: function(url, options = {}) {
                return new Promise((resolve, reject) => {
                    GM_xmlhttpRequest({
                        url,
                        method: options.method || 'GET',
                        headers: { ...this.spoofHeaders(), ...(options.headers || {}) },
                        timeout: options.timeout || config.requestTimeout,
                        onload: (response) => {
                            SESSION_CACHE.networkRequests.push({ url, status: response.status, method: options.method || 'GET' });
                            resolve(response);
                        },
                        onerror: (error) => {
                            SESSION_CACHE.networkRequests.push({ url, status: 'error', method: options.method || 'GET', error });
                            reject(error);
                        },
                        ontimeout: () => {
                            SESSION_CACHE.networkRequests.push({ url, status: 'timeout', method: options.method || 'GET' });
                            reject(new Error('Request timeout'));
                        }
                    });
                });
            },

            getRandomProxy: function() {
                if (config.proxyServers && config.proxyServers.length > 0) {
                    return config.proxyServers[Math.floor(Math.random() * config.proxyServers.length)];
                }
                return null;
            },

            spoofHeaders: function(customHeaders = {}) {
                const headers = {
                    ...HTTP_HEADERS.FAKE_HEADERS,
                    'User-Agent': this.generateFakeUserAgent(),
                    'Accept-Language': 'en-US,en;q=0.9',
                    'X-Requested-With': 'XMLHttpRequest',
                    ...customHeaders
                };
                if (config.stealthMode.fakeIP) {
                     headers["X-Forwarded-For"] = Utils.random.getRandomIP();
                     headers["X-Real-IP"] = Utils.random.getRandomIP();
                }
                return headers;
            },

            generateFakeUserAgent: function() {
                const agents = [
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/115.0",
                    "Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1",
                    "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
                ];
                return agents[Utils.random.getRandomInt(0, agents.length - 1)];
            }
        },

        security: {
            encryptData: function(data, key = CRYPTO_KEYS.primary) {
                try {
                    return CryptoJS.AES.encrypt(JSON.stringify(data), key).toString();
                } catch (e) {
                    Utils.debug.error("Error en encryptData:", e);
                    return JSON.stringify(data);
                }
            },

            decryptData: function(data, key = CRYPTO_KEYS.primary) {
                try {
                    const bytes = CryptoJS.AES.decrypt(data, key);
                    return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
                } catch (e) {
                    Utils.debug.error("Error en decryptData:", e);
                     try { return JSON.parse(data); } catch (pe) { return data; }
                }
            },

            protectFromDetection: function() {
                if (!config.stealthMode.enabled) return;

                try {
                    Object.defineProperty(navigator, 'webdriver', { get: () => false });
                    Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] }); // Un poco más creíble
                    Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });

                    if (config.stealthMode.fakeScreenResolution) {
                        Object.defineProperty(screen, 'width', { get: () => 1920, configurable: true });
                        Object.defineProperty(screen, 'height', { get: () => 1080, configurable: true });
                        Object.defineProperty(screen, 'availWidth', { get: () => 1920, configurable: true });
                        Object.defineProperty(screen, 'availHeight', { get: () => 1040, configurable: true }); // Considerar barra de tareas
                        Object.defineProperty(screen, 'colorDepth', { get: () => 24, configurable: true });
                        Object.defineProperty(screen, 'pixelDepth', { get: () => 24, configurable: true });
                    }

                    if (config.stealthMode.fakeUserAgent && navigator.userAgent) {
                         Object.defineProperty(navigator, 'userAgent', {
                            get: () => Utils.network.generateFakeUserAgent(),
                            configurable: true
                        });
                    }


                    if (config.stealthMode.fakeTimeZone) {
                        const originalDateTimeFormat = Intl.DateTimeFormat;
                        Intl.DateTimeFormat = function(...args) {
                            if (args.length === 0 || (args.length === 1 && args[0] === undefined)) {
                                return new originalDateTimeFormat('en-US', { timeZone: 'America/New_York' });
                            }
                            return new originalDateTimeFormat(...args);
                        };
                        Intl.DateTimeFormat.prototype.resolvedOptions = function() {
                            return { ...originalDateTimeFormat.prototype.resolvedOptions.call(this), timeZone: 'America/New_York' };
                        };
                    }


                    if (config.stealthMode.fakeGeolocation && navigator.geolocation) {
                        Object.defineProperty(navigator, 'geolocation', {
                            get: function() {
                                return {
                                    getCurrentPosition: function(success, error, options) {
                                        success({
                                            coords: {
                                                latitude: 40.712776 + (Math.random() - 0.5) * 0.01, // NY con pequeña variación
                                                longitude: -74.005974 + (Math.random() - 0.5) * 0.01,
                                                accuracy: Utils.random.getRandomInt(5,50),
                                                altitude: null,
                                                altitudeAccuracy: null,
                                                heading: null,
                                                speed: null
                                            },
                                            timestamp: Date.now() - Utils.random.getRandomInt(0,1000)
                                        });
                                    },
                                    watchPosition: function(success, error, options) { return Utils.random.getRandomInt(1,10000); },
                                    clearWatch: function(id) {}
                                };
                            },
                            configurable: true
                        });
                    }

                    if (typeof unsafeWindow !== 'undefined') {
                        unsafeWindow.TamperMonkey = undefined;
                        unsafeWindow.GM_info = undefined;
                        unsafeWindow.GM = undefined;
                    } else {
                        window.TamperMonkey = undefined;
                        window.GM_info = undefined;
                        window.GM = undefined;
                    }
                     Utils.debug.log("Modo sigiloso activado");
                } catch (e) {
                    Utils.debug.error("Error al activar modo sigiloso:", e);
                }
            }
        },

        random: {
            getRandomInt: function(min, max) {
                return Math.floor(Math.random() * (max - min + 1)) + min;
            },

            getRandomString: function(length = 8) {
                const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
                let result = '';
                for (let i = 0; i < length; i++) {
                    result += chars.charAt(Math.floor(Math.random() * chars.length));
                }
                return result;
            },

            getRandomHexColor: function() {
                return `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')}`;
            },

            getRandomIP: function() {
                return `${this.getRandomInt(1, 223)}.${this.getRandomInt(0, 255)}.${this.getRandomInt(0, 255)}.${this.getRandomInt(1, 254)}`; // Evitar IPs especiales
            }
        },

        time: {
            sleep: function(ms) {
                return new Promise(resolve => setTimeout(resolve, ms));
            },

            waitForElement: function(selector, timeout = 5000, interval = 100) {
                return new Promise((resolve, reject) => {
                    const endTime = Date.now() + timeout;
                    const check = () => {
                        const element = document.querySelector(selector);
                        if (element) {
                            resolve(element);
                        } else if (Date.now() >= endTime) {
                            reject(new Error(`Element ${selector} not found after ${timeout}ms`));
                        } else {
                            setTimeout(check, interval);
                        }
                    };
                    check();
                });
            },

            waitForFunction: function(fn, timeout = 5000, interval = 100) {
                return new Promise((resolve, reject) => {
                    const endTime = Date.now() + timeout;
                    const check = () => {
                        try {
                            const result = fn();
                            if (result) {
                                resolve(result);
                            } else if (Date.now() >= endTime) {
                                reject(new Error(`Function did not return truthy value after ${timeout}ms`));
                            } else {
                                setTimeout(check, interval);
                            }
                        } catch (e) {
                             reject(e);
                        }
                    };
                    check();
                });
            },

            formatDuration: function(ms) {
                if (ms < 0) ms = 0;
                if (ms < 1000) return `${ms}ms`;
                if (ms < 60000) return `${(ms / 1000).toFixed(2)}s`;
                const minutes = Math.floor(ms / 60000);
                const seconds = Math.floor((ms % 60000) / 1000);
                if (ms < 3600000) return `${minutes}m ${seconds}s`;
                const hours = Math.floor(ms / 3600000);
                return `${hours}h ${minutes % 60}m`;
            }
        },

        storage: {
            get: function(key, defaultValue = null) {
                try {
                    const value = GM_getValue(key);
                    if (value === undefined || value === null) return defaultValue;
                    return Utils.security.decryptData(value);
                } catch (e) {
                    Utils.debug.error(`Error al obtener clave ${key}:`, e);
                    return defaultValue;
                }
            },

            set: function(key, value) {
                try {
                    const encrypted = Utils.security.encryptData(value);
                    GM_setValue(key, encrypted);
                    return true;
                } catch (e) {
                    Utils.debug.error(`Error al establecer clave ${key}:`, e);
                    return false;
                }
            },

            remove: function(key) {
                try {
                    GM_deleteValue(key);
                    return true;
                } catch (e) {
                    Utils.debug.error(`Error al eliminar clave ${key}:`, e);
                    return false;
                }
            },

            clear: function() {
                try {
                    const keys = GM_listValues();
                    keys.forEach(key => GM_deleteValue(key));
                    Utils.debug.log("Almacenamiento limpiado.");
                    return true;
                } catch (e) {
                    Utils.debug.error("Error al limpiar almacenamiento:", e);
                    return false;
                }
            }
        },

        ui: {
            showNotification: function(message, duration = 3000, type = 'info') {
                if (!config.uiConfig.showNotifications) return;

                const notification = document.createElement('div');
                notification.style.position = 'fixed';
                notification.style.bottom = '70px';
                notification.style.right = '20px';
                notification.style.backgroundColor = type === 'error' ? '#d32f2f' : type === 'success' ? '#388e3c' : '#1976d2';
                notification.style.color = 'white';
                notification.style.padding = '10px 15px';
                notification.style.borderRadius = '5px';
                notification.style.zIndex = '2147483647';
                notification.style.boxShadow = '0 2px 10px rgba(0,0,0,0.2)';
                notification.style.fontFamily = 'Arial, sans-serif';
                notification.style.fontSize = '14px';
                notification.textContent = message;

                if (document.body) {
                    document.body.appendChild(notification);
                } else {
                    // Fallback si el body no está listo
                    const tempParent = document.documentElement || document;
                    tempParent.appendChild(notification);
                }


                gsap.from(notification, {
                    opacity: 0,
                    y: 20,
                    duration: 0.3
                });

                setTimeout(() => {
                    gsap.to(notification, {
                        opacity: 0,
                        y: -20,
                        duration: 0.3,
                        onComplete: () => {
                            if (notification.parentNode) notification.parentNode.removeChild(notification);
                        }
                    });
                }, duration);
            },

            createToast: function(message, type = 'info', duration = 3000) {
                 this.showNotification(message, duration, type); // Reutilizar showNotification para toasts
            },

            createModal: function(title, content, buttons = []) {
                const modalOverlay = document.createElement('div');
                modalOverlay.style.position = 'fixed';
                modalOverlay.style.top = '0';
                modalOverlay.style.left = '0';
                modalOverlay.style.width = '100%';
                modalOverlay.style.height = '100%';
                modalOverlay.style.backgroundColor = 'rgba(0,0,0,0.7)';
                modalOverlay.style.zIndex = '2147483646';
                modalOverlay.style.display = 'flex';
                modalOverlay.style.justifyContent = 'center';
                modalOverlay.style.alignItems = 'center';

                const modalContent = document.createElement('div');
                modalContent.style.backgroundColor = config.uiConfig.theme === 'dark' ? '#333' : '#fff';
                modalContent.style.color = config.uiConfig.theme === 'dark' ? '#eee' : '#333';
                modalContent.style.padding = '25px';
                modalContent.style.borderRadius = '8px';
                modalContent.style.maxWidth = '90%';
                modalContent.style.width = '500px';
                modalContent.style.maxHeight = '80vh';
                modalContent.style.overflowY = 'auto';
                modalContent.style.boxShadow = '0 5px 15px rgba(0,0,0,0.3)';
                modalContent.style.fontFamily = 'Arial, sans-serif';

                const modalTitle = document.createElement('h2');
                modalTitle.textContent = title;
                modalTitle.style.marginTop = '0';
                modalTitle.style.color = config.uiConfig.theme === 'dark' ? '#ff7070' : '#d32f2f';
                modalTitle.style.borderBottom = `1px solid ${config.uiConfig.theme === 'dark' ? '#555' : '#ddd'}`;
                modalTitle.style.paddingBottom = '10px';
                modalTitle.style.marginBottom = '15px';
                modalTitle.style.fontSize = '1.5em';

                const modalBody = document.createElement('div');
                if (typeof content === 'string') {
                    modalBody.innerHTML = content;
                } else if (content instanceof HTMLElement) {
                    modalBody.appendChild(content);
                }
                modalBody.style.fontSize = '1em';
                modalBody.style.lineHeight = '1.6';

                const modalFooter = document.createElement('div');
                modalFooter.style.marginTop = '25px';
                modalFooter.style.display = 'flex';
                modalFooter.style.justifyContent = 'flex-end';
                modalFooter.style.gap = '10px';

                buttons.forEach(buttonConfig => {
                    const btn = document.createElement('button');
                    btn.textContent = buttonConfig.text;
                    btn.style.padding = '10px 20px';
                    btn.style.borderRadius = '5px';
                    btn.style.border = 'none';
                    btn.style.cursor = 'pointer';
                    btn.style.fontWeight = 'bold';
                    btn.style.fontSize = '0.9em';
                    btn.style.transition = 'background-color 0.2s, transform 0.1s';

                    if (buttonConfig.primary) {
                        btn.style.backgroundColor = config.uiConfig.theme === 'dark' ? '#ff7070' : '#d32f2f';
                        btn.style.color = 'white';
                    } else {
                        btn.style.backgroundColor = config.uiConfig.theme === 'dark' ? '#555' : '#eee';
                        btn.style.color = config.uiConfig.theme === 'dark' ? '#eee' : '#333';
                        btn.style.border = `1px solid ${config.uiConfig.theme === 'dark' ? '#666' : '#ccc'}`;
                    }

                    btn.onmouseover = () => btn.style.opacity = '0.8';
                    btn.onmouseout = () => btn.style.opacity = '1';
                    btn.onmousedown = () => btn.style.transform = 'scale(0.98)';
                    btn.onmouseup = () => btn.style.transform = 'scale(1)';

                    btn.addEventListener('click', () => {
                        if (typeof buttonConfig.action === 'function') buttonConfig.action();
                        if (buttonConfig.closeModal !== false) {
                             if (modalOverlay.parentNode) modalOverlay.parentNode.removeChild(modalOverlay);
                        }
                    });
                    modalFooter.appendChild(btn);
                });

                if (buttons.length === 0) { // Add a default close button if none provided
                    const closeBtn = document.createElement('button');
                    closeBtn.textContent = 'Close';
                    closeBtn.style.padding = '10px 20px';
                    closeBtn.style.borderRadius = '5px';
                    closeBtn.style.border = 'none';
                    closeBtn.style.cursor = 'pointer';
                    closeBtn.style.backgroundColor = config.uiConfig.theme === 'dark' ? '#555' : '#eee';
                    closeBtn.style.color = config.uiConfig.theme === 'dark' ? '#eee' : '#333';
                    closeBtn.addEventListener('click', () => {
                        if (modalOverlay.parentNode) modalOverlay.parentNode.removeChild(modalOverlay);
                    });
                    modalFooter.appendChild(closeBtn);
                }


                modalContent.appendChild(modalTitle);
                modalContent.appendChild(modalBody);
                modalContent.appendChild(modalFooter);
                modalOverlay.appendChild(modalContent);

                if (document.body) {
                    document.body.appendChild(modalOverlay);
                } else {
                    (document.documentElement || document).appendChild(modalOverlay);
                }


                gsap.from(modalOverlay, { opacity: 0, duration: 0.2 });
                gsap.from(modalContent, { opacity: 0, y: -30, duration: 0.3, delay: 0.1 });

                return modalOverlay;
            }
        },

        performance: {
            startTimer: function(name) {
                PERFORMANCE_MARKS[name] = {
                    start: performance.now(),
                    end: null,
                    duration: null
                };
            },

            endTimer: function(name) {
                if (PERFORMANCE_MARKS[name] && PERFORMANCE_MARKS[name].start) {
                    PERFORMANCE_MARKS[name].end = performance.now();
                    PERFORMANCE_MARKS[name].duration =
                        PERFORMANCE_MARKS[name].end - PERFORMANCE_MARKS[name].start;
                } else {
                    Utils.debug.warn(`Timer "${name}" no fue iniciado o ya fue finalizado.`);
                }
            },

            getMetrics: function() {
                return {
                    memory: this.getMemoryUsage(),
                    timing: this.getTimingMetrics(),
                    resources: this.getResourceUsage()
                };
            },

            getMemoryUsage: function() {
                if (performance.memory) {
                    return {
                        jsHeapSizeLimit: performance.memory.jsHeapSizeLimit,
                        totalJSHeapSize: performance.memory.totalJSHeapSize,
                        usedJSHeapSize: performance.memory.usedJSHeapSize
                    };
                }
                return { note: "performance.memory not supported" };
            },

            getTimingMetrics: function() {
                const timing = {};
                for (const [name, mark] of Object.entries(PERFORMANCE_MARKS)) {
                    if (mark.duration !== null) {
                        timing[name] = mark.duration;
                    }
                }
                return timing;
            },

            getResourceUsage: function() {
                const elements = {
                    total: document.getElementsByTagName('*').length,
                    divs: document.getElementsByTagName('div').length,
                    scripts: document.getElementsByTagName('script').length,
                    iframes: document.getElementsByTagName('iframe').length,
                    images: document.getElementsByTagName('img').length
                };
                const requests = SESSION_CACHE.networkRequests.length;
                return { elements, requests };
            },

            optimizePage: function() {
                if (!config.performanceMode.enabled) return;
                Utils.debug.log("Iniciando optimización de página...");

                if (config.performanceMode.removeAds) {
                    RuleEngine.applyRules(['adBlock']);
                }
                if (config.performanceMode.blockThirdParty) {
                    this.blockThirdPartyRequests(); // Note: This sets up an observer, doesn't block retroactively.
                }
                if (config.performanceMode.disableAnimations) {
                    this.disableAnimations();
                }
                if (config.performanceMode.lazyLoadImages) {
                    this.enableLazyLoading();
                }
                if (config.performanceMode.disableWebFonts) {
                    this.disableWebFonts();
                }
                Utils.debug.log("Optimización de página completada");
            },

            blockThirdPartyRequests: function() {
                // This is complex to implement robustly in a userscript for *blocking*.
                // GM_xmlhttpRequest is already used, which can be controlled.
                // For resources loaded by the page (img, script src), it's harder.
                // A more realistic approach is to *monitor* and report, or try to remove elements from third parties.
                Utils.debug.log("Monitoreo de solicitudes de terceros activado (no bloqueo activo).");
                 if (typeof PerformanceObserver !== 'undefined') {
                    const observer = new PerformanceObserver((list) => {
                        list.getEntries().forEach(entry => {
                            try {
                                const url = new URL(entry.name);
                                if (url.hostname !== window.location.hostname) {
                                    SESSION_CACHE.networkRequests.push(entry);
                                    Utils.debug.log(`Solicitud de terceros detectada (PerformanceObserver): ${entry.name}`);
                                }
                            } catch(e) { /* Ignore invalid URLs */ }
                        });
                    });
                    observer.observe({ entryTypes: ["resource"] });
                }
            },

            disableAnimations: function() {
                const styles = `
                    *, *::before, *::after {
                        transition-property: none !important;
                        transition-duration: 0s !important;
                        transition-delay: 0s !important;
                        animation-name: none !important;
                        animation-duration: 0s !important;
                        animation-delay: 0s !important;
                        scroll-behavior: auto !important;
                    }
                `;
                Utils.dom.addStyles(styles);
                Utils.debug.log("Animaciones deshabilitadas.");
            },

            enableLazyLoading: function() {
                document.querySelectorAll('img:not([loading])').forEach(img => {
                    img.loading = 'lazy';
                });
                document.querySelectorAll('iframe:not([loading])').forEach(iframe => {
                    iframe.loading = 'lazy';
                });
                Utils.debug.log("Lazy loading habilitado para imágenes e iframes.");
            },

            disableWebFonts: function() {
                const styles = `
                    @font-face {
                        font-family: 'DigitualForceDefault'; /* Nombre único para evitar conflictos */
                        src: local('Arial'), local('Helvetica'), local('sans-serif'); /* Fuentes comunes del sistema */
                        unicode-range: U+000-5FF; /* Rango amplio para cubrir la mayoría de los caracteres occidentales */
                    }
                    * {
                        font-family: 'DigitualForceDefault', sans-serif !important;
                    }
                `;
                Utils.dom.addStyles(styles);
                Utils.debug.log("Fuentes web deshabilitadas (intentado).");
            }
        },

        compatibility: {
            checkFeatures: function() {
                const features = {
                    GM_xmlhttpRequest: typeof GM_xmlhttpRequest !== 'undefined',
                    GM_setValue: typeof GM_setValue !== 'undefined',
                    GM_addStyle: typeof GM_addStyle !== 'undefined',
                    gsap: typeof gsap !== 'undefined',
                    CryptoJS: typeof CryptoJS !== 'undefined',
                    jQuery: typeof jQuery !== 'undefined',
                    lodash: typeof _ !== 'undefined',
                    MutationObserver: typeof MutationObserver !== 'undefined',
                    PerformanceObserver: typeof PerformanceObserver !== 'undefined'
                };
                Utils.debug.log("Compatibilidad de características:", features);
                return features;
            },

            addPolyfills: function() {
                let polyfillsAdded = false;
                if (!Element.prototype.remove) {
                    Element.prototype.remove = function() {
                        if (this.parentNode) {
                            this.parentNode.removeChild(this);
                        }
                    };
                    polyfillsAdded = true;
                }
                if (typeof NodeList !== 'undefined' && NodeList.prototype && !NodeList.prototype.forEach) {
                    NodeList.prototype.forEach = Array.prototype.forEach;
                    polyfillsAdded = true;
                }
                if (!String.prototype.includes) {
                    String.prototype.includes = function(search, start) {
                        'use strict';
                        if (typeof start !== 'number') {
                            start = 0;
                        }
                        if (start + search.length > this.length) {
                            return false;
                        } else {
                            return this.indexOf(search, start) !== -1;
                        }
                    };
                    polyfillsAdded = true;
                }
                if (polyfillsAdded) {
                    Utils.debug.log("Polyfills añadidos donde era necesario.");
                }
            }
        }
    };

    const PaywallBypass = {
        bypassAll: async function() {
            if (!config.bypassMethods.paywalls) return;

            Utils.debug.log("Iniciando bypass de paywalls...");
            Utils.performance.startTimer('paywall_bypass_all');

            try {
                RuleEngine.applyRules(['paywall']);
                await this.bypassForCurrentSite();
                await this.tryAlternateMethods();
                this.enableBlockedFeatures();

                Utils.debug.log("Bypass de paywalls completado");
                Utils.ui.showNotification("Paywalls eliminados con éxito", 3000, 'success');
            } catch (e) {
                Utils.debug.error("Error en bypass de paywalls:", e);
                Utils.ui.showNotification("Error al eliminar paywalls", 3000, 'error');
            } finally {
                Utils.performance.endTimer('paywall_bypass_all');
            }
        },

        bypassForCurrentSite: async function() {
            const hostname = window.location.hostname;
            Utils.debug.log(`Intentando bypass específico para: ${hostname}`);

            if (hostname.includes('medium.com')) await this.bypassMedium();
            else if (hostname.includes('nytimes.com')) await this.bypassNYT();
            // Añadir más sitios aquí si es necesario, ej:
            // else if (hostname.includes('bloomberg.com')) await this.bypassBloomberg();
            // else if (hostname.includes('wsj.com')) await this.bypassWSJ();
            else {
                Utils.debug.log(`No hay bypass específico para ${hostname}. Se usarán métodos genéricos.`);
            }
        },

        bypassMedium: async function() {
            Utils.debug.log("Ejecutando bypass específico para Medium");
            Utils.dom.remove('[data-testid="paywall-background"]');
            Utils.dom.remove('[data-testid="paywall-container"]');
            Utils.dom.remove('.meteredContent');
            Utils.dom.overrideStyles('body, html', { overflow: 'auto !important' });
            window.onscroll = null; // Intentar eliminar manejadores de scroll
            // Podría intentar buscar el contenido en `window.__APOLLO_STATE__` o similar
        },

        bypassNYT: async function() {
            Utils.debug.log("Ejecutando bypass específico para NYTimes");
            Utils.dom.remove('#gateway-content');
            Utils.dom.remove('.css-1bd8bfl'); // Selector común para el overlay
            Utils.dom.remove('[data-testid="gateway-container"]');
            Utils.dom.overrideStyles('body, html', { overflow: 'auto !important' });
            document.cookie = "NYT-S=0; path=/; domain=.nytimes.com; expires=Thu, 01 Jan 1970 00:00:00 GMT"; // Intenta limpiar cookies de paywall
        },

        tryAlternateMethods: async function() {
            Utils.debug.log("Probando métodos alternativos de bypass...");
            if (await this.tryCachedVersion()) return;
            // if (await this.tryAMPVersion()) return; // AMP a menudo es menos útil o no existe
            // if (await this.tryArchiveToday()) return; // Archive.today es lento y puede tener captchas
        },

        tryCachedVersion: async function() {
            Utils.debug.log("Intentando cargar versión de caché de Google...");
            try {
                const cachedUrl = `https://webcache.googleusercontent.com/search?q=cache:${encodeURIComponent(window.location.href)}`;
                const response = await Utils.network.fetchWithProxy(cachedUrl, { method: 'GET' });

                if (response.status === 200 && response.responseText) {
                    const parser = new DOMParser();
                    const doc = parser.parseFromString(response.responseText, 'text/html');
                    const mainContentSelectors = ['article', '#main', '#content', '.main-content', '.article-body', 'main'];
                    let contentElement = null;
                    for (const selector of mainContentSelectors) {
                        contentElement = doc.querySelector(selector);
                        if (contentElement) break;
                    }

                    if (contentElement && contentElement.innerHTML.length > 500) { // Heurística simple
                        Utils.debug.log("Contenido encontrado en caché de Google. Reemplazando cuerpo de la página...");
                        document.body.innerHTML = `<h1>Contenido cargado desde Google Cache</h1>${contentElement.innerHTML}`;
                        Utils.dom.addStyles("body { padding: 20px; font-family: sans-serif; } h1 { color: #555; border-bottom: 1px solid #ccc; padding-bottom: 10px; }");
                        return true;
                    }
                }
                Utils.debug.log("No se encontró contenido útil en caché de Google.");
            } catch (e) {
                Utils.debug.error("Error al intentar cargar versión cacheada:", e);
            }
            return false;
        },

        enableBlockedFeatures: function() {
            if (config.bypassMethods.textSelection) Utils.dom.enableTextSelection();
            if (config.bypassMethods.rightClick) Utils.dom.enableRightClick();
            if (config.bypassMethods.inspectElement) Utils.dom.enableInspectElement();
        },

        handleNewElements: function(nodeList) { // Para MutationObserver
            if (!nodeList || nodeList.length === 0) return;
            nodeList.forEach(node => {
                if (node.nodeType === Node.ELEMENT_NODE) {
                    // Re-aplicar reglas a los nuevos elementos si es necesario
                    // Esto puede ser costoso, usar con cuidado o con selectores más específicos
                    if (this.detectPaywallElement(node)) {
                         Utils.debug.log("Nuevo elemento de paywall detectado y eliminado:", node);
                         if (node.parentNode) node.parentNode.removeChild(node);
                    }
                }
            });
        },

        detectPaywallElement: function(element) { // Chequea un elemento específico
            if (!element || typeof element.matches !== 'function') return false;
            const paywallSelectors = RuleEngine.selectors.paywall || [];
            return paywallSelectors.some(selector => {
                try { return element.matches(selector); } catch(e) { return false; }
            });
        }
    };

    const RegionBypass = {
        bypassAll: async function() {
            if (!config.bypassMethods.regionBlocks) return;
            Utils.debug.log("Iniciando bypass de bloqueo regional...");
            RuleEngine.applyRules(['regionBlock']);
            // La lógica de bypass regional a menudo implica el uso de proxies para la solicitud inicial
            // o modificar cabeceras, lo cual Utils.network.fetchWithProxy ya intenta.
            // Un bypass regional más avanzado requeriría proxies específicos por región,
            // lo cual está fuera del alcance simple de este script.
            Utils.ui.showNotification("Intento de bypass regional aplicado.", 3000, 'info');
        }
    };

    const AntiAdblockBypass = {
         bypassAll: async function() {
            if (!config.bypassMethods.antiAdBlock) return;
            Utils.debug.log("Iniciando bypass de anti-adblock...");
            // Eliminar selectores comunes de mensajes anti-adblock
            const antiAdblockSelectors = [
                '[class*="adblock"]', '[id*="adblock"]',
                '[class*="blocker"]', '[id*="blocker"]',
                '.adblock-message', '.please-disable-adblock'
            ];
            antiAdblockSelectors.forEach(selector => Utils.dom.remove(selector));
            // Algunas páginas pueden tener scripts más sofisticados.
            // Esto es un intento básico.
            Utils.ui.showNotification("Intento de bypass anti-adblock aplicado.", 3000, 'info');
        }
    };

    const AdvancedUI = {
        init: function() {
            if (!config.uiConfig.enabled) return;
            Utils.debug.log("Inicializando UI avanzada...");
            // Aquí se podrían registrar comandos de menú de Tampermonkey, crear un panel de control, etc.
            // Ejemplo: GM_registerMenuCommand("Configuración de Digitual", this.showSettingsModal);
        },
        showSettingsModal: function() {
            // Implementación de un modal de configuración
            // Utils.ui.createModal("Configuración de Digitual", "Aquí irían las opciones...", [{text: "Guardar", action: () => {}, primary: true}]);
        },
        cleanup: function() {
            // Limpiar elementos de UI si es necesario
        }
    };

    const MachineLearning = {
        init: function() {
            if (!config.learningMode) return;
            Utils.debug.log("Módulo de aprendizaje automático (simulado) inicializado.");
            // En una implementación real, esto cargaría modelos, recolectaría datos anónimos (con consentimiento), etc.
        }
    };

    function initialize() {
        Utils.debug.log(`Inicializando Digitual v${config.version}...`);
        Utils.performance.startTimer('full_initialization');
        Utils.compatibility.checkFeatures();
        Utils.compatibility.addPolyfills();

        loadConfig(); // Cargar configuración guardada por el usuario
        Utils.security.protectFromDetection(); // Aplicar medidas de sigilo temprano

        RuleEngine.init();
        AdvancedUI.init();
        MachineLearning.init();

        if (config.autoBypass) {
            if (config.bypassMethods.paywalls) PaywallBypass.bypassAll();
            if (config.bypassMethods.regionBlocks) RegionBypass.bypassAll();
            if (config.bypassMethods.antiAdBlock) AntiAdblockBypass.bypassAll();
        }

        if (config.performanceMode.enabled) {
            Utils.performance.optimizePage();
        }

        setupObservers();

        Utils.debug.log("Digitual completamente inicializado.");
        Utils.performance.endTimer('full_initialization');
        const initTime = PERFORMANCE_MARKS.full_initialization ? PERFORMANCE_MARKS.full_initialization.duration : null;
        if (initTime) {
            Utils.debug.log(`Tiempo de inicialización: ${Utils.time.formatDuration(initTime)}`);
        }
        Utils.ui.showNotification(`Digitual v${config.version} activado.`, 2000, 'success');
    }

    function loadConfig() {
        const savedConfig = Utils.storage.get(LOCAL_STORAGE_KEY);
        if (savedConfig && typeof savedConfig === 'object') {
            try {
                // Fusionar de forma segura para no sobrescribir toda la estructura si hay nuevas claves en `config`
                for (const key in config) {
                    if (savedConfig.hasOwnProperty(key) && typeof savedConfig[key] === typeof config[key]) {
                        if (typeof config[key] === 'object' && !Array.isArray(config[key]) && config[key] !== null) {
                            Object.assign(config[key], savedConfig[key]);
                        } else {
                            config[key] = savedConfig[key];
                        }
                    }
                }
                Utils.debug.log("Configuración cargada desde almacenamiento:", config);
            } catch (e) {
                Utils.debug.error("Error al cargar o fusionar configuración:", e);
            }
        } else {
            Utils.debug.log("No se encontró configuración guardada o es inválida, usando valores por defecto.");
        }
    }

    function setupObservers() {
        if (typeof MutationObserver === "undefined") {
            Utils.debug.warn("MutationObserver no está disponible. Algunas funciones dinámicas pueden no funcionar.");
            return;
        }
        const observer = new MutationObserver(mutations => {
            if (PaywallBypass.handleNewElements) { // Asegurarse que la función existe
                 PaywallBypass.handleNewElements(mutations.flatMap(m => Array.from(m.addedNodes)));
            }
            // Aquí se podrían añadir más manejadores para otros tipos de bypass si es necesario
        });

        // Observar el body es un buen compromiso, observar documentElement puede ser demasiado.
        // Esperar a que el body exista.
        const observeBody = () => {
            if (document.body) {
                 observer.observe(document.body, { childList: true, subtree: true });
                 DOM_OBSERVERS.push(observer);
                 Utils.debug.log("MutationObserver iniciado en document.body.");
            } else {
                setTimeout(observeBody, 100); // Reintentar pronto
            }
        };
        observeBody();
    }

    function cleanup() {
        Utils.debug.log("Realizando limpieza de Digitual...");
        DOM_OBSERVERS.forEach(observer => observer.disconnect());
        DOM_OBSERVERS.length = 0; // Vaciar el array
        AdvancedUI.cleanup();
        Utils.debug.log("Limpieza completada.");
    }

    // Manejo de la inicialización según el estado del documento
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initialize);
    } else {
        // Si 'interactive' o 'complete', es seguro inicializar.
        // 'document-start' es muy temprano para algunas operaciones DOM.
        // Esperar un poco para asegurar que el entorno esté más estable.
        setTimeout(initialize, 0);
    }

    window.addEventListener('beforeunload', cleanup);
    // 'unload' es menos fiable que 'beforeunload' para tareas de limpieza.

    // Exportar API para desarrollo si está en modo debug
    if (config.debugMode) {
        const digitualAPI = {
            config,
            Utils,
            PaywallBypass,
            RegionBypass,
            AntiAdblockBypass,
            RuleEngine,
            loadConfig,
            initialize,
            cleanup
        };
        if (typeof unsafeWindow !== 'undefined') {
            unsafeWindow.__DIGITUAL_API = digitualAPI;
        } else {
            window.__DIGITUAL_API = digitualAPI;
        }
        Utils.debug.log("API de Digitual exportada a window.__DIGITUAL_API");
    }
})();