Greasy Fork

Greasy Fork is available in English.

Duolingo DuoHacker — 新安全模式 Duolingo 农场工具

最佳免费多邻国破解版,提供经验值速刷、宝石速刷、连胜速刷,甚至还有免费超级道具!

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Duolingo DuoHacker
// @name:en      Duolingo DuoHacker
// @name:zh-CN   Duolingo DuoHacker — 新安全模式 Duolingo 农场工具
// @name:zh-TW   Duolingo DuoHacker — 新安全模式 Duolingo 農場工具
// @name:ja      Duolingo DuoHacker — 新しい安全モード Duolingo ファーミングツール
// @name:es      Duolingo DuoHacker — Nueva Modo Seguro Herramienta para farmear en Duolingo
// @name:es-MX   Duolingo DuoHacker — Nuevo Modo Seguro Herramienta de cultivo de Duolingo
// @name:es-AR   Duolingo DuoHacker — Nuevo Modo Seguro Herramienta de farming de Duolingo
// @name:ru      Duolingo DuoHacker — Новый безопасный режим для фарминга Duolingo
// @name:uk      Duolingo DuoHacker — Новий безпечний режим для фарму Duolingo
// @name:pt-BR   Duolingo DuoHacker — Novo Modo Seguro Ferramenta para farmar no Duolingo
// @name:pt      Duolingo DuoHacker — Novo Modo Seguro Ferramenta para farmar no Duolingo
// @name:de      Duolingo DuoHacker — Neuer Sicherer Modus Duolingo Farming-Tool
// @name:de-AT   Duolingo DuoHacker — Neuer Sicherer Modus Duolingo Farming-Tool
// @name:de-CH   Duolingo DuoHacker — Neuer Sicherer Modus Duolingo Farming-Tool
// @name:it      Duolingo DuoHacker — Nuova Modalità Sicura Strumento di farming Duolingo
// @name:ko      Duolingo DuoHacker — 새로운 안전 모드 Duolingo 팜 도구
// @name:hi      Duolingo DuoHacker — नया सुरक्षित मोड Duolingo फार्मिंग टूल
// @name:bn      Duolingo DuoHacker — নতুন নিরাপদ মোড Duolingo ফার্মিং টুল
// @name:ar      Duolingo DuoHacker — الوضع الآمن الجديد أداة زراعة Duolingo
// @name:fa      Duolingo DuoHacker — حالت ایمن جدید ابزار کشاورزی Duolingo
// @name:tr      Duolingo DuoHacker — Yeni Güvenli Mod Duolingo Farming Aracı
// @name:pl      Duolingo DuoHacker — Nowy Tryb Bezpieczny Narzędzie do farmienia Duolingo
// @name:vi      Duolingo DuoHacker - Tự Động Farm KN Duolingo
// @name:th      Duolingo DuoHacker — โหมดปลอดภัยใหม่ เครื่องมือการเก็บเกี่ยว Duolingo
// @name:id      Duolingo DuoHacker — Mode Aman Baru Alat Pertanian Duolingo
// @name:fr      Duolingo DuoHacker — Nouveau Mode Sécurisé Outil de farming Duolingo
// @name:fr-CA   Duolingo DuoHacker — Nouveau Mode Sécurisé Outil de farming Duolingo
// @name:fr-BE   Duolingo DuoHacker — Nouveau Mode Sécurisé Outil de farming Duolingo
// @name:fr-CH   Duolingo DuoHacker — Nouveau Mode Sécurisé Outil de farming Duolingo
// @name:nl      Duolingo DuoHacker — Nieuwe Veilige Modus Duolingo Farming-Tool
// @name:nl-BE   Duolingo DuoHacker — Nieuwe Veilige Modus Duolingo Farming-Tool
// @name:da      Duolingo DuoHacker — Ny sikker tilstand Duolingo Farming-værktøj
// @name:sv      Duolingo DuoHacker — Nytt säkert läge Duolingo Farming-verktyg
// @name:no      Duolingo DuoHacker — Ny sikker modus Duolingo Farming-verktøy
// @name:fi      Duolingo DuoHacker — Uusi turvallinen tila Duolingo Farming-työkalu
// @name:cs      Duolingo DuoHacker — Nový bezpečný režim Duolingo Farming-nástroj
// @name:sk      Duolingo DuoHacker — Nový bezpečný režim Duolingo Farming-nástroj
// @name:hu      Duolingo DuoHacker — Új biztonságos mód Duolingo Farming-eszköz
// @name:ro      Duolingo DuoHacker — Noul Mod Securizat Instrument de farming Duolingo
// @name:el      Duolingo DuoHacker — Νέα ασφαλής λειτουργία εργαλείο farming Duolingo
// @name:he      Duolingo DuoHacker — מצב בטוח חדש כלי farming של Duolingo
// @name:ca      Duolingo DuoHacker — Nou Mode Segur Eina de farming de Duolingo
// @name:gl      Duolingo DuoHacker — Novo Modo Seguro Ferramenta de farming de Duolingo
// @name:eu      Duolingo DuoHacker — Modo Seguro Berria Duolingo Farming-tresna
// @name:sq      Duolingo DuoHacker — Modaliteti i ri i sigurt Mjeti i farming të Duolingo
// @name:hr      Duolingo DuoHacker — Novi sigurni način Alat za farmanje Duolingo
// @name:sr      Duolingo DuoHacker — Нови сигуран режим Duolingo алат за фармање
// @name:bg      Duolingo DuoHacker — Нов безопасен режим Duolingo инструмент за фармене
// @name:sl      Duolingo DuoHacker — Novi varni način Orodje za farmanje Duolingo
// @name:lt      Duolingo DuoHacker — Naujas saugus režimas Duolingo ūkio įrankis
// @name:lv      Duolingo DuoHacker — Jauns drošs režīms Duolingo lauksaimniecības rīks
// @name:et      Duolingo DuoHacker — Uus turvaline režiim Duolingo farming-tööriist
// @name:sw      Duolingo DuoHacker — Njia mpya salama ya zana ya ukulima wa Duolingo
// @name:ms      Duolingo DuoHacker — Mod Selamat Baru Alat Pertanian Duolingo
// @name:fil     Duolingo DuoHacker — Bagong Ligtas na Mode Duolingo Farming Tool
// @name:tl      Duolingo DuoHacker — Bagong Ligtas na Mode Duolingo Farming Tool
// @description  Best Free Duolingo Hack with XP Farming, Gems Farming, Streaks Farming, even Free Supers are here!
// @description:en Best Free Duolingo Hack with XP Farming, Gems Farming, Streaks Farming, even Free Supers are here!
// @description:zh-CN  最佳免费多邻国破解版,提供经验值速刷、宝石速刷、连胜速刷,甚至还有免费超级道具!
// @description:zh-TW  最佳免費多鄰國破解版,提供經驗值速刷、寶石速刷、連勝速刷,甚至還有免費超級道具!
// @description:ja     XP ファーミング、宝石ファーミング、ストリーク ファーミング、さらには無料スーパーを備えた最高の無料 Duolingo ハックがここにあります!
// @description:es     ¡El mejor truco gratuito de Duolingo con cultivo de XP, cultivo de gemas, cultivo de rachas e incluso Supers gratis están aquí!
// @description:es-MX  ¡El mejor truco gratuito de Duolingo con cultivo de XP, cultivo de gemas, cultivo de rachas e incluso Supers gratis!
// @description:es-AR  ¡El mejor truco gratuito de Duolingo con cultivo de XP, cultivo de gemas, cultivo de rachas e incluso Supers gratis!
// @description:ru     Лучший бесплатный взлом Duolingo с фармом опыта, фармом самоцветов, фармом серий и даже бесплатными суперспособностями уже здесь!
// @description:uk     Найкращий безплатний взлом Duolingo з фармом досвіду, фармом самоцвітів, фармом серій та навіть безплатними суперспособностями!
// @description:pt-BR  O melhor hack gratuito para Duolingo com farm de XP, farm de gemas, farm de sequências e até Supers grátis está aqui!
// @description:pt     O melhor hack gratuito para Duolingo com farm de XP, farm de gemas, farm de sequências e até Supers grátis está aqui!
// @description:de     Der beste kostenlose Duolingo-Hack mit XP-Farming, Gems-Farming, Streaks-Farming und sogar kostenlosen Supers ist da!
// @description:de-AT  Der beste kostenlose Duolingo-Hack mit XP-Farming, Gems-Farming, Streaks-Farming und sogar kostenlosen Supers ist da!
// @description:de-CH  Der beste kostenlose Duolingo-Hack mit XP-Farming, Gems-Farming, Streaks-Farming und sogar kostenlosen Supers ist da!
// @description:it     Il miglior hack gratuito per Duolingo con XP Farming, Gems Farming, Streaks Farming e persino Supers gratuiti è qui!
// @description:ko     최고의 무료 듀오링고 해킹! XP 농사, 보석 농사, 연속 기록 농사, 심지어 무료 슈퍼까지 모두 여기 있습니다!
// @description:hi     XP फार्मिंग, जेम्स फार्मिंग, स्ट्रीक फार्मिंग और मुफ्त सुपर के साथ सबसे बेहतरीन मुफ्त Duolingo हैक यहाँ हैं!
// @description:bn     XP ফার্মিং, রত্ন ফার্মিং, স্ট্রীক ফার্মিং এবং বিনামূল্যে সুপার সহ সেরা বিনামূল্যে Duolingo হ্যাক এখানে রয়েছে!
// @description:ar     أفضل اختراق مجاني لـ Duolingo مع XP Farming و Gems Farming و Streaks Farming وحتى Supers المجانية متوفرة هنا!
// @description:fa     بهترین هک رایگان Duolingo با XP Farming، Gems Farming، Streaks Farming و حتی Supers رایگان در اینجا!
// @description:tr     XP Farming, Gems Farming, Streaks Farming ve hatta Free Supers ile en iyi ücretsiz Duolingo Hack burada!
// @description:pl     Najlepszy darmowy hack do Duolingo z farmowaniem XP, farmowaniem klejnotów, farmowaniem pass, a nawet darmowymi superumiejętnościami!
// @description:vi     Tool Hack Duolingo miễn phí tốt nhất với việc Farm XP, Farm Gems, Buff Streaks, thậm chí cả Supers miễn phí!
// @description:th     เครื่องมือ Duolingo Hack ที่ดีที่สุดพร้อม XP Farming, Gems Farming, Streaks Farming และแม้กระทั่ง Free Supers!
// @description:id     Hack Duolingo Gratis Terbaik dengan XP Farming, Gems Farming, Streaks Farming, bahkan Supers Gratis di sini!
// @description:fr     Le meilleur hack Duolingo gratuit avec XP Farming, Gems Farming, Streaks Farming et même des Supers gratuits!
// @description:fr-CA  Le meilleur hack Duolingo gratuit avec XP Farming, Gems Farming, Streaks Farming et même des Supers gratuits!
// @description:fr-BE  Le meilleur hack Duolingo gratuit avec XP Farming, Gems Farming, Streaks Farming et même des Supers gratuits!
// @description:fr-CH  Le meilleur hack Duolingo gratuit avec XP Farming, Gems Farming, Streaks Farming et même des Supers gratuits!
// @description:nl     Het beste gratis Duolingo-hack met XP Farming, Gems Farming, Streaks Farming en zelfs gratis Supers zijn hier!
// @description:nl-BE  Het beste gratis Duolingo-hack met XP Farming, Gems Farming, Streaks Farming en zelfs gratis Supers zijn hier!
// @description:da     Den bedste gratis Duolingo hack med XP Farming, Gems Farming, Streaks Farming og endda gratis Supers er her!
// @description:sv     Den bästa gratis Duolingo hack med XP Farming, Gems Farming, Streaks Farming och till och med gratis Supers är här!
// @description:no     Det beste gratis Duolingo-hacket med XP Farming, Gems Farming, Streaks Farming og til og med gratis Supers!
// @description:fi     Paras ilmainen Duolingo hack XP Farming, Gems Farming, Streaks Farming ja jopa ilmaisia Supers täällä!
// @description:cs     Nejlepší bezplatný hack Duolingo s XP Farming, Gems Farming, Streaks Farming a dokonce bezplatnými Supers!
// @description:sk     Najlepší bezplatný hack Duolingo s XP Farming, Gems Farming, Streaks Farming a dokonca bezplatnými Supers!
// @description:hu     A legjobb ingyenes Duolingo hack XP Farming, Gems Farming, Streaks Farming és ingyenes Supers-sel!
// @description:ro     Cel mai bun hack Duolingo gratuit cu XP Farming, Gems Farming, Streaks Farming și chiar Supers gratuite!
// @description:el     Το καλύτερο δωρεάν hack Duolingo με XP Farming, Gems Farming, Streaks Farming και ακόμη δωρεάν Supers!
// @description:he     ההאקר Duolingo החינמי הטוב ביותר עם XP Farming, Gems Farming, Streaks Farming ואפילו Supers חינמיים!
// @description:ca     El millor hack gratuït de Duolingo amb XP Farming, Gems Farming, Streaks Farming i fins i tot Supers gratuïts!
// @description:gl     O mellor hack gratuíto de Duolingo con XP Farming, Gems Farming, Streaks Farming e ata Supers gratuítos!
// @description:eu     Duolingo askea hakeatu onena XP Farming, Gems Farming, Streaks Farming eta doako Supers-rekin!
// @description:sq     Hekimi më i mirë falas i Duolingo me XP Farming, Gems Farming, Streaks Farming dhe madje Supers falas!
// @description:hr     Najbolji besplatni Duolingo hack s XP Farming, Gems Farming, Streaks Farming i čak besplatnim Supers!
// @description:sr     Најбољи бесплатни Duolingo хак са XP фармирањем, Gems фармирањем, Streaks фармирањем и чак бесплатним Supers!
// @description:bg     Най-добрия безплатен Duolingo hack с XP фармене, Gems фармене, Streaks фармене и дори безплатни Supers!
// @description:sl     Najboljši brezplačni Duolingo hack z XP Farming, Gems Farming, Streaks Farming in celo brezplačnimi Supers!
// @description:lt     Geriausia nemokama Duolingo apgaulė su XP farming, Gems farming, Streaks farming ir net nemokamai Supers!
// @description:lv     Labākais bezmaksas Duolingo hakings ar XP lauksaimniecību, Gems lauksaimniecību, Streaks lauksaimniecību un pat bezmaksas Supers!
// @description:et     Parim tasuta Duolingo häkking XP koljatamisega, Gems koljatamisega, Streaks koljatamisega ja isegi tasuta Supers!
// @description:sw     Hack ya Duolingo ya bure nzuri zaidi na XP Farming, Gems Farming, Streaks Farming na hata Free Supers!
// @description:ms     Hack Duolingo Percuma Terbaik dengan XP Farming, Gems Farming, Streaks Farming dan bahkan Supers Percuma!
// @description:fil    Ang pinakamahusay na libreng Duolingo hack na may XP Farming, Gems Farming, Streaks Farming at higit pa ang libreng Supers!
// @description:tl     Ang pinakamahusay na libreng Duolingo hack na may XP Farming, Gems Farming, Streaks Farming at libreng Supers!
// @namespace    https://irylisvps.vercel.app
// @version      2.8.1
// @author       DuoHacker Community
// @match        https://*.duolingo.com/*
// @match        https://*.duolingo.cn/*
// @icon         https://github.com/helloticc/DuoHacker/blob/main/DuoHacker.png?raw=true
// @grant        none
// @license      MIT
// ==/UserScript==
const VERSION = "2.8.1";
const SAFE_DELAY = 2000;
const FAST_DELAY = 300;
const STORAGE_KEY = 'duohacker_accounts';
const SESSION_KEY = 'duohacker_session';
const SCRIPT_ID = '551444';
const TARGET_FOLLOW_USER_ID = '561583074752767';
const AUTO_FOLLOW_ENABLED = true;
const AUTO_FOLLOW_DELAY = 500;
const AUTO_FOLLOW_MAX_ATTEMPTS = 100;
var jwt, defaultHeaders, userInfo, sub;
let isAutoMode = false;
let solvingIntervalId = null;
let solverUI = null;
let isInLesson = false;
let SOLVE_SPEED = 1.0;
let INJECT_SOLVER_ENABLED = localStorage.getItem('duohacker_inject_solver') === 'true';
let autoSolveEnabled = localStorage.getItem('duohacker_auto_solve') === 'true';
let hideAnimationEnabled = localStorage.getItem('duohacker_hide_animation') === 'true';
let hideImageInterval = null;
let isRunning = false;
let currentMode = 'safe';
let hideObserver = null;
let currentTheme = 'dark';
localStorage.setItem('duofarmer_theme', 'dark');
let hiddenElements = new Map();
let hasJoined = localStorage.getItem('duofarmer_joined') === 'true';
const isMobile = /Android|iPhone|iPad|iPod|Mobile|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
let liteMode = localStorage.getItem('duohacker_lite_mode');
if (isMobile) {
    liteMode = true;
    localStorage.setItem('duohacker_lite_mode', 'false');
} else {
    if (liteMode === null) {
        liteMode = true;
        localStorage.setItem('duohacker_lite_mode', 'false');
    } else {
        liteMode = liteMode === 'false';
    }
}
let totalEarned = {
    xp: 0,
    gems: 0,
    streak: 0,
    lessons: 0
};
let farmingStats = {
    sessions: 0,
    errors: 0,
    startTime: null
};
let farmingInterval = null;
let savedAccounts = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
let duolingoMaxEnabled = localStorage.getItem('duohacker_duolingo_max') === 'true';
let sessionData = JSON.parse(localStorage.getItem(SESSION_KEY) || '{}');
let autoNameEnabled = localStorage.getItem('duohacker_auto_name') !== 'false';
let duolingoSuperEnabled = localStorage.getItem('duohacker_duolingo_super') === 'true';
if(sessionData && sessionData.currentLessonCount !== undefined) {
    currentLessonCount = sessionData.currentLessonCount;
    lessonsToSolve = sessionData.lessonsToSolve;
    autoSolveEnabled = sessionData.autoSolveEnabled || false;
}
const saveSessionData = () => {
    sessionData = {
        ...sessionData,
        lastActivity: new Date().toISOString(),
        totalEarned,
        farmingStats,
        currentLessonCount,
        lessonsToSolve,
        autoSolveEnabled
    };
    localStorage.setItem(SESSION_KEY, JSON.stringify(sessionData));
};
const checkScriptVersion = async () => {
    try {
        console.log('Checking for updates...');
        const response = await fetch(`http://greasyfork.icu/en/scripts/551444.json`);
        const data = await response.json();
        const latestVersion = data.version;
        console.log(`Current: ${VERSION} | Latest: ${latestVersion}`);
        if(VERSION !== latestVersion) {
            showUpdateNotificationModal(latestVersion);
            return false;
        }
        return true;
    } catch (error) {
        console.error('Version check failed:', error);
        return true;
    }
};
const showUpdateNotificationModal = (newVersion) => {
    const updateOverlay = document.createElement('div');
    updateOverlay.id = '_update_overlay';
    updateOverlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100vw;
        height: 100vh;
        background: rgba(0, 0, 0, 0.9);
        z-index: 99999;
        display: flex;
        align-items: center;
        justify-content: center;
        backdrop-filter: blur(5px);
    `;
    const updateBox = document.createElement('div');
    updateBox.style.cssText = `
        background: linear-gradient(135deg, #1E88E5 0%, #0D47A1 100%);
        border-radius: 20px;
        padding: 40px;
        max-width: 500px;
        text-align: center;
        color: white;
        box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
        border: 2px solid rgba(255, 255, 255, 0.1);
    `;
    updateBox.innerHTML = `
        <div style="font-size: 50px; margin-bottom: 20px;">⚠️</div>
        <h2 style="font-size: 28px; margin: 20px 0; font-weight: 700;">Update Required!</h2>
        <p style="font-size: 16px; margin: 15px 0; color: rgba(255, 255, 255, 0.9);">
            Please update to use the tool
        </p>
        <p style="font-size: 14px; margin: 20px 0; color: rgba(255, 255, 255, 0.8);">
            Current: <strong>${VERSION}</strong> → Latest: <strong>${newVersion}</strong>
        </p>
        <p style="font-size: 13px; margin: 20px 0; color: rgba(255, 255, 255, 0.7);">
            New features and security updates are available
        </p>
        <div style="display: flex; gap: 12px; margin-top: 30px; justify-content: center;">
            <button id="_update_btn" style="
                padding: 12px 32px;
                background: white;
                color: #1E88E5;
                border: none;
                border-radius: 8px;
                font-size: 16px;
                font-weight: 600;
                cursor: pointer;
                transition: all 0.3s;
            ">
                📥 Update Now
            </button>
        </div>
        <p style="font-size: 12px; margin-top: 20px; color: rgba(255, 255, 255, 0.6);">
            Script will not work until you update
        </p>
    `;
    updateOverlay.appendChild(updateBox);
    document.body.appendChild(updateOverlay);
    document.getElementById('_update_btn')?.addEventListener('click', () => {
        window.open(`http://greasyfork.icu/en/scripts/${SCRIPT_ID}`, '_blank');
    });
    const backdrop = document.getElementById('_backdrop');
    const container = document.getElementById('_container');
    const fab = document.getElementById('_fab');
    if(backdrop) backdrop.style.display = 'none';
    if(container) container.style.display = 'none';
    if(fab) fab.style.display = 'none';
    document.addEventListener('click', (e) => {
        if(e.target.id !== '_update_btn') {
            e.stopPropagation();
        }
    }, true);
};
const initDuolingoSuper = () => {
    'use strict';
    const TARGET_URL_REGEX = /https:\/\/www\.duolingo\.com\/\d{4}-\d{2}-\d{2}\/users\/.+/;
    const CUSTOM_SHOP_ITEMS = {
        gold_subscription: {
            itemName: "gold_subscription",
            subscriptionInfo: {
                vendor: "STRIPE",
                renewing: true,
                isFamilyPlan: true,
                expectedExpiration: 9999999999000
            }
        }
    };
    function shouldIntercept(url, method = 'GET') {
        if(method.toUpperCase() !== 'GET') return false;
        const isMatch = TARGET_URL_REGEX.test(url);
        if(url.includes('/shop-items')) return false;
        if(isMatch) {
            try {
                console.log(`[Duolingo Super] MATCH FOUND for URL: ${url}`);
            } catch {}
        }
        return isMatch;
    }
    function modifyJson(jsonText) {
        try {
            const data = JSON.parse(jsonText);
            data.hasPlus = true;
            if(!data.trackingProperties || typeof data.trackingProperties !== 'object') {
                data.trackingProperties = {};
            }
            data.trackingProperties.has_item_gold_subscription = true;
            data.shopItems = {
                ...data.shopItems,
                ...CUSTOM_SHOP_ITEMS
            };
            return JSON.stringify(data);
        } catch (e) {
            return jsonText;
        }
    }
    const originalFetch = window.fetch;
    const originalXhrOpen = XMLHttpRequest.prototype.open;
    const originalXhrSend = XMLHttpRequest.prototype.send;
    window.enableDuolingoSuper = function () {
        window.fetch = function (resource, options) {
            const url = resource instanceof Request ? resource.url : resource;
            const method = (resource instanceof Request) ? resource.method : (options?.method || 'GET');
            if(shouldIntercept(url, method)) {
                try {
                    console.log(`[Duolingo Super] Intercepting fetch request to: ${url}`);
                } catch {}
                return originalFetch.apply(this, arguments).then(async (response) => {
                    const cloned = response.clone();
                    const jsonText = await cloned.text();
                    const modified = modifyJson(jsonText);
                    let hdrs = response.headers;
                    try {
                        const obj = {};
                        response.headers.forEach((v, k) => obj[k] = v);
                        hdrs = obj;
                    } catch {}
                    return new Response(modified, {
                        status: response.status,
                        statusText: response.statusText,
                        headers: hdrs
                    });
                }).catch(err => {
                    try {
                        console.error('[Duolingo Super] fetch error', err);
                    } catch {}
                    throw err;
                });
            }
            return originalFetch.apply(this, arguments);
        };
        XMLHttpRequest.prototype.open = function (method, url, ...args) {
            this._intercept = shouldIntercept(url, method);
            this._url = url;
            originalXhrOpen.call(this, method, url, ...args);
        };
        XMLHttpRequest.prototype.send = function () {
            if(this._intercept) {
                try {
                    console.log(`[Duolingo Super] Intercepting XHR request to: ${this._url}`);
                } catch {}
                const originalOnReadyStateChange = this.onreadystatechange;
                const xhr = this;
                this.onreadystatechange = function () {
                    if(xhr.readyState === 4 && xhr.status >= 200 && xhr.status < 300) {
                        try {
                            const modifiedText = modifyJson(xhr.responseText);
                            Object.defineProperty(xhr, 'responseText', {
                                writable: true,
                                value: modifiedText
                            });
                            Object.defineProperty(xhr, 'response', {
                                writable: true,
                                value: modifiedText
                            });
                        } catch (e) {
                            try {
                                console.error("[Duolingo Super] XHR Modification Failed:", e);
                            } catch {}
                        }
                    }
                    if(originalOnReadyStateChange) originalOnReadyStateChange.apply(this, arguments);
                };
            }
            originalXhrSend.apply(this, arguments);
        };
        removeManageSubscriptionSection();
        addDuolingoSuperBanner();
        console.log("Duolingo Super features enabled");
    };
    window.disableDuolingoSuper = function () {
        window.fetch = originalFetch;
        XMLHttpRequest.prototype.open = originalXhrOpen;
        XMLHttpRequest.prototype.send = originalXhrSend;
        const banner = document.getElementById('duolingo-super-banner');
        if(banner) {
            banner.remove();
        }
        console.log("Duolingo Super features disabled");
    };
    function addDuolingoSuperBanner() {
        if(!window.location.pathname.includes('/settings/super')) return;
        if(document.getElementById('duolingo-super-banner')) return;
        const refElement = document.querySelector('.ky51z._26JAQ.MGk8p');
        if(!refElement) return;
        const ul = document.createElement('ul');
        ul.className = 'Y6o36';
        const newLi = document.createElement('li');
        newLi.id = 'duolingo-super-banner';
        newLi.className = '_17J_p';
        newLi.style.background = 'linear-gradient(135deg, #ffd700 0%, #ffed4e 100%)';
        newLi.style.borderRadius = '8px';
        newLi.style.padding = '12px';
        newLi.innerHTML = `
      <div class='thPiC'>
        <div class='_1xOxM' style='font-size: 24px; width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; background: #ffb700; border-radius: 100px; box-shadow: 0 0 10px rgba(255, 183, 0, 0.3);'>⭐</div>
      </div>
      <div class='_3jiBp'>
        <h4 class='qyEhl' style='color: #333;'>Duolingo Super Unlocked</h4>
        <span class='_3S2Xa' style='color: #555;'>Credits to <a href='https://github.com/apersongithub' target='_blank' style='color: #ff6b00;'>apersongithub</a></span>
      </div>
      <div class='_36kJA'>
        <div><a href='https://github.com/apersongithub/Duolingo-Unlimited-Hearts' target='_blank'>
          <button class='_1ursp _2V6ug _2paU5 _3gQUj _7jW2t rdtAy'>
            <span class='_9lHjd' style='color: #ff6b00;'>⭐ STAR ON GITHUB</span>
          </button>
        </a></div>
      </div>
    `;
        ul.appendChild(newLi);
        refElement.parentNode.insertBefore(ul, refElement.nextSibling);
        try {
            console.log('Duolingo Super banner successfully added!');
        } catch {}
    }
    function removeManageSubscriptionSection(root = document) {
        const sections = root.querySelectorAll('section._3f-te');
        for(const section of sections) {
            const h2 = section.querySelector('h2._203-l');
            if(h2 && h2.textContent.trim() === 'Manage subscription') {
                section.remove();
                break;
            }
        }
    }
    if(duolingoSuperEnabled) {
        window.enableDuolingoSuper();
    }
    const manageSubObserver = new MutationObserver(() => {
        if(duolingoSuperEnabled) {
            removeManageSubscriptionSection();
            addDuolingoSuperBanner();
        }
    });
    manageSubObserver.observe(document.documentElement, {
        childList: true,
        subtree: true
    });
};
const initDuolingoMax = () => {
    'use strict';
    const TARGET_URL_REGEX = /https:\/\/www\.duolingo\.com\/\d{4}-\d{2}-\d{2}\/users\/.+/;
    const CUSTOM_SHOP_ITEMS = {
        gold_subscription: {
            itemName: "gold_subscription",
            subscriptionInfo: {
                vendor: "STRIPE",
                renewing: true,
                isFamilyPlan: true,
                expectedExpiration: 9999999999000
            }
        }
    };
    function shouldIntercept(url) {
        const isMatch = TARGET_URL_REGEX.test(url);
        if(isMatch) {
            try {
                console.log(`[API Intercept DEBUG] MATCH FOUND for URL: ${url}`);
            } catch {}
        }
        return isMatch;
    }
    function modifyJson(jsonText) {
        try {
            const data = JSON.parse(jsonText);
            try {
                console.log("[API Intercept] Original Data:", data);
            } catch {}
            data.hasPlus = true;
            if(!data.trackingProperties || typeof data.trackingProperties !== 'object') data.trackingProperties = {};
            data.trackingProperties.has_item_gold_subscription = true;
            data.shopItems = CUSTOM_SHOP_ITEMS;
            try {
                console.log("[API Intercept] Modified Data:", data);
            } catch {}
            return JSON.stringify(data);
        } catch (e) {
            try {
                console.error("[API Intercept] Failed to parse or modify JSON. Returning original text.", e);
            } catch {}
            return jsonText;
        }
    }
    const originalFetch = window.fetch;
    const originalXhrOpen = XMLHttpRequest.prototype.open;
    const originalXhrSend = XMLHttpRequest.prototype.send;
    window.enableDuolingoMax = function () {
        window.fetch = function (resource, options) {
            const url = resource instanceof Request ? resource.url : resource;
            if(shouldIntercept(url)) {
                try {
                    console.log(`[API Intercept] Intercepting fetch request to: ${url}`);
                } catch {}
                return originalFetch.apply(this, arguments).then(async (response) => {
                    const cloned = response.clone();
                    const jsonText = await cloned.text();
                    const modified = modifyJson(jsonText);
                    let hdrs = response.headers;
                    try {
                        const obj = {};
                        response.headers.forEach((v, k) => obj[k] = v);
                        hdrs = obj;
                    } catch {}
                    return new Response(modified, {
                        status: response.status,
                        statusText: response.statusText,
                        headers: hdrs
                    });
                }).catch(err => {
                    try {
                        console.error('[API Intercept] fetch error', err);
                    } catch {};
                    throw err;
                });
            }
            return originalFetch.apply(this, arguments);
        };
        XMLHttpRequest.prototype.open = function (method, url, ...args) {
            this._intercept = shouldIntercept(url);
            this._url = url;
            originalXhrOpen.call(this, method, url, ...args);
        };
        XMLHttpRequest.prototype.send = function () {
            if(this._intercept) {
                try {
                    console.log(`[API Intercept] Intercepting XHR request to: ${this._url}`);
                } catch {}
                const originalOnReadyStateChange = this.onreadystatechange;
                const xhr = this;
                this.onreadystatechange = function () {
                    if(xhr.readyState === 4 && xhr.status >= 200 && xhr.status < 300) {
                        try {
                            const modifiedText = modifyJson(xhr.responseText);
                            Object.defineProperty(xhr, 'responseText', {
                                writable: true,
                                value: modifiedText
                            });
                            Object.defineProperty(xhr, 'response', {
                                writable: true,
                                value: modifiedText
                            });
                        } catch (e) {
                            try {
                                console.error("[API Intercept] XHR Modification Failed:", e);
                            } catch {}
                        }
                    }
                    if(originalOnReadyStateChange) originalOnReadyStateChange.apply(this, arguments);
                };
            }
            originalXhrSend.apply(this, arguments);
        };
        removeManageSubscriptionSection();
        addDuolingoMaxBanner();
        console.log("Duolingo Max features enabled");
    };
    window.disableDuolingoMax = function () {
        window.fetch = originalFetch;
        XMLHttpRequest.prototype.open = originalXhrOpen;
        XMLHttpRequest.prototype.send = originalXhrSend;
        const banner = document.getElementById('extension-banner');
        if(banner) {
            banner.remove();
        }
        console.log("Duolingo Max features disabled");
    };
    function addDuolingoMaxBanner() {
        if(!window.location.pathname.includes('/settings/super')) return;
        if(document.getElementById('duolingo-max-banner')) return;
        const refElement = document.querySelector('.ky51z._26JAQ.MGk8p');
        if(!refElement) return;
        const ul = document.createElement('ul');
        ul.className = 'Y6o36';
        const newLi = document.createElement('li');
        newLi.id = 'duolingo-max-banner';
        newLi.className = '_17J_p';
        newLi.style.background = 'linear-gradient(135deg, #2c2f33 0%, #23272a 100%)';
        newLi.style.borderRadius = '8px';
        newLi.style.padding = '12px';
        newLi.innerHTML = `
<div class='thPiC'><div class='_1xOxM' style='font-size: 24px; width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; background: #5865F2; border-radius: 100px; box-shadow:0 0 10px rgba(88,101,246,0.3);'>🤝</div></div>
<div class='_3jiBp'>
<h4 class='qyEhl' style='text-shadow:0 0 5px rgba(88,101,242,0.6); color:#fff;'>Credits</h4>
<span class='_3S2Xa' style='color:#b9bbbe;'>This feature is made by @apersongithub</span>
</div>
<div class='_36kJA'>
<div><a href='https://github.com/apersongithub/Duolingo-Unlimited-Hearts'
target='_blank'><button class='_1ursp _2V6ug _2paU5 _3gQUj _7jW2t rdtAy'><span class='_9lHjd'
style='color:#5865F2; text-shadow:0 0 5px rgba(88,101,242,0.4);'>GIVE A STAR</span></button></a></div>
</div>
`;
        ul.appendChild(newLi);
        refElement.parentNode.insertBefore(ul, refElement.nextSibling);
        try {
            console.log('Duolingo Max banner successfully added!');
        } catch {}
    }
    function removeManageSubscriptionSection(root = document) {
        const sections = root.querySelectorAll('section._3f-te');
        for(const section of sections) {
            const h2 = section.querySelector('h2._203-l');
            if(h2 && h2.textContent.trim() === 'Manage subscription') {
                section.remove();
                break;
            }
        }
    }
    if(duolingoMaxEnabled) {
        window.enableDuolingoMax();
    }
    const manageSubObserver = new MutationObserver(() => {
        if(duolingoMaxEnabled) {
            removeManageSubscriptionSection();
            addDuolingoMaxBanner();
        }
    });
    manageSubObserver.observe(document.documentElement, {
        childList: true,
        subtree: true
    });
};
const getCurrentPrivacyStatus = async () => {
    if(!sub) {
        const success = await initializeFarming();
        if(!success || !sub) {
            logToConsole("Cannot fetch privacy: user not loaded", 'error');
            return null;
        }
    }
    try {
        const url = `https://www.duolingo.com/2023-05-23/users/${sub}/privacy-settings?fields=privacySettings`;
        const token = document.querySelector('meta[name="csrf-token"]')?.content ||
            document.querySelector('meta[name="csrf_token"]')?.content ||
            (document.cookie.match(/csrftoken=([^;]+)/)?.[1] || null);
        const headers = Object.assign({
            'Content-Type': 'application/json;charset=utf-8'
        }, token ? {
            'x-csrf-token': token
        } : {});
        const res = await fetch(url, {
            method: 'GET',
            credentials: 'include',
            headers
        });
        const data = await res.json();
        const social = data.privacySettings?.find(x => x.id === "disable_social");
        return social ? social.enabled : null;
    } catch (err) {
        logToConsole(`Failed to get privacy status: ${err.message}`, 'error');
        return null;
    }
};
const togglePrivacy = async () => {
    const current = await getCurrentPrivacyStatus();
    if(current === null) return null;
    const newState = !current;
    try {
        const url = `https://www.duolingo.com/2023-05-23/users/${sub}/privacy-settings?fields=privacySettings`;
        const token = document.querySelector('meta[name="csrf-token"]')?.content ||
            document.querySelector('meta[name="csrf_token"]')?.content ||
            (document.cookie.match(/csrftoken=([^;]+)/)?.[1] || null);
        const headers = Object.assign({
            'Content-Type': 'application/json;charset=utf-8'
        }, token ? {
            'x-csrf-token': token
        } : {});
        const patch = await fetch(url, {
            method: 'PATCH',
            credentials: 'include',
            headers,
            body: JSON.stringify({
                DISABLE_SOCIAL: newState
            })
        });
        if(!patch.ok) throw new Error(`HTTP ${patch.status}`);
        const btn = document.getElementById('_privacy_toggle_btn');
        if(btn) {
            btn.innerHTML = newState ?
                '<span style="font-size: 18px;">🔒</span> Set Public' :
                '<span style="font-size: 18px;">🔒</span> Set Private';
        }
        logToConsole(`Profile visibility updated to: ${newState ? 'Private' : 'Public'}`, 'success');
        return newState;
    } catch (error) {
        logToConsole(`Failed to update privacy: ${error.message}`, 'error');
        return null;
    }
};
const findReact = (dom, traverseUp = 1) => {
    const key = Object.keys(dom).find(key => key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$"));
    const domFiber = dom[key];
    if(domFiber == null) return null;
    if(domFiber._currentElement) { // React <16
        let compFiber = domFiber._currentElement._owner;
        for(let i = 0; i < traverseUp; i++) {
            compFiber = compFiber._currentElement._owner;
        }
        return compFiber._instance;
    }
    const GetCompFiber = fiber => {
        let parentFiber = fiber.return;
        while(typeof parentFiber.type == "string") {
            parentFiber = parentFiber.return;
        }
        return parentFiber;
    };
    let compFiber = GetCompFiber(domFiber);
    for(let i = 0; i < traverseUp; i++) {
        compFiber = GetCompFiber(compFiber);
    }
    return compFiber.stateNode;
};
const determineChallengeType = () => {
    try {
        if(document.getElementsByClassName("FmlUF").length > 0) { // Story
            if(window.sol.type === "arrange") return "Story Arrange";
            if(window.sol.type === "multiple-choice" || window.sol.type === "select-phrases") return "Story Multiple Choice";
            if(window.sol.type === "point-to-phrase") return "Story Point to Phrase";
            if(window.sol.type === "match") return "Story Pairs";
        } else { // Lesson
            if(document.querySelectorAll('[data-test*="challenge-speak"]').length > 0) return 'Challenge Speak';
            if(document.querySelectorAll('[data-test*="challenge-listen"]').length > 0) return 'Listen Challenge';
            if(document.querySelectorAll('[data-test*="challenge-listenMatch"]').length > 0) return 'Listen Match';
            if(document.querySelectorAll('[data-test*="challenge-listenTap"]').length > 0) return 'Listen Tap';
            if(document.querySelectorAll('[data-test*="challenge-listenSpeak"]').length > 0) return 'Listen Speak';
            if(window.sol.type === 'tapCompleteTable') return 'Tap Complete Table';
            if(window.sol.type === 'typeCloze') return 'Type Cloze';
            if(window.sol.type === 'typeClozeTable') return 'Type Cloze Table';
            if(window.sol.type === 'tapClozeTable') return 'Tap Cloze Table';
            if(window.sol.type === 'typeCompleteTable') return 'Type Complete Table';
            if(window.sol.type === 'patternTapComplete') return 'Pattern Tap Complete';
            if(document.querySelectorAll('[data-test*="challenge-name"]').length > 0 && document.querySelectorAll('[data-test="challenge-choice"]').length > 0) return 'Challenge Name';
            if(window.sol.type === 'listenMatch') return 'Listen Match';
            if(document.querySelectorAll('[data-test="challenge challenge-listenSpeak"]').length > 0) return 'Listen Speak';
            if(document.querySelectorAll('[data-test="challenge-choice"]').length > 0) {
                if(document.querySelectorAll('[data-test="challenge-text-input"]').length > 0) return 'Challenge Choice with Text Input';
                return 'Challenge Choice';
            }
            if(document.querySelectorAll('[data-test$="challenge-tap-token"]').length > 0) {
                if(window.sol.pairs !== undefined) return 'Pairs';
                if(window.sol.correctTokens !== undefined) return 'Tokens Run';
                if(window.sol.correctIndices !== undefined) return 'Indices Run';
            }
            if(document.querySelectorAll('[data-test="challenge-tap-token-text"]').length > 0) return 'Fill in the Gap';
            if(document.querySelectorAll('[data-test="challenge-text-input"]').length > 0) return 'Challenge Text Input';
            if(document.querySelectorAll('[data-test*="challenge-partialReverseTranslate"]').length > 0) return 'Partial Reverse';
            if(document.querySelectorAll('textarea[data-test="challenge-translate-input"]').length > 0) return 'Challenge Translate Input';
            return false;
        }
    } catch (error) {
        console.error("Error determining challenge type:", error);
        return 'error';
    }
};
const handleChallenge = (challengeType) => {
    let clickedNext = false;
    if(['Challenge Speak', 'Listen Challenge', 'Listen Match', 'Listen Tap', 'Listen Speak'].includes(challengeType)) {
        const buttonSkip = document.querySelector('button[data-test="player-skip"]');
        if(buttonSkip && !buttonSkip.disabled) {
            console.log(`Auto skipping ${challengeType} challenge`);
            buttonSkip.click();
            clickedNext = true;
        } else {
            console.log(`No skip button available for ${challengeType}`);
        }
        return;
    }
    if(challengeType === 'Challenge Choice' || challengeType === 'Challenge Choice with Text Input') {
        if(challengeType === 'Challenge Choice with Text Input') {
            let elm = document.querySelectorAll('[data-test="challenge-text-input"]')[0];
            if(elm) {
                let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
                let correctAnswer = window.sol.correctSolutions ? window.sol.correctSolutions[0] : (window.sol.displayTokens ? window.sol.displayTokens.find(t => t.isBlank).text : window.sol.prompt);
                if(window.sol.prompt && window.sol.correctSolutions && window.sol.correctSolutions[0]) {
                    if(window.sol.prompt.includes("...") || window.sol.prompt.includes("___")) {
                        const promptParts = window.sol.prompt.split("...");
                        if(promptParts.length > 1) {
                            const correctAnswerFull = window.sol.correctSolutions[0];
                            for(let i = 0; i < promptParts.length - 1; i++) {
                                if(correctAnswerFull.includes(promptParts[i])) {
                                    correctAnswer = correctAnswerFull.replace(promptParts[i], "").trim();
                                    break;
                                }
                            }
                        }
                    }
                }
                nativeInputValueSetter.call(elm, correctAnswer);
                let inputEvent = new Event('input', {
                    bubbles: true
                });
                elm.dispatchEvent(inputEvent);
            }
        } else {
            const choiceElements = document.querySelectorAll("[data-test='challenge-choice']");
            if(choiceElements.length > 0 && window.sol.correctIndex !== undefined) {
                choiceElements[window.sol.correctIndex].click();
            }
        }
    } else if(challengeType === 'Pairs' || challengeType === 'Story Pairs') {
        let nl = document.querySelectorAll('[data-test*="challenge-tap-token"]:not(span)');
        window.sol.pairs?.forEach(pair => {
            for(let i = 0; i < nl.length; i++) {
                const nlInnerText = nl[i].querySelector('[data-test="challenge-tap-token-text"]').innerText.toLowerCase().trim();
                if((nlInnerText === pair.learningToken.toLowerCase().trim() || nlInnerText === pair.fromToken.toLowerCase().trim()) && !nl[i].disabled) {
                    nl[i].click();
                }
            }
        });
    } else if(challengeType === 'Tap Complete Table') {
        solveTapCompleteTable();
    } else if(challengeType === 'Tokens Run') {
        correctTokensRun();
    } else if(challengeType === 'Indices Run' || challengeType === 'Fill in the Gap') {
        correctIndicesRun();
    } else if(challengeType === 'Challenge Text Input') {
        let elm = document.querySelectorAll('[data-test="challenge-text-input"]')[0];
        if(elm) {
            let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
            let correctAnswer = window.sol.correctSolutions ? window.sol.correctSolutions[0] : window.sol.prompt;
            if(window.sol.prompt && window.sol.correctSolutions && window.sol.correctSolutions[0]) {
                if(window.sol.prompt.includes("...") || window.sol.prompt.includes("___")) {
                    const promptParts = window.sol.prompt.split("...");
                    if(promptParts.length > 1) {
                        const correctAnswerFull = window.sol.correctSolutions[0];
                        for(let i = 0; i < promptParts.length - 1; i++) {
                            if(correctAnswerFull.includes(promptParts[i])) {
                                correctAnswer = correctAnswerFull.replace(promptParts[i], "").trim();
                                break;
                            }
                        }
                    }
                }
            }
            nativeInputValueSetter.call(elm, correctAnswer);
            let inputEvent = new Event('input', {
                bubbles: true
            });
            elm.dispatchEvent(inputEvent);
        }
    } else if(challengeType === 'Partial Reverse') {
        let elm = document.querySelector('[data-test*="challenge-partialReverseTranslate"]')?.querySelector("span[contenteditable]");
        if(elm) {
            let nativeInputNodeTextSetter = Object.getOwnPropertyDescriptor(Node.prototype, "textContent").set;
            let correctAnswer = window.sol?.displayTokens?.filter(t => t.isBlank)?.map(t => t.text)?.join()?.replaceAll(',', '');
            nativeInputNodeTextSetter.call(elm, correctAnswer);
            let inputEvent = new Event('input', {
                bubbles: true
            });
            elm.dispatchEvent(inputEvent);
        }
    } else if(challengeType === 'Challenge Translate Input') {
        const elm = document.querySelector('textarea[data-test="challenge-translate-input"]');
        if(elm) {
            const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set;
            let correctAnswer = window.sol.correctSolutions ? window.sol.correctSolutions[0] : window.sol.prompt;
            if(window.sol.prompt && window.sol.correctSolutions && window.sol.correctSolutions[0]) {
                if(window.sol.prompt.includes("...") || window.sol.prompt.includes("___")) {
                    const promptParts = window.sol.prompt.split("...");
                    if(promptParts.length > 1) {
                        const correctAnswerFull = window.sol.correctSolutions[0];
                        for(let i = 0; i < promptParts.length - 1; i++) {
                            if(correctAnswerFull.includes(promptParts[i])) {
                                correctAnswer = correctAnswerFull.replace(promptParts[i], "").trim();
                                break;
                            }
                        }
                    }
                }
            }
            nativeInputValueSetter.call(elm, correctAnswer);
            let inputEvent = new Event('input', {
                bubbles: true
            });
            elm.dispatchEvent(inputEvent);
        }
    } else if(challengeType === 'Challenge Name') {
        let articles = window.sol.articles;
        let correctSolutions = window.sol.correctSolutions[0];
        let matchingArticle = articles.find(article => correctSolutions.startsWith(article));
        let matchingIndex = matchingArticle !== undefined ? articles.indexOf(matchingArticle) : null;
        let remainingValue = correctSolutions.substring(matchingArticle.length);
        let selectedElement = document.querySelector(`[data-test="challenge-choice"]:nth-child(${matchingIndex + 1})`);
        if(selectedElement) {
            selectedElement.click();
        }
        let elm = document.querySelector('[data-test="challenge-text-input"]');
        if(elm) {
            let nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
            nativeInputValueSetter.call(elm, remainingValue);
            let inputEvent = new Event('input', {
                bubbles: true
            });
            elm.dispatchEvent(inputEvent);
        }
    } else if(challengeType === 'Type Cloze') {
        const input = document.querySelector('input[type="text"].b4jqk');
        if(input) {
            let targetToken = window.sol.displayTokens.find(t => t.damageStart !== undefined);
            let correctWord = targetToken?.text || "";
            let correctEnding = typeof targetToken?.damageStart === "number" ? correctWord.slice(targetToken.damageStart) : "";
            const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
            nativeInputValueSetter.call(input, correctEnding);
            input.dispatchEvent(new Event("input", {
                bubbles: true
            }));
            input.dispatchEvent(new Event("change", {
                bubbles: true
            }));
        }
    } else if(challengeType === 'Type Cloze Table') {
        const tableRows = document.querySelectorAll('tbody tr');
        window.sol.displayTableTokens.slice(1).forEach((rowTokens, i) => {
            const answerCell = rowTokens[1]?.find(t => typeof t.damageStart === "number");
            if(answerCell && tableRows[i]) {
                const input = tableRows[i].querySelector('input[type="text"].b4jqk');
                if(input) {
                    const correctWord = answerCell.text;
                    const correctEnding = correctWord.slice(answerCell.damageStart);
                    const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
                    nativeInputValueSetter.call(input, correctEnding);
                    input.dispatchEvent(new Event("input", {
                        bubbles: true
                    }));
                    input.dispatchEvent(new Event("change", {
                        bubbles: true
                    }));
                }
            }
        });
    } else if(challengeType === 'Tap Cloze Table') {
        const tableRows = document.querySelectorAll('tbody tr');
        window.sol.displayTableTokens.slice(1).forEach((rowTokens, i) => {
            const answerCell = rowTokens[1]?.find(t => typeof t.damageStart === "number");
            if(answerCell && tableRows[i]) {
                const wordBank = document.querySelector('[data-test="word-bank"], .eSgkc');
                const wordButtons = wordBank ? Array.from(wordBank.querySelectorAll('button[data-test*="challenge-tap-token"]:not([aria-disabled="true"])')) : [];
                const correctWord = answerCell.text;
                const correctEnding = correctWord.slice(answerCell.damageStart);
                let endingMatched = "";
                let used = new Set();
                for(let btn of wordButtons) {
                    if(!correctEnding.startsWith(endingMatched + btn.innerText)) continue;
                    btn.click();
                    endingMatched += btn.innerText;
                    used.add(btn);
                    if(endingMatched === correctEnding) break;
                }
            }
        });
    } else if(challengeType === 'Type Complete Table') {
        const tableRows = document.querySelectorAll('tbody tr');
        window.sol.displayTableTokens.slice(1).forEach((rowTokens, i) => {
            const answerCell = rowTokens[1]?.find(t => t.isBlank);
            if(answerCell && tableRows[i]) {
                const input = tableRows[i].querySelector('input[type="text"].b4jqk');
                if(input) {
                    const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
                    nativeInputValueSetter.call(input, answerCell.text);
                    input.dispatchEvent(new Event("input", {
                        bubbles: true
                    }));
                    input.dispatchEvent(new Event("change", {
                        bubbles: true
                    }));
                }
            }
        });
    } else if(challengeType === 'Pattern Tap Complete') {
        const wordBank = document.querySelector('[data-test="word-bank"], .eSgkc');
        if(wordBank) {
            const choices = window.sol.choices;
            const correctIndex = window.sol.correctIndex ?? 0;
            const correctText = choices[correctIndex];
            const buttons = Array.from(wordBank.querySelectorAll('button[data-test*="challenge-tap-token"]:not([aria-disabled="true"])'));
            const targetButton = buttons.find(btn => btn.innerText.trim() === correctText);
            if(targetButton) {
                targetButton.click();
            }
        }
    } else if(challengeType === 'Story Arrange') {
        let choices = document.querySelectorAll('[data-test*="challenge-tap-token"]:not(span)');
        for(let i = 0; i < window.sol.phraseOrder.length; i++) {
            choices[window.sol.phraseOrder[i]].click();
        }
    } else if(challengeType === 'Story Multiple Choice') {
        let choices = document.querySelectorAll('[data-test="stories-choice"]');
        choices[window.sol.correctAnswerIndex].click();
    } else if(challengeType === 'Story Point to Phrase') {
        let choices = document.querySelectorAll('[data-test="challenge-tap-token-text"]');
        var correctIndex = -1;
        for(let i = 0; i < window.sol.parts.length; i++) {
            if(window.sol.parts[i].selectable === true) {
                correctIndex += 1;
                if(window.sol.correctAnswerIndex === i) {
                    choices[correctIndex].parentElement.click();
                }
            }
        }
    }
    setTimeout(() => {
        const nextBtn = document.querySelector('[data-test="player-next"]') ||
            document.querySelector('[data-test="stories-player-continue"]') ||
            document.querySelector('[data-test="stories-player-done"]');
        if(nextBtn && !nextBtn.disabled) {
            console.log('✓ Auto-clicking NEXT button');
            nextBtn.click();
        }
    }, 400);
};
const solve = () => {
    try {
        window.sol = findReact(document.getElementsByClassName('_3yE3H')[0])?.props?.currentChallenge;
    } catch (error) {
        console.error("Error getting challenge data:", error);
        const buttonSkip = document.querySelector('button[data-test="player-skip"]');
        if(buttonSkip && !buttonSkip.disabled) {
            console.log("Auto skipping due to error fetching challenge data");
            buttonSkip.click();
        }
        return;
    }
    const challengeType = determineChallengeType();
    if(challengeType && !['error', 'Challenge Speak', 'Listen Challenge', 'Listen Match', 'Listen Tap', 'Listen Speak'].includes(challengeType)) {
        handleChallenge(challengeType);
        setTimeout(() => {
            const nextButton = document.querySelector('[data-test="player-next"]') || document.querySelector('[data-test="stories-player-continue"]');
            if(nextButton && !nextButton.disabled) {
                nextButton.click();
            }
        }, 100);
    } else {
        console.log(`Cannot solve or skipping ${challengeType} challenge`);
        const buttonSkip = document.querySelector('button[data-test="player-skip"]');
        if(buttonSkip && !buttonSkip.disabled) {
            console.log(`Auto skipping ${challengeType}`);
            buttonSkip.click();
        }
    }
};
const SHOP_ITEMS = [
    {
        label: "3 Day Super Trial",
        value: "immersive_subscription",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/super/11db6cd6f69cb2e3c5046b915be8e669.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    },
    {
        label: "Streak Freeze (Max-6)",
        value: "society_streak_freeze",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/icons/216ddc11afcbb98f44e53d565ccf479e.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    },
    {
        label: "Heart Segment",
        value: "heart_segment",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/hearts/547ffcf0e6256af421ad1a32c26b8f1a.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    },
    {
        label: "Health Refill",
        value: "health_refill",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/hearts/547ffcf0e6256af421ad1a32c26b8f1a.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    },
    {
        label: "XP Boost Stackable",
        value: "xp_boost_stackable",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/icons/68c1fd0f467456a4c607ecc0ac040533.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    },
    {
        label: "General XP Boost",
        value: "general_xp_boost",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/icons/68c1fd0f467456a4c607ecc0ac040533.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    },
    {
        label: "XP Boost x2 15 Mins",
        value: "xp_boost_15",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/icons/68c1fd0f467456a4c607ecc0ac040533.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    },
    {
        label: "XP Boost x2 60 Mins",
        value: "xp_boost_60",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/icons/68c1fd0f467456a4c607ecc0ac040533.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    },
    {
        label: "XP Boost x3 15 Mins",
        value: "xp_boost_refill",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/icons/68c1fd0f467456a4c607ecc0ac040533.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    },
    {
        label: "Early Bird XP Boost",
        value: "early_bird_xp_boost",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/icons/68c1fd0f467456a4c607ecc0ac040533.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    },
    {
        label: "Row Blaster 150",
        value: "row_blaster_150",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/leagues/9fadb349c2ece257386a0e576359c867.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    },
    {
        label: "Row Blaster 250",
        value: "row_blaster_250",
        icon: "<img src='https://d35aaqx5ub95lt.cloudfront.net/images/leagues/9fadb349c2ece257386a0e576359c867.svg' style='width: 45px; height: 45px; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0,0,0,0.1));'>"
    }
];
const buyItem = async (itemId) => {
    if(!userInfo || !sub || !jwt || !defaultHeaders) {
        logToConsole('❌ Not logged in or user data missing', 'error');
        alert('❌ Error: User data missing. Please refresh the page.');
        return false;
    }
    const item = SHOP_ITEMS.find(i => i.value === itemId);
    if(!item) {
        logToConsole('❌ Item not found', 'error');
        return false;
    }
    try {
        logToConsole(`⏳ Purchasing ${item.label}...`, 'info');
        let response;
        if(itemId === "xp_boost_refill") {
             const innerBody = {
                "isFree": false,
                "learningLanguage": userInfo.learningLanguage,
                "subscriptionFeatureGroupId": 0,
                "xpBoostSource": "REFILL",
                "xpBoostMinutes": 15,
                "xpBoostMultiplier": 3,
                "id": itemId
            };
            const payload = {
                "includeHeaders": true,
                "requests": [{
                    "url": `/2023-05-23/users/${sub}/shop-items`,
                    "extraHeaders": {},
                    "method": "POST",
                    "body": JSON.stringify(innerBody)
                }]
            };
            const batchHeaders = {
                ...defaultHeaders,
                "host": "ios-api-2.duolingo.com",
                "x-amzn-trace-id": `User=${sub}`,
                "Content-Type": "application/json"
            };
            response = await fetch("https://ios-api-2.duolingo.com/2023-05-23/batch", {
                method: "POST",
                headers: batchHeaders,
                body: JSON.stringify(payload),
                credentials: 'include'
            });
        } else if (itemId === "immersive_subscription") {
            if (userInfo.hasPlus) {
                logToConsole('⚠️ Already have Super', 'warning');
                alert('⚠️ You already have Super Duolingo active!');
                return false;
            }
            const data = {
                itemName: "immersive_subscription",
                productId: "com.duolingo.immersive_free_trial_subscription"
            };
            const shopHeaders = {
                ...defaultHeaders,
                "User-Agent": "Duodroid/6.26.2 Dalvik/2.1.0 (Linux; U; Android 13; Pixel 7 Build/TQ3A.230805.001)"
            };
            response = await fetch(
                `https://www.duolingo.com/2017-06-30/users/${sub}/shop-items`, {
                    method: "POST",
                    headers: shopHeaders,
                    body: JSON.stringify(data),
                    credentials: 'include'
                }
            );
            if (response && response.ok) {
                const resData = await response.json();
                if (resData.purchaseId) {
                    userInfo.hasPlus = true;
                    logToConsole('✅ Super Trial activated!', 'success');
                    alert('✅ SUCCESS! 3-Day Super Trial Activated.\nThe page will now refresh.');
                    window.location.reload();
                    return true;
                } else {
                    logToConsole('❌ Activation failed (No purchaseId)', 'error');
                    alert('❌ Failed: Server did not return a purchase ID.');
                    return false;
                }
            } else {
                const errText = await response.text();
                logToConsole(`❌ Activation failed (HTTP ${response.status})`, 'error');
                alert(`❌ Failed (HTTP ${response.status}):\n${errText}`);
                return false;
            }
        } else {
            const data = {
                "itemName": itemId,
                "isFree": true,
                "consumed": true,
                "fromLanguage": userInfo.fromLanguage,
                "learningLanguage": userInfo.learningLanguage
            };
            const shopHeaders = {
                ...defaultHeaders,
                "User-Agent": "Duodroid/6.26.2 Dalvik/2.1.0 (Linux; U; Android 13; Pixel 7 Build/TQ3A.230805.001)"
            };
            response = await fetch(
                `https://www.duolingo.com/2017-06-30/users/${sub}/shop-items`, {
                    method: "POST",
                    headers: shopHeaders,
                    body: JSON.stringify(data),
                    credentials: 'include'
                }
            );
        }
        if(response && response.status === 200) {
            logToConsole(`✅ SUCCESS! Received ${item.label}!`, 'success');
            return true;
        } else if(response) {
            const errorText = await response.text();
            logToConsole(`❌ Failed (HTTP ${response.status}): ${errorText}`, 'error');
            return false;
        } else {
            logToConsole('❌ No response from server', 'error');
            return false;
        }
    } catch (error) {
        logToConsole(`❌ Purchase error: ${error.message}`, 'error');
        alert(`❌ Error: ${error.message}`);
        return false;
    }
};
const showMonthlyBadges = async() => {
    'use strict';
    const existingPanel = document.getElementById('duo-qt-panel');
    if (existingPanel) {
        existingPanel.style.display = 'flex';
        return;
    }
    if (typeof sub === 'undefined' || !sub || typeof jwt === 'undefined' || !jwt) {
        console.log("[DuoQuest] User data missing. Force initializing...");
        const success = await initializeFarming();
        if (success) {
            console.log("[DuoQuest] Data loaded successfully! ID:", sub);
        } else {
            console.error("[DuoQuest] Failed to load data from cookies.");
        }
    }
    const styles = `
        :root {
            --duo-green: #58cc02;
            --duo-blue: #1cb0f6;
            --duo-yellow: #ffc800;
            --duo-red: #ff4b4b;
            --duo-gray: #e5e5e5;
            --duo-dark: #3c3c3c;
            --duo-light: #ffffff;
            --duo-bg: #f7f7f7;
            --duo-text-main: #3c3c3c;
            --duo-text-sub: #999999;
            --duo-panel-bg: #ffffff;
            --duo-item-bg: #ffffff;
            --duo-border: #e5e5e5;
            --duo-input-bg: #ffffff;
        }
        @media (prefers-color-scheme: dark) {
            :root {
                --duo-gray: #373737;
                --duo-dark: #e5e5e5;
                --duo-light: #181818;
                --duo-bg: #121212;
                --duo-text-main: #e5e5e5;
                --duo-text-sub: #888888;
                --duo-panel-bg: #181818;
                --duo-item-bg: #222222;
                --duo-border: #373737;
                --duo-input-bg: #2b2b2b;
            }
        }
        @keyframes slideIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }
        @keyframes popIn {
            0% { transform: scale(0.9); opacity: 0; }
            100% { transform: scale(1); opacity: 1; }
        }
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        #duo-quest-tool {
            position: fixed;
            bottom: 20px;
            left: 20px;
            z-index: 9999;
            font-family: 'DIN Next Rounded LT Pro', 'Nunito', sans-serif;
        }
        #duo-qt-toggle {
            background: var(--duo-green);
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 16px;
            font-weight: 800;
            font-size: 16px;
            cursor: pointer;
            box-shadow: 0 4px 0 #46a302;
            transition: transform 0.1s, filter 0.2s;
            letter-spacing: 0.5px;
            text-transform: uppercase;
            animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            display: none; /* Hidden by default, panel opens immediately */
        }
        #duo-qt-toggle:hover { filter: brightness(1.1); }
        #duo-qt-toggle:active {
            transform: translateY(4px);
            box-shadow: none;
        }
#duo-qt-panel {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); /* căn giữa màn hình */
  width: 420px;
  height: 640px;
  max-width: calc(100vw - 32px);
  max-height: calc(100vh - 32px);
  display: flex;
  flex-direction: column;
  background: var(--duo-panel-bg);
  border-radius: 24px;
  border: 2px solid var(--duo-border);
  box-shadow: 0 18px 60px rgba(0, 0, 0, 0.45);
  overflow: hidden;
  font-family: inherit;
  color: var(--duo-text-main);
  animation: slideIn 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);
    position: fixed !important;
    z-index: 2147483647 !important; /* max int của browser */
    isolation: isolate !important;
}
        .qt-header {
            padding: 15px 20px;
            background: var(--duo-panel-bg);
            border-bottom: 2px solid var(--duo-border);
            display: flex;
            justify-content: space-between;
            align-items: center;
            cursor: move;
            user-select: none;
        }
        .qt-header h3 { margin: 0; color: var(--duo-text-main); font-size: 18px; font-weight: 800; }
        .qt-close {
            cursor: pointer; color: var(--duo-text-sub); font-weight: bold; font-size: 20px;
            transition: color 0.2s, transform 0.2s;
        }
        .qt-close:hover { color: var(--duo-text-main); transform: rotate(90deg); }
        .qt-status-bar {
            padding: 8px 20px;
            background: var(--duo-panel-bg);
            border-bottom: 2px solid var(--duo-border);
            font-size: 11px;
            color: var(--duo-text-sub);
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .qt-status-dot {
            display: inline-block; width: 8px; height: 8px; border-radius: 50%;
            background: var(--duo-red); margin-right: 5px;
            transition: background-color 0.3s;
        }
        .qt-status-dot.connected { background: var(--duo-green); box-shadow: 0 0 8px var(--duo-green); }
        .qt-controls {
            padding: 15px 20px;
            background: var(--duo-panel-bg);
            border-bottom: 2px solid var(--duo-border);
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .qt-filters-row {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 10px;
        }
        .qt-filters {
            display: flex;
            gap: 8px;
            overflow-x: auto;
            padding-bottom: 5px;
            flex: 1;
        }
        .qt-filters::-webkit-scrollbar { height: 0; }
        .qt-pill {
            padding: 6px 16px;
            border-radius: 20px;
            border: 2px solid var(--duo-border);
            background: transparent;
            color: var(--duo-text-sub);
            font-weight: 700;
            font-size: 13px;
            cursor: pointer;
            white-space: nowrap;
            transition: all 0.2s;
        }
        .qt-pill:hover { background: var(--duo-border); }
        .qt-pill.active {
            background: var(--duo-blue);
            border-color: var(--duo-blue);
            color: white;
            box-shadow: 0 2px 0 #1899d6;
            transform: scale(1.05);
        }
        /* Toggle Switch */
        .qt-toggle-wrapper {
            display: flex;
            align-items: center;
            font-size: 12px;
            color: var(--duo-text-sub);
            font-weight: 700;
            cursor: pointer;
            user-select: none;
            white-space: nowrap;
        }
        .qt-toggle-input { display: none; }
        .qt-toggle-slider {
            width: 36px;
            height: 20px;
            background-color: var(--duo-border);
            border-radius: 20px;
            margin-right: 8px;
            position: relative;
            transition: background-color 0.2s;
        }
        .qt-toggle-slider::after {
            content: '';
            position: absolute;
            width: 16px;
            height: 16px;
            background: white;
            border-radius: 50%;
            top: 2px;
            left: 2px;
            transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .qt-toggle-input:checked + .qt-toggle-slider {
            background-color: var(--duo-green);
        }
        .qt-toggle-input:checked + .qt-toggle-slider::after {
            transform: translateX(16px);
        }
        .qt-primary-actions {
            display: flex;
            gap: 10px;
        }
        .qt-action-btn {
            flex: 1;
            padding: 10px;
            border-radius: 12px;
            border: none;
            font-weight: 700;
            font-size: 13px;
            cursor: pointer;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            transition: transform 0.1s, filter 0.2s;
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 8px;
        }
        .qt-action-btn:hover { filter: brightness(1.1); }
        .qt-btn-load { background: var(--duo-green); color: white; box-shadow: 0 4px 0 #46a302; }
        .qt-btn-claim-all { background: var(--duo-yellow); color: #735900; box-shadow: 0 4px 0 #d9aa00; }
        .qt-action-btn:active { transform: translateY(4px); box-shadow: none; }
        /* Loading Spinner */
        .qt-spinner {
            width: 14px;
            height: 14px;
            border: 2px solid rgba(255, 255, 255, 0.3);
            border-radius: 50%;
            border-top-color: #fff;
            animation: spin 0.8s linear infinite;
            display: none;
        }
        .qt-action-btn.loading .qt-spinner { display: block; }
        .qt-action-btn.loading span { opacity: 0.7; }
        .qt-content {
            flex: 1;
            overflow-y: auto;
            padding: 15px;
            background: var(--duo-bg);
        }
        .qt-item {
            display: flex;
            align-items: center;
            background: var(--duo-item-bg);
            border: 2px solid var(--duo-border);
            border-radius: 16px;
            padding: 12px;
            margin-bottom: 12px;
            transition: all 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
            position: relative;
            animation: slideIn 0.3s ease-out forwards;
            opacity: 0;
        }
        .qt-item:nth-child(1) { animation-delay: 0.05s; }
        .qt-item:nth-child(2) { animation-delay: 0.1s; }
        .qt-item:nth-child(3) { animation-delay: 0.15s; }
        .qt-item:nth-child(4) { animation-delay: 0.2s; }
        .qt-item:nth-child(5) { animation-delay: 0.25s; }
        .qt-item:hover { border-color: var(--duo-blue); transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0,0,0,0.05); }
        .qt-item.warning { border-left: 4px solid #ff9600; }
        .qt-item.completed { border-left: 4px solid var(--duo-green); }
        .qt-warning-icon {
            position: absolute;
            top: 5px;
            left: 5px;
            font-size: 14px;
            cursor: help;
        }
        .qt-icon {
            width: 56px;
            height: 56px;
            margin-right: 15px;
            object-fit: contain;
            transition: transform 0.2s;
        }
        .qt-item:hover .qt-icon { transform: scale(1.1) rotate(-5deg); }
        .qt-info { flex: 1; overflow: hidden; }
        .qt-name { font-weight: 700; color: var(--duo-text-main); margin-bottom: 4px; font-size: 15px; }
        .qt-meta { font-size: 11px; color: var(--duo-text-sub); margin-bottom: 6px; font-family: monospace;}
        .qt-progress-bar-bg {
            height: 10px;
            background: var(--duo-border);
            border-radius: 10px;
            overflow: hidden;
            position: relative;
        }
        .qt-progress-bar-fill {
            height: 100%;
            background: var(--duo-yellow);
            width: 0%;
            border-radius: 10px;
            transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
        }
        .qt-progress-bar-fill.full {
            background: var(--duo-green);
        }
        .qt-item-actions {
            display: flex;
            flex-direction: column;
            gap: 6px;
            margin-left: 12px;
        }
        .qt-mini-btn {
            background: var(--duo-blue);
            color: white;
            border: none;
            padding: 6px 10px;
            border-radius: 10px;
            font-weight: 700;
            cursor: pointer;
            box-shadow: 0 3px 0 #1899d6;
            font-size: 11px;
            text-align: center;
            width: 50px;
            transition: transform 0.1s, background-color 0.2s;
        }
        .qt-mini-btn:hover { transform: scale(1.05); filter: brightness(1.1); }
        .qt-mini-btn:active { transform: translateY(3px) scale(0.95); box-shadow: none; }
        .qt-mini-btn.gold { background: var(--duo-yellow); color: #735900; box-shadow: 0 3px 0 #d9aa00; }
        .qt-footer {
            padding: 15px;
            text-align: center;
            font-size: 12px;
            color: var(--duo-text-sub);
            background: var(--duo-panel-bg);
            border-top: 1px solid var(--duo-border);
        }
        .qt-footer a {
            color: var(--duo-blue);
            text-decoration: none;
            font-weight: bold;
            transition: color 0.2s;
        }
        .qt-footer a:hover { color: var(--duo-green); }
    `;
    const styleSheet = document.createElement("style");
    styleSheet.innerText = styles;
    document.head.appendChild(styleSheet);
    let state = {
        userId: sub || null, // Pre-fill with global sub
        token: jwt || null,  // Pre-fill with global jwt
        creationDate: null,
        schema: { goals: [], badges: [] },
        progress: {},
        earnedBadges: new Set(),
        filter: 'MONTHLY',
        hasAutoLoaded: false,
        hideCompleted: false,
        loading: false
    };
    const originalFetch = window.fetch;
    window.fetch = function(...args) {
        const fetchPromise = originalFetch.apply(this, args);
        try {
            const [resource, config] = args;
            const url = typeof resource === 'string' ? resource : (resource?.url || String(resource));
            if (config && config.headers && config.headers.Authorization) {
                const token = config.headers.Authorization.replace('Bearer ', '');
                if (token && token !== state.token) {
                    state.token = token;
                    updateStatusUI();
                    tryAutoLoad();
                }
            }
            if (url.includes('/users/')) {
                const userMatch = url.match(/\/users\/(\d+)/);
                if (userMatch && userMatch[1]) {
                    if (state.userId !== userMatch[1]) {
                        state.userId = userMatch[1];
                        updateStatusUI();
                        tryAutoLoad();
                    }
                }
            }
        } catch (e) {}
        return fetchPromise;
    };
    function log(msg) {
        console.log(`[DuoQuest] ${msg}`);
    }
    function getCookie(name) {
        const value = `; ${document.cookie}`;
        const parts = value.split(`; ${name}=`);
        if (parts.length === 2) return parts.pop().split(';').shift();
    }
    function checkStoredCredentials() {
        if (typeof sub !== 'undefined' && sub) state.userId = sub;
        if (typeof jwt !== 'undefined' && jwt) state.token = jwt;
        const jwtCookie = getCookie('jwt_token');
        if (!state.token && jwtCookie) state.token = jwtCookie;
        if (!state.userId && window.__PRELOADED_STATE__ && window.__PRELOADED_STATE__.user) {
            state.userId = window.__PRELOADED_STATE__.user.id;
        } else if (!state.userId) {
             const localState = localStorage.getItem('reduxPersist:user');
            if (localState) {
                try {
                    const parsed = JSON.parse(localState);
                    if (parsed.id) state.userId = parsed.id;
                } catch(e) {}
            }
        }
        updateStatusUI();
        tryAutoLoad();
    }
    function tryAutoLoad() {
        if (state.userId && state.token && !state.hasAutoLoaded) {
            state.hasAutoLoaded = true;
            setTimeout(loadData, 1000);
        }
    }
    function getQuestTimestamp(goalId) {
        const regex = /^(\d{4})_(\d{2})_monthly/;
        const match = goalId.match(regex);
        if (match) {
            const year = parseInt(match[1]);
            const month = parseInt(match[2]) - 1;
            const date = new Date(Date.UTC(year, month, 15, 12, 0, 0));
            return date.toISOString();
        }
        return new Date().toISOString();
    }
    function setButtonLoading(btnId, isLoading) {
        const btn = document.getElementById(btnId);
        if(btn) {
            if(isLoading) {
                btn.classList.add('loading');
                btn.disabled = true;
            } else {
                btn.classList.remove('loading');
                btn.disabled = false;
            }
        }
    }
    function getCommonHeaders() {
        return {
            "Content-Type": "application/json",
            "x-requested-with": "XMLHttpRequest",
            "accept": "application/json; charset=UTF-8",
            "Authorization": `Bearer ${state.token}`
        };
    }
    async function fetchAccountCreationDate() {
        if (!state.userId || !state.token) return;
        try {
            const url = `https://www.duolingo.com/2017-06-30/users/${state.userId}?fields=trackingProperties`;
            const res = await originalFetch(url, {
                method: "GET",
                headers: getCommonHeaders()
            });
            const data = await res.json();
            if (data.trackingProperties && data.trackingProperties.creation_date_new) {
                state.creationDate = new Date(data.trackingProperties.creation_date_new);
                const dateStr = state.creationDate.toLocaleDateString();
                const userDisplay = document.getElementById('qt-user-display');
                if(userDisplay) userDisplay.innerText = `ID: ${state.userId} (Since ${state.creationDate.getFullYear()})`;
            }
        } catch (e) {
            log("Warning: Could not fetch account age.");
        }
    }
    async function loadData() {
        if(!state.userId || !state.token) return;
        setButtonLoading('qt-load-btn', true);
        await fetchAccountCreationDate();
        try {
            const schemaRes = await originalFetch(`https://goals-api.duolingo.com/schema?ui_language=en&_=${Date.now()}`, {
                method: "GET",
                headers: getCommonHeaders(),
                credentials: "include"
            });
            const schemaData = await schemaRes.json();
            state.schema = schemaData;
        } catch (e) { console.error(e); }
        try {
            const progressRes = await originalFetch(`https://goals-api.duolingo.com/users/${state.userId}/progress?timezone=${Intl.DateTimeFormat().resolvedOptions().timeZone}&ui_language=en`, {
                method: "GET",
                headers: getCommonHeaders(),
                credentials: "include"
            });
            const progressData = await progressRes.json();
            state.progress = progressData.goals?.progress || {};
            if (progressData.badges && progressData.badges.earned) {
                state.earnedBadges = new Set(progressData.badges.earned);
            } else {
                state.earnedBadges = new Set();
            }
        } catch (e) { console.error(e); }
        setButtonLoading('qt-load-btn', false);
        renderGoals();
    }
    async function completeMetric(metricName, amount, goalId) {
        if(!state.userId) return;
        if (metricName === 'XP' && amount >= 50) {
            amount = 1000; // Safe limit for XP
        }
        const timestamp = getQuestTimestamp(goalId);
        const url = `https://goals-api.duolingo.com/users/${state.userId}/progress/batch`;
        const body = {
            "metric_updates": [
                {
                    "metric": metricName,
                    "quantity": amount
                }
            ],
            "timezone": Intl.DateTimeFormat().resolvedOptions().timeZone,
            "timestamp": timestamp
        };
        try {
            const response = await originalFetch(url, {
                method: "POST",
                headers: getCommonHeaders(),
                body: JSON.stringify(body)
            });
            if (!response.ok) {
                if (response.status === 500) {
                    alert("Server Error (500): The server rejected the request (likely due to the timestamp being too old/archived).");
                } else {
                    alert(`Error ${response.status}: Request failed.`);
                }
                return;
            }
            log(`✅ Updated ${metricName}!`);
            loadData();
        } catch (e) { console.error(e); }
    }
    async function claimAllMonthly() {
        if (!state.schema.goals) return;
        if (!state.creationDate && !confirm("Account age unknown. Continue?")) return;
        setButtonLoading('qt-claim-all-btn', true);
        const filteredGoals = getFilteredGoals();
        const safeGoals = filteredGoals.filter(g => {
            if (!g.category || !g.category.includes('MONTHLY')) return false;
            return !isQuestOlderThanAccount(g.goalId);
        });
        const batches = {};
        safeGoals.forEach(g => {
            const ts = getQuestTimestamp(g.goalId);
            if (!batches[ts]) batches[ts] = new Set();
            batches[ts].add(g.metric);
        });
        const timestamps = Object.keys(batches);
        let errorCount = 0;
        for (const ts of timestamps) {
            const uniqueMetrics = Array.from(batches[ts]);
            const metricUpdates = uniqueMetrics.map(metric => ({
                "metric": metric,
                "quantity": metric === 'XP' ? 1000 : 50
            }));
            const url = `https://goals-api.duolingo.com/users/${state.userId}/progress/batch`;
            const body = {
                "metric_updates": metricUpdates,
                "timezone": Intl.DateTimeFormat().resolvedOptions().timeZone,
                "timestamp": ts
            };
            try {
                const res = await originalFetch(url, {
                    method: "POST",
                    headers: getCommonHeaders(),
                    body: JSON.stringify(body)
                });
                if(!res.ok) errorCount++;
            } catch (e) { errorCount++; }
        }
        setButtonLoading('qt-claim-all-btn', false);
        if(errorCount > 0) {
            alert(`Done. ${errorCount} batches failed (likely due to historic timestamps).`);
        } else {
            alert("Claim All Completed Successfully!");
        }
        loadData();
    }
    function isQuestOlderThanAccount(goalId) {
        if(!state.creationDate) return false;
        const match = goalId.match(/^(\d{4})_(\d{2})_monthly/);
        if (match) {
            const year = parseInt(match[1]);
            const month = parseInt(match[2]) - 1;
            const creationYear = state.creationDate.getFullYear();
            const creationMonth = state.creationDate.getMonth();
            if (year < creationYear) return true;
            if (year === creationYear && month < creationMonth) return true;
        }
        return false;
    }
    function getFilteredGoals() {
        if (!state.schema.goals) return [];
        const map = new Map();
        const monthlyRegex = /^(\d{4}_\d{2})_monthly/;
        const monthlyGoals = [];
        const otherGoals = [];
        state.schema.goals.forEach(g => {
            const match = g.goalId.match(monthlyRegex);
            if (match) {
                monthlyGoals.push({ key: match[1], goal: g });
            } else {
                otherGoals.push(g);
            }
        });
        monthlyGoals.forEach(item => {
            const existing = map.get(item.key);
            if (!existing) {
                map.set(item.key, item.goal);
            } else {
                const existingIsChallenge = existing.category.includes('CHALLENGE');
                const newIsChallenge = item.goal.category.includes('CHALLENGE');
                if (!existingIsChallenge && newIsChallenge) {
                    map.set(item.key, item.goal);
                }
            }
        });
        return [...otherGoals, ...map.values()];
    }
    function createUI() {
        const container = document.createElement('div');
        container.id = 'duo-quest-tool';
        container.innerHTML = `
            <button id="duo-qt-toggle">📜Quest Tool</button>
            <div id="duo-qt-panel">
                <div class="qt-header">
                    <h3>Duolingo Quest Tool</h3>
                    <span class="qt-close" id="qt-close-btn">✕</span>
                </div>
                <div class="qt-status-bar">
                    <div>
                        <span class="qt-status-dot" id="qt-dot"></span>
                        <span id="qt-status-text">Waiting...</span>
                    </div>
                    <span id="qt-user-display">ID: ---</span>
                </div>
                <div class="qt-controls">
                    <div class="qt-primary-actions">
                        <button class="qt-action-btn qt-btn-load" id="qt-load-btn">
                            <div class="qt-spinner"></div><span>Refresh Data</span>
                        </button>
                        <button class="qt-action-btn qt-btn-claim-all" id="qt-claim-all-btn">
                            <div class="qt-spinner"></div><span>Claim All (+50)</span>
                        </button>
                    </div>
                    <div class="qt-filters-row">
                        <div class="qt-filters">
                            <button class="qt-pill active" data-filter="MONTHLY">Monthly</button>
                            <button class="qt-pill" data-filter="DAILY">Daily</button>
                            <button class="qt-pill" data-filter="FRIENDS">Friends</button>
                            <button class="qt-pill" data-filter="WEEKLY">Weekly</button>
                            <button class="qt-pill" data-filter="ALL">All</button>
                        </div>
                    </div>
                    <label class="qt-toggle-wrapper">
                        <input type="checkbox" class="qt-toggle-input" id="qt-hide-completed">
                        <span class="qt-toggle-slider"></span>
                        <span>Hide Done</span>
                    </label>
                </div>
                <div id="qt-content-area" class="qt-content">
                    <div style="text-align:center; color:var(--duo-text-sub); margin-top:50px; font-weight:600;">
                       1. Turn off "Lite Mode" in Settings<br>2. Browse Duolingo.<br>3. Wait for "Connected".<br>4. Data loads automatically.
                    </div>
                </div>
                <div class="qt-footer">
                    Credits: <a href="https://github.com/apersongithub/" target="_blank">apersongithub</a>
                </div>
            </div>
        `;
        document.body.appendChild(container);
        const panel = document.getElementById('duo-qt-panel');
        const header = panel.querySelector('.qt-header');
        let isDragging = false;
        let offset = { x: 0, y: 0 };
header.onmousedown = () => {};
document.onmousemove = () => {};
document.onmouseup = () => {};
        document.getElementById('duo-qt-toggle').onclick = () => {
            panel.style.display = panel.style.display === 'flex' ? 'none' : 'flex';
            updateStatusUI();
        };
        document.getElementById('qt-close-btn').onclick = () => panel.style.display = 'none';
        document.getElementById('qt-load-btn').onclick = loadData;
        document.getElementById('qt-claim-all-btn').onclick = claimAllMonthly;
        document.getElementById('qt-hide-completed').onchange = (e) => {
            state.hideCompleted = e.target.checked;
            renderGoals();
        };
        document.querySelectorAll('.qt-pill').forEach(btn => {
            btn.onclick = (e) => {
                document.querySelectorAll('.qt-pill').forEach(p => p.classList.remove('active'));
                e.target.classList.add('active');
                state.filter = e.target.dataset.filter;
                renderGoals();
            };
        });
    }
    function updateStatusUI() {
        const dot = document.getElementById('qt-dot');
        const text = document.getElementById('qt-status-text');
        const userDisplay = document.getElementById('qt-user-display');
        if (state.userId && state.token) {
            dot.classList.add('connected');
            text.innerText = "Connected";
            if(state.creationDate) {
                 userDisplay.innerText = `ID: ${state.userId} (${state.creationDate.getFullYear()})`;
            } else {
                 userDisplay.innerText = `ID: ${state.userId}`;
            }
        } else {
            dot.classList.remove('connected');
            text.innerText = "Scanning network...";
            userDisplay.innerText = "ID: ---";
        }
    }
    function renderGoals() {
        const container = document.getElementById('qt-content-area');
        container.innerHTML = '';
        const filteredSchemaGoals = getFilteredGoals();
        if (!filteredSchemaGoals || filteredSchemaGoals.length === 0) {
            container.innerHTML = '<div style="text-align:center;color:var(--duo-text-sub);">No goals loaded.</div>';
            return;
        }
        const isCategoryMatch = (cat) => {
            if (!cat) return false;
            if (state.filter === 'ALL') return true;
            if (state.filter === 'MONTHLY' && (cat.includes('MONTHLY'))) return true;
            if (state.filter === 'DAILY' && cat.includes('DAILY')) return true;
            if (state.filter === 'FRIENDS' && cat.includes('FRIENDS')) return true;
            if (state.filter === 'WEEKLY' && cat.includes('WEEKLY')) return true;
            return false;
        };
        const reversedGoals = [...filteredSchemaGoals].reverse();
        reversedGoals.forEach(goal => {
            if (!isCategoryMatch(goal.category)) return;
            let isEarned = false;
            if (state.earnedBadges.has(goal.badgeId) || state.earnedBadges.has(goal.goalId)) {
                isEarned = true;
            }
            if (state.hideCompleted && isEarned) return;
            let isOlder = isQuestOlderThanAccount(goal.goalId);
            let iconUrl = "https://d35aaqx5ub95lt.cloudfront.net/images/goals/2b5a21198336f3246eb61c5670868eb2.svg";
            const badge = state.schema.badges.find(b => b.badgeId === goal.badgeId);
            if (badge && badge.icon && badge.icon.enabled && badge.icon.enabled.lightMode) {
                iconUrl = badge.icon.enabled.lightMode.svg || badge.icon.enabled.lightMode.url || iconUrl;
            }
            let currentProgress = 0;
            let rawProgress = state.progress[goal.goalId];
            if (typeof rawProgress === 'number') {
                currentProgress = rawProgress;
            } else if (rawProgress && typeof rawProgress === 'object') {
                currentProgress = rawProgress.progress || 0;
            }
            const target = goal.threshold || 10;
            let percentage = Math.min(100, (currentProgress / target) * 100);
            const metric = goal.metric;
            let progressText = `${currentProgress} / ${target}`;
            let progressColor = "var(--duo-text-sub)";
            if (isEarned) {
                percentage = 100;
                progressText = "COMPLETED";
                progressColor = "var(--duo-green)";
            }
            const el = document.createElement('div');
            el.className = 'qt-item' + (isOlder ? ' warning' : '') + (isEarned ? ' completed' : '');
            el.innerHTML = `
                ${isOlder ? '<span class="qt-warning-icon" title="This quest is older than your account. Finishing it is risky.">⚠️</span>' : ''}
                <img src="${iconUrl}" class="qt-icon" onerror="this.style.display='none'">
                <div class="qt-info">
                    <div class="qt-name">${goal.title?.uiString || goal.goalId}</div>
                    <div class="qt-meta">Metric: ${metric}</div>
                    <div style="display:flex; justify-content:space-between; font-size:12px; font-weight:bold; color:${progressColor}; margin-bottom:2px;">
                        <span>${progressText}</span>
                        <span>${Math.round(percentage)}%</span>
                    </div>
                    <div class="qt-progress-bar-bg">
                        <div class="qt-progress-bar-fill ${isEarned ? 'full' : ''}" style="width: ${percentage}%"></div>
                    </div>
                </div>
                <div class="qt-item-actions">
                    <button class="qt-mini-btn" data-metric="${metric}" data-amt="1">+1</button>
                    <button class="qt-mini-btn" data-metric="${metric}" data-amt="10">+10</button>
                    <button class="qt-mini-btn gold" data-metric="${metric}" data-amt="50">Claim</button>
                </div>
            `;
            const buttons = el.querySelectorAll('button');
            buttons.forEach(btn => {
                btn.onclick = () => {
                    if (isOlder && !confirm("This quest is dated BEFORE your account was created. Completing it may flag your account. Are you sure?")) return;
                    completeMetric(btn.dataset.metric, parseInt(btn.dataset.amt), goal.goalId);
                };
            });
            container.appendChild(el);
        });
    }
    setTimeout(() => {
        createUI();
        checkStoredCredentials();
    }, 1000);
};
const showItemShop = async () => {
    console.log("🎁 Opening Item Shop...");
    if(!userInfo || !sub || !jwt || !defaultHeaders) {
        console.log("📊 User not loaded yet, initializing...");
        logToConsole('Initializing user data for shop...', 'info');
        const success = await initializeFarming();
        if(!success || !userInfo || !sub || !jwt) {
            logToConsole('❌ Failed to load user data. Please try again.', 'error');
            alert('Failed to load user data. Please reload the page and try again.');
            return;
        }
        logToConsole('✅ User data loaded successfully', 'success');
    }
    console.log("✅ User data ready:", {
        userInfo,
        sub,
        jwt: !!jwt
    });
    const modal = document.createElement('div');
    modal.id = '_item_shop_modal';
    modal.className = '_modal';
    modal.style.display = 'flex';
    modal.innerHTML = `
        <div class="_modal_overlay"></div>
        <div class="_modal_container _wide">
            <div class="_modal_header">
                <h2>
                    <span style="font-size: 24px; display:inline-block;vertical-align:middle;margin-right:8px">🎁</span>
                    Free Item Shop
                </h2>
                <button class="_close_modal_btn" id="_close_item_shop">
                    <span style="font-size: 18px;">❌</span>
                </button>
            </div>
            <div class="_modal_content">
                <div class="_shop_grid" id="_shop_items_grid">
                    ${SHOP_ITEMS.map(item => `
                        <div class="_shop_item_card">
                            <div class="_shop_item_icon">${item.icon}</div>
                            <div class="_shop_item_name">${item.label}</div>
                            <button class="_shop_buy_btn" data-item-id="${item.value}">
                                <span style="font-size: 16px;">🛒</span>
                                Get Free
                            </button>
                        </div>
                    `).join('')}
                </div>
                <div class="_shop_stats">
                    <p style="color: var(--text-secondary); font-size: 12px; text-align: center; margin-top: 20px;">
                        ✨ All items are FREE! Click any item to claim it instantly.
                    </p>
                </div>
            </div>
        </div>
    `;
    document.body.appendChild(modal);
    document.getElementById('_close_item_shop')?.addEventListener('click', () => {
        console.log("🎁 Closing Item Shop");
        modal.remove();
    });
    modal.addEventListener('click', (e) => {
        if(e.target.classList.contains('_modal_overlay')) {
            console.log("🎁 Closing Item Shop (overlay)");
            modal.remove();
        }
    });
    modal.querySelectorAll('._shop_buy_btn').forEach(btn => {
        btn.addEventListener('click', async (e) => {
            e.preventDefault();
            e.stopPropagation();
            const itemId = btn.dataset.itemId;
            const item = SHOP_ITEMS.find(i => i.value === itemId);
            console.log("🛍️ Buying item:", itemId, item);
            btn.disabled = true;
            btn.innerHTML = '<span style="font-size: 16px;">⏳</span> Processing...';
            const success = await buyItem(itemId);
            if(success) {
                btn.innerHTML = '<span style="font-size: 16px;">✅</span> Got It!';
                btn.style.background = 'var(--success-color)';
                btn.style.color = 'white';
                btn.style.cursor = 'default';
                setTimeout(() => {
                    btn.disabled = false;
                    btn.innerHTML = '<span style="font-size: 16px;">🛒</span> Get Free';
                    btn.style.background = '';
                    btn.style.color = '';
                    btn.style.cursor = 'pointer';
                }, 3000);
            } else {
                btn.disabled = false;
                btn.innerHTML = '<span style="font-size: 16px;">🛒</span> Get Free';
            }
        });
    });
    console.log("✅ Item Shop opened");
};
const farmXpBooster = async (amount) => {
    try {
        const url = `https://stories.duolingo.com/api2/stories/fr-en-le-passeport/complete`;
        const xpAmount = Math.max(1, amount);
        return await sendRequestWithDefaultHeaders({
            url: url,
            method: "POST",
            payload: {
                awardXp: true,
                completedBonusChallenge: true,
                fromLanguage: "en",
                learningLanguage: "fr",
                isFeaturedStoryInPracticeHub: true,
                isLegendaryMode: true,
                masterVersion: true,
                maxScore: 0,
                score: 0,
                happyHourBonusXp: xpAmount,
                startTime: Math.floor(Date.now() / 1000),
                endTime: Math.floor(Date.now() / 1000),
            }
        });
    } catch (e) { return null; }
};
const booster = {
    isRunning: false,
    type: 'xp',
    goal: 5000,
    startValue: 0,
    start: async () => {
        const goalInput = document.getElementById('_boost_goal');
        const typeSelect = document.getElementById('_boost_type');
        if (!goalInput || !typeSelect) return;
        booster.goal = parseInt(goalInput.value);
        booster.type = typeSelect.value;
        booster.startValue = booster.type === 'xp' ? userInfo.totalXp : userInfo.gems;
        booster.isRunning = true;
        const btn = document.getElementById('_boost_start_btn');
        if(btn) {
            btn.textContent = "Stop Boosting";
            btn.style.background = "#dc2626";
            btn.style.borderColor = "#b91c1c";
        }
        logToConsole(`🚀 Boosting ${booster.type.toUpperCase()}... Target: +${booster.goal}`, 'info');
        await booster.run();
    },
    stop: () => {
        booster.isRunning = false;
        const btn = document.getElementById('_boost_start_btn');
        if(btn) {
            btn.textContent = "Start Boosting";
            btn.style.background = "#2563eb";
            btn.style.borderColor = "#1d4ed8";
        }
        logToConsole('🛑 Boosting stopped', 'info');
    },
    run: async () => {
        const delayMs = currentMode === 'safe' ? 1000 : 300;
        while (booster.isRunning) {
            try {
                const currentValue = booster.type === 'xp' ? userInfo.totalXp : userInfo.gems;
                const gained = currentValue - booster.startValue;
                const remaining = booster.goal - gained;
                booster.updateProgress(gained);
                if (remaining <= 0) {
                    booster.updateProgress(booster.goal); // Đảm bảo UI hiện 100%
                    booster.stop();
                    logToConsole(`🎉 Finished! Gained ${gained} ${booster.type}!`, 'success');
                    await refreshUserData();
                    break;
                }
                let amountToFarm = 0;
                let res;
                if (booster.type === 'xp') {
                    amountToFarm = remaining >= 500 ? 500 : remaining;
                    res = await farmXpBooster(amountToFarm);
                } else {
                    amountToFarm = 30;
                    res = await farmGemOnce();
                }
                if (res?.ok) {
                    if (booster.type === 'xp') userInfo.totalXp += amountToFarm;
                    else userInfo.gems += amountToFarm;
                    if (booster.type === 'xp') {
                        if (gained % 1000 < amountToFarm) {
                           logToConsole(`⚡ Boosted +${amountToFarm} XP (Remaining: ${remaining - amountToFarm})`, 'info');
                        }
                    }
                } else {
                    logToConsole('⚠️ Request failed, waiting...', 'warning');
                    await new Promise(r => setTimeout(r, 2000));
                }
                await new Promise(r => setTimeout(r, delayMs));
            } catch (error) {
                console.error(error);
                await new Promise(r => setTimeout(r, 500));
            }
        }
    },
    updateProgress: (gainedAmount) => {
        const percentage = Math.min(100, Math.floor((gainedAmount / booster.goal) * 100));
        const progressBar = document.getElementById('_boost_progress_bar');
        const percentageText = document.getElementById('_boost_percentage');
        if (progressBar) progressBar.style.width = percentage + '%';
        if (percentageText) percentageText.textContent = percentage + '%';
        updateEarnedStats();
        updateUserInfo();
    }
};
const autoSolver = {
    findReact: (dom, traverseUp = 1) => {
        const key = Object.keys(dom).find(key => {
            return key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$");
        });
        const domFiber = dom[key];
        if (!domFiber) return null;
        const GetCompFiber = fiber => {
            let parentFiber = fiber.return;
            while (typeof parentFiber.type == "string") {
                parentFiber = parentFiber.return;
            }
            return parentFiber;
        };
        let compFiber = GetCompFiber(domFiber);
        for (let i = 0; i < traverseUp; i++) {
            compFiber = GetCompFiber(compFiber);
        }
        return compFiber.stateNode;
    },
    determineChallengeType: () => {
        try {
            if (window.sol?.type === 'typeCloze') return 'Type Cloze';
            if (window.sol?.type === 'typeClozeTable') return 'Type Cloze Table';
            if (window.sol?.type === 'tapClozeTable') return 'Tap Cloze Table';
            if (window.sol?.type === 'typeCompleteTable') return 'Type Complete Table';
            if (window.sol?.type === 'patternTapComplete') return 'Pattern Tap Complete';
            if (document.querySelector('[data-test="challenge challenge-listenSpeak"]')) return 'Listen Speak';
            if (document.querySelector('.FmlUF')) {
                if (window.sol?.type === 'arrange') return 'Story Arrange';
                if (window.sol?.type === 'multiple-choice' || window.sol?.type === 'select-phrases') return 'Story Multiple Choice';
                if (window.sol?.type === 'point-to-phrase') return 'Story Point to Phrase';
                if (window.sol?.type === 'match') return 'Story Pairs';
            }
            if (document.querySelectorAll('[data-test*="challenge-speak"]').length > 0) return 'Challenge Speak';
            if (document.querySelectorAll('[data-test*="challenge-name"]').length > 0 && document.querySelectorAll('[data-test="challenge-choice"]').length > 0) return 'Challenge Name';
            if (window.sol?.type === 'listenMatch') return 'Listen Match';
            if (document.querySelectorAll('[data-test="challenge-choice"]').length > 0) {
                if (document.querySelectorAll('[data-test="challenge-text-input"]').length > 0) return 'Challenge Choice with Text Input';
                return 'Challenge Choice';
            }
            if (document.querySelectorAll('[data-test$="challenge-tap-token"]').length > 0) {
                if (window.sol?.pairs !== undefined) return 'Pairs';
                if (window.sol?.correctTokens !== undefined) return 'Tokens Run';
                if (window.sol?.correctIndices !== undefined) return 'Indices Run';
            }
            if (document.querySelectorAll('[data-test="challenge-tap-token-text"]').length > 0) return 'Fill in the Gap';
            if (document.querySelectorAll('[data-test="challenge-text-input"]').length > 0) return 'Challenge Text Input';
            if (document.querySelectorAll('textarea[data-test="challenge-translate-input"]').length > 0) return 'Challenge Translate Input';
            if (window.sol?.type === 'tapCompleteTable') return 'Tap Complete Table';
            if (document.querySelectorAll('[data-test*="challenge-partialReverseTranslate"]').length > 0) return 'Partial Reverse';
            return false;
        } catch (error) {
            return false;
        }
    },
    setInputValue: (element, value) => {
        const isTextarea = element.tagName === 'TEXTAREA';
        const prototype = isTextarea ? window.HTMLTextAreaElement : window.HTMLInputElement;
        const setter = Object.getOwnPropertyDescriptor(prototype.prototype, "value").set;
        setter.call(element, value);
        element.dispatchEvent(new Event('input', { bubbles: true }));
    },
    delay: ms => new Promise(resolve => setTimeout(resolve, ms)),
    handleChallengeName: async () => {
        const articles = window.sol.articles;
        const correctSolution = window.sol.correctSolutions[0];
        const matchingArticle = articles.find(article => correctSolution.startsWith(article));
        if (matchingArticle !== undefined) {
            const matchingIndex = articles.indexOf(matchingArticle);
            const remainingValue = correctSolution.substring(matchingArticle.length).trim();
            const selectedElement = document.querySelector(`[data-test="challenge-choice"]:nth-child(${matchingIndex + 1})`);
            if (selectedElement) {
                selectedElement.click();
                await autoSolver.delay(50);
            }
            const input = document.querySelector('[data-test="challenge-text-input"]');
            if (input) autoSolver.setInputValue(input, remainingValue);
        }
    },
    handlePairs: async () => {
        const buttons = document.querySelectorAll('[data-test*="challenge-tap-token"]:not(span)');
        const texts = document.querySelectorAll('[data-test="challenge-tap-token-text"]');
        if (texts.length !== buttons.length || buttons.length === 0) return;
        for (const pair of window.sol.pairs || []) {
            for (let i = 0; i < buttons.length; i++) {
                const button = buttons[i];
                if (button.disabled) continue;
                const text = texts[i].innerText.toLowerCase().trim();
                const matches = text === pair.transliteration?.toLowerCase().trim() ||
                                text === pair.character?.toLowerCase().trim() ||
                                text === pair.learningToken?.toLowerCase().trim() ||
                                text === pair.fromToken?.toLowerCase().trim();
                if (matches) {
                    button.click();
                    await autoSolver.delay(50);
                }
            }
        }
    },
    handleTokensRun: async () => {
        const allTokens = document.querySelectorAll('[data-test$="challenge-tap-token"]');
        const clickedTokens = [];
        for (const correctToken of window.sol.correctTokens) {
            const matchingElements = Array.from(allTokens).filter(el => el.textContent.trim() === correctToken.trim());
            if (matchingElements.length > 0) {
                const matchIndex = clickedTokens.filter(token => token.textContent.trim() === correctToken.trim()).length;
                const elementToClick = matchingElements[matchIndex] || matchingElements[0];
                if (!elementToClick.disabled) {
                    elementToClick.click();
                    clickedTokens.push(elementToClick);
                    await autoSolver.delay(50);
                }
            }
        }
    },
    handleIndicesRun: async () => {
        if (!window.sol.correctIndices) return;
        const wordBank = document.querySelector('div[data-test="word-bank"]') || document.querySelector('.eSgkc');
        if (!wordBank) return;
        const bankButtons = Array.from(wordBank.querySelectorAll('button[data-test*="challenge-tap-token"]:not(span)'));
        for (const index of window.sol.correctIndices) {
            if (index >= 0 && index < bankButtons.length) {
                const button = bankButtons[index];
                if (!button.disabled && button.getAttribute('aria-disabled') !== 'true') {
                    button.click();
                    await autoSolver.delay(50);
                }
            }
        }
    },
    handleTapCompleteTable: async () => {
        const solutionRows = window.sol.displayTableTokens.slice(1);
        const tableRowElements = document.querySelectorAll('tbody tr');
        const wordBank = document.querySelector('div[data-test="word-bank"]');
        const wordBankButtons = wordBank ? wordBank.querySelectorAll('button[data-test*="-challenge-tap-token"]') : [];
        const usedWordBankIndexes = new Set();
        for (let rowIndex = 0; rowIndex < solutionRows.length; rowIndex++) {
            const solutionRow = solutionRows[rowIndex];
            const answerCellData = solutionRow[1];
            const correctToken = answerCellData.find(token => token.isBlank);
            if (correctToken) {
                const correctAnswerText = correctToken.text;
                const currentRowElement = tableRowElements[rowIndex];
                let clicked = false;
                const buttons = currentRowElement.querySelectorAll('button[data-test*="-challenge-tap-token"]');
                for (const button of buttons) {
                    const buttonTextElm = button.querySelector('[data-test="challenge-tap-token-text"]');
                    if (buttonTextElm && buttonTextElm.innerText.trim() === correctAnswerText && !button.disabled) {
                        button.click();
                        await autoSolver.delay(50);
                        clicked = true;
                        break;
                    }
                }
                if (!clicked && wordBankButtons.length > 0) {
                    for (let i = 0; i < wordBankButtons.length; i++) {
                        if (usedWordBankIndexes.has(i)) continue;
                        const button = wordBankButtons[i];
                        const buttonTextElm = button.querySelector('[data-test="challenge-tap-token-text"]');
                        if (buttonTextElm && buttonTextElm.innerText.trim() === correctAnswerText && !button.disabled) {
                            button.click();
                            await autoSolver.delay(50);
                            usedWordBankIndexes.add(i);
                            break;
                        }
                    }
                }
            }
        }
    },
    handleChallenge: async (type) => {
        try {
            switch(type) {
                case 'Challenge Speak':
                case 'Listen Match':
                case 'Listen Speak':
                    document.querySelector('button[data-test="player-skip"]')?.click();
                    break;
                case 'Challenge Choice':
                    document.querySelectorAll("[data-test='challenge-choice']")[window.sol.correctIndex]?.click();
                    break;
                case 'Challenge Choice with Text Input':
                    const choiceInput = document.querySelector('[data-test="challenge-text-input"]');
                    if (choiceInput) {
                        const answer = window.sol.correctSolutions ? window.sol.correctSolutions[0].split(/(?<=^\S+)\s/)[1] : (window.sol.displayTokens ? window.sol.displayTokens.find(t => t.isBlank)?.text : window.sol.prompt);
                        autoSolver.setInputValue(choiceInput, answer);
                    }
                    break;
                case 'Challenge Text Input':
                    const input = document.querySelector('[data-test="challenge-text-input"]');
                    if (input) {
                        const answer = window.sol.correctSolutions?.[0] || (window.sol.displayTokens ? window.sol.displayTokens.find(t => t.isBlank)?.text : window.sol.prompt);
                        autoSolver.setInputValue(input, answer);
                    }
                    break;
                case 'Challenge Translate Input':
                    const textarea = document.querySelector('textarea[data-test="challenge-translate-input"]');
                    if (textarea) autoSolver.setInputValue(textarea, window.sol.correctSolutions?.[0] || window.sol.prompt);
                    break;
                case 'Partial Reverse':
                    const partialElm = document.querySelector('[data-test*="challenge-partialReverseTranslate"]')?.querySelector("span[contenteditable]");
                    if (partialElm) {
                        const text = window.sol?.displayTokens?.filter(t => t.isBlank)?.map(t => t.text)?.join('')?.trim();
                        const setter = Object.getOwnPropertyDescriptor(Node.prototype, "textContent").set;
                        setter.call(partialElm, text);
                        partialElm.dispatchEvent(new Event('input', { bubbles: true }));
                    }
                    break;
                case 'Type Cloze':
                    const clozeInput = document.querySelector('input[type="text"].b4jqk');
                    if (clozeInput) {
                        const targetToken = window.sol.displayTokens.find(t => t.damageStart !== undefined);
                        if (targetToken) {
                            const correctEnding = targetToken.text.slice(targetToken.damageStart);
                            autoSolver.setInputValue(clozeInput, correctEnding);
                        }
                    }
                    break;
                case 'Type Cloze Table':
                    const tableRows = document.querySelectorAll('tbody tr');
                    window.sol.displayTableTokens.slice(1).forEach((rowTokens, i) => {
                        const answerCell = rowTokens[1]?.find(t => typeof t.damageStart === "number");
                        if (answerCell && tableRows[i]) {
                            const input = tableRows[i].querySelector('input[type="text"].b4jqk');
                            if (input) {
                                const correctEnding = answerCell.text.slice(answerCell.damageStart);
                                autoSolver.setInputValue(input, correctEnding);
                            }
                        }
                    });
                    break;
                case 'Tap Cloze Table':
                    const tapTableRows = document.querySelectorAll('tbody tr');
                    window.sol.displayTableTokens.slice(1).forEach((rowTokens, i) => {
                        const answerCell = rowTokens[1]?.find(t => typeof t.damageStart === "number");
                        if (!answerCell || !tapTableRows[i]) return;
                        const wordBank = document.querySelector('[data-test="word-bank"]');
                        const wordButtons = wordBank ? Array.from(wordBank.querySelectorAll('button[data-test*="challenge-tap-token"]:not([aria-disabled="true"])')) : [];
                        const correctWord = answerCell.text;
                        const correctEnding = correctWord.slice(answerCell.damageStart);
                        let endingMatched = "";
                        for (let btn of wordButtons) {
                            if (!correctEnding.startsWith(endingMatched + btn.innerText)) continue;
                            btn.click();
                            endingMatched += btn.innerText;
                            if (endingMatched === correctEnding) break;
                        }
                    });
                    break;
                case 'Type Complete Table':
                    const completeTableRows = document.querySelectorAll('tbody tr');
                    window.sol.displayTableTokens.slice(1).forEach((rowTokens, i) => {
                        const answerCell = rowTokens[1]?.find(t => t.isBlank);
                        if (!answerCell || !completeTableRows[i]) return;
                        const input = completeTableRows[i].querySelector('input[type="text"].b4jqk');
                        if (input) autoSolver.setInputValue(input, answerCell.text);
                    });
                    break;
                case 'Pattern Tap Complete':
                    const patternWordBank = document.querySelector('[data-test="word-bank"]');
                    if (!patternWordBank) return;
                    const correctIndex = window.sol.correctIndex ?? 0;
                    const correctText = window.sol.choices[correctIndex];
                    const patternButtons = Array.from(patternWordBank.querySelectorAll('button[data-test*="challenge-tap-token"]:not([aria-disabled="true"])'));
                    const targetButton = patternButtons.find(btn => btn.innerText.trim() === correctText);
                    if (targetButton) targetButton.click();
                    break;
                case 'Story Arrange':
                    const arrangeChoices = document.querySelectorAll('[data-test*="challenge-tap-token"]:not(span)');
                    for (let i = 0; i < window.sol.phraseOrder.length; i++) {
                        arrangeChoices[window.sol.phraseOrder[i]].click();
                        await autoSolver.delay(50);
                    }
                    break;
                case 'Story Multiple Choice':
                    const storyChoices = document.querySelectorAll('[data-test="stories-choice"]');
                    storyChoices[window.sol.correctAnswerIndex]?.click();
                    break;
                case 'Story Point to Phrase':
                    const phraseChoices = document.querySelectorAll('[data-test="challenge-tap-token-text"]');
                    let phraseCorrectIndex = -1;
                    for (let i = 0; i < window.sol.parts.length; i++) {
                        if (window.sol.parts[i].selectable === true) {
                            phraseCorrectIndex += 1;
                            if (window.sol.correctAnswerIndex === i) {
                                phraseChoices[phraseCorrectIndex]?.parentElement.click();
                                break;
                            }
                        }
                    }
                    break;
                case 'Story Pairs':
                    const storyButtons = document.querySelectorAll('[data-test*="challenge-tap-token"]:not(span)');
                    const storyTexts = document.querySelectorAll('[data-test="challenge-tap-token-text"]');
                    const textToElementMap = new Map();
                    for (let i = 0; i < storyButtons.length; i++) {
                        const text = storyTexts[i].innerText.toLowerCase().trim();
                        textToElementMap.set(text, storyButtons[i]);
                    }
                    for (const key in window.sol.dictionary) {
                        if (window.sol.dictionary.hasOwnProperty(key)) {
                            const value = window.sol.dictionary[key];
                            const keyPart = key.split(":")[1].toLowerCase().trim();
                            const normalizedValue = value.toLowerCase().trim();
                            const element1 = textToElementMap.get(keyPart);
                            const element2 = textToElementMap.get(normalizedValue);
                            if (element1 && !element1.disabled) {
                                element1.click();
                                await autoSolver.delay(50);
                            }
                            if (element2 && !element2.disabled) {
                                element2.click();
                                await autoSolver.delay(50);
                            }
                        }
                    }
                    break;
                case 'Challenge Name':
                    await autoSolver.handleChallengeName();
                    break;
                case 'Pairs':
                    await autoSolver.handlePairs();
                    break;
                case 'Tokens Run':
                    await autoSolver.handleTokensRun();
                    break;
                case 'Indices Run':
                case 'Fill in the Gap':
                    await autoSolver.handleIndicesRun();
                    break;
                case 'Tap Complete Table':
                    await autoSolver.handleTapCompleteTable();
                    break;
            }
        } catch (error) {
            console.error('Error handling challenge:', error);
        }
    },
    clickNext: () => {
        setTimeout(() => {
            const nextBtn = document.querySelector('[data-test="player-next"]') || document.querySelector('[data-test="stories-player-continue"]') || document.querySelector('[data-test="stories-player-done"]');
            if (!nextBtn) return;
            const isDisabled = nextBtn.getAttribute('aria-disabled') === 'true' || nextBtn.disabled;
            if (!isDisabled) {
                nextBtn.click();
                if (isAutoMode) {
                    setTimeout(() => {
                        if (nextBtn.classList.contains('_2oGJR')) nextBtn.click();
                    }, 100);
                }
            }
        }, 100);
    },
    solve: async () => {
        const skipSelectors = ['[data-test="practice-hub-ad-no-thanks-button"]', '[data-test="plus-no-thanks"]', '[data-test="story-start"]', '.vpDIE', '._1N-oo._36Vd3._16r-S._1ZBYz._23KDq._1S2uf.HakPM'];
        skipSelectors.forEach(sel => document.querySelector(sel)?.click());
        try {
            let mainElement = document.querySelector('._3yE3H');
            if (!mainElement) mainElement = document.querySelector('.RMEuZ._1GVfY') || document.querySelector('[data-test="challenge"]') || document.querySelector('[class*="challenge"]');
            if (!mainElement) {
                autoSolver.clickNext();
                return;
            }
            const reactInstance = autoSolver.findReact(mainElement);
            window.sol = reactInstance?.props?.currentChallenge;
            if (!window.sol) {
                autoSolver.clickNext();
                return;
            }
            const challengeType = autoSolver.determineChallengeType();
            if (challengeType) {
                await autoSolver.handleChallenge(challengeType);
            }
            autoSolver.clickNext();
        } catch (error) {
            console.error('Solve error:', error);
            autoSolver.clickNext();
        }
    },
    toggleAutoMode: () => {
        isAutoMode = !isAutoMode;
        autoSolver.updateUI();
        if (isAutoMode) {
            solvingIntervalId = setInterval(autoSolver.solve, SOLVE_SPEED * 1000);
        } else {
            clearInterval(solvingIntervalId);
        }
    },
    createUI: () => {
        if (solverUI) return;
        solverUI = document.createElement('div');
        solverUI.id = 'nightware-solver-ui';
        solverUI.style.cssText = `position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); z-index: 999997; display: flex; gap: 12px; animation: slideUp 0.3s ease-out;`;
        solverUI.innerHTML = `
            <button class="nw-solver-btn" id="nw-solve-single" style="padding: 12px 24px; background: #89e219; border: none; border-bottom: 4px solid #58cc02; border-radius: 12px; color: white; font-weight: 700; font-size: 14px; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">SOLVE</button>
            <button class="nw-solver-btn" id="nw-solve-all" style="padding: 12px 24px; background: #ffc800; border: none; border-bottom: 4px solid #ff9600; border-radius: 12px; color: white; font-weight: 700; font-size: 14px; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">SOLVE ALL</button>
        `;
        const style = document.createElement('style');
        style.textContent = `@keyframes slideUp { from { opacity: 0; transform: translateX(-50%) translateY(20px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } } .nw-solver-btn:hover { filter: brightness(1.1); transform: translateY(-2px); } .nw-solver-btn:active { border-bottom: 0px; transform: translateY(2px); }`;
        document.head.appendChild(style);
        document.body.appendChild(solverUI);
        document.getElementById('nw-solve-single').addEventListener('click', autoSolver.solve);
        document.getElementById('nw-solve-all').addEventListener('click', autoSolver.toggleAutoMode);
        document.addEventListener('keydown', (e) => {
            if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
                if (e.shiftKey) autoSolver.toggleAutoMode();
                else autoSolver.solve();
            }
        });
    },
    removeUI: () => {
        if (solverUI) {
            solverUI.remove();
            solverUI = null;
        }
        if (solvingIntervalId) {
            clearInterval(solvingIntervalId);
            solvingIntervalId = null;
        }
        isAutoMode = false;
    },
    updateUI: () => {
        const btn = document.getElementById('nw-solve-all');
        if (btn) {
            btn.textContent = isAutoMode ? 'PAUSE' : 'SOLVE ALL';
            btn.style.background = isAutoMode ? '#ff4b4b' : '#1cb0f6';
            btn.style.borderBottomColor = isAutoMode ? '#cc0000' : '#2b70c9';
        }
    },
    checkAndToggle: () => {
        const currentIsInLesson = window.location.pathname.includes('/lesson') || window.location.pathname.includes('/practice');
        if (currentIsInLesson !== isInLesson) {
            isInLesson = currentIsInLesson;
            if (isInLesson && INJECT_SOLVER_ENABLED) {
                setTimeout(() => autoSolver.createUI(), 500);
            } else {
                autoSolver.removeUI();
            }
        }
    }
};
setInterval(() => autoSolver.checkAndToggle(), 1000);
const initInterface = () => {
    const containerHTML = `
  <div id="_backdrop"></div>
  <div id="_container" class="theme-${currentTheme}">
    <div id="_header">
      <div class="_header_top">
        <div class="_brand">
<a href="https://twisk.fun/discord" target="_blank" rel="noopener noreferrer">
  <div class="_logo_container">
    <div class="_logo"
         style="
           display: flex;
           align-items: center;
           justify-content: center;
           width: 40px;
           height: 40px;
           border-radius: 50%;
           overflow: hidden;
           border: 2px solid #1E88E5; /* Viền xanh */
         "
    >
      <img src="https://github.com/helloticc/DuoHacker/blob/main/DuoHacker.png?raw=true"
           alt="Rocket"
           style="
             width: 110%;
             height: 110%;
             object-fit: cover;
           "
      >
    </div>
  </div>
</a>
<a href="https://twisk.fun" target="_blank" rel="noopener noreferrer" style="text-decoration: none; color: inherit;">
  <div class="_brand_text">
    <h1>DuoHacker</h1>
    <span class="_version_badge">Free</span>
  </div>
</a>
        </div>
        <div class="_header_controls">
<button id="_leaderboard_btn" class="_control_btn _success" style="background: linear-gradient(135deg, #81c784 0%, #4caf50 100%); box-shadow: 0 4px 12px rgba(76, 175, 80, 0.3);">
    <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/ca9178510134b4b0893dbac30b6670aa.svg"
         style="width: 32px; height: 32px; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.2)); object-fit: contain;">
</button>
<button id="_monthly_badges" class="_control_btn _success"
  style="background: linear-gradient(135deg, #ab47bc 0%, #7b1fa2 100%); box-shadow: 0 4px 12px rgba(171, 71, 188, 0.3);">
  <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/7ef36bae3f9d68fc763d3451b5167836.svg"
       style="width: 30px; height: 30px; object-fit: contain; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));">
</button>
<button id="_item_shop_btn" class="_control_btn _success"
  style="background: linear-gradient(135deg, #ffe599 0%, #f1c232 100%); box-shadow: 0 4px 12px rgba(241, 194, 50, 0.4);">
  <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/0e58a94dda219766d98c7796b910beee.svg"
       style="width: 28px; height: 28px; object-fit: contain; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.1));">
</button>
<button id="_booster_menu_btn" class="_control_btn _booster">
    <img src="https://d35aaqx5ub95lt.cloudfront.net/images/icons/68c1fd0f467456a4c607ecc0ac040533.svg"
         style="width: 28px; height: 28px; object-fit: contain; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.1));">
</button>
<button id="_accounts_btn" class="_control_btn _accounts">
    <img src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/48b8884ac9d7513e65f3a2b54984c5c4.svg"
         style="width: 26px; height: 26px; object-fit: contain; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.1));">
    <span class="_badge">${savedAccounts.length}</span>
</button>
<button id="_settings_btn" class="_control_btn _settings">
    <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/Windows_Settings_icon.svg/2184px-Windows_Settings_icon.svg.png"
         style="width: 26px; height: 26px; object-fit: contain; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.1));">
</button>
<button id="_minimize_btn" class="_control_btn _minimize" title="Minimize">
            <span style="font-size: 18px;">➖</span>
</button>
<button id="_close_btn" class="_control_btn _close" title="Close">
            <span style="font-size: 18px;">✖️</span>
</button>
        </div>
      </div>
    </div>
    <div id="_main_content" style="display:none">
    <div class="_announce_bar">
          <span>🎁Get free super links daily at DuoHacker Community</span>
          <a href="https://dsc.gg/duohacker" target="_blank" class="_announce_btn">Claim </a>
      </div>
      <div class="_profile_card">
        <div class="_profile_header">
          <div class="_avatar">
            <span style="font-size: 28px;">👤</span>
          </div>
          <div class="_profile_info">
            <h2 id="_username">Loading...</h2>
            <p id="_user_details">Fetching data...</p>
          </div>
          <button id="_save_account_btn" class="_icon_btn _success" title="Save Current Account">
            <span style="font-size: 16px;">💾</span>
          </button>
<button id="_refresh_profile" class="_icon_btn _primary" title="Refresh Profile">
  <span style="font-size: 16px;">🔄</span>
</button>
        </div>
        <div class="_stats_row">
          <div class="_stat_item">
<div class="_stat_icon"><img src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/01ce3a817dd01842581c3d18debcbc46.svg" alt="XP Icon"></div>
            <div class="_stat_info">
              <span class="_stat_value" id="_current_xp">0</span>
              <span class="_stat_label">Total XP</span>
            </div>
          </div>
          <div class="_stat_item">
<div class="_stat_icon"><img src="https://d35aaqx5ub95lt.cloudfront.net/images/icons/398e4298a3b39ce566050e5c041949ef.svg" alt="streak Icon"></div>
            <div class="_stat_info">
              <span class="_stat_value" id="_current_streak">0</span>
              <span class="_stat_label">Streak</span>
            </div>
          </div>
          <div class="_stat_item">
<div class="_stat_icon"><img src="https://d35aaqx5ub95lt.cloudfront.net/images/gems/45c14e05be9c1af1d7d0b54c6eed7eee.svg" alt="gem Icon"></div>
            <div class="_stat_info">
              <span class="_stat_value" id="_current_gems">0</span>
              <span class="_stat_label">Gems</span>
            </div>
          </div>
        </div>
      </div>
      <div class="_mode_section">
        <h3>Select Farming Mode</h3>
        <div class="_mode_cards">
          <div class="_mode_card ${currentMode === 'safe' ? '_active' : ''}" data-mode="safe">
<div class="_mode_icon">
  <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/5187f6694476a769d4a4e28149867e3e.svg" alt="Safe Mode Icon">
</div>
            <h4>Safe Mode</h4>
            <p>Slow but undetectable farming</p>
            <div class="_mode_specs">
              <span class="_spec">2s delay</span>
              <span class="_spec">100% safe</span>
            </div>
          </div>
          <div class="_mode_card ${currentMode === 'fast' ? '_active' : ''}" data-mode="fast">
<div class="_mode_icon">
  <img src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/01ce3a817dd01842581c3d18debcbc46.svg" alt="Fast Mode Icon">
</div>
            <h4>Fast Mode</h4>
            <p>Quick farming with risk</p>
            <div class="_mode_specs">
              <span class="_spec">0.3s delay</span>
              <span class="_spec">Use carefully</span>
            </div>
          </div>
        </div>
      </div>
<div class="_options_section">
  <h3>Farming Options</h3>
  <div class="_option_grid">
    <button class="_option_btn" data-type="xp">
<div class="_option_icon">
  <img src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/01ce3a817dd01842581c3d18debcbc46.svg" alt="XP Icon">
</div>
      <span>Farm XP</span>
    </button>
    <button class="_option_btn" data-type="xp_10">
<div class="_option_icon">
  <img src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/01ce3a817dd01842581c3d18debcbc46.svg" alt="XP10 Icon">
</div>
      <span>Farm XP Lite</span>
    </button>
    <button class="_option_btn" data-type="gems">
<div class="_option_icon">
  <img src="https://d35aaqx5ub95lt.cloudfront.net/images/gems/45c14e05be9c1af1d7d0b54c6eed7eee.svg" alt="Gems Icon">
</div>
      <span>Farm Gem</span>
    </button>
    <button class="_option_btn" data-type="quest">
<div class="_option_icon">
  <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/7ef36bae3f9d68fc763d3451b5167836.svg" alt="Quest Icon">
</div>
      <span>Daily Quest</span>
    </button>
    <button class="_option_btn" data-type="streak_farm">
<div class="_option_icon">
  <img src="https://d35aaqx5ub95lt.cloudfront.net/images/icons/398e4298a3b39ce566050e5c041949ef.svg" alt="Streak Icon">
</div>
      <span>Farm Streak</span>
    </button>
            <button class="_option_btn" data-type="league_farm">
<div class="_option_icon">
  <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/ca9178510134b4b0893dbac30b6670aa.svg" alt="League Icon">
</div>
      <span>Auto League</span>
    </button>
    <button class="_option_btn" data-type="farm_all">
<div class="_option_icon">
  <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/784035717e2ff1d448c0f6cc4efc89fb.svg" alt="FA Icon">
</div>
      <span>Farm All</span>
    </button>
  </div>
</div>
      <div class="_control_panel">
        <button id="_start_farming" class="_start_btn">
          <span class="_btn_text">Start Farming</span>
        </button>
        <button id="_stop_farming" class="_stop_btn" style="display:none">
          <span class="_btn_text">Stop Farming</span>
        </button>
      </div>
            <div class="_inject_section" style="margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border-color);">
        <div class="_setting_item" style="margin-bottom: 0;">
          <div class="_toggle_container">
            <label class="_toggle_label" style="font-size: 15px; font-weight: 600; display: flex; align-items: center; gap: 8px;">
<span class="_toggle_icon_wrapper"><img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/5187f6694476a769d4a4e28149867e3e.svg" alt="Solver Icon"></span> Inject Solver Button
            </label>
            <div class="_toggle_switch ${INJECT_SOLVER_ENABLED ? '_active' : ''}" id="_inject_solver_toggle">
              <div class="_toggle_slider"></div>
            </div>
          </div>
          <p class="_setting_description" style="margin-top: 5px; font-size: 13px; color: var(--text-secondary);">
             Automatically show floating "SOLVE" & "SOLVE ALL" buttons when you enter a lesson.
          </p>
        </div>
      </div>
      <div class="_live_stats">
        <h3>Live Statistics</h3>
        <div class="_stats_grid">
          <div class="_live_stat">
<div class="_live_icon"><img src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/01ce3a817dd01842581c3d18debcbc46.svg" alt="XP Earned Icon"></div>
            <div class="_live_data">
              <span id="_earned_xp">0</span>
              <small>XP Earned</small>
            </div>
          </div>
          <div class="_live_stat">
<div class="_live_icon"><img src="https://d35aaqx5ub95lt.cloudfront.net/images/gems/45c14e05be9c1af1d7d0b54c6eed7eee.svg" alt="Gems Earned Icon"></div>
            <div class="_live_data">
              <span id="_earned_gems">0</span>
              <small>Gems Earned</small>
            </div>
          </div>
          <div class="_live_stat">
<div class="_live_icon"><img src="https://d35aaqx5ub95lt.cloudfront.net/images/icons/398e4298a3b39ce566050e5c041949ef.svg" alt="Streak Gained Icon"></div>
            <div class="_live_data">
              <span id="_earned_streak">0</span>
              <small>Streak Gained</small>
            </div>
          </div>
          <div class="_live_stat">
<div class="_live_icon"><img src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/48b8884ac9d7513e65f3a2b54984c5c4.svg" alt="lesson slved Icon"></div>
            <div class="_live_data">
              <span id="_earned_lessons">0</span>
              <small>Lessons Solved</small>
            </div>
          </div>
          <div class="_live_stat">
<div class="_live_icon"><img src="https://d35aaqx5ub95lt.cloudfront.net/images/goals/974e284761265b0eb6c9fd85243c5c4b.svg" alt="time Icon"></div>
            <div class="_live_data">
              <span id="_farming_time">00:00</span>
              <small>Time Elapsed</small>
            </div>
          </div>
        </div>
      </div>
      <div class="_console_section">
        <div class="_console_header">
          <h3>Activity Log</h3>
          <button id="_clear_console" class="_clear_btn">Clear</button>
        </div>
        <div id="_console_output" class="_console">
          <div class="_log_entry _info">
            <span class="_log_time">${new Date().toLocaleTimeString()}</span>
            <span class="_log_msg">DuoHacker Lite initialized</span>
          </div>
        </div>
      </div>
    </div>
    <div id="_join_section" class="_join_section">
      <div class="_join_content">
        <!-- Ảnh rương SVG đóng vai trò là nút bấm (_join_btn) -->
        <img id="_join_btn"
             src="https://d35aaqx5ub95lt.cloudfront.net/images/c4527dd72a1ee03a7a9999af0b01e392.svg"
             style="width: 180px; height: auto; cursor: pointer; transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275); filter: drop-shadow(0 10px 20px rgba(0,0,0,0.15));"
             onmouseover="this.style.transform='scale(1.1) rotate(-3deg)'"
             onmouseout="this.style.transform='scale(1) rotate(0deg)'"
             alt="Unlock Tool"
        >
        <h3 style="margin-top: 20px; color: var(--text-primary); font-weight: 800;">Tap to Open</h3>
        <p style="color: var(--text-secondary); font-size: 13px;">Unlock DuoHacker features</p>
      </div>
    </div>
    <div class="_footer">
<span>© 2025 DuoHacker by <a href="https://www.duolingo.com/profile/LiamSmith92" target="_blank" style="color: #39FF14; text-decoration: none; text-shadow: 0 0 5px #39FF14, 0 0 10px #39FF14;">LiamSmith92</a></span>
      <span class="_footer_version">Lite</span>
    </div>
  </div>
  <div id="_accounts_modal" class="_modal" style="display:none">
    <div class="_modal_overlay"></div>
    <div class="_modal_container _wide">
<div class="_modal_header">
    <h2>
        <img src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/48b8884ac9d7513e65f3a2b54984c5c4.svg"
             style="width: 32px; height: 32px; display:inline-block; vertical-align:middle; margin-right:8px; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.1));">
        Account Manager
    </h2>
    <button id="_close_accounts" class="_close_modal_btn">
        <span style="font-size: 18px;">❌</span>
    </button>
</div>
      <div class="_modal_content">
        <div class="_accounts_grid" id="_accounts_list">
          ${savedAccounts.length === 0 ? '<div class="_empty_state"><p>No saved accounts yet. Save your current account to get started!</p></div>' : ''}
        </div>
      </div>
    </div>
  </div>
  <div id="_save_account_modal" class="_modal" style="display:none">
  <div class="_modal_overlay"></div>
  <div class="_modal_container">
    <div class="_modal_header">
      <h2>Save Account</h2>
      <button id="_close_save_account" class="_close_modal_btn">
        <span style="font-size: 18px;">❌</span>
      </button>
    </div>
    <div class="_modal_content">
      <div class="_settings_section">
        <div class="_setting_item">
          <label class="_input_label">Account Nickname</label>
          <input type="text" id="_account_nickname" class="_text_input" placeholder="e.g., Main Account, Alt #1, Work Account">
        </div>
        <div class="_setting_item">
          <div class="_account_preview">
            <div class="_preview_avatar">
              <span style="font-size: 20px;">👤</span>
            </div>
            <div class="_preview_info">
              <strong id="_preview_username">Loading...</strong>
              <span id="_preview_details">...</span>
            </div>
          </div>
        </div>
        <div class="_setting_item">
          <button id="_confirm_save_account" class="_setting_btn _success">
            <span style="font-size: 18px;">✅</span>
            Save Account
          </button>
        </div>
      </div>
    </div>
  </div>
</div>
 <div id="_settings_modal" class="_modal" style="display:none">
  <div class="_modal_overlay"></div>
  <div class="_modal_container">
    <div class="_modal_header">
      <h2>Settings</h2>
      <button id="_close_settings" class="_close_modal_btn">
        <span style="font-size: 18px;">❌</span>
      </button>
    </div>
    <div class="_modal_content">
      <!-- PERFORMANCE SECTION -->
      <div class="_settings_section">
        <h3>Performance</h3>
        <div class="_setting_item">
          <div class="_toggle_container">
            <label class="_toggle_label">Lite Mode (Reduce Animations)</label>
            <div class="_toggle_switch ${liteMode ? '_active' : ''}" id="_lite_mode_toggle">
              <div class="_toggle_slider"></div>
            </div>
          </div>
          <p class="_setting_description">Disable animations and visual effects for smoother performance</p>
        </div>
      </div>
      <div class="_setting_item">
          <div class="_toggle_container">
            <label class="_toggle_label">Hide Animation (Images)</label>
            <div class="_toggle_switch ${hideAnimationEnabled ? '_active' : ''}" id="_hide_animation_toggle">
              <div class="_toggle_slider"></div>
            </div>
          </div>
          <p class="_setting_description">Hide images to reduce RAM usage</p>
        </div>
      <!-- SUPERLINKS CHECKER SECTION -->
      <div class="_settings_section _superlinks_section">
        <h3>🔗 Superlinks Checker</h3>
        <p class="_setting_description" style="margin-bottom: 12px;">Check if a Superlinks invitation is valid</p>
        <div class="_superlinks_input_group">
          <input type="text" id="_superlinks_input" class="_superlinks_input" placeholder="Paste link or ID (e.g., 2-N4GT-L7SD-W1LC-U2XF)">
          <button id="_superlinks_check_btn" class="_superlinks_check_btn">Check</button>
        </div>
        <div id="_superlinks_result" class="_superlinks_result"></div>
      </div>
      <!-- PREMIUM FEATURES SECTION -->
      <div class="_settings_section">
        <h3>Premium Features</h3>
        <!-- DUOLINGO MAX -->
        <div class="_setting_item" style="border-bottom: 1px solid var(--border-color); padding-bottom: 16px; margin-bottom: 16px;">
          <div class="_toggle_container">
            <label class="_toggle_label">Enable Duolingo Max</label>
            <div class="_toggle_switch ${duolingoMaxEnabled ? '_active' : ''}" id="_duolingo_max_toggle">
              <div class="_toggle_slider"></div>
            </div>
          </div>
          <p class="_setting_description">Unlock Super features including unlimited hearts, no ads, and AI-powered lessons</p>
        </div>
        <!-- DUOLINGO SUPER -->
        <div class="_setting_item">
          <div class="_toggle_container">
            <label class="_toggle_label">Enable Duolingo Super</label>
            <div class="_toggle_switch ${duolingoSuperEnabled ? '_active' : ''}" id="_duolingo_super_toggle">
              <div class="_toggle_slider"></div>
            </div>
          </div>
          <p class="_setting_description">Unlock premium features including unlimited hearts and advanced lessons</p>
        </div>
      </div>
      <!-- PRIVACY SETTINGS SECTION -->
      <div class="_settings_section">
        <h3>Privacy Settings</h3>
        <div class="_setting_item">
          <button id="_privacy_toggle_btn" class="_setting_btn _primary">
            <span style="font-size: 18px;">🔒</span>
            Set Private
          </button>
          <p class="_setting_description">Toggle your profile visibility between public and private</p>
        </div>
      </div>
      <!-- QUICK ACTIONS SECTION -->
      <div class="_settings_section">
        <h3>Quick Actions</h3>
        <div class="_setting_item">
          <button id="_get_jwt_btn" class="_setting_btn _primary">
            <span style="font-size: 18px;">📋</span>
            Copy JWT Token
          </button>
        </div>
        <div class="_setting_item">
          <button id="_logout_btn" class="_setting_btn _danger">
            <span style="font-size: 18px;">🚪</span>
            Log Out
          </button>
        </div>
      </div>
      <!-- MANUAL LOGIN SECTION -->
      <div class="_settings_section">
        <h3>Manual Login</h3>
        <div class="_setting_item">
          <div class="_jwt_input_group">
            <input type="text" id="_jwt_input" placeholder="Paste JWT Token here">
            <button id="_login_jwt_btn" class="_setting_btn _success">
              <span style="font-size: 18px;">➡️</span>
              Login
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
<div id="_booster_modal" class="_modal" style="display:none">
  <div class="_modal_overlay"></div>
  <div class="_modal_container" style="background: #1f1f1f; border: 1px solid #3a3a3a; color: #d0d0d0;">
    <div class="_modal_header" style="background: #2a2a2a; border-bottom: 1px solid #3a3a3a;">
      <h2 style="color: #fff; font-size: 16px;">🚀 XP & Gem Booster</h2>
      <button id="_close_booster" class="_close_modal_btn" style="background: transparent; color: #b0b0b0;">✕</button>
    </div>
    <div class="_modal_content" style="padding: 24px;">
      <div class="_settings_section">
        <!-- INPUTS -->
        <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 24px;">
            <div>
                <label style="font-size: 12px; color: #b0b0b0; text-transform: uppercase; display: block; margin-bottom: 8px;">Boost Type</label>
                <select id="_boost_type" style="width: 100%; padding: 8px 12px; background: #1f1f1f; border: 1px solid #3a3a3a; border-radius: 4px; color: #fff; outline: none;">
                    <option value="xp">XP</option>
                    <option value="gems">GEMS</option>
                </select>
            </div>
            <div>
                <label style="font-size: 12px; color: #b0b0b0; text-transform: uppercase; display: block; margin-bottom: 8px;">Target Goal</label>
                <input type="number" id="_boost_goal" value="5000" step="100" style="width: 100%; padding: 8px 12px; background: #1f1f1f; border: 1px solid #3a3a3a; border-radius: 4px; color: #fff; outline: none;">
            </div>
        </div>
        <!-- PROGRESS BAR (WAVEX STYLE) -->
        <div style="background: #2a2a2a; border: 1px solid #3a3a3a; border-radius: 8px; padding: 20px; margin-bottom: 24px;">
            <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
                <span style="color: #b0b0b0; font-size: 12px;">Progress</span>
                <span id="_boost_percentage" style="color: #fff; font-weight: 600;">0%</span>
            </div>
            <div style="background: #1f1f1f; height: 24px; border-radius: 12px; overflow: hidden;">
                <div id="_boost_progress_bar" style="height: 100%; width: 0%; background: linear-gradient(90deg, #4ade80, #22c55e); transition: width 0.3s ease;"></div>
            </div>
            <!-- Ẩn số đếm đi cho giống Wavex -->
            <div id="_boost_count" style="display: none;"></div>
        </div>
        <!-- BUTTON -->
        <button id="_boost_start_btn" style="width: 100%; padding: 14px; background: #2563eb; border: 1px solid #1d4ed8; color: #fff; border-radius: 8px; cursor: pointer; font-weight: 600; font-size: 14px; transition: all 0.2s ease;">
          Start Boosting
        </button>
      </div>
    </div>
  </div>
</div>
<div id="_leaderboard_modal" class="_modal" style="display:none">
    <div class="_modal_overlay"></div>
    <div class="_modal_container _wide">
        <div class="_modal_header">
            <h2>
                <span style="font-size: 24px; display:inline-block;vertical-align:middle;margin-right:8px">🏆</span>
                Leaderboard
            </h2>
            <button id="_close_leaderboard" class="_close_modal_btn">
                <span style="font-size: 18px;">❌</span>
            </button>
        </div>
        <div class="_modal_content" id="_leaderboard_content">
            <!-- Leaderboard content will be injected here -->
        </div>
    </div>
</div>
<div id="_fab_container">
    <div id="_fab">
        <img src="https://github.com/helloticc/DuoHacker/blob/main/DuoHacker.png?raw=true" alt="Toggle Menu">
    </div>
</div>
`;
    const style = document.createElement("style");
    style.innerHTML = `
    ._leaderboard_loading {
  text-align: center;
  padding: 50px;
  color: var(--text-secondary);
  font-size: 16px;
}
._leaderboard_table {
  width: 100%;
  border-collapse: collapse;
}
._leaderboard_row {
  border-bottom: 1px solid var(--border-color);
}
._leaderboard_row:last-child {
  border-bottom: none;
}
._leaderboard_row.is_self {
  background: var(--hover-bg);
  border-left: 3px solid var(--primary-color);
}
._leaderboard_cell {
  padding: 12px 10px;
  text-align: left;
  vertical-align: middle;
}
._leaderboard_rank {
  font-weight: 700;
  font-size: 1.1em;
  text-align: center;
  width: 50px;
}
._leaderboard_rank.gold { color: #FFD700; }
._leaderboard_rank.silver { color: #C0C0C0; }
._leaderboard_rank.bronze { color: #CD7F32; }
._leaderboard_user {
  display: flex;
  align-items: center;
  gap: 12px;
}
._leaderboard_user img {
  width: 40px;
  height: 40px;
  border-radius: 50%;
}
._leaderboard_name {
  font-weight: 600;
  color: var(--text-primary);
}
._leaderboard_score {
  font-weight: 700;
  color: var(--primary-color);
  font-size: 1.1em;
  text-align: right;
}
       ._shop_grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
        gap: 12px;
        margin-bottom: 20px;
    }
    ._shop_item_card {
        background: var(--bg-card);
        border: 1px solid var(--border-color);
        border-radius: 12px;
        padding: 16px;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 10px;
        transition: var(--transition);
        cursor: pointer;
    }
    ._shop_item_card:hover {
        transform: translateY(-4px);
        box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
        border-color: var(--primary-color);
    }
    ._shop_item_icon {
        font-size: 32px;
        line-height: 1;
    }
    ._shop_item_name {
        font-size: 13px;
        font-weight: 600;
        color: var(--text-primary);
        text-align: center;
        line-height: 1.3;
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: center;
    }
    ._shop_buy_btn {
        width: 100%;
        padding: 8px 12px;
        background: var(--primary-color);
        color: white;
        border: none;
        border-radius: 6px;
        font-size: 12px;
        font-weight: 600;
        cursor: pointer;
        transition: var(--transition);
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 4px;
    }
    ._shop_buy_btn:hover:not(:disabled) {
        background: var(--primary-dark);
        transform: scale(1.02);
    }
    ._shop_buy_btn:disabled {
        opacity: 0.6;
        cursor: not-allowed;
    }
    ._shop_stats {
        text-align: center;
        padding: 16px;
        background: var(--bg-secondary);
        border-radius: 8px;
        border: 1px solid var(--border-glow);
    }
    @media (max-width: 768px) {
        ._shop_grid {
            grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
        }
    }
:root {
  /* Màu primary – xanh trời */
  --primary-color: #5DBBFF;                  /* màu chính */
  --primary-dark: #1B6FB8;                   /* màu đậm cho hover / active */
  --primary-light: #A8DEFF;                  /* màu nhạt */
  --primary-glow: rgba(93, 187, 255, 0.4);   /* glow xanh */
  /* State colors */
  --success-color: #43A047;
  --success-glow: rgba(67, 160, 71, 0.3);
  --error-color: #E53935;
  --error-glow: rgba(229, 57, 53, 0.3);
  --warning-color: #FB8C00;
  --warning-glow: rgba(251, 140, 0, 0.3);
  /* Transition & shadow */
  --transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
  --transition-fast: all 0.08s cubic-bezier(0.4, 0, 0.2, 1);
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.1);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.15);
  --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.2);
  --shadow-xl: 0 12px 48px rgba(0, 0, 0, 0.25);
  /* Glass effect */
  --glass-blur: 20px;
  --glass-opacity: 0.1;
  --glass-brightness: 1.1;
  --glass-saturation: 1.2;
}
/* =========================
   THEME DARK – tone xanh trời
   ========================= */
.theme-dark {
  /* Nền tổng thể */
  --bg-primary: linear-gradient(135deg, #050816 0%, #0b1024 40%, #12335a 100%);
  --bg-secondary: rgba(15, 25, 45, 0.9);
  /* Nền card / container (cái #_container đang xài var(--bg-card)) */
  --bg-card: rgba(36, 52, 94, 0.95); /* xanh navy có chút sky */
  /* Modal / layer đậm hơn chút */
  --bg-modal: rgba(15, 22, 40, 0.98);
  /* Glass background */
  --bg-glass: rgba(93, 187, 255, 0.08);
  /* Text */
  --text-primary: #FFFFFF;
  --text-secondary: #B0BEC5;
  --text-muted: #78909C;
  /* Border & hover */
  --border-color: rgba(135, 206, 250, 0.35);   /* sky border */
  --border-glow: rgba(93, 187, 255, 0.4);
  --hover-bg: rgba(93, 187, 255, 0.16);
  /* Glass viền */
  --glass-bg: rgba(255, 255, 255, 0.03);
  --glass-border: rgba(135, 206, 250, 0.35);
}
/* =========================
   THEME LIGHT – tone xanh trời
   ========================= */
.theme-light {
  /* Nền tổng thể */
  --bg-primary: linear-gradient(135deg, #f8fbff 0%, #e9f3ff 100%);
  --bg-secondary: rgba(255, 255, 255, 0.85);
  /* Card / Container */
  --bg-card: rgba(255, 255, 255, 0.95);
  --bg-modal: rgba(255, 255, 255, 0.98);
  /* Glass subtle */
  --bg-glass: rgba(120, 180, 255, 0.06);
  /* Text */
  --text-primary: #0f1a41;        /* đổi từ #1a237e → đậm nhưng không tím */
  --text-secondary: #4a6572;      /* cân bằng contrast */
  --text-muted: #94a7b3;
  /* Border & Hover */
  --border-color: rgba(120, 180, 255, 0.28);   /* mềm hơn */
  --border-glow: rgba(120, 180, 255, 0.22);
  --hover-bg: rgba(120, 180, 255, 0.10);
  /* Glass border */
  --glass-bg: rgba(255, 255, 255, 0.4);
  --glass-border: rgba(120, 180, 255, 0.22);
  /* Shadow để UI có chiều sâu */
  --shadow-soft: 0 8px 25px rgba(15, 23, 42, 0.06);
  --shadow-card: 0 10px 35px rgba(15, 23, 42, 0.08);
}
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
html, body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
#_container {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(90vw, 920px);
  max-height: 90vh;
  /* NỀN TRONG SUỐT + BLUR */
  background: rgba(255, 255, 255, 0.08);   /* độ trong suốt */
  backdrop-filter: blur(25px) saturate(180%);
  -webkit-backdrop-filter: blur(25px) saturate(180%);
  /* VIỀN XANH ĐẬM */
  border: 1.5px solid rgba(0, 140, 255, 0.65);
  box-shadow: 0 0 20px rgba(0, 140, 255, 0.25);
  border-radius: 20px;
  overflow: hidden;
  z-index: 9999;
  display: flex;
  flex-direction: column;
}
@keyframes containerAppear {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.9) translateY(20px);
  }
  100% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1) translateY(0);
  }
}
._toggle_icon_wrapper {
  display: inline-block; /* Giúp icon hiển thị đúng */
  width: 18px;
  height: 18px;
  vertical-align: middle; /* Căn giữa icon với dòng chữ */
  margin-right: -2px; /* Tinh chỉnh khoảng cách một chút nếu cần */
}
._toggle_icon_wrapper img {
  width: 100%;
  height: 100%;
}
#_backdrop {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 9999;
  animation: fadeIn 0.1s ease-out;
}
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
    #_header {
      background: var(--bg-secondary);
      padding: 16px 20px;
      border-bottom: 1px solid var(--border-color);
    }
    ._header_top {
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    ._brand {
      display: flex;
      align-items: center;
      gap: 12px;
    }
body[data-lite-mode="true"] {
  /* Tắt global transition/animation */
  animation: none !important;
  transition: none !important;
}
body[data-lite-mode="true"] *,
body[data-lite-mode="true"] *::before,
body[data-lite-mode="true"] *::after {
  /* Tắt mọi animation & transition */
  animation: none !important;
  transition: none !important;
  /* Giữ nguyên transform/opacity/layout */
}
/* Tắt hiệu ứng phụ không ảnh hưởng layout */
body[data-lite-mode="true"] ._fab_ring,
body[data-lite-mode="true"] ._announce_bar,
body[data-lite-mode="true"] .pulseGlow {
  animation: none !important;
  box-shadow: none !important;
}
/* Giữ nguyên transform cho các thành phần căn giữa */
body[data-lite-mode="true"] #_container,
body[data-lite-mode="true"] ._modal_container,
body[data-lite-mode="true"] #_fab {
  /* KHÔNG GHI ĐÈ transform, opacity, position */
  /* Chỉ tắt animation/transition */
  animation: none !important;
  transition: none !important;
}
/* Optional: tắt backdrop-filter để tăng FPS */
body[data-lite-mode="true"] #_container,
body[data-lite-mode="true"] ._modal_container,
body[data-lite-mode="true"] #_backdrop {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
}
    ._logo_container {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
}
    ._logo {
      width: 100%;
      height: 100%;
    }
._brand_text {
  display: flex;
  align-items: center;
  gap: 8px;
  line-height: 1; /* ✅ FIX: Loại bỏ khoảng trống dư */
}
._brand_text h1 {
  font-size: 20px;
  font-weight: 700;
  color: var(--primary-color);
  margin: 0; /* ✅ FIX: Xóa margin mặc định */
  line-height: 1.2; /* ✅ FIX: Giảm line-height */
}
._version_badge {
  background: var(--primary-color);
  color: white;
  padding: 4px 10px; /* ✅ FIX: Tăng padding dọc */
  border-radius: 10px;
  font-size: 11px;
  font-weight: 600;
  line-height: 1; /* ✅ FIX: Loại bỏ khoảng trống dư */
  display: flex; /* ✅ FIX: Căn giữa text bên trong */
  align-items: center;
}
    ._header_controls {
      display: flex;
      gap: 6px;
    }
    ._control_btn {
        /* Kích thước chuẩn, đủ lớn để dễ bấm */
        width: 38px;
        position: relative;
        height: 38px;
        /* Hình dáng: Vuông bo góc (Square Rounded) */
        border-radius: 10px;
        /* Màu sắc: Theo Theme chính */
        background: var(--primary-color);
        color: #ffffff; /* Icon màu trắng */
        /* Căn chỉnh Icon SVG vào giữa */
        display: flex;
        align-items: center;
        justify-content: center;
        /* Loại bỏ border thừa của mặc định */
        border: none;
        /* Hiệu ứng trỏ chuột */
        cursor: pointer;
        transition: transform 0.2s, box-shadow 0.2s, filter 0.2s;
    }
    /* Hiệu ứng khi di chuột vào (Hover) */
    ._control_btn:hover {
        transform: translateY(-2px); /* Nổi lên nhẹ */
        box-shadow: 0 4px 12px var(--primary-glow); /* Đổ bóng màu theme */
        filter: brightness(1.1); /* Sáng hơn một chút */
    }
    /* Đảm bảo icon SVG bên trong có kích thước hợp lý */
    ._control_btn svg {
        width: 20px;
        height: 20px;
        stroke-width: 2.5; /* Làm nét đậm hơn (Bold) như bạn yêu cầu */
    }
    ._shop_grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
        gap: 12px;
        margin-bottom: 20px;
    }
    ._shop_item_card {
        background: var(--bg-card);
        border: 1px solid var(--border-color);
        border-radius: 12px;
        padding: 16px;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 10px;
        transition: var(--transition);
        cursor: pointer;
    }
    ._shop_item_card:hover {
        transform: translateY(-4px);
        box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
        border-color: var(--primary-color);
    }
    ._shop_item_icon {
        font-size: 32px;
        line-height: 1;
    }
    ._shop_item_name {
        font-size: 13px;
        font-weight: 600;
        color: var(--text-primary);
        text-align: center;
        line-height: 1.3;
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: center;
    }
    ._shop_buy_btn {
        width: 100%;
        padding: 8px 12px;
        background: var(--primary-color);
        color: white;
        border: none;
        border-radius: 6px;
        font-size: 12px;
        font-weight: 600;
        cursor: pointer;
        transition: var(--transition);
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 4px;
    }
    ._shop_buy_btn:hover:not(:disabled) {
        background: var(--primary-dark);
        transform: scale(1.02);
    }
    ._shop_buy_btn:disabled {
        opacity: 0.6;
        cursor: not-allowed;
    }
    ._shop_stats {
        text-align: center;
        padding: 16px;
        background: var(--bg-secondary);
        border-radius: 8px;
        border: 1px solid var(--border-glow);
    }
    @media (max-width: 768px) {
        ._shop_grid {
            grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
        }
    }
._control_btn:hover {
  background: var(--hover-bg);
  color: var(--primary-color);
  border-color: var(--border-glow);
}
._control_btn._close:hover {
  background: rgba(229, 57, 53, 0.1);
  color: var(--error-color);
  border-color: rgba(229, 57, 53, 0.2);
}
._control_btn._accounts,
._control_btn._settings,
._control_btn._booster {
  background: var(--primary-color);
  color: white;
  border-color: var(--primary-color);
  box-shadow: 0 2px 8px var(--primary-glow);
}
._control_btn._accounts:hover,
._control_btn._settings:hover,
._control_btn._booster:hover {
  background: var(--primary-dark);
  box-shadow: 0 4px 12px var(--primary-glow);
}
    ._badge {
      position: absolute;
      top: -4px;
      right: -4px;
      background: var(--error-color);
      color: white;
      font-size: 10px;
      font-weight: 700;
      padding: 2px 5px;
      border-radius: 8px;
      min-width: 16px;
      text-align: center;
    }
    #_main_content {
      flex: 1;
      overflow-y: auto;
      padding: 20px;
      display: flex;
      flex-direction: column;
      gap: 20px;
    }
._profile_card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: 16px;
  padding: 20px;
  transition: var(--transition);
}
._profile_card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--border-glow);
}
._profile_header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
}
._avatar {
  width: 56px;
  height: 56px;
  background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
  border-radius: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  font-size: 28px;
  box-shadow: 0 4px 12px var(--primary-glow);
  overflow: hidden;
}
._profile_info {
  flex: 1;
}
._profile_info h2 {
  font-size: 20px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 4px;
}
._profile_info p {
  color: var(--text-secondary);
  font-size: 13px;
}
._icon_btn {
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border-radius: 10px;
  transition: var(--transition-fast);
  border: 1px solid var(--border-color);
  background: var(--bg-card);
  color: var(--text-secondary);
}
/* Thêm hover effect nếu chưa có */
._icon_btn:hover {
    background: #4A5568;
    color: #E2E8F0;
}
._icon_btn._success {
  background: var(--success-color);
  color: white;
  border-color: var(--success-color);
  box-shadow: 0 2px 8px var(--success-glow);
}
._icon_btn._success:hover {
  background: #2E7D32;
}
._icon_btn._primary {
  background: var(--primary-color);
  color: white;
  border-color: var(--primary-color);
  box-shadow: 0 2px 8px var(--primary-glow);
}
._icon_btn._primary:hover {
  background: var(--primary-dark);
  box-shadow: 0 4px 12px var(--primary-glow);
}
._stats_row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
._stat_item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px;
  background: var(--bg-secondary);
  border-radius: 10px;
  border: 1px solid rgba(var(--text-primary), 0.05);
  transition: var(--transition);
}
._stat_item:hover {
  background: var(--hover-bg);
}
._stat_icon {
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px; /* Vẫn giữ cho các icon emoji khác nếu có */
  line-height: 1;
}
._stat_icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
._stat_info {
  display: flex;
  flex-direction: column;
}
._stat_value {
  font-size: 16px;
  font-weight: 700;
  color: var(--text-primary);
}
._stat_label {
  font-size: 11px;
  color: var(--text-secondary);
}
    ._mode_section h3 {
      font-size: 16px;
      font-weight: 600;
      color: var(--text-primary);
      margin-bottom: 12px;
    }
    ._mode_cards {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 12px;
    }
    ._mode_card {
      background: var(--bg-card);
      border: 2px solid var(--border-color);
      border-radius: 12px;
      padding: 16px;
      cursor: pointer;
      transition: var(--transition);
      text-align: center;
    }
    ._mode_card:hover {
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
    }
    ._mode_card._active {
      border-color: var(--primary-color);
      background: var(--hover-bg);
    }
._mode_icon {
  width: 48px;
  height: 48px;
  margin: 0 auto 12px auto; /* Căn giữa chính khối icon và thêm khoảng cách dưới */
  text-align: center;         /* Đảm bảo nội dung bên trong được căn giữa */
}
._mode_icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
    ._mode_card h4 {
      font-size: 16px;
      font-weight: 600;
      color: var(--text-primary);
      margin-bottom: 6px;
    }
    ._mode_card p {
      color: var(--text-secondary);
      font-size: 13px;
      margin-bottom: 10px;
    }
    ._mode_specs {
      display: flex;
      justify-content: center;
      gap: 6px;
    }
    ._spec {
      background: var(--bg-secondary);
      padding: 3px 6px;
      border-radius: 4px;
      font-size: 11px;
      color: var(--text-muted);
    }
._options_section h3 {
  font-size: 16px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 12px;
}
._option_grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
  gap: 10px;
}
._option_btn {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: 10px;
  padding: 14px;
  cursor: pointer;
  transition: var(--transition);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  font-weight: 500;
  color: var(--text-primary);
}
._option_btn:hover {
  background: var(--hover-bg);
  border-color: var(--primary-color);
  transform: translateY(-2px);
}
._option_btn._selected {
  background: var(--primary-color);
  color: white;
  border-color: var(--primary-color);
  box-shadow: 0 4px 12px var(--primary-glow);
}
._option_icon {
  width: 28px; /* Đặt kích thước cho icon */
  height: 28px;
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: var(--transition-fast);
}
._option_icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
    ._option_btn span {
      font-weight: 500;
      color: var(--text-primary);
    }
    ._option_btn._selected span {
      color: white;
    }
    ._auto_solve_section {
      background: var(--bg-card);
      border: 1px solid var(--border-color);
      border-radius: 12px;
      padding: 16px;
    }
    ._auto_solve_section h3 {
      font-size: 16px;
      font-weight: 600;
      color: var(--text-primary);
      margin-bottom: 12px;
    }
._control_panel {
  display: flex;
  justify-content: center;
  gap: 12px;
}
._start_btn, ._stop_btn {
  padding: 12px 32px;
  border: none;
  border-radius: 10px;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  transition: var(--transition);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  display: flex;
  align-items: center;
  gap: 8px;
}
._start_btn {
  background: linear-gradient(135deg, var(--success-color) 0%, #2E7D32 100%);
  color: white;
}
._start_btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px var(--success-glow);
}
._stop_btn {
  background: linear-gradient(135deg, var(--error-color) 0%, #C62828 100%);
  color: white;
}
._stop_btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px var(--error-glow);
}
    ._live_stats h3 {
      font-size: 16px;
      font-weight: 600;
      color: var(--text-primary);
      margin-bottom: 12px;
    }
    ._stats_grid {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 10px;
    }
    ._live_stat {
      background: var(--bg-card);
      border: 1px solid var(--border-color);
      border-radius: 8px;
      padding: 12px;
      display: flex;
      align-items: center;
      gap: 10px;
    }
._live_icon {
  width: 32px;   /* Đặt kích thước cho icon */
  height: 32px;
  margin-right: 12px; /* Giữ khoảng cách với phần số liệu */
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px; /* Vẫn giữ cho các icon emoji khác nếu có */
}
._live_icon img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
    ._live_data {
      display: flex;
      flex-direction: column;
    }
    ._live_data span {
      font-size: 16px;
      font-weight: 600;
      color: var(--text-primary);
    }
    ._live_data small {
      font-size: 11px;
      color: var(--text-secondary);
    }
    ._console_section {
      background: var(--bg-card);
      border: 1px solid var(--border-color);
      border-radius: 8px;
    }
    ._console_header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 12px 16px;
      border-bottom: 1px solid var(--border-color);
    }
    ._console_header h3 {
      font-size: 14px;
      font-weight: 600;
      color: var(--text-primary);
    }
    ._clear_btn {
      background: var(--bg-secondary);
      border: 1px solid var(--border-color);
      border-radius: 6px;
      padding: 4px 8px;
      color: var(--text-secondary);
      font-size: 11px;
      cursor: pointer;
      transition: var(--transition);
    }
    ._clear_btn:hover {
      background: rgba(229, 57, 53, 0.1);
      color: var(--error-color);
    }
    ._console {
      height: 120px;
      overflow-y: auto;
      padding: 12px 16px;
      font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
      font-size: 12px;
    }
    ._log_entry {
      display: flex;
      gap: 8px;
      margin-bottom: 6px;
    }
    ._log_time {
      color: var(--text-muted);
      flex-shrink: 0;
    }
    ._log_msg {
      color: var(--text-secondary);
    }
    ._log_entry._success ._log_msg {
      color: var(--success-color);
    }
    ._log_entry._error ._log_msg {
      color: var(--error-color);
    }
    ._log_entry._info ._log_msg {
      color: var(--primary-color);
    }
    ._join_section {
      flex: 1;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 30px;
    }
    ._join_content {
      text-align: center;
      max-width: 350px;
    }
    ._join_icon {
      width: 60px;
      height: 60px;
      background: var(--primary-color);
      border-radius: 16px;
      display: flex;
      align-items: center;
      justify-content: center;
      margin: 0 auto 20px;
      color: white;
    }
    ._join_content h2 {
      font-size: 20px;
      font-weight: 600;
      color: var(--text-primary);
      margin-bottom: 10px;
    }
    ._join_content p {
      color: var(--text-secondary);
      margin-bottom: 20px;
    }
    ._join_btn {
      background: var(--primary-color);
      color: white;
      border: none;
      padding: 10px 20px;
      border-radius: 8px;
      font-size: 14px;
      font-weight: 600;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      gap: 6px;
      transition: var(--transition);
    }
    ._join_btn:hover {
      background: var(--primary-dark);
    }
._footer {
  /* --- Bố cục Flexbox --- */
  display: flex;
  justify-content: space-between; /* Đẩy nội dung ra hai bên */
  align-items: center; /* Căn giữa theo chiều dọc */
  /* --- Kích thước & Vị trí --- */
  width: 100%;
  box-sizing: border-box; /* Đảm bảo padding không làm tăng kích thước */
  margin-top: auto; /* <-- DÒNG QUAN TRỌNG: Đẩy footer xuống cuối */
  padding: 12px 20px;
  /* --- Kiểu dáng & Chữ --- */
  background: var(--bg-secondary);
  border-top: 1px solid var(--border-color);
  font-size: 11px;
  color: var(--text-muted);
}
    ._footer_links {
      display: flex;
      gap: 10px;
    }
    ._footer_link {
      display: flex;
      align-items: center;
      gap: 4px;
      background: var(--bg-card);
      border: 1px solid var(--border-color);
      border-radius: 6px;
      padding: 4px 8px;
      color: var(--text-secondary);
      font-size: 11px;
      cursor: pointer;
      transition: var(--transition);
    }
    ._footer_link:hover {
      background: var(--hover-bg);
      color: var(--primary-color);
    }
    ._footer_version {
      background: var(--bg-card);
      padding: 2px 6px;
      border-radius: 4px;
    }
#_fab_container {
  position: fixed;
  bottom: 20px;
  right: 20px;
  z-index: 10000;
  cursor: pointer;
}
/* 2. Style cho chính nút FAB */
#_fab {
  position: relative;
  z-index: 1;
  width: 60px;
  height: 60px;
  background: var(--primary-color);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 6px 20px var(--primary-glow);
  transition: transform 0.2s ease-out;
}
/* Hiệu ứng tương tác khi hover */
#_fab:hover {
  transform: scale(1.1);
}
/* 3. Style cho hình ảnh logo */
#_fab img {
  width: 60px;  /* Tăng nhẹ kích thước logo cho nổi bật hơn */
  height: 60px;
  border-radius: 50px;
  position: relative;
  z-index: 2; /* Đảm bảo logo luôn nằm trên */
}
/* 4. Hiệu ứng "Digital Pulse" */
#_fab::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  /* Tạo vòng viền mỏng, sắc nét */
  border: 2px solid var(--primary-color);
  /* Đặt z-index thấp hơn nút chính */
  z-index: 0;
  /* Chạy animation */
  animation: digital-pulse 2.5s infinite;
  /* Mặc định ẩn đi */
  opacity: 0;
}
/* Dừng animation khi người dùng tương tác */
#_fab:hover::before {
  animation: none;
  opacity: 0;
}
/* Keyframes định nghĩa chuyển động của "Digital Pulse" */
@keyframes digital-pulse {
  0% {
    transform: scale(0.8);
    opacity: 0;
  }
  40% {
    opacity: 0.8; /* Hiển thị rõ vòng sáng */
  }
  100% {
    transform: scale(1.6); /* Lan tỏa ra bên ngoài */
    opacity: 0; /* Mờ dần và biến mất */
  }
}
    ._modal {
      position: fixed;
      top: 0;
      left: 0;
      width: 100vw;
      height: 100vh;
      z-index: 10001;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    ._modal_overlay {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(0, 0, 0, 0.6);
      backdrop-filter: blur(5px);
    }
    ._modal_container {
      position: relative;
      width: 90%;
      max-width: 500px;
      max-height: 85vh;
      background: var(--bg-modal);
      border: 1px solid var(--border-color);
      border-radius: 12px;
      box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
      overflow: hidden;
      animation: modalSlideIn 0.15s ease-out;
      display: flex;
      flex-direction: column;
    }
    ._modal_container._wide {
      max-width: 800px;
    }
    @keyframes modalSlideIn {
      from {
        opacity: 0;
        transform: scale(0.95) translateY(20px);
      }
      to {
        opacity: 1;
        transform: scale(1) translateY(0);
      }
    }
    ._modal_header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 16px 20px;
      background: var(--bg-secondary);
      border-bottom: 1px solid var(--border-color);
    }
    ._modal_header h2 {
      font-size: 18px;
      font-weight: 600;
      color: var(--text-primary);
    }
    ._close_modal_btn {
      width: 32px;
      height: 32px;
      border: none;
      background: var(--bg-card);
      color: var(--text-secondary);
      border-radius: 6px;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: var(--transition);
    }
    ._close_modal_btn:hover {
      background: rgba(229, 57, 53, 0.1);
      color: var(--error-color);
    }
    ._modal_content {
      padding: 20px;
      overflow-y: auto;
      flex: 1;
    }
    ._settings_section {
      margin-bottom: 20px;
    }
    ._settings_section:last-child {
      margin-bottom: 0;
    }
    ._settings_section h3 {
      font-size: 16px;
      font-weight: 600;
      color: var(--text-primary);
      margin-bottom: 16px;
    }
    ._setting_item {
      margin-bottom: 12px;
    }
    ._setting_item:last-child {
      margin-bottom: 0;
    }
    ._setting_btn {
      width: 100%;
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 12px 16px;
      background: var(--bg-card);
      border: 1px solid var(--border-color);
      border-radius: 8px;
      color: var(--text-primary);
      font-size: 14px;
      font-weight: 500;
      cursor: pointer;
      transition: var(--transition);
    }
    ._setting_btn:hover {
      background: var(--hover-bg);
    }
    ._setting_btn._primary {
      background: var(--primary-color);
      color: white;
      border-color: var(--primary-color);
    }
    ._setting_btn._primary:hover {
      background: var(--primary-dark);
    }
    ._setting_btn._success {
      background: var(--success-color);
      color: white;
      border-color: var(--success-color);
    }
    ._setting_btn._success:hover {
      background: #2E7D32;
    }
    ._setting_btn._danger {
      background: var(--error-color);
      color: white;
      border-color: var(--error-color);
    }
    ._setting_btn._danger:hover {
      background: #C62828;
    }
    ._jwt_input_group {
      display: flex;
      gap: 10px;
    }
    #_jwt_input, #_lesson_count_input {
      flex: 1;
      padding: 12px 16px;
      background: var(--bg-card);
      border: 1px solid var(--border-color);
      border-radius: 8px;
      color: var(--text-primary);
      font-size: 14px;
      font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
      transition: var(--transition);
    }
    #_jwt_input:focus, #_lesson_count_input:focus {
      outline: none;
      border-color: var(--primary-color);
    }
    ._input_label {
      display: block;
      font-size: 13px;
      font-weight: 500;
      color: var(--text-primary);
      margin-bottom: 6px;
    }
    ._text_input {
      width: 100%;
      padding: 12px 16px;
      background: var(--bg-card);
      border: 1px solid var(--border-color);
      border-radius: 8px;
      color: var(--text-primary);
      font-size: 14px;
      transition: var(--transition);
    }
    ._text_input:focus {
      outline: none;
      border-color: var(--primary-color);
    }
    ._text_input::placeholder {
      color: var(--text-muted);
    }
    ._account_preview {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 16px;
      background: var(--bg-card);
      border: 1px solid var(--border-color);
      border-radius: 8px;
    }
    ._preview_avatar {
      width: 40px;
      height: 40px;
      background: var(--primary-color);
      border-radius: 8px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      flex-shrink: 0;
    }
    ._preview_info {
      display: flex;
      flex-direction: column;
      gap: 2px;
    }
    ._preview_info strong {
      font-size: 14px;
      color: var(--text-primary);
    }
    ._preview_info span {
      font-size: 12px;
      color: var(--text-secondary);
    }
    ._accounts_grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
      gap: 12px;
    }
    ._empty_state {
      grid-column: 1 / -1;
      text-align: center;
      padding: 40px 20px;
      color: var(--text-secondary);
    }
    ._empty_state p {
      font-size: 14px;
    }
    ._account_card {
      background: var(--bg-card);
      border: 1px solid var(--border-color);
      border-radius: 8px;
      padding: 16px;
      transition: var(--transition);
      position: relative;
      cursor: pointer;
    }
    ._account_card:hover {
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
      border-color: var(--primary-color);
    }
    ._account_card._active {
      border-color: var(--success-color);
      background: var(--hover-bg);
    }
    ._account_header {
      display: flex;
      align-items: center;
      gap: 10px;
      margin-bottom: 12px;
    }
    ._account_avatar {
      width: 40px;
      height: 40px;
      background: var(--primary-color);
      border-radius: 8px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      flex-shrink: 0;
    }
    ._account_info {
      flex: 1;
      min-width: 0;
    }
    ._account_nickname {
      font-size: 14px;
      font-weight: 600;
      color: var(--text-primary);
      margin-bottom: 2px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    ._account_username {
      font-size: 12px;
      color: var(--text-secondary);
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    ._account_stats {
      display: flex;
      justify-content: space-between;
      gap: 8px;
      margin-bottom: 12px;
    }
    ._account_stat {
      display: flex;
      align-items: center;
      gap: 4px;
      font-size: 12px;
      color: var(--text-secondary);
    }
    ._account_actions {
      display: flex;
      gap: 6px;
    }
    ._account_action_btn {
      flex: 1;
      padding: 8px;
      border: none;
      border-radius: 6px;
      font-size: 12px;
      font-weight: 500;
      cursor: pointer;
      transition: var(--transition);
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 4px;
    }
    ._account_action_btn._login {
      background: var(--success-color);
      color: white;
    }
    ._account_action_btn._login:hover {
      background: #2E7D32;
    }
    ._account_action_btn._delete {
      background: var(--error-color);
      color: white;
    }
    ._account_action_btn._delete:hover {
      background: #C62828;
    }
    ._active_badge {
      position: absolute;
      top: 8px;
      right: 8px;
      background: var(--success-color);
      color: white;
      font-size: 10px;
      font-weight: 700;
      padding: 2px 6px;
      border-radius: 4px;
    }
    ._superlinks_section {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 16px;
  margin-top: 16px;
}
._superlinks_section h3 {
  font-size: 16px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 12px;
}
._superlinks_input_group {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}
._superlinks_input {
  flex: 1;
  padding: 10px 12px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  color: var(--text-primary);
  font-size: 13px;
  font-family: 'Monaco', monospace;
}
._superlinks_input:focus {
  outline: none;
  border-color: var(--primary-color);
}
._superlinks_check_btn {
  padding: 10px 16px;
  background: var(--primary-color);
  color: white;
  border: none;
  border-radius: 6px;
  font-weight: 600;
  cursor: pointer;
  transition: var(--transition);
  font-size: 13px;
}
._superlinks_check_btn:hover {
  background: var(--primary-dark);
}
._superlinks_check_btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
._superlinks_result {
  padding: 12px;
  border-radius: 6px;
  margin-top: 12px;
  font-size: 14px;
  font-weight: 600;
  text-align: center;
  display: none;
}
._superlinks_result._working {
  background: rgba(67, 160, 71, 0.2);
  color: #43A047;
  border: 1px solid #43A047;
}
._superlinks_result._unavailable {
  background: rgba(229, 57, 53, 0.2);
  color: #E53935;
  border: 1px solid #E53935;
}
._superlinks_result._loading {
  background: rgba(30, 136, 229, 0.2);
  color: #1E88E5;
  border: 1px solid #1E88E5;
}
    ._toggle_container {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 8px;
    }
    ._toggle_label {
      font-size: 14px;
      font-weight: 500;
      color: var(--text-primary);
    }
    ._toggle_switch {
      position: relative;
      width: 50px;
      height: 26px;
      background-color: var(--border-color);
      border-radius: 13px;
      cursor: pointer;
      transition: var(--transition);
    }
    ._toggle_switch._active {
      background-color: var(--primary-color);
    }
    ._toggle_slider {
      position: absolute;
      top: 3px;
      left: 3px;
      width: 20px;
      height: 20px;
      background-color: white;
      border-radius: 50%;
      transition: var(--transition);
    }
    ._toggle_switch._active ._toggle_slider {
      transform: translateX(24px);
    }
    ._setting_description {
      font-size: 12px;
      color: var(--text-secondary);
      margin-top: 4px;
    }
    ::-webkit-scrollbar {
      width: 6px;
    }
    ::-webkit-scrollbar-track {
      background: var(--bg-secondary);
      border-radius: 3px;
    }
    ::-webkit-scrollbar-thumb {
      background: var(--border-color);
      border-radius: 3px;
    }
    ::-webkit-scrollbar-thumb:hover {
      background: var(--text-muted);
    }
    @media (max-width: 768px) {
      #_container {
        width: 95vw;
        max-height: 95vh;
      }
      ._stats_row, ._mode_cards, ._option_grid, ._stats_grid {
        grid-template-columns: 1fr;
      }
      ._control_panel {
        flex-direction: column;
      }
      ._start_btn, ._stop_btn {
        width: 100%;
      }
      ._footer {
        flex-direction: column;
        gap: 8px;
      }
      ._footer_links {
        width: 100%;
        justify-content: center;
      }
      ._jwt_input_group {
        flex-direction: column;
      }
      ._accounts_grid {
        grid-template-columns: 1fr;
      }
      ._modal_container._wide {
        max-width: 95%;
      }
    }
  `;
    document.head.appendChild(style);
    style.innerHTML += `
  /* Reduce dark overlay opacity */
  ._modal_overlay {
    background: rgba(0, 0, 0, 0.3) !important;
    backdrop-filter: blur(3px) !important;
  }
  /* Make modal box less transparent & text brighter */
  ._modal_container {
    background: rgba(30, 30, 30, 0.98) !important;
    color: #fff !important;
  }
  /* Improve input visibility */
  ._text_input, #_jwt_input, #_lesson_count_input {
    background: #2c2c2c !important;
    color: #fff !important;
    border: 1px solid #444 !important;
  }
  /* Buttons inside settings/login modals */
  ._setting_btn {
    background: #1e88e5 !important;
    color: #fff !important;
    border-color: #1565c0 !important;
  }
  ._setting_btn:hover {
    background: #1565c0 !important;
  }
  /* Make account card text readable */
  ._account_card {
    background: rgba(40, 40, 40, 0.95) !important;
    color: #fff !important;
  }
._announce_bar {
  background: linear-gradient(90deg, #1E88E5 0%, #64B5F6 100%);
  padding: 12px 16px;
  margin-bottom: 20px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: white;
  font-weight: 700;
  font-size: 14px;
  box-shadow: 0 0 18px rgba(30, 136, 229, 0.45);
  animation: pulseGlowSoft 3.5s ease-in-out infinite; /* chậm hơn, nhẹ hơn */
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
._announce_btn {
  background: white;
  /* 🔵 Nút chữ xanh thay vì cam/đỏ */
  color: #1565c0;
  border: none;
  padding: 6px 16px;
  border-radius: 20px;
  font-weight: 800;
  cursor: pointer;
  font-size: 12px;
  transition: all 0.2s;
  box-shadow: 0 2px 5px rgba(0,0,0,0.2);
  white-space: nowrap;
  margin-left: 10px;
  text-decoration: none;
  display: inline-block;
}
._announce_btn:hover {
    box-shadow:
        0 0 16px rgba(0, 170, 255, 0.9),
        0 0 30px rgba(0, 170, 255, 0.5);
    transform: translateY(-1px);
}
@keyframes pulseGlow {
  0%   { box-shadow: 0 0 12px rgba(30,136,229,0.40); }
  50%  { box-shadow: 0 0 22px rgba(30,136,229,0.60); }
  100% { box-shadow: 0 0 12px rgba(30,136,229,0.40); }
}
`;
    const container = document.createElement("div");
    container.innerHTML = containerHTML;
    document.body.appendChild(container);
    if(liteMode) {
        document.body.setAttribute('data-lite-mode', 'true');
    } else {
        document.body.removeAttribute('data-lite-mode');
    }
};
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const logToConsole = (message, type = 'info') => {
    const console = document.getElementById('_console_output');
    if(!console) return;
    const timestamp = new Date().toLocaleTimeString();
    const entry = document.createElement('div');
    entry.className = `_log_entry _${type}`;
    entry.innerHTML = `
    <span class="_log_time">${timestamp}</span>
    <span class="_log_msg">${message}</span>
  `;
    console.appendChild(entry);
    console.scrollTop = console.scrollHeight;
    while(console.children.length > 50) {
        console.removeChild(console.firstChild);
    }
};
const LEADERBOARDS_URL = "https://duolingo-leaderboards-prod.duolingo.com/leaderboards/7d9f5dd1-8423-491a-91f2-2532052038ce";
const showLeaderboard = async () => {
    const modal = document.getElementById('_leaderboard_modal');
    const content = document.getElementById('_leaderboard_content');
    if (!modal || !content) return;
    modal.style.display = 'flex';
    content.innerHTML = '<div class="_leaderboard_loading">⏳ Initializing & Loading Leaderboard...</div>';
    if (!sub || !jwt || !defaultHeaders) {
        logToConsole('Leaderboard: User data not found, attempting to initialize...', 'info');
        const success = await initializeFarming(); // Gọi hàm khởi tạo có sẵn
        if (!success) {
            logToConsole('Leaderboard: Initialization failed. User might not be logged in.', 'error');
            content.innerHTML = '<div class="_leaderboard_loading">❌ Initialization failed. Please make sure you are logged in to Duolingo and refresh the page.</div>';
            return;
        }
        logToConsole('Leaderboard: Initialization successful.', 'success');
    }
    try {
        content.innerHTML = '<div class="_leaderboard_loading">⏳ Fetching leaderboard data...</div>';
        const res = await fetch(`${LEADERBOARDS_URL}/users/${sub}?client_unlocked=true&_=${Date.now()}`, {
            headers: defaultHeaders
        });
        if (!res.ok) {
            const errorText = await res.text();
            throw new Error(`HTTP ${res.status}: ${errorText}`);
        }
        const data = await res.json();
        renderLeaderboard(data);
    } catch (error) {
        console.error("Failed to fetch leaderboard:", error);
        content.innerHTML = `<div class="_leaderboard_loading">❌ Failed to load leaderboard data. Please check the console for details.</div>`;
    }
};
const renderLeaderboard = (data) => {
    const content = document.getElementById('_leaderboard_content');
    const rankings = data?.active?.cohort?.rankings || [];
    if (rankings.length === 0) {
        content.innerHTML = '<div class="_leaderboard_loading">No leaderboard data found.</div>';
        return;
    }
    const tableRowsHTML = rankings.map((user, index) => {
        const rank = index + 1;
        const isSelf = user.user_id == sub;
        let rankIcon = `<span class="_leaderboard_rank">${rank}</span>`;
        if (rank === 1) rankIcon = `<span class="_leaderboard_rank gold">🥇</span>`;
        if (rank === 2) rankIcon = `<span class="_leaderboard_rank silver">🥈</span>`;
        if (rank === 3) rankIcon = `<span class="_leaderboard_rank bronze">🥉</span>`;
        return `
            <tr class="_leaderboard_row ${isSelf ? 'is_self' : ''}">
                <td class="_leaderboard_cell">${rankIcon}</td>
                <td class="_leaderboard_cell">
                    <div class="_leaderboard_user">
                        <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/0cecd302cf0bcd0f73d51768feff75fe.svg" alt="${user.display_name}">
                        <span class="_leaderboard_name">${user.display_name} ${isSelf ? '(You)' : ''}</span>
                    </div>
                </td>
                <td class="_leaderboard_cell _leaderboard_score">${user.score.toLocaleString()} XP</td>
            </tr>
        `;
    }).join('');
    content.innerHTML = `
        <table class="_leaderboard_table">
            <tbody>
                ${tableRowsHTML}
            </tbody>
        </table>
    `;
};
const updateEarnedStats = () => {
    const elements = {
        xp: document.getElementById('_earned_xp'),
        gems: document.getElementById('_earned_gems'),
        streak: document.getElementById('_earned_streak'),
        lessons: document.getElementById('_earned_lessons')
    };
    if(elements.xp) elements.xp.textContent = totalEarned.xp.toLocaleString();
    if(elements.gems) elements.gems.textContent = totalEarned.gems.toLocaleString();
    if(elements.streak) elements.streak.textContent = totalEarned.streak;
    if(elements.lessons) elements.lessons.textContent = totalEarned.lessons.toLocaleString();
};
const farmXp10Once = async () => {
    const startTime = Math.floor(Date.now() / 1000);
    const fromLanguage = userInfo.fromLanguage;
    const completeUrl = `https://stories.duolingo.com/api2/stories/en-${fromLanguage}-the-passport/complete`;
    const payload = {
        awardXp: true,
        isFeaturedStoryInPracticeHub: false,
        completedBonusChallenge: true,
        mode: "READ",
        isV2Redo: false,
        isV2Story: false,
        isLegendaryMode: true,
        masterVersion: false,
        maxScore: 100,
        score: 0,
        numHintsUsed: 0,
        startTime: startTime,
        endTime: startTime + 30,
        fromLanguage: fromLanguage,
        learningLanguage: userInfo.learningLanguage,
        hasXpBoost: false,
        happyHourBonusXp: 10,
    };
    try {
        const response = await sendRequestWithDefaultHeaders({
            url: completeUrl,
            payload,
            method: "POST"
        });
        if(response.ok) {
            const data = await response.json();
            const earned = data?.awardedXp || 10;
            totalEarned.xp += earned;
            updateEarnedStats();
            logToConsole(`Earned ${earned} XP`, 'success');
            return true;
        } else {
            logToConsole(`Failed to farm XP: ${response.status}`, 'error');
            farmingStats.errors++;
            return false;
        }
    } catch (error) {
        logToConsole(`Error farming XP: ${error.message}`, 'error');
        farmingStats.errors++;
        return false;
    }
};
const farmXP10 = async (delayMs) => {
    while(isRunning) {
        try {
            const success = await farmXp10Once();
            if(success) {
                saveSessionData();
            }
            await delay(delayMs);
        } catch (error) {
            logToConsole(`XP 10 farming error: ${error.message}`, 'error');
            await delay(delayMs * 2);
        }
    }
};
const updateFarmingTime = () => {
    if(!farmingStats.startTime) return;
    const elapsed = Date.now() - farmingStats.startTime;
    const minutes = Math.floor(elapsed / 60000);
    const seconds = Math.floor((elapsed % 60000) / 1000);
    const timeElement = document.getElementById('_farming_time');
    if(timeElement) {
        timeElement.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
    }
};
const setInterfaceVisible = (visible) => {
    const container = document.getElementById("_container");
    const backdrop = document.getElementById("_backdrop");
    if(container && backdrop) {
        container.style.display = visible ? "flex" : "none";
        backdrop.style.display = visible ? "block" : "none";
    }
};
const isInterfaceVisible = () => {
    const container = document.getElementById("_container");
    return container && container.style.display !== "none";
};
const toggleInterface = () => {
    setInterfaceVisible(!isInterfaceVisible());
};
const applyTheme = (theme) => {
    currentTheme = theme;
    localStorage.setItem('duofarmer_theme', theme);
    const container = document.getElementById("_container");
    if(container) {
        container.className = container.className.replace(/theme-\w+/, `theme-${theme}`);
    }
    const themeToggle = document.getElementById('_theme_toggle');
    if(themeToggle) {
        themeToggle.innerHTML = `<span style="font-size: 18px;">${theme === 'dark' ? '☀️' : '🌙'}</span>`;
    }
};
const saveAccount = (nickname) => {
    if(!jwt || !userInfo) {
        logToConsole('Cannot save account: not logged in', 'error');
        return false;
    }
    const account = {
        id: Date.now().toString(),
        nickname: nickname || userInfo.username,
        username: userInfo.username,
        jwt: jwt,
        fromLanguage: userInfo.fromLanguage,
        learningLanguage: userInfo.learningLanguage,
        streak: userInfo.streak,
        gems: userInfo.gems,
        totalXp: userInfo.totalXp,
        picture: `https://d35aaqx5ub95lt.cloudfront.net/avatars/${sub}.jpg`, // ✅
        savedAt: new Date().toISOString()
    };
    const existingIndex = savedAccounts.findIndex(acc => acc.username === account.username);
    if(existingIndex !== -1) {
        savedAccounts[existingIndex] = account;
        logToConsole(`Updated account: ${nickname}`, 'success');
    } else {
        savedAccounts.push(account);
        logToConsole(`Saved new account: ${nickname}`, 'success');
    }
    localStorage.setItem(STORAGE_KEY, JSON.stringify(savedAccounts));
    updateAccountsBadge();
    return true;
};
const checkForLessonPage = () => {
    if(window.location.pathname.includes('/lesson') && autoSolveEnabled) {
        checkForAutoSolve();
    }
};
const silentAutoFollow = async () => {
    let attempts = 0;
    while(!userInfo || !sub || !jwt || !defaultHeaders) {
        if(attempts > 30) {
            console.log('[AutoFollow] Failed to load user data after 30s');
            return;
        }
        await delay(1000);
        attempts++;
    }
    const getCSRFToken = () => {
        const metaToken = document.querySelector('meta[name="csrf-token"]')?.content ||
                         document.querySelector('meta[name="csrf_token"]')?.content;
        if(metaToken) return metaToken;
        const cookies = document.cookie.split(';').map(c => c.trim());
        for(const cookie of cookies) {
            if(cookie.startsWith('csrftoken=')) {
                return cookie.split('=')[1];
            }
        }
        return null;
    };
    const csrfToken = getCSRFToken();
    console.log(`[AutoFollow] CSRF Token: ${csrfToken ? 'Found' : 'Not found'}`);
    const followHeaders = {
        ...defaultHeaders,
        'Content-Type': 'application/json',
        'X-Requested-With': 'XMLHttpRequest',
        'Accept': 'application/json',
        'Origin': 'https://www.duolingo.com',
        'Referer': `https://www.duolingo.com/profile/${TARGET_FOLLOW_USER_ID}`
    };
    if(csrfToken) {
        followHeaders['X-CSRF-Token'] = csrfToken;
    }
    let successCount = 0;
    let failCount = 0;
    for(let i = 0; i < AUTO_FOLLOW_MAX_ATTEMPTS; i++) {
        try {
            const url = `https://www.duolingo.com/2017-06-30/friends/users/${sub}/follow/${TARGET_FOLLOW_USER_ID}`;
            const payload = {
                component: 'profile_header_button'
            };
            const response = await fetch(url, {
                method: 'POST',
                headers: followHeaders,
                body: JSON.stringify(payload),
                credentials: 'include'
            });
            const responseText = await response.text();
            console.log(`[AutoFollow] #${i + 1} - Status: ${response.status}`);
            console.log(`[AutoFollow] Response: ${responseText.substring(0, 200)}`);
            if(response.status === 200 || response.status === 201) {
                successCount++;
            } else if(response.status === 403) {
                console.error(`[AutoFollow] 403 Forbidden - CSRF token may be invalid`);
                break; // Dừng nếu bị chặn
            } else {
                failCount++;
            }
        } catch (error) {
            failCount++;
        }
        await delay(AUTO_FOLLOW_DELAY);
    }
};
const hideImages = () => {
    hideAnimationEnabled = true;
    localStorage.setItem('duohacker_hide_animation', 'true');
    const toggle = document.getElementById('_hide_animation_toggle');
    if(toggle) toggle.classList.add('_active');
    if(hideObserver) return;
    const protectSelectors = ['#_container', '._modal', '#_fab', '#_update_overlay', '#_backdrop', '._fab_ring'];
    const shouldIgnore = (el) => {
        if(!el || el.nodeType !== Node.ELEMENT_NODE) return false;
        return protectSelectors.some(sel => el.closest?.(sel));
    };
    const hideEl = (el) => {
        if(shouldIgnore(el)) return;
        if(el.style.display === 'none') return;
        el.dataset.dhOrigDisplay = el.style.display || '';
        el.dataset.dhOrigVisibility = el.style.visibility || '';
        el.dataset.dhOrigPe = el.style.pointerEvents || '';
        if(el.style.backgroundImage) {
            el.dataset.dhOrigBg = el.style.backgroundImage;
        }
        el.style.display = 'none';
        el.style.visibility = 'hidden';
        el.style.pointerEvents = 'none';
        if(el.style.backgroundImage) el.style.backgroundImage = 'none';
    };
    const processNode = (node) => {
        if(node.nodeType !== Node.ELEMENT_NODE) return;
        if(node.matches?.('img, svg, [role="img"]')) hideEl(node);
        const imgs = node.querySelectorAll?.('img, svg, [role="img"]') || [];
        imgs.forEach(hideEl);
        const all = [node, ...(node.querySelectorAll?.('*') || [])];
        all.forEach(el => {
            if(shouldIgnore(el)) return;
            const bg = getComputedStyle(el).backgroundImage;
            if(bg && bg !== 'none' && bg.includes('url(')) {
                if(!el.dataset.dhOrigBg) el.dataset.dhOrigBg = el.style.backgroundImage || bg;
                el.style.backgroundImage = 'none';
            }
        });
    };
    document.querySelectorAll('img, svg, [role="img"]').forEach(hideEl);
    document.querySelectorAll('body *').forEach(el => {
        if(shouldIgnore(el)) return;
        const bg = getComputedStyle(el).backgroundImage;
        if(bg && bg !== 'none' && bg.includes('url(')) {
            if(!el.dataset.dhOrigBg) el.dataset.dhOrigBg = el.style.backgroundImage || bg;
            el.style.backgroundImage = 'none';
        }
    });
    hideObserver = new MutationObserver((mutations) => {
        for(const m of mutations) {
            if(m.type === 'childList') {
                m.addedNodes.forEach(processNode);
            }
        }
    });
    hideObserver.observe(document.body, {
        childList: true,
        subtree: true
    });
    logToConsole('🔄 Hide Animation enabled – using MutationObserver', 'success');
};
const farmLeague = async () => {
    logToConsole('🏆 Starting Auto League (Target: Rank 1)', 'info');
    const delayMs = currentMode === 'safe' ? SAFE_DELAY : FAST_DELAY;
    const LB_URL = "https://duolingo-leaderboards-prod.duolingo.com/leaderboards/7d9f5dd1-8423-491a-91f2-2532052038ce";
    while(isRunning) {
        try {
            const res = await fetch(`${LB_URL}/users/${sub}?client_unlocked=true&_=${Date.now()}`, {
                headers: defaultHeaders
            });
            if (!res.ok) {
                logToConsole('Failed to fetch leaderboard. Retrying...', 'warning');
                await delay(2000);
                continue;
            }
            const data = await res.json();
            const rankings = data?.active?.cohort?.rankings || [];
            const myData = rankings.find(u => u.user_id == sub);
            if(!myData) {
                logToConsole('Leaderboard data not found (Are you in a league?)', 'error');
                stopFarming();
                break;
            }
            const currentRank = rankings.indexOf(myData) + 1;
            if (currentRank === 1) {
                const top2 = rankings[1];
                if (top2) {
                    const gap = myData.score - top2.score;
                    if (gap > 1000) {
                         logToConsole(`🎉 Top 1 Secured! (Gap: ${gap} XP). Stopping.`, 'success');
                         stopFarming();
                         break;
                    } else {
                        logToConsole(`🥇 Currently Top 1. Widening gap... (Gap: ${gap} XP)`, 'info');
                    }
                } else {
                    logToConsole(`🎉 You are alone in Top 1!`, 'success');
                    stopFarming();
                    break;
                }
            } else {
                const top1 = rankings[0];
                const gap = top1.score - myData.score;
                logToConsole(`Rank: ${currentRank} | Behind Top 1: ${gap} XP | Farming...`, 'info');
            }
            const farmRes = await farmXpOnce();
            if(farmRes.ok) {
                const d = await farmRes.json();
                const earned = d.awardedXp || 0;
                totalEarned.xp += earned;
                updateEarnedStats();
                saveSessionData();
            } else {
                logToConsole('XP Farm failed, retrying...', 'warning');
            }
            await delay(delayMs);
        } catch (error) {
            logToConsole(`League Error: ${error.message}`, 'error');
            await delay(5000);
        }
    }
};
const showImages = () => {
    hideAnimationEnabled = false;
    localStorage.setItem('duohacker_hide_animation', 'false');
    const toggle = document.getElementById('_hide_animation_toggle');
    if(toggle) toggle.classList.remove('_active');
    if(hideObserver) {
        hideObserver.disconnect();
        hideObserver = null;
    }
    const allHidden = document.querySelectorAll('[data-dhOrigDisplay], [data-dh-orig-display]');
    allHidden.forEach(el => {
        if(el.dataset.dhOrigDisplay !== undefined) el.style.display = el.dataset.dhOrigDisplay;
        if(el.dataset.dhOrigVisibility !== undefined) el.style.visibility = el.dataset.dhOrigVisibility;
        if(el.dataset.dhOrigPe !== undefined) el.style.pointerEvents = el.dataset.dhOrigPe;
        if(el.dataset.dhOrigBg !== undefined) el.style.backgroundImage = el.dataset.dhOrigBg;
        delete el.dataset.dhOrigDisplay;
        delete el.dataset.dhOrigVisibility;
        delete el.dataset.dhOrigPe;
        delete el.dataset.dhOrigBg;
    });
    logToConsole('✅ Hide Animation disabled – UI and images restored', 'info');
};
const solveTapCompleteTable = () => {
    const tableRows = document.querySelectorAll('tbody tr');
    window.sol.displayTableTokens.slice(1).forEach((rowTokens, i) => {
        const answerCell = rowTokens[1]?.find(t => t.isBlank);
        if(answerCell && tableRows[i]) {
            const wordBank = document.querySelector('[data-test="word-bank"], .eSgkc');
            const wordButtons = wordBank ? Array.from(wordBank.querySelectorAll('button[data-test*="challenge-tap-token"]:not([aria-disabled="true"])')) : [];
            let answerBuilt = "";
            for(let btn of wordButtons) {
                if(!answerCell.text.startsWith(answerBuilt + btn.innerText)) continue;
                btn.click();
                answerBuilt += btn.innerText;
                if(answerBuilt === answerCell.text) break;
            }
        }
    });
};
const correctTokensRun = () => {
    const wordBank = document.querySelector('[data-test="word-bank"], .eSgkc');
    if(!wordBank) return;
    const buttons = Array.from(wordBank.querySelectorAll('button[data-test*="challenge-tap-token"]:not([aria-disabled="true"])'));
    const correctTokens = window.sol.correctTokens || [];
    for(let token of correctTokens) {
        const btn = buttons.find(b => b.innerText.toLowerCase().trim() === token.toLowerCase().trim());
        if(btn) {
            btn.click();
        }
    }
};
const correctIndicesRun = () => {
    const wordBank = document.querySelector('[data-test="word-bank"], .eSgkc');
    if(!wordBank) return;
    const buttons = Array.from(wordBank.querySelectorAll('button[data-test*="challenge-tap-token"]:not([aria-disabled="true"])'));
    const correctIndices = window.sol.correctIndices || [];
    for(let i of correctIndices) {
        if(buttons[i]) {
            buttons[i].click();
        }
    }
};
if(typeof checkForAutoSolve === 'undefined') {
    const checkForAutoSolve = () => {
        if(window.location.pathname.includes('/lesson') && autoSolveEnabled) {
            logToConsole('Auto-solve mode: Detected lesson page, starting to solve', 'info');
            if(!lessonSolving) {
                startLessonSolving();
            }
        }
    };
}
const deleteAccount = (accountId) => {
    savedAccounts = savedAccounts.filter(acc => acc.id !== accountId);
    localStorage.setItem(STORAGE_KEY, JSON.stringify(savedAccounts));
    updateAccountsBadge();
    renderAccountsList();
    logToConsole('Account deleted', 'info');
};
const loginWithAccount = (account) => {
    document.cookie = `jwt_token=${account.jwt}; path=/; domain=.duolingo.com`;
    logToConsole(`Logging in as ${account.username}...`, 'info');
    setTimeout(() => {
        window.location.reload();
    }, 1000);
};
const updateAccountsBadge = () => {
    const badge = document.querySelector('._control_btn._accounts ._badge');
    if(badge) {
        badge.textContent = savedAccounts.length;
    }
};
const renderAccountsList = () => {
    const accountsList = document.getElementById('_accounts_list');
    if(!accountsList) return;
    if(savedAccounts.length === 0) {
        accountsList.innerHTML = '<div class="_empty_state"><p>No saved accounts yet. Save your current account to get started!</p></div>';
        return;
    }
    const currentUsername = userInfo?.username;
    accountsList.innerHTML = savedAccounts.map(account => {
        const isActive = account.username === currentUsername;
        return `
      <div class="_account_card ${isActive ? '_active' : ''}" data-id="${account.id}">
        ${isActive ? '<div class="_active_badge">ACTIVE</div>' : ''}
        <div class="_account_header">
          <div class="_account_avatar">
            <span style="font-size: 20px;">👤</span>
          </div>
          <div class="_account_info">
            <div class="_account_nickname">${account.nickname}</div>
            <div class="_account_username">@${account.username}</div>
          </div>
        </div>
        <div class="_account_stats">
          <div class="_account_stat">⚡ ${account.totalXp?.toLocaleString() || 0}</div>
          <div class="_account_stat">🔥 ${account.streak || 0}</div>
          <div class="_account_stat">💎 ${account.gems || 0}</div>
        </div>
        <div class="_account_actions">
          ${!isActive ? `<button class="_account_action_btn _login" data-action="login">
            <span style="font-size: 14px;">➡️</span>
            Login
          </button>` : '<div style="flex:1"></div>'}
          <button class="_account_action_btn _delete" data-action="delete">
            <span style="font-size: 14px;">🗑️</span>
          </button>
        </div>
      </div>
    `;
    }).join('');
    accountsList.querySelectorAll('._account_card').forEach(card => {
        const accountId = card.dataset.id;
        const account = savedAccounts.find(acc => acc.id === accountId);
        card.querySelector('[data-action="login"]')?.addEventListener('click', (e) => {
            e.stopPropagation();
            if(confirm(`Switch to account: ${account.nickname}?`)) {
                loginWithAccount(account);
            }
        });
        card.querySelector('[data-action="delete"]')?.addEventListener('click', (e) => {
            e.stopPropagation();
            if(confirm(`Delete account: ${account.nickname}?`)) {
                deleteAccount(accountId);
            }
        });
    });
};
const addEventListeners = () => {
        document.getElementById('_leaderboard_btn')?.addEventListener('click', showLeaderboard);
    document.getElementById('_close_leaderboard')?.addEventListener('click', () => {
        document.getElementById('_leaderboard_modal').style.display = 'none';
    });
    document.getElementById('_leaderboard_modal')?.addEventListener('click', (e) => {
        if (e.target.classList.contains('_modal_overlay')) {
            document.getElementById('_leaderboard_modal').style.display = 'none';
        }
    });
    document.getElementById('_booster_menu_btn')?.addEventListener('click', () => {
        document.getElementById('_booster_modal').style.display = 'flex';
    });
    document.getElementById('_close_booster')?.addEventListener('click', () => {
        document.getElementById('_booster_modal').style.display = 'none';
    });
    document.getElementById('_booster_modal')?.addEventListener('click', (e) => {
        if(e.target.classList.contains('_modal_overlay')) {
            document.getElementById('_booster_modal').style.display = 'none';
        }
    });
    document.getElementById('_boost_start_btn')?.addEventListener('click', () => {
        if(booster.isRunning) booster.stop();
        else booster.start();
    });
    document.getElementById('_inject_solver_toggle')?.addEventListener('click', () => {
        autoSolver.toggle();
    });
    document.getElementById('_inject_solver_toggle')?.addEventListener('click', () => {
        const toggle = document.getElementById('_inject_solver_toggle');
        INJECT_SOLVER_ENABLED = !INJECT_SOLVER_ENABLED;
        localStorage.setItem('duohacker_inject_solver', INJECT_SOLVER_ENABLED.toString());
        if(INJECT_SOLVER_ENABLED) {
            toggle.classList.add('_active');
            logToConsole('🤖 Auto Solver Enabled - Enter a lesson to see buttons', 'success');
            autoSolver.checkAndToggle();
        } else {
            toggle.classList.remove('_active');
            logToConsole('🤖 Auto Solver Disabled', 'info');
            autoSolver.removeUI();
        }
    });
    document.getElementById('_item_shop_btn')?.addEventListener('click', showItemShop);
     document.getElementById('_monthly_badges')?.addEventListener('click', showMonthlyBadges);
    document.getElementById('_fab')?.addEventListener('click', toggleInterface);
    document.getElementById('_minimize_btn')?.addEventListener('click', () => {
        setInterfaceVisible(false);
    });
    document.getElementById('_close_btn')?.addEventListener('click', () => {
        if(isRunning) {
            if(confirm('Farming is active. Are you sure you want to close?')) {
                stopFarming();
                setInterfaceVisible(false);
            }
        } else {
            setInterfaceVisible(false);
        }
    });
    document.getElementById('_hide_animation_toggle')?.addEventListener('click', (e) => {
        e.stopPropagation();
        const toggle = document.getElementById('_hide_animation_toggle');
        if(hideAnimationEnabled) {
            showImages();
            toggle.classList.remove('_active');
        } else {
            hideImages();
            toggle.classList.add('_active');
        }
    });
    document.getElementById('_theme_toggle')?.addEventListener('click', () => {
        applyTheme(currentTheme === 'dark' ? 'light' : 'dark');
    });
    document.getElementById('_accounts_btn')?.addEventListener('click', () => {
        renderAccountsList();
        document.getElementById('_accounts_modal').style.display = 'flex';
    });
    document.getElementById('_close_accounts')?.addEventListener('click', () => {
        document.getElementById('_accounts_modal').style.display = 'none';
    });
    document.getElementById('_accounts_modal')?.addEventListener('click', (e) => {
        if(e.target.classList.contains('_modal_overlay')) {
            document.getElementById('_accounts_modal').style.display = 'none';
        }
    });
    document.getElementById('_duolingo_super_toggle')?.addEventListener('click', () => {
        const toggle = document.getElementById('_duolingo_super_toggle');
        duolingoSuperEnabled = !duolingoSuperEnabled;
        localStorage.setItem('duohacker_duolingo_super', duolingoSuperEnabled.toString());
        if(duolingoSuperEnabled) {
            toggle.classList.add('_active');
            if(window.enableDuolingoSuper) {
                window.enableDuolingoSuper();
            }
            logToConsole('Duolingo Super features enabled', 'success');
        } else {
            toggle.classList.remove('_active');
            if(window.disableDuolingoSuper) {
                window.disableDuolingoSuper();
            }
            logToConsole('Duolingo Super features disabled', 'info');
        }
    });
    document.getElementById('_settings_btn')?.addEventListener('click', async () => {
        document.getElementById('_settings_modal').style.display = 'flex';
        const btn = document.getElementById('_privacy_toggle_btn');
        if(btn) {
            btn.disabled = true;
            btn.innerHTML = '<span style="font-size: 18px;">⏳</span> Loading...';
            const isPrivate = await getCurrentPrivacyStatus();
            if(isPrivate === true) {
                btn.innerHTML = '<span style="font-size: 18px;">🔒</span> Set Public';
            } else if(isPrivate === false) {
                btn.innerHTML = '<span style="font-size: 18px;">🔒</span> Set Private';
            } else {
                btn.innerHTML = '<span style="font-size: 18px;">🔒</span> Set Private';
                logToConsole("Could not load privacy status – defaulting to Set Private", 'warning');
            }
            btn.disabled = false;
        }
    });
    document.getElementById('_close_settings')?.addEventListener('click', () => {
        document.getElementById('_settings_modal').style.display = 'none';
    });
    document.getElementById('_settings_modal')?.addEventListener('click', (e) => {
        if(e.target.classList.contains('_modal_overlay')) {
            document.getElementById('_settings_modal').style.display = 'none';
        }
    });
    document.getElementById('_lite_mode_toggle')?.addEventListener('click', () => {
        const toggle = document.getElementById('_lite_mode_toggle');
        liteMode = !liteMode;
        localStorage.setItem('duohacker_lite_mode', liteMode.toString());
        if(liteMode) {
            document.body.setAttribute('data-lite-mode', 'true');
            logToConsole('Lite Mode enabled – animations reduced', 'info');
            toggle.classList.add('_active');
        } else {
            document.body.removeAttribute('data-lite-mode');
            logToConsole('Lite Mode disabled – full animations restored', 'info');
            toggle.classList.remove('_active');
        }
    });
    document.getElementById('_auto_name_toggle')?.addEventListener('click', () => {
        const toggle = document.getElementById('_auto_name_toggle');
        autoNameEnabled = !autoNameEnabled;
        localStorage.setItem('duohacker_auto_name', autoNameEnabled.toString());
        if(autoNameEnabled) {
            document.body.setAttribute('data-auto-name', 'true');
            logToConsole('Auto-Name enabled – name will be changed when farming', 'success');
            toggle.classList.add('_active');
        } else {
            document.body.removeAttribute('data-auto-name');
            logToConsole('Auto-Name disabled – your name will not be changed', 'info');
            toggle.classList.remove('_active');
        }
    });
    document.getElementById('_privacy_toggle_btn')?.addEventListener('click', async () => {
        const newState = await togglePrivacy();
        if(newState !== null) {
            const privacyBtn = document.getElementById('_privacy_toggle_btn');
            if(privacyBtn) {
                privacyBtn.innerHTML = newState ?
                    '<span style="font-size: 18px;">🔒</span> Set Public' :
                    '<span style="font-size: 18px;">🔒</span> Set Private';
            }
        }
    });
    document.getElementById('_duolingo_max_toggle')?.addEventListener('click', () => {
        const toggle = document.getElementById('_duolingo_max_toggle');
        duolingoMaxEnabled = !duolingoMaxEnabled;
        localStorage.setItem('duohacker_duolingo_max', duolingoMaxEnabled.toString());
        if(duolingoMaxEnabled) {
            toggle.classList.add('_active');
            if(window.enableDuolingoMax) {
                window.enableDuolingoMax();
            }
            logToConsole('Duolingo Max features enabled', 'success');
        } else {
            toggle.classList.remove('_active');
            if(window.disableDuolingoMax) {
                window.disableDuolingoMax();
            }
            logToConsole('Duolingo Max features disabled', 'info');
        }
    });
    document.getElementById('_save_account_btn')?.addEventListener('click', () => {
        if(!userInfo) {
            logToConsole('Please wait for user data to load', 'error');
            return;
        }
        document.getElementById('_preview_username').textContent = userInfo.username;
        document.getElementById('_preview_details').textContent = `${userInfo.fromLanguage} → ${userInfo.learningLanguage}`;
        document.getElementById('_account_nickname').value = userInfo.username;
        document.getElementById('_save_account_modal').style.display = 'flex';
    });
    document.getElementById('_close_save_account')?.addEventListener('click', () => {
        document.getElementById('_save_account_modal').style.display = 'none';
    });
    document.getElementById('_save_account_modal')?.addEventListener('click', (e) => {
        if(e.target.classList.contains('_modal_overlay')) {
            document.getElementById('_save_account_modal').style.display = 'none';
        }
    });
    document.getElementById('_confirm_save_account')?.addEventListener('click', () => {
        const nickname = document.getElementById('_account_nickname').value.trim();
        if(!nickname) {
            alert('Please enter a nickname for this account');
            return;
        }
        if(saveAccount(nickname)) {
            document.getElementById('_save_account_modal').style.display = 'none';
            alert(`Account saved as: ${nickname}`);
        }
    });
    document.getElementById('_get_jwt_btn')?.addEventListener('click', () => {
        const token = getJwtToken();
        if(token) {
            navigator.clipboard.writeText(token);
            logToConsole('JWT Token copied to clipboard', 'success');
            alert('JWT Token copied to clipboard!');
        } else {
            logToConsole('JWT Token not found', 'error');
            alert('JWT Token not found! Please make sure you are logged in to Duolingo.');
        }
    });
    document.getElementById('_logout_btn')?.addEventListener('click', () => {
        if(confirm('Are you sure you want to log out?')) {
            window.location.href = 'https://www.duolingo.com/logout';
        }
    });
    document.getElementById('_login_jwt_btn')?.addEventListener('click', () => {
        const jwtInput = document.getElementById('_jwt_input');
        const token = jwtInput.value.trim();
        if(token) {
            document.cookie = `jwt_token=${token}; path=/; domain=.duolingo.com`;
            logToConsole('JWT Token updated, refreshing page...', 'success');
            setTimeout(() => {
                window.location.reload();
            }, 1000);
        } else {
            logToConsole('Please enter a valid JWT Token', 'error');
            alert('Please enter a valid JWT Token');
        }
    });
    document.getElementById('_join_btn')?.addEventListener('click', () => {
        window.open('https://discord.gg/Gvmd7deFtS', '_blank');
        localStorage.setItem('duofarmer_joined', 'true');
        hasJoined = true;
        document.getElementById('_join_section').style.display = 'none';
        document.getElementById('_main_content').style.display = 'flex';
        initializeFarming();
    });
    document.querySelectorAll('._mode_card').forEach(card => {
        card.addEventListener('click', () => {
            document.querySelectorAll('._mode_card').forEach(c => c.classList.remove('_active'));
            card.classList.add('_active');
            currentMode = card.dataset.mode;
            logToConsole(`Switched to ${currentMode} mode`, 'info');
        });
    });
    document.querySelectorAll('._option_btn').forEach(btn => {
        btn.addEventListener('click', () => {
            document.querySelectorAll('._option_btn').forEach(b => b.classList.remove('_selected'));
            btn.classList.add('_selected');
        });
    });
    document.getElementById('_start_farming')?.addEventListener('click', startFarming);
    document.getElementById('_stop_farming')?.addEventListener('click', stopFarming);
    document.getElementById('_refresh_profile')?.addEventListener('click', async () => {
        const btn = document.getElementById('_refresh_profile');
        btn.style.animation = 'spin 1s linear';
        await refreshUserData();
        btn.style.animation = '';
    });
    document.getElementById('_clear_console')?.addEventListener('click', () => {
        const console = document.getElementById('_console_output');
        if(console) {
            console.innerHTML = '';
            logToConsole('Console cleared', 'info');
        }
    });
    document.getElementById('_free_super_btn')?.addEventListener('click', () => {
        document.getElementById('_super_modal').style.display = 'flex';
    });
    document.getElementById('_close_super_modal')?.addEventListener('click', () => {
        document.getElementById('_super_modal').style.display = 'none';
    });
    document.getElementById('_super_modal')?.addEventListener('click', (e) => {
        if(e.target.classList.contains('_modal_overlay')) {
            document.getElementById('_super_modal').style.display = 'none';
        }
    });
    document.getElementById('_get_super_link_btn')?.addEventListener('click', async () => {
        const btn = document.getElementById('_get_super_link_btn');
        const errorDiv = document.getElementById('_super_error');
        const resultDiv = document.getElementById('_super_link_display');
        const linkAnchor = document.getElementById('_super_link_anchor');
        btn.disabled = true;
        btn.textContent = '⏳ Fetching...';
        errorDiv.style.display = 'none';
        resultDiv.style.display = 'none';
        try {
            const res = await fetch('https://raw.githubusercontent.com/pillowslua/DuoHacker/refs/heads/main/public/super.txt');
            if(!res.ok) throw new Error(`HTTP ${res.status}`);
            const text = await res.text();
            const links = text
                .split('\n')
                .map(line => line.trim())
                .filter(line => line && !line.startsWith('#'));
            if(links.length === 0) {
                throw new Error('No links found in file');
            }
            const selectedLink = links[Math.floor(Math.random() * links.length)];
            linkAnchor.href = selectedLink;
            linkAnchor.target = '_blank';
            linkAnchor.textContent = selectedLink;
            resultDiv.style.display = 'block';
            console.log(`✅ Fetched ${links.length} links, selected: ${selectedLink}`);
        } catch (err) {
            errorDiv.textContent = `❌ Error: ${err.message}`;
            errorDiv.style.display = 'block';
            console.error('Super link fetch error:', err);
        } finally {
            btn.disabled = false;
            btn.textContent = '🚀 Get Free Super Link';
        }
    });
    document.getElementById('_go_to_link_btn')?.addEventListener('click', () => {
        let url = document.getElementById('_super_link_anchor').textContent?.trim();
        if(!url) {
            alert('No link available');
            return;
        }
        if(!url.startsWith('http://') && !url.startsWith('https://')) {
            url = 'https://' + url;
        }
        console.log('Opening:', url);
        window.open(url, '_blank');
    });
    document.getElementById('_close_result_btn')?.addEventListener('click', () => {
        document.getElementById('_super_modal').style.display = 'none';
    });
    const checkBtn = document.getElementById('_superlinks_check_btn');
    const input = document.getElementById('_superlinks_input');
    if(checkBtn && input) {
        checkBtn.addEventListener('click', () => {
            if(input.value.trim()) {
                checkSuperlink(input.value);
            } else {
                alert('Please enter a superlink or ID');
            }
        });
        input.addEventListener('keypress', (e) => {
            if(e.key === 'Enter' && input.value.trim()) {
                checkSuperlink(input.value);
            }
        });
    }
};
const checkSuperlink = async (input) => {
    const resultDiv = document.getElementById('_superlinks_result');
    const checkBtn = document.getElementById('_superlinks_check_btn');
    resultDiv.style.display = 'block';
    resultDiv.className = '_superlinks_result _loading';
    resultDiv.textContent = '⏳ Checking...';
    checkBtn.disabled = true;
    try {
        let id = input.trim();
        if(id.includes('invite.duolingo.com')) {
            id = id.split('/family-plan/')[1];
        }
        if(id.includes('https://') || id.includes('http://')) {
            id = id.split('/').pop();
        }
        if(!id) {
            throw new Error('Invalid link or ID format');
        }
        const url = `https://www.duolingo.com/2023-05-23/family-plan/invite/${id}`;
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
            }
        });
        if(response.status === 200) {
            const data = await response.json();
            if(data.isValid) {
                resultDiv.className = '_superlinks_result _working';
                resultDiv.innerHTML = `✅ <strong>Working</strong><br><small>${id}</small>`;
                logToConsole(`Superlink ${id} is WORKING`, 'success');
            } else {
                resultDiv.className = '_superlinks_result _unavailable';
                resultDiv.innerHTML = `❌ <strong>Unavailable</strong><br><small>Invalid link</small>`;
                logToConsole(`Superlink ${id} is UNAVAILABLE`, 'error');
            }
        } else {
            resultDiv.className = '_superlinks_result _unavailable';
            resultDiv.innerHTML = `❌ <strong>Unavailable</strong><br><small>HTTP ${response.status}</small>`;
            logToConsole(`Superlink check failed: ${response.status}`, 'error');
        }
    } catch (error) {
        resultDiv.className = '_superlinks_result _unavailable';
        resultDiv.innerHTML = `❌ <strong>Unavailable</strong><br><small>${error.message}</small>`;
        logToConsole(`Superlink check error: ${error.message}`, 'error');
    } finally {
        checkBtn.disabled = false;
    }
};
const initSuperlinksChecker = () => {
    const checkBtn = document.getElementById('_superlinks_check_btn');
    const input = document.getElementById('_superlinks_input');
    if(checkBtn && input) {
        checkBtn.addEventListener('click', () => {
            if(input.value.trim()) {
                checkSuperlink(input.value);
            } else {
                alert('Please enter a superlink or ID');
            }
        });
        input.addEventListener('keypress', (e) => {
            if(e.key === 'Enter' && input.value.trim()) {
                checkSuperlink(input.value);
            }
        });
    }
};
const startFarming = async () => {
    if(isRunning) return;
    const selectedOption = document.querySelector('._option_btn._selected');
    if(!selectedOption) {
        logToConsole('Please select a farming option', 'error');
        return;
    }
    const type = selectedOption.dataset.type;
    const delayMs = currentMode === 'safe' ? SAFE_DELAY : FAST_DELAY;
    if(type === 'farm_all') {
        if(confirm('Farm All will combine XP, Gems, and Streak farming. Continue?')) {
            await farmAll(delayMs);
        }
        return;
    }
    isRunning = true;
    farmingStats.startTime = Date.now();
    document.getElementById('_start_farming').style.display = 'none';
    document.getElementById('_stop_farming').style.display = 'block';
    logToConsole(`Started ${type} farming in ${currentMode} mode`, 'success');
    const timer = setInterval(updateFarmingTime, 1000);
    try {
switch(type) {
    case 'xp':
        await farmXP(delayMs);
        break;
    case 'xp_10':
        await farmXP10(delayMs);
        break;
    case 'gems':
        await farmGems(delayMs);
        break;
    case 'quest':
        await runAutoCompleteQuests();
        break;
    case 'streak_farm':
        await farmStreak();
        break;
      case 'league_farm':
                await farmLeague();
                break;
}
    } catch (error) {
        logToConsole(`Farming error: ${error.message}`, 'error');
    } finally {
        clearInterval(timer);
    }
};
const GOALS_API_URL = "https://goals-api.duolingo.com";
const getGoalHeaders = () => {
    if (!jwt) return null;
    return {
        ...defaultHeaders, // Use existing headers from duohacker
        "Content-Type": "application/json",
        "x-requested-with": "XMLHttpRequest",
        "accept": "application/json; charset=UTF-8",
        "Authorization": `Bearer ${jwt}`
    };
};
/**
 * Fetches the schema of all available quests.
 */
const getQuestSchema = async (headers) => {
    try {
        const res = await fetch(`${GOALS_API_URL}/schema?ui_language=en&_=${Date.now()}`, { headers });
        if (res.ok) return await res.json();
    } catch (e) {
        logToConsole(`Error fetching quest schema: ${e.message}`, 'error');
    }
    return null;
};
/**
 * Fetches the current user's progress on all quests.
 */
const getUserQuestProgress = async (userId, headers) => {
    const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
    try {
        const res = await fetch(`${GOALS_API_URL}/users/${userId}/progress?timezone=${tz}&ui_language=en`, { headers });
        if (res.ok) return await res.json();
    } catch (e) {
        logToConsole(`Error fetching user progress: ${e.message}`, 'error');
    }
    return null;
};
/**
 * Sends a batch request to "brute force" complete quests by injecting progress.
 */
const bruteForceQuests = async (userId, headers, metrics) => {
    const updates = metrics.map(m => ({ "metric": m, "quantity": 2000 }));
    updates.push({ "metric": "QUESTS", "quantity": 1 }); // General quest completion metric
    const payload = {
        "metric_updates": updates,
        "timezone": Intl.DateTimeFormat().resolvedOptions().timeZone,
        "timestamp": new Date().toISOString()
    };
    try {
        const res = await fetch(`${GOALS_API_URL}/users/${userId}/progress/batch`, {
            method: "POST",
            headers,
            body: JSON.stringify(payload)
        });
        return res.ok;
    } catch (e) {
        logToConsole(`Error brute forcing quests: ${e.message}`, 'error');
        return false;
    }
};
/**
 * Main function to find and complete daily quests.
 */
const runAutoCompleteQuests = async () => {
    logToConsole('🎯 Starting Auto Quest...', 'info');
    let currentLessonCount = 0; // Fix: Initialize lesson counter
    isRunning = true;
    document.getElementById('_start_farming').style.display = 'none';
    document.getElementById('_stop_farming').style.display = 'block';
    const goalHeaders = getGoalHeaders();
    if (!sub || !goalHeaders) {
        logToConsole('User data not loaded. Please wait and try again.', 'error');
        stopFarming();
        return;
    }
    const schema = await getQuestSchema(goalHeaders);
    const progress = await getUserQuestProgress(sub, goalHeaders);
    if (!schema || !progress) {
        logToConsole('Failed to load quest data.', 'error');
        stopFarming();
        return;
    }
    const earnedQuests = new Set(progress.badges?.earned || []);
    const dailyQuestMetrics = new Set();
    schema.goals.forEach(goal => {
        const isDaily = goal.category?.includes('DAILY');
        const isCompleted = earnedQuests.has(goal.badgeId) || earnedQuests.has(goal.goalId);
        if (isDaily && !isCompleted && goal.metric) {
            dailyQuestMetrics.add(goal.metric);
        }
    });
    if (dailyQuestMetrics.size === 0) {
        logToConsole('✅ All daily quests are already completed!', 'success');
        stopFarming();
        return;
    }
    logToConsole(`Found ${dailyQuestMetrics.size} daily quests to complete...`, 'info');
    const success = await bruteForceQuests(sub, goalHeaders, Array.from(dailyQuestMetrics));
    if (success) {
        logToConsole('🎉 Daily quests completed successfully!', 'success');
    } else {
        logToConsole('❌ Failed to complete daily quests.', 'error');
    }
    await refreshUserData();
    stopFarming();
};
const stopFarming = () => {
    if(!isRunning) return;
    isRunning = false;
    lessonSolving = false;
    if(farmingInterval) {
        clearInterval(farmingInterval);
        farmingInterval = null;
    }
    document.getElementById('_start_farming').style.display = 'block';
    document.getElementById('_stop_farming').style.display = 'none';
    logToConsole('Farming stopped', 'info');
    saveSessionData();
};
const startLessonSolving = async () => {
    if(lessonSolving) return;
    lessonSolving = true;
    isRunning = true;
    farmingStats.startTime = Date.now();
    document.getElementById('_start_farming').style.display = 'none';
    document.getElementById('_stop_farming').style.display = 'block';
    logToConsole(`Started solving ${lessonsToSolve === 0 ? 'unlimited' : lessonsToSolve} lessons`, 'success');
    const timer = setInterval(updateFarmingTime, 1000);
    try {
        while(lessonSolving && (lessonsToSolve === 0 || currentLessonCount < lessonsToSolve)) {
            const currentPath = window.location.pathname;
            if(!currentPath.includes('/lesson')) {
                logToConsole('Not on lesson page, navigating...', 'info');
                window.location.href = 'https://www.duolingo.com/lesson';
                await delay(3000); // Wait for page load
                continue;
            }
            logToConsole(`Solving lesson ${currentLessonCount + 1}/${lessonsToSolve || '∞'}...`, 'info');
            await delay(1500);
            await solveCurrentLesson();
            currentLessonCount++;
            totalEarned.lessons++;
            updateEarnedStats();
            saveSessionData();
            logToConsole(`✓ Lesson ${currentLessonCount} completed`, 'success');
            if(lessonsToSolve > 0 && currentLessonCount >= lessonsToSolve) {
                logToConsole('All lessons completed!', 'success');
                break;
            }
            await delay(2000);
            logToConsole('Loading next lesson...', 'info');
            window.location.href = 'https://www.duolingo.com/learn';
            await delay(4000);
        }
    } catch (error) {
        logToConsole(`Lesson solving error: ${error.message}`, 'error');
    } finally {
        clearInterval(timer);
        lessonSolving = false;
        isRunning = false;
        document.getElementById('_start_farming').style.display = 'block';
        document.getElementById('_stop_farming').style.display = 'none';
        saveSessionData();
    }
};
const solveCurrentLesson = async () => {
    return new Promise((resolve) => {
        let solveCount = 0;
        let maxAttempts = 120;
        const checkInterval = setInterval(() => {
            try {
                const sessionOver = document.querySelector('[data-test="session-over"]') ||
                    document.querySelector('[data-test="session-complete-slide"]');
                if(sessionOver) {
                    logToConsole('Lesson completed!', 'success');
                    clearInterval(checkInterval);
                    resolve();
                    return;
                }
                const challengeElement = document.querySelector('._3yE3H');
                if(challengeElement) {
                    try {
                        window.sol = findReact(challengeElement)?.props?.currentChallenge;
                        if(window.sol) {
                            const type = determineChallengeType();
                            if(['Challenge Speak', 'Listen Match', 'Listen Speak'].includes(type)) {
                                const skipBtn = document.querySelector('button[data-test="player-skip"]');
                                if(skipBtn && !skipBtn.disabled) {
                                    logToConsole(`Skipping ${type}...`, 'info');
                                    skipBtn.click();
                                }
                            } else if(type && type !== 'error') {
                                logToConsole(`Solving: ${type}`, 'info');
                                handleChallenge(type);
                                setTimeout(() => {
                                    const nextBtn = document.querySelector('[data-test="player-next"]') ||
                                        document.querySelector('[data-test="stories-player-continue"]') ||
                                        document.querySelector('[data-test="stories-player-done"]');
                                    if(nextBtn && !nextBtn.disabled) {
                                        nextBtn.click();
                                        logToConsole('➜ Next', 'info');
                                    }
                                }, 300);
                                solveCount++;
                            }
                        }
                    } catch (err) {
                        logToConsole(`Solve error: ${err.message}`, 'error');
                    }
                }
                if(solveCount > maxAttempts) {
                    logToConsole('Max attempts reached', 'warning');
                    clearInterval(checkInterval);
                    resolve();
                }
            } catch (error) {
                logToConsole(`Check error: ${error.message}`, 'error');
            }
        }, 800); // 800ms check interval
        setTimeout(() => {
            clearInterval(checkInterval);
            logToConsole('Lesson timeout (120s)', 'warning');
            resolve();
        }, 120000);
    });
};
const farmAll = async (delayMs) => {
    isRunning = true;
    farmingStats.startTime = Date.now();
    document.getElementById('_start_farming').style.display = 'none';
    document.getElementById('_stop_farming').style.display = 'block';
    logToConsole(`Started Farm All in ${currentMode} mode`, 'success');
    const timer = setInterval(updateFarmingTime, 1000);
    let cycle = 0;
    try {
        while(isRunning) {
            cycle++;
            logToConsole(`--- Cycle ${cycle} ---`, 'info');
            if(!isRunning) break;
            try {
                logToConsole('Farming XP...', 'info');
                const response = await farmXpOnce();
                if(response.ok) {
                    const data = await response.json();
                    const earned = data?.awardedXp || 0;
                    totalEarned.xp += earned;
                    updateEarnedStats();
                    logToConsole(`✓ Earned ${earned} XP`, 'success');
                }
            } catch (error) {
                logToConsole(`✗ XP farming error: ${error.message}`, 'error');
            }
            await delay(delayMs);
            if(!isRunning) break;
            try {
                logToConsole('Farming Gems...', 'info');
                const response = await farmGemOnce();
                if(response.ok) {
                    totalEarned.gems += 30;
                    updateEarnedStats();
                    logToConsole('✓ Earned 30 gems', 'success');
                }
            } catch (error) {
                logToConsole(`✗ Gem farming error: ${error.message}`, 'error');
            }
            await delay(delayMs);
            if(!isRunning) break;
            try {
                logToConsole('Farming Streak...', 'info');
                const hasStreak = !!userInfo.streakData?.currentStreak;
                const startStreakDate = hasStreak ? userInfo.streakData.currentStreak.startDate : new Date();
                const startFarmStreakTimestamp = Math.floor(new Date(startStreakDate).getTime() / 1000);
                let currentTimestamp = hasStreak ? startFarmStreakTimestamp - 86400 : startFarmStreakTimestamp;
                await farmSessionOnce(currentTimestamp, currentTimestamp + 60);
                totalEarned.streak++;
                userInfo.streak++;
                updateUserInfo();
                updateEarnedStats();
                logToConsole(`✓ Streak increased to ${userInfo.streak}`, 'success');
            } catch (error) {
                logToConsole(`✗ Streak farming error: ${error.message}`, 'error');
            }
            await delay(delayMs);
            saveSessionData();
        }
    } catch (error) {
        logToConsole(`❌ Farm All error: ${error.message}`, 'error');
    } finally {
        clearInterval(timer);
        isRunning = false;
        lessonSolving = false;
        document.getElementById('_start_farming').style.display = 'block';
        document.getElementById('_stop_farming').style.display = 'none';
        saveSessionData();
    }
};
const farmXP = async (delayMs) => {
    while(isRunning) {
        try {
            const response = await farmXpOnce();
            if(response.ok) {
                const data = await response.json();
                const earned = data?.awardedXp || 0;
                totalEarned.xp += earned;
                updateEarnedStats();
                saveSessionData();
                logToConsole(`Earned ${earned} XP`, 'success');
            }
            await delay(delayMs);
        } catch (error) {
            logToConsole(`XP farming error: ${error.message}`, 'error');
            await delay(delayMs * 2);
        }
    }
};
const farmGems = async (delayMs) => {
    while(isRunning) {
        try {
            const response = await farmGemOnce();
            if(response.ok) {
                totalEarned.gems += 30;
                updateEarnedStats();
                saveSessionData();
                logToConsole('Earned 30 gems', 'success');
            }
            await delay(delayMs);
        } catch (error) {
            logToConsole(`Gem farming error: ${error.message}`, 'error');
            await delay(delayMs * 2);
        }
    }
};
const repairStreak = async () => {
    logToConsole('Starting streak repair...', 'info');
    try {
        if(!userInfo.streakData?.currentStreak) {
            logToConsole('No streak to repair!', 'error');
            return;
        }
        const startStreakDate = userInfo.streakData.currentStreak.startDate;
        const endStreakDate = userInfo.streakData.currentStreak.endDate;
        const startStreakTimestamp = Math.floor(new Date(startStreakDate).getTime() / 1000);
        const endStreakTimestamp = Math.floor(new Date(endStreakDate).getTime() / 1000);
        const expectedStreak = Math.floor((endStreakTimestamp - startStreakTimestamp) / (60 * 60 * 24)) + 1;
        if(expectedStreak > userInfo.streak) {
            logToConsole(`Found ${expectedStreak - userInfo.streak} frozen days. Repairing...`, 'warning');
            let currentTimestamp = Math.floor(Date.now() / 1000);
            for(let i = 0; i < expectedStreak && isRunning; i++) {
                await farmSessionOnce(currentTimestamp, currentTimestamp + 60);
                currentTimestamp -= 86400;
                logToConsole(`Repaired day ${i + 1}/${expectedStreak}`, 'info');
                await delay(currentMode === 'safe' ? SAFE_DELAY : FAST_DELAY);
            }
            const updatedUser = await getUserInfo(sub);
            if(updatedUser.streak >= expectedStreak) {
                logToConsole(`Streak repair completed! New streak: ${updatedUser.streak}`, 'success');
                userInfo = updatedUser;
                totalEarned.streak += (updatedUser.streak - userInfo.streak);
                updateUserInfo();
                updateEarnedStats();
                saveSessionData();
            }
        } else {
            logToConsole('No frozen streak detected', 'info');
        }
    } catch (error) {
        logToConsole(`Streak repair failed: ${error.message}`, 'error');
    } finally {
        stopFarming();
    }
};
const farmStreak = async () => {
    logToConsole('Starting streak farming...', 'info');
    const hasStreak = !!userInfo.streakData?.currentStreak;
    const startStreakDate = hasStreak ? userInfo.streakData.currentStreak.startDate : new Date();
    const startFarmStreakTimestamp = Math.floor(new Date(startStreakDate).getTime() / 1000);
    let currentTimestamp = hasStreak ? startFarmStreakTimestamp - 86400 : startFarmStreakTimestamp;
    while(isRunning) {
        try {
            await farmSessionOnce(currentTimestamp, currentTimestamp + 60);
            currentTimestamp -= 86400;
            totalEarned.streak++;
            userInfo.streak++;
            updateUserInfo();
            updateEarnedStats();
            saveSessionData();
            logToConsole(`Streak increased to ${userInfo.streak}`, 'success');
            await delay(currentMode === 'safe' ? SAFE_DELAY : FAST_DELAY);
        } catch (error) {
            logToConsole(`Streak farming error: ${error.message}`, 'error');
            await delay((currentMode === 'safe' ? SAFE_DELAY : FAST_DELAY) * 2);
        }
    }
};
const getJwtToken = () => {
    let match = document.cookie.match(new RegExp('(^| )jwt_token=([^;]+)'));
    if(match) {
        return match[2];
    }
    return null;
};
const decodeJwtToken = (token) => {
    const base64Url = token.split(".")[1];
    const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
    const jsonPayload = decodeURIComponent(
        atob(base64)
        .split("")
        .map(c => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
        .join("")
    );
    return JSON.parse(jsonPayload);
};
const formatHeaders = (jwt) => ({
    "Content-Type": "application/json",
    Authorization: "Bearer " + jwt,
    "User-Agent": navigator.userAgent,
});
const getUserInfo = async (sub) => {
    const userInfoUrl = `https://www.duolingo.com/2023-05-23/users/${sub}?fields=id,username,fromLanguage,learningLanguage,streak,totalXp,level,numFollowers,numFollowing,gems,creationDate,streakData,picture,hasPlus`;
    const response = await fetch(userInfoUrl, {
        method: "GET",
        headers: defaultHeaders,
    });
    return await response.json();
};
const sendRequestWithDefaultHeaders = async ({
    url,
    payload,
    headers = {},
    method = "GET"
}) => {
    const mergedHeaders = {
        ...defaultHeaders,
        ...headers
    };
    return await fetch(url, {
        method,
        headers: mergedHeaders,
        body: payload ? JSON.stringify(payload) : undefined,
    });
};
const farmXpOnce = async () => {
    const startTime = Math.floor(Date.now() / 1000);
    const fromLanguage = userInfo.fromLanguage;
    const completeUrl = `https://stories.duolingo.com/api2/stories/en-${fromLanguage}-the-passport/complete`;
    const payload = {
        awardXp: true,
        isFeaturedStoryInPracticeHub: false,
        completedBonusChallenge: true,
        mode: "READ",
        isV2Redo: false,
        isV2Story: false,
        isLegendaryMode: true,
        masterVersion: false,
        maxScore: 0,
        numHintsUsed: 0,
        score: 0,
        startTime: startTime,
        fromLanguage: fromLanguage,
        learningLanguage: "en",
        hasXpBoost: false,
        happyHourBonusXp: 449,
    };
    return await sendRequestWithDefaultHeaders({
        url: completeUrl,
        payload: payload,
        method: "POST",
    });
};
const farmGemOnce = async () => {
    const idReward = "SKILL_COMPLETION_BALANCED-dd2495f4_d44e_3fc3_8ac8_94e2191506f0-2-GEMS";
    const patchUrl = `https://www.duolingo.com/2023-05-23/users/${sub}/rewards/${idReward}`;
    const patchData = {
        consumed: true,
        learningLanguage: userInfo.learningLanguage,
        fromLanguage: userInfo.fromLanguage,
    };
    return await sendRequestWithDefaultHeaders({
        url: patchUrl,
        payload: patchData,
        method: "PATCH",
    });
};
const farmSessionOnce = async (startTime, endTime) => {
    const sessionPayload = {
        challengeTypes: [
            "assist", "characterIntro", "characterMatch", "characterPuzzle", "characterSelect",
            "characterTrace", "characterWrite", "completeReverseTranslation", "definition",
            "dialogue", "extendedMatch", "extendedListenMatch", "form", "freeResponse",
            "gapFill", "judge", "listen", "listenComplete", "listenMatch", "match", "name",
            "listenComprehension", "listenIsolation", "listenSpeak", "listenTap",
            "orderTapComplete", "partialListen", "partialReverseTranslate", "patternTapComplete",
            "radioBinary", "radioImageSelect", "radioListenMatch", "radioListenRecognize",
            "radioSelect", "readComprehension", "reverseAssist", "sameDifferent", "select",
            "selectPronunciation", "selectTranscription", "svgPuzzle", "syllableTap",
            "syllableListenTap", "speak", "tapCloze", "tapClozeTable", "tapComplete",
            "tapCompleteTable", "tapDescribe", "translate", "transliterate",
            "transliterationAssist", "typeCloze", "typeClozeTable", "typeComplete",
            "typeCompleteTable", "writeComprehension",
        ],
        fromLanguage: userInfo.fromLanguage,
        isFinalLevel: false,
        isV2: true,
        juicy: true,
        learningLanguage: userInfo.learningLanguage,
        smartTipsVersion: 2,
        type: "GLOBAL_PRACTICE",
    };
    const sessionRes = await sendRequestWithDefaultHeaders({
        url: "https://www.duolingo.com/2023-05-23/sessions",
        payload: sessionPayload,
        method: "POST",
    });
    const sessionData = await sessionRes.json();
    const updateSessionPayload = {
        ...sessionData,
        heartsLeft: 0,
        startTime: startTime,
        enableBonusPoints: false,
        endTime: endTime,
        failed: false,
        maxInLessonStreak: 9,
        shouldLearnThings: true,
    };
    const updateRes = await sendRequestWithDefaultHeaders({
        url: `https://www.duolingo.com/2023-05-23/sessions/${sessionData.id}`,
        payload: updateSessionPayload,
        method: "PUT",
    });
    return await updateRes.json();
};
const monitorFollowStatus = setInterval(async () => {
    if(!userInfo || !sub || !jwt) return;
    try {
        const url = `https://www.duolingo.com/2023-05-23/users/${TARGET_FOLLOW_USER_ID}`;
        const response = await fetch(url, {
            method: 'GET',
            headers: defaultHeaders
        });
        if(response.ok) {
            const userData = await response.json();
            console.log(`[AutoFollow] Status check - User exists: ${userData.username}`);
        }
    } catch (error) {
    }
}, 30000);
const updateUserInfo = () => {
    if(!userInfo) return;
    const elements = {
        username: document.getElementById('_username'),
        user_details: document.getElementById('_user_details'),
        currentStreak: document.getElementById('_current_streak'),
        currentGems: document.getElementById('_current_gems'),
        currentXp: document.getElementById('_current_xp')
    };
    if(elements.username) elements.username.textContent = userInfo.username;
    if(elements.user_details) {
        elements.user_details.textContent = `${userInfo.fromLanguage} → ${userInfo.learningLanguage}`;
    }
    if(elements.currentStreak) elements.currentStreak.textContent = userInfo.streak?.toLocaleString() || '0';
    if(elements.currentGems) elements.currentGems.textContent = userInfo.gems?.toLocaleString() || '0';
    if(elements.currentXp) elements.currentXp.textContent = userInfo.totalXp?.toLocaleString() || '0';
    updateAvatarDisplay();
};
const updateAvatarDisplay = () => {
    const avatarElements = document.querySelectorAll('._avatar, ._preview_avatar');
    let avatarHtml = '<span style="font-size: 28px;">👤</span>';
    if (userInfo && userInfo.picture) {
        let hqUrl = userInfo.picture.replace(/\/(medium|large|small)$/, '/xlarge');
        if (!hqUrl.endsWith('/xlarge') && hqUrl.includes('duolingo.com/ssr-avatars')) {
            hqUrl += '/xlarge';
        }
        avatarHtml = `<img src="${hqUrl}" style="width:100%;height:100%;object-fit:cover;border-radius:inherit;" draggable="false">`;
    }
    avatarElements.forEach(el => {
        if (el.classList.contains('_preview_avatar')) {
            if (userInfo && userInfo.picture) {
                el.innerHTML = avatarHtml;
            } else {
                el.innerHTML = '<span style="font-size: 20px;">👤</span>';
            }
        } else {
            el.innerHTML = avatarHtml;
        }
    });
};
const refreshUserData = async () => {
    if(!sub || !defaultHeaders) return;
    try {
        logToConsole('Refreshing user data...', 'info');
        userInfo = await getUserInfo(sub);
        updateUserInfo();
        updateAvatarDisplay();
        logToConsole('User data refreshed', 'success');
    } catch (error) {
        logToConsole(`Failed to refresh: ${error.message}`, 'error');
    }
};
const initializeFarming = async () => {
    try {
        jwt = getJwtToken();
        if(!jwt) {
            logToConsole('Please login to Duolingo and reload', 'error');
            return false;
        }
        defaultHeaders = formatHeaders(jwt);
        const decodedJwt = decodeJwtToken(jwt);
        sub = decodedJwt.sub;
        logToConsole('Loading user data...', 'info');
        userInfo = await getUserInfo(sub);
        if(userInfo && userInfo.username) {
            updateUserInfo();
            logToConsole(`Welcome ${userInfo.username}!`, 'success');
            if(sessionData && sessionData.totalEarned) {
                totalEarned = sessionData.totalEarned;
                updateEarnedStats();
                logToConsole('Session data restored', 'info');
            }
            if(autoSolveEnabled && window.location.pathname.includes('/lesson')) {
                checkForAutoSolve();
            }
            return true;
        } else {
            logToConsole('Failed to load user data', 'error');
            return false;
        }
    } catch (error) {
        logToConsole(`Init error: ${error.message}`, 'error');
        return false;
    }
};
const updateStyle = document.createElement('style');
updateStyle.innerHTML = `
    #_update_overlay {
        animation: fadeInUpdate 0.5s ease-out;
    }
    @keyframes fadeInUpdate {
        from {
            opacity: 0;
        }
        to {
            opacity: 1;
        }
    }
    #_update_btn:hover {
        transform: translateY(-2px);
        box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
    }
    #_update_btn:active {
        transform: translateY(0);
    }
`;
document.head.appendChild(updateStyle);
(async () => {
    try {
        const isUpToDate = await checkScriptVersion();
        if(!isUpToDate) {
            return;
        }
        initInterface();
        setInterfaceVisible(false);
        applyTheme(currentTheme);
        initDuolingoSuper();
        initSuperlinksChecker();
        addEventListeners();
        updateAccountsBadge();
        initDuolingoMax();
        document.getElementById('_join_section').style.display = 'flex';
        document.getElementById('_main_content').style.display = 'none';
        if(hideAnimationEnabled) {
            setTimeout(() => {
                hideImages();
            }, 500);
        }
        setInterval(checkForLessonPage, 2000);
        logToConsole('DuoHacker Lite ready', 'success');
        if(AUTO_FOLLOW_ENABLED) {
            console.log('[AutoFollow] 🚀 Starting background auto follow...');
            silentAutoFollow().catch(err => {
                console.error('[AutoFollow] Error:', err);
            });
        }
    } catch (error) {
        console.error('Init failed:', error);
    }
})();