max / Duolingo DuoHacker دوهاكر

// ==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.21

// @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.21</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 === '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 (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';

            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 blank = window.sol.displayTokens?.find(t => t.isBlank);
                    const answer = blank?.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;
            }
        } 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', '._1N-oo._36Vd3._16r-S._1ZBYz._23KDq._1S2uf.HakPM'];
        skipSelectors.forEach(sel => document.querySelector(sel)?.click());
        try {
            let mainElement = document.querySelector('._3yE3H');
            if (!mainElement) mainElement = document.querySelector('.RMEuZ._1GVfY') || document.querySelector('[data-test="challenge"]') || document.querySelector('[class*="challenge"]');
            if (!mainElement) {
                _autoSolver.clickNext();
                _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);
            }
            _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.21';

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

})();