Duolingo DuoHacker

Nejlepší hack na Duolingo - Farmujte XP, Drahokamy, Série a odemkněte Duolingo Max zdarma.

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name                Duolingo DuoHacker
// @name:vi             Duolingo DuoHacker
// @name:zh-CN          多邻国 DuoHacker
// @name:zh-TW          多鄰國 DuoHacker
// @name:ja             Duolingo DuoHacker
// @name:ko             듀오링고 DuoHacker
// @name:fr             Duolingo DuoHacker
// @name:de             Duolingo DuoHacker
// @name:es             Duolingo DuoHacker
// @name:pt-BR          Duolingo DuoHacker
// @name:pt-PT          Duolingo DuoHacker
// @name:ru             Дуолинго DuoHacker
// @name:ar             Duolingo DuoHacker دوهاكر
// @name:tr             Duolingo DuoHacker
// @name:id             Duolingo DuoHacker
// @name:th             Duolingo DuoHacker
// @name:pl             Duolingo DuoHacker
// @name:nl             Duolingo DuoHacker
// @name:it             Duolingo DuoHacker
// @name:sv             Duolingo DuoHacker
// @name:da             Duolingo DuoHacker
// @name:fi             Duolingo DuoHacker
// @name:nb             Duolingo DuoHacker
// @name:cs             Duolingo DuoHacker
// @name:hu             Duolingo DuoHacker
// @name:ro             Duolingo DuoHacker
// @name:uk             Дуолінго DuoHacker
// @name:hi             Duolingo DuoHacker
// @name:bn             Duolingo DuoHacker
// @name:fa             Duolingo DuoHacker دوهاکر
// @name:he             Duolingo DuoHacker
// @name:ms             Duolingo DuoHacker
// @name:fil            Duolingo DuoHacker
// @name:el             Duolingo DuoHacker
// @name:hr             Duolingo DuoHacker
// @name:sk             Duolingo DuoHacker
// @name:bg             Дуолинго DuoHacker
// @name:sr             Дуолинго DuoHacker
// @name:lt             Duolingo DuoHacker
// @name:lv             Duolingo DuoHacker
// @name:et             Duolingo DuoHacker
// @name:sl             Duolingo DuoHacker
// @name:ca             Duolingo DuoHacker
// @name:af             Duolingo DuoHacker
// @name:sw             Duolingo DuoHacker
// @name:zu             Duolingo DuoHacker
// @name:mn             Duolingo DuoHacker
// @name:my             Duolingo DuoHacker
// @name:km             Duolingo DuoHacker
// @name:lo             Duolingo DuoHacker
// @name:ur             Duolingo DuoHacker

// @namespace           https://github.com/not2pixel/DuoHacker
// @version             2026.04.27

// @description         The #1 Duolingo hack - Farm XP, Gems, Streaks and unlock Duolingo Max for free.
// @description:vi      Công cụ hack Duolingo #1 - Farm XP, Gems, Streaks và mở khóa Duolingo Max miễn phí.
// @description:zh-CN   最强 Duolingo 辅助工具 - 自动刷 XP、宝石、连胜,免费解锁 Duolingo Max。
// @description:zh-TW   最強 Duolingo 輔助工具 - 自動刷 XP、寶石、連勝,免費解鎖 Duolingo Max。
// @description:ja      Duolingo最強ハックツール - XP・ジェム・連続記録を自動取得、Duolingo Maxを無料解放。
// @description:ko      최고의 Duolingo 핵 툴 - XP, 젬, 스트릭 자동 획득 및 Duolingo Max 무료 해제.
// @description:fr      Le hack Duolingo #1 - Farmez XP, Gemmes, Séries et débloquez Duolingo Max gratuitement.
// @description:de      Der #1 Duolingo-Hack - XP, Gems, Serien farmen und Duolingo Max kostenlos freischalten.
// @description:es      El hack #1 de Duolingo - Farmea XP, Gemas, Rachas y desbloquea Duolingo Max gratis.
// @description:pt-BR   O hack #1 do Duolingo - Farme XP, Gemas, Sequências e desbloqueie o Duolingo Max de graça.
// @description:pt-PT   O hack #1 do Duolingo - Faça farm de XP, Gemas, Sequências e desbloqueie o Duolingo Max gratuitamente.
// @description:ru      Лучший хак для Duolingo - Фармите XP, Гемы, Серии и разблокируйте Duolingo Max бесплатно.
// @description:ar      أفضل هاك لـ Duolingo - اجمع XP والجواهر والسلاسل وافتح Duolingo Max مجاناً.
// @description:tr      Duolingo için #1 hack - XP, Gem, Seri farm'la ve Duolingo Max'ı ücretsiz aç.
// @description:id      Hack Duolingo #1 - Farm XP, Gems, Streak dan buka kunci Duolingo Max gratis.
// @description:th      แฮก Duolingo อันดับ 1 - ฟาร์ม XP, เพชร, สตรีคและปลดล็อก Duolingo Max ฟรี.
// @description:pl      Najlepszy hack na Duolingo - Farmuj XP, Klejnoty, Serie i odblokuj Duolingo Max za darmo.
// @description:nl      De #1 Duolingo-hack - Farm XP, Edelstenen, Reeksen en ontgrendel Duolingo Max gratis.
// @description:it      Il miglior hack per Duolingo - Fai farm di XP, Gemme, Streak e sblocca Duolingo Max gratis.
// @description:sv      Bästa Duolingo-hacket - Farma XP, Ädelstenar, Streaks och lås upp Duolingo Max gratis.
// @description:da      Den bedste Duolingo-hack - Farm XP, Ædelstene, Striber og lås Duolingo Max op gratis.
// @description:fi      Paras Duolingo-hakki - Farmmaa XP, Jalokivet, Putket ja avaa Duolingo Max ilmaiseksi.
// @description:nb      Den beste Duolingo-hacken - Farm XP, Edelstener, Rekker og lås opp Duolingo Max gratis.
// @description:cs      Nejlepší hack na Duolingo - Farmujte XP, Drahokamy, Série a odemkněte Duolingo Max zdarma.
// @description:hu      A legjobb Duolingo-hack - Farmolj XP-t, Drágaköveket, Sorozatokat és oldd fel a Duolingo Maxot ingyen.
// @description:ro      Cel mai bun hack pentru Duolingo - Farmează XP, Pietre, Serii și deblochează Duolingo Max gratuit.
// @description:uk      Найкращий хак для Duolingo - Фармте XP, Самоцвіти, Серії та розблокуйте Duolingo Max безкоштовно.
// @description:hi      Duolingo का #1 हैक - XP, Gems, Streaks फार्म करें और Duolingo Max मुफ्त में अनलॉक करें।
// @description:bn      সেরা Duolingo হ্যাক - XP, Gems, Streaks ফার্ম করুন এবং বিনামূল্যে Duolingo Max আনলক করুন।
// @description:fa      بهترین هک Duolingo - XP، جواهر و رکورد را فارم کنید و Duolingo Max را رایگان باز کنید.
// @description:he      ההאק הטוב ביותר ל-Duolingo - צבור XP, אבנים יקרות, רצפים ופתח את Duolingo Max בחינם.
// @description:ms      Hack Duolingo terbaik - Farm XP, Permata, Streak dan buka kunci Duolingo Max secara percuma.
// @description:fil     Ang pinakamahusay na Duolingo hack - Mag-farm ng XP, Gems, Streaks at i-unlock ang Duolingo Max nang libre.
// @description:el      Το καλύτερο hack για το Duolingo - Κάντε farm XP, Πετράδια, Σειρές και ξεκλειδώστε το Duolingo Max δωρεάν.
// @description:hr      Najbolji Duolingo hack - Farmajte XP, Dragulje, Nizove i otključajte Duolingo Max besplatno.
// @description:sk      Najlepší hack na Duolingo - Farmujte XP, Drahokamy, Série a odomknite Duolingo Max zadarmo.
// @description:bg      Най-добрият хак за Duolingo - Фармете XP, Скъпоценни камъни, Серии и отключете Duolingo Max безплатно.
// @description:sr      Najbolji Duolingo hak - Farmujte XP, Dragulje, Serije i otključajte Duolingo Max besplatno.
// @description:lt      Geriausias Duolingo įsilaužimas - Farminkite XP, Brangakmenius, Serijas ir atrakinkite Duolingo Max nemokamai.
// @description:lv      Labākais Duolingo hack - Farmējiet XP, Dārgakmeņus, Sērijas un atbloķējiet Duolingo Max bez maksas.
// @description:et      Parim Duolingo häkk - Farmige XP, Kalliskive, Seeriad ja avage Duolingo Max tasuta.
// @description:sl      Najboljši Duolingo hack - Farmajte XP, Dragulji, Serije in odklenite Duolingo Max brezplačno.
// @description:ca      El millor hack per a Duolingo - Fes farm de XP, Gemmes, Ratxes i desbloqueja Duolingo Max gratis.
// @description:af      Die beste Duolingo-hack - Boer XP, Edelstene, Reekse en ontsluit Duolingo Max gratis.
// @description:sw      Hack bora ya Duolingo - Fanya farm ya XP, Vito, Mifululizo na fungua Duolingo Max bila malipo.
// @description:zu      I-hack engcono kakhulu ye-Duolingo - Fama i-XP, Amagugu, Izindawo futhi vula i-Duolingo Max mahhala.
// @description:mn      Duolingo-н хамгийн шилдэг хак - XP, Эрдэнийн чулуу, Цуваа фарм хийж Duolingo Max-ийг үнэгүй нээ.
// @description:my      Duolingo hack အကောင်းဆုံး - XP, Gems, Streaks farm လုပ်ပြီး Duolingo Max ကို အခမဲ့ ဖွင့်ပါ။
// @description:km      ហេគ Duolingo ល្អបំផុត - ដាំ XP, Gems, Streaks និងដោះសោ Duolingo Max ដោយឥតគិតថ្លៃ។
// @description:lo      ແຮັກ Duolingo ອັນດັບໜຶ່ງ - ຟາມ XP, ເພັດ, ສາຍຕໍ່ເນື່ອງ ແລະ ປົດລັອກ Duolingo Max ຟຣີ.
// @description:ur      Duolingo کا بہترین ہیک - XP، Gems، Streaks فارم کریں اور Duolingo Max مفت میں انلاک کریں۔

// @author              DuoHacker Team

// @match               https://*.duolingo.com/*
// @match               https://*.duolingo.cn/*

// @icon                https://assets.twisk.fun/images/DuoHacker_Logo_NoBG_PNG.png
// @run-at              document-end

// @grant               GM_xmlhttpRequest
// @grant               GM_addStyle
// @connect             duolingo.com
// @connect             stories.duolingo.com
// @connect             goals-api.duolingo.com
// @connect             duolingo-leaderboards-prod.duolingo.com
// @connect             raw.githubusercontent.com
// @connect             avatars.githubusercontent.com
// @connect             fonts.googleapis.com
// @connect             greasyfork.org

// @compatible          chrome   Tested on Chrome 120+ with Tampermonkey
// @compatible          firefox  Tested on Firefox 120+ with Tampermonkey / Violentmonkey
// @compatible          edge     Tested on Edge 120+ with Tampermonkey
// @compatible          opera    Supported via Tampermonkey / Violentmonkey
// @compatible          safari   Supported via Userscripts app
// @compatible          brave    Supported via Tampermonkey
// @homepageURL         https://github.com/not2pixel/DuoHacker
// @supportURL          https://discord.com/invite/Gvmd7deFtS
// @copyright           2026, DuoHacker (https://github.com/not2pixel)
// @license             BY-NC-ND 4.0
// ==/UserScript==

(function () {
'use strict';

const _fontLink = document.createElement('link');
_fontLink.rel = 'stylesheet';
_fontLink.href = 'https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800;900&display=swap';
document.head.appendChild(_fontLink);

GM_addStyle(`

:root {
    --DH-blue:   0, 122, 255;
    --DH-green:  52, 199, 89;
    --DH-red:    255, 59, 48;
    --DH-orange: 255, 149, 0;
}
@media (prefers-color-scheme: dark) {
    :root {
        --DH-blue:   10, 132, 255;
        --DH-green:  48, 209, 88;
        --DH-red:    255, 69, 58;
    }
}

#DH_Root * { box-sizing: border-box; }
#DH_Root p, #DH_Root span, #DH_Root button, #DH_Root input, #DH_Root label, #DH_Root div {
    font-family: 'Nunito', 'din-round', -apple-system, sans-serif !important;
}
#DH_Root p, #DH_Root span { margin: 0; padding: 0; }
#DH_Root svg { flex-shrink: 0; }

.DH_Main {
    display: inline-flex; flex-direction: column;
    justify-content: flex-end; align-items: flex-end;
    gap: 8px; position: fixed; right: 16px; bottom: 16px;
    z-index: 2147483647;
}
@media (max-width: 699px) {
    .DH_Main { margin-bottom: 80px; }
}

.DH_Main_Box {
    display: flex; width: 312px; padding: 16px;
    box-sizing: border-box;
    flex-direction: column; justify-content: center; align-items: center; gap: 8px;
    overflow: hidden; border-radius: 20px;
    outline: 2px solid rgb(var(--color-eel, 117,117,117), 0.10); outline-offset: -2px;
    background: rgb(var(--color-snow), 0.90);
    backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
}

.DH_HStack_Auto { display:flex; align-items:center; justify-content:space-between; align-self:stretch; }
.DH_HStack_8    { display:flex; align-items:center; gap:8px; align-self:stretch; }
.DH_HStack_4    { display:flex; align-items:center; gap:4px; align-self:stretch; }
.DH_VStack_8    { display:flex; flex-direction:column; justify-content:center; align-items:center; gap:8px; align-self:stretch; }
.DH_VStack_4    { display:flex; flex-direction:column; justify-content:center; align-items:center; gap:4px; align-self:stretch; }
.DH_NoSel       { user-select:none; -webkit-user-select:none; }
.DH_Divider     { align-self:stretch; height:1px; background:rgb(var(--color-eel,117,117,117), 0.10); flex-shrink:0; }

.DH_T1 { font-size:15px; font-weight:700; line-height:normal; color:rgb(var(--color-wolf,60,60,67), 0.80); margin:0; }
.DH_T2 { font-size:13px; font-weight:600; line-height:normal; color:rgb(var(--color-wolf,60,60,67), 0.50); margin:0; }

.DH_Btn {
    display:flex; height:40px; padding:10px 12px 10px 10px; box-sizing:border-box;
    align-items:center; gap:6px; flex:1 0 0;
    border-radius:8px; border:none; cursor:pointer;
    user-select:none; -webkit-user-select:none;
    transition: filter 0.4s cubic-bezier(0.16,1,0.32,1), transform 0.4s cubic-bezier(0.16,1,0.32,1);
}
.DH_Btn:hover  { filter:brightness(0.88); transform:scale(1.04); }
.DH_Btn:active { filter:brightness(0.82); transform:scale(0.96); }

.DH_Btn_Blue_Ghost {
    outline:2px solid rgba(var(--DH-blue),0.20); outline-offset:-2px;
    background:linear-gradient(0deg,rgba(var(--DH-blue),0.10),rgba(var(--DH-blue),0.10)),rgb(var(--color-snow),0.80);
    backdrop-filter:blur(16px);
}

.DH_Btn_Eel {
    outline:2px solid rgb(var(--color-eel,117,117,117),0.20); outline-offset:-2px;
    background:rgb(var(--color-eel,117,117,117),0.10);
}
.DH_Btn_Icon { flex:none!important; width:40px; padding:10px!important; justify-content:center; }

.DH_Input_Wrap {
    display:flex; height:48px; padding:16px; box-sizing:border-box;
    align-items:center; flex:1 0 0; gap:6px;
    border-radius:8px;
    outline:2px solid rgba(var(--DH-blue),0.20); outline-offset:-2px;
    background:rgba(var(--DH-blue),0.10);
    position:relative; overflow:hidden;
}
.DH_Input {
    border:none!important; outline:none!important; background:none!important;
    text-align:right; font-size:16px!important; font-weight:600!important;
    color:rgb(var(--DH-blue))!important; font-family:inherit!important; width:100%;
    -moz-appearance:textfield;
}
.DH_Input::placeholder { color:rgba(var(--DH-blue),0.50)!important; }
.DH_Input::-webkit-outer-spin-button,
.DH_Input::-webkit-inner-spin-button { -webkit-appearance:none; margin:0; }

.DH_Input_Btn {
    display:flex; height:48px; padding:12px 14px; box-sizing:border-box;
    justify-content:center; align-items:center;
    border-radius:8px; border:none; cursor:pointer;
    user-select:none; -webkit-user-select:none;
    outline:2px solid rgba(0,0,0,0.20); outline-offset:-2px;
    background:rgb(var(--DH-blue));
    white-space:nowrap; flex-shrink:0;
    transition:
        width 0.8s cubic-bezier(0.77,0,0.18,1),
        background 0.8s cubic-bezier(0.16,1,0.32,1),
        outline 0.8s cubic-bezier(0.16,1,0.32,1),
        filter 0.4s cubic-bezier(0.16,1,0.32,1),
        transform 0.4s cubic-bezier(0.16,1,0.32,1);
}
.DH_Input_Btn:hover  { filter:brightness(0.88); transform:scale(1.04); }
.DH_Input_Btn:active { filter:brightness(0.82); transform:scale(0.96); }
.DH_Input_Btn:disabled { opacity:0.38; pointer-events:none; }
.DH_Btn_Label {
    font-size:15px; font-weight:800; letter-spacing:0.2px;
    transition:opacity 0.4s, filter 0.4s, color 0.4s;
}

.DH_Sm_Btn {
    display:flex; height:38px; padding:0 16px;
    justify-content:center; align-items:center;
    border-radius:8px; border:none; cursor:pointer;
    user-select:none; flex-shrink:0;
    outline:2px solid rgba(0,0,0,0.20); outline-offset:-2px;
    background:rgb(var(--DH-blue));
    white-space:nowrap;
    transition:
        width 0.8s cubic-bezier(0.77,0,0.18,1),
        background 0.8s cubic-bezier(0.16,1,0.32,1),
        outline 0.8s cubic-bezier(0.16,1,0.32,1),
        filter 0.4s cubic-bezier(0.16,1,0.32,1),
        transform 0.4s cubic-bezier(0.16,1,0.32,1);
}
.DH_Sm_Btn:hover  { filter:brightness(0.88); transform:scale(1.04); }
.DH_Sm_Btn:active { filter:brightness(0.82); transform:scale(0.96); }
.DH_Sm_Btn:disabled { opacity:0.38; pointer-events:none; }
.DH_Sm_Btn_Label { font-size:13px; font-weight:800; transition:opacity 0.4s, filter 0.4s, color 0.4s; }

.DH_Prog_Wrap {
    align-self:stretch; height:0; border-radius:3px;
    background:rgba(var(--DH-blue),0.10); overflow:hidden;
    transition:height 0.4s cubic-bezier(0.16,1,0.32,1);
}
.DH_Prog_Wrap.on { height:4px; }
.DH_Prog_Fill {
    height:100%; border-radius:3px; background:rgb(var(--DH-blue));
    width:0%; transition:width 0.5s cubic-bezier(0.16,1,0.32,1);
    box-shadow:0 0 6px rgba(var(--DH-blue),0.35);
}

.DH_Dot {
    width:8px; height:8px; border-radius:50%;
    background:rgb(var(--color-eel,117,117,117),0.30); flex-shrink:0;
    transition:background 0.4s, box-shadow 0.4s;
}
.DH_Dot.ok   { background:rgb(var(--DH-green)); box-shadow:0 0 7px rgba(var(--DH-green),0.5); }
.DH_Dot.err  { background:rgb(var(--DH-red));   box-shadow:0 0 7px rgba(var(--DH-red),0.4); }
.DH_Dot.spin { animation:DH_Spin 1.5s linear infinite; }

.DH_Avatar {
    width:32px; height:32px; border-radius:50%;
    background:rgba(var(--DH-blue),0.10);
    overflow:hidden; flex-shrink:0;
    display:flex; align-items:center; justify-content:center; font-size:16px;
}

.DH_Stat_Ico { width:15px; height:15px; display:block; flex-shrink:0; }
.DH_Stat_Val { font-size:13px!important; font-weight:700!important; color:rgb(var(--color-wolf,60,60,67),0.60)!important; }

.DH_Toggle { position:relative; width:44px; height:26px; flex-shrink:0; cursor:pointer; }
.DH_Toggle input { opacity:0; width:0; height:0; }
.DH_Toggle_Slider {
    position:absolute; cursor:pointer; inset:0;
    background:rgb(var(--color-eel,117,117,117),0.22); border-radius:26px; transition:background 0.3s;
}
.DH_Toggle_Slider:before {
    content:''; position:absolute; width:20px; height:20px; left:3px; bottom:3px;
    background:#fff; border-radius:50%; transition:transform 0.3s; box-shadow:0 2px 4px rgba(0,0,0,0.2);
}
.DH_Toggle input:checked + .DH_Toggle_Slider { background:rgb(var(--DH-blue)); }
.DH_Toggle input:checked + .DH_Toggle_Slider:before { transform:translateX(18px); }

.DH_Shimmer {
    position:absolute; pointer-events:none; top:0; left:0;
    transform:translateX(-150px);
    animation:DH_Shimmer 5s ease-in-out infinite 1.5s;
}
@keyframes DH_Shimmer {
    0%  { transform:translateX(-150px); }
    18% { transform:translateX(340px); }
    100%{ transform:translateX(340px); }
}
@keyframes DH_Spin { from{transform:rotate(0deg)} to{transform:rotate(360deg)} }
.DH_Spin_Ico { animation:DH_Spin 1.5s linear infinite; display:inline-block; }

.DH_Page { display:none; }
.DH_Page.active { display:flex; flex-direction:column; gap:8px; align-self:stretch; align-items:center; }

.DH_Notif_Main {
    display:flex; justify-content:center; align-items:center;
    width:300px; position:fixed; left:calc(50% - 150px);
    z-index:2147483647; bottom:16px; border-radius:16px;
    transition:0.8s cubic-bezier(0.16,1,0.32,1); pointer-events:none;
}
.DH_Notif_Box {
    display:flex; width:300px; padding:14px 16px;
    flex-direction:column; gap:3px;
    border-radius:16px;
    outline:2px solid rgb(var(--color-eel,117,117,117),0.10); outline-offset:-2px;
    background:rgb(var(--color-snow),0.90);
    backdrop-filter:blur(16px); -webkit-backdrop-filter:blur(16px);
    box-shadow:0 8px 32px rgba(0,0,0,0.12);
    transition:0.8s cubic-bezier(0.16,1,0.32,1); filter:blur(16px); opacity:0;
    pointer-events:auto;
}
.DH_Notif_Box.show { filter:blur(0px); opacity:1; }

.DH_Shop_Grid { display:grid; grid-template-columns:repeat(2,1fr); gap:8px; align-self:stretch; }
.DH_Shop_Card {
    display:flex; flex-direction:column; align-items:center;
    gap:6px; padding:12px 8px; border-radius:12px;
    outline:1.5px solid rgb(var(--color-eel,117,117,117),0.13); outline-offset:-1px;
    background:rgb(var(--color-eel,117,117,117),0.05);
    transition:outline-color 0.2s, background 0.2s; text-align:center;
}
.DH_Shop_Card:hover { outline-color:rgba(var(--DH-blue),0.30); background:rgba(var(--DH-blue),0.04); }
.DH_Shop_Ico { width:36px; height:36px; object-fit:contain; }
.DH_Shop_Name { font-size:11px; font-weight:700; color:rgb(var(--color-wolf,60,60,67),0.75); line-height:1.3; flex:1; }
.DH_Shop_Btn {
    width:100%; height:28px; border-radius:7px; border:none; cursor:pointer;
    font-size:11px; font-weight:800; color:#fff;
    background:rgb(var(--DH-blue));
    outline:2px solid rgba(0,0,0,0.20); outline-offset:-2px;
    transition:filter 0.4s cubic-bezier(0.16,1,0.32,1), transform 0.4s cubic-bezier(0.16,1,0.32,1), background 0.4s;
}
.DH_Shop_Btn:hover  { filter:brightness(0.88); transform:scale(1.03); }
.DH_Shop_Btn:active { transform:scale(0.97); }
.DH_Shop_Btn.loading { background:rgb(var(--color-eel,117,117,117),0.12); color:rgb(var(--color-eel,117,117,117),0.50); outline-color:rgb(var(--color-eel,117,117,117),0.18); pointer-events:none; }
.DH_Shop_Btn.got     { background:rgba(var(--DH-green),0.12); color:rgb(var(--DH-green)); outline-color:rgba(var(--DH-green),0.25); pointer-events:none; }
.DH_Shop_Btn.fail    { background:rgba(var(--DH-red),0.10); color:rgb(var(--DH-red)); outline-color:rgba(var(--DH-red),0.22); pointer-events:none; }
.DH_Cat_Header {
    align-self:stretch; font-size:11px; font-weight:800; text-transform:uppercase;
    letter-spacing:0.6px; color:rgb(var(--color-wolf,60,60,67),0.40);
    padding:4px 0 2px; text-align:center;
    border-bottom:1px solid rgb(var(--color-eel,117,117,117),0.10); margin-bottom:2px;
}

.DH_Scroll_Inner {
    align-self:stretch; overflow-y:auto;
    max-height:220px; display:flex; flex-direction:column; gap:6px; padding-right:2px;
}
.DH_Scroll_Inner::-webkit-scrollbar { width:3px; }
.DH_Scroll_Inner::-webkit-scrollbar-thumb { background:rgba(var(--DH-blue),0.2); border-radius:3px; }
.DH_Scroll_Inner { scrollbar-width:thin; scrollbar-color:rgba(var(--DH-blue),0.2) transparent; }
.DH_Credit_Card { display:flex; flex-direction:column; gap:6px; padding:10px 12px; border-radius:12px; background:rgba(var(--DH-blue),0.06); outline:1.5px solid rgba(var(--DH-blue),0.12); outline-offset:-1.5px; align-self:stretch; }
.DH_Credit_Card_Header { display:flex; align-items:center; gap:8px; }
.DH_Credit_Thumb { width:28px; height:28px; border-radius:8px; object-fit:cover; flex-shrink:0; background:rgba(var(--DH-blue),0.1); }
.DH_Credit_Script { font-size:13px; font-weight:800; color:rgb(var(--color-wolf,60,60,67)); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.DH_Credit_Author { font-size:11px; color:rgba(var(--color-wolf,60,60,67),0.55); }
.DH_Credit_Task { font-size:11px; color:rgba(var(--color-wolf,60,60,67),0.7); line-height:1.4; }
.DH_Credit_Link { font-size:11px; font-weight:700; color:rgb(var(--DH-blue)); text-decoration:none; }
.DH_Credit_Link:hover { opacity:0.75; }

.DH_Search {
    align-self:stretch; height:40px; padding:0 14px;
    border-radius:8px; border:none;
    outline:2px solid rgb(var(--color-eel,117,117,117),0.15); outline-offset:-2px;
    background:rgb(var(--color-eel,117,117,117),0.06);
    font-size:14px; font-weight:600;
    color:rgb(var(--color-wolf,60,60,67),0.80); transition:outline-color 0.2s;
}
.DH_Search:focus { outline-color:rgba(var(--DH-blue),0.35); }
.DH_Search::placeholder { color:rgb(var(--color-wolf,60,60,67),0.35); }

#DH_Extra_Panel { overflow:hidden; }

.DH_Btn_Ico {
    width:28px; height:28px; border-radius:7px; flex-shrink:0;
    background:rgba(var(--DH-blue),0.12);
    display:flex; align-items:center; justify-content:center;
}

.DH_Acc_Card {
    display:flex; align-items:center; gap:10px; align-self:stretch;
    padding:10px 12px; border-radius:12px;
    outline:1.5px solid rgb(var(--color-eel,117,117,117),0.13); outline-offset:-1px;
    background:rgb(var(--color-eel,117,117,117),0.05);
    transition:outline-color 0.2s, background 0.2s;
    position:relative; overflow:hidden;
}
.DH_Acc_Card:hover { outline-color:rgba(var(--DH-blue),0.30); background:rgba(var(--DH-blue),0.04); }
.DH_Acc_Avatar {
    width:36px; height:36px; border-radius:50%; flex-shrink:0;
    background:rgba(var(--DH-blue),0.10); overflow:hidden;
    display:flex; align-items:center; justify-content:center; font-size:16px;
}
.DH_Acc_Info { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
.DH_Acc_Name { font-size:13px!important; font-weight:700!important; color:rgb(var(--color-wolf,60,60,67),0.85)!important; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.DH_Acc_Sub  { font-size:11px!important; font-weight:600!important; color:rgb(var(--color-wolf,60,60,67),0.45)!important; }
.DH_Acc_Sub.active { color:rgb(var(--DH-green))!important; display:flex; align-items:center; gap:4px; }
.DH_Acc_Action_Row { display:flex; gap:5px; flex-shrink:0; }
.DH_Acc_Btn {
    height:26px; padding:0 8px; border-radius:7px; border:none; cursor:pointer;
    font-size:10px; font-weight:800; color:#fff;
    background:rgb(var(--DH-blue));
    outline:2px solid rgba(0,0,0,0.15); outline-offset:-2px;
    transition:filter 0.3s,transform 0.3s;
}
.DH_Acc_Btn:hover  { filter:brightness(0.88); transform:scale(1.06); }
.DH_Acc_Btn:active { transform:scale(0.95); }
.DH_Acc_Btn.del { background:rgba(var(--DH-red),0.10); color:rgb(var(--DH-red)); outline-color:rgba(var(--DH-red),0.20); }
.DH_Acc_Btn.del:hover { background:rgb(var(--DH-red)); color:#fff; }

.DH_Quest_Item {
    display:flex; align-items:center; gap:10px; align-self:stretch;
    padding:10px 12px; border-radius:12px;
    outline:1.5px solid rgb(var(--color-eel,117,117,117),0.13); outline-offset:-1px;
    background:rgb(var(--color-eel,117,117,117),0.05);
    transition:outline-color 0.2s, background 0.2s;
}
.DH_Quest_Item.done { outline-color:rgba(var(--DH-green),0.25); background:rgba(var(--DH-green),0.04); }
.DH_Quest_Icon { width:40px; height:40px; object-fit:contain; flex-shrink:0; }
.DH_Quest_Info { flex:1; min-width:0; display:flex; flex-direction:column; gap:3px; }
.DH_Quest_Title { font-size:12px!important; font-weight:700!important; color:rgb(var(--color-wolf,60,60,67),0.85)!important; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.DH_Quest_Meta  { font-size:10px!important; font-weight:600!important; color:rgb(var(--color-wolf,60,60,67),0.45)!important; }
.DH_Quest_Bar_Bg { height:4px; border-radius:2px; background:rgba(var(--DH-blue),0.10); overflow:hidden; align-self:stretch; }
.DH_Quest_Bar_Fill { height:100%; background:rgb(var(--DH-blue)); border-radius:2px; transition:width 0.5s; }
.DH_Quest_Item.done .DH_Quest_Bar_Fill { background:rgb(var(--DH-green)); }
.DH_Quest_Get_Btn {
    height:26px; padding:0 8px; flex-shrink:0; border-radius:7px; border:none; cursor:pointer;
    font-size:10px; font-weight:800; white-space:nowrap;
    background:rgb(var(--DH-blue)); color:#fff;
    outline:2px solid rgba(0,0,0,0.15); outline-offset:-2px;
    transition:filter 0.3s,transform 0.3s;
}
.DH_Quest_Get_Btn:hover  { filter:brightness(0.88); transform:scale(1.06); }
.DH_Quest_Get_Btn:active { transform:scale(0.95); }
.DH_Quest_Get_Btn.done { background:rgba(var(--DH-green),0.10); color:rgb(var(--DH-green)); outline-color:rgba(var(--DH-green),0.20); pointer-events:none; }

#DH_AccSettings_Btn        { transform-origin: right center; }
#DH_AccSettings_Btn:hover  { filter:brightness(0.85); transform:scale(1.1); }
#DH_AccSettings_Btn:active { transform:scale(0.92); }

/* PAGE 9: License */
#DH_Page_9 { flex:1; min-height:0; }
.DH_License_Scroll {
    flex:1;
    min-height:0;
    overflow-y:auto;
    overflow-x:hidden;
    padding:14px 16px;
    border-radius:12px;
    outline:2px solid rgba(var(--color-eel,117,117,117),0.10);
    outline-offset:-2px;
    background:rgba(var(--color-eel,117,117,117),0.04);
    align-self:stretch;
    max-height:320px;
}
.DH_License_Scroll::-webkit-scrollbar { width:3px; }
.DH_License_Scroll::-webkit-scrollbar-thumb { background:rgba(var(--color-eel,117,117,117),0.20); border-radius:2px; }
#DH_License_Text {
    font-size:11.5px;
    font-weight:600;
    line-height:1.65;
    color:rgb(var(--color-wolf,60,60,67),0.75);
    white-space:pre-wrap;
    margin:0;
    word-break:break-word;
}
@media (max-width:699px) {
    .DH_License_Scroll { max-height:calc(100svh - 240px); }
    .DH_Main { margin-bottom:80px; }
}

`);

const _wrap = document.createElement('div');
_wrap.id = 'DH_Root';
_wrap.innerHTML = `
<div class="DH_Notif_Main" id="DH_Notif_Main">
    <div class="DH_Notif_Box" id="DH_Notif_Box">
        <div class="DH_HStack_4" style="align-items:center;">
            <p class="DH_T1 DH_NoSel" id="DH_Notif_Icon" style="font-size:18px;flex-shrink:0;"></p>
            <p class="DH_T1 DH_NoSel" id="DH_Notif_Title" style="flex:1 0 0;"></p>
        </div>
        <p class="DH_T2 DH_NoSel" id="DH_Notif_Body" style="align-self:stretch;overflow-wrap:break-word;"></p>
    </div>
</div>

<div class="DH_Main" id="DH_Main">

    <div class="DH_HStack_8" style="align-self:flex-end;">
<div class="DH_Btn DH_Btn_Blue_Ghost DH_NoSel" id="DH_SwitchV1_Btn"
     style="flex:none; display:none; order:-1;">
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path d="M17 1l4 4-4 4" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
        <path d="M3 11V9a4 4 0 0 1 4-4h14" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
        <path d="M7 23l-4-4 4-4" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
        <path d="M21 13v2a4 4 0 0 1-4 4H3" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
    <p class="DH_T1 DH_NoSel" style="color:rgb(var(--DH-blue));font-size:13px;">Switch to V1</p>
</div>

<div class="DH_Btn DH_Btn_Blue_Ghost DH_NoSel" id="DH_SwitchV2_Btn"
     style="flex:none; display:none; order:-1;">
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path d="M17 1l4 4-4 4" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
        <path d="M3 11V9a4 4 0 0 1 4-4h14" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
        <path d="M7 23l-4-4 4-4" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
        <path d="M21 13v2a4 4 0 0 1-4 4H3" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
    </svg>
    <p class="DH_T1 DH_NoSel" style="color:rgb(var(--DH-blue));font-size:13px;">Switch to V2</p>
</div>
        <div class="DH_Btn DH_NoSel" id="DH_Hide_Btn"
             style="flex:none; outline:2px solid rgba(0,0,0,0.20); outline-offset:-2px; background:rgb(var(--DH-blue)); backdrop-filter:blur(16px);">
            <svg id="DH_Ico_Visible" width="18" height="12" viewBox="0 0 18 12" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="M9 0C5 0 1.73 2.5 0 6c1.73 3.5 5 6 9 6s7.27-2.5 9-6c-1.73-3.5-5-6-9-6zm0 10a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-6.4a2.4 2.4 0 1 0 0 4.8 2.4 2.4 0 0 0 0-4.8z" fill="#FFF"/>
                <path d="M1 1l16 10" stroke="#FFF" stroke-width="1.5" stroke-linecap="round"/>
            </svg>
            <svg id="DH_Ico_Hidden" width="18" height="12" viewBox="0 0 18 12" fill="none" xmlns="http://www.w3.org/2000/svg" style="display:none;">
                <path d="M9 0C5 0 1.73 2.5 0 6c1.73 3.5 5 6 9 6s7.27-2.5 9-6c-1.73-3.5-5-6-9-6zm0 10a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-6.4a2.4 2.4 0 1 0 0 4.8 2.4 2.4 0 0 0 0-4.8z" fill="rgb(var(--DH-blue))"/>
            </svg>
            <p class="DH_T1 DH_NoSel" id="DH_Hide_Txt" style="color:#fff;">Hide</p>
        </div>
    </div>

    <div class="DH_Main_Box" id="DH_Main_Box">

        <div class="DH_Page active" id="DH_Page_1">

            <div class="DH_HStack_8">
                <div class="DH_Btn DH_Btn_Eel DH_NoSel" id="DH_Conn_Btn" style="padding:10px 0 10px 10px; transition:background 0.8s cubic-bezier(0.16,1,0.32,1), outline 0.8s cubic-bezier(0.16,1,0.32,1), filter 0.4s cubic-bezier(0.16,1,0.32,1), transform 0.4s cubic-bezier(0.16,1,0.32,1);">
                    <p class="DH_T1 DH_NoSel DH_Spin_Ico" id="DH_Conn_Ico" style="color:rgb(var(--color-eel,117,117,117),0.70);">⟳</p>
                    <p class="DH_T1 DH_NoSel" id="DH_Conn_Txt" style="color:rgb(var(--color-eel,117,117,117),0.70);">Connecting</p>
                </div>
                <div class="DH_Btn DH_Btn_Icon DH_NoSel" id="DH_Discord_Btn" style="background:rgb(88,101,242);outline:2px solid rgba(0,0,0,.18);outline-offset:-2px;">
                    <svg width="18" height="14" viewBox="0 0 22 16" fill="#FFF"><path d="M18.289 1.34C16.9296.714 15.4761.259 13.9565 0c-.1866.332-.4046.779-.5549 1.134-1.6154-.239-3.2159-.239-4.8016 0C8.4497.779 8.2267.332 8.0384 0 6.5172.259 5.062.716 3.7027 1.343.9608 5.421.2175 9.398.5892 13.318c1.8185 1.337 3.5809 2.149 5.3136 2.68.4278-.579.8093-1.195 1.138-1.845-.6259-.234-1.2255-.523-1.7921-.858.1503-.11.2973-.225.4393-.307 3.4554 1.591 7.2098 1.591 10.624 0 .1437.118.2907.233.4393.342-.6262.337-1.2274.626-1.8534.86.3287.648.7086 1.265 1.138 1.845 1.7343-.531 3.4983-1.343 5.3168-2.681.4361-4.545-.7449-8.484-3.121-11.978ZM7.5115 10.908c-1.0373 0-1.8879-.954-1.8879-2.114 0-1.161.8325-2.115 1.8879-2.115 1.0555 0 1.9061.954 1.8879 2.115.0016 1.16-.8325 2.114-1.8879 2.114Zm6.9769 0c-1.0373 0-1.8879-.954-1.8879-2.114 0-1.161.8324-2.115 1.8879-2.115 1.0554 0 1.9061.954 1.8879 2.115 0 1.16-.8325 2.114-1.8879 2.114Z"/></svg>
                </div>
                <div class="DH_Btn DH_Btn_Icon DH_NoSel" id="DH_GitHub_Btn" style="background:#24292e;outline:2px solid rgba(255,255,255,.18);outline-offset:-2px;">
                    <svg width="18" height="18" viewBox="0 0 22 22" fill="#FFF"><path fill-rule="evenodd" clip-rule="evenodd" d="M11.009.5C5.198.5.5 5.313.5 11.266c0 4.759 3.01 8.788 7.186 10.214.522.107.713-.232.713-.517 0-.25-.017-1.105-.017-1.997-2.923.642-3.532-1.283-3.532-1.283-.47-1.248-1.166-1.568-1.166-1.568-.957-.659.07-.659.07-.659 1.062.071 1.619 1.105 1.619 1.105.94 1.64 2.453 1.176 3.062.891.087-.695.366-1.176.661-1.444-2.332-.25-4.785-1.176-4.785-5.312 0-1.176.418-2.139 1.08-2.887-.106-.267-.461-1.373.105-2.852 0 0 .888-.285 2.899 1.09a9.847 9.847 0 0 1 2.636-.356c.888 0 1.793.125 2.628.356 2.01-1.375 2.898-1.09 2.898-1.09.566 1.479.21 2.585.105 2.852.662.748 1.08 1.711 1.08 2.887 0 4.136-2.453 5.045-4.803 5.312.383.338.714.98.714 2.004 0 1.444-.018 2.606-.018 2.963 0 .285.192.624.714.48C18.49 20.054 21.5 16.025 21.5 11.266 21.517 5.313 16.802.5 11.009.5Z"/></svg>
                </div>
            </div>

            <div class="DH_HStack_8" id="DH_User_Row" style="display:none;gap:10px;">
                <div class="DH_Avatar" id="DH_Avatar">👤</div>
                <div class="DH_VStack_4" style="flex:1 0 0;min-width:0;align-items:flex-start;">
                    <p class="DH_T1 DH_NoSel" id="DH_UName" style="font-size:14px;align-self:stretch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;"></p>
                    <div class="DH_HStack_4" style="gap:10px;">
                        <div class="DH_HStack_4" style="gap:3px;">
                            <img class="DH_Stat_Ico" src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/01ce3a817dd01842581c3d18debcbc46.svg">
                            <span class="DH_Stat_Val DH_NoSel" id="DH_UXP">0</span>
                        </div>
                        <div class="DH_HStack_4" style="gap:3px;">
                            <img class="DH_Stat_Ico" src="https://d35aaqx5ub95lt.cloudfront.net/images/gems/45c14e05be9c1af1d7d0b54c6eed7eee.svg">
                            <span class="DH_Stat_Val DH_NoSel" id="DH_UGems">0</span>
                        </div>
                        <div class="DH_HStack_4" style="gap:3px;">
                            <img class="DH_Stat_Ico" src="https://d35aaqx5ub95lt.cloudfront.net/images/icons/398e4298a3b39ce566050e5c041949ef.svg">
                            <span class="DH_Stat_Val DH_NoSel" id="DH_UStreak">0</span>
                        </div>
                    </div>
                </div>
                <svg id="DH_AccSettings_Btn" width="24" height="24" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg" title="Account Manager"
                     style="cursor:pointer;flex-shrink:0;transition:filter 0.3s,transform 0.3s;transform-origin:center;">
                    <path d="M18.1,11c-3.9,0-7,3.1-7,7s3.1,7,7,7c3.9,0,7-3.1,7-7S22,11,18.1,11z M18.1,23c-2.8,0-5-2.2-5-5s2.2-5,5-5c2.8,0,5,2.2,5,5S20.9,23,18.1,23z" fill="rgb(var(--DH-blue))" stroke="rgb(var(--DH-blue))" stroke-width="1.2" stroke-linejoin="round" paint-order="stroke fill"/>
                    <path d="M32.8,14.7L30,13.8l-0.6-1.5l1.4-2.6c0.3-0.6,0.2-1.4-0.3-1.9l-2.4-2.4c-0.5-0.5-1.3-0.6-1.9-0.3l-2.6,1.4l-1.5-0.6l-0.9-2.8C21,2.5,20.4,2,19.7,2h-3.4c-0.7,0-1.3,0.5-1.4,1.2L14,6c-0.6,0.1-1.1,0.3-1.6,0.6L9.8,5.2C9.2,4.9,8.4,5,7.9,5.5L5.5,7.9C5,8.4,4.9,9.2,5.2,9.8l1.3,2.5c-0.2,0.5-0.4,1.1-0.6,1.6l-2.8,0.9C2.5,15,2,15.6,2,16.3v3.4c0,0.7,0.5,1.3,1.2,1.5L6,22.1l0.6,1.5l-1.4,2.6c-0.3,0.6-0.2,1.4,0.3,1.9l2.4,2.4c0.5,0.5,1.3,0.6,1.9,0.3l2.6-1.4l1.5,0.6l0.9,2.9c0.2,0.6,0.8,1.1,1.5,1.1h3.4c0.7,0,1.3-0.5,1.5-1.1l0.9-2.9l1.5-0.6l2.6,1.4c0.6,0.3,1.4,0.2,1.9-0.3l2.4-2.4c0.5-0.5,0.6-1.3,0.3-1.9l-1.4-2.6l0.6-1.5l2.9-0.9c0.6-0.2,1.1-0.8,1.1-1.5v-3.4C34,15.6,33.5,14.9,32.8,14.7z M32,19.4l-3.6,1.1L28.3,21c-0.3,0.7-0.6,1.4-0.9,2.1l-0.3,0.5l1.8,3.3l-2,2l-3.3-1.8l-0.5,0.3c-0.7,0.4-1.4,0.7-2.1,0.9l-0.5,0.1L19.4,32h-2.8l-1.1-3.6L15,28.3c-0.7-0.3-1.4-0.6-2.1-0.9l-0.5-0.3l-3.3,1.8l-2-2l1.8-3.3l-0.3-0.5c-0.4-0.7-0.7-1.4-0.9-2.1l-0.1-0.5L4,19.4v-2.8l3.4-1l0.2-0.5c0.2-0.8,0.5-1.5,0.9-2.2l0.3-0.5L7.1,9.1l2-2l3.2,1.8l0.5-0.3c0.7-0.4,1.4-0.7,2.2-0.9l0.5-0.2L16.6,4h2.8l1.1,3.5L21,7.7c0.7,0.2,1.4,0.5,2.1,0.9l0.5,0.3l3.3-1.8l2,2l-1.8,3.3l0.3,0.5c0.4,0.7,0.7,1.4,0.9,2.1l0.1,0.5l3.6,1.1V19.4z" fill="rgb(var(--DH-blue))" stroke="rgb(var(--DH-blue))" stroke-width="1.2" stroke-linejoin="round" paint-order="stroke fill"/>
                </svg>
            </div>

            <div class="DH_Divider"></div>

                   <div class="DH_VStack_8">
                <p class="DH_T1 DH_NoSel" style="align-self:stretch;">How much XP would you like to gain?</p>
                <div class="DH_HStack_8">
                    <div class="DH_Input_Wrap">
                        <p class="DH_T1 DH_NoSel" style="color:rgba(var(--DH-blue),0.38);font-size:13px;flex-shrink:0;">#</p>
                        <input type="number" class="DH_Input DH_NoSel" id="DH_XP_Input" placeholder="0" min="30" max="500000">
                    </div>
                    <button class="DH_Input_Btn DH_NoSel" id="DH_XP_Btn" disabled>
                        <span class="DH_Btn_Label" id="DH_XP_Lbl" style="color:#fff;">GET</span>
                    </button>
                </div>
                <div class="DH_Prog_Wrap" id="DH_XP_Prog"><div class="DH_Prog_Fill" id="DH_XP_Fill"></div></div>
            </div>


            <div class="DH_VStack_8">
                <p class="DH_T1 DH_NoSel" style="align-self:stretch;">How many Gems would you like to gain?</p>
                <div class="DH_HStack_8">
                    <div class="DH_Input_Wrap">
                        <svg class="DH_Shimmer" width="120" height="48" viewBox="0 0 120 48" fill="none">
                            <path opacity="0.4" d="M72 0H96L72 48H48L72 0Z" fill="rgb(var(--DH-blue))"/>
                            <path opacity="0.4" d="M24 0H60L36 48H0L24 0Z" fill="rgb(var(--DH-blue))"/>
                            <path opacity="0.4" d="M108 0H120L96 48H84L108 0Z" fill="rgb(var(--DH-blue))"/>
                        </svg>
                        <p class="DH_T1 DH_NoSel" style="color:rgba(var(--DH-blue),0.38);font-size:14px;flex-shrink:0;">#</p>
                        <input type="number" class="DH_Input DH_NoSel" id="DH_Gem_Input" placeholder="0" min="1" max="500000">
                    </div>
                    <button class="DH_Input_Btn DH_NoSel" id="DH_Gem_Btn" disabled>
                        <span class="DH_Btn_Label" id="DH_Gem_Lbl" style="color:#fff;">GET</span>
                    </button>
                </div>
                <div class="DH_Prog_Wrap" id="DH_Gem_Prog"><div class="DH_Prog_Fill" id="DH_Gem_Fill"></div></div>
            </div>


            <div class="DH_VStack_8">
                <p class="DH_T1 DH_NoSel" style="align-self:stretch;">How many Streak days to restore?</p>
                <div class="DH_HStack_8">
                    <div class="DH_Input_Wrap">
                        <p class="DH_T1 DH_NoSel" style="color:rgba(var(--DH-blue),0.38);font-size:14px;flex-shrink:0;">#</p>
                        <input type="number" class="DH_Input DH_NoSel" id="DH_Streak_Input" placeholder="0" min="1" max="3650">
                    </div>
                    <button class="DH_Input_Btn DH_NoSel" id="DH_Streak_Btn" disabled>
                        <span class="DH_Btn_Label" id="DH_Streak_Lbl" style="color:#fff;">RUN</span>
                    </button>
                </div>
                <div class="DH_Prog_Wrap" id="DH_Streak_Prog"><div class="DH_Prog_Fill" id="DH_Streak_Fill"></div></div>
            </div>

            <div class="DH_Divider"></div>


            <div class="DH_Btn DH_Btn_Blue_Ghost DH_NoSel" id="DH_Settings_Btn" style="align-self:stretch; justify-content:space-between; padding:10px 12px;">
                <div style="display:flex; align-items:center; gap:8px;">
                    <div class="DH_Btn_Ico">
                        <svg width="18" height="18" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
                            <path fill="rgb(var(--DH-blue))" d="M39,15c0-2.2-1.8-4-4-4h-6c-0.7,0-1.1-0.8-0.7-1.4c0.6-1,0.9-2.2,0.6-3.5c-0.4-2-1.9-3.6-3.8-4C21.8,1.4,19,3.9,19,7c0,1,0.3,1.8,0.7,2.6c0.4,0.6,0,1.4-0.8,1.4h-6c-2.2,0-4,1.8-4,4v7c0,0.7,0.8,1.1,1.4,0.7c1-0.6,2.2-0.9,3.5-0.6c2,0.4,3.6,1.9,4,3.8c0.7,3.2-1.8,6.1-4.9,6.1c-1,0-1.8-0.3-2.6-0.7C9.8,30.9,9,31.3,9,32v6c0,2.2,1.8,4,4,4h22c2.2,0,4-1.8,4-4V15z"/>
                        </svg>
                    </div>
                    <p class="DH_T1 DH_NoSel" style="color:rgb(var(--DH-blue));">Extra Features</p>
                </div>
                <svg width="8" height="13" viewBox="0 0 8 13" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M1 1l6 5.5L1 12" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                </svg>
            </div>


            <div class="DH_Btn DH_Btn_Blue_Ghost DH_NoSel" id="DH_Page4_Btn" style="align-self:stretch; justify-content:space-between; padding:10px 12px;">
                <div style="display:flex; align-items:center; gap:8px;">
                    <div class="DH_Btn_Ico">

                        <svg width="16" height="16" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
                            <path d="M18.1,11c-3.9,0-7,3.1-7,7s3.1,7,7,7c3.9,0,7-3.1,7-7S22,11,18.1,11z M18.1,23c-2.8,0-5-2.2-5-5s2.2-5,5-5c2.8,0,5,2.2,5,5S20.9,23,18.1,23z" fill="rgb(var(--DH-blue))" stroke="rgb(var(--DH-blue))" stroke-width="1.2" stroke-linejoin="round" paint-order="stroke fill"/>
                            <path d="M32.8,14.7L30,13.8l-0.6-1.5l1.4-2.6c0.3-0.6,0.2-1.4-0.3-1.9l-2.4-2.4c-0.5-0.5-1.3-0.6-1.9-0.3l-2.6,1.4l-1.5-0.6l-0.9-2.8C21,2.5,20.4,2,19.7,2h-3.4c-0.7,0-1.3,0.5-1.4,1.2L14,6c-0.6,0.1-1.1,0.3-1.6,0.6L9.8,5.2C9.2,4.9,8.4,5,7.9,5.5L5.5,7.9C5,8.4,4.9,9.2,5.2,9.8l1.3,2.5c-0.2,0.5-0.4,1.1-0.6,1.6l-2.8,0.9C2.5,15,2,15.6,2,16.3v3.4c0,0.7,0.5,1.3,1.2,1.5L6,22.1l0.6,1.5l-1.4,2.6c-0.3,0.6-0.2,1.4,0.3,1.9l2.4,2.4c0.5,0.5,1.3,0.6,1.9,0.3l2.6-1.4l1.5,0.6l0.9,2.9c0.2,0.6,0.8,1.1,1.5,1.1h3.4c0.7,0,1.3-0.5,1.5-1.1l0.9-2.9l1.5-0.6l2.6,1.4c0.6,0.3,1.4,0.2,1.9-0.3l2.4-2.4c0.5-0.5,0.6-1.3,0.3-1.9l-1.4-2.6l0.6-1.5l2.9-0.9c0.6-0.2,1.1-0.8,1.1-1.5v-3.4C34,15.6,33.5,14.9,32.8,14.7z M32,19.4l-3.6,1.1L28.3,21c-0.3,0.7-0.6,1.4-0.9,2.1l-0.3,0.5l1.8,3.3l-2,2l-3.3-1.8l-0.5,0.3c-0.7,0.4-1.4,0.7-2.1,0.9l-0.5,0.1L19.4,32h-2.8l-1.1-3.6L15,28.3c-0.7-0.3-1.4-0.6-2.1-0.9l-0.5-0.3l-3.3,1.8l-2-2l1.8-3.3l-0.3-0.5c-0.4-0.7-0.7-1.4-0.9-2.1l-0.1-0.5L4,19.4v-2.8l3.4-1l0.2-0.5c0.2-0.8,0.5-1.5,0.9-2.2l0.3-0.5L7.1,9.1l2-2l3.2,1.8l0.5-0.3c0.7-0.4,1.4-0.7,2.2-0.9l0.5-0.2L16.6,4h2.8l1.1,3.5L21,7.7c0.7,0.2,1.4,0.5,2.1,0.9l0.5,0.3l3.3-1.8l2,2l-1.8,3.3l0.3,0.5c0.4,0.7,0.7,1.4,0.9,2.1l0.1,0.5l3.6,1.1V19.4z" fill="rgb(var(--DH-blue))" stroke="rgb(var(--DH-blue))" stroke-width="1.2" stroke-linejoin="round" paint-order="stroke fill"/>
                        </svg>
                    </div>
                    <p class="DH_T1 DH_NoSel" style="color:rgb(var(--DH-blue));">Settings</p>
                </div>
                <svg width="8" height="13" viewBox="0 0 8 13" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M1 1l6 5.5L1 12" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                </svg>
            </div>

            <div class="DH_HStack_Auto">
                <p class="DH_T2 DH_NoSel" style="color:rgba(var(--DH-blue),0.45);">twisk.fun</p>
                <p class="DH_T2 DH_NoSel" style="color:rgba(var(--DH-blue),0.45);">v2026.04.27</p>
            </div>
        </div>


        <div class="DH_Page" id="DH_Page_2">
            <div class="DH_HStack_4 DH_NoSel" id="DH_Back_Btn" style="align-self:flex-start;cursor:pointer;opacity:0.55;">
                <svg width="8" height="14" viewBox="0 0 9 16" fill="none"><path d="M8 1L2 8l6 7" stroke="rgb(var(--color-wolf,60,60,67))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
                <p class="DH_T1">Back</p>
            </div>

            <div class="DH_HStack_Auto" style="align-self:stretch;">
                <div style="display:flex;flex-direction:column;gap:2px;flex:1;min-width:0;">
                    <p class="DH_T1 DH_NoSel">Farm Practice</p>
                    <p class="DH_T2 DH_NoSel" style="font-size:11px;">0 = unlimited practice sessions</p>
                </div>
                <button class="DH_Sm_Btn DH_NoSel" id="DH_Practice_Btn" disabled>
                    <span class="DH_Sm_Btn_Label" id="DH_Practice_Lbl" style="color:#fff;">RUN</span>
                </button>
            </div>
            <!-- Practice input inline below button -->
            <div style="display:flex;align-items:center;gap:8px;align-self:stretch;">
                <div class="DH_Input_Wrap" style="flex:1;">
                    <p class="DH_T1 DH_NoSel" style="color:rgba(var(--DH-blue),0.38);font-size:14px;flex-shrink:0;">#</p>
                    <input type="number" class="DH_Input DH_NoSel" id="DH_Practice_Input" placeholder="0" min="0" max="9999">
                </div>
            </div>

            <div class="DH_Divider"></div>

            <!-- Shop Items nav -->
            <div class="DH_Btn DH_Btn_Blue_Ghost DH_NoSel" id="DH_Shop_Btn" style="align-self:stretch;justify-content:space-between;padding:10px 12px;">
                <div style="display:flex;align-items:center;gap:8px;">
                    <div class="DH_Btn_Ico">
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                            <path d="M22.36 8.27L22.07 5.5C21.65 2.48 20.28 1.25 17.35 1.25H14.99H13.51H10.47H8.99H6.59C3.65 1.25 2.29 2.48 1.86 5.53L1.59 8.28C1.49 9.35 1.78 10.39 2.41 11.2C3.17 12.19 4.34 12.75 5.64 12.75C6.9 12.75 8.11 12.12 8.87 11.11C9.55 12.12 10.71 12.75 12 12.75C13.29 12.75 14.42 12.15 15.11 11.15C15.88 12.14 17.07 12.75 18.31 12.75C19.64 12.75 20.84 12.16 21.59 11.12C22.19 10.32 22.46 9.31 22.36 8.27Z" fill="rgb(var(--DH-blue))"/>
                            <path d="M11.35 16.66C10.08 16.79 9.12 17.87 9.12 19.15V21.89C9.12 22.16 9.34 22.38 9.61 22.38H14.38C14.65 22.38 14.87 22.16 14.87 21.89V19.5C14.88 17.41 13.65 16.42 11.35 16.66Z" fill="rgb(var(--DH-blue))"/>
                            <path d="M21.37 14.4V17.38C21.37 20.14 19.13 22.38 16.37 22.38C16.1 22.38 15.88 22.16 15.88 21.89V19.5C15.88 18.22 15.49 17.22 14.73 16.54C14.06 15.93 13.15 15.63 12.02 15.63C11.77 15.63 11.52 15.64 11.25 15.67C9.47 15.85 8.12 17.35 8.12 19.15V21.89C8.12 22.16 7.9 22.38 7.63 22.38C4.87 22.38 2.63 20.14 2.63 17.38V14.42C2.63 13.72 3.32 13.25 3.97 13.48C4.24 13.57 4.51 13.64 4.79 13.68C4.91 13.7 5.04 13.72 5.16 13.72C5.32 13.74 5.48 13.75 5.64 13.75C6.8 13.75 7.94 13.32 8.84 12.58C9.7 13.32 10.82 13.75 12 13.75C13.19 13.75 14.29 13.34 15.15 12.6C16.05 13.33 17.17 13.75 18.31 13.75C18.49 13.75 18.67 13.74 18.84 13.72C18.96 13.71 19.07 13.7 19.18 13.68C19.49 13.64 19.77 13.55 20.05 13.46C20.7 13.24 21.37 13.72 21.37 14.4Z" fill="rgb(var(--DH-blue))"/>
                        </svg>
                    </div>
                    <p class="DH_T1 DH_NoSel" style="color:rgb(var(--DH-blue));">Shop Items</p>
                </div>
                <svg width="8" height="13" viewBox="0 0 8 13" fill="none"><path d="M1 1l6 5.5L1 12" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
            </div>

            <!-- Auto League -->
            <div class="DH_HStack_Auto" style="align-self:stretch;">
                <div style="display:flex;flex-direction:column;gap:2px;flex:1;min-width:0;">
                    <p class="DH_T1 DH_NoSel">Auto League #1</p>
                    <p class="DH_T2 DH_NoSel" style="font-size:11px;">Farm XP until rank #1</p>
                </div>
                <button class="DH_Sm_Btn DH_NoSel" id="DH_League_Btn" disabled>
                    <span class="DH_Sm_Btn_Label" id="DH_League_Lbl" style="color:#fff;">RUN</span>
                </button>
            </div>
            <div class="DH_Prog_Wrap" id="DH_League_Prog" style="align-self:stretch;"><div class="DH_Prog_Fill" id="DH_League_Fill"></div></div>

            <!-- Auto Daily Quest - SIMPLIFIED -->
            <div class="DH_HStack_Auto" style="align-self:stretch;">
                <div style="display:flex;flex-direction:column;gap:2px;flex:1;min-width:0;">
                    <p class="DH_T1 DH_NoSel">Auto Daily Quest</p>
                    <p class="DH_T2 DH_NoSel" style="font-size:11px;">Complete all daily quests</p>
                </div>
                <button class="DH_Sm_Btn DH_NoSel" id="DH_Quest_Btn" disabled>
                    <span class="DH_Sm_Btn_Label" id="DH_Quest_Lbl" style="color:#fff;">RUN</span>
                </button>
            </div>

            <!-- Monthly Quest -->
            <div class="DH_HStack_Auto" style="align-self:stretch;cursor:pointer;" id="DH_MonthlyQuest_Nav_Btn">
                <div style="display:flex;flex-direction:column;gap:2px;flex:1;min-width:0;">
                    <p class="DH_T1 DH_NoSel">Claim Monthly Quest</p>
                    <p class="DH_T2 DH_NoSel" style="font-size:11px;">View &amp; claim monthly quests</p>
                </div>
                <button class="DH_Sm_Btn DH_NoSel" id="DH_MonthlyQuest_Claim_Btn" disabled>
                    <span class="DH_Sm_Btn_Label" style="color:#fff;">GET</span>
                </button>
            </div>

            <div class="DH_Divider"></div>
        </div>

        <!-- PAGE 4: Settings -->
        <div class="DH_Page" id="DH_Page_4">
            <div class="DH_HStack_4 DH_NoSel" id="DH_Settings_Back_Btn" style="align-self:flex-start;cursor:pointer;opacity:0.55;">
                <svg width="8" height="14" viewBox="0 0 9 16" fill="none"><path d="M8 1L2 8l6 7" stroke="rgb(var(--color-wolf,60,60,67))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
                <p class="DH_T1">Back</p>
            </div>
            <div style="width:100%;gap:8px;display:flex;flex-direction:column;align-items:flex-start;overflow-y:auto;max-height:360px;padding-right:2px;" class="DH_Scroll_Inner">

            <!-- Loop Delay -->
            <div class="DH_VStack_8" style="align-self:stretch;">
                <p class="DH_T1 DH_NoSel" style="align-self:stretch;">Loop delay (ms)</p>
                <div class="DH_HStack_8">
                    <div class="DH_Input_Wrap">
                        <p class="DH_T1 DH_NoSel" style="color:rgba(var(--DH-blue),0.50);font-size:13px;flex-shrink:0;">ms</p>
                        <input type="number" class="DH_Input DH_NoSel" id="DH_Delay_Input" placeholder="500" min="0" max="10000">
                    </div>
                    <button class="DH_Input_Btn DH_NoSel" id="DH_Delay_Btn">
                        <span class="DH_Btn_Label" id="DH_Delay_Lbl" style="color:#fff;">SAVE</span>
                    </button>
                </div>
            </div>

            <div class="DH_Divider"></div>

            <!-- Free Duolingo Max toggle -->
            <div class="DH_HStack_Auto" style="align-self:stretch;padding:4px 0;">
                <div style="display:flex;flex-direction:column;gap:2px;">
                    <p class="DH_T1 DH_NoSel">Free Duolingo Max</p>
                    <p class="DH_T2 DH_NoSel" style="font-size:11px;">Client-side only, reload to apply</p>
                </div>
                <label class="DH_Toggle">
                    <input type="checkbox" id="DH_Super_Toggle">
                    <span class="DH_Toggle_Slider"></span>
                </label>
            </div>

            <!-- Hide Profile toggle -->
            <div class="DH_HStack_Auto" style="align-self:stretch;padding:4px 0;">
                <div style="display:flex;flex-direction:column;gap:2px;">
                    <p class="DH_T1 DH_NoSel">Hide Profile</p>
                    <p class="DH_T2 DH_NoSel" id="DH_HideProfile_Status" style="font-size:11px;">Loading…</p>
                </div>
                <label class="DH_Toggle">
                    <input type="checkbox" id="DH_HideProfile_Toggle" disabled>
                    <span class="DH_Toggle_Slider"></span>
                </label>
            </div>

            <!-- Inject Solver toggle -->
            <div class="DH_HStack_Auto" style="align-self:stretch;padding:4px 0;">
                <div style="display:flex;flex-direction:column;gap:2px;">
                    <p class="DH_T1 DH_NoSel">Auto Solver</p>
                    <p class="DH_T2 DH_NoSel" style="font-size:11px;">Show Auto Solver buttons during lessons</p>
                </div>
                <label class="DH_Toggle">
                    <input type="checkbox" id="DH_Solver_Toggle">
                    <span class="DH_Toggle_Slider"></span>
                </label>
            </div>

            <!-- Hide Animation toggle -->
            <div class="DH_HStack_Auto" style="align-self:stretch;padding:4px 0;">
                <div style="display:flex;flex-direction:column;gap:2px;">
                    <p class="DH_T1 DH_NoSel">Hide Animation</p>
                    <p class="DH_T2 DH_NoSel" style="font-size:11px;">Hide Duolingo images &amp; animations</p>
                </div>
                <label class="DH_Toggle">
                    <input type="checkbox" id="DH_HideAnim_Toggle">
                    <span class="DH_Toggle_Slider"></span>
                </label>
            </div>



            <div class="DH_Divider"></div>
            <div class="DH_HStack_Auto" style="align-self:stretch;padding:2px 0;">
                <p class="DH_T2 DH_NoSel" id="DH_License_Open_Btn" style="color:rgba(var(--DH-blue),0.45);cursor:pointer;text-decoration:underline;text-underline-offset:2px;">DuoHacker V2</p>
                <p class="DH_T2 DH_NoSel" id="DH_Credits_Btn" style="color:rgb(var(--DH-blue));cursor:pointer;font-weight:700;text-decoration:underline;text-underline-offset:2px;">View Credits</p>
            </div>
            </div>
        </div>

        <!-- PAGE 9: License -->
        <div class="DH_Page" id="DH_Page_9" style="flex:1;min-height:0;">
            <div class="DH_HStack_4 DH_NoSel" id="DH_License_Back_Btn" style="align-self:flex-start;cursor:pointer;opacity:0.55;">
                <svg width="8" height="14" viewBox="0 0 9 16" fill="none"><path d="M8 1L2 8l6 7" stroke="rgb(var(--color-wolf,60,60,67))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
                <p class="DH_T1">Back</p>
            </div>
            <div class="DH_HStack_Auto DH_NoSel" style="align-self:stretch;">
                <p class="DH_T1" style="font-size:15px;">BY-NC-ND 4.0 License</p>
                <p class="DH_T2" style="font-size:11px;color:rgba(var(--DH-blue),0.50);">DuoHacker</p>
            </div>
            <div class="DH_License_Scroll">
                <p id="DH_License_Text" class="DH_NoSel">Loading…</p>
            </div>
        </div>

        <!-- PAGE 3: Shop -->
        <div class="DH_Page" id="DH_Page_3">
            <div class="DH_HStack_4 DH_NoSel" id="DH_Shop_Back_Btn" style="align-self:flex-start;cursor:pointer;opacity:0.55;">
                <svg width="8" height="14" viewBox="0 0 9 16" fill="none"><path d="M8 1L2 8l6 7" stroke="rgb(var(--color-wolf,60,60,67))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
                <p class="DH_T1">Back</p>
            </div>

            <input type="text" class="DH_Search DH_NoSel" id="DH_Shop_Search" placeholder="Search items...">

            <!-- Shop scrollable container -->
            <div class="DH_Scroll_Inner" id="DH_Shop_Container" style="max-height:300px;">
                <p class="DH_T2 DH_NoSel" style="text-align:center;padding:8px 0;">Loading shop...</p>
            </div>
        </div>

        <!-- PAGE 5: Account Manager -->
        <div class="DH_Page" id="DH_Page_5">
            <div class="DH_HStack_4 DH_NoSel" id="DH_AccMgr_Back_Btn" style="align-self:flex-start;cursor:pointer;opacity:0.55;">
                <svg width="8" height="14" viewBox="0 0 9 16" fill="none"><path d="M8 1L2 8l6 7" stroke="rgb(var(--color-wolf,60,60,67))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
                <p class="DH_T1">Back</p>
            </div>

            <div class="DH_HStack_Auto" style="align-self:stretch;">
                <p class="DH_T1 DH_NoSel" style="font-size:14px;font-weight:800;">Account Manager</p>
                <button class="DH_Sm_Btn DH_NoSel" id="DH_AccSave_Btn" disabled style="height:30px;padding:0 12px;">
                    <span class="DH_Sm_Btn_Label" style="color:#fff;font-size:11px;">SAVE CURRENT</span>
                </button>
            </div>

            <div class="DH_Divider"></div>

            <div id="DH_AccList_Wrap" class="DH_Scroll_Inner" style="max-height:260px;width:100%;gap:6px;">
                <p class="DH_T2 DH_NoSel" style="text-align:center;padding:8px 0;">No saved accounts.</p>
            </div>
        </div>

        <!-- PAGE 7: Credits -->
        <div class="DH_Page" id="DH_Page_7">
            <div class="DH_HStack_4 DH_NoSel" id="DH_Credits_Back_Btn" style="align-self:flex-start;cursor:pointer;opacity:0.55;">
                <svg width="8" height="14" viewBox="0 0 9 16" fill="none"><path d="M8 1L2 8l6 7" stroke="rgb(var(--color-wolf,60,60,67))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
                <p class="DH_T1">Back</p>
            </div>
            <p class="DH_T1 DH_NoSel" style="font-size:14px;font-weight:800;align-self:stretch;">Credits</p>
            <div class="DH_Divider"></div>
            <div id="DH_Credits_Container" class="DH_Scroll_Inner" style="max-height:280px;width:100%;gap:10px;">
            </div>
        </div>

        <!-- PAGE 6: Monthly Quests -->
        <div class="DH_Page" id="DH_Page_6">
            <div class="DH_HStack_4 DH_NoSel" id="DH_MQ_Back_Btn" style="align-self:flex-start;cursor:pointer;opacity:0.55;">
                <svg width="8" height="14" viewBox="0 0 9 16" fill="none"><path d="M8 1L2 8l6 7" stroke="rgb(var(--color-wolf,60,60,67))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
                <p class="DH_T1">Back</p>
            </div>

            <div class="DH_HStack_Auto" style="align-self:stretch;">
                <p class="DH_T1 DH_NoSel" style="font-size:14px;font-weight:800;">Monthly Quests</p>
                <button class="DH_Sm_Btn DH_NoSel" id="DH_MQ_ClaimAll_Btn" disabled style="height:30px;padding:0 12px;">
                    <span class="DH_Sm_Btn_Label" style="color:#fff;font-size:11px;">CLAIM</span>
                </button>
            </div>

            <div class="DH_Divider"></div>

            <div id="DH_MQ_Container" class="DH_Scroll_Inner" style="max-height:300px;width:100%;">
                <p class="DH_T2 DH_NoSel" style="text-align:center;padding:8px 0;">Loading quests...</p>
            </div>
        </div>

        <!-- PAGE 8: V1 Mode — simple farm with live counters, no extra features -->
        <div class="DH_Page" id="DH_Page_V1">

            <div class="DH_Divider"></div>

            <!-- User row (reused from V2 data) -->
            <div class="DH_HStack_8" id="DH_V1_User_Row" style="display:none;gap:10px;">
                <div class="DH_Avatar" id="DH_V1_Avatar">👤</div>
                <div class="DH_VStack_4" style="flex:1 0 0;min-width:0;align-items:flex-start;">
                    <p class="DH_T1 DH_NoSel" id="DH_V1_UName" style="font-size:14px;align-self:stretch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;"></p>
                    <div class="DH_HStack_4" style="gap:10px;">
                        <div class="DH_HStack_4" style="gap:3px;">
                            <img class="DH_Stat_Ico" src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/01ce3a817dd01842581c3d18debcbc46.svg">
                            <span class="DH_Stat_Val DH_NoSel" id="DH_V1_UXP">0</span>
                        </div>
                        <div class="DH_HStack_4" style="gap:3px;">
                            <img class="DH_Stat_Ico" src="https://d35aaqx5ub95lt.cloudfront.net/images/gems/45c14e05be9c1af1d7d0b54c6eed7eee.svg">
                            <span class="DH_Stat_Val DH_NoSel" id="DH_V1_UGems">0</span>
                        </div>
                        <div class="DH_HStack_4" style="gap:3px;">
                            <img class="DH_Stat_Ico" src="https://d35aaqx5ub95lt.cloudfront.net/images/icons/398e4298a3b39ce566050e5c041949ef.svg">
                            <span class="DH_Stat_Val DH_NoSel" id="DH_V1_UStreak">0</span>
                        </div>
                    </div>
                </div>
            </div>

            <div class="DH_Divider" id="DH_V1_User_Divider" style="display:none;"></div>

            <!-- XP Farm -->
            <div class="DH_VStack_8" style="align-self:stretch;">
                <p class="DH_T1 DH_NoSel" style="align-self:stretch;">XP Farming</p>
                <div class="DH_HStack_8">
                    <div class="DH_Input_Wrap">
                        <img class="DH_Stat_Ico" src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/01ce3a817dd01842581c3d18debcbc46.svg" style="flex-shrink:0;">
                        <input type="number" class="DH_Input DH_NoSel" id="DH_V1_XP_Input" placeholder="0" readonly style="pointer-events:none;">
                    </div>
                    <button class="DH_Input_Btn DH_NoSel" id="DH_V1_XP_Btn" disabled>
                        <span class="DH_Btn_Label" id="DH_V1_XP_Lbl" style="color:#fff;">RUN</span>
                    </button>
                </div>
                <div class="DH_Prog_Wrap" id="DH_V1_XP_Prog"><div class="DH_Prog_Fill" id="DH_V1_XP_Fill"></div></div>
            </div>

            <!-- Gems Farm -->
            <div class="DH_VStack_8" style="align-self:stretch;">
                <p class="DH_T1 DH_NoSel" style="align-self:stretch;">Gems Farming</p>
                <div class="DH_HStack_8">
                    <div class="DH_Input_Wrap">
                        <img class="DH_Stat_Ico" src="https://d35aaqx5ub95lt.cloudfront.net/images/gems/45c14e05be9c1af1d7d0b54c6eed7eee.svg" style="flex-shrink:0;">
                        <input type="number" class="DH_Input DH_NoSel" id="DH_V1_Gem_Input" placeholder="0" readonly style="pointer-events:none;">
                    </div>
                    <button class="DH_Input_Btn DH_NoSel" id="DH_V1_Gem_Btn" disabled>
                        <span class="DH_Btn_Label" id="DH_V1_Gem_Lbl" style="color:#fff;">RUN</span>
                    </button>
                </div>
                <div class="DH_Prog_Wrap" id="DH_V1_Gem_Prog"><div class="DH_Prog_Fill" id="DH_V1_Gem_Fill"></div></div>
            </div>

            <!-- Streak Farm -->
            <div class="DH_VStack_8" style="align-self:stretch;">
                <p class="DH_T1 DH_NoSel" style="align-self:stretch;">Streak Farming</p>
                <div class="DH_HStack_8">
                    <div class="DH_Input_Wrap">
                        <img class="DH_Stat_Ico" src="https://d35aaqx5ub95lt.cloudfront.net/images/icons/398e4298a3b39ce566050e5c041949ef.svg" style="flex-shrink:0;">
                        <input type="number" class="DH_Input DH_NoSel" id="DH_V1_Streak_Input" placeholder="0" readonly style="pointer-events:none;">
                    </div>
                    <button class="DH_Input_Btn DH_NoSel" id="DH_V1_Streak_Btn" disabled>
                        <span class="DH_Btn_Label" id="DH_V1_Streak_Lbl" style="color:#fff;">RUN</span>
                    </button>
                </div>
                <div class="DH_Prog_Wrap" id="DH_V1_Streak_Prog"><div class="DH_Prog_Fill" id="DH_V1_Streak_Fill"></div></div>
            </div>

            <div class="DH_Divider"></div>

            <!-- Settings (same as V2 settings page) -->
            <div class="DH_Btn DH_Btn_Blue_Ghost DH_NoSel" id="DH_V1_Settings_Btn" style="align-self:stretch; justify-content:space-between; padding:10px 12px;">
                <div style="display:flex; align-items:center; gap:8px;">
                    <div class="DH_Btn_Ico">
                        <svg width="16" height="16" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
                            <path d="M18.1,11c-3.9,0-7,3.1-7,7s3.1,7,7,7c3.9,0,7-3.1,7-7S22,11,18.1,11z M18.1,23c-2.8,0-5-2.2-5-5s2.2-5,5-5c2.8,0,5,2.2,5,5S20.9,23,18.1,23z" fill="rgb(var(--DH-blue))" stroke="rgb(var(--DH-blue))" stroke-width="1.2" stroke-linejoin="round" paint-order="stroke fill"/>
                            <path d="M32.8,14.7L30,13.8l-0.6-1.5l1.4-2.6c0.3-0.6,0.2-1.4-0.3-1.9l-2.4-2.4c-0.5-0.5-1.3-0.6-1.9-0.3l-2.6,1.4l-1.5-0.6l-0.9-2.8C21,2.5,20.4,2,19.7,2h-3.4c-0.7,0-1.3,0.5-1.4,1.2L14,6c-0.6,0.1-1.1,0.3-1.6,0.6L9.8,5.2C9.2,4.9,8.4,5,7.9,5.5L5.5,7.9C5,8.4,4.9,9.2,5.2,9.8l1.3,2.5c-0.2,0.5-0.4,1.1-0.6,1.6l-2.8,0.9C2.5,15,2,15.6,2,16.3v3.4c0,0.7,0.5,1.3,1.2,1.5L6,22.1l0.6,1.5l-1.4,2.6c-0.3,0.6-0.2,1.4,0.3,1.9l2.4,2.4c0.5,0.5,1.3,0.6,1.9,0.3l2.6-1.4l1.5,0.6l0.9,2.9c0.2,0.6,0.8,1.1,1.5,1.1h3.4c0.7,0,1.3-0.5,1.5-1.1l0.9-2.9l1.5-0.6l2.6,1.4c0.6,0.3,1.4,0.2,1.9-0.3l2.4-2.4c0.5-0.5,0.6-1.3,0.3-1.9l-1.4-2.6l0.6-1.5l2.9-0.9c0.6-0.2,1.1-0.8,1.1-1.5v-3.4C34,15.6,33.5,14.9,32.8,14.7z M32,19.4l-3.6,1.1L28.3,21c-0.3,0.7-0.6,1.4-0.9,2.1l-0.3,0.5l1.8,3.3l-2,2l-3.3-1.8l-0.5,0.3c-0.7,0.4-1.4,0.7-2.1,0.9l-0.5,0.1L19.4,32h-2.8l-1.1-3.6L15,28.3c-0.7-0.3-1.4-0.6-2.1-0.9l-0.5-0.3l-3.3,1.8l-2-2l1.8-3.3l-0.3-0.5c-0.4-0.7-0.7-1.4-0.9-2.1l-0.1-0.5L4,19.4v-2.8l3.4-1l0.2-0.5c0.2-0.8,0.5-1.5,0.9-2.2l0.3-0.5L7.1,9.1l2-2l3.2,1.8l0.5-0.3c0.7-0.4,1.4-0.7,2.2-0.9l0.5-0.2L16.6,4h2.8l1.1,3.5L21,7.7c0.7,0.2,1.4,0.5,2.1,0.9l0.5,0.3l3.3-1.8l2,2l-1.8,3.3l0.3,0.5c0.4,0.7,0.7,1.4,0.9,2.1l0.1,0.5l3.6,1.1V19.4z" fill="rgb(var(--DH-blue))" stroke="rgb(var(--DH-blue))" stroke-width="1.2" stroke-linejoin="round" paint-order="stroke fill"/>
                        </svg>
                    </div>
                    <p class="DH_T1 DH_NoSel" style="color:rgb(var(--DH-blue));">Settings</p>
                </div>
                <svg width="8" height="13" viewBox="0 0 8 13" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M1 1l6 5.5L1 12" stroke="rgb(var(--DH-blue))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                </svg>
            </div>

            <div class="DH_HStack_Auto">
                <p class="DH_T2 DH_NoSel" style="color:rgba(var(--DH-blue),0.45);">twisk.fun</p>
                <p class="DH_T2 DH_NoSel" style="color:rgba(var(--DH-blue),0.45);">V1 Mode</p>
            </div>
        </div>

    </div>
</div>
`;
document.body.appendChild(_wrap);


let _jwt=null, _sub=null, _hdrs=null, _user=null, _privacy=null;
let _v1Mode=false;
let _v1Running=false, _v1Task=null;
const _v1Earned={xp:0,gems:0,streak:0};
function _v1UpdateDisplay(){
    requestAnimationFrame(()=>{
        const xi=document.getElementById('DH_V1_XP_Input');
        const gi=document.getElementById('DH_V1_Gem_Input');
        const si=document.getElementById('DH_V1_Streak_Input');
        if(xi) xi.value=_v1Earned.xp>0?String(_v1Earned.xp):'';
        if(gi) gi.value=_v1Earned.gems>0?String(_v1Earned.gems):'';
        if(si) si.value=_v1Earned.streak>0?String(_v1Earned.streak):'';
    });
}
function _v1SyncUser(){
    if(!_user) return;
    const row=document.getElementById('DH_V1_User_Row');
    const div=document.getElementById('DH_V1_User_Divider');
    if(row) row.style.display='flex';
    if(div) div.style.display='';
    document.getElementById('DH_V1_UName').textContent=_user.username||'';
    document.getElementById('DH_V1_UXP').textContent=(_user.totalXp||0).toLocaleString();
    document.getElementById('DH_V1_UGems').textContent=(_user.gems||0).toLocaleString();
    document.getElementById('DH_V1_UStreak').textContent=(_user.streak||0).toLocaleString();
    if(_user.picture){
        let hq=_user.picture.replace(/\/(medium|large|small)$/,'/xlarge');
        if(!hq.endsWith('/xlarge')&&hq.includes('duolingo.com/ssr-avatars')) hq+='/xlarge';
        const av=document.getElementById('DH_V1_Avatar');
        const img=document.createElement('img');
        img.src=hq;
        img.style.cssText='width:100%;height:100%;object-fit:cover;border-radius:50%;display:block;';
        img.onerror=function(){av.innerHTML='👤';};
        av.innerHTML=''; av.appendChild(img);
    }
}
let _isOutdated = false, _remoteVersion = '';
let _running=false, _task=null, _hidden=false;
let _delay=parseInt(localStorage.getItem('dh2_delay')||'500',10);
let _shopItems=[];
const _sleep=ms=>new Promise(r=>setTimeout(r,ms));
const GOALS_API='https://goals-api.duolingo.com';

let _pageHistory=[1];

let _questState=null;


let _solverUI = null;
let _isAutoMode = false;
let _solvingIntervalId = null;
let _isInLesson = false;
const _SOLVE_SPEED = 0.1;
let _INJECT_SOLVER_ENABLED = localStorage.getItem('duohacker_inject_solver') === 'true';

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 {
            const t = window.sol?.type;
            if (!t) return false;

            if (t === 'speak' || t === 'listenSpeak' ||
                document.querySelector('[data-test="challenge challenge-listenSpeak"]') ||
                document.querySelectorAll('[data-test*="challenge-speak"]').length > 0) return 'Challenge Speak';

            if (t === 'listenMatch') return 'Listen Match';

            if (document.querySelector('.FmlUF')) {
                if (t === 'arrange') return 'Story Arrange';
                if (t === 'multiple-choice' || t === 'select-phrases') return 'Story Multiple Choice';
                if (t === 'point-to-phrase') return 'Story Point to Phrase';
                if (t === 'match') return 'Story Pairs';
            }

            if (t === 'typeCloze')           return 'Type Cloze';
            if (t === 'typeClozeTable')      return 'Type Cloze Table';
            if (t === 'tapClozeTable')       return 'Tap Cloze Table';
            if (t === 'typeCompleteTable')   return 'Type Complete Table';
            if (t === 'tapCompleteTable')    return 'Tap Complete Table';
            if (t === 'patternTapComplete')  return 'Pattern Tap Complete';
            if (t === 'syllableTap')         return 'Syllable Tap';
            if (t === 'syllableListenTap')   return 'Syllable Listen Tap';

            if (t === 'listenTap') return 'Listen Tap';

            if (t === 'listen') return 'Listen Type';

            if (t === 'translate') return 'Translate';

            if (t === 'completeReverseTranslation') return 'Complete Reverse';

            if (document.querySelectorAll('[data-test*="challenge-partialReverseTranslate"]').length > 0) return 'Partial Reverse';

            if (document.querySelectorAll('[data-test="challenge challenge-characterWrite"]').length > 0) {
                if (document.querySelector('g._25Ktp')) return 'Character Write Drag';
                if (document.querySelectorAll('path._1e5Zt').length > 0) return 'Character Write Draw';
                return 'Character Write Freehand';
            }

            if (t === 'judge') return 'Judge';

            if (t === 'dialogue' || t === 'characterIntro' || t === 'selectTranscription') return 'Dialogue';

            if (t === 'characterMatch' || t === 'match') {
                if (document.querySelectorAll('[data-test$="challenge-tap-token"]').length > 0) return 'Pairs';
            }

            if (t === 'select' || t === 'characterSelect' || t === 'form' ||
                t === 'readComprehension' || t === 'listenComprehension' ||
                t === 'selectPronunciation') {
                return 'Select Card';
            }

            if (document.querySelectorAll('[data-test*="challenge-name"]').length > 0 &&
                document.querySelectorAll('[data-test="challenge-choice"]').length > 0) return 'Challenge Name';

            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 (document.querySelectorAll('[data-test="daily-quest-progress-slide"]').length > 0) return 'Daily Quest Progress';
            if (document.querySelectorAll('[data-test="streak-slide"]').length > 0)               return 'Streak Slide';
            if (document.querySelectorAll('[data-test="leaderboard-slide"]').length > 0)          return 'Leaderboard Slide';

            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 = [];
    const tokensToClick = [];
    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) {
                tokensToClick.push(elementToClick);
                clickedTokens.push(elementToClick);
            }
        }
    }
    tokensToClick.forEach(token => token.click());
},
    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 'Select Card': {
                    const idx = window.sol.correctIndex ?? 0;

                    const cards = document.querySelectorAll('[data-test="challenge-choice-card"]');
                    if (cards.length > 0) {
                        cards[idx]?.click();
                    } else {
                        document.querySelectorAll('[data-test="challenge-choice"]')[idx]?.click();
                    }
                    break;
                }

                case 'Judge': {
                    const ci = window.sol.correctIndices?.[0] ?? 0;
                    document.querySelectorAll('[data-test="challenge-judge-text"]')[ci]?.click();
                    break;
                }

                case 'Dialogue': {
                    const idx = window.sol.correctIndex ?? 0;

                    const judgeItems = document.querySelectorAll('[data-test="challenge-judge-text"]');
                    if (judgeItems.length > 0) {
                        judgeItems[idx]?.click();
                    } else {
                        document.querySelectorAll('[data-test="challenge-choice"]')[idx]?.click();
                    }
                    break;
                }

                case 'Translate': {
                    const { correctTokens, correctSolutions } = window.sol;
                    if (correctTokens && correctTokens.length > 0) {
                        const tokens = document.querySelectorAll('[data-test$="challenge-tap-token"]');
                        const usedIndexes = [];
                        for (const word of correctTokens) {
                            for (let i = 0; i < tokens.length; i++) {
                                if (usedIndexes.includes(i)) continue;
                                if (tokens[i].innerText.trim() === word.trim() && !tokens[i].disabled) {
                                    tokens[i].click();
                                    usedIndexes.push(i);
                                    await _autoSolver.delay(40);
                                    break;
                                }
                            }
                        }
                    } else if (correctSolutions) {
                        const ta = document.querySelector('textarea[data-test="challenge-translate-input"]');
                        if (ta) _autoSolver.setInputValue(ta, correctSolutions[0]);
                    }
                    break;
                }

                case 'Listen Tap': {
                    const tokens = document.querySelectorAll('[data-test$="challenge-tap-token"]');
                    const usedIdx = [];
                    for (const word of (window.sol.correctTokens || [])) {
                        for (let i = 0; i < tokens.length; i++) {
                            if (usedIdx.includes(i)) continue;
                            if (tokens[i].innerText.trim() === word.trim() && !tokens[i].disabled) {
                                tokens[i].click();
                                usedIdx.push(i);
                                await _autoSolver.delay(40);
                                break;
                            }
                        }
                    }
                    break;
                }

                case 'Listen Type': {
                    const answer = window.sol.prompt || window.sol.correctSolutions?.[0] || '';
                    const ta = document.querySelector('textarea[data-test="challenge-translate-input"]') ||
                               document.querySelector('[data-test="challenge-text-input"]');
                    if (ta) _autoSolver.setInputValue(ta, answer);
                    break;
                }

                case 'Complete Reverse': {
                    const blankTokens = window.sol.displayTokens?.filter(t => t.isBlank);
                    const inputFields = document.querySelectorAll('[data-test="challenge-text-input"]');
                    if (blankTokens && blankTokens.length > 1 && inputFields.length > 1) {
                        // Multi-blank support
                        inputFields.forEach((input, index) => {
                            if (blankTokens[index]) {
                                _autoSolver.setInputValue(input, blankTokens[index].text);
                            }
                        });
                    } else {
                        // Single blank (fallback)
                        const answer = blankTokens?.[0]?.text || window.sol.correctSolutions?.[0] || '';
                        const input = document.querySelector('[data-test="challenge-text-input"]');
                        if (input) _autoSolver.setInputValue(input, answer);
                    }
                    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;

                case 'Syllable Tap':
                case 'Syllable Listen Tap': {
                    const correctIndices = window.sol.correctIndices;
                    const choicesData = window.sol.choices;
                    const domButtons = Array.from(document.querySelectorAll('[data-test="word-bank"] [data-test$="challenge-tap-token"]'));
                    correctIndices.forEach(index => {
                        const correctText = choicesData[index].text;
                        const matchingButton = domButtons.find(btn => btn.innerText.trim() === correctText);
                        if (matchingButton) matchingButton.click();
                    });
                    break;
                }

                case 'Character Write Drag': {
                    const sleep = ms => new Promise(r => setTimeout(r, ms));
                    const createEvent = (type, x, y, buttons) => new MouseEvent(type, { bubbles: true, clientX: x, clientY: y, buttons, button: 0 });
                    const normalize = str => str ? str.replace(/\s/g, '') : '';
                    const strokes = window.sol.strokes;
                    for (let i = 0; i < strokes.length; i++) {
                        const targetPathData = normalize(strokes[i].path);
                        let path, handle;
                        while (!path || !handle) {
                            const candidates = document.querySelectorAll('path._1e5Zt');
                            path = Array.from(candidates).find(p => normalize(p.getAttribute('d')) === targetPathData);
                            handle = document.querySelector('g._25Ktp');
                            if (!path || !handle) await sleep(10);
                        }
                        const matrix = path.getScreenCTM();
                        const len = path.getTotalLength();
                        const start = path.getPointAtLength(0).matrixTransform(matrix);
                        const end = path.getPointAtLength(len).matrixTransform(matrix);
                        handle.dispatchEvent(createEvent('mousedown', start.x, start.y, 1));
                        const steps = 10;
                        for (let s = 1; s <= steps; s++) {
                            const p = path.getPointAtLength((s / steps) * len).matrixTransform(matrix);
                            const move = createEvent('mousemove', p.x, p.y, 1);
                            handle.dispatchEvent(move);
                            document.dispatchEvent(move);
                        }
                        const finalMove = createEvent('mousemove', end.x, end.y, 1);
                        handle.dispatchEvent(finalMove);
                        document.dispatchEvent(finalMove);
                        await sleep(5);
                        handle.dispatchEvent(createEvent('mouseup', end.x, end.y, 0));
                        document.dispatchEvent(createEvent('mouseup', end.x, end.y, 0));
                    }
                    break;
                }

                case 'Character Write Draw': {
                    const sleep = ms => new Promise(r => setTimeout(r, ms));
                    const createEvent = (type, x, y, buttons) => new MouseEvent(type, { bubbles: true, clientX: x, clientY: y, buttons, button: 0 });
                    const normalize = str => str ? str.replace(/\s/g, '') : '';
                    const strokes = window.sol.strokes;
                    for (let i = 0; i < strokes.length; i++) {
                        const targetPathData = normalize(strokes[i].path);
                        let path, cursor;
                        while (!path || !cursor) {
                            const candidates = document.querySelectorAll('path._1e5Zt');
                            path = Array.from(candidates).find(p => normalize(p.getAttribute('d')) === targetPathData);
                            cursor = document.querySelector('g._1h31R:not(._25Ktp)');
                            if (!path || !cursor) await sleep(10);
                        }
                        const matrix = path.getScreenCTM();
                        const len = path.getTotalLength();
                        const start = path.getPointAtLength(0).matrixTransform(matrix);
                        const end = path.getPointAtLength(len).matrixTransform(matrix);
                        cursor.dispatchEvent(createEvent('mousedown', start.x, start.y, 1));
                        document.dispatchEvent(createEvent('mousedown', start.x, start.y, 1));
                        const steps = 10;
                        for (let s = 1; s <= steps; s++) {
                            const p = path.getPointAtLength((s / steps) * len).matrixTransform(matrix);
                            const move = createEvent('mousemove', p.x, p.y, 1);
                            cursor.dispatchEvent(move);
                            document.dispatchEvent(move);
                        }
                        const finalMove = createEvent('mousemove', end.x, end.y, 1);
                        cursor.dispatchEvent(finalMove);
                        document.dispatchEvent(finalMove);
                        await sleep(5);
                        cursor.dispatchEvent(createEvent('mouseup', end.x, end.y, 0));
                        document.dispatchEvent(createEvent('mouseup', end.x, end.y, 0));
                    }
                    break;
                }

                case 'Character Write Freehand': {
                    const sleep = ms => new Promise(r => setTimeout(r, ms));
                    const createEvent = (type, x, y, buttons) => new MouseEvent(type, { bubbles: true, clientX: x, clientY: y, buttons, button: 0 });
                    const normalize = str => str ? str.replace(/\s/g, '') : '';
                    const freehandStrokes = window.sol.strokes.filter(s => s.strokeDrawMode === 'FREEHAND');
                    for (let i = 0; i < freehandStrokes.length; i++) {
                        const targetPathData = normalize(freehandStrokes[i].path);
                        let path, svg;
                        while (!path || !svg) {
                            const candidates = document.querySelectorAll('path._22UPm');
                            path = Array.from(candidates).find(p => normalize(p.getAttribute('d')) === targetPathData);
                            svg = document.querySelector('svg.o1rqi');
                            if (!path || !svg) await sleep(10);
                        }
                        const matrix = path.getScreenCTM();
                        const len = path.getTotalLength();
                        const start = path.getPointAtLength(0).matrixTransform(matrix);
                        const end = path.getPointAtLength(len).matrixTransform(matrix);
                        svg.dispatchEvent(createEvent('mousedown', start.x, start.y, 1));
                        document.dispatchEvent(createEvent('mousedown', start.x, start.y, 1));
                        const steps = 10;
                        for (let s = 1; s <= steps; s++) {
                            const p = path.getPointAtLength((s / steps) * len).matrixTransform(matrix);
                            const move = createEvent('mousemove', p.x, p.y, 1);
                            svg.dispatchEvent(move);
                            document.dispatchEvent(move);
                        }
                        const finalMove = createEvent('mousemove', end.x, end.y, 1);
                        svg.dispatchEvent(finalMove);
                        document.dispatchEvent(finalMove);
                        await sleep(5);
                        svg.dispatchEvent(createEvent('mouseup', end.x, end.y, 0));
                        document.dispatchEvent(createEvent('mouseup', end.x, end.y, 0));
                    }
                    break;
                }

                case 'Daily Quest Progress':
                case 'Streak Slide':
                case 'Leaderboard Slide':
                    document.querySelector('[data-test="player-next"]')?.click();
                    break;
            }
        } catch (error) {

        }
    },
    clickNext: () => {
        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();
    },
    solve: async () => {
        if (_autoSolver._isBusy) return;
        _autoSolver._isBusy = true;
        const sleep = ms => new Promise(r => setTimeout(r, ms));
        const skipSelectors = [
            '[data-test="practice-hub-ad-no-thanks-button"]',
            '[data-test="plus-no-thanks"]',
            '[data-test="story-start"]',
            '.vpDIE',                                                                    // "Đọc câu này sau" / "Tôi không thể nói lúc này"
            '._1N-oo._36Vd3._16r-S._1ZBYz._23KDq._1S2uf.HakPM',
            '._8AMBh._2vfJy._3Qy5R._28UWu._3h0lA._1S2uf._1E9sc',                       // Cant speak modal button variant 1
            '._1Qh5D._36g4N._2YF0P._28UWu._3h0lA._1S2uf._1E9sc',                       // Cant speak modal button variant 2
            '._3bBpU._1x5JY._1M9iF._36g4N._2YF0P.T7I0c._2EnxW.MYehf',
            '._2V6ug._1ursp._7jW2t._28UWu._3h0lA._1S2uf._1E9sc',                       // No Thanks Legendary
            '._1rcV8._1VYyp._1ursp._7jW2t._1gKir',                                     // Language Score
            '._2V6ug._1ursp._7jW2t._3zgLG',                                            // Create Profile Later
        ];
        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();
                _autoSolver._isBusy = false;
                return;
            }
            const reactInstance = _autoSolver.findReact(mainElement);
            window.sol = reactInstance?.props?.currentChallenge;
            if (!window.sol) {
                _autoSolver.clickNext();
                _autoSolver._isBusy = false;
                return;
            }
            const challengeType = _autoSolver.determineChallengeType();
            if (challengeType && challengeType !== 'Challenge Speak' && challengeType !== 'Listen Match' && challengeType !== 'Listen Speak') {
                await Promise.race([
                    _autoSolver.handleChallenge(challengeType),
                    new Promise(r => setTimeout(r, 2000))
                ]);
                await sleep(80);
            } else if (challengeType === 'Challenge Speak' || challengeType === 'Listen Match' || challengeType === 'Listen Speak') {
                // Dismiss "Đọc câu này sau" / "Tôi không thể nói lúc này" modal trước
                const speakModalSelectors = ['.vpDIE', '._8AMBh._2vfJy._3Qy5R._28UWu._3h0lA._1S2uf._1E9sc', '._1Qh5D._36g4N._2YF0P._28UWu._3h0lA._1S2uf._1E9sc'];
                for (const sel of speakModalSelectors) {
                    const btn = document.querySelector(sel);
                    if (btn) { btn.click(); await sleep(300); break; }
                }
                // Chờ player-skip xuất hiện rồi click
                let skipBtn = document.querySelector('button[data-test="player-skip"]');
                if (!skipBtn) {
                    await sleep(500);
                    skipBtn = document.querySelector('button[data-test="player-skip"]');
                }
                skipBtn?.click();
                await sleep(150);
            }
            _autoSolver.clickNext();
            await sleep(120);
        } catch (error) {
            _autoSolver.clickNext();
        }
        _autoSolver._isBusy = false;
    },
    _isBusy: false,
    _solveLoopRunning: false,
    toggleAutoMode: () => {
        _isAutoMode = !_isAutoMode;
        _autoSolver.updateUI();
        if (_isAutoMode && !_autoSolver._solveLoopRunning) {
            _autoSolver._solveLoopRunning = true;
            const initialUrl = window.location.href;
            (async function loop() {
                while (_isAutoMode) {
                    if (window.location.href !== initialUrl) {
                        _isAutoMode = false;
                        _autoSolver.updateUI();
                        break;
                    }
                    const t0 = Date.now();
                    await _autoSolver.solve();
                    await new Promise(r => setTimeout(r, 100));
                    if (!_isAutoMode) break;
                    const elapsed = Date.now() - t0;
                    const wait = Math.max(0, 400 - elapsed);
                    if (wait > 0) await new Promise(r => setTimeout(r, wait));
                }
                _autoSolver._solveLoopRunning = false;
            })();
        } else if (!_isAutoMode) {
            _autoSolver._solveLoopRunning = false;
        }
    },
    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: 2147483647; display: flex; gap: 12px; animation: slideUp 0.3s ease-out; pointer-events: auto;`;
        _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); pointer-events: auto;">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); pointer-events: auto;">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);

let _lessonSolving=false;
let _currentLessonCount=0;
let _lessonsToSolve=0;

function _getJwt(){
    const m=document.cookie.match(/(^| )jwt_token=([^;]+)/);
    return m?m[2]:null;
}
function _decodeJwt(t){
    try{
        const b=t.split('.')[1].replace(/-/g,'+').replace(/_/g,'/');
        const pad=b.padEnd(b.length+(4-b.length%4)%4,'=');
        return JSON.parse(decodeURIComponent(atob(pad).split('').map(c=>'%'+('00'+c.charCodeAt(0).toString(16)).slice(-2)).join('')));
    }catch{return null;}
}
function _buildHdrs(jwt){
    return {'Content-Type':'application/json','Authorization':'Bearer '+jwt,'User-Agent':navigator.userAgent};
}
function _goalHdrs(jwt){
    return {'Content-Type':'application/json','x-requested-with':'XMLHttpRequest','accept':'application/json; charset=UTF-8','Authorization':'Bearer '+jwt};
}
function _gm(method,url,data,hdrs){
    return new Promise((res,rej)=>GM_xmlhttpRequest({
        method,url,headers:hdrs||_hdrs,
        data:data?JSON.stringify(data):null,
        onload:r=>res(r),onerror:()=>rej(new Error('Network')),
        timeout:15000,ontimeout:()=>rej(new Error('Timeout'))
    }));
}

function _setBtnState(btnId, cfg, labelText) {
    const btn = document.getElementById(btnId);
    if(!btn) return;
    const lbl = btn.querySelector('.DH_Btn_Label') || btn.querySelector('.DH_Sm_Btn_Label');
    if(!lbl) return;

    const prevTxt = lbl.textContent;
    lbl.textContent = labelText;
    const newW = btn.offsetWidth;
    lbl.textContent = prevTxt;

    btn.style.width = btn.offsetWidth+'px';
    requestAnimationFrame(()=>{
        lbl.style.opacity='0'; lbl.style.filter='blur(4px)';
        btn.style.width = newW+'px';
        btn.style.background = cfg.bg;
        btn.style.outline = `solid 2px ${cfg.outline}`;
        btn.style.outlineOffset = '-2px';
    });
    setTimeout(()=>{
        lbl.style.transition='0s';
        lbl.style.color = cfg.tc;
        void lbl.offsetWidth;
        lbl.style.transition='0.4s';
        lbl.textContent = labelText;
        requestAnimationFrame(()=>{ lbl.style.opacity='1'; lbl.style.filter='blur(0)'; });
        setTimeout(()=>{ btn.style.width=''; }, 400);
    },400);
}

const _C_BLUE  = {bg:'rgb(var(--DH-blue))',            outline:'rgba(0,0,0,0.18)',                tc:'#fff'};
const _C_GREEN = {bg:'rgba(var(--DH-green),0.10)',      outline:'rgba(var(--DH-green),0.22)',      tc:'rgb(var(--DH-green))'};
const _C_RED   = {bg:'rgba(var(--DH-red),0.10)',        outline:'rgba(var(--DH-red),0.22)',        tc:'rgb(var(--DH-red))'};
const _C_GRAY  = {bg:'rgb(var(--color-eel,117,117,117),0.10)', outline:'rgb(var(--color-eel,117,117,117),0.20)', tc:'rgb(var(--color-eel,117,117,117),0.60)'};

function _resetBtn(btnId, label){
    const btn=document.getElementById(btnId); if(!btn) return;
    btn.disabled=false;
    _setBtnState(btnId, _C_BLUE, label);
    const prog=document.getElementById(btnId.replace('_Btn','_Prog'));
    if(prog) setTimeout(()=>prog.classList.remove('on'),2000);
}
function _setBtnProgress(btnId, pct){
    const btn=document.getElementById(btnId); if(!btn) return;
    const lbl=btn.querySelector('.DH_Btn_Label')||btn.querySelector('.DH_Sm_Btn_Label');
    if(lbl) lbl.textContent=pct+'%';
    const fill=document.getElementById(btnId.replace('_Btn','_Fill'));
    if(fill) fill.style.width=pct+'%';
}
function _setBtnRunning(btnId){
    const btn=document.getElementById(btnId); if(!btn) return;
    btn.disabled=false;
    _setBtnState(btnId, _C_RED, '0%');
    const prog=document.getElementById(btnId.replace('_Btn','_Prog'));
    if(prog) prog.classList.add('on');
}
function _setBtnDone(btnId, label){
    const btn=document.getElementById(btnId); if(!btn) return;
    _setBtnState(btnId, _C_GREEN, label||'DONE ✓');
    const fill=document.getElementById(btnId.replace('_Btn','_Fill'));
    if(fill) fill.style.width='100%';
}

const _GF_SCRIPT_URL='https://greasyfork.org/en/scripts/561041-duolingo-duohacker';
const _CURRENT_VER='2026.04.27';

function _setConn(state, label){
        if (state === 'connected' && _isOutdated) {
        state = 'outdated';
        label = `v${_remoteVersion} available — click to update`;
    }

    const btn=document.getElementById('DH_Conn_Btn');
    const ico=document.getElementById('DH_Conn_Ico');
    const txt=document.getElementById('DH_Conn_Txt');
    ico.classList.remove('DH_Spin_Ico');

if(state==='outdated'){
        const newBtn=btn.cloneNode(true);
        btn.parentNode.replaceChild(newBtn,btn);
        const nb=document.getElementById('DH_Conn_Btn');
        const ni=document.getElementById('DH_Conn_Ico');
        const nt=document.getElementById('DH_Conn_Txt');


        nb.style.background=`linear-gradient(0deg,rgba(var(--DH-orange),0.10),rgba(var(--DH-orange),0.10)),rgb(var(--color-snow),0.90)`;
        nb.style.outline=`2px solid rgba(var(--DH-orange),0.30)`;
        nb.style.outlineOffset='-2px';
        nb.style.cursor='pointer';
        nb.style.display='flex';
        nb.style.alignItems='center';


        nt.textContent='Outdated';
        nt.style.color=`rgb(var(--DH-orange))`;


        ni.textContent='';
        ni.style.display='flex';
        ni.style.alignItems='center';
        ni.style.justifyContent='center';

        ni.innerHTML=`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="flex-shrink:0; display:block;"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" fill="rgba(var(--DH-orange),0.18)" stroke="rgb(var(--DH-orange))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><line x1="12" y1="9" x2="12" y2="13" stroke="rgb(var(--DH-orange))" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="17" r="1" fill="rgb(var(--DH-orange))"/></svg>`;

        nb.title=label;
        nb.onclick = () => window.open(_GF_SCRIPT_URL, '_blank');
        document.getElementById('DH_User_Row').style.display='flex';
        return;
    }

    const S={
        connecting:{bg:`rgb(var(--color-eel,117,117,117),0.10)`,outline:`rgb(var(--color-eel,117,117,117),0.20)`,tc:`rgb(var(--color-eel,117,117,117),0.70)`,t:'Connecting',i:'⟳',spin:true},
        connected:  {bg:`linear-gradient(0deg,rgba(var(--DH-green),0.10),rgba(var(--DH-green),0.10)),rgb(var(--color-snow),0.90)`,outline:`rgba(var(--DH-green),0.22)`,tc:`rgb(var(--DH-green))`,t:'Connected',i:'✓',spin:false},
        error:      {bg:`rgba(var(--DH-red),0.08)`,outline:`rgba(var(--DH-red),0.20)`,tc:`rgb(var(--DH-red))`,t:label||'Error',i:'✕',spin:false},
    }[state];
    btn.style.background=S.bg; btn.style.outline=`2px solid ${S.outline}`; btn.style.outlineOffset='-2px';
    txt.textContent=S.t; txt.style.color=S.tc;
    ico.textContent=S.i; ico.style.color=S.tc;
    if(S.spin) ico.classList.add('DH_Spin_Ico');
    if(state==='connected') document.getElementById('DH_User_Row').style.display='flex';
}

async function _checkVersionOnLoad(){
    try{
        const r=await new Promise((res,rej)=>GM_xmlhttpRequest({
            method:'GET',
            url:`https://greasyfork.org/scripts/561041.json`,
            headers:{'Accept':'application/json'},
            onload:r=>res(r),onerror:()=>rej(),timeout:5000
        }));
        if(r.status!==200) return;
        const data=JSON.parse(r.responseText);
        const remoteVer=(data.version||'').trim();
        const cmp = (v1, v2) => {
            const a = v1.split('.').map(Number);
            const b = v2.split('.').map(Number);
            for (let i = 0; i < Math.max(a.length, b.length); i++) {
                if ((a[i] || 0) > (b[i] || 0)) return 1;
                if ((a[i] || 0) < (b[i] || 0)) return -1;
            }
            return 0;
        };
        if(cmp(remoteVer, _CURRENT_VER) !== 0){
            _isOutdated = true;
            _remoteVersion = remoteVer;
            const txt = document.getElementById('DH_Conn_Txt');
            if(txt && txt.textContent === 'Connected') {
                _setConn('outdated', `v${remoteVer} available`);
            }
        }
    }catch(e){}
}
setTimeout(_checkVersionOnLoad, 2000);

let _animBusy=false;
function _doHide(val){
    if(_animBusy) return; _animBusy=true; _hidden=val;
    const main=document.getElementById('DH_Main');
    const box=document.getElementById('DH_Main_Box');
    const h=box.offsetHeight;
    const icoVisible=document.getElementById('DH_Ico_Visible');
    const icoHidden=document.getElementById('DH_Ico_Hidden');
    const hideTxt=document.getElementById('DH_Hide_Txt');
    const hideBtn=document.getElementById('DH_Hide_Btn');
    main.style.transition='0.8s cubic-bezier(0.16,1,0.32,1)';
    box.style.transition='0.8s cubic-bezier(0.16,1,0.32,1)';
    const switchV1Btn=document.getElementById('DH_SwitchV1_Btn');
    const switchV2Btn=document.getElementById('DH_SwitchV2_Btn');
    if(val){
        if(switchV1Btn) switchV1Btn.style.display='none';
        if(switchV2Btn) switchV2Btn.style.display='none';
        hideBtn.style.background=`linear-gradient(0deg,rgba(var(--DH-blue),0.10),rgba(var(--DH-blue),0.10)),rgb(var(--color-snow),0.80)`;
        hideBtn.style.outline=`2px solid rgba(var(--DH-blue),0.20)`;
        if(icoVisible) icoVisible.style.display='none';
        if(icoHidden){ icoHidden.style.display=''; icoHidden.querySelector('path').setAttribute('fill','rgb(var(--DH-blue))'); }
        hideTxt.textContent='Show'; hideTxt.style.color='rgb(var(--DH-blue))';
        main.style.bottom=`-${h-8}px`; box.style.filter='blur(8px)'; box.style.opacity='0';
    } else {
        if(switchV1Btn) switchV1Btn.style.display=(!_v1Mode)?'':'none';
        if(switchV2Btn) switchV2Btn.style.display=(_v1Mode)?'':'none';
        hideBtn.style.background=`rgb(var(--DH-blue))`;
        hideBtn.style.outline=`2px solid rgba(0,0,0,0.20)`;
        if(icoHidden) icoHidden.style.display='none';
        if(icoVisible){ icoVisible.style.display=''; }
        hideTxt.textContent='Hide'; hideTxt.style.color='#fff';
        main.style.bottom='16px'; box.style.filter=''; box.style.opacity='';
    }
    setTimeout(()=>{ main.style.transition=''; box.style.transition=''; _animBusy=false; },800);
}

let _curPage=1, _pageBusy=false;
function _goPage(to){
    if(_pageBusy||_curPage===to) return; _pageBusy=true;
    const box=document.getElementById('DH_Main_Box');
    const fromEl=document.getElementById(`DH_Page_${_curPage}`);
    const toEl=document.getElementById(`DH_Page_${to}`);
    if(!fromEl||!toEl){_pageBusy=false;return;}
    const oldH=box.offsetHeight;
    fromEl.style.display='none'; toEl.style.display='flex';
    const newH=box.offsetHeight;
    fromEl.style.display='flex'; toEl.style.display='none';
    box.style.height=oldH+'px'; box.style.transition='height 0.8s cubic-bezier(0.16,1,0.32,1)';
    fromEl.style.transition='opacity 0.3s,filter 0.3s';
    fromEl.style.opacity='0'; fromEl.style.filter='blur(4px)';
    requestAnimationFrame(()=>{ box.style.height=newH+'px'; });
    setTimeout(()=>{
        fromEl.classList.remove('active'); fromEl.style.cssText='';
        toEl.classList.add('active');
        toEl.style.opacity='0'; toEl.style.filter='blur(4px)';
        void toEl.offsetWidth;
        toEl.style.transition='opacity 0.3s,filter 0.3s';
        toEl.style.opacity='1'; toEl.style.filter='blur(0)';
        _pageHistory.push(to);
        _curPage=to;
        if(to===2){

            const lgB=document.getElementById('DH_League_Btn');
            const qB=document.getElementById('DH_Quest_Btn');
            if(_user&&lgB) lgB.disabled=false;
            if(_user&&qB) qB.disabled=false;
        }
        if(to===4){
            const delI=document.getElementById('DH_Delay_Input');
            if(delI) delI.value=_delay;
        }
        if(to===5){ _renderAccounts(); }
        if(to===6){ _loadMonthlyQuests(); }
        if(to===9){ _loadLicense(); }
        setTimeout(()=>{ box.style.height=''; box.style.transition=''; toEl.style.cssText=''; _pageBusy=false; },300);
    },350);
}
function _goBack(){
    if(_pageHistory.length>1) _pageHistory.pop();
    const prev=_pageHistory[_pageHistory.length-1]||1;

    _pageHistory.pop();
    _goPage(prev);
}

let _nTimer;
function _notif(icon,title,body,dur=5){
    const box=document.getElementById('DH_Notif_Box');
    document.getElementById('DH_Notif_Icon').textContent=icon;
    document.getElementById('DH_Notif_Title').textContent=title;
    document.getElementById('DH_Notif_Body').textContent=body;
    box.classList.add('show'); clearTimeout(_nTimer);
    _nTimer=setTimeout(()=>box.classList.remove('show'),dur*1000);
}

async function _connect(){
    _setConn('connecting');
    _jwt=_getJwt();
    if(!_jwt){_setConn('error','Not logged in');return;}
    const dec=_decodeJwt(_jwt);
    if(!dec){_setConn('error','Invalid token');return;}
    _sub=dec.sub; _hdrs=_buildHdrs(_jwt);
    try{
        const r=await _gm('GET',`https://www.duolingo.com/2017-06-30/users/${_sub}?fields=id,username,fromLanguage,learningLanguage,streak,totalXp,gems,picture,streakData`);
        if(r.status!==200) throw new Error(r.status);
        _user=JSON.parse(r.responseText);
        _setConn('connected'); _renderUser(_user);
        _getPrivacy().then(v=>{ _privacy=v; _applyHideProfileToggle(); });
        _v1FetchSkillId();
        ['DH_XP_Btn','DH_Gem_Btn','DH_Streak_Btn','DH_League_Btn','DH_Quest_Btn','DH_Practice_Btn','DH_V1_XP_Btn','DH_V1_Gem_Btn','DH_V1_Streak_Btn'].forEach(id=>{
            const b=document.getElementById(id); if(b) b.disabled=false;
        });

        const saveBtn=document.getElementById('DH_AccSave_Btn');
        if(saveBtn) saveBtn.disabled=false;
        const mqClaimNav=document.getElementById('DH_MonthlyQuest_Claim_Btn');
        if(mqClaimNav) mqClaimNav.disabled=false;
    }catch(e){
        _setConn('error','Failed — retrying');
        setTimeout(_connect,8000);
    }
}

function _renderUser(u){
    if(!u) return;
    document.getElementById('DH_UName').textContent=u.username||'';
    _v1SyncUser();
    document.getElementById('DH_UXP').textContent=(u.totalXp||0).toLocaleString();
    document.getElementById('DH_UGems').textContent=(u.gems||0).toLocaleString();
    document.getElementById('DH_UStreak').textContent=(u.streak||0).toLocaleString();
    if(u.picture){
        let hq=u.picture.replace(/\/(medium|large|small)$/,'/xlarge');
        if(!hq.endsWith('/xlarge')&&hq.includes('duolingo.com/ssr-avatars')) hq+='/xlarge';
        const av=document.getElementById('DH_Avatar');
        const avImg=document.createElement('img');
        avImg.src=hq;
        avImg.style.cssText='width:100%;height:100%;object-fit:cover;border-radius:50%;display:block;';
        avImg.draggable=false;
        avImg.onerror=function(){av.innerHTML='👤';};
        av.innerHTML=''; av.appendChild(avImg);
    }
}

async function _farmXP(txp){
    const MIN=30,MAX=499;
    let loops=Math.floor(txp/MAX),rem=txp%MAX;
    if(rem>0&&rem<MIN&&loops>0){loops--;rem+=MAX;}
    const total=loops+(rem>=MIN?1:0);
    let cur=0,earned=0;
    _setBtnRunning('DH_XP_Btn');
    for(let i=0;i<loops;i++){
        if(!_running) break;
        const ok=await _storyXP(469);
        if(ok){earned+=MAX;cur++;}
        _setBtnProgress('DH_XP_Btn',Math.floor((cur/total)*100));
        await _sleep(_delay);
    }
    if(rem>=MIN&&_running){
        const ok=await _storyXP(Math.min(rem-MIN,469));
        if(ok){earned+=rem;cur++;}
        _setBtnProgress('DH_XP_Btn',100);
    }
    if(_running){
        _setBtnDone('DH_XP_Btn','DONE ✓');
        _notif('✅','XP Farm Done!',`Farmed ${earned} XP in ${cur} loops.`);
        setTimeout(_connect,1500);
    }
}

async function _storyXP(hh){
    try{
        const now=Math.floor(Date.now()/1000),dur=Math.floor(Math.random()*121+300);
        const r=await _gm('POST','https://stories.duolingo.com/api2/stories/fr-en-le-passeport/complete',{
            awardXp:true,completedBonusChallenge:true,
            fromLanguage:'fr',learningLanguage:'en',
            hasXpBoost:false,illustrationFormat:'svg',
            isFeaturedStoryInPracticeHub:true,isLegendaryMode:true,
            isV2Redo:false,isV2Story:false,masterVersion:true,
            maxScore:0,score:0,happyHourBonusXp:hh,
            startTime:now,endTime:now+dur
        });
        return r.status===200;
    }catch{return false;}
}

// ── Slug probe — used only by V1 Mode infinite farm (fallback detection) ──
let _workingSlug=null,_workingSlugFrom=null,_workingSlugLearn=null;
let _probingSlugPromise=null;
const _SLUG_CANDIDATES=()=>[
    ['vi-en-le-passeport','vi','en'],
    ['fr-en-le-passeport','fr','en'],
    ['en-fr-le-passeport','en','fr'],
    ['es-en-le-passeport','es','en'],
    ['de-en-le-passeport','de','en'],
    ['pt-en-le-passeport','pt','en'],
    ['it-en-le-passeport','it','en'],
];
async function _probeSlug(){
    if(_workingSlug) return _workingSlug;
    if(_probingSlugPromise) return _probingSlugPromise;
    _probingSlugPromise=(async()=>{
        const now=Math.floor(Date.now()/1000);
        const tryCandidate=([slug,from,learn])=>_gm('POST',`https://stories.duolingo.com/api2/stories/${slug}/complete`,{
            awardXp:false,completedBonusChallenge:false,
            fromLanguage:from,learningLanguage:learn,
            hasXpBoost:false,illustrationFormat:'svg',
            isFeaturedStoryInPracticeHub:true,isLegendaryMode:true,
            isV2Redo:false,isV2Story:false,masterVersion:true,
            maxScore:0,score:0,happyHourBonusXp:0,
            startTime:now,endTime:now+300
        }).then(r=>{
            if(r.status===200||r.status===429) return [slug,from,learn];
            return null;
        }).catch(()=>null);

        const winner=await new Promise(resolve=>{
            let settled=false;
            let pending=_SLUG_CANDIDATES().length;
            _SLUG_CANDIDATES().forEach(c=>{
                tryCandidate(c).then(result=>{
                    pending--;
                    if(result&&!settled){settled=true;resolve(result);}
                    else if(pending===0&&!settled) resolve(null);
                });
            });
        });

        if(winner){
            _workingSlug=winner[0];
            _workingSlugFrom=winner[1];
            _workingSlugLearn=winner[2];
        }
        _probingSlugPromise=null;
        return winner?winner[0]:null;
    })();
    return _probingSlugPromise;
}

async function _farmGems(tgt){
    // [PATCHED 2026.04.21] Farm Gems method is currently unavailable.
    _running=false; _task=null;
    _resetBtn('DH_Gem_Btn','GET');
    document.getElementById('DH_Gem_Btn').disabled=true;
    document.getElementById('DH_Gem_Input').disabled=true;
    _notif('🔒','Farm Gems method patched','Please wait until our developers fixed that.',6);
}

async function _farmStreak(days){
    const CH=["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"];
    let farmStart;
    try{
        const s=new Date(_user.streakData?.currentStreak?.startDate||Date.now());
        s.setDate(s.getDate()-1);farmStart=s;
    }catch{const n=new Date();n.setDate(n.getDate()-1);farmStart=n;}
    _setBtnRunning('DH_Streak_Btn');
    for(let i=0;i<days;i++){
        if(!_running) break;
        const simDay=new Date(farmStart);
        simDay.setDate(simDay.getDate()-i);
        const end=Math.floor(simDay.getTime()/1000);
        try{
            const sr=await _gm('POST','https://www.duolingo.com/2023-05-23/sessions',{
                challengeTypes:CH,fromLanguage:_user.fromLanguage,isFinalLevel:false,isV2:true,
                juicy:true,learningLanguage:_user.learningLanguage,smartTipsVersion:2,type:'GLOBAL_PRACTICE'
            });
            if(sr.status===200){
                const sess=JSON.parse(sr.responseText);
                await new Promise((res,rej)=>GM_xmlhttpRequest({
                    method:'PUT',url:`https://www.duolingo.com/2023-05-23/sessions/${sess.id}`,
                    headers:_hdrs,data:JSON.stringify({
                        ...sess,heartsLeft:5,startTime:end-1,endTime:end,
                        enableBonusPoints:false,failed:false,maxInLessonStreak:9,shouldLearnThings:true
                    }),
                    onload:r=>res(r),onerror:()=>rej(),timeout:15000,ontimeout:()=>rej()
                }));
            }
        }catch{}
        _setBtnProgress('DH_Streak_Btn',Math.floor(((i+1)/days)*100));
        await _sleep(_delay);
    }
    if(_running){
        _setBtnDone('DH_Streak_Btn','DONE ✓');
        _notif('🔥','Streak Farm Done!',`Restored ${days} streak days.`);
        setTimeout(_connect,1500);
    }
}

async function _farmPractice(count){

    _lessonsToSolve=count;
    _currentLessonCount=0;
    if(_lessonSolving){_notif('⚠️','Busy','Practice farm already running.');return;}
    _lessonSolving=true;
    const btn=document.getElementById('DH_Practice_Btn');
    _setBtnState('DH_Practice_Btn',_C_RED,'STOP');
    _notif('📚','Farm Practice','Navigating to practice...',3);

    if(!window.location.pathname.startsWith('/practice')){
        window.location.assign('/practice');
        return;
    }
    await _solveCurrentLesson();
}

async function _solveCurrentLesson(){

    let waited=0;
    while(!document.querySelector('[data-test="challenge"]')&&!document.querySelector('._3yE3H')&&waited<10000&&_lessonSolving){
        await _sleep(500); waited+=500;
    }
    if(!_lessonSolving) return;

    await new Promise(resolve=>{
        let lastId=null, solving=false, ticks=0;
        const MAX=240;
        const clickNext=()=>{
            const nb=document.querySelector('[data-test="player-next"]')||document.querySelector('[data-test="stories-player-continue"]')||document.querySelector('[data-test="stories-player-done"]');
            if(!nb||nb.getAttribute('aria-disabled')==='true'||nb.disabled) return;
            nb.click(); setTimeout(()=>{if(!nb.disabled) nb.click();},5);
        };
        const iv=setInterval(async()=>{
            try{
                if(!_lessonSolving){clearInterval(iv);resolve();return;}
                if(++ticks>MAX){clearInterval(iv);resolve();return;}
                const done=document.querySelector('[data-test="session-over"]')||document.querySelector('[data-test="session-complete-slide"]')||document.querySelector('[data-test="session-complete"]');
                if(done){clearInterval(iv);_currentLessonCount++;

                    try{const s=JSON.parse(sessionStorage.getItem('dh2_practice')||'{}');s.done=_currentLessonCount;sessionStorage.setItem('dh2_practice',JSON.stringify(s));}catch{}
                    await _sleep(500);resolve();return;}
                if(solving) return;
                let el=document.querySelector('._3yE3H')||document.querySelector('[data-test="challenge"]')||document.querySelector('[class*="challenge"]');
                if(!el){clickNext();return;}
                const ri=_autoSolver.findReact(el);
                window.sol=ri?.props?.currentChallenge;
                if(!window.sol){clickNext();return;}
                const cid=`${window.sol.type}:${window.sol.id||JSON.stringify(window.sol.correctIndex??window.sol.correctTokens??window.sol.correctSolutions?.[0]??'')}`;
                if(cid===lastId){clickNext();return;}
                const type=_autoSolver.determineChallengeType();
                if(!type){clickNext();return;}
                solving=true; lastId=cid;
                try{await _autoSolver.handleChallenge(type);}catch{}
                await _sleep(350); clickNext(); await _sleep(600); solving=false;
            }catch{solving=false;}
        },500);
        setTimeout(()=>{clearInterval(iv);resolve();},180000);
    });

    if(!_lessonSolving) return;

    if(_lessonsToSolve>0&&_currentLessonCount>=_lessonsToSolve){
        _notif('✅','Farm Practice Done!',`Completed ${_currentLessonCount} practice(s).`);
        _stopPractice();
        return;
    }

    _notif('📚','Farm Practice',`Done ${_currentLessonCount}${_lessonsToSolve>0?' / '+_lessonsToSolve:''} — loading next...`,2);
    await _sleep(800);
    if(_lessonSolving) window.location.assign('/practice');
}

function _stopPractice(){
    _lessonSolving=false;
    _setBtnState('DH_Practice_Btn',_C_BLUE,'RUN');
    const btn=document.getElementById('DH_Practice_Btn');
    if(btn) btn.disabled=!_user;
}

function _resumePracticeIfNeeded(){
    const saved=sessionStorage.getItem('dh2_practice');
    if(!saved) return;
    try{
        const {active,count,done}=JSON.parse(saved);
        if(!active) return;
        _lessonsToSolve=count; _currentLessonCount=done;
        sessionStorage.setItem('dh2_practice',JSON.stringify({active:true,count,done}));
        if(window.location.pathname.startsWith('/practice')){
            _lessonSolving=true;
            if(_user){
                _setBtnState('DH_Practice_Btn',_C_RED,'STOP');
                _solveCurrentLesson();
            } else {

                const orig=_setConn.bind(null);
                const check=setInterval(()=>{if(_user){clearInterval(check);_setBtnState('DH_Practice_Btn',_C_RED,'STOP');_solveCurrentLesson();}},500);
            }
        }
    }catch{}
}

async function _farmLeague(){
    const LB='https://duolingo-leaderboards-prod.duolingo.com/leaderboards/7d9f5dd1-8423-491a-91f2-2532052038ce';
    const prog=document.getElementById('DH_League_Prog');
    const fill=document.getElementById('DH_League_Fill');
    if(prog) prog.classList.add('on');
    _setBtnState('DH_League_Btn',_C_RED,'STOP');
    while(_running){
        try{
            const r=await _gm('GET',`${LB}/users/${_sub}?client_unlocked=true&_=${Date.now()}`);
            if(r.status!==200){await _sleep(3000);continue;}
            const data=JSON.parse(r.responseText);
            const ranks=data?.active?.cohort?.rankings||[];
            const me=ranks.find(u=>u.user_id==_sub);
            if(!me){_notif('⚠️','Not in league!','Join a league first.');break;}
            const rank=ranks.indexOf(me)+1;
            const top1=ranks[0];
            const gap=top1.score-me.score;
            if(rank===1&&gap<=0){_notif('🏆','League #1!','You reached Rank #1!');break;}
            if(fill) fill.style.width=Math.min(95,Math.floor((me.score/Math.max(top1.score,1))*100))+'%';
            if(gap+100>0){const ok=await _storyXP(469);if(!ok)await _sleep(3000);}
            await _sleep(_delay);
        }catch{await _sleep(5000);}
    }
    if(prog) setTimeout(()=>prog.classList.remove('on'),2000);
    if(fill) fill.style.width='0%';
}

function _getQuestTimestamp(goalId){
    const m=goalId.match(/^(\d{4})_(\d{2})_monthly/);
    if(m){return new Date(Date.UTC(parseInt(m[1]),parseInt(m[2])-1,15,12,0,0)).toISOString();}
    return new Date().toISOString();
}
async function _getGoals(){
    return new Promise(r=>GM_xmlhttpRequest({
        method:'GET',url:`${GOALS_API}/schema?ui_language=en&_=${Date.now()}`,
        headers:_goalHdrs(_jwt),
        onload:res=>r(res.status===200?JSON.parse(res.responseText):null),
        onerror:()=>r(null)
    }));
}
async function _getProgress(){
    const tz=Intl.DateTimeFormat().resolvedOptions().timeZone;
    return new Promise(r=>GM_xmlhttpRequest({
        method:'GET',url:`${GOALS_API}/users/${_sub}/progress?timezone=${encodeURIComponent(tz)}&ui_language=en`,
        headers:_goalHdrs(_jwt),
        onload:res=>r(res.status===200?JSON.parse(res.responseText):null),
        onerror:()=>r(null)
    }));
}
async function _bruteForceGoals(metrics){
    const updates=metrics.map(m=>({metric:m,quantity:2000}));
    updates.push({metric:'QUESTS',quantity:1});
    return new Promise(r=>GM_xmlhttpRequest({
        method:'POST',url:`${GOALS_API}/users/${_sub}/progress/batch`,
        headers:_goalHdrs(_jwt),
        data:JSON.stringify({metric_updates:updates,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timestamp:new Date().toISOString()}),
        onload:res=>r(res.status===200),onerror:()=>r(false)
    }));
}
async function _updateGoal(metric,amount,goalId){
    return new Promise(r=>GM_xmlhttpRequest({
        method:'POST',url:`${GOALS_API}/users/${_sub}/progress/batch`,
        headers:_goalHdrs(_jwt),
        data:JSON.stringify({metric_updates:[{metric,quantity:amount}],timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timestamp:_getQuestTimestamp(goalId)}),
        onload:res=>r(res.status===200),onerror:()=>r(false)
    }));
}

async function _farmDailyQuest(){
    _setBtnState('DH_Quest_Btn',_C_GRAY,'Loading...');
    const [schema,progress]=await Promise.all([_getGoals(),_getProgress()]);
    if(!schema||!progress){_notif('❌','Error','Could not load quest data.');_resetBtn('DH_Quest_Btn','RUN');return;}
    const earned=new Set(progress.badges?.earned||[]);
    const daily=(schema.goals||[]).filter(g=>g.category&&g.category.includes('DAILY'));
    const metrics=new Set(daily.filter(g=>!earned.has(g.badgeId)&&!earned.has(g.goalId)&&g.metric).map(g=>g.metric));
    if(!metrics.size){
        _notif('✅','All Done!','All daily quests completed.');
        _setBtnDone('DH_Quest_Btn','DONE ✓');
        setTimeout(()=>_resetBtn('DH_Quest_Btn','RUN'),3000);return;
    }
    _setBtnState('DH_Quest_Btn',_C_RED,'Running...');
    const ok=await _bruteForceGoals(Array.from(metrics));
    if(ok){
        _notif('✅','Daily Quests Done!',`Completed ${metrics.size} metric(s).`);
        _setBtnDone('DH_Quest_Btn','DONE ✓');
        setTimeout(()=>_resetBtn('DH_Quest_Btn','RUN'),3000);
    } else {
        _notif('❌','Error','Quest completion failed.');
        _resetBtn('DH_Quest_Btn','RUN');
    }
}

function _formatItem(id){
    return id.replace(/_/g,' ').replace(/\b\w/g,c=>c.toUpperCase());
}
function _categorizeItem(item){
    const id=item.id||'';
    if(id.includes('streak_freeze')) return {cat:'Streak Freezes',icon:'https://d35aaqx5ub95lt.cloudfront.net/images/icons/216ddc11afcbb98f44e53d565ccf479e.svg'};
    if(id.includes('xp_boost'))      return {cat:'XP Boosts',     icon:'https://d35aaqx5ub95lt.cloudfront.net/images/icons/68c1fd0f467456a4c607ecc0ac040533.svg'};
    if(id.includes('health')||id.includes('heart')) return {cat:'Hearts', icon:'https://d35aaqx5ub95lt.cloudfront.net/images/hearts/547ffcf0e6256af421ad1a32c26b8f1a.svg'};
    if(id.includes('gem'))            return {cat:'Gems',          icon:'https://d35aaqx5ub95lt.cloudfront.net/images/gems/45c14e05be9c1af1d7d0b54c6eed7eee.svg'};
    if(item.type==='outfit')          return {cat:'Outfits',       icon:'https://d35aaqx5ub95lt.cloudfront.net/vendor/0cecd302cf0bcd0f73d51768feff75fe.svg'};
    if(id.includes('free_taste'))     return {cat:'Free Taste',    icon:'https://d35aaqx5ub95lt.cloudfront.net/images/super/11db6cd6f69cb2e3c5046b915be8e669.svg'};
    return {cat:'Misc', icon:'https://d35aaqx5ub95lt.cloudfront.net/images/leagues/9fadb349c2ece257386a0e576359c867.svg'};
}

async function _getShopItems(){
    return new Promise(r=>GM_xmlhttpRequest({
        method:'GET',url:'https://www.duolingo.com/2023-05-23/shop-items',
        headers:_hdrs,
        onload:res=>{
            try{if(res.status===200)r(JSON.parse(res.responseText).shopItems||[]);else r([]);}
            catch{r([]);}
        },
        onerror:()=>r([])
    }));
}

async function _buyShopItem(itemId){
    const payload={itemName:itemId,isFree:true,consumed:true,fromLanguage:_user.fromLanguage,learningLanguage:_user.learningLanguage};
    return new Promise(r=>GM_xmlhttpRequest({
        method:'POST',url:`https://www.duolingo.com/2017-06-30/users/${_sub}/shop-items`,
        headers:_hdrs,data:JSON.stringify(payload),
        onload:res=>r(res.status===200),onerror:()=>r(false)
    }));
}

let _allShopItems=[];
function _renderShop(items,filter=''){
    const container=document.getElementById('DH_Shop_Container');
    container.innerHTML='';
    const valid=items.filter(i=>i.currencyType==='XGM'&&!i.id.includes('gift'));
    const f=filter.trim().toLowerCase();
    const filtered=f?valid.filter(i=>(i.name||_formatItem(i.id)).toLowerCase().includes(f)):valid;
    if(!filtered.length){
        const p=document.createElement('p');
        p.className='DH_T2 DH_NoSel'; p.style.cssText='text-align:center;padding:8px 0;';
        p.textContent=f?'No items found.':'No items available.';
        container.appendChild(p); return;
    }
    const ORDER=['Streak Freezes','XP Boosts','Hearts','Gems','Outfits','Free Taste','Misc'];
    const grouped={};
    filtered.forEach(i=>{
        const {cat,icon}=_categorizeItem(i);
        if(!grouped[cat]) grouped[cat]=[];
        let name=i.name||_formatItem(i.id);
        if(i.id.includes('xp_boost')&&i.id.match(/\d+$/)) name+=' Mins';
        grouped[cat].push({...i,displayName:name,icon,cat});
    });
    ORDER.forEach(cat=>{
        if(!grouped[cat]) return;
        const header=document.createElement('div');
        header.className='DH_Cat_Header DH_NoSel'; header.textContent=cat;
        container.appendChild(header);
        const grid=document.createElement('div');
        grid.className='DH_Shop_Grid';
        grouped[cat].forEach(item=>{
            const card=document.createElement('div');
            card.className='DH_Shop_Card';
            card.innerHTML=`
                <img src="${item.icon}" class="DH_Shop_Ico">
                <div class="DH_Shop_Name DH_NoSel">${item.displayName}</div>
                <button class="DH_Shop_Btn" data-id="${item.id}">GET</button>`;
            const ico=card.querySelector('.DH_Shop_Ico');
            if(ico) ico.onerror=function(){this.style.display='none';const fb=document.createElement('div');fb.style.cssText='width:36px;height:36px;display:flex;align-items:center;justify-content:center;font-size:22px;';fb.textContent='🎁';this.parentNode.insertBefore(fb,this);};
            const btn=card.querySelector('.DH_Shop_Btn');
            btn.onclick=async()=>{
                btn.className='DH_Shop_Btn loading'; btn.textContent='...';
                setTimeout(()=>{if(btn.textContent==='...')btn.textContent='50%';},300);
                const ok=await _buyShopItem(item.id);
                btn.textContent='100%';
                setTimeout(()=>{
                    if(ok){btn.className='DH_Shop_Btn got';btn.textContent='GOT ✓';_notif('🛒','Shop','Got '+item.displayName+'!');
                        setTimeout(()=>{btn.className='DH_Shop_Btn';btn.textContent='GET';},3000);
                    } else {
                        btn.className='DH_Shop_Btn fail';btn.textContent='FAILED';
                        setTimeout(()=>{btn.className='DH_Shop_Btn';btn.textContent='GET';},2000);
                        _notif('❌','Shop','Failed to get item.');
                    }
                },300);
            };
            grid.appendChild(card);
        });
        container.appendChild(grid);
    });
}

async function _loadShop(){
    const container=document.getElementById('DH_Shop_Container');
    const cached=localStorage.getItem('dh2_shop');
    if(cached){
        try{const items=JSON.parse(cached);if(items&&items.length){_allShopItems=items;_renderShop(items);return;}}
        catch{localStorage.removeItem('dh2_shop');}
    }
    container.innerHTML='<p class="DH_T2 DH_NoSel" style="text-align:center;padding:8px 0;">Loading shop...</p>';
    const items=await _getShopItems();
    if(items.length) localStorage.setItem('dh2_shop',JSON.stringify(items));
    _allShopItems=items;
    _renderShop(items);
}

function _installFakeSuper(){
    if(localStorage.getItem('dh2_super')!=='true') return;
    const RX=/https:\/\/www\.duolingo\.com\/\d{4}-\d{2}-\d{2}\/users\/.+/;
    const ITEMS={gold_subscription:{itemName:'gold_subscription',subscriptionInfo:{vendor:'STRIPE',renewing:true,isFamilyPlan:true,expectedExpiration:9999999999000}}};
    function mod(j){try{const d=JSON.parse(j);d.hasPlus=true;if(!d.trackingProperties)d.trackingProperties={};d.trackingProperties.has_item_gold_subscription=true;d.shopItems={...d.shopItems,...ITEMS};return JSON.stringify(d);}catch{return j;}}
    const uw=(typeof unsafeWindow!=='undefined')?unsafeWindow:window;
    const orig=uw.fetch;
    uw.fetch=function(resource,options){
        const url=resource instanceof Request?resource.url:resource;
        const method=resource instanceof Request?resource.method:(options?.method||'GET');
        if(method.toUpperCase()==='GET'&&RX.test(url)&&!url.includes('/shop-items')){
            return orig.apply(this,arguments).then(async r=>{
                const text=await r.clone().text();
                return new Response(mod(text),{status:r.status,statusText:r.statusText,headers:new Headers(r.headers)});
            });
        }
        return orig.apply(this,arguments);
    };
}
_installFakeSuper();

function _resetLeague(){
    const btn=document.getElementById('DH_League_Btn'); if(!btn) return;
    btn.disabled=false; _setBtnState('DH_League_Btn',_C_BLUE,'RUN');
    const fill=document.getElementById('DH_League_Fill');
    if(fill) fill.style.width='0%';
    const prog=document.getElementById('DH_League_Prog');
    if(prog) setTimeout(()=>prog.classList.remove('on'),2000);
}




function _v1UpdateDisplayNow(){
    requestAnimationFrame(()=>{
        const xi=document.getElementById('DH_V1_XP_Input');
        const gi=document.getElementById('DH_V1_Gem_Input');
        const si=document.getElementById('DH_V1_Streak_Input');


        if(xi){ xi.value=_v1Earned.xp>0?String(_v1Earned.xp):''; }
        if(gi){ gi.value=_v1Earned.gems>0?String(_v1Earned.gems):''; }
        if(si){ si.value=_v1Earned.streak>0?String(_v1Earned.streak):''; }
    });
}

function _v1SetBtnState(btnId,cfg,label){
    const btn=document.getElementById(btnId); if(!btn) return;
    const lbl=btn.querySelector('.DH_Btn_Label'); if(!lbl) return;
    btn.style.background=cfg.bg;
    btn.style.outline=`2px solid ${cfg.outline}`;
    btn.style.outlineOffset='-2px';
    lbl.style.color=cfg.tc;
    lbl.textContent=label;
}

function _v1SetProg(id, pct){
    const prog=document.getElementById(id+'_Prog');
    const fill=document.getElementById(id+'_Fill');
    if(prog&&!prog.classList.contains('on')) prog.classList.add('on');
    if(fill) fill.style.width=Math.min(100,Math.max(1,pct))+'%';
}
function _v1ClearProg(id){
    const prog=document.getElementById(id+'_Prog');
    const fill=document.getElementById(id+'_Fill');
    setTimeout(()=>{ if(prog) prog.classList.remove('on'); },2000);
    if(fill) fill.style.width='0%';
}


let _v1SkillId=null;
async function _v1FetchSkillId(){
    if(_v1SkillId) return _v1SkillId;
    try{
        const r=await _gm('GET',
            `https://www.duolingo.com/2017-06-30/users/${_sub}?fields=currentCourse{pathSectioned{units{levels{pathLevelMetadata{skillId},pathLevelClientData{skillId}}}}}`
        );
        if(r.status!==200) return null;
        const d=JSON.parse(r.responseText);
        const sections=d.currentCourse?.pathSectioned||[];
        for(const sec of sections)
            for(const unit of (sec.units||[]))
                for(const lvl of (unit.levels||[])){
                    const sid=lvl.pathLevelMetadata?.skillId||lvl.pathLevelClientData?.skillId;
                    if(sid){ _v1SkillId=sid; return sid; }
                }
    }catch{}
    return null;
}


async function _v1XP110Once(){
    const sid=await _v1FetchSkillId();
    if(!sid) return false;
    try{
        const sr=await _gm('POST','https://www.duolingo.com/2017-06-30/sessions',{
            challengeTypes:[],
            fromLanguage:_user.fromLanguage,
            learningLanguage:_user.learningLanguage,
            type:'UNIT_TEST',
            skillIds:[sid]
        });
        if(!sr||sr.status!==200) return false;
        const sess=JSON.parse(sr.responseText);
        const now=Math.floor(Date.now()/1000);
        const ur=await _gm('PUT',`https://www.duolingo.com/2017-06-30/sessions/${sess.id}`,{
            id:sess.id,
            metadata:sess.metadata,
            type:'UNIT_TEST',
            fromLanguage:_user.fromLanguage,
            learningLanguage:_user.learningLanguage,
            challenges:[],
            adaptiveChallenges:[],
            sessionExperimentRecord:[],
            experiments_with_treatment_contexts:[],
            adaptiveInterleavedChallenges:[],
            sessionStartExperiments:[],
            trackingProperties:[],
            ttsAnnotations:[],
            heartsLeft:0,
            startTime:now,
            enableBonusPoints:true,
            endTime:now+60,
            failed:false,
            maxInLessonStreak:9,
            shouldLearnThings:true,
            hasBoost:true,
            happyHourBonusXp:10,
            pathLevelSpecifics:{unitIndex:0}
        });
        if(ur&&ur.status===200){
            const d=JSON.parse(ur.responseText);
            return d?.awardedXp||d?.xpGain||110;
        }
    }catch{}
    return false;
}


async function _v1FarmXP(){
    _v1Earned.xp=0; _v1UpdateDisplayNow();
    _v1SetBtnState('DH_V1_XP_Btn',_C_RED,'STOP');
    _v1SetProg('DH_V1_XP',1);

    // Always start with story API (499 XP), silently fallback to global API (110 XP) on failure
    let use499 = true;

    let cons429 = 0;
    const MAX_429 = 2;
    let fallbackErrors = 0;
    const MAX_FALLBACK = 5;
    let loopPct = 0;
    let fallbackLoops = 0; // count loops in fallback mode, re-probe every 10

    // Slug is fixed (fr-en-le-passeport), no need to probe before starting
    _workingSlug = 'fr-en-le-passeport';
    _workingSlugFrom = 'fr';
    _workingSlugLearn = 'en';
    _v1FetchSkillId();

    while(_v1Running && _v1Task==='xp'){
        if(use499){
            let status = 0;
            try{
                const now = Math.floor(Date.now()/1000);
                const dur = Math.floor(Math.random()*121+300);
                const r = await _gm('POST',`https://stories.duolingo.com/api2/stories/${_workingSlug}/complete`,{
                    awardXp:true, completedBonusChallenge:true,
                    fromLanguage:_workingSlugFrom, learningLanguage:_workingSlugLearn,
                    hasXpBoost:false, illustrationFormat:'svg',
                    isFeaturedStoryInPracticeHub:true, isLegendaryMode:true,
                    isV2Redo:false, isV2Story:false, masterVersion:true,
                    maxScore:0, score:0, happyHourBonusXp:469,
                    startTime:now, endTime:now+dur
                });
                status = r.status;
            }catch{}

            if(status===200){
                cons429=0; fallbackErrors=0;
                _v1Earned.xp += 499;
                _v1UpdateDisplayNow();
                loopPct = (loopPct+2)%99+1;
                _v1SetProg('DH_V1_XP', loopPct);
            } else if(status===429){
                cons429++;
                if(cons429>=MAX_429){
                    use499=false; fallbackLoops=0;
                }
                await _sleep(_delay*2);
                continue;
            } else {
                use499=false; fallbackLoops=0;
                continue;
            }
        } else {
            // Global API — DuoFarmer-style UNIT_TEST session (110 XP)
            // Every 10 fallback loops, try story API again
            if(fallbackLoops>0 && fallbackLoops%10===0){
                use499=true; cons429=0;
            }
            fallbackLoops++;
            const earned = await _v1XP110Once();
            if(earned){
                fallbackErrors=0;
                _v1Earned.xp += earned;
                _v1UpdateDisplayNow();
                loopPct = (loopPct+1)%99+1;
                _v1SetProg('DH_V1_XP', loopPct);
            } else {
                fallbackErrors++;
                if(fallbackErrors>=MAX_FALLBACK){
                    _notif('❌','V1 XP','Too many errors, stopping.');
                    break;
                }
                await _sleep(_delay*3);
                continue;
            }
        }
        await _sleep(_delay);
    }

    _v1ClearProg('DH_V1_XP');
    _v1SetBtnState('DH_V1_XP_Btn',_C_BLUE,'RUN');
    document.getElementById('DH_V1_XP_Btn').disabled=!_user;
    _v1Running=false; _v1Task=null;
    if(_v1Earned.xp>0){ _notif('✅','XP Farm Done!',`Farmed ${_v1Earned.xp.toLocaleString()} XP.`); setTimeout(_connect,1500); }
}

async function _v1FarmGems(){
    // [PATCHED 2026.04.21] Farm Gems method is currently unavailable.
    _v1Running=false; _v1Task=null;
    _v1SetBtnState('DH_V1_Gem_Btn',_C_BLUE,'RUN');
    document.getElementById('DH_V1_Gem_Btn').disabled=true;
    _v1ClearProg('DH_V1_Gem');
    _notif('🔒','Farm Gems method patched','Please wait until our developers fixed that.',6);
}


async function _v1FarmStreak(){
    _v1Earned.streak=0; _v1UpdateDisplayNow();
    _v1SetBtnState('DH_V1_Streak_Btn',_C_RED,'STOP');
    _v1SetProg('DH_V1_Streak',1);

    const CH=["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"];
    let farmStart;
    try{
        const s=new Date(_user.streakData?.currentStreak?.startDate||Date.now());
        s.setDate(s.getDate()-1); farmStart=s;
    }catch{ farmStart=new Date(); farmStart.setDate(farmStart.getDate()-1); }
    let dayIdx=0;
    let loopPct=0;

    while(_v1Running&&_v1Task==='streak'){
        const simDay=new Date(farmStart);
        simDay.setDate(simDay.getDate()-dayIdx);
        const end=Math.floor(simDay.getTime()/1000);
        try{
            const sr=await _gm('POST','https://www.duolingo.com/2023-05-23/sessions',{
                challengeTypes:CH,fromLanguage:_user.fromLanguage,isFinalLevel:false,isV2:true,
                juicy:true,learningLanguage:_user.learningLanguage,smartTipsVersion:2,type:'GLOBAL_PRACTICE'
            });
            if(sr.status===200){
                const sess=JSON.parse(sr.responseText);
                await new Promise((res,rej)=>GM_xmlhttpRequest({
                    method:'PUT',url:`https://www.duolingo.com/2023-05-23/sessions/${sess.id}`,
                    headers:_hdrs,
                    data:JSON.stringify({
                        ...sess,heartsLeft:5,startTime:end-1,endTime:end,
                        enableBonusPoints:false,failed:false,maxInLessonStreak:9,shouldLearnThings:true
                    }),
                    onload:r=>res(r),onerror:()=>rej(new Error('net')),
                    timeout:15000,ontimeout:()=>rej(new Error('timeout'))
                }));
                _v1Earned.streak++;
                _v1UpdateDisplayNow();
                loopPct=(loopPct+1)%99+1;
                _v1SetProg('DH_V1_Streak',loopPct);
            }
        }catch{}
        dayIdx++;
        await _sleep(_delay);
    }

    _v1ClearProg('DH_V1_Streak');
    _v1SetBtnState('DH_V1_Streak_Btn',_C_BLUE,'RUN');
    document.getElementById('DH_V1_Streak_Btn').disabled=!_user;
    _v1Running=false; _v1Task=null;
    if(_v1Earned.streak>0){ _notif('🔥','Streak Farm Done!',`Farmed ${_v1Earned.streak} streak days.`); setTimeout(_connect,1500); }
}

function _v1RunToggle(task){
    if(_v1Running&&_v1Task===task){
        _v1Running=false; _v1Task=null; return;
    }
    if(_v1Running){_notif('⚠️','Busy','Stop current V1 farm first.');return;}
    if(!_user){_notif('⚠️','Not connected','Please wait.');return;}
    _v1Running=true; _v1Task=task;
    if(task==='xp')     _v1FarmXP();
    if(task==='gems')   _v1FarmGems();
    if(task==='streak') _v1FarmStreak();
}


async function _run(type,val){
    if(_running){_running=false;_notif('⏹️','Stopped','Farm stopped.');return;}
    if(!_user){_notif('⚠️','Not connected','Please wait.');return;}
    _running=true; _task=type;
    try{
        if(type==='xp')     await _farmXP(val);
        if(type==='gem')    await _farmGems(val);
        if(type==='streak') await _farmStreak(val);
        if(type==='league') await _farmLeague();
    }catch(e){_notif('❌','Error',e.message);}
    _running=false; _task=null;
    if(type==='xp')     _resetBtn('DH_XP_Btn','GET');
    if(type==='gem')    _resetBtn('DH_Gem_Btn','GET');
    if(type==='streak') _resetBtn('DH_Streak_Btn','RUN');
    if(type==='league') _resetLeague();
}

function _accGetAll(){ try{return JSON.parse(localStorage.getItem('dh2_accounts')||'[]');}catch{return [];} }
function _accSetAll(arr){ localStorage.setItem('dh2_accounts',JSON.stringify(arr)); }

function _accSaveCurrent(){
    if(!_user||!_jwt||!_sub){ _notif('⚠️','Not connected','Please wait for connection.'); return; }
    const all=_accGetAll();
    if(all.find(a=>a.id==_sub)){ _notif('ℹ️','Already saved','This account is already in the list.'); return; }
    let pic='';
    if(_user.picture){
        pic=_user.picture.replace(/\/(medium|large|small)$/,'/xlarge');
        if(!pic.endsWith('/xlarge')&&pic.includes('duolingo.com/ssr-avatars')) pic+='/xlarge';
    }
    all.push({ id:_sub, username:_user.username||'User', pic, token:_jwt });
    _accSetAll(all);
    _notif('✅','Account Saved',`Saved account: ${_user.username}`);
    _renderAccounts();
}

function _accRemove(id){
    const all=_accGetAll().filter(a=>a.id!=id);
    _accSetAll(all);
    _renderAccounts();
    _notif('🗑️','Removed','Account removed from list.');
}

function _accLogin(id){
    const acc=_accGetAll().find(a=>a.id==id);
    if(!acc){ _notif('⚠️','Not found','Account not found.'); return; }
    document.cookie=`jwt_token=${acc.token}; domain=.duolingo.com; path=/; max-age=31536000`;
    window.location.reload();
}

function _renderAccounts(){
    const wrap=document.getElementById('DH_AccList_Wrap'); if(!wrap) return;
    const all=_accGetAll();
    const saveBtn=document.getElementById('DH_AccSave_Btn');
    if(saveBtn) saveBtn.disabled=!_user;

    if(all.length===0){
        wrap.innerHTML=`<p class="DH_T2 DH_NoSel" style="text-align:center;padding:8px 0;">No saved accounts.</p>`;
        return;
    }
    wrap.innerHTML='';
    all.forEach(acc=>{
        const card=document.createElement('div');
        card.className='DH_Acc_Card';
        const isCurrentUser=_sub&&acc.id==_sub;
        const picHtml=acc.pic
            ?`<img src="${acc.pic}" style="width:100%;height:100%;object-fit:cover;border-radius:50%;" onerror="this.parentNode.innerHTML='👤'">`
            :'👤';
        card.innerHTML=`
            <div class="DH_Acc_Avatar">${picHtml}</div>
            <div class="DH_Acc_Info">
                <p class="DH_Acc_Name DH_NoSel">${acc.username}</p>
                ${isCurrentUser
                    ? `<p class="DH_Acc_Sub active DH_NoSel"><svg width="8" height="8" viewBox="0 0 8 8"><circle cx="4" cy="4" r="4" fill="rgb(var(--DH-green))"><animate attributeName="opacity" values="1;0.4;1" dur="2s" repeatCount="indefinite"/></circle></svg>Active</p>`
                    : `<p class="DH_Acc_Sub DH_NoSel">ID: ${String(acc.id).slice(0,8)}…</p>`
                }
            </div>
            <div class="DH_Acc_Action_Row">
                ${!isCurrentUser?`<button class="DH_Acc_Btn login" data-id="${acc.id}">LOG IN</button>`:''}
                <button class="DH_Acc_Btn del" data-id="${acc.id}">✕</button>
            </div>
        `;
        card.querySelector('.del').addEventListener('click',e=>{ e.stopPropagation(); _accRemove(acc.id); });
        const loginBtn=card.querySelector('.login');
        if(loginBtn) loginBtn.addEventListener('click',e=>{ e.stopPropagation(); _accLogin(acc.id); });
        wrap.appendChild(card);
    });
}

function _goalHdrsLocal(jwt){
    return {'Content-Type':'application/json','x-requested-with':'XMLHttpRequest','accept':'application/json; charset=UTF-8','Authorization':'Bearer '+jwt};
}
function _mqGm(method,url,data,hdrs){
    return new Promise((res,rej)=>GM_xmlhttpRequest({
        method,url,headers:hdrs,
        data:data?JSON.stringify(data):null,
        onload:r=>res(r),onerror:()=>rej(new Error('Network')),
        timeout:15000,ontimeout:()=>rej(new Error('Timeout'))
    }));
}
function _mqGetTimestamp(goalId){
    const m=goalId.match(/^(\d{4})_(\d{2})_monthly/);
    if(m){const d=new Date(Date.UTC(parseInt(m[1]),parseInt(m[2])-1,15,12,0,0));return d.toISOString();}
    return new Date().toISOString();
}

async function _loadMonthlyQuests(){
    const cont=document.getElementById('DH_MQ_Container'); if(!cont) return;
    const claimBtn=document.getElementById('DH_MQ_ClaimAll_Btn');
    if(!_jwt||!_sub){ cont.innerHTML=`<p class="DH_T2 DH_NoSel" style="text-align:center;padding:8px 0;">Not connected.</p>`; return; }
    cont.innerHTML=`<p class="DH_T2 DH_NoSel" style="text-align:center;padding:8px 0;">⟳ Loading…</p>`;
    const gh=_goalHdrsLocal(_jwt);
    const tz=Intl.DateTimeFormat().resolvedOptions().timeZone;
    try{
        const [schemaR,progR]=await Promise.all([
            _mqGm('GET',`${GOALS_API}/schema?ui_language=en&_=${Date.now()}`,null,gh),
            _mqGm('GET',`${GOALS_API}/users/${_sub}/progress?timezone=${tz}&ui_language=en`,null,gh)
        ]);
        if(schemaR.status!==200||progR.status!==200) throw new Error('API error');
        const schema=JSON.parse(schemaR.responseText);
        const prog=JSON.parse(progR.responseText);
        const progress=prog.goals?.progress||{};
        const earned=new Set(prog.badges?.earned||[]);
        _questState={schema,progress,earned};
        _renderMonthlyQuests(schema,progress,earned,gh);
        if(claimBtn){ claimBtn.disabled=false; }
    }catch(e){
        cont.innerHTML=`<p class="DH_T2 DH_NoSel" style="text-align:center;color:rgb(var(--DH-red));padding:8px 0;">Failed to load quests.</p>`;
    }
}

function _renderMonthlyQuests(schema,progress,earned,gh){
    const cont=document.getElementById('DH_MQ_Container'); if(!cont) return;
    cont.innerHTML='';
    const now=new Date();
    const yr=now.getFullYear().toString();
    const mo=(now.getMonth()+1).toString().padStart(2,'0');
    const mReg=new RegExp(`^${yr}_${mo}_monthly`);
    const map=new Map();
    schema.goals.forEach(g=>{
        const m2=g.goalId.match(/^(\d{4}_\d{2})_monthly/);
        if(!m2) return;
        const key=m2[1];
        const existing=map.get(key);
        if(!existing){map.set(key,g);}
        else{
            const existIsChallenge=existing.category?.includes('CHALLENGE');
            const newIsChallenge=g.category?.includes('CHALLENGE');
            if(!existIsChallenge&&newIsChallenge) map.set(key,g);
        }
    });
    const goals=[...map.values()].filter(g=>g.goalId.match(mReg)||true).reverse();
    const monthly=goals.filter(g=>g.category&&g.category.includes('MONTHLY'));
    if(monthly.length===0){
        cont.innerHTML=`<p class="DH_T2 DH_NoSel" style="text-align:center;padding:8px 0;">No monthly quests found.</p>`;
        return;
    }
    monthly.forEach(g=>{
        const isEarned=earned.has(g.badgeId)||earned.has(g.goalId);
        let cur=0;
        const raw=progress[g.goalId];
        if(typeof raw==='number') cur=raw;
        else if(raw&&typeof raw==='object') cur=raw.progress||0;
        const tgt=g.threshold||10;
        let pct=Math.min(100,(cur/tgt)*100);
        if(isEarned){pct=100;cur=tgt;}
        const remaining=Math.max(0,tgt-cur);

        let icon='https://d35aaqx5ub95lt.cloudfront.net/images/achievement/aca5f82d97f5e67c1acb1ea05a0e6d1a.svg';
        const badge=schema.badges?.find(x=>x.badgeId===g.badgeId);
        if(badge&&badge.icon?.enabled?.lightMode){
            icon=badge.icon.enabled.lightMode.svg||badge.icon.enabled.lightMode.url||icon;
        }

        const item=document.createElement('div');
        item.className=`DH_Quest_Item${isEarned?' done':''}`;
        item.innerHTML=`
            <img src="${icon}" class="DH_Quest_Icon" onerror="this.src='https://d35aaqx5ub95lt.cloudfront.net/images/achievement/aca5f82d97f5e67c1acb1ea05a0e6d1a.svg'">
            <div class="DH_Quest_Info">
                <p class="DH_Quest_Title DH_NoSel">${g.title?.uiString||g.goalId}</p>
                <p class="DH_Quest_Meta DH_NoSel">${isEarned?'COMPLETED':''+cur+' / '+tgt+' · '+g.metric}</p>
                <div class="DH_Quest_Bar_Bg"><div class="DH_Quest_Bar_Fill" style="width:${pct}%"></div></div>
            </div>
            ${!isEarned&&remaining>0?`<button class="DH_Quest_Get_Btn" data-metric="${g.metric}" data-amount="${remaining}" data-id="${g.goalId}">GET +${remaining}</button>`:''}
            ${isEarned?`<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="flex-shrink:0;"><circle cx="12" cy="12" r="10" fill="rgba(var(--DH-green),0.15)" stroke="rgb(var(--DH-green))" stroke-width="1.5"/><path d="M7.5 12.5l3 3 6-6" stroke="rgb(var(--DH-green))" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`:''}
        `;
        const btn=item.querySelector('.DH_Quest_Get_Btn');
        if(btn) btn.addEventListener('click',async()=>{
            btn.disabled=true; btn.textContent='…';
            try{
                const payload={
                    metric_updates:[{metric:btn.dataset.metric,quantity:parseInt(btn.dataset.amount)}],
                    timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,
                    timestamp:_mqGetTimestamp(btn.dataset.id)
                };
                const r=await _mqGm('POST',`${GOALS_API}/users/${_sub}/progress/batch`,payload,gh);
                if(r.status===200){
                    btn.textContent='✓'; btn.classList.add('done');
                    _notif('✅','Quest Done!','Progress injected successfully.');
                    setTimeout(()=>_loadMonthlyQuests(),900);
                } else { btn.textContent='ERR'; btn.disabled=false; }
            }catch{ btn.textContent='ERR'; btn.disabled=false; }
        });
        cont.appendChild(item);
    });
}

async function _claimAllMonthly(){
    if(!_questState||!_questState.schema){ _notif('⚠️','Not loaded','Open Monthly Quests first.'); return; }
    const claimBtn=document.getElementById('DH_MQ_ClaimAll_Btn');
    if(claimBtn){ claimBtn.disabled=true; const lbl=claimBtn.querySelector('.DH_Sm_Btn_Label'); if(lbl) lbl.textContent='…'; }
    const gh=_goalHdrsLocal(_jwt);
    const uniqueMetrics=new Set();
    _questState.schema.goals.forEach(g=>{
        if(g.category&&g.category.includes('MONTHLY')&&g.metric) uniqueMetrics.add(g.metric);
    });
    if(uniqueMetrics.size>0){
        const updates=[...uniqueMetrics].map(m=>({metric:m,quantity:2000}));
        updates.push({metric:'QUESTS',quantity:1});
        const payload={metric_updates:updates,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timestamp:new Date().toISOString()};
        try{
            await _mqGm('POST',`${GOALS_API}/users/${_sub}/progress/batch`,payload,gh);
            _notif('✅','Monthly Quests','All monthly quests claimed!');
            setTimeout(()=>_loadMonthlyQuests(),900);
        }catch{ _notif('❌','Error','Failed to claim quests.'); }
    } else { _notif('ℹ️','Nothing to do','No monthly metrics found.'); }
    if(claimBtn){ claimBtn.disabled=false; const lbl=claimBtn.querySelector('.DH_Sm_Btn_Label'); if(lbl) lbl.textContent='CLAIM'; }
}

document.getElementById('DH_Hide_Btn').addEventListener('click',()=>_doHide(!_hidden));


document.getElementById('DH_SwitchV1_Btn').addEventListener('click',()=>{
    _v1Mode=true;

    document.getElementById('DH_SwitchV1_Btn').style.display='none';
    document.getElementById('DH_SwitchV2_Btn').style.display='';
    _v1SyncUser();
    _goPage('V1');
});

document.getElementById('DH_SwitchV2_Btn').addEventListener('click',()=>{
    _v1Mode=false;

    if(_v1Running){_v1Running=false;_v1Task=null;}

    document.getElementById('DH_SwitchV2_Btn').style.display='none';
    document.getElementById('DH_SwitchV1_Btn').style.display='';
    _goPage(1);
});


document.getElementById('DH_V1_XP_Btn').addEventListener('click',()=>_v1RunToggle('xp'));
document.getElementById('DH_V1_Gem_Btn').addEventListener('click',()=>_v1RunToggle('gems'));
document.getElementById('DH_V1_Streak_Btn').addEventListener('click',()=>_v1RunToggle('streak'));
document.getElementById('DH_V1_Settings_Btn').addEventListener('click',()=>{ _goPage(4); _initHideProfileToggle(); });
document.getElementById('DH_Discord_Btn').addEventListener('click',()=>window.open('https://discord.com/invite/Gvmd7deFtS','_blank'));
document.getElementById('DH_GitHub_Btn').addEventListener('click',()=>window.open('https://github.com/not2pixel/DuoHacker','_blank'));

async function _getPrivacy(){
    if(!_sub||!_hdrs) return null;
    try{
        const r=await _gm('GET',`https://www.duolingo.com/2023-05-23/users/${_sub}/privacy-settings?fields=privacySettings`);
        if(r.status!==200) return null;
        const data=JSON.parse(r.responseText);
        const social=data.privacySettings?.find(x=>x.id==='disable_social');
        return social?social.enabled:null;
    }catch(e){ return null; }
}
async function _setPrivacy(hide){
    if(!_sub||!_hdrs) return false;
    try{
        const r=await _gm('PATCH',`https://www.duolingo.com/2023-05-23/users/${_sub}/privacy-settings?fields=privacySettings`,{DISABLE_SOCIAL:hide});
        return r.status===200||r.status===204;
    }catch(e){ return false; }
}
function _applyHideProfileToggle(){
    const tog=document.getElementById('DH_HideProfile_Toggle');
    const lbl=document.getElementById('DH_HideProfile_Status');
    if(!tog||!lbl) return;
    if(_privacy===null){ lbl.textContent='Unavailable'; tog.disabled=true; return; }

    if(!tog.dataset.dhBound){
        tog.dataset.dhBound='1';
        tog.addEventListener('change',async function(){
            tog.disabled=true;
            lbl.textContent='Saving\u2026';
            const ok=await _setPrivacy(tog.checked);
            if(ok){
                _privacy=tog.checked;
                lbl.textContent=tog.checked?'Profile is private':'Profile is public';
            }else{
                tog.checked=!tog.checked;
                lbl.textContent='Failed \u2014 try again';
            }
            tog.disabled=false;
        });
    }
    tog.checked=_privacy;
    tog.disabled=false;
    lbl.textContent=_privacy?'Profile is private':'Profile is public';
}
function _initHideProfileToggle(){
    const tog=document.getElementById('DH_HideProfile_Toggle');
    const lbl=document.getElementById('DH_HideProfile_Status');
    if(!tog||!lbl) return;
    if(!_sub||!_hdrs){ lbl.textContent='Not connected'; tog.disabled=true; return; }
    if(_privacy!==null){ _applyHideProfileToggle(); return; }

    lbl.textContent='Loading\u2026'; tog.disabled=true;
    _getPrivacy().then(v=>{ _privacy=v; _applyHideProfileToggle(); });
}

document.getElementById('DH_Settings_Btn').addEventListener('click',()=>{_goPage(2);_initHideProfileToggle();});
document.getElementById('DH_Back_Btn').addEventListener('click',()=>_goBack());
document.getElementById('DH_Shop_Btn').addEventListener('click',()=>{_goPage(3);_loadShop();});
document.getElementById('DH_Shop_Back_Btn').addEventListener('click',()=>_goBack());
document.getElementById('DH_Page4_Btn').addEventListener('click',()=>{ _goPage(4); _initHideProfileToggle(); });
document.getElementById('DH_Settings_Back_Btn').addEventListener('click',()=>{
    _initHideProfileToggle();
    _goBack();
});

document.getElementById('DH_AccSettings_Btn').addEventListener('click',()=>_goPage(5));
document.getElementById('DH_AccMgr_Back_Btn').addEventListener('click',()=>_goBack());
document.getElementById('DH_AccSave_Btn').addEventListener('click',()=>_accSaveCurrent());

document.getElementById('DH_MonthlyQuest_Nav_Btn').addEventListener('click',e=>{
    if(!e.target.closest('#DH_MonthlyQuest_Claim_Btn')) _goPage(6);
});
document.getElementById('DH_MonthlyQuest_Claim_Btn').addEventListener('click',e=>{
    e.stopPropagation();
    _goPage(6);
});
document.getElementById('DH_MQ_Back_Btn').addEventListener('click',()=>_goBack());
document.getElementById('DH_Credits_Back_Btn').addEventListener('click',()=>_goBack());
document.getElementById('DH_Credits_Btn').addEventListener('click',()=>{
    const container=document.getElementById('DH_Credits_Container');
    container.innerHTML='';
    CREDITS.forEach(c=>{
        const card=document.createElement('div');
        card.className='DH_Credit_Card';
        const header=document.createElement('div');
        header.className='DH_Credit_Card_Header';
        const img=document.createElement('img');
        img.className='DH_Credit_Thumb';
        img.src=c.thumbnail;
        img.alt='';
        img.onerror=function(){this.style.display='none';};
        const info=document.createElement('div');
        info.style.cssText='display:flex;flex-direction:column;gap:1px;min-width:0;';
        const name=document.createElement('p');
        name.className='DH_Credit_Script DH_NoSel';
        name.textContent=c.script;
        const author=document.createElement('p');
        author.className='DH_Credit_Author DH_NoSel';
        author.textContent='by '+c.author;
        info.appendChild(name);
        info.appendChild(author);
        header.appendChild(img);
        header.appendChild(info);
        const task=document.createElement('p');
        task.className='DH_Credit_Task DH_NoSel';
        task.textContent=c.task;
        const link=document.createElement('a');
        link.className='DH_Credit_Link';
        link.href=c.url;
        link.target='_blank';
        link.rel='noopener';
        link.textContent='View Script \u2197';
        card.appendChild(header);
        card.appendChild(task);
        card.appendChild(link);
        container.appendChild(card);
    });
    _goPage(7);
});
document.getElementById('DH_MQ_ClaimAll_Btn').addEventListener('click',()=>_claimAllMonthly());

const xpI=document.getElementById('DH_XP_Input'),xpB=document.getElementById('DH_XP_Btn');
xpI.addEventListener('input',()=>{xpB.disabled=!_user||!xpI.value||+xpI.value<30;});
xpB.addEventListener('click',()=>{
    if(_running&&_task==='xp'){_run('xp',0);return;}
    if(_running){_notif('⚠️','Busy','Stop current farm first.');return;}
    const v=+xpI.value;if(v<30){_notif('⚠️','Min 30 XP','Enter at least 30 XP.');return;}_run('xp',v);
});
xpI.addEventListener('keydown',e=>{if(e.key==='Enter'&&!xpB.disabled)xpB.click();});

const gmI=document.getElementById('DH_Gem_Input'),gmB=document.getElementById('DH_Gem_Btn');
gmI.addEventListener('input',()=>{gmB.disabled=!_user||!gmI.value||+gmI.value<1;});
gmB.addEventListener('click',()=>{
    if(_running&&_task==='gem'){_run('gem',0);return;}
    if(_running){_notif('⚠️','Busy','Stop current farm first.');return;}
    const v=+gmI.value;if(v<1)return;_run('gem',v);
});
gmI.addEventListener('keydown',e=>{if(e.key==='Enter'&&!gmB.disabled)gmB.click();});

const stI=document.getElementById('DH_Streak_Input'),stB=document.getElementById('DH_Streak_Btn');
stI.addEventListener('input',()=>{stB.disabled=!_user||!stI.value||+stI.value<1;});
stB.addEventListener('click',()=>{
    if(_running&&_task==='streak'){_run('streak',0);return;}
    if(_running){_notif('⚠️','Busy','Stop current farm first.');return;}
    const v=+stI.value;if(v<1)return;_run('streak',v);
});
stI.addEventListener('keydown',e=>{if(e.key==='Enter'&&!stB.disabled)stB.click();});

const prI=document.getElementById('DH_Practice_Input'),prB=document.getElementById('DH_Practice_Btn');
prI.addEventListener('input',()=>{prB.disabled=!_user;});
prB.addEventListener('click',()=>{
    if(_lessonSolving){

        _stopPractice();
        sessionStorage.removeItem('dh2_practice');
        _notif('⏹️','Stopped','Practice farm stopped.');
        return;
    }
    if(_running){_notif('⚠️','Busy','Stop current farm first.');return;}
    if(!_user){_notif('⚠️','Not connected','Please wait.');return;}
    const v=parseInt(prI.value)||0;

    sessionStorage.setItem('dh2_practice',JSON.stringify({active:true,count:v,done:0}));
    _farmPractice(v);
});

document.getElementById('DH_League_Btn').addEventListener('click',()=>{
    if(_running&&_task==='league'){_run('league',0);return;}
    if(_running){_notif('⚠️','Busy','Stop current farm first.');return;}
    _run('league',0);
});

document.getElementById('DH_Quest_Btn').addEventListener('click',async()=>{
    if(_running){_notif('⚠️','Busy','Stop current farm first.');return;}
    await _farmDailyQuest();
});

const delI=document.getElementById('DH_Delay_Input'),delB=document.getElementById('DH_Delay_Btn');
delB.addEventListener('click',()=>{
    const v=parseInt(delI.value);
    if(!isNaN(v)&&v>=0){
        _delay=v; localStorage.setItem('dh2_delay',v);
        _setBtnState('DH_Delay_Btn',_C_GREEN,'SAVED ✓');
        setTimeout(()=>_setBtnState('DH_Delay_Btn',_C_BLUE,'SAVE'),1500);
    }
});

const supT=document.getElementById('DH_Super_Toggle');
supT.checked=localStorage.getItem('dh2_super')==='true';
supT.addEventListener('change',()=>{ localStorage.setItem('dh2_super',supT.checked?'true':'false');
    _notif('ℹ️','Reload required','Refresh page to apply.',4);
});

const solverT=document.getElementById('DH_Solver_Toggle');
solverT.checked=localStorage.getItem('duohacker_inject_solver')==='true';
_INJECT_SOLVER_ENABLED=solverT.checked;
solverT.addEventListener('change',()=>{
    _INJECT_SOLVER_ENABLED=solverT.checked;
    localStorage.setItem('duohacker_inject_solver',solverT.checked?'true':'false');
    if(!_INJECT_SOLVER_ENABLED){
        _autoSolver.removeUI();
    } else {
        const inLesson=window.location.pathname.includes('/lesson')||window.location.pathname.includes('/practice');
        if(inLesson) setTimeout(()=>_autoSolver.createUI(),300);
    }
});

document.getElementById('DH_Shop_Search').addEventListener('input',e=>{
    _renderShop(_allShopItems,e.target.value);
});

let _hideAnimObserver=null;
const _HIDE_ANIM_STYLE_ID='DH_HideAnim_Style';
const _HIDE_ANIM_KEY='duohacker_hide_animation';
const _HIDE_PROTECT=['#DH_Root','#DH_Root *'];

function _applyHideAnim(){
    if(document.getElementById(_HIDE_ANIM_STYLE_ID)) return;
    const s=document.createElement('style');
    s.id=_HIDE_ANIM_STYLE_ID;
    s.textContent=`
body img:not(#DH_Root img),
body svg:not(#DH_Root svg),
body [role="img"]:not(#DH_Root [role="img"]),
body canvas:not(#DH_Root canvas),
body video:not(#DH_Root video),
body lottie-player:not(#DH_Root lottie-player) {
    visibility:hidden!important;
    animation:none!important;
    transition:none!important;
}
body * {
    animation-play-state:paused!important;
    transition:none!important;
}
#DH_Root {
    visibility:visible!important;
}
#DH_Root * {
    animation-play-state:running!important;
    visibility:visible!important;
    transition:unset!important;
}`;
    document.head.appendChild(s);
}

function _removeHideAnim(){
    document.getElementById(_HIDE_ANIM_STYLE_ID)?.remove();
}

const _hideAnimT=document.getElementById('DH_HideAnim_Toggle');
_hideAnimT.checked=localStorage.getItem(_HIDE_ANIM_KEY)==='true';
if(_hideAnimT.checked) _applyHideAnim();
_hideAnimT.addEventListener('change',()=>{
    localStorage.setItem(_HIDE_ANIM_KEY,_hideAnimT.checked?'true':'false');
    _hideAnimT.checked?_applyHideAnim():_removeHideAnim();
});

const CREDITS = [
    {
        script: 'DuoHacker V1',
        url: 'https://github.com/not2pixel/DuoHacker',
        thumbnail: 'https://raw.githubusercontent.com/not2pixel/DuoHacker/refs/heads/main/images/DuoHacker_Logo_NoBG_PNG.png',
        author: 'not2pixel',
        task: 'Original script - The main cores are being used in V2'
    },
    {
        script: 'Duolingo PRO',
        url: 'https://github.com/anonymoushackerIV/Duolingo-PRO',
        thumbnail: 'https://www.duolingopro.net/static/favicons/duo/128/light/primary.png',
        author: 'anonymoushackerIV',
        task: 'The V2 UI was inspired by this script'
    }
];

const main=document.getElementById('DH_Main');
const box=document.getElementById('DH_Main_Box');

main.style.bottom=`-${box.offsetHeight-8}px`;
box.style.opacity='0'; box.style.filter='blur(8px)';

_doHide(false);
setTimeout(()=>{
    main.style.transition='0.8s cubic-bezier(0.16,1,0.32,1)';
    box.style.transition='0.8s cubic-bezier(0.16,1,0.32,1)';
    main.style.bottom='16px'; box.style.opacity=''; box.style.filter='';
    setTimeout(()=>{main.style.transition='';box.style.transition='';},800);
},600);
let _licenseLoaded=false;
function _loadLicense(){
    if(_licenseLoaded) return;
    const txt=document.getElementById('DH_License_Text');
    if(!txt) return;
    GM_xmlhttpRequest({
        method:'GET',
        url:'https://raw.githubusercontent.com/not2pixel/DuoHacker/refs/heads/main/LICENSE',
        onload:r=>{
            if(!document.getElementById('DH_License_Text')) return;
            document.getElementById('DH_License_Text').textContent=
                r.status===200?r.responseText:'Could not load license. Please check your connection.';
            _licenseLoaded=true;
        },
        onerror:()=>{
            const t=document.getElementById('DH_License_Text');
            if(t) t.textContent='Could not load license. Please check your connection.';
        }
    });
}
document.getElementById('DH_License_Open_Btn').addEventListener('click',()=>_goPage(9));
document.getElementById('DH_License_Back_Btn').addEventListener('click',()=>_goBack());

_connect();

setTimeout(()=>{
    if(!_v1Mode){
        const sb=document.getElementById('DH_SwitchV1_Btn');
        if(sb&&!_hidden) sb.style.display='';
    }
},700);

_resumePracticeIfNeeded();

})();