Digitual

Une fonction qui vous permet d'accéder à n'importe quelle page web sans aucune restriction

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

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