// ==UserScript== // @name KG_Latest_Games // @namespace klavogonki // @version 1.8.7 // @description Fast game creation buttons on all the pages // @match *://klavogonki.ru/* // @author Patcher // @icon https://www.google.com/s2/favicons?sz=64&domain=klavogonki.ru // ==/UserScript== (()=>{"use strict";var e={56:(e,t,a)=>{e.exports=function(e){var t=a.nc;t&&e.setAttribute("nonce",t)}},72:e=>{var t=[];function a(e){for(var a=-1,r=0;r{e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}},314:e=>{e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var a="",r=void 0!==t[5];return t[4]&&(a+="@supports (".concat(t[4],") {")),t[2]&&(a+="@media ".concat(t[2]," {")),r&&(a+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),a+=e(t),r&&(a+="}"),t[2]&&(a+="}"),t[4]&&(a+="}"),a})).join("")},t.i=function(e,a,r,n,o){"string"==typeof e&&(e=[[null,e,void 0]]);var s={};if(r)for(var i=0;i0?" ".concat(p[5]):""," {").concat(p[1],"}")),p[5]=o),a&&(p[2]?(p[1]="@media ".concat(p[2]," {").concat(p[1],"}"),p[2]=a):p[2]=a),n&&(p[4]?(p[1]="@supports (".concat(p[4],") {").concat(p[1],"}"),p[4]=n):p[4]="".concat(n)),t.push(p))}},t}},540:e=>{e.exports=function(e){var t=document.createElement("style");return e.setAttributes(t,e.attributes),e.insert(t,e.options),t}},601:e=>{e.exports=function(e){return e[1]}},659:e=>{var t={};e.exports=function(e,a){var r=function(e){if(void 0===t[e]){var a=document.querySelector(e);if(window.HTMLIFrameElement&&a instanceof window.HTMLIFrameElement)try{a=a.contentDocument.head}catch(e){a=null}t[e]=a}return t[e]}(e);if(!r)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");r.appendChild(a)}},825:e=>{e.exports=function(e){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var t=e.insertStyleElement(e);return{update:function(a){!function(e,t,a){var r="";a.supports&&(r+="@supports (".concat(a.supports,") {")),a.media&&(r+="@media ".concat(a.media," {"));var n=void 0!==a.layer;n&&(r+="@layer".concat(a.layer.length>0?" ".concat(a.layer):""," {")),r+=a.css,n&&(r+="}"),a.media&&(r+="}"),a.supports&&(r+="}");var o=a.sourceMap;o&&"undefined"!=typeof btoa&&(r+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(o))))," */")),t.styleTagTransform(r,e,t.options)}(t,e,a)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},911:(e,t,a)=>{a.d(t,{A:()=>i});var r=a(601),n=a.n(r),o=a(314),s=a.n(o)()(n());s.push([e.id,'.vocabulary-types-popup,.game-migration-popup,.vocabulary-creation-popup,.game-popup{position:fixed;display:flex;flex-direction:column;gap:5px;padding:5px;background-color:var(--rg-bg-primary);border:1px solid var(--rg-border-primary);border-radius:8px !important;box-shadow:0 2px 10px rgba(0,0,0,.1) !important;max-height:50vh;max-width:400px;overflow-y:auto;scrollbar-width:none;z-index:2000;user-select:none}.vocabulary-types-popup .popup-header-qualification,.game-migration-popup .popup-header-qualification,.vocabulary-creation-popup .popup-header-qualification,.game-popup .popup-header-qualification{display:flex;align-items:center;justify-content:center;width:16px;height:16px;cursor:pointer}.vocabulary-types-popup .popup-header,.game-migration-popup .popup-header,.vocabulary-creation-popup .popup-header,.game-popup .popup-header{display:inline-flex;font:600 14px "Montserrat",sans-serif;color:var(--rg-header-text);padding:6px;justify-content:space-between}.vocabulary-types-popup .popup-subheader,.game-migration-popup .popup-subheader,.vocabulary-creation-popup .popup-subheader,.game-popup .popup-subheader{font:600 14px "Montserrat",sans-serif;color:var(--rg-text-secondary);padding:6px}.vocabulary-types-popup .timeouts-container,.game-migration-popup .timeouts-container,.vocabulary-creation-popup .timeouts-container,.game-popup .timeouts-container{display:flex;flex-direction:row;gap:5px}.vocabulary-types-popup .timeouts-container .game-popup-button,.game-migration-popup .timeouts-container .game-popup-button,.vocabulary-creation-popup .timeouts-container .game-popup-button,.game-popup .timeouts-container .game-popup-button{display:inline-block;padding:5px 15px;font:600 14px "Montserrat",sans-serif;border-radius:4px !important;background:var(--rg-bg-card) !important;color:var(--rg-text-primary) !important;border:1.5px solid var(--rg-border-primary);cursor:pointer;user-select:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;text-decoration:none}.vocabulary-types-popup .timeouts-container .game-popup-button:hover,.vocabulary-types-popup .timeouts-container .game-popup-button:focus,.game-migration-popup .timeouts-container .game-popup-button:hover,.game-migration-popup .timeouts-container .game-popup-button:focus,.vocabulary-creation-popup .timeouts-container .game-popup-button:hover,.vocabulary-creation-popup .timeouts-container .game-popup-button:focus,.game-popup .timeouts-container .game-popup-button:hover,.game-popup .timeouts-container .game-popup-button:focus{border-color:var(--rg-border-hover);background:var(--rg-bg-hover);color:var(--rg-text-primary)}.vocabulary-types-popup .group-tab,.vocabulary-types-popup .popup-button,.game-migration-popup .group-tab,.game-migration-popup .popup-button,.vocabulary-creation-popup .group-tab,.vocabulary-creation-popup .popup-button,.game-popup .group-tab,.game-popup .popup-button{display:inline-flex;padding:5px 15px;min-height:30px;max-width:300px;font:600 14px "Montserrat",sans-serif;border-radius:4px !important;background:var(--rg-bg-card);color:var(--rg-text-primary);border:2px solid var(--rg-border-primary);cursor:pointer;user-select:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;height:fit-content;transition:border .1s ease,background-color .1s ease}.vocabulary-types-popup .group-tab:hover,.vocabulary-types-popup .group-tab:focus,.vocabulary-types-popup .popup-button:hover,.vocabulary-types-popup .popup-button:focus,.game-migration-popup .group-tab:hover,.game-migration-popup .group-tab:focus,.game-migration-popup .popup-button:hover,.game-migration-popup .popup-button:focus,.vocabulary-creation-popup .group-tab:hover,.vocabulary-creation-popup .group-tab:focus,.vocabulary-creation-popup .popup-button:hover,.vocabulary-creation-popup .popup-button:focus,.game-popup .group-tab:hover,.game-popup .group-tab:focus,.game-popup .popup-button:hover,.game-popup .popup-button:focus{border-color:var(--rg-border-hover);background:var(--rg-bg-hover);color:var(--rg-text-primary)}.vocabulary-types-popup .group-tab.active,.vocabulary-types-popup .popup-button.active,.game-migration-popup .group-tab.active,.game-migration-popup .popup-button.active,.vocabulary-creation-popup .group-tab.active,.vocabulary-creation-popup .popup-button.active,.game-popup .group-tab.active,.game-popup .popup-button.active{color:var(--rg-gametype-normal) !important;background-color:var(--rg-bg-card-pinned-normal) !important;border:2px solid var(--rg-border-pinned-normal) !important}.vocabulary-types-popup .group-tab.warning,.vocabulary-types-popup .popup-button.warning,.game-migration-popup .group-tab.warning,.game-migration-popup .popup-button.warning,.vocabulary-creation-popup .group-tab.warning,.vocabulary-creation-popup .popup-button.warning,.game-popup .group-tab.warning,.game-popup .popup-button.warning{color:var(--rg-gametype-chars) !important;background-color:var(--rg-bg-card-pinned-chars) !important;border:2px solid var(--rg-border-pinned-chars) !important}.vocabulary-types-popup .group-tab.danger,.vocabulary-types-popup .popup-button.danger,.game-migration-popup .group-tab.danger,.game-migration-popup .popup-button.danger,.vocabulary-creation-popup .group-tab.danger,.vocabulary-creation-popup .popup-button.danger,.game-popup .group-tab.danger,.game-popup .popup-button.danger{color:var(--rg-gametype-marathon) !important;background-color:var(--rg-bg-card-pinned-marathon) !important;border:2px solid var(--rg-border-pinned-marathon) !important}.vocabulary-types-popup .rank-slider-container,.game-migration-popup .rank-slider-container,.vocabulary-creation-popup .rank-slider-container,.game-popup .rank-slider-container{display:flex;flex-direction:column;align-items:stretch;margin:6px}.vocabulary-types-popup .rank-slider-container .rank-slider-display,.game-migration-popup .rank-slider-container .rank-slider-display,.vocabulary-creation-popup .rank-slider-container .rank-slider-display,.game-popup .rank-slider-container .rank-slider-display{margin:0 0 12px;font:600 14px "Montserrat",sans-serif;color:var(--rg-text-secondary)}.vocabulary-types-popup .rank-slider-container .rank-slider-track,.game-migration-popup .rank-slider-container .rank-slider-track,.vocabulary-creation-popup .rank-slider-container .rank-slider-track,.game-popup .rank-slider-container .rank-slider-track{position:relative;height:8px;background:var(--rg-rank-slider-track-bg);border-radius:4px !important;cursor:pointer;border:2px solid var(--rg-rank-slider-border);box-sizing:border-box}.vocabulary-types-popup .rank-slider-container .rank-slider-range,.game-migration-popup .rank-slider-container .rank-slider-range,.vocabulary-creation-popup .rank-slider-container .rank-slider-range,.game-popup .rank-slider-container .rank-slider-range{position:absolute;height:100%;background:var(--rg-rank-slider-range);border-radius:4px !important;z-index:1}.vocabulary-types-popup .rank-slider-container .rank-slider-handle,.game-migration-popup .rank-slider-container .rank-slider-handle,.vocabulary-creation-popup .rank-slider-container .rank-slider-handle,.game-popup .rank-slider-container .rank-slider-handle{position:absolute;top:50%;width:18px;height:18px;background:var(--rg-rank-slider-handle-bg);border:2px solid var(--rg-rank-slider-border);border-radius:50% !important;transform:translate(-50%, -50%);z-index:2;cursor:pointer;box-shadow:0 1px 4px rgba(0,0,0,.08) !important;transition:border-color .2s,background .2s}.vocabulary-types-popup .rank-slider-container .rank-slider-handle:focus,.game-migration-popup .rank-slider-container .rank-slider-handle:focus,.vocabulary-creation-popup .rank-slider-container .rank-slider-handle:focus,.game-popup .rank-slider-container .rank-slider-handle:focus{outline:none;border-color:var(--rg-rank-slider-border-focus)}.vocabulary-types-popup .rank-slider-container .rank-slider-handle.overlap-left,.game-migration-popup .rank-slider-container .rank-slider-handle.overlap-left,.vocabulary-creation-popup .rank-slider-container .rank-slider-handle.overlap-left,.game-popup .rank-slider-container .rank-slider-handle.overlap-left{transform:translate(-100%, -50%)}.vocabulary-types-popup .rank-slider-container .rank-slider-handle.overlap-right,.game-migration-popup .rank-slider-container .rank-slider-handle.overlap-right,.vocabulary-creation-popup .rank-slider-container .rank-slider-handle.overlap-right,.game-popup .rank-slider-container .rank-slider-handle.overlap-right{transform:translate(0, -50%)}.latest-games-search-container{position:relative;margin:10px 10px 0;display:flex;flex-direction:row;align-items:center}.latest-games-search-container.latest-games-hidden{display:none}.latest-games-search-container #latest-games-search-input{width:100%;box-sizing:border-box;padding:8px 12px;font-size:15px;font-family:"Montserrat",sans-serif;border:1.5px solid var(--rg-border-primary);border-radius:6px !important;background:var(--rg-bg-card);color:var(--rg-text-primary);outline:none;transition:border-color .2s,background .2s,color .2s}.latest-games-search-container #latest-games-search-input:focus{border-color:var(--rg-border-hover);background:var(--rg-bg-hover);color:var(--rg-text-primary)}.latest-games-search-container .latest-games-clear-btn{position:absolute;top:50%;transform:translateY(-50%);width:24px;height:24px;border:none;outline:none;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;visibility:hidden;transition:opacity .15s ease;z-index:1}.latest-games-search-container .latest-games-clear-btn svg{width:14px;height:14px}.latest-games-search-container .latest-games-clear-btn.visible{opacity:1;visibility:visible}.latest-games-search-noresults{display:inline-flex;padding:5px 15px;max-width:300px;font:500 14px "Montserrat",sans-serif;border-radius:4px !important;user-select:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;height:auto;justify-content:center;align-items:center;color:var(--rg-gametype-marathon);border:2px solid var(--rg-border-pinned-marathon);background-color:var(--rg-bg-card-pinned-marathon)}.latest-games-search-more{display:inline-flex;padding:5px 15px;max-width:300px;font:500 14px "Montserrat",sans-serif;border-radius:4px !important;user-select:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;height:auto;justify-content:center;align-items:center;color:var(--rg-gametype-chars);border:2px solid var(--rg-border-pinned-chars);background-color:var(--rg-bg-card-pinned-chars);cursor:pointer}.games-data-container .indicator{transition:.2s ease-in-out;font-family:"Montserrat",sans-serif;font-size:1.5em;font-weight:500;font-variant-numeric:tabular-nums;padding:8px;display:flex;justify-content:flex-start;align-items:center;cursor:default;border-radius:.2em !important;height:fit-content}.games-data-container{position:fixed;display:flex;flex-direction:row;top:50px;right:5px;gap:5px;user-select:none;z-index:2000}.games-data-container .period-indicators-container{display:flex;flex-direction:row;gap:5px}.games-data-container .period-indicators-container .period-indicator-description{padding-right:5px;font-family:"Montserrat",sans-serif;font-size:.5em;font-weight:600;text-transform:uppercase}.games-data-container .sleep-start-indicator{color:hsl(88,50%,55%);background-color:hsl(88,40%,20%);border:1px solid hsl(88,45%,35%)}.games-data-container .sleep-replay-indicator{color:hsl(208,50%,70%);background-color:hsl(208,40%,25%);border:1px solid hsl(208,45%,50%)}.games-data-container .remaining-count-indicator{color:hsl(50,0%,75%);background-color:hsl(50,0%,15%);border:1px solid hsl(50,0%,30%)}.games-data-container .today-play-count-indicator{color:hsl(30,60%,65%);background-color:hsl(30,45%,20%);border:1px solid #963;cursor:pointer}.games-data-container .week-play-count-indicator{color:hsl(150,60%,65%);background-color:hsl(150,45%,20%);border:1px solid #396}.games-data-container .month-play-count-indicator{color:hsl(340,55%,65%);background-color:hsl(340,40%,20%);border:1px solid hsl(340,45%,40%)}.games-data-container .year-play-count-indicator{color:hsl(200,55%,65%);background-color:hsl(200,40%,20%);border:1px solid hsl(200,45%,40%)}.games-data-container .period-indicator:not(.show){display:none !important}.games-data-container .period-indicator.show{display:flex !important;animation:fallDown 320ms cubic-bezier(0.22, 0.9, 0.31, 1) both;animation-delay:var(--fall-delay, 0ms)}@keyframes fallDown{0%{transform:translateY(-20px) scaleY(0.98);opacity:0}100%{transform:translateY(0) scaleY(1);opacity:1}}.vocabulary-tooltip-popup{font:500 14px "Montserrat",sans-serif;position:fixed;background:var(--rg-bg-primary);color:var(--rg-text-primary);padding:0;z-index:1200;font-size:.9em;pointer-events:auto;white-space:pre-wrap;border:1px solid var(--rg-border-primary) !important;border-radius:4px !important;box-shadow:0 2px 5px rgba(0,0,0,.3) !important;max-width:700px;width:auto;max-height:80vh;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:var(--rg-text-tertiary) var(--rg-bg-primary);word-wrap:break-word;overflow-wrap:break-word}.vocabulary-tooltip-popup::-webkit-scrollbar{width:8px;height:8px}.vocabulary-tooltip-popup::-webkit-scrollbar-track{background:var(--rg-bg-primary) !important}.vocabulary-tooltip-popup::-webkit-scrollbar-thumb{background-color:var(--rg-text-tertiary) !important}.vocabulary-tooltip-popup::-webkit-scrollbar-thumb:hover{background-color:var(--rg-text-secondary) !important}.vocabulary-tooltip-popup .tooltip-header{padding:12px 16px;background:var(--rg-bg-secondary);border-bottom:1px solid var(--rg-border-primary)}.vocabulary-tooltip-popup .tooltip-author{display:flex;align-items:center;margin-bottom:10px;gap:10px}.vocabulary-tooltip-popup .tooltip-avatar{width:32px;height:32px;border-radius:.4rem;object-fit:contain;background:var(--rg-bg-tertiary);border:1px solid var(--rg-border-secondary)}.vocabulary-tooltip-popup .tooltip-author-name{font-weight:600;color:var(--rg-text-primary);font-size:1em}.vocabulary-tooltip-popup .tooltip-title{font-size:1.1em;font-weight:600;color:var(--rg-text-primary);margin-bottom:8px;line-height:1.3}.vocabulary-tooltip-popup .tooltip-rating{display:flex;align-items:center;gap:8px;margin-bottom:6px;font-size:.95em}.vocabulary-tooltip-popup .stars-container{position:relative;display:inline-grid;line-height:1}.vocabulary-tooltip-popup .stars-bg{grid-area:1/1;font-size:16px;line-height:1;letter-spacing:2px;filter:grayscale(100%);opacity:.4}.vocabulary-tooltip-popup .stars-filled{grid-area:1/1;font-size:16px;line-height:1;letter-spacing:2px;overflow:hidden;white-space:nowrap}.vocabulary-tooltip-popup .rating-count{color:var(--rg-text-secondary);font-size:.9em}.vocabulary-tooltip-popup .tooltip-users{font-size:.9em;color:var(--rg-text-secondary);margin-bottom:8px}.vocabulary-tooltip-popup .tooltip-type{font-size:.9em;color:var(--rg-text-secondary);margin-bottom:6px}.vocabulary-tooltip-popup .tooltip-type strong{color:var(--rg-text-primary);font-weight:600}.vocabulary-tooltip-popup .tooltip-description{font-size:.95em;color:var(--rg-text-primary);margin-bottom:8px;padding:8px;background:var(--rg-bg-tertiary);border-radius:4px;line-height:1.4}.vocabulary-tooltip-popup .tooltip-stats{font-size:.85em;color:var(--rg-text-tertiary);margin-bottom:6px;font-style:italic}.vocabulary-tooltip-popup .tooltip-date{font-size:.85em;color:var(--rg-text-secondary);margin-bottom:4px}.vocabulary-tooltip-popup .tooltip-date strong{color:var(--rg-text-primary);font-weight:600}.vocabulary-tooltip-popup .tooltip-version{font-size:.8em;color:var(--rg-text-tertiary);margin-left:0;font-style:italic}.vocabulary-tooltip-popup .tooltip-divider{height:1px;background:var(--rg-border-primary);margin:0}.vocabulary-tooltip-popup .tooltip-content{padding:12px 16px;white-space:pre-wrap}.vocabulary-tooltip-popup .tooltip-number{color:var(--rg-text-secondary);opacity:.5;font-weight:400}.vocabularies-manager-popup{position:fixed;background:var(--rg-bg-primary);color:var(--rg-text-primary);padding:1em;z-index:1200;font-size:.9em;font-family:"Montserrat","Noto Color Emoji",sans-serif !important;pointer-events:auto;white-space:nowrap;border:1px solid var(--rg-border-primary) !important;border-radius:4px !important;box-shadow:0 2px 5px rgba(0,0,0,.3) !important;min-width:300px;max-width:500px;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin;scrollbar-color:var(--rg-border-hover) var(--rg-bg-primary)}.vocabularies-manager-popup .popup-header{font-weight:600 !important;color:var(--rg-text-primary) !important;margin-bottom:.8em !important;padding-bottom:.5em;border-bottom:1px solid var(--rg-border-primary);font-size:1.1em;position:relative}.vocabularies-manager-popup .popup-actions{display:flex;justify-content:flex-start;align-items:center;margin-bottom:.8em;padding-bottom:.5em;border-bottom:1px solid var(--rg-border-primary);gap:.5em;flex-wrap:wrap}.vocabularies-manager-popup .popup-actions .copy-all-btn,.vocabularies-manager-popup .popup-actions .remove-all-btn,.vocabularies-manager-popup .popup-actions .sort-all-btn,.vocabularies-manager-popup .popup-actions .force-fetch-btn,.vocabularies-manager-popup .popup-actions .save-btn,.vocabularies-manager-popup .popup-actions .revert-btn{background:var(--rg-bg-card);border-radius:3px !important;padding:.4em .8em;font-size:.85em;font-weight:500;cursor:pointer;transition:all .2s ease;font-family:inherit}.vocabularies-manager-popup .popup-actions .copy-all-btn:disabled,.vocabularies-manager-popup .popup-actions .remove-all-btn:disabled,.vocabularies-manager-popup .popup-actions .sort-all-btn:disabled,.vocabularies-manager-popup .popup-actions .force-fetch-btn:disabled,.vocabularies-manager-popup .popup-actions .save-btn:disabled,.vocabularies-manager-popup .popup-actions .revert-btn:disabled{opacity:.5;cursor:not-allowed}.vocabularies-manager-popup .popup-actions .copy-all-btn{color:hsl(var(--rg-popup-btn-copy));border:1px solid hsla(var(--rg-popup-btn-copy)/0.5)}.vocabularies-manager-popup .popup-actions .copy-all-btn:hover{background:hsla(var(--rg-popup-btn-copy)/0.15);border-color:hsl(var(--rg-popup-btn-copy))}.vocabularies-manager-popup .popup-actions .copy-all-btn:active{background:hsla(var(--rg-popup-btn-copy)/0.25)}.vocabularies-manager-popup .popup-actions .remove-all-btn{color:hsl(var(--rg-popup-btn-remove));border:1px solid hsla(var(--rg-popup-btn-remove)/0.5)}.vocabularies-manager-popup .popup-actions .remove-all-btn:hover:not(:disabled){background:hsla(var(--rg-popup-btn-remove)/0.15);border-color:hsl(var(--rg-popup-btn-remove))}.vocabularies-manager-popup .popup-actions .remove-all-btn:active:not(:disabled){background:hsla(var(--rg-popup-btn-remove)/0.25)}.vocabularies-manager-popup .popup-actions .sort-all-btn{color:hsl(var(--rg-popup-btn-sort));border:1px solid hsla(var(--rg-popup-btn-sort)/0.5)}.vocabularies-manager-popup .popup-actions .sort-all-btn:hover:not(:disabled){background:hsla(var(--rg-popup-btn-sort)/0.15);border-color:hsl(var(--rg-popup-btn-sort))}.vocabularies-manager-popup .popup-actions .sort-all-btn:active:not(:disabled){background:hsla(var(--rg-popup-btn-sort)/0.25)}.vocabularies-manager-popup .popup-actions .force-fetch-btn{color:hsl(var(--rg-popup-btn-fetch));border:1px solid hsla(var(--rg-popup-btn-fetch)/0.5)}.vocabularies-manager-popup .popup-actions .force-fetch-btn:hover:not(:disabled){background:hsla(var(--rg-popup-btn-fetch)/0.15);border-color:hsl(var(--rg-popup-btn-fetch))}.vocabularies-manager-popup .popup-actions .force-fetch-btn:active:not(:disabled){background:hsla(var(--rg-popup-btn-fetch)/0.25)}.vocabularies-manager-popup .popup-actions .save-btn{color:hsl(var(--rg-popup-btn-save));border:1px solid hsla(var(--rg-popup-btn-save)/0.5);font-weight:600;box-shadow:0 0 8px hsla(var(--rg-popup-btn-save)/0.3)}.vocabularies-manager-popup .popup-actions .save-btn:hover:not(:disabled){background:hsla(var(--rg-popup-btn-save)/0.15);border-color:hsl(var(--rg-popup-btn-save));box-shadow:0 0 12px hsla(var(--rg-popup-btn-save)/0.5)}.vocabularies-manager-popup .popup-actions .save-btn:active:not(:disabled){background:hsla(var(--rg-popup-btn-save)/0.25);box-shadow:0 0 6px hsla(var(--rg-popup-btn-save)/0.4)}.vocabularies-manager-popup .popup-actions .revert-btn{color:hsl(var(--rg-popup-btn-revert));border:1px solid hsla(var(--rg-popup-btn-revert)/0.5)}.vocabularies-manager-popup .popup-actions .revert-btn:hover:not(:disabled){background:hsla(var(--rg-popup-btn-revert)/0.15);border-color:hsl(var(--rg-popup-btn-revert))}.vocabularies-manager-popup .popup-actions .revert-btn:active:not(:disabled){background:hsla(var(--rg-popup-btn-revert)/0.25)}.vocabularies-manager-popup .popup-search-filters{padding:.5em 0;margin-bottom:.5em;border-bottom:1px solid var(--rg-border-primary);display:flex;flex-direction:column;gap:.6em}.vocabularies-manager-popup .popup-search-filters .search-input{width:100%;background:var(--rg-bg-card);color:var(--rg-text-primary);border:1px solid var(--rg-border-primary);border-radius:3px !important;padding:.5em .7em;font-size:.85em;font-family:inherit;transition:all .2s ease}.vocabularies-manager-popup .popup-search-filters .search-input:focus{outline:none;border-color:var(--rg-border-hover);background:var(--rg-bg-hover)}.vocabularies-manager-popup .popup-search-filters .search-input::placeholder{color:var(--rg-text-tertiary);font-style:italic}.vocabularies-manager-popup .popup-search-filters .filter-buttons{display:flex;gap:.4em;justify-content:flex-start;flex-wrap:wrap}.vocabularies-manager-popup .popup-search-filters .filter-buttons .filter-btn{background:var(--rg-bg-card);color:var(--rg-text-secondary);border:1px solid var(--rg-border-primary);border-radius:3px !important;padding:.35em .7em;font-size:.8em;font-weight:500;cursor:pointer;transition:all .2s ease;font-family:inherit;white-space:nowrap}.vocabularies-manager-popup .popup-search-filters .filter-buttons .filter-btn:hover{background:var(--rg-bg-hover);border-color:var(--rg-border-hover);color:var(--rg-text-primary)}.vocabularies-manager-popup .popup-search-filters .filter-buttons .filter-btn:active{background:var(--rg-bg-secondary);transform:translateY(1px)}.vocabularies-manager-popup .popup-search-filters .filter-buttons .filter-btn.active{background:hsl(var(--rg-popup-btn-save)) !important;color:var(--rg-bg-primary) !important;border-color:hsl(var(--rg-popup-btn-save)) !important;box-shadow:0 1px 3px hsla(var(--rg-popup-btn-save)/0.3)}.vocabularies-manager-popup .popup-search-filters .filter-buttons .filter-btn.active:hover{background:hsla(var(--rg-popup-btn-save)/0.9) !important;border-color:hsl(var(--rg-popup-btn-save)) !important}.vocabularies-manager-popup .popup-search-filters .filter-buttons .filter-btn.active:active{background:hsla(var(--rg-popup-btn-save)/0.8) !important;transform:translateY(1px)}.vocabularies-manager-popup .vocab-list{display:flex;flex-direction:column;gap:.3em;max-height:60vh;overflow-y:auto;overflow-x:hidden}.vocabularies-manager-popup .vocab-list .vocab-labels-container{padding:.5em .7em;margin:.6em 0 .3em 0;background:hsl(var(--rg-popup-item-new));border-radius:2px;position:sticky;top:0;z-index:10;display:flex;justify-content:space-between;align-items:center;gap:1em;font-family:"Montserrat","Noto Color Emoji",sans-serif}.vocabularies-manager-popup .vocab-list .vocab-labels-container .vocab-date,.vocabularies-manager-popup .vocab-list .vocab-labels-container .vocab-count{font-weight:600;font-size:.85em;color:var(--rg-bg-primary)}.vocabularies-manager-popup .vocab-list .vocab-item{display:flex;justify-content:space-between;align-items:center;padding:.4em .6em;background:var(--rg-bg-card);border:1px solid var(--rg-border-primary);border-radius:3px !important;transition:all .2s ease;gap:.8em}.vocabularies-manager-popup .vocab-list .vocab-item:hover{background:var(--rg-bg-hover);border-color:var(--rg-border-hover)}.vocabularies-manager-popup .vocab-list .vocab-item.vocab-item-new{background:hsla(var(--rg-popup-item-new)/0.15) !important;border:1px solid hsla(var(--rg-popup-item-new)/0.6) !important}.vocabularies-manager-popup .vocab-list .vocab-item.vocab-item-new:hover{background:hsla(var(--rg-popup-item-new)/0.25) !important;border-color:hsl(var(--rg-popup-item-new)) !important}.vocabularies-manager-popup .vocab-list .vocab-item .vocab-left{display:inline-flex;align-items:center;flex-shrink:0}.vocabularies-manager-popup .vocab-list .vocab-item .vocab-left .vocab-play-count-badge{display:inline-flex;align-items:center;justify-content:center;margin-left:.5em;padding:4px 8px;background:var(--rg-vocab-badge-bg);color:var(--rg-vocab-badge-text);border-radius:6px;font-size:1em;font-weight:600;font-family:"Montserrat","Courier New",monospace}.vocabularies-manager-popup .vocab-list .vocab-item .vocab-left .vocab-play-btn,.vocabularies-manager-popup .vocab-list .vocab-item .vocab-left .vocab-info-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;margin-right:.5em;padding:0;background:rgba(0,0,0,0);border:none;outline:none;appearance:none;cursor:pointer;border-radius:4px;transition:background .15s ease;color:var(--rg-text-secondary)}.vocabularies-manager-popup .vocab-list .vocab-item .vocab-left .vocab-play-btn svg,.vocabularies-manager-popup .vocab-list .vocab-item .vocab-left .vocab-info-btn svg{width:16px;height:16px}.vocabularies-manager-popup .vocab-list .vocab-item .vocab-left .vocab-play-btn:hover,.vocabularies-manager-popup .vocab-list .vocab-item .vocab-left .vocab-info-btn:hover{background:var(--rg-vocab-play-hover-bg);color:var(--rg-bg-primary)}.vocabularies-manager-popup .vocab-list .vocab-item .vocab-left .vocab-id{color:var(--rg-text-primary);font-weight:500;font-family:"Montserrat","Courier New",monospace;font-size:.9em}.vocabularies-manager-popup .vocab-list .vocab-item .vocab-right{flex:1;min-width:0;text-align:right}.vocabularies-manager-popup .vocab-list .vocab-item .vocab-right .vocab-name{color:var(--rg-text-secondary);font-size:.85em;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.vocabularies-manager-popup .vocab-list .vocab-item .vocab-right .vocab-author,.vocabularies-manager-popup .vocab-list .vocab-item .vocab-right .vocab-type{color:var(--rg-text-tertiary);font-size:.75em;margin-top:.2em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.vocabularies-manager-popup .vocab-list .vocab-item .vocab-right .vocab-loading{color:hsl(var(--rg-popup-btn-fetch));font-size:.8em;font-style:italic}.vocabularies-manager-popup .vocab-list .vocab-item .remove-btn{flex-shrink:0;background:rgba(0,0,0,0);color:hsl(var(--rg-popup-btn-remove));border:1px solid hsla(var(--rg-popup-btn-remove)/0.5);border-radius:3px !important;padding:.2em .5em;font-size:.8em;cursor:pointer;transition:all .2s ease;font-weight:500;font-family:inherit;min-width:60px}.vocabularies-manager-popup .vocab-list .vocab-item .remove-btn:hover{background:hsla(var(--rg-popup-btn-remove)/0.15);color:hsl(var(--rg-popup-btn-remove));border-color:hsl(var(--rg-popup-btn-remove))}.vocabularies-manager-popup .vocab-list .vocab-item .remove-btn:active{background:hsla(var(--rg-popup-btn-remove)/0.25)}.vocabularies-manager-popup .empty-state{text-align:center;color:var(--rg-text-tertiary);font-style:italic;padding:1em 0}.vocabularies-manager-popup::-webkit-scrollbar{width:8px;height:8px}.vocabularies-manager-popup::-webkit-scrollbar-track{background:var(--rg-bg-primary) !important}.vocabularies-manager-popup::-webkit-scrollbar-thumb{background-color:var(--rg-border-hover) !important}.vocabularies-manager-popup::-webkit-scrollbar-thumb:hover{background-color:var(--rg-text-secondary) !important}.vocabularies-manager-popup .vocab-list::-webkit-scrollbar{width:6px}.vocabularies-manager-popup .vocab-list::-webkit-scrollbar-track{background:var(--rg-bg-card) !important}.vocabularies-manager-popup .vocab-list::-webkit-scrollbar-thumb{background-color:var(--rg-border-hover) !important;border-radius:3px}.vocabularies-manager-popup .vocab-list::-webkit-scrollbar-thumb:hover{background-color:var(--rg-text-secondary) !important}:root.latest-games-light-theme{--rg-bg-primary:#fff;--rg-bg-secondary:hsl(0,0%,98%);--rg-bg-card:hsl(0,0%,98%);--rg-bg-card-pinned:hsl(120,50%,96%);--rg-bg-hover:hsl(0,0%,96%);--rg-border-primary:hsl(0,0%,88%);--rg-border-hover:hsl(0,0%,74%);--rg-border-pinned:hsl(122,39%,49%);--rg-text-primary:hsl(0,0%,15%);--rg-text-secondary:#666;--rg-text-tertiary:hsl(0,0%,55%);--rg-text-options:hsl(0,0%,30%);--rg-enabled-yellow:#960;--rg-bg-enabled-yellow:rgba(204,136,0,.2);--rg-enabled-blue:hsl(215,75%,50%);--rg-bg-enabled-blue:hsla(215,75%,50%,.2);--rg-gametype-voc:hsl(215,75%,50%);--rg-gametype-normal:hsl(130,50%,30%);--rg-gametype-abra:hsl(215,20%,40%);--rg-gametype-referats:hsl(80,55%,30%);--rg-gametype-noerror:hsl(200,45%,35%);--rg-gametype-marathon:hsl(340,65%,45%);--rg-gametype-chars:rgb(153,89.25,0);--rg-gametype-digits:hsl(0,0%,50%);--rg-gametype-sprint:hsl(5,40%,40%);--rg-icon-primary:currentColor;--rg-icon-delete:hsl(4,90%,58%);--rg-bg-hover-delete:hsla(4,90%,58%,.2);--rg-icon-pin:hsl(122,39%,49%);--rg-bg-hover-pin:hsla(122,39%,49%,.2);--rg-icon-info:hsl(0,0%,55%);--rg-bg-hover-info:hsla(0,0%,55%,.2);--rg-icon-edit:#c90;--rg-bg-hover-edit:rgba(204,153,0,.2);--rg-icon-theme-sun:hsl(48,100%,41%);--rg-icon-theme-moon:hsl(207,89%,76%);--rg-hover-control:hsl(0,0%,92%);--rg-hover-control-btn:hsl(213,77%,96%);--rg-bg-card-pinned-voc:hsl(215,80%,95%);--rg-border-pinned-voc:hsl(215,80%,80%);--rg-bg-card-pinned-normal:hsl(130,50%,90%);--rg-border-pinned-normal:hsl(130,50%,70%);--rg-bg-card-pinned-abra:hsl(215,20%,90%);--rg-border-pinned-abra:hsl(215,20%,70%);--rg-bg-card-pinned-referats:hsl(80,55%,90%);--rg-border-pinned-referats:hsl(80,55%,70%);--rg-bg-card-pinned-noerror:hsl(200,45%,90%);--rg-border-pinned-noerror:hsl(200,45%,70%);--rg-bg-card-pinned-marathon:hsl(340,65%,90%);--rg-border-pinned-marathon:hsl(340,65%,70%);--rg-bg-card-pinned-chars:hsl(35,100%,90%);--rg-border-pinned-chars:hsl(35,100%,70%);--rg-bg-card-pinned-digits:hsl(0,0%,90%);--rg-border-pinned-digits:hsl(0,0%,70%);--rg-bg-card-pinned-sprint:hsl(5,40%,90%);--rg-border-pinned-sprint:hsl(5,40%,70%);--rg-bg-tab:hsl(0,0%,97%);--rg-bg-tab-hover:hsl(0,0%,94%);--rg-bg-tab-active:#fff;--rg-icon-accent:hsl(215,75%,50%);--rg-qualification-icon:hsl(48,100%,41%);--rg-panel-toggle-background:hsl(215,80%,95%);--rg-panel-toggle-stroke:hsl(215,75%,50%);--rg-panel-toggle-border:hsl(215,80%,80%);--rg-panel-toggle-bg-hover:hsl(215,80%,88%);--rg-header-text:hsl(77,100%,30%);--rg-rank-slider-track-bg:hsl(215,80%,95%);--rg-rank-slider-border:hsl(215,80%,80%);--rg-rank-slider-range:hsl(215,80%,80%);--rg-rank-slider-handle-bg:hsl(215,80%,95%);--rg-rank-slider-border-focus:hsl(215,80%,60%);--rg-popup-btn-copy:215 75% 45%;--rg-popup-btn-remove:4 90% 45%;--rg-popup-btn-sort:130 50% 35%;--rg-popup-btn-fetch:40 100% 35%;--rg-popup-btn-save:195 75% 40%;--rg-popup-btn-revert:30 100% 40%;--rg-popup-item-new:120 30% 50%;--rg-vocab-badge-bg:hsla(195,75%,40%,.9);--rg-vocab-badge-text:hsl(0,0%,95%);--rg-vocab-play-hover-bg:hsl(30,75%,50%)}:root.latest-games-dark-theme{--rg-bg-primary:hsl(210,10%,11%);--rg-bg-secondary:hsl(220,10%,15%);--rg-bg-card:hsl(220,10%,15%);--rg-bg-card-pinned:hsl(140,20%,15%);--rg-bg-hover:hsl(220,10%,15%);--rg-border-primary:hsl(220,10%,15%);--rg-border-hover:hsl(0,0%,38%);--rg-border-pinned:hsl(133,43%,47%);--rg-text-primary:hsl(0,0%,88%);--rg-text-secondary:hsl(0,0%,88%);--rg-text-tertiary:hsl(0,0%,88%);--rg-text-options:hsl(0,0%,88%);--rg-enabled-yellow:#fc0;--rg-bg-enabled-yellow:rgba(255,204,0,.2);--rg-enabled-blue:hsl(207,89%,76%);--rg-bg-enabled-blue:hsla(207,89%,76%,.2);--rg-gametype-voc:hsl(215,80%,65%);--rg-gametype-normal:#6c7;--rg-gametype-abra:hsl(215,20%,60%);--rg-gametype-referats:hsl(80,55%,40%);--rg-gametype-noerror:hsl(200,45%,65%);--rg-gametype-marathon:hsl(340,70%,55%);--rg-gametype-chars:hsl(35,100%,45%);--rg-gametype-digits:hsl(0,0%,50%);--rg-gametype-sprint:hsl(5,40%,60%);--rg-icon-primary:hsl(207,89%,76%);--rg-icon-delete:hsl(4,100%,75%);--rg-bg-hover-delete:hsla(4,100%,75%,.2);--rg-icon-pin:hsl(133,43%,47%);--rg-bg-hover-pin:hsla(133,43%,47%,.2);--rg-icon-info:hsl(0,0%,88%);--rg-bg-hover-info:hsla(0,0%,88%,.2);--rg-icon-edit:#fc3;--rg-bg-hover-edit:rgba(255,204,51,.2);--rg-icon-theme-sun:#fc0;--rg-icon-theme-moon:hsl(207,89%,76%);--rg-hover-control:hsl(0,0%,38%);--rg-hover-control-btn:hsl(213,81.6%,29.8%);--rg-bg-card-pinned-voc:hsl(215,80%,10%);--rg-border-pinned-voc:hsl(215,80%,30%);--rg-bg-card-pinned-normal:hsl(130,50%,10%);--rg-border-pinned-normal:hsl(130,50%,30%);--rg-bg-card-pinned-abra:hsl(215,20%,10%);--rg-border-pinned-abra:hsl(215,20%,30%);--rg-bg-card-pinned-referats:hsl(80,55%,10%);--rg-border-pinned-referats:hsl(80,55%,30%);--rg-bg-card-pinned-noerror:hsl(200,45%,10%);--rg-border-pinned-noerror:hsl(200,45%,30%);--rg-bg-card-pinned-marathon:hsl(340,65%,10%);--rg-border-pinned-marathon:hsl(340,65%,30%);--rg-bg-card-pinned-chars:#320;--rg-border-pinned-chars:#960;--rg-bg-card-pinned-digits:hsl(0,0%,10%);--rg-border-pinned-digits:hsl(0,0%,30%);--rg-bg-card-pinned-sprint:hsl(5,40%,10%);--rg-border-pinned-sprint:hsl(5,40%,30%);--rg-bg-tab:hsl(220,10%,15%);--rg-bg-tab-hover:hsl(220,10%,18%);--rg-bg-tab-active:hsl(210,10%,11%);--rg-icon-accent:hsl(207,89%,76%);--rg-qualification-icon:#fc0;--rg-panel-toggle-background:hsl(215,80%,20%);--rg-panel-toggle-stroke:hsl(215,80%,65%);--rg-panel-toggle-border:hsl(215,80%,30%);--rg-panel-toggle-bg-hover:hsl(215,80%,25%);--rg-header-text:#fc0;--rg-rank-slider-track-bg:hsl(215,80%,10%);--rg-rank-slider-border:hsl(215,80%,30%);--rg-rank-slider-range:hsl(215,80%,30%);--rg-rank-slider-handle-bg:hsl(215,80%,10%);--rg-rank-slider-border-focus:hsl(215,80%,50%);--rg-popup-btn-copy:195 53% 79%;--rg-popup-btn-remove:0 90% 75%;--rg-popup-btn-sort:120 90% 70%;--rg-popup-btn-fetch:40 100% 70%;--rg-popup-btn-save:195 100% 70%;--rg-popup-btn-revert:30 100% 70%;--rg-popup-item-new:120 40% 40%;--rg-vocab-badge-bg:hsla(195,100%,70%,.9);--rg-vocab-badge-text:hsl(0,0%,11%);--rg-vocab-play-hover-bg:hsl(30,100%,70%)}#latest-games-container{display:flex;flex-direction:column;font-family:"Montserrat",sans-serif;position:fixed;top:50px;width:auto;min-width:200px;max-width:330px;background-color:var(--rg-bg-primary);border:1px solid var(--rg-border-primary);border-left:none;border-radius:0 8px 8px 0 !important;box-shadow:2px 0 10px rgba(0,0,0,.1) !important;z-index:1020;padding:10px 0;opacity:0;pointer-events:none;user-select:none;transition:left .3s ease,opacity .3s ease;overflow:hidden;color:var(--rg-text-primary)}#latest-games-container #latest-games-content{overflow-y:auto;overflow-x:hidden;scrollbar-width:none;height:calc(100% - 40px);width:100%}#latest-games-container.visible{left:0 !important;opacity:1;pointer-events:auto;user-select:auto}#latest-games-container.display-mode-wrap{max-width:none;width:95vw;display:flex;flex-direction:row;flex-wrap:wrap;align-items:flex-start;position:fixed}#latest-games-container.display-mode-wrap .latest-games-controls{flex-direction:row}#latest-games-container #latest-games{margin:0;position:relative;padding:0;list-style:none;display:flex;flex-direction:column;gap:5px}#latest-games-container #latest-games .group-header{display:inline-flex;padding:5px 15px;min-height:30px;max-width:300px;font:600 14px "Montserrat",sans-serif;border-radius:4px !important;background:var(--rg-bg-card);color:var(--rg-text-primary);border:2px solid var(--rg-border-primary);cursor:pointer;user-select:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;height:fit-content;transition:border .1s ease,background-color .1s ease;width:100%;margin:0 10px}#latest-games-container #latest-games .group-header:hover,#latest-games-container #latest-games .group-header:focus{border-color:var(--rg-border-hover);background:var(--rg-bg-hover);color:var(--rg-text-primary)}#latest-games-container #latest-games .group-header.active{color:var(--rg-gametype-normal) !important;background-color:var(--rg-bg-card-pinned-normal) !important;border:2px solid var(--rg-border-pinned-normal) !important}#latest-games-container #latest-games .group-header.warning{color:var(--rg-gametype-chars) !important;background-color:var(--rg-bg-card-pinned-chars) !important;border:2px solid var(--rg-border-pinned-chars) !important}#latest-games-container #latest-games .group-header.danger{color:var(--rg-gametype-marathon) !important;background-color:var(--rg-bg-card-pinned-marathon) !important;border:2px solid var(--rg-border-pinned-marathon) !important}#latest-games-container #latest-games.display-mode-wrap{display:flex;flex-direction:row;flex-wrap:wrap;max-height:none;margin:0 10px}#latest-games-container #latest-games.display-mode-wrap .latest-game,#latest-games-container #latest-games.display-mode-wrap .group-header{margin:0 !important;max-width:none}#latest-games-container #latest-games .latest-game{position:relative;margin:0 10px;border:2px solid var(--rg-border-primary);border-radius:4px !important;background-color:var(--rg-bg-card);transition:border .1s ease,background-color .1s ease;display:inline-flex;max-width:300px}#latest-games-container #latest-games .latest-game.pin-game{cursor:move}#latest-games-container #latest-games .latest-game.pin-game.pin-gametype-voc{border:2px solid var(--rg-border-pinned-voc);background-color:var(--rg-bg-card-pinned-voc)}#latest-games-container #latest-games .latest-game.pin-game.pin-gametype-normal{border:2px solid var(--rg-border-pinned-normal);background-color:var(--rg-bg-card-pinned-normal)}#latest-games-container #latest-games .latest-game.pin-game.pin-gametype-abra{border:2px solid var(--rg-border-pinned-abra);background-color:var(--rg-bg-card-pinned-abra)}#latest-games-container #latest-games .latest-game.pin-game.pin-gametype-referats{border:2px solid var(--rg-border-pinned-referats);background-color:var(--rg-bg-card-pinned-referats)}#latest-games-container #latest-games .latest-game.pin-game.pin-gametype-noerror{border:2px solid var(--rg-border-pinned-noerror);background-color:var(--rg-bg-card-pinned-noerror)}#latest-games-container #latest-games .latest-game.pin-game.pin-gametype-marathon{border:2px solid var(--rg-border-pinned-marathon);background-color:var(--rg-bg-card-pinned-marathon)}#latest-games-container #latest-games .latest-game.pin-game.pin-gametype-chars{border:2px solid var(--rg-border-pinned-chars);background-color:var(--rg-bg-card-pinned-chars)}#latest-games-container #latest-games .latest-game.pin-game.pin-gametype-digits{border:2px solid var(--rg-border-pinned-digits);background-color:var(--rg-bg-card-pinned-digits)}#latest-games-container #latest-games .latest-game.pin-game.pin-gametype-sprint{border:2px solid var(--rg-border-pinned-sprint);background-color:var(--rg-bg-card-pinned-sprint)}#latest-games-container #latest-games .latest-game:hover{border-color:var(--rg-border-hover);background-color:var(--rg-bg-hover)}#latest-games-container #latest-games .latest-game.dragging{opacity:.7;z-index:1021;transition:transform .1s ease}#latest-games-container #latest-games .latest-game.display-mode-wrap{margin:0}#latest-games-container #latest-games .latest-game a{display:block;width:100%;padding:5px 15px;text-decoration:none;color:inherit}#latest-games-container #latest-games .latest-game .latest-game-name{display:flex;font-weight:bold;font-size:12px;margin-bottom:2px;align-items:center}#latest-games-container #latest-games .latest-game .latest-game-name.gametype-voc{color:var(--rg-gametype-voc) !important}#latest-games-container #latest-games .latest-game .latest-game-name.gametype-normal{color:var(--rg-gametype-normal) !important}#latest-games-container #latest-games .latest-game .latest-game-name.gametype-abra{color:var(--rg-gametype-abra) !important}#latest-games-container #latest-games .latest-game .latest-game-name.gametype-referats{color:var(--rg-gametype-referats) !important}#latest-games-container #latest-games .latest-game .latest-game-name.gametype-noerror{color:var(--rg-gametype-noerror) !important}#latest-games-container #latest-games .latest-game .latest-game-name.gametype-marathon{color:var(--rg-gametype-marathon) !important}#latest-games-container #latest-games .latest-game .latest-game-name.gametype-chars{color:var(--rg-gametype-chars) !important}#latest-games-container #latest-games .latest-game .latest-game-name.gametype-digits{color:var(--rg-gametype-digits) !important}#latest-games-container #latest-games .latest-game .latest-game-name.gametype-sprint{color:var(--rg-gametype-sprint) !important}#latest-games-container #latest-games .latest-game .latest-game-description{display:inline-flex;font-size:10px;color:var(--rg-text-secondary)}#latest-games-container #latest-games .latest-game .latest-game-qual,#latest-games-container #latest-games .latest-game .latest-game-state-icon{display:inline-flex;align-items:center;justify-content:center;margin-left:4px}#latest-games-container #latest-games .latest-game .latest-game-qual svg,#latest-games-container #latest-games .latest-game .latest-game-state-icon svg{width:14px;height:14px}#latest-games-container #latest-games .latest-game .latest-game-levels{display:block;font-size:9px;color:var(--rg-text-tertiary);margin-top:1px}#latest-games-container #latest-games .latest-game .latest-game-buttons{position:absolute;display:flex;flex-direction:row;justify-content:center;align-items:center;gap:2px;top:0;right:0;transform:translateY(-100%);background-color:var(--rg-bg-card);border-radius:4px !important;border:2px solid var(--rg-border-primary);box-shadow:0 1px 4px rgba(0,0,0,.2) !important;visibility:hidden}#latest-games-container #latest-games .latest-game:hover .latest-game-buttons{opacity:1}#latest-games-container #latest-games .latest-game .latest-game-pin{width:24px;height:24px;cursor:pointer;border-radius:2px !important;display:flex;align-items:center;justify-content:center;transition:background-color .2s ease;background-color:rgba(0,0,0,0)}#latest-games-container #latest-games .latest-game .latest-game-pin:hover{background-color:var(--rg-bg-hover-pin)}#latest-games-container #latest-games .latest-game .latest-game-pin svg{width:16px;height:16px;stroke:var(--rg-icon-pin);fill:none}#latest-games-container #latest-games .latest-game .latest-game-delete{width:24px;height:24px;cursor:pointer;border-radius:2px !important;display:flex;align-items:center;justify-content:center;transition:background-color .2s ease;background-color:rgba(0,0,0,0)}#latest-games-container #latest-games .latest-game .latest-game-delete:hover{background-color:var(--rg-bg-hover-delete)}#latest-games-container #latest-games .latest-game .latest-game-delete svg{width:16px;height:16px;stroke:var(--rg-icon-delete);fill:none}#latest-games-container #latest-games .latest-game .latest-game-info{width:24px;height:24px;cursor:pointer;border-radius:2px !important;display:flex;align-items:center;justify-content:center;transition:background-color .2s ease;background-color:rgba(0,0,0,0)}#latest-games-container #latest-games .latest-game .latest-game-info:hover{background-color:var(--rg-bg-hover-info)}#latest-games-container #latest-games .latest-game .latest-game-info svg{width:16px;height:16px;stroke:var(--rg-icon-info);fill:none}#latest-games-container #latest-games .latest-game .latest-game-edit{width:24px;height:24px;cursor:pointer;border-radius:2px !important;display:flex;align-items:center;justify-content:center;transition:background-color .2s ease;background-color:rgba(0,0,0,0)}#latest-games-container #latest-games .latest-game .latest-game-edit:hover{background-color:var(--rg-bg-hover-edit)}#latest-games-container #latest-games .latest-game .latest-game-edit svg{width:16px;height:16px;stroke:var(--rg-icon-edit);fill:none}#latest-games-container #latest-games .latest-game.previous-game,#latest-games-container #latest-games .latest-game.dragged-game{animation:tilt-n-move-shaking .3s ease 5}#latest-games-container .latest-games-controls{display:flex;flex-direction:column;align-items:flex-start;padding:0 10px 10px;top:0;position:sticky;width:100%;z-index:10;background-color:var(--rg-bg-primary);border-bottom:1px solid var(--rg-border-primary)}#latest-games-container .latest-games-controls .controls-buttons{gap:2px;display:flex;flex-wrap:wrap;position:relative}#latest-games-container .latest-games-controls .controls-buttons .controls-visible{display:flex;gap:6px;align-items:center;flex-basis:100%}#latest-games-container .latest-games-controls .controls-buttons .controls-limiter{width:100%;display:flex;justify-content:center;gap:8px;align-items:center;padding-bottom:6px;border-bottom:1px solid var(--rg-border-primary)}#latest-games-container .latest-games-controls .controls-buttons .controls-more{display:none;position:absolute;left:0;top:100%;margin-top:6px;background:var(--rg-bg-card);padding:8px;border-radius:8px !important;border:1px solid var(--rg-border-primary);box-shadow:0 6px 18px rgba(0,0,0,.15);flex-wrap:wrap;gap:6px;z-index:2000;min-width:400px}#latest-games-container .latest-games-controls .controls-buttons .controls-more.open{display:flex}#latest-games-container .latest-games-controls .controls-buttons .latest-games-more-toggle{width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:4px !important;background:rgba(0,0,0,0)}#latest-games-container .latest-games-controls .controls-buttons .latest-games-more-toggle.open{color:var(--rg-enabled-yellow)}#latest-games-container .latest-games-controls .controls-buttons .latest-games-replay.replay-next-game,#latest-games-container .latest-games-controls .controls-buttons .latest-games-random.random-global{background-color:var(--rg-bg-enabled-yellow)}#latest-games-container .latest-games-controls .controls-buttons .latest-games-replay.replay-next-game svg,#latest-games-container .latest-games-controls .controls-buttons .latest-games-random.random-global svg{stroke:var(--rg-enabled-yellow)}#latest-games-container #latest-games-options{display:flex;align-items:center;font-size:13px;gap:5px;color:var(--rg-text-options);user-select:none}#latest-games-container #latest-games-count{margin:0 6px;font-weight:bold;font-size:14px;min-width:18px;text-align:center;color:var(--rg-enabled-yellow);cursor:pointer}#latest-games-container #latest-games-count-inc,#latest-games-container #latest-games-count-dec{height:24px;width:24px;cursor:pointer;font-size:16px;border-radius:3px !important;transition:background .15s;user-select:none;display:flex;align-items:center;justify-content:center;color:var(--rg-icon-primary)}#latest-games-container #latest-games-count-inc:hover,#latest-games-container #latest-games-count-dec:hover{background:var(--rg-hover-control-btn)}#latest-games-container #latest-games-count-inc svg,#latest-games-container #latest-games-count-dec svg{width:16px;height:16px}#latest-games-container .theme-toggle,#latest-games-container .display-mode-toggle,#latest-games-container .control-button{cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:3px !important;width:24px;height:24px;background-color:rgba(0,0,0,0);border-radius:4px;transition:background .15s;user-select:none}#latest-games-container .theme-toggle svg,#latest-games-container .display-mode-toggle svg,#latest-games-container .control-button svg{width:16px;height:16px;display:block;transition:stroke .2s,fill .2s}#latest-games-container .theme-toggle svg.feather-sun,#latest-games-container .display-mode-toggle svg.feather-sun,#latest-games-container .control-button svg.feather-sun{stroke:var(--rg-icon-theme-sun);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}#latest-games-container .theme-toggle svg.feather-moon,#latest-games-container .display-mode-toggle svg.feather-moon,#latest-games-container .control-button svg.feather-moon{stroke:var(--rg-icon-theme-moon);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}#latest-games-container .control-button{box-sizing:border-box}#latest-games-container .control-button svg{pointer-events:none}#latest-games-container #latest-games-groups{display:flex;flex-direction:column;align-items:start;margin-bottom:0}#latest-games-container #latest-games-groups .tabs-container{display:inline-flex;flex-direction:row;gap:5px;flex-wrap:wrap;align-items:center;margin:0 10px 10px}#latest-games-container #latest-games-groups .group-tab{display:inline-flex;padding:5px 15px;min-height:30px;max-width:300px;font:600 14px "Montserrat",sans-serif;border-radius:4px !important;background:var(--rg-bg-card);color:var(--rg-text-primary);border:2px solid var(--rg-border-primary);cursor:pointer;user-select:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;height:fit-content;transition:border .1s ease,background-color .1s ease}#latest-games-container #latest-games-groups .group-tab:hover,#latest-games-container #latest-games-groups .group-tab:focus{border-color:var(--rg-border-hover);background:var(--rg-bg-hover);color:var(--rg-text-primary)}#latest-games-container #latest-games-groups .group-tab.active{color:var(--rg-gametype-normal) !important;background-color:var(--rg-bg-card-pinned-normal) !important;border:2px solid var(--rg-border-pinned-normal) !important}#latest-games-container #latest-games-groups .group-tab.warning{color:var(--rg-gametype-chars) !important;background-color:var(--rg-bg-card-pinned-chars) !important;border:2px solid var(--rg-border-pinned-chars) !important}#latest-games-container #latest-games-groups .group-tab.danger{color:var(--rg-gametype-marathon) !important;background-color:var(--rg-bg-card-pinned-marathon) !important;border:2px solid var(--rg-border-pinned-marathon) !important}#latest-games-container #latest-games-groups .group-controls{gap:2px;display:inline-flex;align-items:center;padding:10px}#latest-games-container .group-tab.previous-game-group,#latest-games-container .group-header.previous-game-group{color:var(--rg-gametype-chars) !important;background-color:var(--rg-bg-card-pinned-chars) !important;border:2px solid var(--rg-border-pinned-chars) !important}#latest-games-container .resize-handle-horizontal{position:absolute;top:0;bottom:0;right:0;width:4px;height:100%;cursor:ew-resize;background:rgba(0,0,0,0);z-index:1021;border-radius:4px 0 0 4px;transition:background .2s}#latest-games-container .resize-handle-horizontal:hover{background-color:rgba(0,0,0,.18)}#latest-games-container .resize-handle-vertical{position:absolute;left:0;right:0;width:100%;height:4px;cursor:ns-resize;background-color:rgba(0,0,0,0);z-index:1021;border-radius:0 0 4px 4px;transition:background .2s}#latest-games-container .resize-handle-vertical:hover{background-color:rgba(0,0,0,.18)}#latest-games-container .resize-handle-vertical-top{top:0}#latest-games-container .resize-handle-vertical-bottom{bottom:0}#latest-games-container #latest-games.display-mode-wrap .drop-indicator{border-left:2px solid var(--rg-gametype-voc)}#latest-games-hover-area{position:fixed;left:0;top:0;width:4px;height:100vh;z-index:1023;background-color:rgba(0,0,0,0);pointer-events:auto}.latest-games-panel-toggle{position:fixed;left:0;top:50%;transform:translateY(-50%);z-index:1024;background:var(--rg-panel-toggle-background);border:2px solid var(--rg-panel-toggle-border);border-radius:0 .5em .5em 0 !important;box-shadow:0 2px 8px rgba(0,0,0,.15) !important;width:40px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer;transition:background .2s;outline:none}.latest-games-panel-toggle:hover,.latest-games-panel-toggle:focus{background:var(--rg-panel-toggle-bg-hover)}.latest-games-panel-toggle svg{stroke:var(--rg-panel-toggle-stroke);width:1.5em;height:1.5em;display:block;pointer-events:none}.custom-tooltip-popup{position:fixed;background:#161616;color:#dedede;padding:.5em;z-index:2010 !important;font-size:.9em;font-family:"Montserrat","Noto Color Emoji",sans-serif !important;pointer-events:none;white-space:nowrap;opacity:0;transition:opacity .1s;display:none;flex-direction:column;left:0;top:0;border:1px solid #3c3c3c !important;border-radius:4px !important;box-shadow:0 2px 5px rgba(0,0,0,.3) !important}.custom-tooltip-popup .tooltip-item{display:inline-flex !important;align-items:center !important}.custom-tooltip-popup .tooltip-header{font-weight:500 !important;color:gray !important;margin:.5em !important}.custom-tooltip-popup .tooltip-action{font-weight:500 !important;color:#add8e6 !important}.latest-games-disabled{background-color:rgba(0,0,0,0) !important;filter:grayscale(1);opacity:.5}.latest-games-hidden{display:none !important}@keyframes tilt-n-move-shaking{0%{transform:translate(0, 0) rotate(0deg)}25%{transform:translate(4px, 0) rotate(2deg)}50%{transform:translate(0, 0) rotate(0eg)}75%{transform:translate(-4px, 0) rotate(-2deg)}100%{transform:translate(0, 0) rotate(0deg)}}',""]);const i=s}},t={};function a(r){var n=t[r];if(void 0!==n)return n.exports;var o=t[r]={id:r,exports:{}};return e[r](o,o.exports,a),o.exports}a.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return a.d(t,{a:t}),t},a.d=(e,t)=>{for(var r in t)a.o(t,r)&&!a.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},a.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a.nc=void 0;var r=a(72),n=a.n(r),o=a(825),s=a.n(o),i=a(659),l=a.n(i),c=a(56),p=a.n(c),g=a(540),d=a.n(g),u=a(113),m=a.n(u),h=a(911),v={};v.styleTagTransform=m(),v.setAttributes=p(),v.insert=l().bind(null,"head"),v.domAPI=s(),v.insertStyleElement=d();n()(h.A,v);h.A&&h.A.locals&&h.A.locals;const b={montserrat:{id:"kg-latest-games-montserrat-font",url:"https://fonts.googleapis.com/css2?family=Montserrat&display=swap"},notoColorEmoji:{id:"kg-latest-games-noto-emoji-font",url:"https://fonts.googleapis.com/css2?family=Montserrat&family=Noto+Color+Emoji&display=swap"}};const y="☀️",f="📅",x="📋",w="📜",k="💬",M="⚡",C={normal:"Oбычный",abra:"Абракадабра",referats:"Яндекс.Рефераты",noerror:"Безошибочный",marathon:"Марафон",chars:"Буквы",digits:"Цифры",sprint:"Спринт",voc:"Словарь"},S={words:"Слова",phrases:"Фразы",texts:"Тексты",book:"Книги"},E={Слова:"words",Фразы:"phrases",Тексты:"texts",Книга:"books",Генератор:"generator"},G={normal:"открытый",practice:"одиночный",private:"дружеский"},L=["новички","любители","таксисты","профи","гонщики","маньяки","супермены","кибергонщики","экстракиберы"],T={новичков:1,любителей:2,таксистов:3,профи:4,гонщиков:5,маньяков:6,суперменов:7,кибергонщиков:8,экстракиберов:9},I=[5,10,20,30,45,60],D={maxGameCount:5,currentTheme:"light",displayMode:"scroll",previousScrollPosition:0,panelWidth:"70vw",panelHeight:"40vh",panelWidths:{},panelHeights:{},hoverTimeout:null,isHovered:!1,enableDragging:!0,wasDragging:!1,shouldAutoSave:!0,hidePanelDelay:1e3,shouldStart:!1,startDelay:1e3,shouldReplay:!1,replayDelay:1e3,replayNextGame:!1,shouldReplayMore:!1,replayNextGameCount:1,remainingReplayCount:null,replayWithoutWaiting:!1,randomGameId:!1,randomVocabulariesType:{words:!0,phrases:!0,texts:!0,books:!0,generator:!0},showSearchBox:!1,showButtonDescriptions:!0,showHelpTooltips:!0,showBlockedVocabAlert:!0,qualificationEnabled:!1,showVocabularyData:!0,rankRange:[0,8],panelYPosition:{main:0,gamelist:0,profile:0,chatlogs:0,rating:0,vocabularies:0,about:0,donation:0,forum:0,game:0},alwaysVisiblePanel:{main:!0,gamelist:!1,profile:!1,chatlogs:!1,rating:!1,vocabularies:!1,about:!1,donation:!1,forum:!1,game:!0}},N="http://www.w3.org/2000/svg",$={sun:`\n \n \n \n \n \n \n \n \n \n \n \n `,moon:`\n \n \n \n `,delete:`\n \n \n \n \n `,decrease:`\n \n \n \n `,increase:`\n \n \n \n `,play:`\n \n \n \n `,replay:`\n \n \n \n \n `,replayImmediately:`\n \n \n \n \n \n `,replayMore:`\n \n \n \n \n `,pin:`\n \n \n \n \n `,unpin:`\n \n \n \n \n `,sort:`\n \n \n \n \n \n `,import:`\n \n \n \n \n \n `,export:`\n \n \n \n \n \n `,trashNothing:`\n \n \n \n \n `,trashSomething:`\n \n \n \n \n \n \n `,wrap:`\n \n \n \n \n \n \n `,scroll:`\n \n \n \n \n \n `,addGroup:`\n \n \n \n \n `,renameGroup:`\n \n \n \n `,qualification:`\n \n \n \n \n `,panelToggleClosed:`\n \n \n \n \n `,panelToggleOpened:`\n \n \n \n \n `,moreHorizontal:`\n \n \n \n \n \n `,broom:`\n \n \n \n \n \n `,checkmark:`\n \n \n \n `,dragToggle:`\n \n \n \n \n \n \n \n \n `,search:`\n \n \n \n \n `,info:`\n \n \n \n \n \n `,help:`\n \n \n \n \n \n `,parameters:`\n \n \n \n \n \n \n \n \n \n \n \n `,refresh:`\n \n \n \n \n \n `,reset:`\n \n \n \n \n \n `,paused:`\n \n \n \n \n `,playing:`\n \n \n \n `,random:`\n \n \n \n \n \n \n \n `,start:`\n \n \n \n \n `,slash:`\n \n \n \n \n `,book:`\n \n \n \n \n `,vocabularyData:`\n \n \n \n \n \n \n \n `};let A=null,V=null,H=null,B=!1,j=!1,q=null,O=null;const P=e=>{if("info"===e){return!0===(()=>{if(null===O)try{const e=localStorage.getItem("latestGamesSettings");O=e?JSON.parse(e):{}}catch(e){console.warn("Failed to parse latestGamesSettings from localStorage:",e),O={}}return O})().showHelpTooltips}return!0},z=(e,t)=>{if(!A)return;let a=e+10;const r=A.offsetWidth,n=window.innerWidth;a=Math.min(Math.max(a,10),n-r-10),A.style.left=`${a}px`,A.style.top=`${t+18}px`},R=e=>A&&z(e.clientX,e.clientY);function _(){B=!1,q=null,clearTimeout(H),clearTimeout(V),V=setTimeout((()=>{A&&(A.style.opacity="0",j=!1,setTimeout((()=>{!B&&A&&(A.style.display="none",A.textContent="",document.removeEventListener("mousemove",R))}),50))}),100)}function W(e,t,a="info"){null!=t&&P(a)&&(e._tooltipContent=t,e._tooltipType=a,e._tooltipInitialized||(e._tooltipInitialized=!0,A||=(()=>{const e=document.createElement("div");return e.classList.add("custom-tooltip-popup"),e.style.display="none",e.style.opacity="0",document.body.appendChild(e),e})(),e.addEventListener("mouseenter",(t=>{P(e._tooltipType||"info")&&(B=!0,q=e,clearTimeout(V),clearTimeout(H),A.innerHTML=K(e._tooltipContent),A.style.display="flex",A.style.opacity="0",A.offsetHeight,z(t.clientX,t.clientY),document.addEventListener("mousemove",R),H=setTimeout((()=>{A.style.opacity="1",j=!0}),600))})),e.addEventListener("mouseleave",(()=>{_(),document.removeEventListener("mousemove",R)})),e.addEventListener("click",_)))}function Y(e,t,a="info"){if(e._tooltipInitialized){if(P(a)&&(e._tooltipContent=t,e._tooltipType=a,q===e&&B&&A)){A.innerHTML=K(t),j||(clearTimeout(H),A.style.opacity="1",j=!0);const a=e.getBoundingClientRect();z(a.left+a.width/2,a.bottom)}}else W(e,t,a)}function K(e){let t="";const a=/\[([^\]]+)\]([^\[]*)/g;return e.split(/(## [^[]*)/g).forEach((e=>{if(e.startsWith("## ")){const a=e.slice(3).trim();t+=`
${a}
`}else{a.lastIndex=0;const r=[...e.matchAll(a)];r.length?r.forEach((e=>{const a=e[1],r=e[2].trim();t+=`\n
\n ${a} \n ${r}\n
`})):e.trim()&&(t+=`\n
\n ${e.trim()}\n
`)}})),t}function U(e){const t=new Set([...e.map((e=>e.id)),...e.flatMap((e=>e.games.map((e=>e.id))))]);let a;do{a=Array.from(crypto.getRandomValues(new Uint8Array(32))).map((e=>(e%36).toString(36))).join("")}while(t.has(a));return a}function F(e){let t;const a=new Promise((a=>{t=setTimeout(a,e)}));return a.cancel=()=>{t&&(clearTimeout(t),t=null)},a}function J(){const e=window.location.pathname;return"/"===e?"main":"/gamelist/"===e?"gamelist":"/u/"===e?"profile":e.startsWith("/chatlogs/")?"chatlogs":e.startsWith("/top/")?"rating":e.startsWith("/vocs/")?"vocabularies":"/about/"===e?"about":"/fuel/"===e?"donation":e.startsWith("/forum/")?"forum":"/g/"===e?"game":"unknown"}function X(e,t={}){const a=document.createElement(e);return t.className&&(a.className=t.className),t.id&&(a.id=t.id),t.innerHTML&&(a.innerHTML=t.innerHTML),t.textContent&&(a.textContent=t.textContent),t.href&&(a.href=t.href),t.title&&(a.title=t.title),t.src&&(a.src=t.src),t.style&&Object.assign(a.style,t.style),t.attributes&&Object.entries(t.attributes).forEach((([e,t])=>{a.setAttribute(e,t)})),a}function Z(){const e=J();return"vocabularies"===e?".columns.voclist":"profile"===e?".profile-root, .dlg-profile-vocs .vocs":"forum"===e?"#posts-list .list":"gamelist"===e?"#gamelist":"game"===e?"#gamedesc":null}function Q(e){const t=e.getAttribute("href");if(/\/create\//.test(t)){const e=t.match(/[?&]voc=(\d+)/);return e?e[1]:null}try{const e=new URL(t,window.location.origin),a=e.pathname.match(/^\/vocs\/(\d+)\/?$/);return a?a[1]:null}catch(e){return null}}function ee(){const e=document.querySelector("#gamedesc");if(!e)return{category:"default",subtype:"Unknown"};const t=e.textContent.toLowerCase(),a=e.querySelector("span");if(!a)return{category:"default",subtype:"Unknown"};const r=a.className.match(/gametype-(\w+)/),n=r?r[1]:null,o=n&&C[n]||"Unknown";if(t.includes("соревнование"))return{category:"competition",subtype:o};if(t.includes("квалификация"))return{category:"qualification",subtype:o};if("voc"===n){if(e.querySelector('a[href*="/vocs/"]'))return{category:"vocabulary",subtype:o}}return{category:"default",subtype:o}}new MutationObserver((()=>{q&&!document.contains(q)&&_()})).observe(document,{childList:!0,subtree:!0});class te{constructor(e){this.main=e}applyTheme(){document.documentElement.classList.remove("latest-games-light-theme","latest-games-dark-theme"),document.documentElement.classList.add("light"===this.main.currentTheme?"latest-games-light-theme":"latest-games-dark-theme"),this.updateThemeIcon()}updateThemeIcon(){const e=document.querySelector("#latest-games-container .theme-toggle");e&&(e.innerHTML="light"===this.main.currentTheme?$.sun:$.moon)}toggleTheme(e){this.main.currentTheme="light"===this.main.currentTheme?"dark":"light",W(e,"Изменить тему на "+("light"===this.main.currentTheme?"тёмную":"светлую")),this.main.settingsManager.saveSettings(),this.applyTheme()}createThemeToggle(){const e=X("div",{className:"theme-toggle control-button"});return e.innerHTML="light"===this.main.currentTheme?$.sun:$.moon,e.addEventListener("click",(()=>this.toggleTheme(e))),W(e,"Изменить тему на "+("light"===this.main.currentTheme?"тёмную":"светлую")),e}}class ae{constructor(e){this.main=e}loadSettings(){try{const e=JSON.parse(localStorage.getItem("latestGamesSettings")||"{}");this.main.maxGameCount=e.maxGameCount??this.main.maxGameCount,this.main.currentTheme=e.currentTheme??this.main.currentTheme,this.main.displayMode=e.displayMode??this.main.displayMode,this.main.groupsManager.groupViewMode=e.groupViewMode??this.main.groupsManager.groupViewMode,this.main.previousScrollPosition=e.previousScrollPosition??this.main.previousScrollPosition,this.main.enableDragging=e.enableDragging??this.main.enableDragging,this.main.shouldAutoSave=e.shouldAutoSave??this.main.shouldAutoSave,this.main.hidePanelDelay=e.hidePanelDelay??this.main.hidePanelDelay,this.main.shouldStart=e.shouldStart??this.main.shouldStart,this.main.startDelay=e.startDelay??this.main.startDelay,this.main.shouldReplay=e.shouldReplay??this.main.shouldReplay,this.main.replayDelay=e.replayDelay??this.main.replayDelay,this.main.replayNextGame=e.replayNextGame??this.main.replayNextGame,this.main.shouldReplayMore=e.shouldReplayMore??this.main.shouldReplayMore,this.main.replayNextGameCount=e.replayNextGameCount??this.main.replayNextGameCount,this.main.remainingReplayCount=null!=e.remainingReplayCount?e.remainingReplayCount:this.main.replayNextGameCount,this.main.replayWithoutWaiting=e.replayWithoutWaiting??this.main.replayWithoutWaiting,this.main.showSearchBox=e.showSearchBox??this.main.showSearchBox,this.main.showButtonDescriptions=e.showButtonDescriptions??this.main.showButtonDescriptions,this.main.showHelpTooltips=e.showHelpTooltips??this.main.showHelpTooltips,this.main.randomGameId=e.randomGameId??this.main.randomGameId,this.main.showBlockedVocabAlert=e.showBlockedVocabAlert??this.main.showBlockedVocabAlert,this.main.qualificationEnabled=e.qualificationEnabled??this.main.qualificationEnabled,this.main.rankRange=e.rankRange??this.main.rankRange,this.main.showVocabularyData=e.showVocabularyData??this.main.showVocabularyData,this.loadValidVocabularies(),e.randomVocabulariesType&&"object"==typeof e.randomVocabulariesType&&(this.main.randomVocabulariesType={...this.main.randomVocabulariesType,...e.randomVocabulariesType}),e.panelYPosition&&"object"==typeof e.panelYPosition&&(this.main.panelYPosition={...this.main.panelYPosition,...e.panelYPosition}),e.panelWidths&&"object"==typeof e.panelWidths&&(this.main.panelWidths={...this.main.panelWidths,...e.panelWidths}),e.panelHeights&&"object"==typeof e.panelHeights&&(this.main.panelHeights={...this.main.panelHeights,...e.panelHeights}),e.alwaysVisiblePanel&&"object"==typeof e.alwaysVisiblePanel&&(this.main.alwaysVisiblePanel={...this.main.alwaysVisiblePanel,...e.alwaysVisiblePanel})}catch(e){console.warn("Could not load settings from localStorage:",e)}}loadValidVocabularies(){try{const e=localStorage.getItem("validVocabularies");if(e){const t=JSON.parse(e);if(!t||"object"!=typeof t||Array.isArray(t))return void(this.main.validVocabularies={});const a={};for(const[e,r]of Object.entries(t))Array.isArray(r)&&(a[e]=this._normalizeVocabList(r));try{const e=localStorage.getItem("bannedVocabularies"),t=localStorage.getItem("playedVocabularies"),r=e?JSON.parse(e):[],n=t?JSON.parse(t):[];if(Array.isArray(r)||Array.isArray(n)){const e=Array.isArray(r)?r.map((e=>"string"==typeof e?e:"object"==typeof e&&null!==e&&e.id||String(e))):[],t=Array.isArray(n)?n.map((e=>"string"==typeof e?e:"object"==typeof e&&null!==e&&e.id||String(e))):[],o=new Set(e.map((e=>String(e)))),s=new Set(t.map((e=>String(e)))),i=new Set([...o,...s]),l={};for(const[e,t]of Object.entries(a))l[e]=t.filter((e=>!i.has(String(e))));const c=Object.values(l).flat().length,p=Object.values(a).flat().length;if(0===c&&p>0){if(confirm("Все доступные словари уже были проиграны. Очистить данные о проигранных словарях и начать заново?")){localStorage.removeItem("playedVocabularies");const e={};for(const[t,r]of Object.entries(a))e[t]=r.filter((e=>!o.has(String(e))));this.main.validVocabularies=e}else this.main.validVocabularies={};return}return void(this.main.validVocabularies=l)}}catch(e){console.warn("Could not parse banned/played vocabularies from localStorage",e)}return void(this.main.validVocabularies=a)}}catch(e){console.warn("Could not parse validVocabularies from localStorage",e)}this.main.validVocabularies={}}saveValidVocabularies(e){try{let t;if(Array.isArray(e))t={all:this._normalizeVocabList(e)};else if(e&&"object"==typeof e){t={};for(const[a,r]of Object.entries(e))Array.isArray(r)&&(t[a]=this._normalizeVocabList(r))}else t={};return localStorage.setItem("validVocabularies",JSON.stringify(t)),this.main.validVocabularies=t,this.main.uiManager&&"function"==typeof this.main.uiManager.refreshContainer&&this.main.uiManager.refreshContainer(),t}catch(e){return console.warn("Could not save validVocabularies to localStorage",e),{}}}_normalizeVocabList(e){const t=new Set,a=[];for(let r of e){if(null==r)continue;if("string"==typeof r&&(r=r.trim()),""===r||null==r)continue;if(!/^\d+$/.test(String(r)))continue;const e=String(r);t.has(e)||(t.add(e),a.push(r))}return a}saveSettings(){try{const e={maxGameCount:this.main.maxGameCount,currentTheme:this.main.currentTheme,displayMode:this.main.displayMode,groupViewMode:this.main.groupsManager.groupViewMode,previousScrollPosition:this.main.previousScrollPosition,panelWidths:this.main.panelWidths,panelHeights:this.main.panelHeights,panelYPosition:this.main.panelYPosition,enableDragging:this.main.enableDragging,shouldAutoSave:this.main.shouldAutoSave,hidePanelDelay:this.main.hidePanelDelay,shouldStart:this.main.shouldStart,startDelay:this.main.startDelay,shouldReplay:this.main.shouldReplay,replayDelay:this.main.replayDelay,replayNextGame:this.main.replayNextGame,shouldReplayMore:this.main.shouldReplayMore,replayNextGameCount:this.main.replayNextGameCount,remainingReplayCount:this.main.remainingReplayCount,replayWithoutWaiting:this.main.replayWithoutWaiting,showSearchBox:this.main.showSearchBox,showButtonDescriptions:this.main.showButtonDescriptions,showHelpTooltips:this.main.showHelpTooltips,showBlockedVocabAlert:this.main.showBlockedVocabAlert,qualificationEnabled:this.main.qualificationEnabled,showVocabularyData:this.main.showVocabularyData,rankRange:this.main.rankRange,randomGameId:this.main.randomGameId,randomVocabulariesType:this.main.randomVocabulariesType,alwaysVisiblePanel:this.main.alwaysVisiblePanel};localStorage.setItem("latestGamesSettings",JSON.stringify(e))}catch(e){console.warn("Could not save settings to localStorage:",e)}}async importSettings(e){const t=document.createElement("input");t.type="file",t.accept=".json,application/json",t.style.display="none",t.onchange=async t=>{const a=t.target.files[0];if(a)try{const t=await a.text(),r=JSON.parse(t);"object"==typeof r&&null!==r?(r.validVocabularies&&localStorage.setItem("validVocabularies",JSON.stringify(r.validVocabularies)),r.bannedVocabularies&&localStorage.setItem("bannedVocabularies",JSON.stringify(r.bannedVocabularies)),r.playedVocabularies&&localStorage.setItem("playedVocabularies",JSON.stringify(r.playedVocabularies)),r.latestGamesSettings&&localStorage.setItem("latestGamesSettings",JSON.stringify(r.latestGamesSettings)),r.latestGamesData&&localStorage.setItem("latestGamesData",JSON.stringify(r.latestGamesData)),e.settingsManager.loadSettings(),e.gamesManager.loadGameData(),e.uiManager.refreshContainer(),e.themeManager.applyTheme()):alert("Файл не содержит валидный JSON настроек.")}catch(e){alert("Ошибка при импорте: "+e)}},document.body.appendChild(t),t.click(),setTimeout((()=>t.remove()),1e3)}exportSettings(e){const t={latestGamesSettings:JSON.parse(localStorage.getItem("latestGamesSettings")||"{}"),latestGamesData:{groups:e.groupsManager.groups,currentGroupId:e.groupsManager.currentGroupId},validVocabularies:JSON.parse(localStorage.getItem("validVocabularies")||"[]"),bannedVocabularies:JSON.parse(localStorage.getItem("bannedVocabularies")||"[]"),playedVocabularies:JSON.parse(localStorage.getItem("playedVocabularies")||"[]")},a=new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),r=URL.createObjectURL(a),n=document.createElement("a");n.href=r,n.download="kg-latest-games-settings.json",document.body.appendChild(n),n.click(),setTimeout((()=>{URL.revokeObjectURL(r),n.remove()}),1e3)}removeAllSettings(e){localStorage.removeItem("latestGamesSettings"),localStorage.removeItem("latestGamesData"),e.groupsManager.groups=[e.groupsManager.createGroup("Группа-1")],e.groupsManager.currentGroupId=e.groupsManager.groups[0].id,e.gamesManager.saveGameData(),e.uiManager.refreshContainer()}}class re{constructor(e){this.main=e,this.groups=[],this.currentGroupId=null,this.groupViewMode="tabs"}createGroup(e){let t;if(e&&e.trim())t=e.trim();else{let e,a=1;do{e="Группа-"+a++}while(this.groups.some((t=>t.title===e)));t=e}return{id:U(this.groups),title:t,games:[]}}renameGroup(e,t){const a=this.groups.find((t=>t.id===e));a&&(a.title=t)}removeGroup(e){const t=this.groups.findIndex((t=>t.id===e));return-1!==t&&this.groups.splice(t,1),this.groups}initializeGroups(){if(0===this.groups.length){const e=this.createGroup();this.groups=[e],this.currentGroupId=e.id}else this.currentGroupId&&this.groups.some((e=>e.id===this.currentGroupId))||(this.currentGroupId=this.groups[0].id)}getCurrentGroup(){return this.groups.find((e=>e.id===this.currentGroupId))||null}setGroups(e,t){this.groups=e,this.currentGroupId=t}setGroupViewMode(e){this.groupViewMode=e}getGroupViewMode(){return this.groupViewMode}createGroupViewToggle(){const e=X("div",{className:"group-view-toggle control-button"});return e.innerHTML="tabs"===this.groupViewMode?$.wrap:$.scroll,W(e,"tabs"===this.groupViewMode?"Переключить в единый вид со всеми играми":"Переключить в режим вкладок по группам"),e.addEventListener("click",(()=>{this.groupViewMode="tabs"===this.groupViewMode?"unified":"tabs",this.main.settingsManager.saveSettings(),this.updateGroupViewToggle(e),this.main.uiManager.refreshContainer()})),e}updateGroupViewToggle(e){e.innerHTML="tabs"===this.groupViewMode?$.wrap:$.scroll,W(e,"tabs"===this.groupViewMode?"Переключить в единый вид со всеми играми":"Переключить в режим вкладок по группам")}moveGroup(e){const t=this.groups.findIndex((e=>e.id===this.currentGroupId));if(-1===t)return;const a=t+e;if(a<0||a>=this.groups.length)return;const r=this.groups[t];this.groups[t]=this.groups[a],this.groups[a]=r,this.main.gamesManager.saveGameData(),this.main.uiManager.refreshContainer()}updateGroupControlStates(){const e=document.querySelector(".move-group-left"),t=document.querySelector(".move-group-right");if(e&&t){const a=this.groups.findIndex((e=>e.id===this.currentGroupId)),r=0===a,n=a===this.groups.length-1;e.classList.toggle("latest-games-disabled",r),t.classList.toggle("latest-games-disabled",n)}}createGroupHeader(e){const t=X("div",{className:this.getGroupClass(e,"group-header"),textContent:e.title,dataset:{groupId:e.id}});return t.addEventListener("click",(()=>this.selectGroup(e.id))),t}createGroupTab(e){const t=X("span",{className:this.getGroupClass(e,"group-tab"),textContent:e.title,dataset:{groupId:e.id}});return t.addEventListener("click",(()=>this.selectGroup(e.id))),t}getGroupClass(e,t=""){const a=e.id===this.currentGroupId,r=this.main.gamesManager.latestGamesData?.previousGameId;return`${t}${a?" active":""}${e.games.some((e=>e.id===r))&&!a?" previous-game-group":""}`.trim()}createGroupsContainer(){const e=X("div",{id:"latest-games-groups"}),t=X("div",{className:"group-controls"+("unified"===this.groupViewMode?" unified-controls":"")}),a=X("span",{className:"add-group control-button",innerHTML:$.addGroup});W(a,"Добавить группу"),a.addEventListener("click",(()=>this.addGroup()));const r=X("span",{className:"rename-group control-button",innerHTML:$.renameGroup});W(r,"Переименовать группу"),r.addEventListener("click",(()=>this.renameActiveGroup()));const n=X("span",{className:"remove-group control-button",innerHTML:$.trashNothing});W(n,"\n [Клик] Удалить группу и сделать предыдущую активной\n [Shift + Клик] Удалить группу и сделать следующую активной\n "),n.addEventListener("click",(e=>this.removeActiveGroup(e)));const o=this.createGroupViewToggle(),s=X("span",{className:"move-group-left control-button",innerHTML:$.decrease});W(s,"Переместить вкладку назад"),s.addEventListener("click",(()=>{s.classList.contains("latest-games-disabled")||this.moveGroup(-1)}));const i=X("span",{className:"move-group-right control-button",innerHTML:$.increase});W(i,"Переместить вкладку вперёд"),i.addEventListener("click",(()=>{i.classList.contains("latest-games-disabled")||this.moveGroup(1)})),t.append(a,r,n,o,s,i),e.appendChild(t);const l=X("div",{className:"tabs-container"});return this.groups.forEach((e=>{const t=this.createGroupTab(e);l.appendChild(t)})),"unified"===this.groupViewMode&&l.classList.add("latest-games-hidden"),e.appendChild(l),e}selectGroup(e){this.groups.some((t=>t.id===e))&&(this.currentGroupId=e,this.main.gamesManager.saveGameData(),this.updateActiveGroup(),this.main.uiManager.refreshContainer())}updateActiveGroup(){document.querySelectorAll(".group-header").forEach((e=>e.classList.toggle("active",e.dataset.groupId===this.currentGroupId))),document.querySelectorAll(".group-tab").forEach((e=>e.classList.toggle("active",e.dataset.groupId===this.currentGroupId)))}addGroup(){const e=prompt("Введите название группы:");if(null===e)return;const t=this.createGroup(e?.trim()||null);this.groups.push(t),this.currentGroupId=t.id,this.main.gamesManager.saveGameData(),this.main.uiManager.refreshContainer()}renameActiveGroup(){const e=this.getCurrentGroup(),t=prompt("Введите новое название группы:",e?.title)?.trim();t&&(this.renameGroup(this.currentGroupId,t),this.main.gamesManager.saveGameData(),this.main.uiManager.refreshContainer())}removeActiveGroup(e){if(this.groups.length<=1)return void alert("Нельзя удалить последнюю группу.");const t=this.groups.findIndex((e=>e.id===this.currentGroupId));let a;this.removeGroup(this.currentGroupId),e&&e.shiftKey?a=t>=this.groups.length?this.groups.length-1:t:(a=t-1,a<0&&(a=0)),this.currentGroupId=this.groups[a].id,this.main.gamesManager.saveGameData(),this.main.uiManager.refreshContainer()}refreshGroupsContainer(){const e=document.getElementById("latest-games-groups");if(e){const t=e.querySelector(".group-controls");t&&(t.className="group-controls"+("unified"===this.groupViewMode?" unified-controls":""));const a=e.querySelector(".tabs-container");a&&(a.innerHTML="","tabs"===this.groupViewMode?(this.groups.forEach((e=>{const t=this.createGroupTab(e);a.appendChild(t)})),a.classList.remove("latest-games-hidden")):a.classList.add("latest-games-hidden"))}this.updateGroupControlStates()}isCyrillic(e){const t=e.charCodeAt(0);return t>=1040&&t<=1103||1025===t||1105===t}compareGameNames(e,t){const a=this.main.gamesManager.generateGameName(e).toLowerCase(),r=this.main.gamesManager.generateGameName(t).toLowerCase(),n=this.isCyrillic(a[0]),o=this.isCyrillic(r[0]);return n&&!o?-1:!n&&o?1:a.localeCompare(r,"ru")}sortActiveGroupGames(){const e=this.getCurrentGroup();if(!e)return;const t=e.games.filter((e=>e.pin)),a=e.games.filter((e=>!e.pin));t.sort(((e,t)=>this.compareGameNames(e,t))),a.sort(((e,t)=>this.compareGameNames(e,t))),e.games=[...t,...a],this.main.gamesManager.saveGameData(),this.main.uiManager.refreshContainer()}getPinnedGameCount(){const e=this.getCurrentGroup();return e?e.games.filter((e=>e.pin)).length:0}}class ne{constructor(e){this.main=e}getDisplayMode(){return this.main.displayMode}setDisplayMode(e){this.main.displayMode=e,this.main.settingsManager.saveSettings()}createDisplayModeToggle(){const e=X("div",{className:"display-mode-toggle control-button"});return e.innerHTML="wrap"===this.getDisplayMode()?$.wrap:$.scroll,W(e,"wrap"===this.getDisplayMode()?"Переключить режим отображения в вертикальный вид":"Переключить режим отображения в горизонтальный вид"),e.addEventListener("click",(()=>{const t="scroll"===this.getDisplayMode()?"wrap":"scroll";if(this.setDisplayMode(t),e.innerHTML="wrap"===t?$.wrap:$.scroll,this.updateDisplayModeClass(),W(e,"wrap"===t?"Переключить режим отображения в вертикальный вид":"Переключить режим отображения в горизонтальный вид"),"scroll"===t){const e=document.getElementById("latest-games-container");e&&setTimeout((()=>e.scrollTop=e.scrollHeight),0)}})),e}updateDisplayModeClass(){const e=document.getElementById("latest-games-container"),t=document.getElementById("latest-games");if(!e||!t)return;const a=this.getDisplayMode();e.classList.toggle("display-mode-wrap","wrap"===a),t.classList.toggle("display-mode-wrap","wrap"===a),this.updateContainerLeftOffset()}updateContainerLeftOffset(){const e=document.getElementById("latest-games-container");if(!e)return;if("wrap"===this.getDisplayMode()){const t=this.main.panelWidth||D.panelWidth;e.style.left=`calc(-1 * (${t} - 100px))`}else e.style.left="-330px"}}let oe=new Map,se=null;const ie='a[href*="/vocs/"], a[href*="/create/"]',le=["#latest-games-container",".game-popup",".userpanel","#head","#footer"];function ce(e){for(const t of le)if(e.closest(t))return!1;return!0}function pe(e){const t=Q(e);if(!t)return;const a=e.parentNode,r=a.querySelector(".kg-voc-checkmark");if(r&&r.remove(),oe.has(t)){const e=document.createElement("span");e.className="kg-voc-checkmark",e.innerHTML=$.checkmark,W(e,"Словарь уже существует в группе: "+oe.get(t).join(", "));const r=window.location.pathname.startsWith("/vocs/"),n=a.querySelector(".desc");r&&n?a.insertBefore(e,n):a.insertBefore(e,a.firstChild)}}function ge(e){e.forEach((e=>{if(e.addedNodes.forEach((e=>{if(e.nodeType===Node.ELEMENT_NODE&&ce(e)){e.matches&&e.matches(ie)&&pe(e);const t=e.querySelectorAll&&e.querySelectorAll(ie);t&&t.forEach((e=>{ce(e)&&pe(e)}))}})),"attributes"===e.type&&"href"===e.attributeName){const t=e.target;ce(t)&&t.matches&&t.matches("a")&&pe(t)}}))}function de(e){const t=J();["profile","forum","vocabularies","gamelist","game"].includes(t)&&(oe.clear(),e.forEach((e=>{e.games.forEach((t=>{if(t.params&&t.params.vocId){const a=String(t.params.vocId);oe.has(a)||oe.set(a,[]),oe.get(a).push(e.name||e.title||"Группа")}}))})),document.querySelectorAll(ie).forEach((e=>{ce(e)&&pe(e)})),se&&se.disconnect(),se=new MutationObserver(ge),se.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["href"]}))}function ue(e,t,a="popup",r,n=!1){const o=document.querySelector(`.${a}`);o&&o.remove();const s=X("div",{className:a});if(r){const e=X("div",{className:"popup-header",textContent:r});s.appendChild(e)}e.forEach((e=>{const t=X("button",{className:e.className||"popup-button",textContent:e.text,...e.dataset&&{dataset:e.dataset}});e.onClick&&t.addEventListener("click",(()=>{e.onClick(t),n||s.remove()})),s.appendChild(t)})),s.style.visibility="hidden",document.body.appendChild(s),s.querySelectorAll("button").forEach((e=>{e.scrollWidth>e.clientWidth&&W(e,e.textContent)}));const i=s.getBoundingClientRect(),l=window.innerWidth,c=window.innerHeight;let p=Math.max(10,Math.min(t.clientX,l-i.width-10)),g=Math.max(10,Math.min(t.clientY,c-i.height-10));s.style.left=`${p}px`,s.style.top=`${g}px`,s.style.visibility="visible";const d=e=>{e&&"keydown"===e.type&&"Escape"!==e.key||(s.remove(),document.removeEventListener("click",u),document.removeEventListener("keydown",m))},u=e=>{s.contains(e.target)||d(e)},m=e=>{"Escape"===e.key&&d(e)};return requestAnimationFrame((()=>{document.addEventListener("click",u),document.addEventListener("keydown",m)})),s}let me=null,he=null,ve=null,be=null;async function ye(e){try{const t=await fetch(`https://klavogonki.ru/vocs/${e}/`),a=await t.text(),r=(new DOMParser).parseFromString(a,"text/html");let n="Данные отсутствуют";const o=r.querySelector(".words");if(o){const e=o.querySelectorAll("tr");e.length>0&&(n=Array.from(e).map(((e,t)=>{const a=e.querySelector("td.num"),r=e.querySelector("td.text");if(!r)return null;const n=r.innerHTML.replace(//gi,"\n").replace(/<[^>]*>/g,"").trim();if(""===n||"…"===n)return null;if(a){const e=a.textContent.trim();return""===e||"…"===e?null:`${e}. ${n}`}return`${t+1}. ${n}`})).filter((e=>null!==e)).join("\n\n"))}const s={},i=r.querySelector(".user-title .title");if(i){const e=Array.from(i.childNodes).find((e=>e.nodeType===Node.TEXT_NODE&&e.textContent.trim()));s.title=e?e.textContent.trim():"Без названия"}const l=r.querySelector(".rating_stars");if(l){const e=l.className.match(/rating_stars(\d+)/);e&&(s.rating=parseInt(e[1]))}const c=r.querySelector("#rating_cnt");c&&(s.ratingCount=c.textContent.trim());const p=r.querySelector("#fav_cnt");p&&(s.usersCount=p.textContent.trim());const g=r.querySelector('.user-content dl dd[style*="background"]');if(g){const e=g.querySelector("a");if(e){s.authorName=e.textContent.trim();const t=e.getAttribute("href").match(/\/profile\/(\d+)/);t&&(s.authorId=t[1])}const t=g.getAttribute("style");if(t){const e=t.match(/url\s*\(\s*['""]*([^'")\s]+)['""]*\s*\)/);s.authorAvatar=e?e[1].replace(/"/g,""):s.authorId?`/storage/avatars/${s.authorId}_big.png`:null}}const d=r.querySelectorAll(".user-content dl");for(const e of d){const t=e.querySelector("dt"),a=e.querySelector("dd");if(!t||!a)continue;const r=t.textContent;if(r.includes("Создан:")){const e=Array.from(a.childNodes).find((e=>e.nodeType===Node.TEXT_NODE&&e.textContent.trim()));e&&(s.createdDate=e.textContent.trim());const t=a.querySelector(".note");t&&(s.versionDate=t.textContent.trim())}else r.includes("Тип словаря:")?s.vocabularyType=a.textContent.trim().split("\n")[0].trim():r.includes("Описание:")?s.description=a.textContent.trim():r.includes("Содержание:")&&(s.contentStats=a.textContent.trim().split("\n")[0].trim())}return{content:n,metadata:s}}catch(t){return console.error(`Error fetching vocabulary data for vocId ${e}:`,t),{content:"Ошибка загрузки словаря",metadata:null}}}function fe(e,t){const a=document.createElement("div");a.className="vocabulary-tooltip-popup";let r=e,n=t;e&&"object"==typeof e&&"content"in e&&(r=e.content,n=e.metadata||t),r=String(r||"Данные отсутствуют");let o="";if(n){if(o+='
',n.authorAvatar&&n.authorName&&(o+=`
\n ${n.authorName}\n ${n.authorName}\n
`),n.title&&(o+=`
${n.title}
`),void 0!==n.rating){o+=`
\n
\n
⭐️⭐️⭐️⭐️⭐️
\n
⭐️⭐️⭐️⭐️⭐️
\n
`,n.ratingCount&&(o+=` (${n.ratingCount})`),o+="
"}if(n.usersCount){const e=(e=>{const t=Math.abs(e)%100,a=t%10;return t>10&&t<20?"человек":a>1&&a<5?"человека":"человек"})(parseInt(n.usersCount));o+=`
Использует ${n.usersCount} ${e}
`}n.vocabularyType&&(o+=`
Тип: ${n.vocabularyType}
`),n.description&&(o+=`
${n.description}
`),o+='
'}return o+='
',o+=r.replace(/^(\d+)\.\s/gm,'$1. '),o+="
",a.innerHTML=o,document.body.appendChild(a),a}function xe(e,t,a=null){if(he&&clearTimeout(he),ve&&clearTimeout(ve),!me||be!==e){if(me&&we(),!e)return be=null,me=fe(t,a),Ce(null,me),me.addEventListener("mouseenter",(()=>{he&&clearTimeout(he)})),void me.addEventListener("mouseleave",ke);ve=setTimeout((()=>{be=e,me=fe(t,a),Ce(e,me),me.addEventListener("mouseenter",(()=>{he&&clearTimeout(he)})),me.addEventListener("mouseleave",ke)}),400)}}function we(){me&&(me.remove(),me=null,be=null),he&&clearTimeout(he),ve&&clearTimeout(ve)}function ke(){he&&clearTimeout(he);try{if(me&&me.matches(":hover"))return}catch(e){}he=setTimeout(we,300)}function Me(){try{const e=document.querySelector('#status #gamedesc a, #status a[href*="/vocs/"]');if(e){const t=(e.getAttribute("href")||"").match(/\/vocs\/(\d+)(?:\/|$)/);if(t&&t[1])return String(t[1])}const t=sessionStorage.getItem("latestGames_showVocTooltip");if(!t)return null;return(JSON.parse(t)||{}).vocId||null}catch(e){return console.warn("Could not determine session voc id:",e),null}}function Ce(e,t){const a=window.innerWidth,r=window.innerHeight,n=10,o=t.getBoundingClientRect();let s,i;if(e){const t=e.getBoundingClientRect();if(s=t.left,i=t.bottom+5,s+o.width>a-n&&(s=a-o.width-n),sr-n){const e=t.top-o.height-5;i=e>=n?e:n}i"))continue;const i=(new DOMParser).parseFromString(s,"text/html"),l=i.querySelector(".user-title");if(!l)continue;const c=l.querySelector("td.title");if(!c)continue;const p=c.querySelector("#rating_cnt"),g=c.querySelector("#fav_cnt");if(p&&g){t.abort();const a=c.childNodes[0].textContent.trim(),r=parseInt(p.textContent.trim(),10),n=parseInt(g.textContent.trim(),10);let o="",s=null;const l=i.querySelectorAll(".user-content dl");for(const e of l){const t=e.querySelector("dt"),a=e.querySelector("dd");if(!t||!a)continue;const r=t.textContent.trim();if("Автор:"===r){const e=a.querySelector('a[href^="/profile/"]');e&&(o=e.textContent.trim())}if("Тип словаря:"===r){const e=a.childNodes[0]?.textContent?.trim();e&&E[e]&&(s=E[e])}}return{vocId:e,vocabularyName:a,ratingCount:r,fansCount:n,vocabularyAuthor:o,vocabularyType:s}}}return null}catch(e){return"AbortError"===e.name||console.error("Error fetching/parsing vocabulary basic data:",e),null}}function Ee(e,t,a,r,n,o){if(e.games.some((e=>String(e.params?.vocId)===String(t))))return void alert(`Этот словарь уже добавлен в ${e.title}`);const s={id:U(n),params:{gametype:"voc",vocName:a,vocId:t,vocType:r||null,type:"normal",level_from:1,level_to:9,timeout:10,qual:0,premium_abra:0},pin:1};e.games.push(s);let i=o.gamesManager.latestGamesData||{};i={...i,latestGroupAddedGameId:e.id},o.gamesManager.latestGamesData=i,o.gamesManager.saveGameData(),o.uiManager.refreshContainer(),de(n)}!async function(){const e=localStorage.getItem("latestGamesSettings");if((e?JSON.parse(e):{}).showVocabularyData&&(await new Promise((e=>setTimeout(e,500))),"game"===J()))try{const e=Me();if(!e)return;if("vocabulary"!==ee().category)return;const t=await ye(e);xe(null,t.content,t.metadata),setTimeout((()=>{try{ke()}catch(e){}}),5e3)}catch(e){}}();const Ge=new WeakSet;function Le(e,t,a){async function r(e,t){const a=await Se(e);return a&&a.vocabularyName?{success:!0,vocName:a.vocabularyName,vocType:a.vocabularyType||null}:(alert("⚠️ Не удалось получить данные словаря. Добавление отменено."),{success:!1})}Ge.has(e)||(Ge.add(e),e.addEventListener("contextmenu",(async e=>{const n=e.target.closest("a");if(!n)return;const o=n.getAttribute("href");if(!o||!o.includes("/vocs/")&&!o.includes("/create/"))return;const s=Q(n);if(!s)return void console.warn("Invalid vocabulary link (extra path segments present), ignoring:",o);let i=a.gamesManager.latestGamesData||{};if(e.ctrlKey){const n=i.latestGroupAddedGameId;if(n){const o=t.find((e=>e.id===n));if(o){e.preventDefault(),e.stopPropagation();const n=await r(s);if(!n.success)return;return void Ee(o,s,n.vocName,n.vocType,t,a)}}return}e.preventDefault(),e.stopPropagation();const l=await r(s);l.success&&function(e,t,a,r,n,o){we(),ue(e.map((t=>{const s=t.games.some((e=>String(e.params?.vocId)===String(a)));return{text:t.title,className:"group-tab"+(s?" active":""),dataset:{groupId:t.id},onClick:()=>{Ee(t,a,r,n,e,o)}}})),t,"vocabulary-creation-popup","Добавить")}(t,e,s,l.vocName,l.vocType,a)})))}function Te(e,t){const a=Z();if(!a)return void console.warn("Vocabulary creation is not supported on this page.");a.split(",").map((e=>e.trim())).forEach((a=>{const r=document.querySelector(a);r&&Le(r,e,t),function(e,t){new MutationObserver((a=>{a.forEach((a=>{"childList"===a.type&&a.addedNodes.forEach((a=>{a.nodeType===Node.ELEMENT_NODE&&(a.matches(e)&&t(a),a.querySelectorAll(e).forEach((e=>t(e))))}))}))})).observe(document.body,{childList:!0,subtree:!0})}(a,(a=>Le(a,e,t)))}))}class Ie{constructor(e){this.main=e,this.container=null,this.startIndicator=null,this.replayIndicator=null,this.startTimer=null,this.replayTimer=null,this.playCountIndicators={day:null,week:null,month:null,year:null}}ensureContainer(){if(this.container)return;const e=document.createElement("div");e.className="games-data-container",document.body.appendChild(e),this.container=e}createIndicator(e,t,a=null,r=null){this.ensureContainer();const n=document.createElement("div");return n.className=`indicator ${e}`,n.textContent=t,a&&W(n,a),(r||this.container).appendChild(n),n}getPlayCount(e){try{const t=JSON.parse(localStorage.getItem("playedVocabularies")||"[]"),a=new Date,r=new Date(a.getFullYear(),a.getMonth(),a.getDate()).getTime(),n=(a.getDay()+6)%7,o=new Date(a.getFullYear(),a.getMonth(),a.getDate()-n).getTime(),s=new Date(a.getFullYear(),a.getMonth(),1).getTime(),i=new Date(a.getFullYear(),0,1).getTime();let l=0,c=0;return t.forEach((t=>{if(!t.playHistory)return;let a=!1;t.playHistory.forEach((t=>{const n=new Date(t.date),l=new Date(n.getFullYear(),n.getMonth(),n.getDate()).getTime();("day"===e&&l===r||"week"===e&&l>=o&&l<=r||"month"===e&&l>=s&&l<=r||"year"===e&&l>=i&&l<=r)&&(a=!0,c+=t.count||0)})),a&&l++})),{uniqueVocabs:l,totalGames:c}}catch(t){return console.error(`Error calculating ${e} play count:`,t),{uniqueVocabs:0,totalGames:0}}}createGamesDataContainer(){this.ensureContainer(),this.createPlayCountIndicators(),this.createRemainingCountIndicator()}createPlayCountIndicators(){const e=document.createElement("div");e.className="period-indicators-container",this.container.appendChild(e);let t=0;[{period:"day",class:"today-play-count-indicator",description:"День",tooltipSuffix:"сегодня"},{period:"week",class:"week-play-count-indicator",description:"Неделя",tooltipSuffix:"неделю"},{period:"month",class:"month-play-count-indicator",description:"Месяц",tooltipSuffix:"месяц"},{period:"year",class:"year-play-count-indicator",description:"Год",tooltipSuffix:"год"}].forEach((({period:a,class:r,description:n,tooltipSuffix:o})=>{const{uniqueVocabs:s,totalGames:i}=this.getPlayCount(a);if(0===i&&"day"!==a)return;const l=this.createIndicator(r,"",`Количество словарей / Количество заездов за ${o}`,e);this.playCountIndicators[a]=l;const c=document.createElement("span");c.className="period-indicator-description",c.textContent=n,c.style.display="none";const p=document.createTextNode(`${s}/${i}`);l.appendChild(c),l.appendChild(p),l._descSpan=c,"day"!==a&&(l.classList.add("period-indicator"),l.style.setProperty("--fall-delay",90*t+++"ms"))})),e.addEventListener("mouseenter",(()=>this.toggleExtendedIndicators(!0))),e.addEventListener("mouseleave",(()=>this.toggleExtendedIndicators(!1)))}toggleExtendedIndicators(e){["day","week","month","year"].forEach((t=>{const a=this.playCountIndicators[t];a&&("day"!==t&&a.classList.toggle("show",e),a._descSpan.style.display=e?"":"none")}))}createRemainingCountIndicator(){this.main.shouldReplayMore&&this.createIndicator("remaining-count-indicator",`${this.main.remainingReplayCount}`,"Колличество оставшихся повторов текущего словаря")}createSleepIndicator(e,t){this.ensureContainer();const a=document.createElement("div");a.className="indicator "+("start"===e?"sleep-start-indicator":"sleep-replay-indicator"),this.container.insertBefore(a,this.container.firstChild);W(a,"start"===e?"Таймер автоматического старта игры":"Таймер автоматического повтора игры"),"start"===e?this.startIndicator=a:this.replayIndicator=a;let r=t;const n=Date.now(),o=()=>{const s=Date.now()-n;r=Math.max(0,t-s);const i=Math.floor(r/1e3),l=Math.floor(r%1e3/10);if(a.textContent=`${i.toString().padStart(2,"0")}:${l.toString().padStart(2,"0")}`,r>0){const t=requestAnimationFrame(o);"start"===e?this.startTimer=t:this.replayTimer=t}};o()}removeSleepIndicator(e){"start"===e?(this.startTimer&&(cancelAnimationFrame(this.startTimer),this.startTimer=null),this.startIndicator&&(this.startIndicator.remove(),this.startIndicator=null)):"replay"===e&&(this.replayTimer&&(cancelAnimationFrame(this.replayTimer),this.replayTimer=null),this.replayIndicator&&(this.replayIndicator.remove(),this.replayIndicator=null))}}class De{constructor(e){this.main=e,this.gamesDataContainer=new Ie(e),this.replaySleep=null,this.startSleep=null,this.isHoveringLatestGames=!1,this.remainingReplayCount=this.main.replayNextGameCount}handlePageSpecificLogic(){const{href:e}=location;if(/https?:\/\/klavogonki\.ru\/g\/\?gmid=/.test(e)){this.gamesDataContainer.createGamesDataContainer(),this.setupHoverListeners();const e=new MutationObserver((()=>{const t=document.querySelector("#gamedesc");t&&t.textContent&&(e.disconnect(),this.saveCurrentGameParams(),this.handleStartAction())}));e.observe(document.body,{childList:!0,subtree:!0});const t=this.main.replayWithoutWaiting?document.querySelector("#typeblock #bookinfo"):document.querySelector("#status-inner #finished");if(t){const e=new MutationObserver((()=>{e.disconnect();try{const e=Me();if(e)try{if("vocabulary"===ee().category)try{this.main.gamesManager.markVocabAsPlayed(e)}catch(e){}}catch(e){}}catch(e){}this.handleReplayAction()}));e.observe(t,{attributes:!0})}}null!==Z()&&(de(this.main.groupsManager.groups),Te(this.main.groupsManager.groups,this.main),function(){const e=[".columns.voclist","#gamelist","#gamedesc"].map((e=>document.querySelector(e))).filter((e=>e));if(0===e.length)return void console.warn("No supported containers found.");const t=async e=>{if(!e.shiftKey)return;const t=e.target.closest('a[href*="/vocs/"]');if(t){const e=t.getAttribute("href"),a=e.match(/\/vocs\/(\d+)(?:\/|$)/);if(!a)return void console.warn(`Invalid vocabulary href: ${e}`);const r=a[1];if(t._tooltipData)xe(t,t._tooltipData.content,t._tooltipData.metadata);else{const e=await ye(r);t._tooltipData=e,xe(t,e.content,e.metadata)}}},a=e=>{const t=e.target.closest('a[href*="/vocs/"]');t&&be===t&&ke(),ve&&clearTimeout(ve)};e.forEach((e=>{e.addEventListener("mouseenter",t,{capture:!0}),e.addEventListener("mouseleave",a,{capture:!0})}))}())}setupHoverListeners(){const e=document.querySelector("#latest-games-container");e&&(e.addEventListener("mouseenter",(()=>{this.isHoveringLatestGames=!0,this.replaySleep&&"function"==typeof this.replaySleep.cancel&&(this.replaySleep.cancel(),this.replaySleep=null,this.gamesDataContainer.removeSleepIndicator("replay"))})),e.addEventListener("mouseleave",(()=>{this.isHoveringLatestGames=!1,this.handleReplayAction()})))}saveCurrentGameParams(){const e=document.querySelector("#gamedesc");if(!e)throw new Error("#gamedesc element not found.");const t=e.querySelector("span");if(!t)throw new Error("#gamedesc span element not found.");const a=e.textContent;if(/соревнование/.test(a)||!this.main.maxGameCount||!1===this.main.shouldAutoSave)return!1;const r=this.main.gamesManager.parseGameParams(t,a),n=JSON.stringify(r);let o=this.main.groupsManager.groups.find((e=>"Сохранённые"===e.title));o||(o=this.main.groupsManager.createGroup("Сохранённые"),this.main.groupsManager.groups.push(o));if(o.games.some((e=>JSON.stringify(e.params)===n)))return;const s={params:r,id:U(this.main.groupsManager.groups),pin:0},i=o.games.filter((e=>e.pin)).length;o.games.splice(i,0,s);const l=i+this.main.maxGameCount;o.games.length>l&&o.games.splice(l,o.games.length-l),this.main.gamesManager.assignGameIds(),this.main.gamesManager.saveGameData()}handleStartAction(){if(this.main.shouldStart){const e=document.querySelector("#status-inner #paused");e&&"none"!==e.style.display&&"undefined"!=typeof game&&game.hostStart&&(this.gamesDataContainer.removeSleepIndicator("start"),this.gamesDataContainer.createSleepIndicator("start",this.main.startDelay),this.startSleep=F(this.main.startDelay),this.startSleep.then((()=>{this.gamesDataContainer.removeSleepIndicator("start"),game.hostStart()})).catch((()=>{this.gamesDataContainer.removeSleepIndicator("start"),this.startSleep=null})))}}replayNextGame(){const e=this.main.groupsManager,t=this.main.gamesManager;let a=null,r=null,n=null,o=null;if(this.main.randomGameId){const s=t.getRandomGameId();if(!s)return;if("global"===s.mode)return void(async()=>{const e=await t.getValidRandomGameId();if(!e)return alert("Максимальное количество попыток поиска подходящей игры исчерпано. Попробуйте ещё раз.");if(a=e.id,o=e.url,a)try{t.registerPendingPlayed(a)}catch(e){}window.location.href=o})();if("local"===s.mode){const i=e.groups.find((e=>e.games.some((e=>e.id===s.id))));if(i&&e.selectGroup(i.id),t.latestGamesData=t.latestGamesData||{},t.latestGamesData.previousGameId=s.id,t.saveGameData(),a=String(s.game?.params?.vocId||""),r=s.game?.params?.vocName||null,n=s.game?.params?.vocType||null,o=s.game?t.generateGameLink(s.game):s.url,a)try{t.registerPendingPlayed(a,r||null,n||null)}catch(e){}o&&(window.location.href=o)}return}const s=e.getCurrentGroup(e.groups,e.currentGroupId);if(!s||!Array.isArray(s.games)||0===s.games.length)return;const i=t.latestGamesData?.previousGameId;let l=s.games.findIndex((e=>e.id===i));l=-1===l?0:(l+1)%s.games.length;const c=s.games[l];if(c){if(t.latestGamesData.previousGameId=c.id,t.saveGameData(),a=String(c.params.vocId||""),r=c.params.vocName||null,n=c.params.vocType||null,o=t.generateGameLink(c),a)try{t.registerPendingPlayed(a,r||null,n||null)}catch(e){}window.location.href=o}}handleReplayAction(){if(!["competition","qualification"].includes(ee().category)&&this.main.shouldReplay){const e=this.main.replayWithoutWaiting?document.querySelector("#typeblock #bookinfo"):document.querySelector("#status-inner #finished");if(e&&"none"!==e.style.display){const e=location.href.match(/gmid=(\d+)/);if(e){const t=e[1];this.isHoveringLatestGames||(this.gamesDataContainer.removeSleepIndicator("replay"),this.gamesDataContainer.createSleepIndicator("replay",this.main.replayDelay),this.replaySleep=F(this.main.replayDelay),this.replaySleep.then((()=>{this.gamesDataContainer.removeSleepIndicator("replay"),this.main.shouldReplayMore?this.main.remainingReplayCount>1?(this.main.remainingReplayCount--,this.main.settingsManager.saveSettings(),window.location.href=`https://klavogonki.ru/g/${t}.replay`):(this.main.remainingReplayCount=this.main.replayNextGameCount,this.main.settingsManager.saveSettings(),this.main.replayNextGame?this.replayNextGame():window.location.href=`https://klavogonki.ru/g/${t}.replay`):this.main.replayNextGame?this.replayNextGame():window.location.href=`https://klavogonki.ru/g/${t}.replay`})).catch((()=>{this.gamesDataContainer.removeSleepIndicator("replay"),this.replaySleep=null})))}}}}}function Ne(e,t,a,r,n){_();const o=t.filter((e=>e.id!==a)).map((t=>({text:t.title,className:"group-tab",dataset:{groupId:t.id},onClick:()=>{!function(e,t,a){const r=e.groupsManager.groups.find((e=>e.games.some((e=>e.id===t)))),n=e.groupsManager.groups.find((e=>e.id===a));if(!r||!n)return;if(r.id===n.id)return;const o=r.games.findIndex((e=>e.id===t));if(-1===o)return;const[s]=r.games.splice(o,1);n.games.push(s),e.gamesManager.saveGameData(),e.uiManager.refreshContainer()}(e,n,t.id)}})));ue(o,r,"game-migration-popup","Переместить")}const $e=10;const Ae=Object.keys(G),Ve=0,He=5,Be=5,je=8,qe=[".popup-header",".popup-header-title",".popup-subheader",".rank-slider-display",".timeouts-container"],Oe=[".game-popup-button",".rank-slider-handle",".rank-slider-track",".rank-slider-range",".popup-header-qualification"];function Pe(e,t){return t?Math.max(Ve,Math.min(He,e)):Math.max(Be,Math.min(je,e))}function ze(e,t,a,r="game-popup"){_();const n=document.querySelector(`.${r}`);n&&n.remove();const o=X("div",{className:r}),s=X("div",{className:"popup-header"}),i=X("div",{className:"popup-header-title",textContent:"Выбрать"}),l=X("span",{className:"popup-header-qualification",innerHTML:$.qualification});let c=a.qualificationEnabled??!1;l.classList.toggle("latest-games-disabled",!c),W(l,"Квалификация "+(c?"включена":"выключена")),l.addEventListener("click",(e=>{e.preventDefault(),e.stopPropagation(),c=!c,a.qualificationEnabled=c,a.settingsManager.saveSettings(),l.classList.toggle("latest-games-disabled",!c),W(l,"Квалификация "+(c?"включена":"выключена")),f()})),s.append(i,l),o.appendChild(s);const p=X("div",{className:"rank-slider-container"}),g=X("div",{className:"rank-slider-track"}),d=X("div",{className:"rank-slider-range"}),u=[X("div",{className:"rank-slider-handle",tabIndex:0}),X("div",{className:"rank-slider-handle",tabIndex:0})],m=X("div",{className:"rank-slider-display"});let[h,v]=a.rankRange||[Ve,je];h=Pe(h,!0),v=Pe(v,!1),h>v&&(h=v),vv&&(h=v),v{r[t].forEach((t=>e.classList.toggle(t,a)))})),f()}function f(){const t=h!==Ve||v!==je;b.forEach((({btn:r,type:n,timeout:o})=>{const s={...e,params:{...e.params,type:n,timeout:o,level_from:t?h+1:e.params.level_from,level_to:t?v+1:e.params.level_to}};c&&(s.params.qual=1);const i=a.gamesManager.generateGameLink(s);r.setAttribute("href",i),r.onclick=e=>{e.preventDefault(),window.location.href=i}}))}function x(){a.rankRange=[h,v],a.settingsManager.saveSettings()}return g.addEventListener("click",(e=>{const t=g.getBoundingClientRect(),a=(e.clientX-t.left)/t.width;let r=Math.round(a*(L.length-1));Math.abs(r-h){e.addEventListener("mousedown",(e=>{e.preventDefault();let a=0===t?h:v;const r=({clientX:e})=>{const{left:r,width:n}=g.getBoundingClientRect();let o=Math.round((e-r)/n*(L.length-1));o=Pe(o,0===t);const s=0===t?Math.min(o,v):Math.max(o,h);s!==a&&(a=s,0===t?h=s:v=s,y())},n=()=>{x(),document.removeEventListener("mousemove",r),document.removeEventListener("mouseup",n)};document.addEventListener("mousemove",r),document.addEventListener("mouseup",n)}))})),g.appendChild(d),u.forEach((e=>g.appendChild(e))),p.appendChild(m),p.appendChild(g),o.appendChild(p),y(),Ae.forEach((t=>{const r=X("div",{className:"popup-subheader",textContent:G[t]});o.appendChild(r);const n=X("div",{className:"timeouts-container"});I.forEach((r=>{if("normal"===t&&5===r)return;const o=h!==Ve||v!==je,s={...e,params:{...e.params,type:t,timeout:r,level_from:o?h+1:e.params.level_from,level_to:o?v+1:e.params.level_to}};c&&(s.params.qual=1);const i=a.gamesManager.generateGameLink(s),l=X("a",{href:i,className:"game-popup-button",textContent:r});l.addEventListener("click",(e=>{e.preventDefault(),window.location.href=i})),b.push({btn:l,type:t,timeout:r}),n.appendChild(l)})),o.appendChild(n)})),function(e,t){e.querySelectorAll("a").forEach((e=>{e.scrollWidth>e.clientWidth&&W(e,e.textContent)})),function(e,t,a={}){const{draggableSelectors:r=[],interactiveSelectors:n=[],onClose:o=null}=a;e.parentNode||(e.style.visibility="hidden",document.body.appendChild(e));const s=(t,a)=>{const r=window.innerWidth,n=window.innerHeight,o=e.getBoundingClientRect(),s=r-o.width-$e,i=n-o.height-$e,l=Math.max($e,Math.min(t,s)),c=Math.max($e,Math.min(a,i));e.style.left=`${l}px`,e.style.top=`${c}px`};s(t.clientX,t.clientY),e.style.visibility="visible";const i={clickOutside:null,keydown:null,popupMouseDown:t=>{if((a=t.target)!==e&&!r.some((e=>a.matches&&a.matches(e)))||(e=>n.some((t=>e.matches&&(e.matches(t)||e.closest(t)))))(t.target))return;var a;if(0!==t.button)return;t.preventDefault();const o=t.clientX,l=t.clientY,c=parseInt(e.style.left,$e),p=parseInt(e.style.top,$e),g=e=>{const t=e.clientX-o,a=e.clientY-l;s(c+t,p+a)},d=()=>{document.removeEventListener("mousemove",g),document.removeEventListener("mouseup",d),i.currentDrag=null};i.currentDrag={onMouseMove:g,onMouseUp:d},document.addEventListener("mousemove",g),document.addEventListener("mouseup",d)},currentDrag:null};e.addEventListener("mousedown",i.popupMouseDown),e.style.cursor="move";const l=t=>{t&&"keydown"===t.type&&"Escape"!==t.key||(o&&o(),c(),e.remove())},c=()=>{i.clickOutside&&document.removeEventListener("click",i.clickOutside),i.keydown&&document.removeEventListener("keydown",i.keydown),i.popupMouseDown&&e.removeEventListener("mousedown",i.popupMouseDown),i.currentDrag&&(document.removeEventListener("mousemove",i.currentDrag.onMouseMove),document.removeEventListener("mouseup",i.currentDrag.onMouseUp))};i.clickOutside=t=>{e.contains(t.target)||l(t)},i.keydown=e=>{"Escape"===e.key&&l(e)},requestAnimationFrame((()=>{document.addEventListener("click",i.clickOutside),document.addEventListener("keydown",i.keydown)}))}(e,t,{draggableSelectors:qe,interactiveSelectors:Oe})}(o,t),o}function Re(e,t,a,r){let n,o,s=!1;const i=e=>{if(!s)return;const r=t(e,n);a(r,o)},l=()=>{s&&(s=!1,document.removeEventListener("mousemove",i),document.removeEventListener("mouseup",l),r())};e.onmousedown=e=>{0===e.button&&(s=!0,[n,o]=t(e),document.addEventListener("mousemove",i),document.addEventListener("mouseup",l),e.preventDefault())}}function _e(e,t,a,r,n){const o=e.main.viewManager.getDisplayMode(),s=J();if("wrap"===o){const r=e.main.panelWidths?.[s]||e.main.panelWidth;t.style.width=r,a.style.display="",Re(a,((e,a)=>void 0===a?[e.clientX,t.offsetWidth]:e.clientX-a),((e,a)=>{let r=a+e;const n=.95*window.innerWidth;r=Math.max(350,Math.min(r,n));const o=Math.round(r/window.innerWidth*100*10)/10;t.style.width=`${o}vw`}),(()=>{e.main.panelWidths=e.main.panelWidths||{},e.main.panelWidths[s]=t.style.width,e.main.settingsManager.saveSettings()}))}else a.style.display="none",t.style.width="",a.onmousedown=null;const i=e.main.panelHeights?.[s]||D.panelHeight;t.style.height=i,r&&(r.style.display="",Re(r,((e,a)=>void 0===a?[e.clientY,t.offsetHeight]:e.clientY-a),((e,a)=>{let r=a+e;const n=.95*window.innerHeight;r=Math.max(200,Math.min(r,n));const o=Math.round(r/window.innerHeight*100*10)/10;t.style.height=`${o}vh`}),(()=>{e.main.panelHeights=e.main.panelHeights||{},e.main.panelHeights[s]=t.style.height,e.main.settingsManager.saveSettings()}))),n&&(n.style.display="",Re(n,((e,a)=>{if(void 0===a){const a=parseFloat(t.style.top)||0;return[e.clientY,{height:t.offsetHeight,top:a}]}return a-e.clientY}),((e,a)=>{let r=a.height+e;const n=.95*window.innerHeight;r=Math.max(200,Math.min(r,n));const o=(r-a.height)/window.innerHeight*100;let s=a.top-o;s=Math.max(0,s);const i=Math.round(r/window.innerHeight*100*10)/10,l=Math.round(10*s)/10;t.style.height=`${i}vh`,t.style.top=`${l}vh`}),(()=>{const a=J();e.main.panelHeights=e.main.panelHeights||{},e.main.panelHeights[a]=t.style.height,e.main.panelYPosition=e.main.panelYPosition||{};const r=parseFloat(t.style.top)||0;e.main.panelYPosition[a]=r,e.main.settingsManager.saveSettings()})))}function We(e,t){if("wrap"===e.main.viewManager.getDisplayMode()){const a=J(),r=e.main.panelYPosition[a]??0;"number"==typeof r&&r>=0&&r<=100&&(t.style.top=`${r}vh`);let n,o,s=!1;const i=e=>{if(!s)return;const a=e.clientY-n,r=o+a/window.innerHeight*100,i=t.offsetHeight,l=Math.max(0,(window.innerHeight-i)/window.innerHeight*100),c=Math.max(0,Math.min(r,l)),p=Math.round(10*c)/10;t.style.top=`${p}vh`},l=()=>{if(!s)return;s=!1,document.removeEventListener("mousemove",i),document.removeEventListener("mouseup",l);const a=J(),r=t.getBoundingClientRect(),n=Math.round(r.top/window.innerHeight*100*10)/10;e.main.panelYPosition[a]=n,e.main.settingsManager.saveSettings()},c=e=>{if(0!==e.button)return;if([".latest-game",".group-tab",".control-button",".resize-handle-horizontal",".resize-handle-vertical","#latest-games-search-input"].some((t=>e.target.closest(t))))return;s=!0,n=e.clientY;const a=t.getBoundingClientRect();o=a.top/window.innerHeight*100,document.addEventListener("mousemove",i),document.addEventListener("mouseup",l),e.preventDefault()};t.addEventListener("mousedown",c)}}const Ye={draggedElement:null,isDragging:!1,isRightHalf:!1,dragDirection:0,lastDragDirection:0,lastPanelDragY:0,dragOffset:{x:0,y:0},initialX:0,initialY:0,dragThreshold:1,rotationAccumulator:0,rotationDegreeLimit:5,globalEvents:{},reset(){this.draggedElement=null,this.isDragging=!1,this.isRightHalf=!1,this.dragDirection=0,this.lastDragDirection=0,this.lastPanelDragY=0,this.dragOffset={x:0,y:0},this.initialX=0,this.initialY=0,this.rotationAccumulator=0,this.globalEvents={}},cleanup(){this.globalEvents.handleDragMove&&document.removeEventListener("mousemove",this.globalEvents.handleDragMove),this.globalEvents.handleDragEnd&&document.removeEventListener("mouseup",this.globalEvents.handleDragEnd),this.globalEvents={}}};function Ke(e){const t=e.getBoundingClientRect(),a=e.parentElement.getBoundingClientRect(),r=e.parentElement;return{element:{rect:t,width:e.offsetWidth,height:e.offsetHeight},parent:{rect:a,width:r.offsetWidth,height:r.offsetHeight}}}let Ue=null;function Fe(){Ue&&Ue.parentNode&&Ue.parentNode.removeChild(Ue)}function Je(e,t){const a=Ke(Ye.draggedElement);let r=e.clientX-Ye.dragOffset.x-a.parent.rect.left,n=e.clientY-Ye.dragOffset.y-a.parent.rect.top;r=Math.max(0,Math.min(r,a.parent.width-a.element.width)),n=Math.max(0,Math.min(n,a.parent.height-a.element.height)),Ye.draggedElement.style.left=`${r}px`,Ye.draggedElement.style.top=`${n}px`;const o=Array.from(t.querySelectorAll(".pin-game:not(.dragging)"));let s=null,i=1/0;if(o.forEach((t=>{const a=t.getBoundingClientRect(),r=a.left+a.width/2,n=a.top+a.height/2,o=Math.hypot(e.clientX-r,e.clientY-n);o{if(a.preventDefault(),0!==a.button)return;if(a.target.closest(".latest-game-buttons"))return;Ye.cleanup(),e.wasDragging=!1,Ye.initialX=a.clientX,Ye.initialY=a.clientY,Ye.isDragging=!0,Ye.draggedElement=t;const r=Ke(t),n=a.clientX-r.element.rect.left;Ye.isRightHalf=n>r.element.rect.width/2,Ye.lastPanelDragY=a.clientY,Ye.dragOffset={x:a.clientX-r.element.rect.left,y:a.clientY-r.element.rect.top},Ye.globalEvents.handleDragMove=t=>function(e,t){if(!Ye.isDragging||!Ye.draggedElement)return;if(document.querySelectorAll(".dragged-game").forEach((e=>e.classList.remove("dragged-game"))),!t.wasDragging&&function(e){return Math.abs(e.clientX-Ye.initialX)>Ye.dragThreshold||Math.abs(e.clientY-Ye.initialY)>Ye.dragThreshold}(e)&&(t.wasDragging=!0,Ye.draggedElement.classList.add("dragging"),"wrap"===t.viewManager.getDisplayMode())){const e=Ke(Ye.draggedElement);Ye.draggedElement.style.position="absolute",Ye.draggedElement.style.left=e.element.rect.left-e.parent.rect.left+"px",Ye.draggedElement.style.top=e.element.rect.top-e.parent.rect.top+"px",Ye.draggedElement.style.width=`${e.element.rect.width}px`}e.preventDefault();const a=t.viewManager.getDisplayMode(),r=document.getElementById("latest-games");"scroll"===a?function(e,t){const a=Array.from(t.querySelectorAll(".pin-game:not(.dragging)"));let r=null;for(const t of a){const a=t.getBoundingClientRect(),n=a.top+a.height/2;if(e.clientYfunction(e){if(Ye.cleanup(),Fe(),!Ye.isDragging||!Ye.draggedElement)return void Ye.reset();Ye.isDragging=!1,Ye.draggedElement.classList.remove("dragging"),Ye.draggedElement.classList.add("dragged-game");const t=e.viewManager.getDisplayMode();"wrap"===t&&(Ye.draggedElement.style.position="",Ye.draggedElement.style.left="",Ye.draggedElement.style.top="",Ye.draggedElement.style.width="");Ye.draggedElement.style.transform="",e.gamesManager.updateGameOrderFromDOM(),Ye.reset()}(e),document.addEventListener("mousemove",Ye.globalEvents.handleDragMove),document.addEventListener("mouseup",Ye.globalEvents.handleDragEnd)}))}const Ze=new class{constructor(){this.cache=new Map}getUserId(){const e=document.querySelector(".userpanel .user-block .name img");if(!e)return null;const t=e.src.match(/\/avatars\/(\d+)_/);return t?t[1]:null}parseGameParams(e){const t=e.href,a=new URL(t),r={};for(const[e,t]of a.searchParams)r[e]=t;return r}getGameId(e){const t=this.parseGameParams(e);return"voc"===t.gametype&&t.voc?t.voc:t.gametype?t.gametype:"normal"}buildApiUrl(e,t){const a=new URLSearchParams({userId:e}),r=Object.keys(C);return"voc"===t.gametype&&t.voc?a.append("gametype",`voc-${t.voc}`):t.gametype&&r.includes(t.gametype)?a.append("gametype",t.gametype):(console.warn(`Unsupported gametype "${t.gametype}", defaulting to "normal"`),a.append("gametype","normal")),`https://klavogonki.ru/api/profile/get-stats-details?${a.toString()}`}async fetchGameStats(e){if(this.cache.has(e))return this.cache.get(e);try{const t=await fetch(e);if(!t.ok)throw new Error(`HTTP error! status: ${t.status}`);const a=await t.json();return this.cache.set(e,a),a}catch(e){return console.error("Failed to fetch game stats:",e),null}}formatTime(e){if(!e)return"N/A";return`${Math.floor(e/60)}:${(e%60).toString().padStart(2,"0")}`}formatDate(e){if(!e)return"N/A";try{return new Date(e).toLocaleDateString("ru-RU",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"})}catch(t){return e}}formatStats(e,t,a){if(!e||!e.ok)return"Данные отсутствуют";const{gametype:r,info:n}=e;let o="";if(o+="## Информация",r){if(r.name&&(o+=`[Название] ${r.name}`),r.id&&(o+=`[ID словаря] ${r.id}`),r.type){o+=`[Категория] ${S[r.type]||r.type}`}r.symbols&&(o+=`[Символов] ${r.symbols.toLocaleString()}`),r.rows&&(o+=`[Строк] ${r.rows.toLocaleString()}`)}if(o+="## Статистика",n&&(n.num_races&&(o+=`[Заездов] ${n.num_races}`),n.avg_speed&&(o+=`[Средняя скорость] ${Math.round(n.avg_speed)} зн/мин`),n.best_speed&&(o+=`[Лучшая скорость] ${n.best_speed} зн/мин`),void 0!==n.avg_error&&(o+=`[Средний % ошибок] ${n.avg_error.toFixed(2)}%`),void 0!==n.qual&&(o+="[Квалификация] "+(0===n.qual?"Нет":"Да")),n.haul&&n.haul.total&&(o+=`[Общее время] ${this.formatTime(n.haul.total)}`),n.haul)){const e=[];n.haul.hour&&e.push(`${n.haul.hour}ч`),n.haul.min&&e.push(`${n.haul.min}м`),e.length&&(o+=`[Время в игре] ${e.join(" ")}`)}return o.trim()}async getGameStats(e){const t=e.closest("li").querySelector("a");if(!t)return"[Ошибка] Не удалось найти параметры игры";const a=this.getGameId(t);if(!a)return"[Ошибка] Не удалось получить ID игры";const r=this.getUserId();if(!r)return`[Game ID] ${a} [Ошибка] Не удалось получить ID пользователя`;const n=this.parseGameParams(t),o=this.buildApiUrl(r,n);try{const e=await this.fetchGameStats(o);return this.formatStats(e,a,n)}catch(e){return console.error("Error getting game stats:",e),`[Game ID] ${a} [Ошибка] Ошибка загрузки статистики`}}};async function Qe(e,t){const a="voc"===t.params.gametype&&t.params.vocId,r=t.params.gametype,n="https://klavogonki.ru";let o=[{text:`${y} День`,className:"popup-button",onClick:()=>{const e=a?`${n}/vocs/${t.params.vocId}/top/day/`:`${n}/top/day/${r}/`;window.open(e,"_blank")}},{text:`${f} Неделя`,className:"popup-button",onClick:()=>{const e=a?`${n}/vocs/${t.params.vocId}/top/week/`:`${n}/top/week/${r}/`;window.open(e,"_blank")}}];if(a){const e=t.params.vocId,a=`${n}/vocs/${e}`,r=Ze.getUserId(),s=`${n}/u/#/${r}/stats`;if(o.unshift({text:`${x} Общая`,className:"popup-button",onClick:()=>window.open(a+"/","_blank")}),o.push({text:`${w} История`,className:"popup-button",onClick:()=>window.open(a+"/history/","_blank")},{text:`${k} Комментарии`,className:"popup-button",onClick:()=>window.open(a+"/comments/","_blank")}),r){const a={gametype:t.params.gametype,voc:t.params.vocId||t.params.voc},n=Ze.buildApiUrl(r,a),i=await Ze.fetchGameStats(n);i&&i.ok&&i.info&&i.info.num_races>0&&o.push({text:`${M} Статистика`,className:"popup-button",onClick:()=>window.open(s+`/voc-${e}/`,"_blank")})}}return ue(o,e,"game-popup","Информация")}function et(e,t,a){const r=e.gamesManager.getPreviousGameId(),n=t.pin?"pin-game":"",o=t.params&&t.params.gametype?`pin-gametype-${t.params.gametype}`:"",s=a===r?"previous-game":"";let i="";a===r&&(i="game"===J()?$.playing:$.paused);const l=X("li",{className:`latest-game ${n} ${o} ${s}`.trim(),id:`latest-game-${a}`});let c;const p=X("div",{className:"latest-game-buttons"});l.addEventListener("mouseenter",(()=>{c=setTimeout((()=>{p.style.visibility="visible"}),400)})),l.addEventListener("mouseleave",(()=>{clearTimeout(c),p.style.visibility="hidden"}));const g=X("div",{className:"latest-game-pin",innerHTML:t.pin?$.unpin:$.pin});W(g,t.pin?"[Клик] Открепить с подтверждением. [Shift + Клик] Открепить без подтверждения.":"[Клик] Закрепить с подтверждением. [Shift + Клик] Закрепить без подтверждения."),g.addEventListener("click",(r=>{(r.shiftKey||confirm(t.pin?"Открепить игру?":"Закрепить игру?"))&&e.gamesManager.pinGame(a)}));const d=X("div",{className:"latest-game-delete",innerHTML:$.delete});W(d,"[Клик] Удалить с подтверждением. [Shift + Клик] Удалить без подтверждения."),d.addEventListener("click",(t=>{(t.shiftKey||confirm("Удалить игру?"))&&e.gamesManager.deleteGame(a)}));const u=X("div",{className:"latest-game-info",innerHTML:$.info});W(u,"voc"===t.params.gametype&&t.params.vocId?"Показать информацию о словаре":"Показать информацию об игре"),u.addEventListener("click",(e=>{e.preventDefault(),e.stopPropagation(),Qe(e,t)})),p.append(u,g,d);const m=X("a",{href:e.gamesManager.generateGameLink(t),innerHTML:e.gamesManager.generateGameName(t,{stateIcon:i})});m.addEventListener("click",(a=>{e.wasDragging&&(a.preventDefault(),e.wasDragging=!1);try{const e=m.closest("li");if(e&&e.id&&e.id.startsWith("latest-game-")){const t=e.id.replace("latest-game-",""),a=JSON.parse(localStorage.getItem("latestGamesData"))||{};a.previousGameId=t,localStorage.setItem("latestGamesData",JSON.stringify(a))}}catch(e){}const r=String(t.params.vocId||"");if(r)try{e.gamesManager.registerPendingPlayed(r,t.params.vocName||null,t.params.vocType||null)}catch(e){}}));const h={vocabulary:new WeakMap,stats:new WeakMap};return m.addEventListener("mouseover",(async e=>{const a="voc"===t.params?.gametype&&t.params?.vocId;if(e.shiftKey&&a){e.preventDefault(),e.stopPropagation(),_();try{if(!h.vocabulary.has(m)){const e=await ye(t.params.vocId);h.vocabulary.set(m,e)}xe(m,h.vocabulary.get(m))}catch(e){console.error("Error loading vocabulary:",e)}}else if(e.ctrlKey){we(),Y(m,"[Loading] Загрузка статистики...","stats");try{if(!h.stats.has(m)){const e=await Ze.getGameStats(m);h.stats.set(m,e)}Y(m,h.stats.get(m),"stats")}catch(e){console.error("Error loading game stats:",e),Y(m,"[Ошибка] Не удалось загрузить статистику","stats")}}else Y(m,"\n [Удерживание ЛКМ] Создать игру с альтернативными параметрами\n [ПКМ] Переместить игру в другую группу\n [Shift + Наведение] Показать содержимое словаря\n [Ctrl + Наведение] Показать статистику игры\n ","info")})),m.addEventListener("mouseleave",(()=>{ke()})),l.appendChild(p),l.appendChild(m),t.pin&&e.enableDragging&&Xe(e,l),l}const tt="latestGamesSearchQuery";function at(){try{localStorage.removeItem(tt)}catch(e){console.warn("Failed to clear search query:",e)}}function rt(e,t){const a=e.value;if(!a)return void(t.style.left="");const r=function(e,t){const a=document.createElement("canvas").getContext("2d");return a.font=t,a.measureText(e).width}(a,function(e){const t=window.getComputedStyle(e);return`${t.fontWeight} ${t.fontSize} ${t.fontFamily}`}(e)),n=r+20;t.style.left=`${n}px`;n+(t.offsetWidth||24)>e.offsetWidth-8&&t.classList.remove("visible")}function nt(e){const t=X("div",{className:"latest-games-search-container "+(e.showSearchBox?"":"latest-games-hidden")}),a=X("input",{type:"search",id:"latest-games-search-input"}),r=X("div",{id:"latest-games-clear-button",className:"latest-games-clear-btn",innerHTML:$.delete});t.style.position="relative";const n=function(){try{return localStorage.getItem(tt)||""}catch(e){return console.warn("Failed to load search query:",e),""}}();return n&&(a.value=n,requestAnimationFrame((()=>{ot(r,n),rt(a,r),st(e,n)}))),a.addEventListener("input",(t=>{const n=t.target.value.trim();st(e,n),ot(r,n),rt(a,r),function(e){try{e&&e.trim()?localStorage.setItem(tt,e.trim()):localStorage.removeItem(tt)}catch(e){console.warn("Failed to save search query:",e)}}(n)})),r.addEventListener("click",(()=>{a.value="",a.focus(),st(e,""),ot(r,""),rt(a,r),at()})),a.addEventListener("keydown",(e=>{"Backspace"!==e.key&&"Delete"!==e.key||1!==a.value.length||a.value.trim()||at()})),ot(r,a.value),rt(a,r),t.appendChild(a),t.appendChild(r),t}function ot(e,t){e.classList.toggle("visible",!!t)}function st(e,t,a=!1){const r=document.getElementById("latest-games");if(!r)return;if(r.innerHTML="",!t)return void e.uiManager.populateGamesList(r);const n=[];if(e.groupsManager.groups.forEach((a=>{a.games.forEach((r=>{const o=function(e,t){const a=e.toLowerCase(),r=t.toLowerCase();if(!r)return 0;if(a===r)return-1e3;if(a.startsWith(r))return-500;if(a.includes(r))return-100;let n=0,o=0,s=0;for(;ne.score-t.score));const o=a?n.length:50,s=n.slice(0,o),i=n.length-o;if(s.forEach((({group:t,game:a})=>{const n=e.uiManager.createGameElement(a,a.id);n.classList.add("latest-games-search-result"),n.addEventListener("click",(()=>{e.groupsManager.currentGroupId=t.id,e.uiManager.refreshContainer(),setTimeout((()=>{const e=document.getElementById(`latest-game-${a.id}`);e&&e.scrollIntoView({behavior:"smooth",block:"center"})}),100)})),r.appendChild(n)})),i>0){const a=X("li",{className:"latest-games-search-more",textContent:`Ещё ${i} результатов скрыто`});W(a,"Нажмите для показа всех результатов"),a.addEventListener("click",(()=>{st(e,t,!0)})),r.appendChild(a)}}const it={popup:null,isDragging:!1,offsetX:0,offsetY:0,hasUnsavedChanges:!1,currentListType:"bannedVocabularies",listConfigs:{bannedVocabularies:{title:"Заблокированные словари",adjective:"заблокированных",mainKey:"bannedVocabularies",backupKey:"bannedVocabularies*Backup"},playedVocabularies:{title:"Проигранные словари",adjective:"проигранных",mainKey:"playedVocabularies",backupKey:"playedVocabularies*Backup"}},getConfig(){return this.listConfigs[this.currentListType]},get(){try{const e=this.getConfig(),t=localStorage[e.backupKey]?e.backupKey:e.mainKey,a=JSON.parse(localStorage[t])||[];return this.hasUnsavedChanges=t===e.backupKey,a.map((e=>"string"==typeof e?{id:e,isNew:!1}:{...e,isNew:e.isNew||!1}))}catch{return[]}},save(e,t=!0){const a=this.getConfig();if(t)localStorage[a.backupKey]=JSON.stringify(e),this.hasUnsavedChanges=!0;else{const t=this.hasUnsavedChanges?a.backupKey:a.mainKey;localStorage[t]=JSON.stringify(e)}},commitSave(){const e=this.getConfig(),t=localStorage[e.backupKey];t&&(localStorage[e.mainKey]=t,delete localStorage[e.backupKey]),this.hasUnsavedChanges=!1},revertChanges(){const e=this.getConfig();delete localStorage[e.backupKey],this.hasUnsavedChanges=!1},add(e){const t=this.get();t.some((t=>t.id===e))||(t.push({id:e,isNew:!0}),this.save(t))},filterVocabs(e,t,a="all",r="all"){let n=e;if("new"===a?n=n.filter((e=>e.isNew)):"old"===a?n=n.filter((e=>!e.isNew)):"unavailable"===a&&(n=n.filter((e=>!e.name))),"all"!==r&&(n=n.filter((e=>e.vocType===r))),t?.trim()){const e=t.toLowerCase().trim();n=n.filter((t=>t.id.toLowerCase().includes(e)||t.name&&t.name.toLowerCase().includes(e)||t.author&&t.author.toLowerCase().includes(e)))}return n},async fetchAndCacheVocabData(e,t=!1){if(!t&&e.name&&e.author&&e.vocType)return e;const a=await Se(e.id);return a?{...e,name:a.vocabularyName,author:a.vocabularyAuthor,vocType:a.vocabularyType}:{...e,name:null,author:null,vocType:null}},remove(e){this.save(this.get().filter((t=>t.id!==e))),this.refresh()},toggleBtnText(e,t,a,r=1e3){const n=this.popup.querySelector(e),o=a();n.textContent=t,setTimeout((()=>n.textContent=o),r)},async copy(e=null,t=!1,a="all",r="all",n=!1){const o=e||this.get();let s;if(t){s=o.map(((e,t)=>`${t+1}. Автор: ${e.author||"Неизвестный автор"}, Словарь: ${e.name||"Название недоступно"} - ${`https://klavogonki.ru/vocs/${e.id}/`}`)).join("\n")}else s=o.map((e=>e.id)).join(",");try{await navigator.clipboard.writeText(s)}catch{}this.toggleBtnText(".copy-all-btn","Скопировано!",(()=>this.getButtonText("copy",a,r,o.length,n)))},removeAll(e="all",t="all",a=null){const r=this.get();let n;if(a){const e=new Set(a.map((e=>e.id)));n=r.filter((t=>!e.has(t.id)))}else n="all"===e&&"all"===t?[]:r.filter((a=>{let r=!0,n=!0;return"new"===e?r=!a.isNew:"old"===e?r=a.isNew:"unavailable"===e&&(r=!!a.name),"all"!==t&&(n=a.vocType!==t),r&&n}));const o=r.length-n.length;this.save(n),this.toggleBtnText(".remove-all-btn","Удалено!",(()=>this.getButtonText("remove",e,t,o,!!a))),this.refresh()},getButtonText(e,t,a,r,n=!1){const o={all:"все",new:"новые",old:"старые",unavailable:"недоступные"},s={words:"Слова",phrases:"Фразы",texts:"Тексты",url:"URL",books:"Книга",generator:"Генератор"},i={copy:"Копировать",remove:"Удалить"}[e]||"";if(n)return`${i} результат (${r})`;const l=[];"all"!==t&&l.push(o[t]),"all"!==a&&l.push(s[a]);return`${i} ${l.length>0?l.join(" "):o.all} (${r})`},sortAll(){let e=this.get().map((e=>({...e,isNew:!1})));if("playedVocabularies"===this.currentListType){e.forEach((e=>{e.playHistory&&Array.isArray(e.playHistory)&&(e.playHistory=e.playHistory.sort(((e,t)=>new Date(e.date)-new Date(t.date))))}));const t={};e.forEach((e=>{if(e.playHistory&&e.playHistory.length>0){const a=e.playHistory[0].date,r=new Date(a).toLocaleDateString("ru-RU",{day:"numeric",month:"long",year:"numeric"});t[r]||(t[r]=[]),t[r].push(e)}}));e=Object.keys(t).sort(((e,t)=>new Date(e)-new Date(t))).flatMap((e=>t[e].sort(((e,t)=>parseInt(e.id)-parseInt(t.id)))))}else e.sort(((e,t)=>parseInt(e.id)-parseInt(t.id)));this.save(e),this.toggleBtnText(".sort-all-btn","Отсортировано!",(()=>"Сортировать")),this.refresh()},async forceFetchAll(){const e=this.popup.querySelector(".force-fetch-btn");e.textContent="Обновление...",e.disabled=!0;const t=this.get(),a=await Promise.all(t.map((e=>this.fetchAndCacheVocabData(e,!0)))),r=a.filter((e=>e.name)).length,n=a.filter((e=>!e.name)).length;this.save(a,!1),e.disabled=!1,this.toggleBtnText(".force-fetch-btn","Обновлено!",(()=>"Обновить все")),await this.refresh(),alert(`Обновление завершено!\n\nВсего словарей: ${a.length}\nДоступно: ${r}\nНедоступно: ${n}`)},async handleSave(){this.commitSave(),this.toggleBtnText(".save-btn","Сохранено!",(()=>"Сохранить")),await this.refresh()},async handleRevert(){this.revertChanges(),this.toggleBtnText(".revert-btn","Отменено!",(()=>"Отменить")),await this.refresh()},scrollToBottom(){if(this.popup){const e=this.popup.querySelector(".vocab-list");e&&(e.scrollTop=e.scrollHeight)}},scheduleScrollToBottom(){requestAnimationFrame((()=>this.scrollToBottom()))},createSearchAndFilterSection(){const e=document.createElement("div");e.className="popup-search-filters";const t=Object.assign(document.createElement("input"),{type:"text",placeholder:"Поиск по ID, названию или автору...",className:"search-input"}),a=document.createElement("div");a.className="filter-buttons";const r=Object.assign(document.createElement("button"),{className:"filter-btn active",textContent:"Все"});r.setAttribute("data-filter","all"),W(r,"Показать все словари");const n=Object.assign(document.createElement("button"),{className:"filter-btn",textContent:"Новые"});n.setAttribute("data-filter","new"),W(n,"Показать только новые словари");const o=Object.assign(document.createElement("button"),{className:"filter-btn",textContent:"Старые"});o.setAttribute("data-filter","old"),W(o,"Показать только старые словари");const s=Object.assign(document.createElement("button"),{className:"filter-btn",textContent:"Недоступные"});s.setAttribute("data-filter","unavailable"),W(s,"Показать только недоступные словари"),a.append(r,n,o,s);const i=document.createElement("div");i.className="filter-buttons type-filter-buttons";const l=Object.assign(document.createElement("button"),{className:"filter-btn active",textContent:"Все типы"});l.setAttribute("data-type-filter","all"),W(l,"Показать все типы словарей");const c=Object.assign(document.createElement("button"),{className:"filter-btn",textContent:"Слова"});c.setAttribute("data-type-filter","words"),W(c,'Показать только словари типа "Слова"');const p=Object.assign(document.createElement("button"),{className:"filter-btn",textContent:"Фразы"});p.setAttribute("data-type-filter","phrases"),W(p,'Показать только словари типа "Фразы"');const g=Object.assign(document.createElement("button"),{className:"filter-btn",textContent:"Тексты"});g.setAttribute("data-type-filter","texts"),W(g,'Показать только словари типа "Тексты"');const d=Object.assign(document.createElement("button"),{className:"filter-btn",textContent:"URL"});d.setAttribute("data-type-filter","url"),W(d,'Показать только словари типа "URL"');const u=Object.assign(document.createElement("button"),{className:"filter-btn",textContent:"Книга"});u.setAttribute("data-type-filter","books"),W(u,'Показать только словари типа "Книга"');const m=Object.assign(document.createElement("button"),{className:"filter-btn",textContent:"Генератор"});return m.setAttribute("data-type-filter","generator"),W(m,'Показать только словари типа "Генератор"'),i.append(l,c,p,g,d,u,m),e.append(t,a,i),{searchSection:e,searchInput:t,statusFilterContainer:a,typeFilterContainer:i}},createVocabItem(e,t=0){const a=document.createElement("div");a.className="vocab-item",e.isNew&&a.classList.add("vocab-item-new"),a.dataset.id=e.id,a.style.cursor="pointer";const r=document.createElement("div");r.className="vocab-left";const n=Object.assign(document.createElement("button"),{className:"vocab-play-btn control-button",innerHTML:$.start});n.addEventListener("click",(t=>{t.stopPropagation();const a=new URLSearchParams({gametype:"voc",type:"normal",timeout:"10",level_from:"1",level_to:"9",submit:"1",voc:String(e.id)});window.location.href=`${location.protocol}//klavogonki.ru/create/?${a.toString()}`}));const o=Object.assign(document.createElement("button"),{className:"vocab-info-btn control-button",innerHTML:$.info});o.addEventListener("click",(t=>{t.stopPropagation();Qe(t,{params:{gametype:"voc",vocId:e.id}})}));const s=Object.assign(document.createElement("span"),{className:"vocab-id",textContent:e.id});if(r.appendChild(n),r.appendChild(o),r.appendChild(s),t>1){const e=Object.assign(document.createElement("span"),{className:"vocab-play-count-badge",textContent:t.toString()});r.appendChild(e)}const i=document.createElement("div");if(i.className="vocab-right",e.name){const t=Object.assign(document.createElement("div"),{className:"vocab-name",textContent:e.name});if(i.appendChild(t),e.author){const t=Object.assign(document.createElement("div"),{className:"vocab-author",textContent:`Автор: ${e.author}`});i.appendChild(t)}if(e.vocType){const t=Object.keys(E).find((t=>E[t]===e.vocType))||e.vocType,a=Object.assign(document.createElement("div"),{className:"vocab-type",textContent:`Тип словаря: ${t}`});i.appendChild(a)}}else{const e=Object.assign(document.createElement("div"),{className:"vocab-loading",textContent:"Не удалось загрузить"});i.appendChild(e)}const l=Object.assign(document.createElement("button"),{className:"remove-btn",textContent:"Удалить"});return a.append(r,i,l),a},async createElements(){const e=this.get(),t=document.createElement("div");t.className="vocabularies-manager-popup";const a=document.createElement("div");a.className="popup-header";const r=this.getConfig();a.textContent=this.hasUnsavedChanges?`${r.title} *`:r.title,a.style.cursor="move",a.addEventListener("mousedown",(e=>this.startDrag(e))),t.appendChild(a);const n=document.createElement("div");n.className="popup-actions";const o=Object.assign(document.createElement("button"),{className:"copy-all-btn",textContent:this.getButtonText("copy","all","all",e.length,!1),disabled:!e.length});W(o,"[Клик] Копировать в соответствии с текущим фильтром или результатами поиска\n [Shift + Клик] Копировать в расширенном формате с авторами, названиями и ссылками");const s=Object.assign(document.createElement("button"),{className:"remove-all-btn",textContent:this.getButtonText("remove","all","all",e.length,!1),disabled:!e.length});W(s,"Удалить в соответствии с текущим фильтром или результатами поиска");const i=Object.assign(document.createElement("button"),{className:"sort-all-btn",textContent:"Сортировать",disabled:!e.length,onclick:()=>this.sortAll()});W(i,"Отсортировать все словари по ID и снять статус новых");const l=Object.assign(document.createElement("button"),{className:"force-fetch-btn",textContent:"Обновить",disabled:!e.length,onclick:()=>this.forceFetchAll()});if(W(l,"Принудительно обновить информацию о всех словарях"),n.append(o,s,i,l),this.hasUnsavedChanges){const e=Object.assign(document.createElement("button"),{className:"save-btn",textContent:"Сохранить",onclick:()=>this.handleSave()});W(e,"[Ctrl + S] Сохранить изменения");const t=Object.assign(document.createElement("button"),{className:"revert-btn",textContent:"Отменить",onclick:()=>this.handleRevert()});W(t,"[Ctrl + Z] Отменить все изменения"),n.append(e,t)}t.appendChild(n);const{searchSection:c,searchInput:p,statusFilterContainer:g,typeFilterContainer:d}=this.createSearchAndFilterSection();t.appendChild(c);const u=document.createElement("div");if(u.className="vocab-list",e.length){const t=await Promise.all(e.map((e=>this.fetchAndCacheVocabData(e))));this.save(t,!1);let a=t,r="all",n="all";const i=(e,a,r,n)=>{const i=n?.trim().length>0;if(o.textContent=this.getButtonText("copy",e,a,r.length,i),o.disabled=0===r.length,i)s.textContent=this.getButtonText("remove",e,a,r.length,!0),s.disabled=0===r.length;else{const r=this.filterVocabs(t,"",e,a);s.textContent=this.getButtonText("remove",e,a,r.length,!1),s.disabled=0===r.length}},l=()=>{const e=g.querySelector('[data-filter="all"]'),a=g.querySelector('[data-filter="new"]'),r=g.querySelector('[data-filter="old"]'),n=g.querySelector('[data-filter="unavailable"]'),o=t.filter((e=>e.isNew)).length,s=t.filter((e=>!e.isNew)).length,i=t.filter((e=>!e.name)).length;e.textContent=`Все (${t.length})`,a.textContent=`Новые (${o})`,r.textContent=`Старые (${s})`,n.textContent=`Недоступные (${i})`;const l=d.querySelector('[data-type-filter="all"]'),c=t.filter((e=>"words"===e.vocType)).length,p=t.filter((e=>"phrases"===e.vocType)).length,u=t.filter((e=>"texts"===e.vocType)).length,m=t.filter((e=>"url"===e.vocType)).length,h=t.filter((e=>"books"===e.vocType)).length,v=t.filter((e=>"generator"===e.vocType)).length;l.textContent=`Все типы (${t.length})`,d.querySelector('[data-type-filter="words"]').textContent=`Слова (${c})`,d.querySelector('[data-type-filter="phrases"]').textContent=`Фразы (${p})`,d.querySelector('[data-type-filter="texts"]').textContent=`Тексты (${u})`,d.querySelector('[data-type-filter="url"]').textContent=`URL (${m})`,d.querySelector('[data-type-filter="books"]').textContent=`Книга (${h})`,d.querySelector('[data-type-filter="generator"]').textContent=`Генератор (${v})`},c=e=>{if(u.innerHTML="",a=e,0===e.length){const e=document.createElement("div");return e.className="empty-state",e.textContent="Ничего не найдено",void u.appendChild(e)}if("playedVocabularies"===this.currentListType){const t=new Map;e.forEach((e=>{e.playHistory&&Array.isArray(e.playHistory)&&e.playHistory.forEach((a=>{const r=new Date(a.date).toLocaleDateString("ru-RU",{day:"numeric",month:"long",year:"numeric"});t.has(r)||t.set(r,{items:[],sortDate:new Date(a.date)}),t.get(r).items.push({vocab:e,count:a.count,date:a.date})}))}));Array.from(t.entries()).sort(((e,t)=>e[1].sortDate-t[1].sortDate)).map((([e])=>e)).forEach((e=>{const a=t.get(e).items,r=a.length,n=a.reduce(((e,{count:t})=>e+t),0),o=document.createElement("div");o.className="vocab-labels-container";const s=document.createElement("div");s.className="vocab-date",s.textContent=`${e}`;const i=document.createElement("div");i.className="vocab-count",i.textContent=n>r?`Словарей: ${r} | Заездов: ${n}`:`Словарей: ${r}`,o.appendChild(s),o.appendChild(i),u.appendChild(o),a.forEach((({vocab:e,count:t})=>{u.appendChild(this.createVocabItem(e,t))}))}))}else e.forEach((e=>u.appendChild(this.createVocabItem(e,0))));this.scheduleScrollToBottom()},m=()=>{const e=p.value,a=this.filterVocabs(t,e,r,n);c(a),i(r,n,a,e)};l(),c(t),i(r,n,a,""),o.addEventListener("click",(e=>{const t=e.shiftKey,o=p.value.trim().length>0;this.copy(a,t,r,n,o)})),s.addEventListener("click",(()=>{const e=p.value.trim().length>0;this.removeAll(r,n,e?a:null)})),p.addEventListener("input",m),g.addEventListener("click",(e=>{e.target.classList.contains("filter-btn")&&(g.querySelectorAll(".filter-btn").forEach((e=>e.classList.remove("active"))),e.target.classList.add("active"),r=e.target.dataset.filter,m())})),d.addEventListener("click",(e=>{e.target.classList.contains("filter-btn")&&(d.querySelectorAll(".filter-btn").forEach((e=>e.classList.remove("active"))),e.target.classList.add("active"),n=e.target.dataset.typeFilter,m())})),u.addEventListener("click",(e=>{const t=e.target.closest(".vocab-item");if(!t)return;const a=t.dataset.id;e.target.classList.contains("remove-btn")?this.remove(a):window.open(`https://klavogonki.ru/vocs/${a}/`,"_blank")})),u.addEventListener("mouseover",(e=>{if(!e.shiftKey)return;const t=e.target.closest(".vocab-item");if(!t)return;const a=t.dataset.id||t.querySelector(".vocab-id")?.textContent;a&&ye(a).then((e=>xe(t,e))).catch((()=>{}))}),{capture:!0}),u.addEventListener("mouseout",(e=>{e.target.closest(".vocab-item")&&ke()}),{capture:!0})}else{const e=document.createElement("div");e.className="empty-state",e.textContent=`Нет ${this.getConfig().adjective} словарей`,u.appendChild(e)}return t.appendChild(u),t},async refresh(){if(this.popup){const e=await this.createElements(),t=this.popup.parentNode,a=this.popup.getBoundingClientRect();t.replaceChild(e,this.popup),this.popup=e,this.popup.style.left=a.left+"px",this.popup.style.top=a.top+"px",this.scheduleScrollToBottom()}},async show(e=100,t=100,a=20,r=20){this.hide(),this.popup=await this.createElements(),document.body.appendChild(this.popup),this.popup.style.left=e+a+"px",this.popup.style.top=t+r+"px",this.constrainToScreen(),this.scheduleScrollToBottom(),setTimeout((()=>{document.addEventListener("click",this.outside),document.addEventListener("keydown",this.keydown)}),100)},hide(){this.popup&&(document.body.removeChild(this.popup),this.popup=null,this.isDragging=!1,document.removeEventListener("click",this.outside),document.removeEventListener("keydown",this.keydown),document.removeEventListener("mousemove",this.drag),document.removeEventListener("mouseup",this.stopDrag))},toggle(e,t,a="bannedVocabularies"){this.popup?this.currentListType===a?this.hide():(this.currentListType=a,this.refresh().catch((()=>{}))):(this.currentListType=a,this.show(e,t))},outside:e=>{it.popup?.contains(e.target)||"BUTTON"===e.target.tagName||it.hide()},keydown:e=>{"Escape"===e.key?it.hide():(e.ctrlKey||e.metaKey)&&"s"===e.key?(e.preventDefault(),it.hasUnsavedChanges&&it.handleSave()):(e.ctrlKey||e.metaKey)&&"z"===e.key&&(e.preventDefault(),it.hasUnsavedChanges&&it.handleRevert())},startDrag(e){this.isDragging=!0;const t=this.popup.getBoundingClientRect();this.offsetX=e.clientX-t.left,this.offsetY=e.clientY-t.top,document.addEventListener("mousemove",this.drag),document.addEventListener("mouseup",this.stopDrag)},drag:e=>{it.isDragging&&it.popup&&(it.popup.style.left=e.clientX-it.offsetX+"px",it.popup.style.top=e.clientY-it.offsetY+"px",it.constrainToScreen())},stopDrag:()=>{it.isDragging=!1,document.removeEventListener("mousemove",it.drag),document.removeEventListener("mouseup",it.stopDrag)},constrainToScreen(){if(!this.popup)return;const e=this.popup.getBoundingClientRect(),t=window.innerWidth-e.width,a=window.innerHeight-e.height;e.left<0&&(this.popup.style.left="0px"),e.top<0&&(this.popup.style.top="0px"),e.left>t&&(this.popup.style.left=t+"px"),e.top>a&&(this.popup.style.top=a+"px")}},lt=Object.entries(E).map((([e,t])=>({label:e,key:t}))),ct=e=>{const t=e?JSON.parse(e):[];return Array.isArray(t)?t.map((e=>String("object"==typeof e&&e?.id?e.id:e))):[]};function pt(e,t){try{const a=(e.validVocabularies?.[t]||[]).length,r=new Set(ct(localStorage.getItem("playedVocabularies"))),n=new Set(ct(localStorage.getItem("bannedVocabularies"))),o=(JSON.parse(localStorage.getItem("validVocabularies")||"{}")[t]||[]).filter((e=>r.has(String(e))&&!n.has(String(e)))).length;return{total:o+a,played:o,remained:a}}catch(e){return console.warn("Error calculating vocabulary counts:",e),{total:0,played:0,remained:0}}}function gt(e,t,a){return a&&0!==t?0===e?" danger":e<=10?" warning":"":""}function dt(e,t){const a=lt.map((({label:e,key:a})=>{const r=pt(t,a),n=t.randomVocabulariesType[a];return{text:e,className:`group-tab${n?" active":""}${gt(r.remained,r.total,n)}`,onClick:e=>function(e,t,a){if(!(e instanceof HTMLElement))return;const r=!a.randomVocabulariesType[t];if(a.randomVocabulariesType[t]=r,e.classList.remove("active","warning","danger"),r){e.classList.add("active");const r=pt(a,t),n=gt(r.remained,r.total,!0).trim();n&&e.classList.add(n)}a.settingsManager.saveSettings()}(e,a,t),counts:r}})),r=ue(a,e,"vocabulary-types-popup","Тип",!0);return r.querySelectorAll(".group-tab").forEach(((e,t)=>{const{total:r,played:n,remained:o}=a[t].counts;W(e,`[Всего:]${r} [Проиграно:]${n} [Осталось:]${o}`,"stats")})),r}function ut(e){const t=X("div",{className:"latest-games-controls"}),a=X("div",{className:"controls-limiter"}),r=X("div",{className:"controls-buttons"}),n=X("div",{className:"controls-visible"}),o=X("div",{className:"controls-more"});r.append(n,o),o.appendChild(a),t.append(r);const s=X("span",{id:"latest-games-options"});a.appendChild(s);const i=X("span",{id:"latest-games-count-dec",className:"control-button",innerHTML:$.decrease});W(i,"Уменьшить количество сохраняемых игр");const l=X("span",{id:"latest-games-count",className:!1===e.shouldAutoSave?"latest-games-disabled":"",textContent:e.maxGameCount.toString()});W(l,e.shouldAutoSave?"Автосохранение включено":"Автосохранение отключено"),l.addEventListener("click",(()=>{e.shouldAutoSave=!e.shouldAutoSave,e.uiManager.updateGameCountDisplay(),e.settingsManager.saveSettings(),e.uiManager.refreshContainer()}));const c=X("span",{id:"latest-games-count-inc",className:"control-button",innerHTML:$.increase});W(c,"Увеличить количество сохраняемых игр"),i.addEventListener("click",(()=>e.gamesManager.changeGameCount(-1))),c.addEventListener("click",(()=>e.gamesManager.changeGameCount(1))),s.append(i,l,c);const p=(e,t,a,r)=>{const n="function"==typeof a.click?a.click(t):a.click,o="function"==typeof a.shift?a.shift(t):a.shift,s=a.ctrl?"function"==typeof a.ctrl?a.ctrl(t):a.ctrl:"",i=a.alt?"function"==typeof a.alt?a.alt(t):a.alt:"",l=a.shiftAlt?"function"==typeof a.shiftAlt?a.shiftAlt(t):a.shiftAlt:"";W(e,`\n [Клик] ${n}\n [Shift + Клик] ${o}${r?` (${r} мс)`:""}\n ${s?`[Ctrl + Клик] ${s}`:""}\n ${i?`[Alt + Клик] ${i}`:""}\n ${l?`[Shift + Alt + Клик] ${l}`:""}\n `)},g=(t,a,r,n,o)=>{const s=a[r];t.classList.toggle("latest-games-disabled",!s),p(t,s,o,a[n]),t.onclick=s=>{if(s.ctrlKey&&t===v)return e.replayNextGame=!e.replayNextGame,e.settingsManager.saveSettings(),t.classList.toggle("replay-next-game",e.replayNextGame),t.innerHTML=h(),void p(t,a[r],o,a[n]);if(s.altKey&&t===v)return e.replayWithoutWaiting=!e.replayWithoutWaiting,e.settingsManager.saveSettings(),t.classList.toggle("replay-without-waiting",e.replayWithoutWaiting),t.innerHTML=h(),void p(t,a[r],o,a[n]);const i="function"==typeof o.shift?o.shift(a[r]):o.shift;if(s.shiftKey){const s=prompt(i,"");if(null!==s){const i=parseInt(s,10);!isNaN(i)&&i>=0?(a[n]=i,e.settingsManager.saveSettings(),p(t,a[r],o,i)):alert(o.delayErrorText)}}else a[r]=!a[r],e.settingsManager.saveSettings(),t.classList.toggle("latest-games-disabled",!a[r]),p(t,a[r],o,a[n])}},d=X("span",{className:"latest-games-refresh control-button",innerHTML:$.refresh});W(d,"\n [Клик] Сгенерировать новые уникальные ID для всех групп и игр\n [Shift + Клик] Обновить типы словарей для всех игр (если отсутствуют)\n "),d.addEventListener("click",(async t=>{if(t.shiftKey){if(!confirm("Вы уверены, что хотите обновить типы словарей для всех игр без них? Это может занять время."))return;const t=[];if(e.groupsManager.groups.forEach((e=>{e.games.forEach((a=>{!a.params||null!==a.params.vocType&&void 0!==a.params.vocType||t.push({group:e,game:a})}))})),0===t.length)return void alert("✔️ Все игры уже имеют типы словарей.");let a=0;const r=500;for(const{group:e,game:n}of t){const e=n.params.vocId;if(e){const t=await Se(e).catch((()=>null));t&&t.vocabularyType&&(n.params.vocType=t.vocabularyType,a++)}r>0&&await new Promise((e=>setTimeout(e,r)))}e.gamesManager.saveGameData(),e.uiManager.refreshContainer(),alert(`✔️ Обновлено ${a} игр с типами словарей.`)}else{if(!confirm("Вы уверены, что хотите сгенерировать новые уникальные ID для всех групп и игр? Это действие нельзя отменить."))return;const t=e.groupsManager.currentGroupId,a=e.gamesManager.latestGamesData?.previousGameId;if(e.groupsManager.groups.forEach((e=>{e._oldId=e.id,e.games.forEach((e=>{e._oldId=e.id}))})),e.groupsManager.groups.forEach((t=>{t.id=U(e.groupsManager.groups),t.games.forEach((t=>{t.id=U(e.groupsManager.groups)}))})),t){const a=e.groupsManager.groups.find((e=>e._oldId===t));a&&(e.groupsManager.currentGroupId=a.id)}if(a)for(const t of e.groupsManager.groups){const r=t.games.find((e=>e._oldId===a));if(r){e.gamesManager.latestGamesData.previousGameId=r.id;break}}e.groupsManager.groups.forEach((e=>{delete e._oldId,e.games.forEach((e=>delete e._oldId))})),e.gamesManager.saveGameData(),e.uiManager.refreshContainer(),alert("✔️ Все ID для групп и игр были обновлены!")}}));const u=X("span",{className:"latest-games-reset-panels control-button",innerHTML:$.reset});W(u,"Сбросить настройки панели на значения по умолчанию"),u.addEventListener("click",(()=>{confirm("Вы уверены, что хотите сбросить настройки панели на значения по умолчанию? Это действие нельзя отменить.")&&function(e){e.panelWidths={...D.panelWidths},e.panelHeights={...D.panelHeights},e.panelYPosition={...D.panelYPosition},e.alwaysVisiblePanel={...D.alwaysVisiblePanel},e.settingsManager.saveSettings(),e.uiManager&&e.uiManager.refreshContainer&&e.uiManager.refreshContainer()}(e)}));const m=X("span",{className:"latest-games-play control-button",innerHTML:$.play});g(m,e,"shouldStart","startDelay",{click:e=>e?"Отключить автозапуск игры":"Включить автозапуск игры",shift:()=>"Изменить задержку запуска в миллисекундах",delayErrorText:"Пожалуйста, введите корректное значение задержки запуска."});const h=()=>e.replayWithoutWaiting?$.replayImmediately:$.replay,v=X("span",{className:"latest-games-replay control-button"+(e.replayNextGame?" replay-next-game":"")+(e.replayWithoutWaiting?" replay-without-waiting":""),innerHTML:h()});g(v,e,"shouldReplay","replayDelay",{click:e=>e?"Отключить автоповтор игры":"Включить автоповтор игры",shift:()=>"Изменить задержку автосоздания в миллисекундах:",ctrl:()=>e.replayNextGame?"Режим создания следующей игры":"Режим повтора текущей игры",alt:()=>e.replayWithoutWaiting?"Режим создания без ожидания игроков":"Режим создания с ожиданием игроков",delayErrorText:"Пожалуйста, введите корректное значение задержки автоповтора."});const b=X("span",{className:"latest-games-replay-more control-button"+(!1===e.shouldReplayMore?" latest-games-disabled":""),innerHTML:$.replayMore}),y=()=>{W(b,`\n [Клик] ${e.shouldReplayMore?"Отключить многократный повтор игры":"Включить многократный повтор игры"}\n [Shift + Клик] Изменить количество повторов (${e.replayNextGameCount})\n `)};y(),b.onclick=t=>{if(t.shiftKey){let t;for(;;){if(t=prompt("Введите количество повторов игры:",e.replayNextGameCount.toString()),null===t)return;const a=parseInt(t,10);if(!isNaN(a)&&a>=1)return e.replayNextGameCount=a,e.settingsManager.saveSettings(),void y();alert("⚠️ Пожалуйста, введите корректное число (больше или равно 1).")}}else e.shouldReplayMore=!e.shouldReplayMore,e.settingsManager.saveSettings(),b.classList.toggle("latest-games-disabled",!e.shouldReplayMore),y()};const f=X("span",{className:"latest-games-pinall control-button",innerHTML:$.pin});W(f,"\n [Клик] Закрепить все игры в текущей группе\n [Shift + Клик] Закрепить все игры во всех группах\n "),f.onclick=t=>{if(t.shiftKey)e.groupsManager.groups.forEach((e=>e.games.forEach((e=>e.pin=1))));else{const t=e.groupsManager.getCurrentGroup(e.groupsManager.groups,e.groupsManager.currentGroupId);t&&t.games.forEach((e=>e.pin=1))}e.gamesManager.saveGameData(),e.uiManager.refreshContainer()};const x=X("span",{className:"latest-games-unpinall control-button",innerHTML:$.unpin});W(x,"\n [Клик] Открепить все игры в текущей группе\n [Shift + Клик] Открепить все игры во всех группах\n "),x.onclick=t=>{if(t.shiftKey)e.groupsManager.groups.forEach((e=>e.games.forEach((e=>e.pin=0))));else{const t=e.groupsManager.getCurrentGroup(e.groupsManager.groups,e.groupsManager.currentGroupId);t&&t.games.forEach((e=>e.pin=0))}e.gamesManager.saveGameData(),e.uiManager.refreshContainer()};const w=X("span",{className:"latest-games-sort control-button",innerHTML:$.sort});W(w,"Сортировать игры в текущей группе по алфавиту"),w.addEventListener("click",(()=>e.groupsManager.sortActiveGroupGames()));const k=X("span",{className:"latest-games-import control-button",innerHTML:$.import});W(k,"Импортировать настройки из JSON файла"),k.onclick=()=>e.settingsManager.importSettings(e);const M=X("span",{className:"latest-games-export control-button",innerHTML:$.export});W(M,"Экспортировать все настройки в JSON файл"),M.onclick=()=>e.settingsManager.exportSettings(e);const C=X("span",{className:"latest-games-removeall control-button",innerHTML:$.trashNothing});W(C,"Удалить все настройки"),C.onclick=()=>e.settingsManager.removeAllSettings(e);const S=X("span",{className:"latest-games-remove-unpinned control-button",innerHTML:$.broom});W(S,"\n [Клик] Удалить все незакреплённые игры в текущей группе\n [Shift + Клик] Удалить все незакреплённые игры во всех группах\n "),S.onclick=t=>{if(t.shiftKey)e.groupsManager.groups.forEach((e=>{e.games=e.games.filter((e=>e.pin))}));else{const t=e.groupsManager.getCurrentGroup(e.groupsManager.groups,e.groupsManager.currentGroupId);t&&(t.games=t.games.filter((e=>e.pin)))}e.gamesManager.saveGameData(),e.uiManager.refreshContainer()};const E=X("span",{className:"latest-games-drag-toggle control-button",innerHTML:$.dragToggle});W(E,e.enableDragging?"Перетаскивание включено":"Перетаскивание отключено"),E.classList.toggle("latest-games-disabled",!e.enableDragging),E.onclick=()=>{e.enableDragging=!e.enableDragging,e.settingsManager.saveSettings(),e.uiManager.refreshContainer(),W(E,e.enableDragging?"Перетаскивание включено":"Перетаскивание отключено"),E.classList.toggle("latest-games-disabled",!e.enableDragging)};const G=X("span",{className:"latest-games-desc-toggle control-button",innerHTML:$.info});W(G,e.showButtonDescriptions?"Скрыть описания кнопок":"Показать описания кнопок"),G.classList.toggle("latest-games-disabled",!e.showButtonDescriptions),G.onclick=()=>{e.showButtonDescriptions=!e.showButtonDescriptions,e.settingsManager.saveSettings(),G.classList.toggle("latest-games-disabled",!e.showButtonDescriptions),W(G,e.showButtonDescriptions?"Скрыть описания кнопок":"Показать описания кнопок"),e.uiManager.refreshContainer(),setTimeout((()=>{const e=document.querySelector(".latest-games-controls");e&&(e.scrollTop=e.scrollHeight)}),0)};const L=X("span",{className:"latest-games-help-toggle control-button"+(e.showHelpTooltips?"":" latest-games-disabled"),innerHTML:$.help}),T=()=>{W(L,e.showHelpTooltips?"Скрыть подсказки":"Показать подсказки","help"),L.classList.toggle("latest-games-disabled",!e.showHelpTooltips)};T(),L.addEventListener("click",(()=>{O=null,e.showHelpTooltips=!e.showHelpTooltips,e.settingsManager.saveSettings(),T(),e.uiManager.refreshContainer()}));const I=X("span",{className:"latest-games-search-btn control-button"+(e.showSearchBox?"":" latest-games-disabled"),innerHTML:$.search}),N=()=>{W(I,e.showSearchBox?"Скрыть строку поиска":"Показать строку поиска"),I.classList.toggle("latest-games-disabled",!e.showSearchBox)};N(),I.addEventListener("click",(()=>{!function(e){const t=document.querySelector(".latest-games-search-container");if(!t)return;const a=t.classList.toggle("latest-games-hidden");if(e.showSearchBox=!a,e.settingsManager&&"function"==typeof e.settingsManager.saveSettings&&e.settingsManager.saveSettings(),!a){const e=document.getElementById("latest-games-search-input");e&&(e.focus(),e.select())}}(e),N()}));const A=X("span",{className:"latest-games-random control-button"+(e.randomGameId?"":" latest-games-disabled"),innerHTML:$.random}),V=()=>{p(A,!!e.randomGameId,{click:t=>{const a="global"===e.randomGameId?"глобальный":"local"===e.randomGameId?"локальный":"выключен";return t?`Отключить случайный выбор игры (${a})`:`Включить случайный выбор игры (${a})`},shift:()=>{let e=[];try{const t=JSON.parse(localStorage.getItem("validVocabularies")||"{}");t&&"object"==typeof t&&(e=Object.values(t).flat().filter(Boolean).map(String))}catch(t){e=[]}const t=new Set(e).size,a=(()=>{try{return new Set([...(JSON.parse(localStorage.getItem("bannedVocabularies")||"[]")||[]).map((e=>String("string"==typeof e?e:e.id||e||""))),...(JSON.parse(localStorage.getItem("playedVocabularies")||"[]")||[]).map((e=>String("string"==typeof e?e:e.id||e||"")))].filter(Boolean))}catch(e){return new Set}})();let r=0;for(const t of new Set(e))a.has(t)||r++;return`Обновить список допустимых словарей (всего: ${t}, доступно: ${r})`},alt:()=>e.showBlockedVocabAlert?"Отключить предупреждение о недоступных словарях":"Включить предупреждение о недоступных словарях",ctrl:()=>"global"===e.randomGameId?"Отключить глобальный режим":"Включить глобальный режим",shiftAlt:()=>"Выбрать типы словарей"}),A.classList.toggle("latest-games-disabled",!e.randomGameId),A.classList.remove("random-global","random-local"),"global"===e.randomGameId?A.classList.add("random-global"):"local"===e.randomGameId&&A.classList.add("random-local")};V(),A.onclick=t=>{if(t.shiftKey&&t.altKey)return t.preventDefault(),void dt(t,e);if(t.altKey)return e.showBlockedVocabAlert=!e.showBlockedVocabAlert,e.settingsManager.saveSettings(),V(),void alert(e.showBlockedVocabAlert?"✔️ Предупреждение о заблокированных словарях включено.":"❌ Предупреждение о заблокированных словарях отключено.");if(t.shiftKey){fetch("https://raw.githubusercontent.com/VimiummuimiV/KG_Latest_Games/refs/heads/main/src/etc/valid_vocabularies.txt",{cache:"no-store"}).then((e=>{if(!e.ok)throw new Error("Network response was not ok: "+e.status);return e.json()})).then((t=>{try{const a=e.settingsManager.saveValidVocabularies(t.validVocabularies||{}),r=Object.values(a).flat().length;V(),alert(`✔️ Список словарей обновлён, записано ${r} ID.`)}catch(e){console.warn("Could not save valid vocabularies via SettingsManager",e),alert("⚠️ Не удалось сохранить список в localStorage.")}})).catch((e=>{console.warn("Failed to fetch valid vocabularies:",e),alert("⚠️ Ошибка загрузки списка допустимых словарей: "+e.message)}))}else{if(t.ctrlKey)return e.randomGameId="global"!==e.randomGameId&&"global",e.settingsManager.saveSettings(),void V();e.randomGameId="local"!==e.randomGameId&&"local",e.settingsManager.saveSettings(),V()}};const H=X("span",{className:"latest-games-start control-button",innerHTML:$.start});W(H,"\n [Shift + Enter | Клик] Начать игру (последняя или следующая: работает только на странице игры)\n [Ctrl + Shift + Enter | Клик] Пройти квалификацию по словарю\n [Shift + Alt + Enter | Клик] Добавить текущий словарь в Избранные\n ");const B=e=>{try{const t=new URL(e);return t.searchParams.set("qual","1"),t.toString()}catch(t){return e}},j=(t=!1)=>{const a=!t&&e.randomGameId;let r=null;try{if("game"===J()&&!a&&!t){const a=e.groupsManager.getCurrentGroup(e.groupsManager.groups,e.groupsManager.currentGroupId);if(!a||!Array.isArray(a.games)||0===a.games.length)return alert("❌ Нет игр в текущей группе");const r=e.gamesManager.getPreviousGameId();let n=a.games.findIndex((e=>String(e.id)===String(r)));n=-1===n?0:(n+1)%a.games.length;const o=a.games[n];if(!o)return alert("❌ Не удалось определить следующую игру");e.groupsManager.selectGroup(a.id),e.gamesManager.latestGamesData=e.gamesManager.latestGamesData||{},e.gamesManager.latestGamesData.previousGameId=o.id,e.gamesManager.saveGameData();const s=String(o.params?.vocId||"");if(s)try{e.gamesManager.registerPendingPlayed(s,o.params?.vocName||null,o.params?.vocType||null)}catch(e){}const i=e.gamesManager.generateGameLink(o);return void(location.href=t?B(i):i)}}catch(e){console.warn("Error selecting next game in group",e)}if(a){if(r=e.gamesManager.getRandomGameId(),!r)return alert("❌ Нет подходящей игры")}else{const t=e.gamesManager.getPreviousGameId();if(!t)return alert("❌ Нет подходящей игры");const a=e.gamesManager.findGameById(t);if(!a)return alert("❌ Игра не найдена");r={mode:"local",id:t,game:a,groupId:e.groupsManager.currentGroupId,url:e.gamesManager.generateGameLink(a)}}if("local"!==r.mode)"global"!==r.mode||(async()=>{const a=await e.gamesManager.getValidRandomGameId();if(!a)return alert("🔒 Максимальное количество попыток поиска подходящей игры исчерпано. Попробуйте ещё раз.");if(a.id)try{e.gamesManager.registerPendingPlayed(a.id)}catch(e){}window.location.href=t?B(a.url):a.url})();else{if(r.groupId)e.groupsManager.selectGroup(r.groupId);else for(const t of e.groupsManager.groups)if(t.games.some((e=>e.id===r.id))){e.groupsManager.selectGroup(t.id);break}e.gamesManager.latestGamesData=e.gamesManager.latestGamesData||{},e.gamesManager.latestGamesData.previousGameId=r.id,e.gamesManager.saveGameData();const a=String(r.game.params.vocId||"");if(a)try{e.gamesManager.registerPendingPlayed(a,r.game.params.vocName||null,r.game.params.vocType||null)}catch(e){}if(!r.url){if(!r.game)return alert("❌ Игра не найдена");r.url=e.gamesManager.generateGameLink(r.game)}location.href=t?B(r.url):r.url}};async function q(){if("game"!==J())return alert("⚠️ Блокировать словарь можно только на странице игры"),!1;const e=Me();if(!e)return alert("⚠️ Не удалось определить ID текущего словаря"),!1;try{it.currentListType="bannedVocabularies";const t=it.get();if(t.some((t=>t.id===String(e))))return alert(`🛑 Словарь ${e} уже в чёрном списке`),!1;const a=await Se(e).catch((()=>null)),r={id:String(e),name:a?.vocabularyName||null,author:a?.vocabularyAuthor||null,vocType:a?.vocabularyType||null,isNew:!0},n=[...t,r];it.save(n,!1),alert(`✔️ Словарь ${e} добавлен в чёрный список`);try{j()}catch(e){console.warn("Could not start a new game after banning vocabulary",e)}return!0}catch(e){return console.error("Error banning vocabulary:",e),alert("⚠️ Ошибка при блокировке словаря"),!1}}function P(){if("game"!==J())return alert("⚠️ Добавлять в Избранные можно только на странице игры"),!1;const t=Me();if(!t)return alert("⚠️ Не удалось определить ID текущего словаря"),!1;let a=e.groupsManager.groups.find((e=>"Избранные"===e.title));if(!a){const t=e.groupsManager.createGroup("Избранные");e.groupsManager.groups.push(t),a=t}(async()=>{try{let r="",n=null;const o=await Se(t).catch((()=>null));o&&o.vocabularyName&&(r=o.vocabularyName,n=o.vocabularyType||null);const s=e.groupsManager.groups.find((e=>e.games.some((e=>String(e.params?.vocId)===String(t)))));if(s)return void(s.id===a.id?alert(`🛑 Словарь ${t} уже в группе "Избранные"`):alert(`🛑 Словарь ${t} уже в группе "${s.title}"`));Ee(a,String(t),r,n,e.groupsManager.groups,e),alert(`✔️ Словарь ${t} добавлен в группу "Избранные"`);const i=a.games.find((e=>String(e.params?.vocId)===String(t)));if(i){const t={clientX:Math.floor(window.innerWidth/2),clientY:Math.floor(window.innerHeight/2)};try{Ne(e,e.groupsManager.groups,a.id,t,i.id)}catch(e){console.warn("Could not open migration popup for newly added vocabulary",e)}}}catch(e){console.warn("Could not add vocabulary to favorites group",e),alert("⚠️ Не удалось добавить словарь в Избранные")}})()}H.onclick=e=>e.altKey&&e.shiftKey?(e.preventDefault(),void P()):e.ctrlKey&&e.shiftKey?(e.preventDefault(),void j(!0)):void j();const z=X("span",{className:"latest-games-ban-vocabulary control-button",innerHTML:$.slash});W(z,"\n [Клик] Показать заблокированные словари\n [Alt + Enter | Alt + Клик] Заблокировать текущий словарь\n "),z.onclick=e=>{e.altKey?(e.preventDefault(),q()):(e.stopPropagation(),it.toggle(e.clientX,e.clientY,"bannedVocabularies"))};const R=X("span",{className:"latest-games-played-vocabularies control-button",innerHTML:$.book});W(R,"Показать проигранные словари"),R.onclick=e=>{e.stopPropagation(),it.toggle(e.clientX,e.clientY,"playedVocabularies")},document.addEventListener("keydown",(e=>e.altKey&&e.shiftKey&&"Enter"===e.code?(e.preventDefault(),void P()):e.ctrlKey&&e.shiftKey&&"Enter"===e.code?(e.preventDefault(),void j(!0)):e.shiftKey&&"Enter"===e.code?void j():e.altKey&&"Enter"===e.code?(e.preventDefault(),void q()):void 0));const _=X("span",{className:"latest-games-vocabulary-data control-button",innerHTML:$.vocabularyData}),Y=()=>{W(_,e.showVocabularyData?"Скрыть содержимое словаря":"Показать содержимое словаря"),_.classList.toggle("latest-games-disabled",!e.showVocabularyData)};Y(),_.addEventListener("click",(()=>{e.showVocabularyData=!e.showVocabularyData,e.settingsManager.saveSettings(),Y(),e.uiManager.refreshContainer()}));const K=[m,v,b,A,H,z,R],F=[e.themeManager.createThemeToggle(),e.viewManager.createDisplayModeToggle(),d,u,f,x,w,k,M,C,S,E,G,L,I,_],Z=X("span",{className:"latest-games-more-toggle control-button",innerHTML:$.moreHorizontal});K.forEach((e=>n.appendChild(e))),n.appendChild(Z),W(Z,"Показать дополнительные кнопки"),F.forEach((e=>o.appendChild(e)));const Q=()=>{o.classList.remove("open"),Z.classList.remove("open"),document.removeEventListener("click",ee)},ee=e=>{r.contains(e.target)||Q()};return Z.addEventListener("click",(e=>{e.stopPropagation(),o.classList.contains("open")?Q():(o.classList.add("open"),Z.classList.add("open"),setTimeout((()=>{document.addEventListener("click",ee)}),0))})),t}function mt(e){const t=X("div",{id:"latest-games-hover-area"});t.addEventListener("mouseenter",(()=>ht(e))),t.addEventListener("mouseleave",(()=>vt(e))),document.body.appendChild(t)}function ht(e){e.isHovered=!0,e.hoverTimeout&&clearTimeout(e.hoverTimeout),e.hoverTimeout=null;const t=document.getElementById("latest-games-container");if(t){const a=t.classList.contains("visible");if(t.classList.add("visible"),t.style.left="0","wrap"===e.viewManager.getDisplayMode()&&(t.style.top=`${e.panelYPosition}vh`),t.scrollTop=e.previousScrollPosition,!a){const e=t.querySelector(".latest-game.previous-game");e&&(e.style.animation="none",setTimeout((()=>e.style.animation=""),10))}}}function vt(e){const t=J();(e.alwaysVisiblePanel[t]??!1)||(e.isHovered=!1,e.hoverTimeout&&clearTimeout(e.hoverTimeout),e.hoverTimeout=setTimeout((()=>{if(!e.isHovered){const t=document.getElementById("latest-games-container");t&&(t.classList.remove("visible"),e.viewManager.updateContainerLeftOffset())}}),e.hidePanelDelay))}function bt(e){const t=document.getElementById("latest-games-container"),a=J(),r=e.alwaysVisiblePanel[a]??!1;return`\n [Клик] ${t&&t.classList.contains("visible")?"Скрыть":"Показать"} панель\n [Shift + Клик] ${r?"Открепить":"Закрепить"} панель\n [Ctrl + Клик] Изменить задержку скрытия панели\n (${e.hidePanelDelay??D.hidePanelDelay} мс)\n `}function yt(e){if(document.getElementById("latest-games-panel-toggle"))return;const t=J(),a=e.alwaysVisiblePanel[t]??!1,r=X("button",{id:"latest-games-panel-toggle",className:"latest-games-panel-toggle",type:"button",innerHTML:a?$.panelToggleOpened:$.panelToggleClosed}),n=document.getElementById("latest-games-container"),o=()=>{Y(r,bt(e))};r.addEventListener("mouseenter",o),W(r,bt(e)),a&&r.classList.add("always-visible"),n&&(n.classList.toggle("visible",a),a||e.viewManager.updateContainerLeftOffset()),r.addEventListener("click",(t=>{const a=document.getElementById("latest-games-container");if(!a)return;const n=J();if(t.ctrlKey){const t=e.hidePanelDelay??D.hidePanelDelay,a=prompt("Изменить задержку автоскрытия панели в миллисекундах:",t),r=parseInt(a,10);!isNaN(r)&&r>=0?(e.hidePanelDelay=r,e.settingsManager.saveSettings()):null!==a&&alert("Пожалуйста, введите корректное значение задержки.")}else if(t.shiftKey){e.alwaysVisiblePanel[n]=!e.alwaysVisiblePanel[n];const t=e.alwaysVisiblePanel[n];r.classList.toggle("always-visible",t),r.innerHTML=t?$.panelToggleOpened:$.panelToggleClosed,a.classList.toggle("visible",t),t||e.viewManager.updateContainerLeftOffset(),e.settingsManager.saveSettings(),o()}else{a.classList.contains("visible")?(e.hoverTimeout&&(clearTimeout(e.hoverTimeout),e.hoverTimeout=null),a.classList.remove("visible"),e.viewManager.updateContainerLeftOffset()):e.uiManager.showContainer(),o()}})),document.body.appendChild(r)}class ft{constructor(e){this.main=e,this.createGameElement=et.bind(null,this.main),this.createControls=ut.bind(null,this.main),this.createSearchBox=nt.bind(null,this.main),this.createHoverArea=mt.bind(null,this.main),this.showContainer=ht.bind(null,this.main),this.hideContainer=vt.bind(null,this.main),this.createPanelToggleButton=yt.bind(null,this.main)}scrollToPreviousGame(){const e=document.getElementById("latest-games-content"),t=document.querySelector(".previous-game");if(!e||!t)return;const a=e.getBoundingClientRect(),r=t.getBoundingClientRect(),n=r.top-a.top-a.height/2+r.height/2;e.scrollTop+=n}createContainer(){const e=X("div",{id:"latest-games-container"});e.addEventListener("mouseenter",(()=>{this.showContainer(),requestAnimationFrame((()=>this.scrollToPreviousGame()))}));const t=X("div",{id:"latest-games-content"}),a=this.createSearchBox();t.appendChild(a);const r=this.main.groupsManager.createGroupsContainer();t.appendChild(r);const n=X("ul",{id:"latest-games"});this.populateGamesList(n),t.appendChild(n);const o=this.createControls();e.append(o,t),t.addEventListener("scroll",(()=>{this.main.previousScrollPosition=t.scrollTop,this.main.settingsManager.saveSettings()})),e.addEventListener("mouseenter",(()=>this.showContainer())),e.addEventListener("mouseleave",(()=>this.hideContainer()));let s=null,i=!1;const l=e=>{const t=e.target.closest(".latest-game");if(!t)return;const a=t.id.replace("latest-game-",""),r=this.main.gamesManager.findGameById(a);r&&!this.main.enableDragging&&ze(r,e,this.main)};n.addEventListener("mousedown",(e=>{0===e.button&&(s=setTimeout((()=>{i=!0,e.preventDefault(),l(e)}),300))})),n.addEventListener("mouseup",(()=>{clearTimeout(s)})),n.addEventListener("click",(e=>{i&&(e.stopImmediatePropagation(),e.preventDefault(),i=!1)}),{capture:!0}),n.addEventListener("contextmenu",(e=>{const t=e.target.closest(".latest-game");if(t){e.preventDefault();const a=t.id.replace("latest-game-","");Ne(this.main,this.main.groupsManager.groups,this.main.groupsManager.currentGroupId,e,a)}}));let c=e.querySelector(".resize-handle-horizontal");c||(c=X("div",{className:"resize-handle-horizontal"}),e.appendChild(c));let p=e.querySelector(".resize-handle-vertical-bottom");p||(p=X("div",{className:"resize-handle-vertical resize-handle-vertical-bottom"}),e.appendChild(p));let g=e.querySelector(".resize-handle-vertical-top");g||(g=X("div",{className:"resize-handle-vertical resize-handle-vertical-top"}),e.appendChild(g)),_e(this,e,c,p,g),We(this,e),document.body.appendChild(e),this.main.groupsManager.updateGroupControlStates(),this.main.viewManager.updateDisplayModeClass();e.querySelectorAll(".group-tab").forEach((e=>{e.getBoundingClientRect().width>=300&&W(e,e.textContent)}));const d=this.main.viewManager.updateDisplayModeClass.bind(this.main.viewManager);this.main.viewManager.updateDisplayModeClass=(...t)=>{d(...t),_e(this,e,c,p,g),We(this,e)},this.updateRemoveIcons(),setTimeout((()=>requestAnimationFrame((()=>this.scrollToPreviousGame()))),100)}updateGameCountDisplay(){const e=document.getElementById("latest-games-count");e&&(e.textContent=this.main.maxGameCount.toString(),e.classList.toggle("latest-games-disabled",!1===this.main.shouldAutoSave),W(e,this.main.shouldAutoSave?"Автосохранение включено":"Автосохранение отключено"))}populateGamesList(e){if(e.innerHTML="","tabs"===this.main.groupsManager.getGroupViewMode()){const t=this.main.groupsManager.getCurrentGroup();if(!t)return;const a=this.main.groupsManager.getPinnedGameCount(),r=Math.min(t.games.length,this.main.maxGameCount+a);for(let a=0;a{if(t.games.length>0){const a=this.main.groupsManager.createGroupHeader(t);e.appendChild(a);const r=t.games.filter((e=>e.pin)).length,n=Math.min(t.games.length,this.main.maxGameCount+r);for(let a=0;a0?$.trashSomething:$.trashNothing);const a=document.querySelector(".latest-games-removeall.control-button"),r=this.main.groupsManager.groups.some((e=>e.games&&e.games.length>0));a&&(a.innerHTML=r?$.trashSomething:$.trashNothing)}refreshContainer(){this.main.groupsManager.refreshGroupsContainer();const e=document.getElementById("latest-games");e&&(this.populateGamesList(e),this.main.viewManager.updateDisplayModeClass()),this.updateRemoveIcons(),this.updateGameCountDisplay(),requestAnimationFrame((()=>this.scrollToPreviousGame()))}}class xt{constructor(e){this.mainManager=e}parseGameParams(e,t){const a=e.className.split("-").pop(),r="voc"===a?e.textContent.replace(/[«»]/g,""):"";let n="";if("voc"===a){const t=e.querySelector("a");if(t){const e=t.href.match(/vocs\/(\d+)/);n=e?parseInt(e[1],10):""}}let o="normal";/одиночный/.test(t)?o="practice":/друзьями/.test(t)&&(o="private");let s=1,i=9;const l=t.match(/для (\S+)–(\S+),/);l&&(s=T[l[1]]||1,i=T[l[2]]||9);const c=t.match(/таймаут\s(\d+)\s(сек|мин)/);return{gametype:a,vocName:r,vocId:n,vocType:null,type:o,level_from:s,level_to:i,timeout:c?"сек"===c[2]?parseInt(c[1],10):60*parseInt(c[1],10):60,qual:/квалификация/.test(t)?1:0,premium_abra:0}}generateGameName(e,t={}){const a=C[e.params.gametype],{vocName:r,timeout:n,type:o,level_from:s,level_to:i,qual:l}=e.params;let c="";t&&t.stateIcon&&(c=t.stateIcon);const p=X("span",{className:`latest-game-name gametype-${e.params.gametype}`});if(p.appendChild(document.createTextNode(""===r?a:`«${r}»`)),c){const e=X("span",{className:"latest-game-state-icon",innerHTML:c});p.appendChild(e)}let g=null;this.mainManager.showButtonDescriptions&&(g=X("span",{className:"latest-game-description"}));const d=X("span",{className:"latest-game-qual",innerHTML:l?$.qualification:""});let u="";if(1!==s||9!==i){u=` ${L[s-1]} - ${L[i-1]}`}const m=X("span",{className:"latest-game-levels",textContent:u});g&&(g.textContent=`${G[o]}, ${n} секунд`,g.appendChild(d),u&&g.appendChild(m));const h=X("div");return h.appendChild(p),g&&h.appendChild(g),h.innerHTML}generateGameLink(e){const{gametype:t,vocId:a,type:r,level_from:n,level_to:o,timeout:s,qual:i}=e.params,l=new URLSearchParams({gametype:t,type:r,timeout:s.toString(),submit:"1"});return"practice"!==r&&"private"!==r&&(l.set("level_from",n.toString()),l.set("level_to",o.toString())),""!==a&&l.set("voc",a),i&&l.set("qual","1"),`${location.protocol}//klavogonki.ru/create/?${l.toString()}`}loadGameData(){try{let e=localStorage.getItem("latestGamesData");if(e)if(e=JSON.parse(e),Array.isArray(e)){const t=[{id:U(e),title:"Группа-1",games:e}],a=t[0].id;this.mainManager.groupsManager.setGroups(t,a),this.latestGamesData={}}else e&&Array.isArray(e.groups)?(this.mainManager.groupsManager.setGroups(e.groups,e.currentGroupId),this.latestGamesData={previousGameId:e.previousGameId,latestGroupAddedGameId:e.latestGroupAddedGameId}):(this.mainManager.groupsManager.setGroups([],null),this.latestGamesData={});else this.mainManager.groupsManager.setGroups([],null),this.latestGamesData={};this.migrateOldGameData(),this.assignGameIds()}catch(e){console.warn("Could not load game data from localStorage:",e),this.mainManager.groupsManager.setGroups([],null),this.latestGamesData={}}}saveGameData(){try{const e={groups:this.mainManager.groupsManager.groups,currentGroupId:this.mainManager.groupsManager.currentGroupId,previousGameId:this.latestGamesData?.previousGameId,latestGroupAddedGameId:this.latestGamesData?.latestGroupAddedGameId};localStorage.setItem("latestGamesData",JSON.stringify(e))}catch(e){console.warn("Could not save game data to localStorage:",e)}}migrateOldGameData(){this.mainManager.groupsManager.groups.forEach((e=>{e.games=e.games.map((e=>("on"!==e.params.qual&&""!==e.params.qual||(e.params.qual="on"===e.params.qual?1:0),e)))}))}assignGameIds(){const e=new Set;this.mainManager.groupsManager.groups.forEach((t=>{t.games.forEach((t=>{t.id&&e.add(t.id)}))})),this.mainManager.groupsManager.groups.forEach((t=>{t.games=t.games.map((t=>{if(t.id&&-1!==t.id)return e.add(t.id),t;{const a=U(this.mainManager.groupsManager.groups);return e.add(a),{...t,id:a}}}))}))}updateGameOrderFromDOM(){const e=this.mainManager.groupsManager.getCurrentGroup(this.mainManager.groupsManager.groups,this.mainManager.groupsManager.currentGroupId);if(!e)return;const t=Array.from(document.querySelectorAll("#latest-games .latest-game"));e.games=t.map((t=>{const a=t.id.replace("latest-game-","");return e.games.find((e=>e.id===a))})).filter((e=>void 0!==e)),this.saveGameData()}findGameIndex(e){for(const t of this.mainManager.groupsManager.groups){const a=t.games.findIndex((t=>t.id==e));if(-1!==a)return{group:t,index:a}}return null}findGameById(e){for(const t of this.mainManager.groupsManager.groups){const a=t.games.find((t=>t.id===e));if(a)return a}return null}deleteGame(e){const t=this.findGameIndex(e);if(!t)return null;const{group:a,index:r}=t,n=a.games.splice(r,1)[0];return this.assignGameIds(),this.saveGameData(),this.mainManager.uiManager.refreshContainer(),n}pinGame(e){const t=this.findGameIndex(e);if(!t)return;const{group:a,index:r}=t,n=a.games[r];n.pin=n.pin?0:1,a.games.sort(((e,t)=>t.pin-e.pin)),this.assignGameIds(),this.saveGameData(),this.mainManager.uiManager.refreshContainer()}changeGameCount(e){e<0&&this.mainManager.maxGameCount>0?this.mainManager.maxGameCount--:e>0&&this.mainManager.maxGameCount++,this.mainManager.uiManager.updateGameCountDisplay(),this.mainManager.settingsManager.saveSettings(),this.mainManager.uiManager.refreshContainer()}getPreviousGameId(){return this.latestGamesData&&this.latestGamesData.previousGameId?this.latestGamesData.previousGameId:null}getRandomGame(){if(!(this.mainManager&&this.mainManager.validVocabularies&&"object"==typeof this.mainManager.validVocabularies&&this.mainManager.randomVocabulariesType&&"object"==typeof this.mainManager.randomVocabulariesType))return null;const e=new Set;try{const t=localStorage.getItem("bannedVocabularies");if(t){const a=JSON.parse(t);Array.isArray(a)&&a.forEach((t=>{const a="string"==typeof t?t:t.id||String(t);e.add(String(a))}))}const a=localStorage.getItem("playedVocabularies");if(a){const t=JSON.parse(a);Array.isArray(t)&&t.forEach((t=>{const a="string"==typeof t?t:t.id||String(t);e.add(String(a))}))}}catch(e){console.warn("Could not parse banned/played vocabularies",e)}const t=Object.keys(this.mainManager.randomVocabulariesType).filter((e=>!0===this.mainManager.randomVocabulariesType[e]));if("global"===this.mainManager.randomGameId){const a=t.flatMap((e=>this.mainManager.validVocabularies[e]||[])).filter((t=>null!=t&&!e.has(String(t))));if(0===a.length)return null;return{mode:"global",params:{gametype:"voc",vocName:"",vocId:a[Math.floor(Math.random()*a.length)],vocType:null,type:"normal",level_from:1,level_to:9,timeout:10,qual:0,premium_abra:0}}}const a=[];if(this.mainManager.groupsManager.groups.forEach((r=>{r.games.forEach((n=>{const o=String(n.params.vocId||"");!(o&&e.has(o))&&n.params.vocType&&t.includes(n.params.vocType)&&a.push({game:n,groupId:r.id})}))})),0===a.length)return null;const r=Math.floor(Math.random()*a.length);return{mode:"local",game:a[r].game,groupId:a[r].groupId}}getRandomGameId(){const e=this.getRandomGame();if(!e)return null;if("global"===e.mode){const t={params:e.params};return{mode:"global",id:e.params.vocId,params:e.params,url:this.generateGameLink(t)}}return{mode:"local",id:e.game?e.game.id:null,game:e.game,groupId:e.groupId,url:e.game?this.generateGameLink(e.game):null}}async getValidRandomGameId(e=50){const t=!e||e<=0;for(let a=0;t||a("string"==typeof e?e:e.id)===r));if(-1!==i){"string"==typeof n[i]&&(n[i]={id:n[i],playHistory:[]}),n[i].playHistory||(n[i].playHistory=[]);const e=n[i].playHistory.find((e=>{const t=new Date(e.date);return t.setHours(0,0,0,0),t.toISOString()===s}));e?e.count++:n[i].playHistory.push({date:s,count:1}),n[i].playedAt=(new Date).toISOString(),n[i].isNew=!0}else{const e=t&&a?null:await Se(r).catch((()=>null));n.push({id:r,name:t||e?.vocabularyName||null,author:e?.vocabularyAuthor||null,vocType:a||e?.vocabularyType||null,isNew:!0,playedAt:(new Date).toISOString(),playHistory:[{date:s,count:1}]})}localStorage.setItem("playedVocabularies",JSON.stringify(n));try{this.registerPendingPlayed(r)}catch(e){}}catch(e){}}}Object.values(b).forEach((e=>{if(!document.getElementById(e.id)){const t=document.createElement("link");t.id=e.id,t.rel="stylesheet",t.href=e.url,document.head.appendChild(t)}})),window.latestGamesManager??=new class{constructor(){this.initializeDefaults(),this.initializeManagers(),this.init()}initializeDefaults(){Object.assign(this,D)}initializeManagers(){this.themeManager=new te(this),this.settingsManager=new ae(this),this.groupsManager=new re(this),this.viewManager=new ne(this),this.pageHandler=new De(this),this.uiManager=new ft(this),this.gamesManager=new xt(this)}init(){this.settingsManager.loadSettings(),this.gamesManager.loadGameData(),this.groupsManager.initializeGroups(),this.uiManager.createHoverArea(),this.uiManager.createContainer(),this.alwaysVisiblePanel&&this.uiManager.showContainer(),this.uiManager.createPanelToggleButton(),this.pageHandler.handlePageSpecificLogic(),this.exposeGlobalFunctions(),this.themeManager.applyTheme()}exposeGlobalFunctions(){window.latestGamesManager=this}}})();