duogang / DuoGang

// ==UserScript==
// @name         DuoGang
// @license CC-BY-NC-SA-4.0; https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
// @license GPL-3.0-or-later; http://www.gnu.org/licenses/gpl-3.0.txt
// @namespace  https://openuserjs.org/users/duogang
// @version      2.1.23
// @description  Duolingo automation - Auto-solve lessons, farm XP, Gems, Streaks 
// @author      DuoGangTeam
// @match        *://*.duolingo.com/*
// @match        *://*.duolingo.cn/*
// @icon      data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAfKklEQVR42u17eZRlV1nv7/v2PsMd69Y8dFXPY7pDd7o7nXSmTtJkMBDIwwwIERAEmUTNExUUIvGJGtEIy/d4IA+eCCwMikiYNAToQCBkHjs9psfqmm/d+d5zzt77e3/cqu5KG6TbFcW1fGets6pu3VPnnO+3v/H3fRv4/8fP/KD/qoLz3Dl/qP8KKz0v9ClhB7M9pwmv5z7zf4R20L/TPReeFoCcflFq2cD5cPJupdSMc3bcAWgenvhTepFrFwDn5j4LXvy6nykA86toX+zLzhVDI1EifbFp+Qbc67F+S28ud1U+lRpNkqR4olrOJcbsc4K/15AZ7QWjHLnR2thYEYCjBZIveJ4sAOVnBgDPrwgBWLxkSXikXlwM0CZovSadSu0koiiKo7JmnvV9/9qQVc1XugXIAIFmiIgAOOPMWiPit5JkJjIJQfCc7/tPxyaZjppRhKT1PQiOnTO0fOy53btjeaHGuZ8FAAzAERF4qOtKG7U26TC1vSPT0ded78ikfX9Vy0TlOIqey7AqpgJ/NZysISBFRAwQaMEbiIgjIuPENRqxcU2bHBbFE5kgNcSsRmpx9FyxWjo8W6nOSr16n5/J705OTO+TU77D/EcBQPMrzou6L7dJ9IquQvcFy4ZGOruyhYBNtChJmm6yUn3WGpPLaG+573mhiMBaCycCEREBSEREnAOIQETERFDMYKXARGglSVRPosnAD+LefGE4TKVakaBartef3HPkYL3aqFPaT/1x4+jYY6f5iX83AAiAbNmyxXti7NBfZlLpa89ft6HYly/0l2eL/ZVamSuNemO22Xi6K5VblfK9rjmhrYiQtZZFZH7FMf/7yZsTgYnBikUrBaUUERHqUWtsttE81JvNXJRLp9FR6EKYykwfHBuNdh86mCQu+bg9PnOnnJJJ/j0AIADUvWZNplSbvmegs2f95edt03GrUThy9BCMSUSIazPN5uN9mcx2zeRZJwKAjLUQcbDWAYBQ+1io/nDOuTYG7S88raG1BgDRSlFkTWu20XiyKww3WGdT2XSWhxctkaZ1U997/MGk3mrcbY7P3CZnoQnq3+DpnQn5/fl0+hVXb7uEyqVi14GDex0ACXyfy63mNwthuMlXnDfOybyVU1vFoT2NINCklQJDOYAtM5OnFXkBE4FIHGTh4hARWWtdoD1PKS41EvOjbJja0IpadqY4Tb3dPdkVw0tn9o0e2ajymadtpX5wQZR4yQAgAG7NmjW5qWb1fReduzmV9ryhffv3OK00+Z7HLWP2CEk5G4TnGWsdUTvTI2IAJIGvyVqqTM1E+yebDVRRjxvUalZs1CpXo/21khwOPK1SaS8n0gYNEDgIFDM551ygvf6GSY7AST7wvZyIQ6lUkqGBRZ0CPHN8/IRH9ejeeVP9aULps7X9Q+Wp4Uwqc6S/s2fT2OgRMIEAghChaczxXOBf6MQJEUhE5oQXeJ6iidnmbNUrP3fuazC0dINX6OrzfM8nGOOkWnbpseejyce+UatNH8k8vbg/u9o6F1jnwNI2ESIiJyIppTdHJvlhKN5/I7CYJMHk5Bgt7V/U/9TBvddnly76fOnw6JNn4hTPCgACEJtk++rBRRlnbWG2NCvMilgRjLWxETfkKd1trRURobYik2jNND7V2OeWFOkX35u5aGAJQaxALOCcCCDoHqJw1cZgybarfNz7+cbjT/6tfGXlSMctSIyICDnnwG0tEI9VX4NMxVgbE+AzM2ZnZ5Dv7BksZAtJsVq6AMAZAcBnAUBbnRTv6EhntjTrFRibAIBTxEic25fR3uycQxPnBAJAKaJG01SbuVL1jbdnVw0uAeplh2YdiJpAHIHimClqKqqVBEIOr3p79rxlVzQ2T8409/q+JgHEWAvrHJxzwkyshXIOMjH/vGarKc60guHevsedTdafqXfXZ2P/mdWre2rliUP9XV3nVktFEEgACCsFODnsAWvRDm3knINSSgigUrPZSjI2/c1PRs+VJmWxZhxOYoc4onNIuOn58lSmwD9qNdwFJuLzgkxUrVVRqNrGkX6XMkSkiQjWWogIdDtH6HfOTWtWI23ALaKoqXo7uxQc+i7bsUPv2rXLvlQACADU3HScSYfTvtaDURyBmIm4rUSJtbHn6V43F9dZKSEicULSlLiYqxek+Wi6W5P1NatFgWIICREklJqcw7M0EgoyzomWKfLTMK5MxTAy1jAJz9u/c84JwIqpyzhXDjRh3tFGUYx0vnOAlVfaV6v5AKKfVi/os0l5UberUvmO6wF0JkkszHzSLo1Lepm8LDGgWRERoJjbGS/jxz35zLWpwOszxkIEBRFAhAQCFpE8gDwBYAaIqcDwMBWpohWbZMIgNNZBICQCZkUgS2nnMEZEjpVyxMRxFCFD1K09ta5SPJYD0DitcPoXVeSZAbADjF1wgLpUK3UlQARxFPgazAwRiHW0Qiwl9aZtRIlVSeJK5PiwIeNNVVtLXKMUs4cy2B0k5QhM/cqjUe3JmNY0JQ4FE2FtYtEFhxIMV+qRWX98qnog59kZ4+xyn3U99Lwye8lGMJrMXPE8zUoxCwQCB5+1CbTORHH8UbWo52+yKv3D8tGjs6fnMvNA6LNKg5wtpFKpkjOUKpdMHMVmtmWigUQ5E6tEKJvszQ5Sf0fOFnqGILk+l7Vs85d4wUCQMdAhhekcb/ACBWLyPE19UHKeYhKQOBPDs5bIGtcbx9aaZhCYxC5u1CpdtuFlWMwMO7N776O2tzJt95XHrVRqqW8pp7t8TZ2FDn+QSPms9LFsWt2ihK6rxdEJtajvHivR51eme587cOBAtAAIS2eRAVp/Ue9NqTC8o3sgRen+RqZ3CUyhVw8X+qE6+5RN5a3uHXTIFxRSXg5MGsVKA+VyBCbVTu2E2mvlAHECmkv4ZIFmEgGsABEHENDZkUKhEMIhQTOpo1xMUCxqtGaVrVWS8ekTrjp5CNWxvRiRSmHPsePTXYVcumM43+laUTxQT2JTaTX3VaI4dsb+XSjqs7Wxsen50H7GpS8RnGS6PvKGj2R/dfNVgW8igmIFY2PUoxK69Bqszl0n2bSmZxt/LUAsPndQPWqhXGmRMQRmAp/2VBGBENoxBYCDQATQGijkAkkFPpp2FinulPWZN8l4aZz31/8ZNTlOGb8DSjGcA5QG/vmvm7Vv/q/o4ECnPxs5LNKebmXTqTgbBDljbG+l0ZgoNutk4T4RH5m862xSYb79dtAD3w3rW25M3drZT6pRgjSadUoiwRV978P1S+/E2u6raXHqEgz4W2g6foZK5hClgpAy6QBCgsRaWCdwcwm/QOBE4GxbaIFAaUYu46OzI4TyYmrZWRr0L6Sd3XfRmvwNvKb75XRu4dXkEsb+mR9JHAlsC5IKIUf3Itj7o3h0IJMaCUUvo8SGrWZcn23Ua7FNUukwbHak0ulWEv88ctny2fgA+dCH4JAzee1DggwjMjHldLe8ftVnqE9vfkHMWJS5EDdlvoG98afxVP3TSKSMTD6AtR6aLYtGlMA6wDkBhKFZQWkgDDRSoQfNBOtiZNRivCz7K1imbnrBy+TCAVy77HasHDifvnrkV2ENoNIa5MdlWDdjRAoQgWbu8Ik6AMDErlGLKk3y1GMKyhGZXzkrH7B8+ZI3Oaj39Kxw6zIFChKTIO8tMiO5LRKZKgOkFbeVyokFk4KWDCbjZ1A2B6F1AJ6zOpkr3Od/tqOJgLgNirVWnBj0BRuow1uBWKpwrn3PNo/g4MQh1Fkcrf8ITVMW7Xs0e8LVpw+7UY+xWEQ0gFjaj2kKoUsUc93G0w1nAMWvO5uM0SxduvRLWusbW3VjnYViIohyon2pMSlLRAUAcM5Jm8gAMrksAt0BRUpOnBi1rSjS1K6goJjQzpvaLlAsTqLih2xSQZ4cImURg6DgxMEag2wuizAIQQSp1moozzRIs4ZAoH2GHzAaNvlhxcXPALQMJINO5EFH2CbAhEAehnWfjo5NHTyrMEhEBiLw0+33ZqJWT3d/qLWXm6vW4JyDYqZG1Kpns1nT19Pb4UgAcdRoTatqPTlJo8Z1gfYBcYCzIn6eCEIIUgo9PT2axG9rk4OdrVaibBj6nufp/v5+MDOUUjj4/EGK4whE7fJZnDMirDX469Wk9gnfy/aCEhdLMokoHWNsrLHQr50pAA4AOXafNJDNiLEcLJJK6QSgMEmS+ZqEiAjVWq3YiOL0yPBIECcxjLX26LGjDWtcjsCwiYVzYje9htWK7QrGkDz37QT7viNG+6JDP4tWU1rOtiiTTgfFyoyZLM36VT80a1esYGsMOWaamppqTIxPaM/zAicOzkCskFidHPAcvoAT1ZkY1ZlTYpTbHupkYgd3VgAcOXjku/5Id+2CyzvU6APWMji3gNaiOY4vKdVr8frV6zp9HVCcRKhVy3aiVAxzYQaKgWZFZPtblVzwVoVWTQAWGrkkhPZi3v11B+7WKFbKgRFBPWq6aqPmeVozaWUDP3Ag0tZaGR8fT2vdLgacgWQ6YbpeJtUf/FPtEUzOHD6t2pWTsuw6VRucTTlMt98ONnX56/XXunhwA1FUFzfH66JN5zmICBQzK0WmGbVgrU1GJ8YaSnmewEnSFOTWONn486TT4xEWz0YYmWohMzmGc1/r2OWNMbFzUKDIRFSqV1iYWETccF+/IiKtlMLU1FSz2Wy26xEFxHXI6svYW3uVHcWke+RueUHjxP2kbtJZ8QF33AHnitEXdUDNrb/AHCdmgqnN2rYBYADQA729GYh4ioHJmclGrdFIeZ4H5xwZaHnPG/vlDaVxefNEEbcWJ/H6uuCNmXfhbWmSN986YGZLEcLABxNDaw1nLQq5PHV1FDQgaDQadmJiItRaMxFgE0ClrTv31UoqU9IPFvNaBXsmpO/ZANC+NgheUS+51MpLFK55d5g/cWx6xtgYvu+DmeH7Pg32D2SUUmg0m7XRyQnyU2GQRC1USi333nfsjN65ZlwtaTaJybnYGRfpggRhN1a3pukPLm/4N1x/QWtydCpRBCil4CvdGhkYMhABM2N8fCwREdKeRhRHaNYje91vpKlvDVy9ovuQURfMrfVLCMBNbQWiLN8MQtCqW3vZL1P63X9yScwmP3F89EhUr1eRyaRBzNCelvGpibher+fL0zMuHwQzn//Mp92t7/zdJ9/7seMfvv9QV8P3PE51pDirDlLyzH+Xrz4azFzzgee//jsf+PDsH95xh0Oc1KfHJ002lQ4C3/dAhEqlmkxPz4RRFNHY+Ggy0Lm8/pt/eZnbepOouCaiFAEMJWcR38/qEIeagAAnKBYbtO6GycHPXfwnydf/9pHkm/d+uXpi7JhuHIx8ArkgDJLtmzeNvXznyzvfdOvbO7r6wJ965hfWfeTezBc/+kP9V79+nVe5dJW76kRJcv/4eM/D3/yRi4PV/Mij8R3XvvVt/1tffdV1+NRnPm5++MMHkoMH96sojj1jDKczqWTVylWVV15zU3jxDX3+vo47vQOHLHRI7QrLonmmfY8zB2Dy5M3qIIEwodVQOD65D430B7xfeu8feb/x3ne56bGKTBenGSQ0NDCUz3elFAB/MnkMXzz2PmsKB/K3frjvlV9/f+nu/pDeds8jpkEkyWUr7CXf+QHu+uXblrz1uHev95XR17uXL/vD4A/u+B+Agx0fK9Ls7Awxa9XX20edvZmOMdynvzvxfpSmZhHFBC9NDBKDxI7PceLykmsAAIIATIw4tqjXAjAdxxcP34zFmR28svNa9A2uhY8sRXZf6tnKbhyq34sJ9wCaLavKJXabruCdpds6ux7cVdpz60XxTWnflv7im/K5q9838Lbl52Fjacx3pvBj/tLxGzDs7cDizA7VO7ASSxbl0EIZY83v867xr/NY9DB8SqNWJThrQKIhQgzFuZfeBHZBXJt6y4IAsSAGUG00YayPjnwGo9H9ONr8Dkg8MDSILAy14Cyh1fBRrzswMUcN6668RZ+3Z0NP9s++Un3UJ9q35n3ZbSvX0MZmLbbiSJVLDJNpohncgwOtf4QiD4o0DGI4xFAUgCWL6VKEODFgQrvJKmJATM6BzqTYP6u+AANCirpFuM2KQdod3ChBNGMQej58LwTptpo4S4iTDKLIwFqLOf4UIuBa2cjq9bxqeHkWInRBNi1oVKyARYEcxBLKFYImD0HA8AK0eQQJYF2IKDaIkwZYAAbBQgjsrBAFIAm53ZXgnzSwcbZRgACYG39jOCVlc0QrakKI52/BxCAQWnGMcr2BYrmB2XIL5VqMRpS0ixTFIJ5jPVhAGlSvWmFjRYtxjZp1IJC4dukGEjAJnCRotCKUKi0USxGK5SYq1Sbi2IDbpUN7IYQEohQJ6qRl6dadQ90Akp8mI59h/KehS4dGvvSJ1idffVvPwPptgd+sWfCcQG6O1BASgAgMOkVttVsHcPP+iE8RUUQgYZAQMTGxULuvKwTIyRGpdlNVMYMZUIrBitrqOJ/RMiAsECdUnXJVMXrR43vsx4ZvGk79tGhwRhrACu7Eo/Hvbb0+e+Nrb+u4mihR4oSI2lwsSE7yWac/SaSdILevWZiMEmhe2jkhFxotgea/E0gbD17Q+j9Z/fEc6c9CScTY+7Dpfd1vd/P684NVx/+x9TaRk6bwbwJAiUCc13PLqgvD8999Z5c3MVN2s0XTJjBITr74yZMJzG0CkQD4ISOVUsTEgBWxVsQaEWcEzrVpMGcFxjhxFuIsRBwJE5znEzJ5pnROkTXUNh1ycwrUJkXm4IPvM8oTkkyfMI+s34GV7/7jznX5YXWjP9D7Rmr7AX22ACgANjU88Iv5IfVrt320d3HCsZouGvIDNafKfHKq41Si5No2LAIRxok9nEwc59nEKIjPlMkryuQ1ZTsVsgWFTCchUyDkCky5LqZsXlGYVWRI8ew03MGn5ejD98hYdcZzzARxC9VIAHEQ6+CHhANPJFG+l8tGG8n2Sva2jw0sNYncml81tGlufojPNAowANu3tW/55H7z3jd9oHdZftBl9u9rSOgzyUl1pxexLgJE4CxcmGcefSJ+aPNsVHrI+LHX4Ta7gtdQHPcZoYyfEsvaGpuQMgbNVsM2paU7GnVqDPpy/7E9yFw5rNOjBN31c2bQtETARG0Wqe0o5vyAwDI9uSueWLvN35brJjqwv+Y2XNo5fMPbu90//PnMOzbuWPLbT+46Ujl9buAnaoAIaHKP/bVNO7NDO25Mh4cP10TpU2tNBIDcnCrKC6puAretVAzyq3nYkV60gpDbUDFm/DmNVRs7U8MDofWMbqo4KGkTVDM6sOec06HPOb/TL4+rg9fkoNZ2SYejOFi6w1vra0CE5vjAU/NEEAU/IBo7aKPDT7r7t/6cHySxEeMcHTlelpvekesZWh+89pndrQ8QwZ0us/pJfcA/+r+Da7WWW373UwMjETUz5XICrYiECMRztkf0gvuJgygCEQjERHHLybK1QeGJYsj6SPNwrkfrsNkK48jarTd29lx8TSq9fntQ2HRxmNu4PZ0NC15u7P7KkdWthq45FflxPDO6rXvVVa8KR8Ym6kI8Pz5EIGqHd7GQVFbRvX8THfJDph23BKvjphGtFNcbDoU+5Y8sSVd3famSWXZJ/9dKh0rVhb76RQFgghgb/uGVN+d3dPaqnnIjQpgDidBcJ0fmDIBOdnSsFQnTTHFTw0HASsDM1GxEbuvFqfR01Uvi/fXAKNYj1j32iU+27psqusbzT0WNx3bVg4fuqxz7hzujb2zJSnGyIb1ZQ9PeVZ35y1+T2TI6VnXNSHg+86C5IT1xgBcAxVGWu/+4duz6d2U29S0mz8Tt5fECRaMHne0I0q3Zomvtvr/WoqTx0JzpuxczAQJgU0v7+lNdaufR/a4xMd2qZ3scuaQdlNpazpC5T+IAcc519Coa2y+V798dH/dDgsxNfgDMR45WeMW13rkntnYOzVTs0SAMenucdLy/99DAO3LTQ29ZtMG7/RWfyG9Zu63PRbOLM7538MT2wqrlO7ydR46WZLaaMKsXTpShnTW5MK3pu19o/njlZj2zbrtKt+rWzTelnYF09Avv2V2vlqZQCLr4nR+8/YXZ4YsBgHQqWNWqyVDfCIWbrtC5VsOCuM35zTOE4gTWiIQpINvp87P34fCnf6vx94te5tJKO5E5B8ltVgPF2arberUpDNyS2fRI4oa6Ot3SdWvsuk3bz+m8/JVvTW84r7P/vJGx8UdVUONX6is3XBKtPXa0IrWGoTbt50A0x3BRm0XOdCp+/NtJ/NA9Sfm6t2QvcdaKE2GQA8hBYMmYhDZfw4vZN2WTUNf/+afhwkkV/kkA1KqmO8xQ4/pfyvbX61G7AHTthqazIiTighDI5ommj1LrC7/beuTzH6o9//J36Vf0r3BdpklgYppLBds5PBFXZxMsXS/dS27wVuhCVGx5W6zNvw6JDAJH7kLemyovvz63Zfk5yNZnE8capLid6hLNpchgOAMJMkSzk7rx1T+rf2bnG8IVqy7k0FpHRCLOnhw+hUkg7CfqVW/JrnCJy7fqdulCWfnFJqGa060t516YMqoj4unpRAJPgRnih0CqgyjIKi6Ocv3Ld8UTf/mu2mhxJuLX/L6+om+F7WtVnZACwQngBLACsdLu/iiFesVJ6CdJ3XTLifrF9WJ9i5va+7fNxpHvl/YfOhFoS7pZFyFNLPPJ4FwnCACsEfgpIhMp+7kP1lxtluzeB+MH/+7ORqU2rZqprIdMXlEQMJhJgkDR6GgTQ+ucWroulRSPy+ULtV+fbv+XfXBJuOuu+hXrL/JSx2dLXKuIE8+RNY4qU0qKx7j43P3Js889YFI65BGIdJ73c8GK3uUG1Wkr7GsYAyjV7vq0U+F29janyAhC5Q/taOx8z5e/McX8bcVUqviKT2Q391yyetClTSJzcp+alxQhwIlkckwm0s3P/V69dehx83D/4tSfHn+y1nP8WZN96GvJ1tXn647V28FDK6GDnIRC4mZKMXROeO0FYerQU81XMeHP3VwCQaer/8prV/qHnqg+te06f2X3mohrJUZlXDBzFNXiMUpXDyVHl16UGjv3WtkyuJq8PT+Q+sN/Zw+svBBLt7yaO/P9BJtAMqFGJqvJ0/MzwXSKohHASxGEXHtGoF0/Q7Egrs8HeVng8QEoBx0CYwco+cqdsT38jLl/7Wb1uj33nZjB3GgN9w1sNSV7JUJsLiyi3p6lNNwxgNWFQUa2Gzj64wBP3hd9R6bHdoq8+IAEA3Dh4qGLWnXzZk/TRicQ26QfK5+KpMzNl92cLV3yen3h9GxNTIvITxGmjsI8dLctTh+xE2su032rL+b+woCAPSBQjMAj53saSjExE4EE4toSssJ8diOuPR0652xFnLQrIQNBtWri3d+Tsfs/Z2ajGh5fvd3++t6vzlQXmPHJFV130znZA98qD8Zkd4KxlX2sI4hlzTYI8Xu158ceODnq/69OUS+Yu+69oK+/Mipfufn9HRt6V7fCZmS1F8AmkZDyBVorHj9Apae+bSemDjozuIJTwxt5uHcxqSAvKggFWisQkWhmYgXHMvcERrtadMR2rsS1QmjUBaUJiyNPiey9H/HUfnzXC/Rvmsljz84Po502AcYLtuksGDZeUDqc4bT4QlRpzlfYcLj/5jiR3+4aotUj61W9MIDedCfgpwBigdIEYxVGn8GxJ76WjDknI/ke1v2r8UxmCTU78rIxl6dFfgbwUgpat8mR+frBJM7FsZSL0xzZBu0bfcKNTBw0hysT2AtSD5xzpf3K7i9N1U4fdPpX9i3xaWNytFBbznZcngBI17aV+eKe8nZEtAQ+bVIpulRrcYDMxrHskViOBxkKUgW1LyQ8OjXhVmZSdNPrt7b0Q8e8vqdP6KNeGh1eSIs8DQKjByzjYlCPY+73EvvMuoKJx0pcPjhGR5fUJ//nYUGkVTsQuAXv8rPYNMULbW3+L862uQkiQBYNb0CdPkQpuyiVklqjbPcsHyH/+79Tf+vTRzFz7QdzH1dd8rgdHf8y0Jtt32Sq0Z/p75kg/dmd21zP599T3fLZ7/kP/9bHg79KD9LLQG5xo0w+tGtk8/T22oHxqZcKhLPdLzAfl9TcSRDIhz7UdtbhwMD5XSn3nr/45fjyN1wm/d991qdCCFy1Xne//op46cpe0uQjfvQQ9+uObMaUJx8DNeL+l/X3VhV/6rxlRn30Da5v1XrbU1Dh2NeeUcshrvud1wT5O9/sth2boe69x9yFq18W3jNzrBm/FJu++N/wPzLnZMyCnFoBQGRo00ivrLn+vLjwzFF8+4tvb/JjHy5dfevW0pZdj7nowX2WdqyOL13aKxsbsVzm2gBSq87DkeGLfuFiu9bE9ZUPPmBqJ060Vnzrt2YvHP1EY7NHsrtLJ8fedrltOKtXNMrctzCd/c+wb5ABSLB48VKh+G9SGiurTTr2O6+Iepd1RfjCw8HgE8d0y1meckS5VuK+TMreFR+a3j/vsMLFg58kJZsDtrETSF/W9V6/0aVXDqH3sw+EDz/2vFSDFF0aJ/j9+OjYnWdCef9Hb5wkALJyJYID9d6tgedtiupuLTQVkMgeBPQtkLGAB5w48eSCFTxlxwMDvbB2kQ7YN5HaAiW3wvCT0FJNefYHzYQOYnx8N/4THy9IH5iAu++G4jMDn07/cPvt0C+ygfgl3e77/wDDQrUr7qEmMQAAAABJRU5ErkJggg==
// @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      fonts.googleapis.com
// @connect      openuserjs.org
// @connect      raw.githubusercontent.com
// @run-at       document-end
// @downloadURL https://openuserjs.org/src/scripts/duogang/DuoGang.user.js
// @updateURL https://openuserjs.org/meta/duogang/DuoGang.meta.js
// ==/UserScript==

(function() {
    'use strict';

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

    GM_addStyle(`
        :root {
            --DG-gold: 255, 179, 0;
            --DG-gold-dark: 204, 143, 0;
            --DG-blue: 0, 122, 255;
            --DG-green: 52, 199, 89;
            --DG-red: 255, 59, 48;
            --DG-purple: 175, 82, 222;
            --DG-orange: 255, 149, 0;
            --DG-pink: 255, 45, 85;
            --DG-indigo: 88, 86, 214;
            --DG-teal: 0, 199, 190;
            --DG-cyan: 90, 200, 250;
            --DG-yellow: 255, 204, 0;

            --DG-bg: rgba(255,255,255,0.92);
            --DG-surface: rgba(248,248,248,0.85);
            --DG-text: rgb(60, 60, 60);
            --DG-text-sub: rgba(60, 60, 60, 0.55);
            --DG-divider: rgba(0,0,0,0.08);
            --DG-outline: rgba(0,0,0,0.08);
            --DG-input-bg: rgba(255, 179, 0, 0.08);
            --DG-input-outline: rgba(255, 179, 0, 0.25);
            --DG-notif-bg: rgba(255,255,255,0.92);
            --DG-shadow: rgba(0,0,0,0.10);

            --DG-corner-s: superellipse(1.32);
            --DG-corner-r-s: 4px;
            --DG-corner-r-m: 8px;
            --DG-corner-r-ml: 12px;
            --DG-corner-r-l: 16px;
            --DG-corner-r-xl: 20px;

            --DG-accent: var(--DG-gold);
            --DG-accent-dark: var(--DG-gold-dark);
        }

        @supports (corner-shape: superellipse(1.32)) {
            :root {
                --DG-corner-r-s: 6px;
                --DG-corner-r-m: 10px;
                --DG-corner-r-ml: 16px;
                --DG-corner-r-l: 20px;
                --DG-corner-r-xl: 26px;
            }
        }

        #DG_Root.DG_Dark {
            --DG-bg: rgba(22,22,28,0.97);
            --DG-surface: rgba(30,30,38,0.95);
            --DG-text: rgb(240, 240, 240);
            --DG-text-sub: rgba(240, 240, 240, 0.55);
            --DG-divider: rgba(255,255,255,0.08);
            --DG-outline: rgba(255,255,255,0.08);
            --DG-input-bg: rgba(255, 179, 0, 0.08);
            --DG-input-outline: rgba(255, 179, 0, 0.28);
            --DG-notif-bg: rgba(28,28,36,0.98);
            --DG-shadow: rgba(0,0,0,0.45);
        }

        #DG_Root * {
            box-sizing: border-box;
            -webkit-font-smoothing: antialiased;
        }
        #DG_Root p, #DG_Root span, #DG_Root button, #DG_Root input, #DG_Root label, #DG_Root div {
            font-family: 'Inter', 'din-round', -apple-system, BlinkMacSystemFont, sans-serif !important;
        }
        #DG_Root p, #DG_Root span { margin: 0; padding: 0; }

        .DG_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;
            transition: bottom 0.8s cubic-bezier(0.16, 1, 0.32, 1), right 0.8s cubic-bezier(0.16, 1, 0.32, 1);
            user-select: none;
        }
        .DG_Main.DG_Dragging { transition: none !important; }
        @media (max-width: 699px) {
            .DG_Main {
                margin-bottom: 80px;
            }
        }

        .DG_Main_Box {
            display: flex;
            width: 320px;
            padding: 16px;
            flex-direction: column;
            gap: 10px;
            border-radius: var(--DG-corner-r-xl);
            corner-shape: var(--DG-corner-s);
            outline: 2px solid var(--DG-outline);
            outline-offset: -2px;
            background: var(--DG-bg);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            box-shadow: 0 8px 32px var(--DG-shadow);
            transition: opacity 0.8s cubic-bezier(0.16, 1, 0.32, 1),
                        filter 0.8s cubic-bezier(0.16, 1, 0.32, 1),
                        width 0.8s cubic-bezier(0.16, 1, 0.32, 1);
            max-height: 80vh;
            overflow-y: auto;
            overflow-x: hidden;
        }

        .DG_HStack { display:flex; align-items:center; gap:8px; align-self:stretch; }
        .DG_HStack_4 { display:flex; align-items:center; gap:4px; align-self:stretch; }
        .DG_HStack_6 { display:flex; align-items:center; gap:6px; align-self:stretch; }
        .DG_HStack_Between { display:flex; align-items:center; justify-content:space-between; align-self:stretch; }
        .DG_HStack_Auto_Top {
            display: flex;
            align-items: flex-start;
            justify-content: space-between;
            align-self: stretch;
        }
        .DG_VStack { display:flex; flex-direction:column; gap:8px; align-self:stretch; }
        .DG_VStack_4 { display:flex; flex-direction:column; gap:4px; align-self:stretch; }
        .DG_VStack_6 { display:flex; flex-direction:column; gap:6px; align-self:stretch; }
        .DG_VStack_0 { display:flex; flex-direction:column; gap:0; align-self:stretch; align-items:flex-start; }
        .DG_Divider { height:1px; background:var(--DG-divider); align-self:stretch; flex-shrink:0; }

        .DG_Title {
            font-size: 16px;
            font-weight: 600;
            color: var(--DG-text);
            line-height: normal;
            margin: 0;
        }
        .DG_Title_Large {
            font-size: 22px;
            font-weight: 700;
            color: var(--DG-text);
            line-height: normal;
            margin: 0;
        }
        .DG_Subtitle {
            font-size: 15px;
            font-weight: 500;
            color: var(--DG-text-sub);
            line-height: normal;
            margin: 0;
        }

        .DG_Btn {
            display:flex;
            height: 42px;
            padding: 10px 14px 10px 12px;
            align-items:center;
            gap: 6px;
            border-radius: var(--DG-corner-r-m);
            corner-shape: var(--DG-corner-s);
            border: none;
            cursor: pointer;
            font-size: 15px;
            font-weight: 600;
            transition: filter 0.4s cubic-bezier(0.16, 1, 0.32, 1),
                        transform 0.4s cubic-bezier(0.16, 1, 0.32, 1);
            user-select: none;
            -webkit-user-select: none;
            flex: 1 0 0;
        }
        .DG_Btn:hover { filter: brightness(0.9); transform: scale(1.04); }
        .DG_Btn:active { filter: brightness(0.85); transform: scale(0.95); }

        .DG_Btn_Primary {
            background: rgb(var(--DG-accent));
            color: #1a1a1a;
            outline: 2px solid rgba(0, 0, 0, 0.18);
            outline-offset: -2px;
        }
        .DG_Btn_Blue {
            background: linear-gradient(0deg, rgba(var(--DG-accent), 0.12) 0%, rgba(var(--DG-accent), 0.12) 100%), rgba(var(--color-snow, 255, 255, 255), 0.80);
            backdrop-filter: blur(16px);
            outline: 2px solid rgba(var(--DG-accent), 0.22);
            outline-offset: -2px;
            color: rgb(var(--DG-accent-dark));
        }
        .DG_Btn_Green {
            background: rgb(var(--DG-green));
            color: #FFF;
            outline: 2px solid rgba(0, 0, 0, 0.18);
            outline-offset: -2px;
        }
        .DG_Btn_Red {
            background: rgb(var(--DG-red));
            color: #FFF;
            outline: 2px solid rgba(0, 0, 0, 0.18);
            outline-offset: -2px;
        }
        .DG_Btn_Ghost {
            background: linear-gradient(0deg, rgba(var(--DG-accent), 0.12) 0%, rgba(var(--DG-accent), 0.12) 100%), rgba(var(--color-snow, 255, 255, 255), 0.80);
            backdrop-filter: blur(16px);
            outline: 2px solid rgba(var(--DG-accent), 0.22);
            outline-offset: -2px;
            color: rgb(var(--DG-accent-dark));
        }
        .DG_Btn_Icon { flex: none; width: 42px; padding: 10px; justify-content: center; }

        .DG_Input_Wrap {
            display:flex;
            height: 48px;
            padding: 16px;
            align-items:center;
            gap: 6px;
            flex: 1;
            border-radius: var(--DG-corner-r-m);
            corner-shape: var(--DG-corner-s);
            outline: 2px solid var(--DG-input-outline);
            outline-offset: -2px;
            background: var(--DG-input-bg);
        }
        .DG_Input {
            border: none;
            outline: none;
            background: none;
            font-size: 16px;
            font-weight: 600;
            color: rgb(var(--DG-accent-dark));
            text-align: right;
            width: 100%;
            font-family: inherit;
            -moz-appearance: textfield;
        }
        .DG_Input::placeholder { color: rgba(var(--DG-accent-dark), 0.40); }
        .DG_Input::-webkit-outer-spin-button,
        .DG_Input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

        .DG_Input_Btn {
            display:flex;
            height: 48px;
            padding: 12px 14px 12px 16px;
            align-items:center;
            gap: 6px;
            border-radius: var(--DG-corner-r-m);
            corner-shape: var(--DG-corner-s);
            border: none;
            cursor: pointer;
            font-size: 15px;
            font-weight: 700;
            color: #1a1a1a;
            background: rgb(var(--DG-accent));
            outline: 2px solid rgba(0, 0, 0, 0.16);
            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);
            white-space: nowrap;
            flex-shrink: 0;
        }
        .DG_Input_Btn:hover { filter: brightness(0.9); transform: scale(1.04); }
        .DG_Input_Btn:active { filter: brightness(0.85); transform: scale(0.95); }
        .DG_Input_Btn:disabled { opacity: 0.5; pointer-events: none; }
        .DG_Input_Btn.Running {
            background: linear-gradient(0deg, rgba(var(--DG-red), 0.12) 0%, rgba(var(--DG-red), 0.12) 100%), rgba(var(--color-snow, 255, 255, 255), 0.80);
            backdrop-filter: blur(16px);
            outline: 2px solid rgba(var(--DG-red), 0.22);
            color: rgb(var(--DG-red));
        }
        .DG_Input_Btn.Done {
            background: linear-gradient(0deg, rgba(var(--DG-green), 0.12) 0%, rgba(var(--DG-green), 0.12) 100%), rgba(var(--color-snow, 255, 255, 255), 0.80);
            backdrop-filter: blur(16px);
            outline: 2px solid rgba(var(--DG-green), 0.22);
            color: rgb(var(--DG-green));
        }

        .DG_Prog_Wrap { height: 0; border-radius: 2px; background: rgba(var(--DG-accent), 0.10); overflow: hidden; transition: height 0.4s; }
        .DG_Prog_Wrap.on { height: 4px; }
        .DG_Prog_Fill { height: 100%; border-radius: 2px; background: linear-gradient(90deg, rgb(var(--DG-accent)), rgb(var(--DG-accent-dark))); width: 0%; transition: width 0.5s; }

        .DG_Page { display: none; flex-direction: column; gap: 10px; }
        .DG_Page.active { display: flex; }

        .DG_Notif {
            display: flex;
            justify-content: center;
            align-items: center;
            transition: 0.8s cubic-bezier(0.16, 1, 0.32, 1);
            width: 300px;
            position: fixed;
            left: calc(50% - (300px / 2));
            z-index: 2147483646;
            bottom: 16px;
            border-radius: var(--DG-corner-r-l);
            corner-shape: var(--DG-corner-s);
        }
        .DG_Notif_Box {
            display: flex;
            width: 300px;
            padding: 16px;
            flex-direction: column;
            gap: 4px;
            border-radius: var(--DG-corner-r-l);
            corner-shape: var(--DG-corner-s);
            outline: 2px solid var(--DG-outline);
            outline-offset: -2px;
            background: var(--DG-notif-bg);
            backdrop-filter: blur(16px);
            -webkit-backdrop-filter: blur(16px);
            box-shadow: 0 8px 32px var(--DG-shadow);
            transition: 0.8s cubic-bezier(0.16, 1, 0.32, 1);
            filter: blur(16px);
            opacity: 0;
        }
        .DG_Notif_Box.show {
            filter: blur(0px);
            opacity: 1;
        }

        .DG_User_Row { display: none; gap: 10px; }
        .DG_Avatar {
            width: 22px;
            height: 22px;
            border-radius: var(--DG-corner-r-l);
            corner-shape: var(--DG-corner-s);
            background: rgba(var(--DG-accent), 0.12);
            overflow: hidden;
            flex-shrink: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
            outline: 2px solid rgba(0, 0, 0, 0.16);
            outline-offset: -2px;
        }
        .DG_Stat { display: flex; align-items: center; gap: 4px; }
        .DG_Stat img { width: 16px; height: 16px; }
        .DG_Stat span { font-size: 15px; font-weight: 600; color: var(--DG-text-sub); }

        .DG_Drag_Handle { cursor: grab; }
        .DG_Drag_Handle:active { cursor: grabbing; }

        .DG_Header_Btns {
            display: flex;
            gap: 8px;
            align-self: flex-end;
        }
        .DG_Header_Btns .DG_Hideable {
            transition: opacity 0.8s cubic-bezier(0.16, 1, 0.32, 1),
                        filter 0.8s cubic-bezier(0.16, 1, 0.32, 1);
        }
        .DG_Header_Btns .DG_Hideable.DG_Header_Hidden {
            opacity: 0;
            filter: blur(8px);
            pointer-events: none;
        }

        .DG_YT_Btn {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 42px;
            height: 42px;
            padding: 0;
            border-radius: var(--DG-corner-r-m);
            corner-shape: var(--DG-corner-s);
            border: none;
            cursor: pointer;
            text-decoration: none;
            background: linear-gradient(0deg, rgba(var(--DG-red), 0.10) 0%, rgba(var(--DG-red), 0.10) 100%), rgba(var(--color-snow, 255, 255, 255), 0.80);
            backdrop-filter: blur(16px);
            outline: 2px solid rgba(var(--DG-red), 0.18);
            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);
            flex-shrink: 0;
            color: rgb(var(--DG-red));
        }
        #DG_Root.DG_Dark .DG_YT_Btn {
            background: rgba(255, 45, 85, 0.12);
            color: rgb(255, 69, 95);
            outline-color: rgba(255, 69, 95, 0.22);
        }
        .DG_YT_Btn:hover { filter: brightness(0.9); transform: scale(1.04); }
        .DG_YT_Btn:active { filter: brightness(0.85); transform: scale(0.95); }

        .DG_DarkToggle {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 42px;
            height: 42px;
            border-radius: var(--DG-corner-r-m);
            corner-shape: var(--DG-corner-s);
            border: none;
            cursor: pointer;
            background: linear-gradient(0deg, rgba(var(--DG-accent), 0.12) 0%, rgba(var(--DG-accent), 0.12) 100%), rgba(var(--color-snow, 255, 255, 255), 0.80);
            backdrop-filter: blur(16px);
            outline: 2px solid rgba(var(--DG-accent), 0.22);
            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);
            flex-shrink: 0;
            color: rgb(var(--DG-accent-dark));
        }
        .DG_DarkToggle:hover { filter: brightness(0.9); transform: scale(1.04); }
        .DG_DarkToggle:active { filter: brightness(0.85); transform: scale(0.95); }

        .DG_Hide_Btn {
            display: flex;
            height: 42px;
            padding: 10px 14px 10px 12px;
            align-items: center;
            gap: 6px;
            border-radius: var(--DG-corner-r-m);
            corner-shape: var(--DG-corner-s);
            cursor: pointer;
            background: linear-gradient(0deg, rgba(var(--DG-accent), 0.12) 0%, rgba(var(--DG-accent), 0.12) 100%), rgba(var(--color-snow, 255, 255, 255), 0.80);
            backdrop-filter: blur(16px);
            outline: 2px solid rgba(var(--DG-accent), 0.22);
            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);
            user-select: none;
            -webkit-user-select: none;
            flex-shrink: 0;
        }
        .DG_Hide_Btn:hover { filter: brightness(0.9); transform: scale(1.04); }
        .DG_Hide_Btn:active { filter: brightness(0.85); transform: scale(0.95); }
        .DG_Hide_Btn svg { flex-shrink: 0; }
        .DG_Eye_Open { display: block; }
        .DG_Eye_Closed { display: none; }
        .DG_Hide_Btn_Hidden .DG_Eye_Open { display: none; }
        .DG_Hide_Btn_Hidden .DG_Eye_Closed { display: block; }

        .DG_Solver_Btn {
            position: fixed;
            bottom: 80px;
            left: 50%;
            transform: translateX(-50%);
            z-index: 2147483647;
            display: flex;
            gap: 20px;
            animation: DG_SlideUp 0.3s ease-out;
        }
        @keyframes DG_SlideUp {
            from { opacity: 0; transform: translateX(-50%) translateY(20px); }
            to { opacity: 1; transform: translateX(-50%) translateY(0); }
        }
        .DG_Solver_Btn button {
            position: relative;
            min-width: 100px;
            font-size: 17px;
            border: none;
            border-bottom: 4px solid rgba(0,0,0,0.2);
            border-radius: 16px;
            padding: 13px 16px;
            transition: filter .0s;
            font-weight: 700;
            letter-spacing: .8px;
            cursor: pointer;
            user-select: none;
        }
        .DG_Solver_Btn button:hover { filter: brightness(1.1); }
        .DG_Solver_Btn button:active { border-bottom: 0; margin-bottom: 4px; top: 4px; }
        .DG_Solve_One { background: rgb(var(--DG-accent)) !important; color: #1a1a1a !important; }
        .DG_Solve_All { background: rgb(var(--DG-blue)) !important; border-bottom-color: #1b5fb8 !important; color: #FFF !important; }

        .DG_Toggle {
            position: relative;
            width: 48px;
            height: 30px;
            flex-shrink: 0;
            cursor: pointer;
            border-radius: 16px;
            outline: 2px solid rgba(0, 0, 0, 0.18);
            outline-offset: -2px;
            transition: transform 0.4s cubic-bezier(0.16, 1, 0.32, 1);
        }
        .DG_Toggle input { opacity: 0; width: 0; height: 0; }
        .DG_Toggle_Slider { position: absolute; inset: 0; background: rgba(0,0,0,0.08); border-radius: 16px; transition: 0.4s cubic-bezier(0.16, 1, 0.32, 1); }
        .DG_Toggle_Slider:before {
            content: '';
            position: absolute;
            width: 22px;
            height: 22px;
            left: 4px;
            top: 4px;
            background: #FFF;
            border-radius: 50%;
            transition: 0.4s cubic-bezier(0.16, 1, 0.32, 1);
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
        }
        .DG_Toggle input:checked + .DG_Toggle_Slider { background: rgb(var(--DG-green)); }
        .DG_Toggle input:checked + .DG_Toggle_Slider:before { transform: translateX(18px); }

        .DG_Shop_Grid {
            display: grid;
            grid-template-columns: repeat(2,1fr);
            gap: 8px;
            align-self: stretch;
        }
        .DG_Shop_Card {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            padding: 14px 10px;
            border-radius: var(--DG-corner-r-m);
            corner-shape: var(--DG-corner-s);
            outline: 2px solid var(--DG-divider);
            outline-offset: -2px;
            background: var(--DG-surface);
            transition: outline-color 0.4s, background 0.4s;
            text-align: center;
        }
        .DG_Shop_Card:hover { outline-color: rgba(var(--DG-accent), 0.35); background: rgba(var(--DG-accent), 0.05); }
        .DG_Shop_Ico { width: 36px; height: 36px; object-fit: contain; }
        .DG_Shop_Name { font-size: 14px; font-weight: 600; color: var(--DG-text); line-height: 1.3; flex: 1; }
        .DG_Shop_Btn {
            width: 100%;
            height: 30px;
            border-radius: var(--DG-corner-r-s);
            corner-shape: var(--DG-corner-s);
            border: none;
            cursor: pointer;
            font-size: 13px;
            font-weight: 700;
            color: #1a1a1a;
            background: rgb(var(--DG-accent));
            outline: 2px solid rgba(0, 0, 0, 0.16);
            outline-offset: -2px;
            transition: filter 0.4s, transform 0.4s, background 0.4s;
        }
        .DG_Shop_Btn:hover { filter: brightness(0.9); transform: scale(1.04); }
        .DG_Shop_Btn:active { filter: brightness(0.85); transform: scale(0.95); }
        .DG_Shop_Btn.got { background: rgba(var(--DG-green), 0.12); color: rgb(var(--DG-green)); outline-color: rgba(var(--DG-green), 0.25); pointer-events: none; }
        .DG_Shop_Btn.fail { background: rgba(var(--DG-red), 0.10); color: rgb(var(--DG-red)); outline-color: rgba(var(--DG-red), 0.22); pointer-events: none; }

        .DG_Scroll_Inner {
            align-self: stretch;
            overflow-y: auto;
            max-height: 240px;
            display: flex;
            flex-direction: column;
            gap: 6px;
            padding-right: 2px;
        }
        .DG_Scroll_Inner::-webkit-scrollbar { width: 3px; }
        .DG_Scroll_Inner::-webkit-scrollbar-thumb { background: rgba(var(--DG-accent), 0.25); border-radius: 3px; }

        .DG_Acc_Card {
            display: flex;
            align-items: center;
            gap: 10px;
            align-self: stretch;
            padding: 10px 12px;
            border-radius: var(--DG-corner-r-m);
            corner-shape: var(--DG-corner-s);
            outline: 2px solid var(--DG-divider);
            outline-offset: -2px;
            background: var(--DG-surface);
            transition: outline-color 0.4s, background 0.4s;
        }
        .DG_Acc_Card:hover { outline-color: rgba(var(--DG-accent), 0.35); background: rgba(var(--DG-accent), 0.05); }
        .DG_Acc_Avatar {
            width: 22px;
            height: 22px;
            border-radius: var(--DG-corner-r-l);
            corner-shape: var(--DG-corner-s);
            flex-shrink: 0;
            background: rgba(var(--DG-accent), 0.12);
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
            outline: 2px solid rgba(0, 0, 0, 0.16);
            outline-offset: -2px;
        }
        .DG_Acc_Info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
        .DG_Acc_Name { font-size: 15px; font-weight: 600; color: var(--DG-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .DG_Acc_Sub { font-size: 14px; font-weight: 500; color: var(--DG-text-sub); }
        .DG_Acc_Sub.active { color: rgb(var(--DG-green)); display: flex; align-items: center; gap: 4px; }
        .DG_Acc_Btn {
            height: 28px;
            padding: 0 10px;
            border-radius: var(--DG-corner-r-s);
            corner-shape: var(--DG-corner-s);
            border: none;
            cursor: pointer;
            font-size: 12px;
            font-weight: 700;
            color: #1a1a1a;
            background: rgb(var(--DG-accent));
            outline: 2px solid rgba(0, 0, 0, 0.16);
            outline-offset: -2px;
            transition: filter 0.4s, transform 0.4s;
        }
        .DG_Acc_Btn:hover { filter: brightness(0.9); transform: scale(1.04); }
        .DG_Acc_Btn:active { filter: brightness(0.85); transform: scale(0.95); }
        .DG_Acc_Btn.del { background: rgba(var(--DG-red), 0.10); color: rgb(var(--DG-red)); outline-color: rgba(var(--DG-red), 0.20); }
        .DG_Acc_Btn.del:hover { background: rgb(var(--DG-red)); color: #FFF; }

        .DG_Magnetic_Hover_1 {
            transition: filter 0.4s cubic-bezier(0.16, 1, 0.32, 1), transform 0.4s cubic-bezier(0.16, 1, 0.32, 1);
            cursor: pointer;
        }
        .DG_Magnetic_Hover_1:hover { filter: brightness(0.9); transform: scale(1.04); }
        .DG_Magnetic_Hover_1:active { filter: brightness(0.85); transform: scale(0.95); }

        .DG_Settings_Toggle_Row {
            display: flex;
            justify-content: center;
            align-items: center;
            align-self: stretch;
            gap: 8px;
        }
        .DG_Settings_Toggle_Info {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            flex: 1 0 0;
            gap: 0;
        }

        @keyframes DG_Rotate_360 {
            from { transform: rotate(0deg); }
            to { transform: rotate(360deg); }
        }
        @keyframes DG_Pulse_Opacity {
            0% { opacity: 1; }
            16.66666666% { opacity: 0.75; }
            33.33333333% { opacity: 1; }
            100% { opacity: 1; }
        }
        @keyframes DG_Outdated_Pulse {
            0%   { box-shadow: 0 0 0 0 rgba(255,140,0,0.55), 0 0 0 0 rgba(255,140,0,0.3); background: rgba(255,140,0,0.18); }
            50%  { box-shadow: 0 0 0 8px rgba(255,140,0,0.18), 0 0 0 16px rgba(255,140,0,0.07); background: rgba(255,140,0,0.32); }
            100% { box-shadow: 0 0 0 0 rgba(255,140,0,0), 0 0 0 0 rgba(255,140,0,0); background: rgba(255,140,0,0.18); }
        }
        @keyframes DG_Outdated_Icon_Bounce {
            0%, 100% { transform: translateY(0); }
            30%       { transform: translateY(-3px); }
            60%       { transform: translateY(1px); }
        }
        #DG_Conn_Btn.DG_Outdated_Btn {
            animation: DG_Outdated_Pulse 2s ease-in-out infinite !important;
            position: relative;
        }
        #DG_Conn_Btn.DG_Outdated_Btn::after {
            content: '⬆ Click to update';
            position: absolute;
            bottom: calc(100% + 8px);
            left: 50%;
            transform: translateX(-50%);
            background: rgba(30,20,0,0.92);
            color: rgb(255,180,40);
            font-size: 12px;
            font-weight: 600;
            padding: 5px 10px;
            border-radius: 8px;
            white-space: nowrap;
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.2s;
            border: 1px solid rgba(255,140,0,0.35);
            z-index: 9999;
        }
        #DG_Conn_Btn.DG_Outdated_Btn:hover::after {
            opacity: 1;
        }
        #DG_Conn_Btn.DG_Outdated_Btn #DG_Conn_Ico {
            animation: DG_Outdated_Icon_Bounce 2s ease-in-out infinite;
        }
        @keyframes slideRight {
            0% { transform: translateX(-150px); }
            20% { transform: translateX(200px); }
            100% { transform: translateX(200px); }
        }
    `);

    
    const wrap = document.createElement('div');
    wrap.id = 'DG_Root';
    wrap.innerHTML = `
        <div class="DG_Notif" id="DG_Notif">
            <div class="DG_Notif_Box" id="DG_Notif_Box">
                <div class="DG_HStack_4" style="align-items: center;">
                    <p class="DG_Title DG_Inset_Icon_1_ID"></p>
                    <p class="DG_Title DG_Inset_Text_1_ID" style="flex: 1 0 0;"></p>
                    <svg class="DG_Magnetic_Hover_1 DG_Inset_Icon_2_ID" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="cursor: pointer; flex-shrink: 0; color: var(--DG-text-sub);">
                        <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
                    </svg>
                </div>
                <p class="DG_Subtitle DG_Inset_Text_2_ID" style="align-self: stretch; overflow-wrap: break-word;"></p>
            </div>
        </div>
        <div class="DG_Main" id="DG_Main">
            <div class="DG_Header_Btns" id="DG_Header_Btns">
                <a class="DG_YT_Btn DG_Magnetic_Hover_1 DG_Hideable" href="https://www.youtube.com/@JULSEXE_Edits/shorts?app=desktop" target="_blank" rel="noopener noreferrer" title="Follow us on YouTube">
                    <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
                        <path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/>
                    </svg>
                </a>
                <button class="DG_DarkToggle DG_Magnetic_Hover_1 DG_Hideable" id="DG_Dark_Btn" title="Toggle dark/light mode">
                    <svg id="DG_Dark_Icon_Moon" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
                    </svg>
                    <svg id="DG_Dark_Icon_Sun" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:none;">
                        <circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
                    </svg>
                </button>
                <button class="DG_Btn DG_Btn_Ghost DG_Magnetic_Hover_1 DG_Hideable" id="DG_Settings_Btn" style="flex: none; width: 42px; justify-content: center; padding: 10px;" title="Settings">
                    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
                    </svg>
                </button>
                <button class="DG_Hide_Btn DG_Drag_Handle" id="DG_Hide_Btn" title="Drag to move · Click to show/hide">
                    <svg class="DG_Eye_Open" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
                        <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>
                    </svg>
                    <svg class="DG_Eye_Closed" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
                        <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/>
                    </svg>
                    <span class="DG_Title" id="DG_Hide_Label" style="font-size: 14px;">Hide</span>
                </button>
            </div>
            <div class="DG_Main_Box" id="DG_Main_Box">
                <!-- PAGE 1: Main -->
                <div class="DG_Page active" id="DG_Page_Main">
                    <div class="DG_HStack">
                        <div class="DG_Btn DG_Btn_Ghost DG_Magnetic_Hover_1" id="DG_Conn_Btn" style="flex: 1;">
                            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" id="DG_Conn_Ico">
                                <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none"/>
                            </svg>
                            <span class="DG_Title" id="DG_Conn_Txt" style="color: inherit;">Connecting</span>
                        </div>
                        <button class="DG_Btn DG_Btn_Ghost DG_Magnetic_Hover_1" id="DG_AccMgr_Btn" style="flex: none; width: 42px; justify-content: center; padding: 10px;" title="Account Manager">
                            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>
                            </svg>
                        </button>
                    </div>

                    <div class="DG_User_Row DG_HStack" id="DG_User_Row">
                        <div class="DG_Avatar" id="DG_Avatar">?</div>
                        <div style="flex:1;min-width:0;">
                            <p class="DG_Title" id="DG_UName" style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;"></p>
                            <div class="DG_HStack" style="gap:12px;">
                                <div class="DG_Stat"><img src="https://d35aaqx5ub95lt.cloudfront.net/images/profile/01ce3a817dd01842581c3d18debcbc46.svg"><span id="DG_UXP">0</span></div>
                                <div class="DG_Stat"><img src="https://d35aaqx5ub95lt.cloudfront.net/images/gems/45c14e05be9c1af1d7d0b54c6eed7eee.svg"><span id="DG_UGems">0</span></div>
                                <div class="DG_Stat"><img src="https://d35aaqx5ub95lt.cloudfront.net/images/icons/398e4298a3b39ce566050e5c041949ef.svg"><span id="DG_UStreak">0</span></div>
                            </div>
                        </div>
                    </div>

                    <div class="DG_Divider"></div>

                    <!-- XP Farm -->
                    <div class="DG_VStack">
                        <div class="DG_HStack_4">
                            <img src="https://d35aaqx5ub95lt.cloudfront.net/images/goals/2b5a211d830a24fab92e291d50f65d1d.svg" width="18" height="18" style="flex-shrink: 0;">
                            <p class="DG_Title">XP to farm</p>
                        </div>
                        <div class="DG_HStack">
                            <div class="DG_Input_Wrap">
                                <input type="number" class="DG_Input" id="DG_XP_Input" placeholder="0" min="30" max="500000">
                            </div>
                            <button class="DG_Input_Btn DG_Magnetic_Hover_1" id="DG_XP_Btn" disabled>
                                <span>GET XP</span>
                            </button>
                        </div>
                        <div class="DG_Prog_Wrap" id="DG_XP_Prog"><div class="DG_Prog_Fill" id="DG_XP_Fill"></div></div>
                    </div>

                    <!-- Gems Farm -->
                    <div class="DG_VStack">
                        <div class="DG_HStack_4">
                            <img src="https://d35aaqx5ub95lt.cloudfront.net/images/gems/45c14e05be9c1af1d7d0b54c6eed7eee.svg" width="18" height="18" style="flex-shrink: 0;">
                            <p class="DG_Title">Farm Gems</p>
                        </div>
                        <div class="DG_HStack">
                            <div class="DG_Input_Wrap" style="position: relative; overflow: hidden;">
                                <svg width="120" height="48" viewBox="0 0 120 48" fill="none" xmlns="http://www.w3.org/2000/svg" style="position: absolute; pointer-events: none; transform: translateX(-150px); animation: slideRight 4s ease-in-out forwards infinite; animation-delay: 2s;">
                                    <path opacity="0.5" d="M72 0H96L72 48H48L72 0Z" fill="rgb(var(--DG-accent))"/>
                                    <path opacity="0.5" d="M24 0H60L36 48H0L24 0Z" fill="rgb(var(--DG-accent))"/>
                                    <path opacity="0.5" d="M108 0H120L96 48H84L108 0Z" fill="rgb(var(--DG-accent))"/>
                                </svg>
                                <input type="number" class="DG_Input" id="DG_Gem_Input" placeholder="0" readonly>
                            </div>
                            <button class="DG_Input_Btn DG_Magnetic_Hover_1" id="DG_Gem_Btn" disabled>
                                <span>RUN</span>
                            </button>
                        </div>
                    </div>

                    <!-- Streak Farm -->
                    <div class="DG_VStack">
                        <div class="DG_HStack_4">
                            <img src="https://d35aaqx5ub95lt.cloudfront.net/images/icons/398e4298a3b39ce566050e5c041949ef.svg" width="18" height="18" style="flex-shrink: 0;">
                            <p class="DG_Title">Streak days to add</p>
                        </div>
                        <div class="DG_HStack">
                            <div class="DG_Input_Wrap">
                                <input type="number" class="DG_Input" id="DG_Streak_Input" placeholder="0" min="1" max="3650">
                            </div>
                            <button class="DG_Input_Btn DG_Magnetic_Hover_1" id="DG_Streak_Btn" disabled>
                                <span>RUN</span>
                            </button>
                        </div>
                        <div class="DG_Prog_Wrap" id="DG_Streak_Prog"><div class="DG_Prog_Fill" id="DG_Streak_Fill"></div></div>
                    </div>

                    <div class="DG_Divider"></div>

                    <!-- Extra Features -->
                    <div class="DG_HStack_Between">
                        <button class="DG_Btn DG_Btn_Ghost DG_Magnetic_Hover_1" id="DG_Practice_Btn" style="flex:1;justify-content:center;" disabled>
                            <img src="https://d35aaqx5ub95lt.cloudfront.net/images/goals/2b5a211d830a24fab92e291d50f65d1d.svg" width="15" height="15">
                            Practice Farm
                        </button>
                        <button class="DG_Btn DG_Btn_Ghost DG_Magnetic_Hover_1" id="DG_Super_Btn" style="flex:1;justify-content:center;" disabled>
                            <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/43ae4670b321ea3e5807b2a983864d18.svg" width="15" height="15">
                            Get Duo Max
                        </button>
                    </div>

                    <div class="DG_HStack_Between">
                        <button class="DG_Btn DG_Btn_Ghost DG_Magnetic_Hover_1" id="DG_Shop_Btn" style="flex:1;justify-content:center;" disabled>
                            <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/0e58a94dda219766d98c7796b910beee.svg" width="15" height="15">
                            Shop Items
                        </button>
                        <button class="DG_Btn DG_Btn_Ghost DG_Magnetic_Hover_1" id="DG_League_Btn" style="flex:1;justify-content:center;" disabled>
                            <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/ca9178510134b4b0893dbac30b6670aa.svg" width="15" height="15">
                            Auto League #1
                        </button>
                    </div>

                    <div class="DG_HStack_Between">
                        <button class="DG_Btn DG_Btn_Ghost DG_Magnetic_Hover_1" id="DG_Quest_Btn" style="flex:1;justify-content:center;" disabled>
                            <img src="https://d35aaqx5ub95lt.cloudfront.net/vendor/7ef36bae3f9d68fc763d3451b5167836.svg" width="15" height="15">
                            Daily Quests
                        </button>
                        <button class="DG_Btn DG_Btn_Ghost DG_Magnetic_Hover_1" id="DG_MonthlyQuest_Btn" style="flex:1;justify-content:center;" disabled>
                            <img src="https://d35aaqx5ub95lt.cloudfront.net/images/streakSociety/6f7448890a01e473d141f94fea3fceb9.svg" width="15" height="15">
                            Monthly Quests
                        </button>
                    </div>

                    <div class="DG_HStack_Between">
                        <div class="DG_HStack_4">
                            <span class="DG_Subtitle">Auto Solver</span>
                            <label class="DG_Toggle">
                                <input type="checkbox" id="DG_Solver_Toggle">
                                <span class="DG_Toggle_Slider"></span>
                            </label>
                        </div>
                        <span class="DG_Subtitle">DuoGang v2.1.23</span>
                    </div>
                </div>

                <!-- PAGE 2: Settings -->
                <div class="DG_Page" id="DG_Page_Settings">
                    <div class="DG_HStack_4 DG_Magnetic_Hover_1" id="DG_Settings_Back_Btn" style="align-self:flex-start;cursor:pointer;opacity:0.55;">
                        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--DG-text)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                            <polyline points="15 18 9 12 15 6"/>
                        </svg>
                        <p class="DG_Title">Back</p>
                    </div>
                    <p class="DG_Title_Large" style="align-self:stretch;">Settings</p>
                    <div class="DG_Divider"></div>
                    <div class="DG_Scroll_Inner" style="max-height: 350px; width: 100%; gap: 8px;">
                        <div class="DG_Settings_Toggle_Row" id="DG_Settings_Show_Solve_Buttons">
                            <div class="DG_Settings_Toggle_Info">
                                <p class="DG_Title">Show Solve Buttons</p>
                                <p class="DG_Subtitle">In lessons and practices, see the solve and solve all buttons.</p>
                            </div>
                            <label class="DG_Toggle">
                                <input type="checkbox" id="DG_Settings_Solve_Toggle">
                                <span class="DG_Toggle_Slider"></span>
                            </label>
                        </div>
                        <div class="DG_Settings_Toggle_Row" id="DG_Settings_Mute_Lessons">
                            <div class="DG_Settings_Toggle_Info">
                                <p class="DG_Title">Mute Lessons</p>
                                <p class="DG_Subtitle">Automatically mute lesson audio when auto-solving.</p>
                            </div>
                            <label class="DG_Toggle">
                                <input type="checkbox" id="DG_Settings_Mute_Toggle">
                                <span class="DG_Toggle_Slider"></span>
                            </label>
                        </div>
                        <div class="DG_Settings_Toggle_Row" id="DG_Settings_Free_Super">
                            <div class="DG_Settings_Toggle_Info">
                                <p class="DG_Title">Free Duo Max</p>
                                <p class="DG_Subtitle">Enable unlimited hearts and legendary access on-client. Reload required.</p>
                            </div>
                            <label class="DG_Toggle">
                                <input type="checkbox" id="DG_Settings_Super_Toggle">
                                <span class="DG_Toggle_Slider"></span>
                            </label>
                        </div>
                        <div class="DG_Settings_Toggle_Row" id="DG_Settings_Reduce_Effects">
                            <div class="DG_Settings_Toggle_Info">
                                <p class="DG_Title">Reduce Visual Effects</p>
                                <p class="DG_Subtitle">Disable confetti and other visual animations.</p>
                            </div>
                            <label class="DG_Toggle">
                                <input type="checkbox" id="DG_Settings_Effects_Toggle">
                                <span class="DG_Toggle_Slider"></span>
                            </label>
                        </div>
                    </div>
                    <button class="DG_Btn DG_Btn_Primary DG_Magnetic_Hover_1" id="DG_Settings_Save_Btn" style="width:100%; height:44px; justify-content:center;">
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                            <path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/>
                        </svg>
                        SAVE & APPLY
                    </button>
                </div>

               
                <div class="DG_Page" id="DG_Page_Shop">
                    <div class="DG_HStack_4 DG_Magnetic_Hover_1" id="DG_Shop_Back_Btn" style="align-self:flex-start;cursor:pointer;opacity:0.55;">
                        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--DG-text)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                            <polyline points="15 18 9 12 15 6"/>
                        </svg>
                        <p class="DG_Title">Back</p>
                    </div>
                    <p class="DG_Title_Large" style="align-self:stretch;">Shop Items</p>
                    <div class="DG_Scroll_Inner" id="DG_Shop_Container" style="max-height:300px;">
                        <p class="DG_Subtitle" style="text-align:center;padding:8px 0;">Loading shop...</p>
                    </div>
                </div>

               
                <div class="DG_Page" id="DG_Page_Accounts">
                    <div class="DG_HStack_4 DG_Magnetic_Hover_1" id="DG_AccMgr_Back_Btn" style="align-self:flex-start;cursor:pointer;opacity:0.55;">
                        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--DG-text)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                            <polyline points="15 18 9 12 15 6"/>
                        </svg>
                        <p class="DG_Title">Back</p>
                    </div>
                    <div class="DG_HStack_Between">
                        <p class="DG_Title_Large">Account Manager</p>
                        <button class="DG_Btn DG_Btn_Primary DG_Magnetic_Hover_1" id="DG_AccSave_Btn" disabled style="height:30px;padding:0 12px; font-size: 12px;">
                            SAVE CURRENT
                        </button>
                    </div>
                    <div class="DG_Divider"></div>
                    <div id="DG_AccList_Wrap" class="DG_Scroll_Inner" style="max-height:260px;width:100%;gap:6px;">
                        <p class="DG_Subtitle" style="text-align:center;padding:8px 0;">No saved accounts.</p>
                    </div>
                </div>

              
                <div class="DG_Page" id="DG_Page_MonthlyQuests">
                    <div class="DG_HStack_4 DG_Magnetic_Hover_1" id="DG_MQ_Back_Btn" style="align-self:flex-start;cursor:pointer;opacity:0.55;">
                        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--DG-text)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                            <polyline points="15 18 9 12 15 6"/>
                        </svg>
                        <p class="DG_Title">Back</p>
                    </div>
                    <div class="DG_HStack_Between">
                        <p class="DG_Title_Large">Monthly Quests</p>
                        <button class="DG_Btn DG_Btn_Primary DG_Magnetic_Hover_1" id="DG_MQ_ClaimAll_Btn" disabled style="height:30px;padding:0 12px; font-size: 12px;">
                            CLAIM ALL
                        </button>
                    </div>
                    <div class="DG_Divider"></div>
                    <div id="DG_MQ_Container" class="DG_Scroll_Inner" style="max-height:300px;width:100%;">
                        <p class="DG_Subtitle" style="text-align:center;padding:8px 0;">Loading quests...</p>
                    </div>
                </div>
            </div>
        </div>
    `;
    document.body.appendChild(wrap);

  
    let jwt = null, sub = null, headers = null, user = null;
    let running = false, task = null, hidden = false;
    let isOutdated = false;
    let delay = parseInt(localStorage.getItem('dg_delay') || '500', 10);
    let earnedGems = 0;
    let currentPage = 'main';
    let solverUI = null;
    let isAutoMode = false;
    let solverEnabled = localStorage.getItem('dg_solver') === 'true';
    let solveLoopRunning = false;
    let lessonSolving = false;
    let lessonsToSolve = 0;
    let currentLessonCount = 0;

    // PRO-inspired: track current React element class and traversal depth
    const DEFAULT_REACT_CLASS = '_3yE3H';
    const STORY_REACT_CLASS   = '_3TJzR';
    let reactClass   = DEFAULT_REACT_CLASS;
    let reactTraverse = 1;

    // Settings state
    let showSolveButtons = localStorage.getItem('dg_showSolveButtons') !== 'false';
    let muteLessons = localStorage.getItem('dg_muteLessons') === 'true';
    let reduceEffects = localStorage.getItem('dg_reduceEffects') === 'true';
    let freeSuper = localStorage.getItem('dg_super') === 'true';

    const sleep = ms => new Promise(r => setTimeout(r, ms));
    const GOALS_API = 'https://goals-api.duolingo.com';

  
    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 buildHeaders(j) {
        return { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + j, 'User-Agent': navigator.userAgent };
    }

    function gm(method, url, data, hdrs) {
        return new Promise((res, rej) => GM_xmlhttpRequest({
            method, url, headers: hdrs || headers,
            data: data ? JSON.stringify(data) : null,
            onload: r => res(r), onerror: () => rej(new Error('Network')),
            timeout: 15000, ontimeout: () => rej(new Error('Timeout'))
        }));
    }

    function goalHdrs(jwt) {
        return {'Content-Type':'application/json','x-requested-with':'XMLHttpRequest','accept':'application/json; charset=UTF-8','Authorization':'Bearer '+jwt};
    }

    function notif(msg, dur = 4) {
        const notifMain = document.getElementById('DG_Notif');
        const notifBox = document.getElementById('DG_Notif_Box');
        const icon = notifBox.querySelector('.DG_Inset_Icon_1_ID');
        const title = notifBox.querySelector('.DG_Inset_Text_1_ID');
        const body = notifBox.querySelector('.DG_Inset_Text_2_ID');

        icon.innerHTML = '';
        icon.style.color = 'rgb(var(--DG-accent-dark))';
        title.textContent = msg;
        body.textContent = '';

        notifBox.classList.add('show');
        clearTimeout(window._dgNotifTimer);
        window._dgNotifTimer = setTimeout(() => notifBox.classList.remove('show'), dur * 1000);

        notifBox.querySelector('.DG_Inset_Icon_2_ID').onclick = () => {
            notifBox.classList.remove('show');
            clearTimeout(window._dgNotifTimer);
        };
    }

    function setConn(state, label) {
        const btn = document.getElementById('DG_Conn_Btn');
        const txt = document.getElementById('DG_Conn_Txt');
        const ico = document.getElementById('DG_Conn_Ico');
        txt.textContent = label || state;
        if (state === 'Connected') {
            ico.innerHTML = '<circle cx="12" cy="12" r="10" fill="rgb(var(--DG-green))"/><path d="M7 12l3 3 7-7" stroke="#fff" stroke-width="2" stroke-linecap="round"/>';
            btn.style.background = 'rgba(var(--DG-green), 0.12)';
            btn.style.outline = '2px solid rgba(var(--DG-green), 0.22)';
            txt.style.color = 'rgb(var(--DG-green))';
            ico.style.color = 'rgb(var(--DG-green))';
            document.getElementById('DG_User_Row').style.display = 'flex';
        } else if (state === 'Outdated') {
            btn.style.outline = '2px solid rgba(255,140,0,0.50)';
            btn.style.color = 'rgb(200, 90, 0)';
            txt.style.color = 'rgb(220, 100, 0)';
            txt.style.fontWeight = '700';
            ico.style.color = 'rgb(220, 100, 0)';
            ico.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none"><circle cx="12" cy="12" r="10" fill="rgba(255,140,0,0.20)" stroke="rgb(220,100,0)" stroke-width="2"/><path d="M12 7v5" stroke="rgb(220,100,0)" stroke-width="2.5" stroke-linecap="round"/><circle cx="12" cy="16.5" r="1.2" fill="rgb(220,100,0)"/></svg>';
            btn.classList.add('DG_Outdated_Btn');
            btn.style.cursor = 'pointer';
            btn.title = 'Click to update DuoGang';
            btn.onclick = () => window.open('https://openuserjs.org/scripts/duogang/DuoGang', '_blank');
            document.querySelectorAll('.DG_Input_Btn, .DG_Btn:not(#DG_Conn_Btn), .DG_Acc_Btn, .DG_Shop_Btn').forEach(el => {
                el.disabled = true;
                el.style.pointerEvents = 'none';
                el.style.opacity = '0.35';
            });
            document.querySelectorAll('.DG_Input, .DG_Toggle input').forEach(el => {
                el.disabled = true;
                el.style.pointerEvents = 'none';
            });
        } else if (state === 'Error - retrying' || state === 'Not logged in' || state === 'Invalid token') {
            btn.style.background = 'rgba(var(--DG-red), 0.12)';
            btn.style.outline = '2px solid rgba(var(--DG-red), 0.22)';
            txt.style.color = 'rgb(var(--DG-red))';
            ico.style.color = 'rgb(var(--DG-red))';
            ico.innerHTML = '<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none"/>';
        } else {
            btn.style.background = 'linear-gradient(0deg, rgba(var(--DG-accent), 0.12) 0%, rgba(var(--DG-accent), 0.12) 100%), rgba(var(--color-snow, 255, 255, 255), 0.80)';
            btn.style.outline = '2px solid rgba(var(--DG-accent), 0.22)';
            txt.style.color = 'rgb(var(--DG-accent-dark))';
            ico.style.color = 'rgb(var(--DG-accent-dark))';
            ico.innerHTML = '<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" fill="none"/>';
        }
    }

    function setBtnState(btnId, cls, label) {
        const btn = document.getElementById(btnId);
        if (!btn) return;
        btn.className = cls;
        const span = btn.querySelector('span');
        if (span) span.textContent = label;
    }

    function resetBtn(btnId, label, btnClass = 'DG_Input_Btn') {
        const btn = document.getElementById(btnId);
        if (!btn) return;
        btn.disabled = !user;
        setBtnState(btnId, btnClass, label);
        const prog = document.getElementById(btnId.replace('_Btn', '_Prog'));
        if (prog) setTimeout(() => prog.classList.remove('on'), 2000);
    }

    function setBtnProgress(btnId, pct) {
        const fill = document.getElementById(btnId.replace('_Btn', '_Fill'));
        if (fill) fill.style.width = pct + '%';
        const btn = document.getElementById(btnId);
        if (btn) {
            const span = btn.querySelector('span');
            if (span) span.textContent = pct + '%';
        }
    }

    function setBtnRunning(btnId) {
        const btn = document.getElementById(btnId);
        if (!btn) return;
        btn.disabled = false;
        setBtnState(btnId, 'DG_Input_Btn Running', 'STOP');
        const prog = document.getElementById(btnId.replace('_Btn', '_Prog'));
        if (prog) prog.classList.add('on');
    }

    function setBtnDone(btnId, label = 'DONE') {
        setBtnState(btnId, 'DG_Input_Btn Done', label);
        const fill = document.getElementById(btnId.replace('_Btn', '_Fill'));
        if (fill) fill.style.width = '100%';
    }

    function switchPage(pageId) {
        document.querySelectorAll('.DG_Page').forEach(p => p.classList.remove('active'));
        const page = document.getElementById('DG_Page_' + pageId);
        if (page) page.classList.add('active');
        currentPage = pageId;
    }

  
    function initSettingsPage() {
        document.getElementById('DG_Settings_Solve_Toggle').checked = showSolveButtons;
        document.getElementById('DG_Settings_Mute_Toggle').checked = muteLessons;
        document.getElementById('DG_Settings_Effects_Toggle').checked = reduceEffects;
        document.getElementById('DG_Settings_Super_Toggle').checked = freeSuper;

        document.getElementById('DG_Settings_Save_Btn').addEventListener('click', () => {
            showSolveButtons = document.getElementById('DG_Settings_Solve_Toggle').checked;
            muteLessons = document.getElementById('DG_Settings_Mute_Toggle').checked;
            reduceEffects = document.getElementById('DG_Settings_Effects_Toggle').checked;
            freeSuper = document.getElementById('DG_Settings_Super_Toggle').checked;

            localStorage.setItem('dg_showSolveButtons', showSolveButtons ? 'true' : 'false');
            localStorage.setItem('dg_muteLessons', muteLessons ? 'true' : 'false');
            localStorage.setItem('dg_reduceEffects', reduceEffects ? 'true' : 'false');

            if (freeSuper) {
                localStorage.setItem('dg_super', 'true');
            } else {
                localStorage.setItem('dg_super', 'false');
            }

            notif('Settings saved! Some changes may require a page reload.');
            setTimeout(() => switchPage('Main'), 800);
        });
    }
    initSettingsPage();

   

    function checkForUpdate() {
        setTimeout(() => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: 'https://raw.githubusercontent.com/JORKLAN/autoupdate_duogang/main/version.json?_=' + Date.now(),
                onload: function(res) {
                    try {
                        console.log('[DuoGang] Update check response:', res.status);
                        const data = JSON.parse(res.responseText);
                        const latest = data.version;
                        if (!latest) { console.log('[DuoGang] No version found in JSON'); return; }
                        const current = GM_info.script.version;
                        console.log('[DuoGang] Latest:', latest, '| Current:', current);
                        const toNum = v => v.split('.').map(Number).reduce((a, b, i) => a + b * Math.pow(1000, 2 - i), 0);
                        if (toNum(latest) > toNum(current)) {
                            console.log('[DuoGang] Update available!');
                            isOutdated = true;
                            setConn('Outdated', 'Outdated');
                        } else {
                            console.log('[DuoGang] Up to date.');
                        }
                    } catch (e) { console.log('[DuoGang] Update check error:', e); }
                },
                onerror: function(e) { console.log('[DuoGang] Update check request failed:', e); }
            });
        }, 500);
    }

    async function connect() {
        setConn('Connecting');
        jwt = getJwt();
        if (!jwt) { setConn('Not logged in'); return; }
        const dec = decodeJwt(jwt);
        if (!dec) { setConn('Invalid token'); return; }
        sub = dec.sub;
        headers = buildHeaders(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);
            if (!isOutdated) setConn('Connected');
            renderUser(user);
            ['DG_XP_Btn', 'DG_Gem_Btn', 'DG_Streak_Btn', 'DG_Practice_Btn', 'DG_Super_Btn', 'DG_Shop_Btn', 'DG_League_Btn', 'DG_Quest_Btn', 'DG_MonthlyQuest_Btn', 'DG_AccSave_Btn', 'DG_MQ_ClaimAll_Btn'].forEach(id => {
                const b = document.getElementById(id);
                if (b) b.disabled = false;
            });
        } catch (e) {
            setConn('Error - retrying');
            setTimeout(connect, 8000);
        }
    }

    function renderUser(u) {
        if (!u) return;
        document.getElementById('DG_UName').textContent = u.username || '';
        document.getElementById('DG_UXP').textContent = (u.totalXp || 0).toLocaleString();
        document.getElementById('DG_UGems').textContent = (u.gems || 0).toLocaleString();
        document.getElementById('DG_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('DG_Avatar');
            const img = document.createElement('img');
            img.src = hq;
            img.style.cssText = 'width:100%;height:100%;object-fit:cover;border-radius:50%;';
            img.onerror = function() { av.innerHTML = '?'; };
            av.innerHTML = '';
            av.appendChild(img);
        }
    }

   
    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; }
    }

    async function farmXP(txp) {
        const MAX = 499;
        let loops = Math.floor(txp / MAX), rem = txp % MAX;
        if (rem > 0 && rem < 30 && loops > 0) { loops--; rem += MAX; }
        const total = loops + (rem >= 30 ? 1 : 0);
        let cur = 0, earned = 0;
        setBtnRunning('DG_XP_Btn');
        for (let i = 0; i < loops; i++) {
            if (!running) break;
            const ok = await storyXP(469);
            if (ok) { earned += MAX; cur++; }
            setBtnProgress('DG_XP_Btn', Math.floor((cur / total) * 100));
            await sleep(delay);
        }
        if (rem >= 30 && running) {
            const ok = await storyXP(Math.min(rem - 30, 469));
            if (ok) { earned += rem; cur++; }
            setBtnProgress('DG_XP_Btn', 100);
        }
        if (running) {
            setBtnDone('DG_XP_Btn', 'DONE');
            notif('Farmed ' + earned.toLocaleString() + ' XP!');
            setTimeout(connect, 1500);
            setTimeout(() => resetBtn('DG_XP_Btn', 'GET XP'), 3000);
        }
    }

   
    async function getGemRewards() {
        try {
            const r = await gm('GET', `https://www.duolingo.com/2023-05-23/users/${sub}?fields=rewardBundles`);
            if (r.status !== 200) return [];
            const bundles = JSON.parse(r.responseText).rewardBundles || [];
            const gems = [];
            for (const bundle of bundles) {
                for (const reward of bundle.rewards || []) {
                    if (!reward.consumed && (reward.id.includes('GEMS') || reward.currency === 'GEMS')) {
                        gems.push({ id: reward.id, amount: reward.amount || 0 });
                    }
                }
            }
            return gems;
        } catch { return []; }
    }

    async function exploitGemReward(rewardId) {
        const body = {
            consumed: true,
            fromLanguage: user.fromLanguage,
            learningLanguage: user.learningLanguage,
            pathLevelSpecifics: {
                anchorSkillId: 'f22fd38157eea63965dc39eeac3c40c1',
                indexSinceAnchorSkill: 0,
                treeId: '14b1a2672c1bb3b250ebaa31b86c343e',
                nodeState: 'active'
            }
        };
        try {
            const r = await gm('PATCH', `https://www.duolingo.com/2023-05-23/users/${sub}/rewards/${rewardId}`, body);
            return r.status === 200;
        } catch { return false; }
    }

    async function getGemCount() {
        try {
            const r = await gm('GET', `https://www.duolingo.com/2023-05-23/users/${sub}?fields=gemsConfig`);
            if (r.status !== 200) return null;
            return JSON.parse(r.responseText).gemsConfig?.gems ?? null;
        } catch { return null; }
    }

    async function farmGems() {
        earnedGems = 0;
        const gemInput = document.getElementById('DG_Gem_Input');
        if (gemInput) gemInput.value = '';
        setBtnRunning('DG_Gem_Btn');

        const THREADS = 3;
        outer: while (running && task === 'gems') {
            const rewards = await getGemRewards();
            if (rewards.length === 0) { await sleep(delay * 2); continue; }

            let gemsBefore = await getGemCount() ?? (user?.gems ?? 0);

            for (let i = 0; i < rewards.length; i += THREADS) {
                if (!running || task !== 'gems') break outer;
                const batch = rewards.slice(i, i + THREADS);
                await Promise.all(batch.map(r => exploitGemReward(r.id)));
                await sleep(200);

                const now = await getGemCount();
                if (now !== null) {
                    const gained = Math.max(0, now - gemsBefore);
                    earnedGems += gained;
                    gemsBefore = now;
                    if (gemInput) gemInput.value = String(earnedGems);
                    if (user) { user.gems = now; renderUser(user); }
                }
                await sleep(Math.max(100, delay));
            }
            await sleep(delay);
        }

        resetBtn('DG_Gem_Btn', 'RUN');
        if (earnedGems > 0) {
            notif('+' + earnedGems.toLocaleString() + ' gems gained!');
            setTimeout(connect, 1500);
        }
    }

   
    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('DG_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: headers, 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('DG_Streak_Btn', Math.floor(((i + 1) / days) * 100));
            await sleep(delay);
        }
        if (running) {
            setBtnDone('DG_Streak_Btn', 'DONE');
            notif('Restored ' + days + ' streak days!');
            setTimeout(connect, 1500);
            setTimeout(() => resetBtn('DG_Streak_Btn', 'RUN'), 3000);
        }
    }

   
    async function run(type, val) {
        if (running) { running = false; notif('Farm stopped.'); return; }
        if (!user) { notif('Please wait for connection.'); return; }
        running = true; task = type;
        try {
            if (type === 'xp') await farmXP(val);
            if (type === 'gems') await farmGems();
            if (type === 'streak') await farmStreak(val);
            if (type === 'league') await farmLeague();
        } catch (e) { notif('Error: ' + e.message); }
        if (!running) {
            if (type === 'xp') resetBtn('DG_XP_Btn', 'GET XP');
            if (type === 'streak') resetBtn('DG_Streak_Btn', 'RUN');
        }
        running = false; task = null;
    }

   
    async function farmLeague() {
        const LB = 'https://duolingo-leaderboards-prod.duolingo.com/leaderboards/7d9f5dd1-8423-491a-91f2-2532052038ce';
        let prog = document.getElementById('DG_League_Prog');
        let fill = document.getElementById('DG_League_Fill');
        if (!prog) {
            const leagueSection = document.getElementById('DG_League_Btn').parentElement;
            prog = document.createElement('div');
            prog.className = 'DG_Prog_Wrap on';
            prog.id = 'DG_League_Prog';
            fill = document.createElement('div');
            fill.className = 'DG_Prog_Fill';
            fill.id = 'DG_League_Fill';
            prog.appendChild(fill);
            leagueSection.appendChild(prog);
        }
        if (prog) prog.classList.add('on');
        if (fill) fill.style.width = '0%';
        setBtnRunning('DG_League_Btn');
        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('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); }
        }
        resetBtn('DG_League_Btn', 'RUN');
    }

    
    async function getGoalsAndProgress() {
        const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
        const [schemaR, progR] = await Promise.all([
            gm('GET', `${GOALS_API}/schema?ui_language=en&_=${Date.now()}`, null, goalHdrs(jwt)),
            gm('GET', `${GOALS_API}/users/${sub}/progress?timezone=${tz}&ui_language=en`, null, goalHdrs(jwt))
        ]);
        if (schemaR.status !== 200 || progR.status !== 200) return null;
        return {
            schema: JSON.parse(schemaR.responseText),
            progress: JSON.parse(progR.responseText)
        };
    }

    async function farmDailyQuest() {
        setBtnState('DG_Quest_Btn', 'DG_Input_Btn', 'Loading...');
        const data = await getGoalsAndProgress();
        if (!data) { notif('Could not load quest data.'); resetBtn('DG_Quest_Btn', 'RUN'); return; }
        const earned = new Set(data.progress.badges?.earned || []);
        const daily = (data.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 daily quests completed!');
            setBtnDone('DG_Quest_Btn', 'DONE');
            setTimeout(() => resetBtn('DG_Quest_Btn', 'RUN'), 3000);
            return;
        }
        setBtnState('DG_Quest_Btn', 'DG_Input_Btn Running', 'Running...');
        const updates = [...metrics].map(m => ({ metric: m, quantity: 2000 }));
        updates.push({ metric: 'QUESTS', quantity: 1 });
        const okR = await gm('POST', `${GOALS_API}/users/${sub}/progress/batch`, {
            metric_updates: updates,
            timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
            timestamp: new Date().toISOString()
        }, goalHdrs(jwt));
        if (okR.status === 200) {
            notif('Daily quests completed!');
            setBtnDone('DG_Quest_Btn', 'DONE');
            setTimeout(() => resetBtn('DG_Quest_Btn', 'RUN'), 3000);
        } else {
            notif('Quest completion failed.');
            resetBtn('DG_Quest_Btn', 'RUN');
        }
    }

    
    let questState = null;

    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 loadMonthlyQuests() {
        const cont = document.getElementById('DG_MQ_Container');
        if (!cont) return;
        cont.innerHTML = '<p class="DG_Subtitle" style="text-align:center;padding:8px 0;">Loading...</p>';
        const gh = goalHdrs(jwt);
        const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
        try {
            const [schemaR, progR] = await Promise.all([
                gm('GET', `${GOALS_API}/schema?ui_language=en&_=${Date.now()}`, null, gh),
                gm('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);
        } catch (e) {
            cont.innerHTML = '<p class="DG_Subtitle" style="text-align:center;color:rgb(var(--DG-red));padding:8px 0;">Failed to load quests.</p>';
        }
    }

    function renderMonthlyQuests(schema, progress, earned, gh) {
        const cont = document.getElementById('DG_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 monthly = (schema.goals || []).filter(g => {
            if (!g.category || !g.category.includes('MONTHLY')) return false;
            const m2 = g.goalId.match(/^(\d{4}_\d{2})_monthly/);
            return m2 && mReg.test(g.goalId);
        });

        if (monthly.length === 0) {
            cont.innerHTML = '<p class="DG_Subtitle" 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);

            const item = document.createElement('div');
            item.className = 'DG_Shop_Card';
            item.style.cssText = 'align-items:flex-start;text-align:left;';
            item.innerHTML = `
                <p class="DG_Title" style="font-size:14px;">${g.title?.uiString || g.goalId}</p>
                <p class="DG_Subtitle">${isEarned ? 'COMPLETED' : cur + ' / ' + tgt + ' · ' + g.metric}</p>
                <div style="width:100%;height:4px;border-radius:2px;background:rgba(var(--DG-accent),0.10);overflow:hidden;">
                    <div style="height:100%;background:rgb(var(--DG-accent));border-radius:2px;width:${pct}%;${isEarned ? 'background:rgb(var(--DG-green));' : ''}"></div>
                </div>
                ${!isEarned && remaining > 0 ? `<button class="DG_Shop_Btn" data-metric="${g.metric}" data-amount="${remaining}" data-id="${g.goalId}">GET +${remaining}</button>` : ''}
                ${isEarned ? '<button class="DG_Shop_Btn got">DONE</button>' : ''}
            `;
            const btn = item.querySelector('.DG_Shop_Btn:not(.got)');
            if (btn) btn.addEventListener('click', async () => {
                btn.textContent = '...';
                btn.disabled = true;
                try {
                    const payload = {
                        metric_updates: [{ metric: btn.dataset.metric, quantity: parseInt(btn.dataset.amount) }],
                        timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
                        timestamp: getQuestTimestamp(btn.dataset.id)
                    };
                    const r = await gm('POST', `${GOALS_API}/users/${sub}/progress/batch`, payload, gh);
                    if (r.status === 200) {
                        btn.textContent = 'OK';
                        btn.classList.add('got');
                        notif('Quest progress injected!');
                        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('Open Monthly Quests first.'); return; }
        const gh = goalHdrs(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 gm('POST', `${GOALS_API}/users/${sub}/progress/batch`, payload, gh);
                notif('All monthly quests claimed!');
                setTimeout(() => loadMonthlyQuests(), 900);
            } catch { notif('Failed to claim quests.'); }
        }
    }

   
    async function getShopItems() {
        return new Promise(r => GM_xmlhttpRequest({
            method: 'GET', url: 'https://www.duolingo.com/2023-05-23/shop-items',
            headers: headers,
            onload: res => {
                try { r(res.status === 200 ? JSON.parse(res.responseText).shopItems || [] : []); }
                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: headers, data: JSON.stringify(payload),
            onload: res => r(res.status === 200), onerror: () => r(false)
        }));
    }

    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' };
        return { cat: 'Misc', icon: 'https://d35aaqx5ub95lt.cloudfront.net/images/leagues/9fadb349c2ece257386a0e576359c867.svg' };
    }

    function formatItemName(id) {
        return id.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
    }

    async function loadShop() {
        const container = document.getElementById('DG_Shop_Container');
        container.innerHTML = '<p class="DG_Subtitle" style="text-align:center;padding:8px 0;">Loading shop...</p>';
        const items = await getShopItems();
        container.innerHTML = '';
        const valid = items.filter(i => i.currencyType === 'XGM' && !i.id.includes('gift'));
        if (!valid.length) {
            container.innerHTML = '<p class="DG_Subtitle" style="text-align:center;padding:8px 0;">No items available.</p>';
            return;
        }
        const ORDER = ['Streak Freezes', 'XP Boosts', 'Hearts', 'Gems', 'Outfits', 'Misc'];
        const grouped = {};
        valid.forEach(i => {
            const { cat, icon } = categorizeItem(i);
            if (!grouped[cat]) grouped[cat] = [];
            let name = i.name || formatItemName(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 grid = document.createElement('div');
            grid.className = 'DG_Shop_Grid';
            grid.innerHTML = `<p class="DG_Title" style="grid-column:1/-1;text-align:center;color:rgb(var(--DG-accent-dark));font-size:12px;text-transform:uppercase;letter-spacing:0.5px;">${cat}</p>`;
            grouped[cat].forEach(item => {
                const card = document.createElement('div');
                card.className = 'DG_Shop_Card';
                card.innerHTML = `
                    <img src="${item.icon}" class="DG_Shop_Ico" onerror="this.style.display='none'">
                    <div class="DG_Shop_Name">${item.displayName}</div>
                    <button class="DG_Shop_Btn" data-id="${item.id}">GET</button>
                `;
                const btn = card.querySelector('.DG_Shop_Btn');
                btn.onclick = async () => {
                    btn.textContent = '...';
                    btn.disabled = true;
                    const ok = await buyShopItem(item.id);
                    if (ok) {
                        btn.textContent = 'GOT';
                        btn.classList.add('got');
                        notif('Got ' + item.displayName + '!');
                    } else {
                        btn.textContent = 'FAIL';
                        btn.classList.add('fail');
                        setTimeout(() => { btn.textContent = 'GET'; btn.classList.remove('fail'); btn.disabled = false; }, 2000);
                    }
                };
                grid.appendChild(card);
            });
            container.appendChild(grid);
        });
    }

   
    function accGetAll() { try { return JSON.parse(localStorage.getItem('dg_accounts') || '[]'); } catch { return []; } }
    function accSetAll(arr) { localStorage.setItem('dg_accounts', JSON.stringify(arr)); }

    function accSaveCurrent() {
        if (!user || !jwt || !sub) { notif('Please wait for connection.'); return; }
        const all = accGetAll();
        if (all.find(a => a.id == sub)) { notif('Already saved.'); 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!');
        renderAccounts();
    }

    function accRemove(id) {
        const all = accGetAll().filter(a => a.id != id);
        accSetAll(all);
        renderAccounts();
        notif('Account removed.');
    }

    function accLogin(id) {
        const acc = accGetAll().find(a => a.id == id);
        if (!acc) { notif('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('DG_AccList_Wrap');
        if (!wrap) return;
        const all = accGetAll();
        if (all.length === 0) {
            wrap.innerHTML = '<p class="DG_Subtitle" style="text-align:center;padding:8px 0;">No saved accounts.</p>';
            return;
        }
        wrap.innerHTML = '';
        all.forEach(acc => {
            const card = document.createElement('div');
            card.className = 'DG_Acc_Card';
            const isCurrent = 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="DG_Acc_Avatar">${picHtml}</div>
                <div class="DG_Acc_Info">
                    <p class="DG_Acc_Name">${acc.username}</p>
                    ${isCurrent ? '<p class="DG_Acc_Sub active"><svg width="8" height="8" viewBox="0 0 8 8"><circle cx="4" cy="4" r="4" fill="rgb(var(--DG-green))"/></svg>Active</p>' : `<p class="DG_Acc_Sub">ID: ${String(acc.id).slice(0,8)}...</p>`}
                </div>
                <div class="DG_HStack" style="gap:5px;flex-shrink:0;">
                    ${!isCurrent ? `<button class="DG_Acc_Btn login" data-id="${acc.id}">LOG IN</button>` : ''}
                    <button class="DG_Acc_Btn del" data-id="${acc.id}">
                        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                            <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
                        </svg>
                    </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);
        });
    }

    
    const solver = {

       
        syncContext: () => {
            const isStory = document.querySelector('.FmlUF') !== null
                || document.querySelector('[data-test="stories-player-continue"],[data-test="stories-player-done"],[data-test="story-start"]') !== null;
            if (isStory) {
                reactClass    = STORY_REACT_CLASS;
                reactTraverse = 0;
            } else {
                reactClass    = DEFAULT_REACT_CLASS;
                reactTraverse = 1;
            }
        },

       
        findReact: (dom, traverseUp) => {
            if (!dom) return null;
            const key = Object.keys(dom).find(k => k.startsWith('__reactFiber$') || k.startsWith('__reactInternalInstance$'));
            if (!key) return null;
            const domFiber = dom[key];
            if (!domFiber) return null;
            const GetCompFiber = fiber => {
                let pf = fiber.return;
                while (pf && typeof pf.type === 'string') pf = pf.return;
                return pf;
            };
            let cf = GetCompFiber(domFiber);
            for (let i = 0; i < traverseUp; i++) {
                if (!cf) break;
                cf = GetCompFiber(cf);
            }
            return cf?.stateNode ?? null;
        },

       
        getSolution: () => {
            solver.syncContext();

           
            let el = document.getElementsByClassName(reactClass)[0];

            // Fallback chain (handles new-word lessons, error reviews, etc.)
            if (!el) el = document.querySelector('._3yE3H');
            if (!el) el = document.querySelector('.RMEuZ._1GVfY');
            if (!el) el = document.querySelector('[data-test="challenge"]');
            if (!el) el = document.querySelector('[class*="challenge"]');

            if (!el) return null;

            const ri = solver.findReact(el, reactTraverse);
            let sol = ri?.props?.currentChallenge ?? null;

           
            if (!sol && reactTraverse !== 0) {
                const ri0 = solver.findReact(el, 0);
                sol = ri0?.props?.currentChallenge ?? null;
            }
           
            if (!sol) {
                const ri2 = solver.findReact(el, 2);
                sol = ri2?.props?.currentChallenge ?? null;
            }

            return sol;
        },

       
        determineType: () => {
            try {
                const t = window.sol?.type;

               
                if (document.querySelector('.FmlUF')) {
                    if (!t) return false;
                    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';
                   
                    return 'Story Slide';
                }

                
                if (document.querySelector('[data-test="session-complete-slide"]') ||
                    document.querySelector('[data-test="session-over"]'))            return 'Session Complete';
                if (document.querySelector('[data-test="daily-quest-progress-slide"]')) return 'Daily Quest Progress';
                if (document.querySelector('[data-test="streak-slide"]'))            return 'Streak Slide';
                if (document.querySelector('[data-test="leaderboard-slide"]'))       return 'Leaderboard Slide';

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

                if (!t) {
                   
                    if (document.querySelector('[data-test="player-next"]')) return 'Next Only';
                    return false;
                }

                if (t === 'listenMatch')                 return 'Listen Match';
                if (t === 'syllableTap')                 return 'Syllable Tap';
                if (t === 'syllableListenTap')           return 'Syllable Listen Tap';
                if (t === 'listenTap')                   return 'Listen Tap';
                if (t === 'listen')                      return 'Listen Type';
                if (t === 'translate')                   return 'Translate';
                if (t === 'completeReverseTranslation')  return 'Complete Reverse';
                if (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 === 'judge')                       return 'Judge';
                if (t === 'dialogue' || t === 'characterIntro' || t === 'selectTranscription') return 'Dialogue';
                if (t === 'definition' || t === 'radioBinary') return 'Select Card';
                if (t === 'characterMatch' || t === 'match') {
                    if (document.querySelector('[data-test$="challenge-tap-token"]')) return 'Pairs';
                }

                if (document.querySelector('[data-test*="challenge-partialReverseTranslate"]')) return 'Partial Reverse';
                if (document.querySelector('[data-test="challenge challenge-characterWrite"]')) {
                    if (document.querySelector('g._25Ktp'))  return 'Character Write Drag';
                    if (document.querySelector('path._1e5Zt')) return 'Character Write Draw';
                    return 'Character Write Freehand';
                }

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

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

                if (document.querySelector('[data-test="challenge-choice"]')) {
                    if (document.querySelector('[data-test="challenge-text-input"]')) return 'Challenge Choice with Text Input';
                    return 'Challenge Choice';
                }
                if (document.querySelector('[data-test$="challenge-tap-token"]')) {
                    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.querySelector('[data-test="challenge-tap-token-text"]')) return 'Fill in the Gap';
                if (document.querySelector('[data-test="challenge-text-input"]'))     return 'Challenge Text Input';
                if (document.querySelector('textarea[data-test="challenge-translate-input"]')) return 'Challenge Translate Input';

                return false;
            } catch { return false; }
        },

        setValue: (el, val) => {
            const proto = el.tagName === 'TEXTAREA' ? window.HTMLTextAreaElement : window.HTMLInputElement;
            const setter = Object.getOwnPropertyDescriptor(proto.prototype, 'value').set;
            setter.call(el, val);
            el.dispatchEvent(new Event('input', { bubbles: true }));
        },

        getCleanButtonText: (button) => {
            const rubyElements = button.querySelectorAll('ruby');
            if (rubyElements.length > 0) {
                let text = '';
                rubyElements.forEach(ruby => {
                    ruby.querySelectorAll('span[lang]:not(rt)').forEach(span => { text += span.textContent; });
                });
                return text.trim();
            }
            const textElement = button.querySelector('[data-test="challenge-tap-token-text"]');
            return textElement ? textElement.innerText.trim() : button.innerText.trim();
        },

        handle: async (type) => {
            const sl = ms => new Promise(r => setTimeout(r, ms));
            try {
                switch (type) {
                    case 'Challenge Speak':
                    case 'Listen Match':
                    case 'Listen Speak': {
                       
                        ['.vpDIE','._8AMBh._2vfJy._3Qy5R._28UWu._3h0lA._1S2uf._1E9sc',
                         '._1Qh5D._36g4N._2YF0P._28UWu._3h0lA._1S2uf._1E9sc'].forEach(sel => {
                            document.querySelector(sel)?.click();
                        });
                        await sl(200);
                        let skipBtn = document.querySelector('button[data-test="player-skip"]');
                        if (!skipBtn) { await sl(500); skipBtn = document.querySelector('button[data-test="player-skip"]'); }
                        skipBtn?.click();
                        await sl(150);
                        break;
                    }
                    case 'Select Card': {
                        const idx = window.sol?.correctIndex ?? 0;
                        const cards = document.querySelectorAll('[data-test="challenge-choice-card"]');
                        if (cards.length) 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 judges = document.querySelectorAll('[data-test="challenge-judge-text"]');
                        if (judges.length) judges[idx]?.click();
                        else document.querySelectorAll('[data-test="challenge-choice"]')[idx]?.click();
                        break;
                    }
                    case 'Translate': {
                        const { correctTokens, correctSolutions } = window.sol;
                        if (correctTokens?.length) {
                            const tokens = document.querySelectorAll('[data-test$="challenge-tap-token"]');
                            const used = [];
                            for (const word of correctTokens) {
                                for (let i = 0; i < tokens.length; i++) {
                                    if (used.includes(i) || tokens[i].disabled) continue;
                                    if (solver.getCleanButtonText(tokens[i]) === word.trim()) {
                                        tokens[i].click(); used.push(i); await sl(40); break;
                                    }
                                }
                            }
                        } else if (correctSolutions) {
                            const ta = document.querySelector('textarea[data-test="challenge-translate-input"]');
                            if (ta) solver.setValue(ta, correctSolutions[0]);
                        }
                        break;
                    }
                    case 'Listen Tap': {
                        const tokens = document.querySelectorAll('[data-test$="challenge-tap-token"]');
                        const used = [];
                        for (const word of (window.sol?.correctTokens || [])) {
                            for (let i = 0; i < tokens.length; i++) {
                                if (used.includes(i) || tokens[i].disabled) continue;
                                if (solver.getCleanButtonText(tokens[i]) === word.trim()) {
                                    tokens[i].click(); used.push(i); await sl(40); break;
                                }
                            }
                        }
                        break;
                    }
                    case 'Listen Type': {
                        const ans = 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) solver.setValue(ta, ans);
                        break;
                    }
                    case 'Complete Reverse': {
                        const blankTokens = window.sol?.displayTokens?.filter(t => t.isBlank);
                        const inputs = document.querySelectorAll('[data-test="challenge-text-input"]');
                        inputs.forEach((inp, i) => { if (blankTokens?.[i]) solver.setValue(inp, blankTokens[i].text); });
                        break;
                    }
                    case 'Challenge Choice':
                        document.querySelectorAll('[data-test="challenge-choice"]')[window.sol?.correctIndex ?? 0]?.click();
                        break;
                    case 'Challenge Choice with Text Input': {
                        const inp = document.querySelector('[data-test="challenge-text-input"]');
                        if (inp) {
                            const ans = window.sol?.correctSolutions
                                ? window.sol.correctSolutions[0].split(/(?<=^\S+)\s/)[1]
                                : (window.sol?.displayTokens?.find(t => t.isBlank)?.text || window.sol?.prompt);
                            solver.setValue(inp, ans);
                        }
                        break;
                    }
                    case 'Challenge Text Input': {
                        const inp = document.querySelector('[data-test="challenge-text-input"]');
                        if (inp) solver.setValue(inp, window.sol?.correctSolutions?.[0] || window.sol?.displayTokens?.find(t => t.isBlank)?.text || window.sol?.prompt);
                        break;
                    }
                    case 'Challenge Translate Input': {
                        const ta = document.querySelector('textarea[data-test="challenge-translate-input"]');
                        if (ta) solver.setValue(ta, window.sol?.correctSolutions?.[0] || window.sol?.prompt);
                        break;
                    }
                    case 'Partial Reverse': {
                        const el = document.querySelector('[data-test*="challenge-partialReverseTranslate"]')?.querySelector('span[contenteditable]');
                        if (el) {
                            const txt = window.sol?.displayTokens?.filter(t => t.isBlank)?.map(t => t.text)?.join('')?.trim() || '';
                            const setter = Object.getOwnPropertyDescriptor(Node.prototype, 'textContent').set;
                            setter.call(el, txt);
                            el.dispatchEvent(new Event('input', { bubbles: true }));
                        }
                        break;
                    }
                    case 'Type Cloze': {
                        const inp = document.querySelector('input[type="text"].b4jqk');
                        if (inp) {
                            const tok = window.sol?.displayTokens?.find(t => t.damageStart !== undefined);
                            if (tok) solver.setValue(inp, tok.text.slice(tok.damageStart));
                        }
                        break;
                    }
                    case 'Type Cloze Table': {
                        const rows = document.querySelectorAll('tbody tr');
                        window.sol?.displayTableTokens?.slice(1).forEach((rowToks, i) => {
                            const cell = rowToks[1]?.find(t => typeof t.damageStart === 'number');
                            if (cell && rows[i]) {
                                const inp = rows[i].querySelector('input[type="text"].b4jqk');
                                if (inp) solver.setValue(inp, cell.text.slice(cell.damageStart));
                            }
                        });
                        break;
                    }
                    case 'Tap Cloze Table': {
                        const rows = document.querySelectorAll('tbody tr');
                        window.sol?.displayTableTokens?.slice(1).forEach((rowToks, i) => {
                            const cell = rowToks[1]?.find(t => typeof t.damageStart === 'number');
                            if (!cell || !rows[i]) return;
                            const bank = document.querySelector('[data-test="word-bank"]');
                            const btns = bank ? Array.from(bank.querySelectorAll('button[data-test*="challenge-tap-token"]:not([aria-disabled="true"])')) : [];
                            const correct = cell.text.slice(cell.damageStart);
                            let matched = '';
                            for (const btn of btns) {
                                if (!correct.startsWith(matched + solver.getCleanButtonText(btn))) continue;
                                btn.click(); matched += solver.getCleanButtonText(btn);
                                if (matched === correct) break;
                            }
                        });
                        break;
                    }
                    case 'Type Complete Table': {
                        const rows = document.querySelectorAll('tbody tr');
                        window.sol?.displayTableTokens?.slice(1).forEach((rowToks, i) => {
                            const cell = rowToks[1]?.find(t => t.isBlank);
                            if (cell && rows[i]) {
                                const inp = rows[i].querySelector('input[type="text"].b4jqk');
                                if (inp) solver.setValue(inp, cell.text);
                            }
                        });
                        break;
                    }
                    case 'Pattern Tap Complete': {
                        const bank = document.querySelector('[data-test="word-bank"]');
                        if (bank) {
                            const idx = window.sol?.correctIndex ?? 0;
                            const txt = window.sol?.choices?.[idx];
                            const btn = Array.from(bank.querySelectorAll('button[data-test*="challenge-tap-token"]:not([aria-disabled="true"])')).find(b => solver.getCleanButtonText(b) === txt);
                            if (btn) btn.click();
                        }
                        break;
                    }
                    case 'Story Arrange': {
                        const choices = document.querySelectorAll('[data-test*="challenge-tap-token"]:not(span)');
                        for (const idx of (window.sol?.phraseOrder || [])) {
                            choices[idx]?.click(); await sl(50);
                        }
                        break;
                    }
                    case 'Story Multiple Choice': {
                        document.querySelectorAll('[data-test="stories-choice"]')[window.sol?.correctAnswerIndex ?? 0]?.click();
                        break;
                    }
                    case 'Story Point to Phrase': {
                        const choices = document.querySelectorAll('[data-test="challenge-tap-token-text"]');
                        let ci = -1;
                        for (let i = 0; i < (window.sol?.parts?.length || 0); i++) {
                            if (window.sol.parts[i].selectable) ci++;
                            if (window.sol.correctAnswerIndex === i) { choices[ci]?.parentElement?.click(); break; }
                        }
                        break;
                    }
                    case 'Story Pairs': {
                        const btns = document.querySelectorAll('[data-test*="challenge-tap-token"]:not(span)');
                        const texts = document.querySelectorAll('[data-test="challenge-tap-token-text"]');
                        const map = new Map();
                        for (let i = 0; i < btns.length; i++) map.set(texts[i]?.innerText?.toLowerCase()?.trim(), btns[i]);
                        for (const key in (window.sol?.dictionary || {})) {
                            const val = window.sol.dictionary[key];
                            const k = key.split(':')[1]?.toLowerCase()?.trim();
                            const v = val?.toLowerCase()?.trim();
                            map.get(k)?.click(); await sl(50);
                            map.get(v)?.click(); await sl(50);
                        }
                        break;
                    }
                    case 'Story Slide':
                       
                        break;
                    case 'Challenge Name': {
                        const arts = window.sol?.articles;
                        const correct = window.sol?.correctSolutions?.[0];
                        if (arts && correct) {
                            const match = arts.find(a => correct.startsWith(a));
                            if (match) {
                                const idx = arts.indexOf(match);
                                const sel = document.querySelector(`[data-test="challenge-choice"]:nth-child(${idx+1})`);
                                if (sel) { sel.click(); await sl(50); }
                                const inp = document.querySelector('[data-test="challenge-text-input"]');
                                if (inp) solver.setValue(inp, correct.substring(match.length).trim());
                            }
                        }
                        break;
                    }
                    case 'Pairs': {
                        const btns = document.querySelectorAll('[data-test*="challenge-tap-token"]:not(span)');
                        const texts = document.querySelectorAll('[data-test="challenge-tap-token-text"]');
                        if (texts.length !== btns.length || !btns.length) break;
                        for (const pair of (window.sol?.pairs || [])) {
                            for (let i = 0; i < btns.length; i++) {
                                if (btns[i].disabled) continue;
                                const t = texts[i].innerText.toLowerCase().trim();
                                if (t === pair.transliteration?.toLowerCase()?.trim() ||
                                    t === pair.character?.toLowerCase()?.trim() ||
                                    t === pair.learningToken?.toLowerCase()?.trim() ||
                                    t === pair.fromToken?.toLowerCase()?.trim()) {
                                    btns[i].click(); await sl(50);
                                }
                            }
                        }
                        break;
                    }
                    case 'Tokens Run': {
                        const all = document.querySelectorAll('[data-test$="challenge-tap-token"]');
                        const clicked = [];
                        for (const ct of (window.sol?.correctTokens || [])) {
                            const match = Array.from(all).filter(el => solver.getCleanButtonText(el) === ct.trim());
                            const idx = clicked.filter(t => solver.getCleanButtonText(t) === ct.trim()).length;
                            const btn = match[idx] || match[0];
                            if (btn && !btn.disabled) { btn.click(); clicked.push(btn); }
                        }
                        break;
                    }
                    case 'Indices Run':
                    case 'Fill in the Gap': {
                        if (!window.sol?.correctIndices) break;
                        const bank = document.querySelector('[data-test="word-bank"]') || document.querySelector('.eSgkc');
                        if (!bank) break;
                        const btns = Array.from(bank.querySelectorAll('button[data-test*="challenge-tap-token"]:not(span)'));
                        for (const idx of window.sol.correctIndices) {
                            if (idx>=0 && idx<btns.length && !btns[idx].disabled && btns[idx].getAttribute('aria-disabled')!=='true') {
                                btns[idx].click(); await sl(50);
                            }
                        }
                        break;
                    }
                    case 'Tap Complete Table': {
                        const rows = document.querySelectorAll('tbody tr');
                        const solRows = window.sol?.displayTableTokens?.slice(1) || [];
                        const bank = document.querySelector('[data-test="word-bank"]');
                        const bankBtns = bank ? Array.from(bank.querySelectorAll('button[data-test*="-challenge-tap-token"]')) : [];
                        const used = new Set();
                        for (let ri = 0; ri < solRows.length; ri++) {
                            const cell = solRows[ri][1]?.find(t => t.isBlank);
                            if (!cell) continue;
                            const txt = cell.text;
                            const rowBtns = rows[ri]?.querySelectorAll('button[data-test*="-challenge-tap-token"]');
                            let clicked = false;
                            if (rowBtns) {
                                for (const btn of rowBtns) {
                                    const tEl = btn.querySelector('[data-test="challenge-tap-token-text"]');
                                    if (tEl?.innerText.trim()===txt && !btn.disabled) { btn.click(); await sl(50); clicked=true; break; }
                                }
                            }
                            if (!clicked && bankBtns.length) {
                                for (let i = 0; i < bankBtns.length; i++) {
                                    if (used.has(i)) continue;
                                    const tEl = bankBtns[i].querySelector('[data-test="challenge-tap-token-text"]');
                                    if (tEl?.innerText.trim()===txt && !bankBtns[i].disabled) { bankBtns[i].click(); await sl(50); used.add(i); break; }
                                }
                            }
                        }
                        break;
                    }
                    case 'Syllable Tap':
                    case 'Syllable Listen Tap': {
                        const indices = window.sol?.correctIndices || [];
                        const choices = window.sol?.choices || [];
                        const domBtns = Array.from(document.querySelectorAll('[data-test="word-bank"] [data-test$="challenge-tap-token"]'));
                        indices.forEach(idx => {
                            const txt = choices[idx]?.text;
                            const btn = domBtns.find(b => solver.getCleanButtonText(b) === txt);
                            if (btn) btn.click();
                        });
                        break;
                    }
                    case 'Character Write Drag': {
                        const createEvent=(t,x,y,btns)=>new MouseEvent(t,{bubbles:true,clientX:x,clientY:y,buttons:btns,button:0});
                        const norm=s=>s?s.replace(/\s/g,''):'';
                        for (const stroke of (window.sol?.strokes||[])) {
                            const target=norm(stroke.path);
                            let path,handle;
                            while (!path||!handle) {
                                const cands=document.querySelectorAll('path._1e5Zt');
                                path=Array.from(cands).find(p=>norm(p.getAttribute('d'))===target);
                                handle=document.querySelector('g._25Ktp');
                                if (!path||!handle) await sl(10);
                            }
                            const mat=path.getScreenCTM(),len=path.getTotalLength();
                            const start=path.getPointAtLength(0).matrixTransform(mat);
                            const end=path.getPointAtLength(len).matrixTransform(mat);
                            handle.dispatchEvent(createEvent('mousedown',start.x,start.y,1));
                            for (let s=1;s<=10;s++){const p=path.getPointAtLength((s/10)*len).matrixTransform(mat);const m=createEvent('mousemove',p.x,p.y,1);handle.dispatchEvent(m);document.dispatchEvent(m);}
                            const fm=createEvent('mousemove',end.x,end.y,1);handle.dispatchEvent(fm);document.dispatchEvent(fm);
                            await sl(5);handle.dispatchEvent(createEvent('mouseup',end.x,end.y,0));document.dispatchEvent(createEvent('mouseup',end.x,end.y,0));
                        }
                        break;
                    }
                    case 'Character Write Draw': {
                        const createEvent=(t,x,y,btns)=>new MouseEvent(t,{bubbles:true,clientX:x,clientY:y,buttons:btns,button:0});
                        const norm=s=>s?s.replace(/\s/g,''):'';
                        for (const stroke of (window.sol?.strokes||[])) {
                            const target=norm(stroke.path);
                            let path,cursor;
                            while (!path||!cursor) {
                                const cands=document.querySelectorAll('path._1e5Zt');
                                path=Array.from(cands).find(p=>norm(p.getAttribute('d'))===target);
                                cursor=document.querySelector('g._1h31R:not(._25Ktp)');
                                if (!path||!cursor) await sl(10);
                            }
                            const mat=path.getScreenCTM(),len=path.getTotalLength();
                            const start=path.getPointAtLength(0).matrixTransform(mat);
                            const end=path.getPointAtLength(len).matrixTransform(mat);
                            cursor.dispatchEvent(createEvent('mousedown',start.x,start.y,1));document.dispatchEvent(createEvent('mousedown',start.x,start.y,1));
                            for (let s=1;s<=10;s++){const p=path.getPointAtLength((s/10)*len).matrixTransform(mat);const m=createEvent('mousemove',p.x,p.y,1);cursor.dispatchEvent(m);document.dispatchEvent(m);}
                            const fm=createEvent('mousemove',end.x,end.y,1);cursor.dispatchEvent(fm);document.dispatchEvent(fm);
                            await sl(5);cursor.dispatchEvent(createEvent('mouseup',end.x,end.y,0));document.dispatchEvent(createEvent('mouseup',end.x,end.y,0));
                        }
                        break;
                    }
                    case 'Character Write Freehand': {
                        const createEvent=(t,x,y,btns)=>new MouseEvent(t,{bubbles:true,clientX:x,clientY:y,buttons:btns,button:0});
                        const norm=s=>s?s.replace(/\s/g,''):'';
                        const freeStrokes=(window.sol?.strokes||[]).filter(s=>s.strokeDrawMode==='FREEHAND');
                        for (const stroke of freeStrokes) {
                            const target=norm(stroke.path);
                            let path,svg;
                            while (!path||!svg) {
                                const cands=document.querySelectorAll('path._22UPm');
                                path=Array.from(cands).find(p=>norm(p.getAttribute('d'))===target);
                                svg=document.querySelector('svg.o1rqi');
                                if (!path||!svg) await sl(10);
                            }
                            const mat=path.getScreenCTM(),len=path.getTotalLength();
                            const start=path.getPointAtLength(0).matrixTransform(mat);
                            const end=path.getPointAtLength(len).matrixTransform(mat);
                            svg.dispatchEvent(createEvent('mousedown',start.x,start.y,1));document.dispatchEvent(createEvent('mousedown',start.x,start.y,1));
                            for (let s=1;s<=10;s++){const p=path.getPointAtLength((s/10)*len).matrixTransform(mat);const m=createEvent('mousemove',p.x,p.y,1);svg.dispatchEvent(m);document.dispatchEvent(m);}
                            const fm=createEvent('mousemove',end.x,end.y,1);svg.dispatchEvent(fm);document.dispatchEvent(fm);
                            await sl(5);svg.dispatchEvent(createEvent('mouseup',end.x,end.y,0));document.dispatchEvent(createEvent('mouseup',end.x,end.y,0));
                        }
                        break;
                    }
                    case 'Next Only':
                    case 'Session Complete':
                    case 'Daily Quest Progress':
                    case 'Streak Slide':
                    case 'Leaderboard Slide':
                        
                        break;
                }
            } catch(e) { console.error('[DuoGang] Solver error:', type, e); }
        },

        clickNext: () => {
            const nb = document.querySelector('[data-test="player-next"]') ||
                       document.querySelector('[data-test="stories-player-continue"]') ||
                       document.querySelector('[data-test="stories-player-done"]') ||
                       document.querySelector('[data-test="story-start"]');
            if (!nb) return;
            const isDisabled = nb.getAttribute('aria-disabled') === 'true' || nb.disabled;
            if (!isDisabled) nb.click();
        },

        _busy: false,

        solve: async () => {
            if (solver._busy) return;
            solver._busy = true;
            try {
              
                [
                    '[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',
                    '._8AMBh._2vfJy._3Qy5R._28UWu._3h0lA._1S2uf._1E9sc',
                    '._1Qh5D._36g4N._2YF0P._28UWu._3h0lA._1S2uf._1E9sc',
                    '._3bBpU._1x5JY._1M9iF._36g4N._2YF0P.T7I0c._2EnxW.MYehf',
                    '._2V6ug._1ursp._7jW2t._28UWu._3h0lA._1S2uf._1E9sc',
                    '._1rcV8._1VYyp._1ursp._7jW2t._1gKir',
                    '._2V6ug._1ursp._7jW2t._3zgLG'
                ].forEach(sel => document.querySelector(sel)?.click());

               
                window.sol = solver.getSolution();

                const ct = solver.determineType();

                if (ct && ct !== 'Challenge Speak' && ct !== 'Listen Match' && ct !== 'Listen Speak') {
                    await Promise.race([
                        solver.handle(ct),
                        new Promise(r => setTimeout(r, 2000))
                    ]);
                    await new Promise(r => setTimeout(r, 80));
                } else if (ct === 'Challenge Speak' || ct === 'Listen Match' || ct === 'Listen Speak') {
                    await solver.handle(ct);
                }

                solver.clickNext();
                await new Promise(r => setTimeout(r, 120));

            } catch(e) {
                solver.clickNext();
            }
            solver._busy = false;
        },

        createUI: () => {
            if (solverUI) return;
            solverUI = document.createElement('div');
            solverUI.className = 'DG_Solver_Btn';
            solverUI.id = 'DG_Solver_UI';
            solverUI.innerHTML = `
                <button class="DG_Solve_One" id="DG_Solve_One">SOLVE</button>
                <button class="DG_Solve_All" id="DG_Solve_All">SOLVE ALL</button>
            `;
            document.body.appendChild(solverUI);
            document.getElementById('DG_Solve_One').addEventListener('click', () => solver.solve());
            document.getElementById('DG_Solve_All').addEventListener('click', () => solver.toggleAuto());
            document.addEventListener('keydown', (e) => {
                if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
                    if (e.shiftKey) solver.toggleAuto();
                    else solver.solve();
                }
            });
        },

        removeUI: () => {
            if (solverUI) { solverUI.remove(); solverUI = null; }
            isAutoMode = false; solveLoopRunning = false;
        },

        updateAutoBtn: () => {
            const btn = document.getElementById('DG_Solve_All'); if (!btn) return;
            if (isAutoMode) {
                btn.textContent = 'PAUSE';
                btn.style.background = 'rgb(var(--DG-red))';
                btn.style.borderBottomColor = '#cc0000';
            } else {
                btn.textContent = 'SOLVE ALL';
                btn.style.background = 'rgb(var(--DG-blue))';
                btn.style.borderBottomColor = '#1b5fb8';
            }
        },

        toggleAuto: () => {
            isAutoMode = !isAutoMode;
            solver.updateAutoBtn();
            if (isAutoMode && !solveLoopRunning) {
                solveLoopRunning = true;
                const initialUrl = window.location.href;
                (async function loop() {
                    while (isAutoMode) {
                        if (window.location.href !== initialUrl) {
                            isAutoMode = false; solver.updateAutoBtn(); break;
                        }
                        const t0 = Date.now();
                        await solver.solve();
                        await new Promise(r => setTimeout(r, 80));
                        if (!isAutoMode) break;
                        const elapsed = Date.now() - t0;
                        const wait = Math.max(0, 380 - elapsed);
                        if (wait > 0) await new Promise(r => setTimeout(r, wait));
                    }
                    solveLoopRunning = false;
                })();
            } else if (!isAutoMode) {
                solveLoopRunning = false;
            }
        }
    };

   
    async function farmPractice(count) {
        lessonsToSolve = count; currentLessonCount = 0;
        if (lessonSolving) { notif('Practice farm already running.'); return; }
        lessonSolving = true;
        const btn = document.getElementById('DG_Practice_Btn');
        if (btn) { btn.style.background = 'rgb(var(--DG-red))'; btn.style.color = '#fff'; btn.textContent = 'STOP'; }
        notif('Navigating to practice...', 3);
        if (!window.location.pathname.startsWith('/practice')) { window.location.assign('/practice'); return; }
        await solveCurrentLesson();
    }

    function isStoryLesson() {
        return !!document.querySelector('.FmlUF') ||
               window.location.pathname.includes('/stories') ||
               !!document.querySelector('[data-test="stories-player-continue"]') ||
               !!document.querySelector('[data-test="stories-player-done"]') ||
               !!document.querySelector('[data-test="story-start"]');
    }

   
    function findStoryReact(dom) {
        if (!dom) return null;
        // Try traverseUp=0 first (story layout), then 1
        for (const up of [0, 1, 2]) {
            try {
                const key = Object.keys(dom).find(k =>
                    k.startsWith("__reactFiber$") || k.startsWith("__reactInternalInstance$")
                );
                if (!key) continue;
                const domFiber = dom[key];
                if (!domFiber) continue;
                const GetCompFiber = fiber => {
                    let p = fiber.return;
                    while (typeof p.type === "string") p = p.return;
                    return p;
                };
                let compFiber = GetCompFiber(domFiber);
                for (let i = 0; i < up; i++) compFiber = GetCompFiber(compFiber);
                const stateNode = compFiber?.stateNode;
                if (stateNode?.props?.currentChallenge || stateNode?.props?.challenge) return stateNode;
            } catch {}
        }
        return null;
    }

    async function solveStoryLesson() {
       
        let waited = 0;
        while (!isStoryLesson() && waited < 10000 && lessonSolving) {
            await sleep(300);
            waited += 300;
        }
        if (!lessonSolving) return;

      
        const startBtn = document.querySelector('[data-test="story-start"]');
        if (startBtn) {
            startBtn.click();
            await sleep(800);
        }

        await new Promise(resolve => {
            let ticks = 0;
            const MAX_TICKS = 300;
            let solving = false;

            const iv = setInterval(async () => {
                try {
                    if (!lessonSolving) { clearInterval(iv); resolve(); return; }
                    if (++ticks > MAX_TICKS) { clearInterval(iv); resolve(); return; }

                   
                    const done = document.querySelector('[data-test="stories-player-done"]') &&
                                 !document.querySelector('[data-test="stories-player-done"]').disabled;
                    const sessionOver = document.querySelector('[data-test="session-over"]') ||
                                        document.querySelector('[data-test="session-complete-slide"]') ||
                                        document.querySelector('[data-test="session-complete"]');

                    if (sessionOver) {
                        clearInterval(iv);
                        currentLessonCount++;
                        try {
                            const s = JSON.parse(sessionStorage.getItem('dg_practice') || '{}');
                            s.done = currentLessonCount;
                            sessionStorage.setItem('dg_practice', JSON.stringify(s));
                        } catch {}
                        await sleep(500);
                        resolve();
                        return;
                    }

                    if (solving) return;

                    
                    const skipSels = [
                        '[data-test="practice-hub-ad-no-thanks-button"]',
                        '[data-test="plus-no-thanks"]',
                        '.vpDIE',
                        '._1N-oo._36Vd3._16r-S._1ZBYz._23KDq._1S2uf.HakPM'
                    ];
                    skipSels.forEach(sel => document.querySelector(sel)?.click());

                    
                    const storyEl = document.querySelector('.FmlUF') ||
                                    document.querySelector('[data-test="stories-player-continue"]')?.closest('div') ||
                                    document.querySelector('[class*="story"]');

                   
                    let challengeEl = document.querySelector('._3yE3H') ||
                                      document.querySelector('.RMEuZ._1GVfY') ||
                                      document.querySelector('[data-test="challenge"]') ||
                                      document.querySelector('.FmlUF');

                    if (challengeEl) {
                        const ri = findStoryReact(challengeEl);
                        window.sol = ri?.props?.currentChallenge || ri?.props?.challenge;
                    }

                    const ct = solver.determineType();

                    if (!ct) {
                       
                        const contBtn = document.querySelector('[data-test="stories-player-continue"]');
                        const nextBtn = document.querySelector('[data-test="player-next"]');
                        if (contBtn && !contBtn.disabled) {
                            contBtn.click();
                        } else if (nextBtn && nextBtn.getAttribute('aria-disabled') !== 'true' && !nextBtn.disabled) {
                            nextBtn.click();
                        }
                        return;
                    }

                    solving = true;
                    try {
                        await solver.handle(ct);
                    } catch (e) {
                        console.error('Story solve error:', e);
                    }
                    await sleep(300);

                   
                    const doneBtn = document.querySelector('[data-test="stories-player-done"]');
                    const contBtn = document.querySelector('[data-test="stories-player-continue"]');
                    const nextBtn = document.querySelector('[data-test="player-next"]');

                    if (doneBtn && !doneBtn.disabled) {
                        doneBtn.click();
                        clearInterval(iv);
                        currentLessonCount++;
                        try {
                            const s = JSON.parse(sessionStorage.getItem('dg_practice') || '{}');
                            s.done = currentLessonCount;
                            sessionStorage.setItem('dg_practice', JSON.stringify(s));
                        } catch {}
                        await sleep(500);
                        resolve();
                        return;
                    } else if (contBtn && !contBtn.disabled) {
                        contBtn.click();
                    } else if (nextBtn && nextBtn.getAttribute('aria-disabled') !== 'true' && !nextBtn.disabled) {
                        nextBtn.click();
                    }

                    await sleep(500);
                    solving = false;
                } catch (e) {
                    console.error('Story tick error:', e);
                    solving = false;
                }
            }, 500);

            
            setTimeout(() => { clearInterval(iv); resolve(); }, 150000);
        });
    }

    async function solveCurrentLesson() {
        
        await sleep(800);

        if (isStoryLesson()) {
           
            await solveStoryLesson();
        } else {
           
            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 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();
                };
                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"]') ||
                            document.querySelector('[data-test="player-practice-again"]');
                        if (done) {
                            clearInterval(iv); currentLessonCount++;
                            try { const s = JSON.parse(sessionStorage.getItem('dg_practice') || '{}'); s.done = currentLessonCount; sessionStorage.setItem('dg_practice', JSON.stringify(s)); } catch {}
                            await sleep(500); resolve(); return;
                        }
                        if (solving) return;
                        window.sol = solver.getSolution();
                        if (!window.sol) { clickNext(); return; }
                        const type = solver.determineType();
                        if (!type) { clickNext(); return; }
                        solving = true;
                        try { await solver.handle(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('Practice farm done! ' + currentLessonCount + ' lessons.');
            stopPractice();
            return;
        }
        notif('Done ' + currentLessonCount + (lessonsToSolve > 0 ? ' / ' + lessonsToSolve : '') + ' — loading next…', 2);
        await sleep(800);
        if (lessonSolving) window.location.assign('/practice');
    }

    function stopPractice() {
        lessonSolving = false;
        const btn = document.getElementById('DG_Practice_Btn');
        if (btn) { btn.style.background = ''; btn.style.color = ''; btn.textContent = 'Practice Farm'; }
    }

    function resumePracticeIfNeeded() {
        const saved = sessionStorage.getItem('dg_practice');
        if (!saved) return;
        try {
            const { active, count, done } = JSON.parse(saved);
            if (!active) return;
            lessonsToSolve = count;
            currentLessonCount = done;
            sessionStorage.setItem('dg_practice', JSON.stringify({ active: true, count, done }));
            if (window.location.pathname.startsWith('/practice')) {
                lessonSolving = true;
                if (user) {
                    const btn = document.getElementById('DG_Practice_Btn');
                    if (btn) { btn.style.background = 'rgb(var(--DG-red))'; btn.style.color = '#fff'; btn.textContent = 'STOP'; }
                    solveCurrentLesson();
                } else {
                    const check = setInterval(() => {
                        if (user) {
                            clearInterval(check);
                            const btn = document.getElementById('DG_Practice_Btn');
                            if (btn) { btn.style.background = 'rgb(var(--DG-red))'; btn.style.color = '#fff'; btn.textContent = 'STOP'; }
                            solveCurrentLesson();
                        }
                    }, 500);
                }
            }
        } catch {}
    }

   
    let solverObserver = null;
    function initSolverObserver() {
        if (solverObserver) solverObserver.disconnect();
        const checkAndInject = () => {
            const inLesson = window.location.pathname.includes('/lesson') ||
                             window.location.pathname.includes('/practice') ||
                             window.location.pathname.includes('/practice-hub') ||
                             window.location.pathname.includes('/stories');
            const hasTarget = !!document.querySelector('[data-test="player-next"],[data-test="stories-player-continue"],[data-test="stories-player-done"],[data-test="story-start"]');
            if (inLesson && solverEnabled && hasTarget && showSolveButtons) {
                if (!solverUI) solver.createUI();
            } else if (!inLesson || !solverEnabled) {
                solver.removeUI();
            }
        };

        solverObserver = new MutationObserver(() => { checkAndInject(); });
        solverObserver.observe(document.body, { childList: true, subtree: true });
        
        const origPush = history.pushState, origReplace = history.replaceState;
        history.pushState = function(){origPush.apply(this,arguments);checkAndInject();};
        history.replaceState = function(){origReplace.apply(this,arguments);checkAndInject();};
        window.addEventListener('popstate', checkAndInject);
        checkAndInject();
    }
    initSolverObserver();

   
    function installFakeSuper() {
        if (localStorage.getItem('dg_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();

   

   
    const dgRoot = document.getElementById('DG_Root');
    let isDark = localStorage.getItem('dg_dark') === 'true';
    function applyDarkMode() {
        if (isDark) {
            dgRoot.classList.add('DG_Dark');
            document.getElementById('DG_Dark_Icon_Moon').style.display = 'none';
            document.getElementById('DG_Dark_Icon_Sun').style.display = 'block';
        } else {
            dgRoot.classList.remove('DG_Dark');
            document.getElementById('DG_Dark_Icon_Moon').style.display = 'block';
            document.getElementById('DG_Dark_Icon_Sun').style.display = 'none';
        }
    }
    applyDarkMode();
    document.getElementById('DG_Dark_Btn').addEventListener('click', () => {
        isDark = !isDark;
        localStorage.setItem('dg_dark', isDark ? 'true' : 'false');
        applyDarkMode();
    });

   
    document.getElementById('DG_Hide_Btn').addEventListener('click', (e) => {
        if (window._dgDragMoved) return;
        hidden = !hidden;
        const box = document.getElementById('DG_Main_Box');
        const btn = document.getElementById('DG_Hide_Btn');
        const label = document.getElementById('DG_Hide_Label');
        const hideables = document.querySelectorAll('.DG_Hideable');

        box.style.transition = 'opacity 0.8s cubic-bezier(0.16, 1, 0.32, 1), filter 0.8s cubic-bezier(0.16, 1, 0.32, 1)';
        if (hidden) {
            box.style.opacity = '0';
            box.style.filter = 'blur(8px)';
            box.style.pointerEvents = 'none';
            hideables.forEach(el => el.classList.add('DG_Header_Hidden'));
            label.textContent = 'Show';
            btn.classList.add('DG_Hide_Btn_Hidden');
        } else {
            box.style.opacity = '';
            box.style.filter = '';
            box.style.pointerEvents = '';
            hideables.forEach(el => el.classList.remove('DG_Header_Hidden'));
            label.textContent = 'Hide';
            btn.classList.remove('DG_Hide_Btn_Hidden');
        }
        setTimeout(() => { box.style.transition = ''; }, 800);
    });

    
    (function() {
        const main = document.getElementById('DG_Main');
        let dragging = false, startX, startY, origRight, origBottom;
        window._dgDragMoved = false;

        main.addEventListener('mousedown', (e) => {
            const hideBtn = document.getElementById('DG_Hide_Btn');
            if (!hideBtn.contains(e.target) && e.target !== hideBtn) return;
            dragging = true;
            window._dgDragMoved = false;
            const rect = main.getBoundingClientRect();
            startX = e.clientX;
            startY = e.clientY;
            origRight = window.innerWidth - rect.right;
            origBottom = window.innerHeight - rect.bottom;
            main.classList.add('DG_Dragging');
            e.preventDefault();
        });

        document.addEventListener('mousemove', (e) => {
            if (!dragging) return;
            const dx = e.clientX - startX;
            const dy = e.clientY - startY;
            if (Math.abs(dx) > 4 || Math.abs(dy) > 4) window._dgDragMoved = true;
            const newRight = Math.max(0, Math.min(window.innerWidth - 50, origRight - dx));
            const newBottom = Math.max(0, Math.min(window.innerHeight - 50, origBottom - dy));
            main.style.right = newRight + 'px';
            main.style.bottom = newBottom + 'px';
        });

        document.addEventListener('mouseup', () => {
            if (!dragging) return;
            dragging = false;
            main.classList.remove('DG_Dragging');
            localStorage.setItem('dg_pos', JSON.stringify({ right: main.style.right, bottom: main.style.bottom }));
            setTimeout(() => { window._dgDragMoved = false; }, 50);
        });

        try {
            const saved = JSON.parse(localStorage.getItem('dg_pos') || 'null');
            if (saved && saved.right && saved.bottom) {
                main.style.right = saved.right;
                main.style.bottom = saved.bottom;
            }
        } catch {}
    })();

    
    document.getElementById('DG_Settings_Btn').addEventListener('click', () => switchPage('Settings'));
    document.getElementById('DG_Settings_Back_Btn').addEventListener('click', () => switchPage('Main'));

   
    const xpI = document.getElementById('DG_XP_Input'), xpB = document.getElementById('DG_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('Stop current farm first.'); return; }
        const v = +xpI.value;
        if (v < 30) { notif('Min 30 XP'); return; }
        run('xp', v);
    });
    xpI.addEventListener('keydown', e => { if (e.key === 'Enter' && !xpB.disabled) xpB.click(); });

   
    document.getElementById('DG_Gem_Btn').addEventListener('click', () => {
        if (running && task === 'gems') { run('gems', 0); return; }
        if (running) { notif('Stop current farm first.'); return; }
        run('gems', 0);
    });

  
    const stI = document.getElementById('DG_Streak_Input'), stB = document.getElementById('DG_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('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(); });

   
    document.getElementById('DG_Practice_Btn').addEventListener('click', () => {
        if (lessonSolving) {
            stopPractice();
            sessionStorage.removeItem('dg_practice');
            notif('Practice farm stopped.');
            return;
        }
        if (running) { notif('Stop current farm first.'); return; }
        if (!user) { notif('Please wait for connection.'); return; }
        sessionStorage.setItem('dg_practice', JSON.stringify({ active: true, count: 0, done: 0 }));
        farmPractice(0);
    });

   
    document.getElementById('DG_Super_Btn').addEventListener('click', () => {
        localStorage.setItem('dg_super', localStorage.getItem('dg_super') === 'true' ? 'false' : 'true');
        notif(localStorage.getItem('dg_super') === 'true' ? 'Free Super activated! Reload page.' : 'Free Super deactivated. Reload page.');
    });

    
    document.getElementById('DG_Shop_Btn').addEventListener('click', () => {
        switchPage('Shop');
        loadShop();
    });
    document.getElementById('DG_Shop_Back_Btn').addEventListener('click', () => switchPage('Main'));

    
    document.getElementById('DG_League_Btn').addEventListener('click', () => {
        if (running && task === 'league') { run('league', 0); return; }
        if (running) { notif('Stop current farm first.'); return; }
        run('league', 0);
    });

   
    document.getElementById('DG_Quest_Btn').addEventListener('click', async () => {
        if (running) { notif('Stop current farm first.'); return; }
        await farmDailyQuest();
    });

  
    document.getElementById('DG_MonthlyQuest_Btn').addEventListener('click', () => {
        switchPage('MonthlyQuests');
        loadMonthlyQuests();
    });
    document.getElementById('DG_MQ_Back_Btn').addEventListener('click', () => switchPage('Main'));
    document.getElementById('DG_MQ_ClaimAll_Btn').addEventListener('click', () => claimAllMonthly());

   
    document.getElementById('DG_AccMgr_Btn').addEventListener('click', () => {
        switchPage('Accounts');
        renderAccounts();
    });
    document.getElementById('DG_AccMgr_Back_Btn').addEventListener('click', () => switchPage('Main'));
    document.getElementById('DG_AccSave_Btn').addEventListener('click', () => accSaveCurrent());

   
    const solverT = document.getElementById('DG_Solver_Toggle');
    solverT.checked = solverEnabled;
    solverT.addEventListener('change', () => {
        solverEnabled = solverT.checked;
        localStorage.setItem('dg_solver', solverEnabled ? 'true' : 'false');
        if (!solverEnabled) solver.removeUI();
    });

   
    const box = document.getElementById('DG_Main_Box');
    box.style.opacity = '0';
    box.style.filter = 'blur(8px)';
    setTimeout(() => {
        box.style.transition = 'opacity 0.8s cubic-bezier(0.16, 1, 0.32, 1), filter 0.8s cubic-bezier(0.16, 1, 0.32, 1)';
        box.style.opacity = '';
        box.style.filter = '';
        setTimeout(() => { box.style.transition = ''; }, 800);
    }, 300);

    resumePracticeIfNeeded();
    checkForUpdate();
    setTimeout(connect, 600);

})();