PageSourceSearch

https://minigames-sand-delta.vercel.app/assets/index-cYDtCzMc.js

js minigames-sand-delta.vercel.app collected 2026-10-03 05:48:42 UTC 76,165 bytes, 805 lines download raw bytes

vendor: 6,157 bytes, lines 1-14
1(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2<path d="M7 14H14V12.5H7V14ZM7 11.25H17V9.75H7V11.25ZM7 8.5H17V7H7V8.5ZM4 20V5.5C4 5.08333 4.14583 4.72917 4.4375 4.4375C4.72917 4.14583 5.08333 4 5.5 4H18.5C18.9167 4 19.2708 4.14583 19.5625 4.4375C19.8542 4.72917 20 5.08333 20 5.5V15.5C20 15.9167 19.8542 16.2708 19.5625 16.5625C19.2708 16.8542 18.9167 17 18.5 17H7L4 20ZM6.375 15.5H18.5V5.5H5.5V16.375L6.375 15.5ZM5.5 15.5V5.5V15.5Z" fill="currentColor"/>
3</svg>
4`,t=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
5<path d="M6.5 19C6.08333 19 5.72917 18.8542 5.4375 18.5625C5.14583 18.2708 5 17.9167 5 17.5C5 17.0833 5.14583 16.7292 5.4375 16.4375C5.72917 16.1458 6.08333 16 6.5 16C6.91667 16 7.27083 16.1458 7.5625 16.4375C7.85417 16.7292 8 17.0833 8 17.5C8 17.9167 7.85417 18.2708 7.5625 18.5625C7.27083 18.8542 6.91667 19 6.5 19ZM17 19C17 17.3333 16.6806 15.7778 16.0417 14.3333C15.4167 12.875 14.5625 11.6042 13.4792 10.5208C12.3958 9.4375 11.125 8.58333 9.66667 7.95833C8.22222 7.31944 6.66667 7 5 7V5C6.94444 5 8.75694 5.36806 10.4375 6.10417C12.1319 6.82639 13.6181 7.82639 14.8958 9.10417C16.1736 10.3819 17.1736 11.8681 17.8958 13.5625C18.6319 15.2431 19 17.0556 19 19H17ZM12 19C12 18.0278 11.8194 17.1181 11.4583 16.2708C11.0972 15.4236 10.5972 14.6806 9.95833 14.0417C9.31944 13.4028 8.57639 12.9028 7.72917 12.5417C6.88194 12.1806 5.97222 12 5 12V10C6.26389 10 7.4375 10.2361 8.52083 10.7083C9.60417 11.1667 10.5556 11.8056 11.375 12.625C12.1944 13.4444 12.8333 14.3958 13.2917 15.4792C13.7639 16.5625 14 17.7361 14 19H12Z" fill="currentColor"/>
6</svg>
7`,n=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
8<path d="M15.5 20.2065C14.8056 20.2065 14.2153 19.9635 13.7292 19.4774C13.2431 18.9913 13 18.401 13 17.7065C13 17.5815 13.0278 17.3802 13.0833 17.1024L8.14583 14.0815C7.92361 14.276 7.67361 14.4288 7.39583 14.5399C7.11806 14.651 6.81944 14.7065 6.5 14.7065C5.80556 14.7065 5.21528 14.4635 4.72917 13.9774C4.24306 13.4913 4 12.901 4 12.2065C4 11.5121 4.24306 10.9218 4.72917 10.4357C5.21528 9.9496 5.80556 9.70654 6.5 9.70654C6.81944 9.70654 7.11806 9.7621 7.39583 9.87321C7.67361 9.98432 7.92361 10.1371 8.14583 10.3315L13.0833 7.31071C13.0556 7.21349 13.0347 7.11627 13.0208 7.01904C13.0069 6.92182 13 6.81765 13 6.70654C13 6.0121 13.2431 5.42182 13.7292 4.93571C14.2153 4.4496 14.8056 4.20654 15.5 4.20654C16.1944 4.20654 16.7847 4.4496 17.2708 4.93571C17.7569 5.42182 18 6.0121 18 6.70654C18 7.40099 17.7569 7.99127 17.2708 8.47738C16.7847 8.96349 16.1944 9.20654 15.5 9.20654C15.1806 9.20654 14.8819 9.15099 14.6042 9.03988C14.3264 8.92877 14.0764 8.77599 13.8542 8.58154L8.91667 11.6024C8.94444 11.6996 8.96528 11.7968 8.97917 11.894C8.99306 11.9913 9 12.0954 9 12.2065C9 12.3177 8.99306 12.4218 8.97917 12.519C8.96528 12.6163 8.94444 12.7135 8.91667 12.8107L13.8542 15.8315C14.0764 15.6371 14.3264 15.4843 14.6042 15.3732C14.8819 15.2621 15.1806 15.2065 15.5 15.2065C16.1944 15.2065 16.7847 15.4496 17.2708 15.9357C17.7569 16.4218 18 17.0121 18 17.7065C18 18.401 17.7569 18.9913 17.2708 19.4774C16.7847 19.9635 16.1944 20.2065 15.5 20.2065ZM15.5 18.7065C15.7778 18.7065 16.0139 18.6093 16.2083 18.4149C16.4028 18.2204 16.5 17.9843 16.5 17.7065C16.5 17.4288 16.4028 17.1927 16.2083 16.9982C16.0139 16.8038 15.7778 16.7065 15.5 16.7065C15.2222 16.7065 14.9861 16.8038 14.7917 16.9982C14.5972 17.1927 14.5 17.4288 14.5 17.7065C14.5 17.9843 14.5972 18.2204 14.7917 18.4149C14.9861 18.6093 15.2222 18.7065 15.5 18.7065ZM6.5 13.2065C6.77778 13.2065 7.01389 13.1093 7.20833 12.9149C7.40278 12.7204 7.5 12.4843 7.5 12.2065C7.5 11.9288 7.40278 11.6927 7.20833 11.4982C7.01389 11.3038 6.77778 11.2065 6.5 11.2065C6.22222 11.2065 5.98611 11.3038 5.79167 11.4982C5.59722 11.6927 5.5 11.9288 5.5 12.2065C5.5 12.4843 5.59722 12.7204 5.79167 12.9149C5.98611 13.1093 6.22222 13.2065 6.5 13.2065ZM15.5 7.70654C15.7778 7.70654 16.0139 7.60932 16.2083 7.41488C16.4028 7.22043 16.5 6.98432 16.5 6.70654C16.5 6.42877 16.4028 6.19265 16.2083 5.99821C16.0139 5.80377 15.7778 5.70654 15.5 5.70654C15.2222 5.70654 14.9861 5.80377 14.7917 5.99821C14.5972 6.19265 14.5 6.42877 14.5 6.70654C14.5 6.98432 14.5972 7.22043 14.7917 7.41488C14.9861 7.60932 15.2222 7.70654 15.5 7.70654Z" fill="currentColor"/>
9</svg>
10`,r=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
11<rect width="24" height="24" rx="12" fill="white"/>
12<path d="M9.6 16.5L5.6 12.5L9.6 8.5L10.45 9.35L7.3 12.5L10.45 15.65L9.6 16.5ZM14.4 16.5L13.55 15.65L16.7 12.5L13.55 9.35L14.4 8.5L18.4 12.5L14.4 16.5Z" fill="currentColor"/>
13</svg>
14`,i=`data:image/svg+xml,%3csvg%20width='32'%20height='32'%20viewBox='0%200%2032%2032'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%20xmlns:xlink='http://www.w3.org/1999/xlink'%3e%3cg%20clip-path='url(%23clip0_1_258)'%3e%3cpath%20d='M26%201H6C3.23858%201%201%203.23858%201%206V26C1%2028.7614%203.23858%2031%206%2031H26C28.7614%2031%2031%2028.7614%2031%2026V6C31%203.23858%2028.7614%201%2026%201Z'%20fill='url(%23pattern0_1_258)'%20stroke='%23242145'%20stroke-width='2'/%3e%3c/g%3e%3cdefs%3e%3cpattern%20id='pattern0_1_258'%20patternContentUnits='objectBoundingBox'%20width='1'%20height='1'%3e%3cuse%20xlink:href='%23image0_1_258'%20transform='scale(0.03125)'/%3e%3c/pattern%3e%3cclipPath%20id='clip0_1_258'%3e%3crect%20width='32'%20height='32'%20fill='white'/%3e%3c/clipPath%3e%3cimage%2
140id='image0_1_258'%20width='32'%20height='32'%20preserveAspectRatio='none'%20xlink:href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAOdEVYdFNvZnR3YXJlAEZpZ21hnrGWYwAABCNJREFUeAG1V91rXEUU/83szeazNj5YTRVJQWoEg1YqKD6of4KKL2KxD4qPPuiLltpabKlatUIefFFEQQT7KAhFSAVfRKFSQQShXbWUZrMJCdm0m9175/TM1/3YvR9J0x52mLkzc875na+ZHcAREU1yO6KI5rnRbWrnQ6KDSJFwyqcJmOfhNMqIPMe2qcFinhVCNIw4RnapUvmtR6SV76uRdcnBm5Mryhn8dP7yJE9vCB0X/ngUt4y25JVzGgBtT8b2MMjcWVEhnTGTUuh2Q9PrJtKsWwAvsSUi81OK8MHps9j/9EnMPnEcn8z9pBM5DvdWKD8EfjEWmPKpViQE9swexq5dO3mW0Gyu4eKfx7JQDUt1LEo9QBko2WGnG9k9/N3rRYM8pbGgzQHwm3u9EKFWYtxshX564gV4BB+ffD7ZrXOD96soyYvBuCTASkNgmQkX/rqMA699g4iFs1yjZGJiGEGtZmSFoUK73UEgJfjH8xJfff4yHpm9vzIngirlmu69507U6wFqtRyHkVU4uXMsmWKUU1OTsa2UsptSfHqiPATOU2NjdWNlpr6LeqZeFOGOidFYT1pnv+xyAI5jZDiwNS98dts1kTbJR5Lnuhuh8ZjZg/I6CNKAKFaqjDwpLT5ddpGiRJDKyStfdowy5L1SJmqV+87LB5nmt9p0nUu8+fYZ7H3sKO6bOYSvv/sVE+PDzgNkeo2GPPI+C3aMj+DbM79h94Pv4IF9R/DWoe8NiDzKVoEbdrnkHn/mFEZHAqNM5PGKxGg9Zk
14FQukdiqYQGKzgkEX45+wbGR0cs+BQFGR+6oJIWpnTMa1ZgfKWm71fbKQeQZAqM26EMC7FBG2xMPTcZZMYk19frNbx64Ek0F9Zx+f8lzH34ojmMtALhDiPh8Eple0HJUa2T8PSJ53D1ygoWFtt4/ZWnjNy8g7nwINKHjU9CTXv3H+Nat6VllPHSUusaJ2eEu+/aYYSTuSeA1dXr+Pv3d2NepW9LmVOvKClDwcpNwhGZBBoyh5CznIcPz+zGP+cP49KF9/DQzFRGrD4RtVJjiJNVVJCDAHL80dnoYWgoMO7XMpoLbXwx95IpT01f8ri1vB6fCwGHsNMJE4HWPcijQQA5ibKyeg31wGcbIRjqY2HNxmIX5HpQQ3u9k5VZcBrJEr2uKoB//1vG4lKbLV9Ds7XGNx3h+Ec/WPsY0PunfuRkgllb5P8GreU2LjZaiRwq1LCJ27AAILlw+NX+deX+uFSRzKIsIB/GuFHsHX+ymIRN7ckop2IdGsA5WCOKSRSggj8mU4DK+Ae3/CGZ9edc2aXks4pQfd8VE6fNZ8I8SgH9OJmuYkjfvv3z6FsTJd9u3JBC7OEmVvRDkecaqCDa5Foe0L4/Jg2ns28TvxP1U+02Ps/nI6Kj2ute5w08AKp+H2eCQgAAAABJRU5ErkJggg=='/%3e%3c/defs%3e%3c/svg%3e`,a=`data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3crect%20width='24'%20height='24'%20rx='12'%20fill='%23242145'/%3e%3cpath%20d='M6.1321%2016V8.72727H9.00142C9.55066%208.72727%2010.0194%208.82552%2010.4077%209.02202C10.7983%209.21615%2011.0954%209.49195%2011.299%209.84943C11.505%2010.2045%2011.608%2010.6224%2011.608%2011.103C11.608%2011.5859%2011.5038%2012.0014%2011.2955%2012.3494C11.0871%2012.6951%2010.7853%2012.9602%2010.3899%2013.1449C9.99692%2013.3295%209.52107%2013.4219%208.96236%2013.4219H7.04119V12.1861H8.71378C9.00734%2012.1861%209.25118%2012.1458%209.44531%2012.0653C9.63944%2011.9848%209.78385%2011.8641%209.87855%2011.7031C9.97562%2011.5421%2010.0241%2011.3421%2010.0241%2011.103C10.0241%2010.8615%209.97562%2010.6579%209.87855%2010.4922C9.78385%2010.3265%209.63826%2010.201%209.44176%2010.1158C9.24763%2010.0282%209.0026%209.98438%208.70668%209.98438H7.66974V16H6.1321ZM10.0597%2012.6903L11.8672%2016H10.1697L8.40128%2012.6903H10.0597ZM16.1399%2010.8189C16.1115%2010.5324%2015.9896%2010.3099%2015.7741%2010.1513C15.5587%209.99266%2015.2663%209.91335%2014.897%209.91335C14.6461%209.91335%2014.4342%209.94886%2014.2614%2010.0199C14.0885%2010.0885%2013.956%2010.1844%2013.8636%2010.3075C13.7737%2010.4306%2013.7287%2010.5703%2013.7287%2010.7266C13.724%2010.8568%2013.7512%2010.9704%2013.8104%2011.0675C13.8719%2011.1645%2013.956%2011.2486%2014.0625%2011.3196C14.169%2011.3883%2014.2921%2011.4486%2014.4318%2011.5007C14.5715%2011.5504%2014.7206%2011.593%2014.8793%2011.6286L15.5327%2011.7848C15.8499%2011.8558%2016.1411%2011.9505%2016.4062%2012.0689C16.6714%2012.1873%2016.901%2012.3329%2017.0952%2012.5057C17.2893%2012.6785%2017.4396%2012.8821%2017.5462%2013.1165C17.6551%2013.3509%2017.7107%2013.6196%2017.7131%2013.9226C17.7107%2014.3677%2017.5971%2014.7536%2017.3722%2015.0803C17.1496%2015.4046%2016.8277%2015.6567%2016.4062%2015.8366C15.9872%2016.0142%2015.4818%2016.103%2014.8899%2016.103C14.3028%2016.103%2013.7914%2016.013%2013.3558%2015.8331C12.9226%2015.6532%2012.584%2015.3868%2012.3402%2015.0341C12.0987%2014.679%2011.9721%2014.2398%2011.9602%2013.7166H13.4482C13.4647%2013.9605%2013.5346%2014.1641%2013.6577%2014.3274C13.7831%2014.4884%2013.95%2014.6103%2014.1584%2014.6932C14.3691%2014.7737%2014.607%2014.8139%2014.8722%2014.8139C15.1326%2014.8139%2015.3587%2014.776%2015.5504%2014.7003C15.7446%2014.6245%2015.8949%2014.5192%2016.0014%2014.3842C16.108%2014.2493%2016.1612%2014.0942%2016.1612%2013.919C16.1612%2013.7557%2016.1127%2013.6184%2016.0156%2013.5071C15.9209%2013.3958%2015.7813%2013.3011%2015.5966%2013.223C15.4143%2013.1449%2015.1906%2013.0739%2014.9254%2013.0099L14.1335%2012.8111C13.5204%2012.6619%2013.0362%2012.4287%2012.6811%2012.1115C12.326%2011.7943%2012.1496%2011.367%2012.152%2010.8295C12.1496%2010.3892%2012.2668%2010.0045%2012.5036%209.67543C12.7427%209.34635%2013.0705%209.08949%2013.4872%208.90483C13.9039%208.72017%2014.3774%208.62784%2014.9077%208.62784C15.4474%208.62784%2015.9186%208.72017%2016.321%208.90483C16.7259%209.08949%2017.0407%209.34635%2017.2656%209.67543C17.4905%2010.0045%2017.6065%2010.3857%2017.6136%2010.8189H16.1399Z'%20fill='%23FFD02B'/%3e%3c/svg%3e`,o=class{element;constructor(e,t){this.element=document.createElement(e),t&&(this.element.className=t)}destroy(){this.element.remove()}query(e){return this.element.querySelector(e)||void 0}},s=class extends o{constructor(){super(`footer`,`footer`),this.element.innerHTML=`
15            <div class="footer__inner container">
16                <div class="footer__top">
17                    <div class="footer__brand">
18                        <a href="/" class="footer__logo logo logo--white" data-link>
19                            <img src="${i}" alt="" class="logo__img" width="32" height="32">
20                            <span class="logo__text">MiniGames</span>
21                        </a>
22                        <p class="footer__text">
23                            Take a short break and have fun. Hundreds of curated casual mini-games
24                            right in your web browser. No download required.
25                        </p>
26                    </div>
27
28                    <nav class="footer__nav">
29                        <div class="footer__group">
30                            <h2 class="footer__title">Explore</h2>
31                            <ul class="footer__list list-unstyled">
32                                <li><a href="/" data-link>Home</a></li>
33                                <li>
34                                    <a href="/library" data-link>Library</a>
35                                </li>
36                                <li>
37                                    <a href="/" data-link>Categories</a>
38                                </li>
39                                <li>
40                                    <a href="/" data-link>Tournaments</a>
41                                </li>
42                            </ul>
43                        </div>
44
45                        <div class="footer__group">
46                            <h2 class="footer__title">Company</h2>
47                            <ul class="footer__list list-unstyled">
48                                <li>
49                                    <a href="/" data-link>About Us</a>
50                                </li>
51                                <li>
52                                    <a href="/" data-link>Contact</a>
53                                </li>
54                                <li>
55                                    <a href="/" data-link>Privacy Policy</a>
56                                </li>
57                                <li>
58                                    <a href="/" data-link>Terms of Service</a>
59                                </li>
60                            </ul>
61                        </div>
62
63                        <div class="footer__group footer__group--community">
64                            <h2 class="footer__title">Community</h2>
65                            <ul class="footer__socials list-unstyled">
66                                <li>
67                                    <a
68                                        href="/"
69                                        class="footer__social-btn"
70                                        aria-label="Share"
71                                        target="_blank"
72                                        rel="noopener noreferrer"
73                                        data-link
74                                        >${n}</a
75                                    >
76                                </li>
77                                <li>
78                                    <a
79                                        href="/"
80                                        class="footer__social-btn"
81                                        aria-label="Community Chat"
82                                        target="_blank"
83                                        rel="noopener noreferrer"
84                                        data-link
85                                        >${e}</a
86                                    >
87                                </li>
88                                <li>
89                                    <a
90                                        href="/"
91                                        class="footer__social-btn"
92                                        aria-label="RSS Feed"
93                                        target="_blank"
94                                        rel="noopener noreferrer"
95                                        data-link
96                                        >${t}</a
97                                    >
98                                </li>
99                            </ul>
100                        </div>
101                    </nav>
102                </div>
103
104                <div class="footer__bottom">
105                    <p class="footer__copyright">© 2026 MiniGames. All rights reserved.</p>
106
107                    <a
108                        href="https://rs.school/courses/short-track"
109                        class="footer__credit"
110                        target="_blank"
111                        rel="noopener noreferrer"
112                    >
113                        <img
114                            src="${a}"
115                            alt=""
116                            class="footer__credit-icon"
117                            width="24"
118                            height="24"
119                        >
120                        RS School
121                    </a>
122
123                    <a
124                        href="https://github.com/aidardev"
125                        class="footer__credit"
126                        target="_blank"
127                        rel="noopener noreferrer"
128                    >
129                        ${r} @aidardev
130                    </a>
131
132                    <p class="footer__attribution">Designed with love</p>
133                </div>
134            </div>
135        `}},c=`<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
136<path d="M1.0625 10L0 8.9375L3.9375 5L0 1.0625L1.0625 -1.19209e-06L5 3.9375L8.9375 -1.19209e-06L10 1.0625L6.0625 5L10 8.9375L8.9375 10L5 6.0625L1.0625 10Z" fill="currentColor"/>
137</svg>
138`,l=`<svg width="16" height="10" viewBox="0 0 16 10" fill="none" xmlns="http://www.w3.org/2000/svg">
139<line y1="1" x2="16" y2="1" stroke="currentColor" stroke-width="2"/>
140<line y1="5" x2="16" y2="5" stroke="currentColor" stroke-width="2"/>
141<line y1="9" x2="16" y2="9" stroke="currentColor" stroke-width="2"/>
142</svg>
143`,u=class extends o{content;pointerDownOnBackdrop=!1;handlePointerDown=e=>{this.pointerDownOnBackdrop=e.target===this.element};handleClick=e=>{this.pointerDownOnBackdrop&&e.target===this.element&&this.close()};handleClose=async()=>{await Promise.allSettled(this.element.getAnimations({subtree:!0}).map(e=>e.finished)),this.element.open||this.destroy()};constructor({label:e,modifier:t}={}){let n=t?`dialog ${t}`:`dialog`;super(`dialog`,n),e&&this.element.setAttribute(`aria-label`,e),this.content=document.createElement(`div`),this.content.classList.add(`dialog__content`),this.element.append(this.content),this.bindEvents()}bindEvents(){this.element.addEventListener(`pointerdown`,this.handlePointerDown),this.element.addEventListener(`click`,this.handleClick),this.element.addEventListener(`close`,this.handleClose)}setContent(e){typeof e==`string`?this.content.innerHTML=e:this.content.replaceChildren(e)}open(){this.element.open||(this.element.isConnected||document.body.append(this.element),this.element.showModal())}close(e){this.element.close(e)}},d=`<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="M240-80q-33 0-56.5-23.5T160-160v-400q0-33 23.5-56.5T240-640h40v-80q0-83 58.5-141.5T480-920q83 0 141.5 58.5T680-720v80h40q33 0 56.5 23.5T800-560v400q0 33-23.5 56.5T720-80H240Zm0-80h480v-400H240v400Zm296.5-143.5Q560-327 560-360t-23.5-56.5Q513-440 480-440t-56.5 23.5Q400-393 400-360t23.5 56.5Q447-280 480-280t56.5-23.5ZM360-640h240v-80q0-50-35-85t-85-35q-50 0-85 35t-35 85v80ZM240-160v-400 400Z"/></svg>`,f=`<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z"/></svg>`,p=`data:image/svg+xml,%3csvg%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M24%2012.2727C24%2011.4218%2023.9221%2010.6036%2023.7774%209.81818H12.2449V14.4655H18.8349C18.5455%2015.96%2017.6772%2017.2255%2016.3748%2018.0764V21.0982H20.3488C22.6642%2019.0036%2024%2015.9273%2024%2012.2727Z'%20fill='%234285F4'/%3e%3cpath%20d='M12.2449%2024C15.551%2024%2018.3228%2022.9309%2020.3488%2021.0982L16.3748%2018.0764C15.2839%2018.7964%2013.8924%2019.2327%2012.2449%2019.2327C9.06122%2019.2327%206.35622%2017.1273%205.38776%2014.2909H1.31354V17.3891C3.32839%2021.3055%207.45826%2024%2012.2449%2024Z'%20fill='%2334A853'/%3e%3cpath%20d='M5.38776%2014.28C5.14286%2013.56%204.99814%2012.7964%204.99814%2012C4.99814%2011.2036%205.14286%2010.44%205.38776%209.72V6.62182H1.31354C0.478664%208.23636%200%2010.0582%200%2012C0%2013.9418%200.478664%2015.7636%201.31354%2017.3782L4.48609%2014.9564L5.38776%2014.28Z'%20fill='%23FBBC05'/%3e%3cpath%20d='M12.2449%204.77818C14.0482%204.77818%2015.6512%205.38909%2016.9314%206.56727L20.4379%203.13091C18.3117%201.18909%2015.551%200%2012.2449%200C7.45826%200%203.32839%202.69455%201.31354%206.62182L5.38776%209.72C6.35622%206.88364%209.06122%204.77818%2012.2449%204.77818Z'%20fill='%23EA4335'/%3e%3c/svg%3e`,m=`<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z"/></svg>`,h=`<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="M607.5-372.5Q660-425 660-500t-52.5-127.5Q555-680 480-680t-127.5 52.5Q300-575 300-500t52.5 127.5Q405-320 480-320t127.5-52.5Zm-204-51Q372-455 372-500t31.5-76.5Q435-608 48
1430-608t76.5 31.5Q588-545 588-500t-31.5 76.5Q525-392 480-392t-76.5-31.5ZM214-281.5Q94-363 40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200q-146 0-266-81.5ZM480-500Zm207.5 160.5Q782-399 832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280q113 0 207.5-59.5Z"/></svg>`;function g(e){let{id:t,name:n,label:r,type:i,placeholder:a,icon:o,autocomplete:s,passwordToggle:c=!1}=e;return`
144        <div class="field${c?` field--has-password-toggle`:``}">
145            <label class="field__label" for="${t}">${r}</label>
146            <div class="field__control">
147                <span class="field__icon" aria-hidden="true">${o}</span>
148                <input
149                    class="field__input"
150                    id="${t}"
151                    name="${n}"
152                    type="${i}"
153                    placeholder="${a}"
154                    autocomplete="${s}"
155                >
156                ${c?_():``}
157            </div>
158        </div>
159    `}function _(){return`
160        <button class="field__toggle" type="button" aria-label="Show password" data-password-toggle>
161            <span class="field__toggle-icon field__toggle-icon--show">${h}</span>
162            <span class="field__toggle-icon field__toggle-icon--hide">${m}</span>
163        </button>
164    `}var v=class extends o{handleSubmit=e=>{e.preventDefault()};constructor(){super(`form`,`auth-form`),this.element.noValidate=!0,this.element.innerHTML=`
165            <div class="auth-form__head">
166                <h2 class="auth-form__title">Welcome Back!</h2>
167                <p class="auth-form__subtitle">Sign in to resume your games and progress.</p>
168            </div>
169
170            <div class="auth-form__fields">
171                ${g({id:`login-email`,name:`email`,label:`Email Address`,type:`email`,placeholder:`e.g. [email protected]`,icon:f,autocomplete:`email`})}
172                ${g({id:`login-password`,name:`password`,label:`Password`,type:`password`,placeholder:`••••••••`,icon:d,autocomplete:`current-password`,passwordToggle:!0})}
173                <button class="auth-form__link auth-form__link--forgot" type="button">
174                    Forgot Password?
175                </button>
176            </div>
177
178            <div class="auth-form__actions">
179                <button
180                    class="auth-form__btn auth-form__btn--submit btn btn--large btn--primary"
181                    type="submit"
182                >
183                    Login
184                </button>
185                <div class="auth-form__divider" aria-hidden="true"><span>OR</span></div>
186                <button
187                    class="auth-form__btn auth-form__btn--google btn btn--medium btn--outline-on-primary"
188                    type="button"
189                >
190                    <img src="${p}" alt="" width="24" height="24">
191                    Continue with Google
192                </button>
193            </div>
194
195            <p class="auth-form__switch">
196                Don't have an account?
197                <button class="auth-form__link" type="button" data-auth-tab="register">
198                    Register
199                </button>
200            </p>
201        `,this.element.addEventListener(`submit`,this.handleSubmit)}},y=`<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="currentColor"><path d="M367-527q-47-47-47-113t47-113q47-47 113-47t113 47q47 47 47 113t-47 113q-47 47-113 47t-113-47ZM160-160v-112q0-34 17.5-62.5T224-378q62-31 126-46.5T480-440q66 0 130 15.5T736-378q29 15 46.5 43.5T800-272v112H160Zm80-80h480v-32q0-11-5.5-20T700-306q-54-27-109-40.5T480-360q-56 0-111 13.5T260-306q-9 5-14.5 14t-5.5 20v32Zm296.5-343.5Q560-607 560-640t-23.5-56.5Q513-720 480-720t-56.5 23.5Q400-673 400-640t23.5 56.5Q447-560 480-560t56.5-23.5ZM480-640Zm0 400Z"/></svg>`,b=class extends o{handleSubmit=e=>{e.preventDefault()};constructor(){super(`form`,`auth-form`),this.element.noValidate=!0,this.element.innerHTML=`
202            <div class="auth-form__head">
203                <h2 class="auth-form__title">Create Account</h2>
204                <p class="auth-form__subtitle">
204Join MiniGames to track your score &amp; streak.</p>
205            </div>
206
207            <div class="auth-form__fields">
208                ${g({id:`register-username`,name:`username`,label:`Username`,type:`text`,placeholder:`e.g. CozyGamer_99`,icon:y,autocomplete:`username`})}
209                ${g({id:`register-email`,name:`email`,label:`Email Address`,type:`email`,placeholder:`[email protected]`,icon:f,autocomplete:`email`})}
210                ${g({id:`register-password`,name:`password`,label:`Password`,type:`password`,placeholder:`Min. 8 characters`,icon:d,autocomplete:`new-password`})}
211                ${g({id:`register-confirm-password`,name:`confirmPassword`,label:`Confirm Password`,type:`password`,placeholder:`Repeat your password`,icon:d,autocomplete:`new-password`})}
212            </div>
213
214            <div class="auth-form__actions">
215                <button
216                    class="auth-form__btn auth-form__btn--submit btn btn--large btn--primary"
217                    type="submit"
218                >
219                    Create Account
220                </button>
221                <div class="auth-form__divider" aria-hidden="true"><span>OR</span></div>
222                <button
223                    class="auth-form__btn auth-form__btn--google btn btn--medium btn--outline-on-primary"
224                    type="button"
225                >
226                    <img src="${p}" alt="" width="24" height="24">
227                    Sign up with Google
228                </button>
229            </div>
230
231            <p class="auth-form__switch">
232                Already have an account?
233                <button class="auth-form__link" type="button" data-auth-tab="login">Login</button>
234            </p>
235        `,this.element.addEventListener(`submit`,this.handleSubmit)}};function x(e){return e===`register`?`register`:`login`}var S=class extends u{handleSwitchClick=e=>{if(!(e.target instanceof Element))return;let t=e.target.closest(`[data-auth-tab]`);t&&this.showTab(x(t.dataset.authTab))};constructor(e=`login`){super({label:`Auth Dialog`,modifier:`dialog--auth`}),this.setContent(`
236            <div class="auth">
237                <div class="auth__tabs" role="tablist" aria-label="Login or register">
238                    <button
239                        class="auth__tab"
240                        id="auth-tab-login"
241                        type="button"
242                        role="tab"
243                        aria-controls="auth-panel-login"
244                        data-auth-tab="login"
245                    >
246                        Login
247                    </button>
248                    <button
249                        class="auth__tab"
250                        id="auth-tab-register"
251                        type="button"
252                        role="tab"
253                        aria-controls="auth-panel-register"
254                        data-auth-tab="register"
255                    >
256                        Register
257                    </button>
258                </div>
259
260                <div
261                    class="auth__panel"
262                    id="auth-panel-login"
263                    role="tabpanel"
264                    aria-labelledby="auth-tab-login"
265                    data-auth-panel="login"
266                ></div>
267                <div
268                    class="auth__panel"
269                    id="auth-panel-register"
270                    role="tabpanel"
271                    aria-labelledby="auth-tab-register"
272                    data-auth-panel="register"
273                ></div>
274            </div>
275        `),this.mountForms(),this.showTab(e),this.bindTabEvents()}mountForms(){this.query(`[data-auth-panel="login"]`)?.append(new v().element),this.query(`[data-auth-panel="register"]`)?.append(new b().element)}bindTabEvents(){this.element.addEventListener(`click`,this.handleSwitchClick)}showTab(e){for(let t of this.element.querySelectorAll(`[role="tab"]`))t.setAttribute(`aria-selected`,String(t.dataset.authTab===e));for(let t of this.element.querySelectorAll(`[role="tabpanel"]`))t.hidden=t.dataset.authPanel!==e}},C=class extends o{isMenuOpen=!1;burgerBtn=void 0;closeBtn=void 0;menuContainer=void 0;navLinks=[];handleDocumentClick=e=>{let t=e.target;t instanceof Node&&(this.element.contains(t)||this.closeMenu())};handleEscKey=e=>{e.key===`Escape`&&this.closeMenu()};handleAuthClick=e=>{if(!(e.target instanceof Element))return;let t=e.target.closest(`[data-auth-tab]`);if(!t)return;let n=x(t.dataset.authTab);this.closeMenu(),new S(n).open()};handleLinksClick=e=>{e.target instanceof Element&&e.target.closest(`a`)&&this.closeMenu()};constructor(){super(`header`,`header`),this.element.innerHTML=`
276            <div class="header__inner container">
277                <a href="/" class="header__logo logo logo--dark" data-link>
278                    <img src="${i}" alt="" class="logo__img" width="32" height="32">
279                    <span class="logo__text">MiniGames</span>
280                </a>
281                <div class="header__menu" id="mobile-menu">
282                    <div class="header__mobile-topbar">
283                        <a href="/" class="header__logo-mobile logo logo--white" data-link>
284                            <img src="${i}" alt="" class="logo__img" width="32" height="32">
285                            <span class="logo__text">MiniGames</span>
286                        </a>
287                        <button class="header__close btn" type="button" aria-label="Close menu">
288                            ${c}
289                        </button>
290                    </div>
291                    <nav class="header__navbar navbar">
292                        <ul class="navbar__list list-unstyled">
293                            <li><a href="/" data-link data-route="/">Home</a></li>
294                            <li><a href="/library" data-link data-route="/library">Library</a></li>
295                            <li><a href="/" data-link>Tournaments</a></li>
296                            <li><a href="/" data-link>Community</a></li>
297                        </ul>
298                    </nav>
299                    <div class="header__btns">
300                        <button
301                            class="header__btn btn btn--medium btn--outline-on-primary"
302                            type="button"
303                            data-auth-tab="login"
304                        >
305                            Log In
306                        </button>
307                        <button
308                            class="header__btn btn btn--medium btn--primary"
309                            type="button"
310                            data-auth-tab="register"
311                        >
312                            Sign Up
313                        </button>
314                    </div>
315                </div>
316                <button
317                    class="header__btn header__btn--tablet btn btn--small btn--primary"
318                    type="button"
319                    data-auth-tab="register"
320                >
321                    Sign Up
322                </button>
323                <button
324                    class="header__hamburger-btn btn btn--icon btn--outline-on-primary"
325                    type="button"
326                    aria-label="Open menu"
327                    aria-expanded="false"
328                    aria-controls="mobile-menu"
329                >
330                    ${l}
331                </button>
332            </div>
333        `,this.initElements(),this.bindEvents()}initElements(){this.burgerBtn=this.query(`.header__hamburger-btn`),this.closeBtn=this.query(`.header__close`),this.menuContainer=this.query(`.header__menu`),this.navLinks=[...this.element.querySelectorAll(`:scope .navbar__list a[data-route]`)]}bindEvents(){this.burgerBtn?.addEventListener(`click`,()=>this.openMenu()),this.closeBtn?.addEventListener(`click`,()=>this.closeMenu()),this.element.addEventListener(`click`,this.handleAuthClick),this.menuContainer?.addEventListener(`click`,this.handleLinksClick)}setActivePath(e){for(let t of this.navLinks){let n=t.dataset.route===e;t.closest(`li`)?.classList.toggle(`is-active`,n)}}openMenu(){this.isMenuOpen||(this.isMenuOpen=!0,this.menuContainer?.classList.add(`is-open`),this.burgerBtn?.setAttribute(`aria-expanded`,`true`),document.body.classList.add(`is-locked`),document.addEventListener(`click`,this.handleDocumentClick),document.addEventListener(`keydown`,this.handleEscKey))}closeMenu(){this.isMenuOpen&&(this.isMenuOpen=!1,this.menuContainer?.classList.remove(`is-open`),this.burgerBtn?.setAttribute(`aria-expanded`,`false`),document.body.classList.remove(`is-locked`),document.removeEventListener(`click`,this.handleDocumentClick),document.removeEventListener(`keydown`,this.handleEscKey))}};async function w(){let e=await fetch(`/mock-data/leaderboard.json`);if(!e.ok)throw Error(`Failed to load leaderboard: ${e.status}`);return(await e.json()).data}var ee=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
334<path d="M12 3V15M7 8L12 3L17 8M21 15V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V15" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
335</svg>
336`,te=`/assets/illustration-side-B1_6Masa.png`,ne=class extends o{constructor(){super(`section`,`section section-developer-cta`),this.element.innerHTML=`
337            <div class="developer-cta container">
338                <img
339                    src="${te}"
340                    alt="Illustration image"
341                    class="developer-cta__img img-responsive"
342                    width="680"
343                    height="480"
344                    loading="lazy"
345                >
346                <div class="developer-cta__card">
347                    <div class="developer-cta__card-content">
348                        <h2 class="developer-cta__title">Are You a Game Developer?</h2>
349                        <p class="developer-cta__text">
350                            Want to see your game on MiniGames? We're always looking for fun,
351                            engaging mini games to add to our platform. Submit your game
352                            and&nbsp;reach thousands of players!
353                        </p>
354                        <button
355                            class="developer-cta__btn btn btn--large btn--primary"
356                            type="button"
357                        >
358                            ${ee} Submit Form
359                        </button>
360                        <p class="developer-cta__hint">
361                            or contact us at
362                            <a href="mailto:[email protected]">[email protected]</a>
363                        </p>
364                    </div>
365                </div>
366            </div>
367        `}},T=class extends o{constructor(){super(`section`,`section-hero`),this.element.innerHTML=`
368            <div class="hero container">
369                <div class="hero__card">
370                    <h1 class="hero__title">Take a Short Break &amp;&nbsp;Have Fun</h1>
371                    <p class="hero__text hero__text--desktop">
372                        Discover hundreds of curated casual mini-games. Play instantly in your
373                        browser — puzzle, match 3, farm, and board classics.
374                    </p>
375                    <p class="hero__text hero__text--mobile">
376                        Discover hundreds of curated casual mini-games right in y
376our browser.
377                    </p>
378                    <a href="/library" class="hero__btn btn btn--large btn--primary" data-link>
379                        Browse Library
380                    </a>
381                </div>
382            </div>
383        `}};function E(e){return e.toLocaleString(`en-US`)}function D(e){return e<1e3?e.toString():e<1e6?`${Math.floor(e/1e3*10)/10}K`:`${Math.floor(e/1e6*10)/10}M`}function O(e){let t=[];for(let n of e)n>=`A`&&n<=`Z`&&t.push(n);return t.length>=2?t[0]+t[1]:e.slice(0,2).toUpperCase()}var k=class extends o{players;constructor(e){super(`section`,`section section-leaderboard`),this.players=e,this.element.innerHTML=`
384            <div class="container">
385                <div class="section-header">
386                    <h2 class="section-header__title section-title">
387                        Top Players<span class="section-leaderboard__title-extra"> This Week</span>
388                    </h2>
389                </div>
390
391                <div class="leaderboard-table-container">
392                    <table class="leaderboard-table">
393                        <thead class="leaderboard-table__head">
394                            <tr>
395                                <th
396                                    scope="col"
397                                    class="leaderboard-table__col leaderboard-table__col--rank"
398                                >
399                                    Rank
400                                </th>
401                                <th
402                                    scope="col"
403                                    class="leaderboard-table__col leaderboard-table__col--player"
404                                >
405                                    Player
406                                </th>
407                                <th
408                                    scope="col"
409                                    class="leaderboard-table__col leaderboard-table__col--games"
410                                >
411                                    <span class="leaderboard-table__text-full">Games Played</span>
412                                    <span class="leaderboard-table__text-short">Games</span>
413                                </th>
414                                <th
415                                    scope="col"
416                                    class="leaderboard-table__col leaderboard-table__col--score"
417                                >
418                                    <span class="leaderboard-table__text-full">Total Score</span>
419                                    <span class="leaderboard-table__text-short">Score</span>
420                                </th>
421                                <th
422                                    scope="col"
423                                    class="leaderboard-table__col leaderboard-table__col--streak"
424                                >
425                                    Streak
426                                </th>
427                                <th
428                                    scope="col"
429                                    class="leaderboard-table__col leaderboard-table__col--favorite"
430                                >
431                                    Favorite Game
432                                </th>
433                            </tr>
434                        </thead>
435                        <tbody class="leaderboard-table__body">
436                            ${this.renderRows()}
437                        </tbody>
438                    </table>
439                </div>
440            </div>
441        `}renderRows(){return this.players.map(e=>{let t=O(e.playerName),n=E(e.totalScore),r=D(e.totalScore);return`
442                    <tr class="leaderboard-table__row">
443                        <td class="leaderboard-table__cell leaderboard-table__col--rank">
444                            <span class="leaderboard-table__rank-val">#${e.rank}</span>
445                        </td>
446                        <td class="leaderboard-table__cell leaderboard-table__col--player">
447                            <div class="leaderboard-table__player-info">
448                                <span class="leaderboard-table__avatar avatar">${t}</span>
449                                <span class="leaderboard-table__username"
450                                    >${e.playerName}</span
451                                >
452                            </div>
453                        </td>
454                        <td class="leaderboard-table__cell leaderboard-table__col--games">
455                            ${e.gamesPlayed}
456                        </td>
457                        <td class="leaderboard-table__cell leaderboard-table__col--score">
458                            <span class="leaderboard-table__text-full">${n}</span>
459                            <span class="leaderboard-table__text-short">${r}</span>
460                        </td>
461                        <td class="leaderboard-table__cell leaderboard-table__col--streak">
462                            <span class="leaderboard-table__streak">
463                                🔥 ${e.streakDays}<span class="leaderboard-table__text-full">
464                                    days</span
465                                ><span class="leaderboard-table__text-short">d</span>
466                            </span>
467                        </td>
468                        <td class="leaderboard-table__cell leaderboard-table__col--favorite">
469                            <span class="leaderboard-table__badge">${e.favoriteGameName}</span>
470                        </td>
471                    </tr>
472                `}).join(``)}};async function A(){let e=await fetch(`/mock-data/comments-tukoni-forest-keepers.json`);if(!e.ok)throw Error(`Failed to load comments: ${e.status}`);return(await e.json()).data}async function j(){let e=await fetch(`/mock-data/game-tukoni-forest-keepers.json`);if(!e.ok)throw Error(`Failed to load game details: ${e.status}`);return(await e.json()).data}async function M(){let e=await fetch(`/mock-data/all-games-seed.json`);if(!e.ok)throw Error(`Failed to load games: ${e.status}`);return(await e.json()).data}var N=`<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="currentColor"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>`,P=`<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="currentColor"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8-8-8z"/></svg>`,F=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
473<path d="M6.4 19L5 17.6L10.6 12L5 6.4L6.4 5L12 10.6L17.6 5L19 6.4L13.4 12L19 17.6L17.6 19L12 13.4L6.4 19Z" fill="currentColor"/>
474</svg>
475`,I=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
476<path d="M12 21L10.55 19.7C8.86667 18.1834 7.475 16.875 6.375 15.775C5.275 14.675 4.4 13.6917 3.75 12.825C3.1 11.9417 2.64167 11.1334 2.375 10.4C2.125 9.66669 2 8.91669 2 8.15002C2 6.58336 2.525 5.27502 3.575 4.22502C4.625 3.17502 5.93333 2.65002 7.5 2.65002C8.36667 2.65002 9.19167 2.83336 9.975 3.20002C10.7583 3.56669 11.4333 4.08336 12 4.75003C12.5667 4.08336 13.2417 3.56669 14.025 3.20002C14.8083 2.83336 15.6333 2.65002 16.5 2.65002C18.0667 2.65002 19.375 3.17502 20.425 4.22502C21.475 5.27502 22 6.58336 22 8.15002C22 8.91669 21.8667 9.66669 21.6 10.4C21.35 11.1334 20.9 11.9417 20.25 12.825C19.6 13.6917 18.725 14.675 17.625 15.775C16.525 16.875 15.1333 18.1834 13.45 19.7L12 21ZM12 18.3C13.6 16.8667 14.9167 15.6417 15.95 14.625C16.9833 13.5917 17.8 12.7 18.4 11.95C19 11.1834 19.4167 10.5084 19.65 9.92503C19.8833 9.32503 20 8.73336 20 8.15002C20 7.15002 19.6667 6.31669 19 5.65003C18.3333 4.98336 17.5 4.65003 16.5 4.65003C15.7167 4.65003 14.9917 4.87503 14.325 5.32503C13.6583 5.75836 13.2 6.31669 12.95 7.00003H11.05C10.8 6.31669 10.3417 5.75836 9.675 5.32503C9.00833 4.87503 8.28333 4.65003 7.5 4.65003C6.5 4.65003 5.66667 4.98336 5 5.
47665003C4.33333 6.31669 4 7.15002 4 8.15002C4 8.73336 4.11667 9.32503 4.35 9.92503C4.58333 10.5084 5 11.1834 5.6 11.95C6.2 12.7 7.01667 13.5917 8.05 14.625C9.08333 15.6417 10.4 16.8667 12 18.3Z" fill="currentColor"/>
477</svg>
478`,L=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
479<path d="M3 20V4L22 12L3 20ZM5 17L16.85 12L5 7V10.5L11 12L5 13.5V17ZM5 17V12V7V10.5V13.5V17Z" fill="currentColor"/>
480</svg>
481`,R=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
482<path d="M8.85 17.825L12 15.925L15.15 17.85L14.325 14.25L17.1 11.85L13.45 11.525L12 8.125L10.55 11.5L6.9 11.825L9.675 14.25L8.85 17.825ZM5.825 22L7.45 14.975L2 10.25L9.2 9.625L12 3L14.8 9.625L22 10.25L16.55 14.975L18.175 22L12 18.275L5.825 22Z" fill="currentColor"/>
483</svg>
484`;function z(e){let t=new Date(e),n=Math.max(0,Date.now()-t.getTime()),r=Math.floor(n/6e4),i=Math.floor(n/36e5),a=Math.floor(n/864e5);if(r<60)return`${Math.max(1,r)} min ago`;if(i<24)return`${i} ${i===1?`hour`:`hours`} ago`;if(a<7)return`${a} ${a===1?`day`:`days`} ago`;let o=Math.floor(a/7);return`${o} ${o===1?`week`:`weeks`} ago`}function B(e,t=16){if(!Number.isFinite(e))throw TypeError(`Value is not a valid number: ${e}`);return`${e/t}rem`}var V=class extends u{game;comments;isFavorite;likedComments=new Set;handleActionClick=e=>{if(!(e.target instanceof Element))return;let t=e.target.closest(`[data-action]`);if(t)switch(t.dataset.action){case`close`:this.close();break;case`favorite`:this.toggleFavorite();break;case`like-comment`:this.toggleCommentLike(t)}};handleSubmit=e=>{let t=e.target;t instanceof HTMLFormElement&&t.matches(`[data-comment-form]`)&&e.preventDefault()};handleInput=e=>{let t=e.target;t instanceof HTMLTextAreaElement&&t.matches(`[data-comment-input]`)&&this.resizeTextarea(t)};constructor({game:e,comments:t}){super({label:`Game Details`,modifier:`dialog--game-details`}),this.game=e,this.comments=t.map(e=>({...e})),this.isFavorite=e.isLikedByCurrentUser;for(let e of this.comments)e.isLikedByCurrentUser&&this.likedComments.add(e.commentId);this.render(),this.updateFavoriteButton(),this.bindGameDetailsEvents()}render(){this.setContent(`
485            <div class="game-details">
486                ${this.renderHero()}
487                <div class="game-details__body">
488                    ${this.renderInfo()} ${this.renderRecords()} ${this.renderComments()}
489                </div>
490            </div>
491        `)}renderHero(){return`
492            <header class="game-details__hero">
493                <img
494                    class="game-details__hero-img img-responsive"
495                    src="${this.game.heroImage}"
496                    alt="${this.game.name}"
497                >
498                <button
499                    class="game-details__close dialog__close btn btn--icon"
500                    type="button"
501                    data-action="close"
502                    aria-label="Close game details"
503                >
504                    ${F}
505                </button>
506            </header>
507        `}renderInfo(){let{specs:e}=this.game;return`
508            <section class="game-details__info">
509                <header class="game-details__info-header">
510                    <div class="game-details__title-row">
511                        <h2 class="game-details__title">${this.game.name}</h2>
512                        <div class="game-details__meta">
513                            <div class="game-details__meta-item meta-item meta-item--rating">
514                                ${R}
515                                <span class="meta-item__value">${this.game.rating}</span>
516                            </div>
517                            <div class="game-details__meta-item meta-item meta-item--likes">
518                                ${I}
519                                <span class="meta-item__value"
520                                    >${D(this.game.likesCount)}</span
521                                >
522                            </div>
523                        </div>
524                    </div>
525                    <p class="game-details__description">${this.game.fullDescription}</p>
526                </header>
527
528                <dl class="game-details__specs">
529                    ${this.renderSpec(`Genre`,e.genre)}
530                    ${this.renderSpec(`Players`,e.players)}
531                    ${this.renderSpec(`Duration`,e.duration)}
532                    ${this.renderSpec(`Price`,e.price)}
533                </dl>
534
535                <div class="game-details__actions">
536                    <button
537                        class="game-details__play btn btn--large btn--primary"
538                        type="button"
539                        data-action="play"
540                    >
541                        Play Now
542                    </button>
543                    <button
544                        class="game-details__favorite btn btn--large"
545                        type="button"
546                        data-action="favorite"
547                        aria-pressed="${this.isFavorite}"
548                    >
549                        ${I}
550                        <span data-favorite-label>
551                            ${this.isFavorite?`Remove from Favorites`:`Add to Favorites`}
552                        </span>
553                    </button>
554                </div>
555            </section>
556        `}updateFavoriteButton(){let e=this.query(`[data-action="favorite"]`);if(!e)return;e.setAttribute(`aria-pressed`,String(this.isFavorite)),e.classList.toggle(`is-active`,this.isFavorite);let t=e.querySelector(`[data-favorite-label]`);t&&(t.textContent=this.isFavorite?`Remove from Favorites`:`Add to Favorites`)}renderSpec(e,t){return`
557            <div class="game-details__spec spec">
558                <dt class="spec__label">${e}</dt>
559                <dd class="spec__value">${t}</dd>
560            </div>
561        `}renderRecords(){return`
562            <section class="game-details__records">
563                <h3 class="game-details__section-title">
564                    <span aria-hidden="true">🏆</span>
565                    Top Records
566                </h3>
567                <ol class="game-details__records-list list-unstyled">
568                    ${this.game.topRecords.map(e=>this.renderRecord(e)).join(``)}
569                </ol>
570            </section>
571        `}renderRecord(e){return`
572            <li class="game-details__record record">
573                <span class="record__position">
574                    <span class="sr-only">Position ${e.position}</span>
575                    <span aria-hidden="true">${this.getMedal(e.position)}</span>
576                </span>
577                <span class="record__player">${e.playerName}</span>
578                <strong class="record__score">${e.score.toLocaleString(`en-US`)} pts</strong>
579                <time class="record__date" datetime="${e.achievedAt}">
580                    ${z(e.achievedAt)}
581                </time>
582            </li>
583        `}renderComments(){return`
584            <section class="game-details__comments">
585                <h3 class="game-details__section-title">Comments (${this.comments.length})</h3>
586
587                <form class="game-details__comment-form comment-form" data-comment-form>
588                    <div class="comment-form__avatar avatar" aria-hidden="true">U</div>
589                    <label class="comment-form__label sr-only" for="game-details-comment">
590                        Write a comment
591                    </label>
592                    <textarea
593                        id="game-details-comment"
594                        class="comment-form__input"
595                        name="comment"
596                        rows="1"
597                        maxlength="1000"
598                        placeholder="Write a comment..."
599                        data-comment-input
600                    ></textarea>
601                    <button
602                        class="comment-form__submit btn btn--icon btn--on-primary"
603                        type="submit"
604                        aria-label="Submit comment"
605                    >
606                        ${L}
607                    </button>
608                </form>
609
610                <ul class="game-details__comments-list list-unstyled">
611                    ${this.comments.map(e=>this.renderComment(e)).join(``)}
612                </ul>
613            </section>
614        `}renderComment(e){let t=this.likedComments.has(e.commentId);return`
615            <li class="game-details__comment">
616                <article class="comment">
617                    <header class="comment__header">
618                        <div class="comment__author">
619                            <span class="comment__avatar avatar" aria-hidden="true">
620                                ${e.authorName.charAt(0).toUpperCase()}
621                            </span>
622
623                            <h4 class="comment__name">${e.authorName}</h4>
624                        </div>
625                        <time class="comment__date" datetime="${e.createdAt}">
626                            ${z(e.createdAt)}
627                        </time>
628                    </header>
629
630                    <p class="comment__text">${e.text}</p>
631
632                    <button
633                        class="comment__like btn"
634                        type="button"
635                        data-action="like-comment"
636                        data-comment-id="${e.commentId}"
637                        aria-pressed="${t}"
638                        aria-label="${t?`Unlike`:`Like`} comment"
639                    >
640                        ${I}
641                        <span data-comment-like-count>
642                            ${e.likesCount+ +!!t}
643                        </span>
644                    </button>
645                </article>
646            </li>
647        `}bindGameDetailsEvents(){this.element.addEventListener(`click`,this.handleActionClick),this.element.addEventListener(`submit`,this.handleSubmit),this.element.addEventListener(`input`,this.handleInput)}toggleFavorite(){this.isFavorite=!this.isFavorite,this.updateFavoriteButton()}toggleCommentLike(e){let t=e.dataset.commentId;if(!t)return;let n=this.likedComments.has(t);n?this.likedComments.delete(t):this.likedComments.add(t),e.setAttribute(`aria-pressed`,String(!n)),e.setAttribute(`aria-label`,n?`Like comment`:`Unlike comment`),e.classList.toggle(`is-active`,!n);let r=this.comments.find(e=>e.commentId===t);if(!r)return;let i=r.likesCount+ +!n,a=e.querySelector(`[data-comment-like-count]`);a&&(a.textContent=String(i))}resizeTextarea(e){e.style.height=`auto`,e.style.height=B(Math.min(e.scrollHeight,88))}getMedal(e){switch(e){case 1:return`🥇`;case 2:return`🥈`;case 3:return`🥉`;default:return String(e)}}},H=class extends o{game;onClick;handleClick=()=>{this.onClick?.(this.game.slug)};constructor({game:e,onClick:t}){super(`article`,`game-slide`),this.game=e,this.onClick=t,this.element.innerHTML=`
648            <img src="${e.cardImage}" alt="" class="game-slide__img" loading="lazy">
649
650            <div class="game-slide__overlay">
651                <h3 class="game-slide__title">
652                    <span class="game-slide__title-text">${e.name}</span>
653                </h3>
654
655                <div class="game-slide__meta">
656                    <div class="game-slide__meta-item meta-item meta-item--rating">
657                        ${R}
658                        <span class="meta-item__value">${e.rating}</span>
659                    </div>
660                    <div class="game-slide__meta-item meta-item meta-item--likes">
661                        ${I}
662                        <span class="meta-item__value"
663                            >${D(e.likesCount)}</span
664                        >
665                    </div>
666                </div>
667            </div>
668        `,this.element.addEventListener(`click`,this.handleClick)}destroy(){this.element.removeEventListener(`click`,this.handleClick),super.destroy()}};function U(e,t=300){let n=0,r;return function(...i){let a=Date.now();return a-n>=t&&(n=a,r=e.apply(this,i)),r}}var W=[`is-active`,`is-near`,`is-far`],G=`is-hidden`,K=[...W,G],q=class extends o{track;slideClassName;autoplayInterval;dragThreshold;swipeThreshold;activeIndex=0;autoplayTimer;autoplayStartTime=0;autoplayRemaining=0;isPointerDown=!1;isDragging=!1;pointerStartX=0;handlePointerDown=e=>{this.isPointerDown=!0,this.isDragging=!1,this.pointerStartX=e.clientX,this.stopAutoplay()};handlePointerMove=e=>{this.isPointerDown&&!this.isDragging&&Math.abs(e.clientX-this.pointerStartX)>=this.dragThreshold&&(this.isDragging=!0,this.track.setPointerCapture(e.pointerId))};handlePointerUp=e=>{if(!this.isPointerDown)return;this.isPointerDown=!1;let t=e.clientX-this.pointerStartX;Math.abs(t)>=this.swipeThreshold?t<0?this.next():this.prev():this.resumeAutoplay()};handlePointerCancel=()=>{this.isPointerDown=!1,this.isDragging=!1,this.resumeAutoplay()};handleClickCapture=e=>{this.isDragging&&=(e.preventDefault(),e.stopPropagation(),!1)};goTo=U(e=>{let t=this.getSlideCount();t!==0&&(this.activeIndex=(e%t+t)%t,this.updatePositions())},400);constructor(e={}){super(`div`,`slider`),this.slideClassName=e.slideClassName,this.autoplayInterval=e.autoplayInterval,this.autoplayRemaining=this.autoplayInterval??0,this.dragThreshold=e.dragThreshold??10,this.swipeThreshold=e.swipeThreshold??50,this.applyClassName(e.className),this.track=document.createElement(`ul`),this.track.classList.add(`slider__track`,`list-unstyled`),e.trackClassName&&this.track.classList.add(e.trackClassName),this.element.append(this.track),this.bindPointerEvents()}createSlide(e){let t=document.createElement(`li`);return t.classList.add(`slider__slide`),this.slideClassName&&t.classList.add(this.slideClassName),t.append(e),t}applyClassName(e){e&&this.element.classList.add(...e.split(` `))}updatePositions(){let e=this.getSlides(),t=e.length,n=Math.floor(t/2);for(let[r,i]of e.entries()){let e=r-this.activeIndex;e<-n&&(e+=t),e>n&&(e-=t),i.style.order=String(e),i.classList.remove(...K),i.classList.add(W[Math.abs(e)]??G)}}startAutoplay(e){this.clearTimer(),!(!this.autoplayInterval||this.get
668SlideCount()<=1)&&(this.autoplayStartTime=Date.now(),this.autoplayTimer=setTimeout(()=>{this.isPointerDown||this.next()},e))}clearTimer(){this.autoplayTimer&&=(clearTimeout(this.autoplayTimer),void 0)}stopAutoplay(){this.autoplayTimer&&(this.clearTimer(),this.autoplayRemaining-=Date.now()-this.autoplayStartTime,this.autoplayRemaining<0&&(this.autoplayRemaining=0))}resumeAutoplay(){this.autoplayInterval&&this.startAutoplay(this.autoplayRemaining)}resetAutoplay(){this.autoplayInterval&&(this.autoplayRemaining=this.autoplayInterval,this.startAutoplay(this.autoplayRemaining))}bindPointerEvents(){this.track.addEventListener(`pointerdown`,this.handlePointerDown),this.track.addEventListener(`pointermove`,this.handlePointerMove),this.track.addEventListener(`pointerup`,this.handlePointerUp),this.track.addEventListener(`pointercancel`,this.handlePointerCancel),this.track.addEventListener(`click`,this.handleClickCapture,{capture:!0})}addSlide(e){this.track.append(this.createSlide(e)),this.updatePositions()}addSlides(e){let t=document.createDocumentFragment();for(let n of e)t.append(this.createSlide(n));this.track.append(t),this.activeIndex=0,this.updatePositions(),this.resetAutoplay()}removeAllSlides(){this.stopAutoplay(),this.track.replaceChildren(),this.activeIndex=0}getSlides(){return[...this.track.children].filter(e=>e instanceof HTMLLIElement)}getSlideCount(){return this.track.children.length}getActiveIndex(){return this.activeIndex}next(){this.goTo(this.activeIndex+1),this.resetAutoplay()}prev(){this.goTo(this.activeIndex-1),this.resetAutoplay()}destroy(){this.stopAutoplay(),super.destroy()}},J=4e3,Y=class extends o{slider;constructor(){super(`section`,`section section-new-games`),this.element.innerHTML=`
669            <div class="container">
670                <div class="section-header">
671                    <h2 class="section-header__title section-title">New Games</h2>
672                    <div class="section-header__slider-controls">
673                        <button
674                            class="slider__arrow slider__arrow--prev"
675                            type="button"
676                            aria-label="Previous slide"
677                        >
678                            ${N}
679                        </button>
680                        <button
681                            class="slider__arrow slider__arrow--next"
682                            type="button"
683                            aria-label="Next slide"
684                        >
685                            ${P}
686                        </button>
687                    </div>
688                </div>
689            </div>
690        `,this.slider=new q({className:`slider-new-games`,trackClassName:`slider-new-games__track`,slideClassName:`slider-new-games__slide`,autoplayInterval:J});let e=this.query(`.container`);e&&(e.append(this.slider.element),this.bindControls(),this.loadGames())}bindControls(){let e=this.query(`.slider__arrow--prev`),t=this.query(`.slider__arrow--next`);e?.addEventListener(`click`,()=>this.slider.prev()),t?.addEventListener(`click`,()=>this.slider.next())}async loadGames(){let e=(await M()).filter(e=>e.featured);this.renderCards(e)}renderCards(e){let t=e.map(e=>new H({game:e,onClick:()=>{this.openGameDetails()}}).element);this.slider.addSlides(t)}async openGameDetails(){let[e,t]=await Promise.all([j(),A()]);new V({game:e,comments:t}).open()}},X=class extends o{developerCta=new ne;constructor(){super(`main`,`home-page`),this.element.append(new T().element,new Y().element,this.developerCta.element),this.loadLeaderboard()}async loadLeaderboard(){let e=new k(await w());this.element.insertBefore(e.element,this.developerCta.element)}};async function Z(){let e=await fetch(`/mock-data/categories.json`);if(!e.ok)throw Error(`Failed to load categories: ${e.status}`);return(await e.json()).data}var re=class extends o{constructor({title:e,subtitle:t}){super(`div`,`page-title container`),this.element.innerHTML=`
691            <h1 class="page-title__title">${e}</h1>
692            ${t?`<p class="page-title__subtitle">${t}</p>`:``}
693        `}},ie=class extends o{activeClass=`chip--active`;activeId;
693onChange;handleClick=e=>{let t=e.target;if(!(t instanceof HTMLElement))return;let n=t.closest(`.chip-group__chip`);if(!n)return;let r=n.dataset.id;r&&r!==this.activeId&&(this.setActive(r),this.onChange?.(r))};constructor({options:e,activeId:t,onChange:n,modifier:r}){super(`div`,`chip-group`),this.activeId=t,this.onChange=n,r&&this.element.classList.add(r),this.element.innerHTML=`
694            ${e.map(e=>`
695                        <button
696                            type="button"
697                            class="chip-group__chip chip ${e.id===this.activeId?this.activeClass:``}"
698                            data-id="${e.id}"
699                        >
700                            ${e.label}
701                        </button>
702                    `).join(``)}
703        `,this.element.addEventListener(`click`,this.handleClick)}setActive(e){this.activeId=e;for(let t of this.element.querySelectorAll(`.chip-group__chip`))t.classList.toggle(this.activeClass,t.dataset.id===e)}},ae=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
704<path d="M12 15L7 10H17L12 15Z" fill="currentColor"/>
705</svg>
706`,oe=`<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
707<path d="M11.6664 3.5L5.25036 9.9162L2.33398 6.99975" stroke="currentColor" stroke-width="3" stroke-linecap="round"/>
708</svg>
709`,se=class extends o{options;onChange;activeId;isOpen=!1;triggerEl;listEl;valueEl;handleTriggerClick=()=>{this.isOpen?this.close():this.open()};handleOptionClick=e=>{let t=e.target;if(!(t instanceof HTMLElement))return;let n=t.closest(`.dropdown__option`);if(!n)return;let r=n.dataset.id;if(!r||r===this.activeId){this.close();return}this.activeId=r,this.updateValueLabel(),this.renderOptions(),this.close(),this.onChange?.(r)};handleOutsideClick=e=>{this.isOpen&&(e.target instanceof Node&&this.element.contains(e.target)||this.close())};handleKeydown=e=>{e.key===`Escape`&&this.isOpen&&this.close()};constructor({options:e,activeId:t,label:n=`Sort by`,onChange:r,modifier:i}){super(`div`,`dropdown`),this.options=e,this.activeId=t,this.onChange=r,i&&this.element.classList.add(i),this.element.innerHTML=`
710            <button type="button" class="dropdown__btn" aria-expanded="false">
711                <span class="dropdown__label">${n}: <span class="dropdown__value"></span></span>
712                ${ae}
713            </button>
714            <ul class="dropdown__list list-unstyled"></ul>
715        `;let a=this.query(`.dropdown__btn`),o=this.query(`.dropdown__list`),s=this.query(`.dropdown__value`);if(!a||!o||!s)throw Error(`Required dropdown elements are missing from the DOM.`);this.triggerEl=a,this.listEl=o,this.valueEl=s,this.renderOptions(),this.updateValueLabel(),this.triggerEl.addEventListener(`click`,this.handleTriggerClick),this.listEl.addEventListener(`click`,this.handleOptionClick),document.addEventListener(`click`,this.handleOutsideClick),document.addEventListener(`keydown`,this.handleKeydown)}renderOptions(){this.listEl.innerHTML=this.options.map(e=>`
716                    <li>
717                        <button
718                            type="button"
719                            class="dropdown__option ${e.id===this.activeId?`dropdown__option--active`:``}"
720                            data-id="${e.id}"
721                        >
722                            ${oe} ${e.label}
723                        </button>
724                    </li>
725                `).join(``)}updateValueLabel(){this.valueEl.textContent=this.options.find(e=>e.id===this.activeId)?.label??``}open(){this.isOpen=!0,this.triggerEl.setAttribute(`aria-expanded`,`true`),this.element.classList.add(`dropdown--open`)}close(){this.isOpen=!1,this.triggerEl.setAttribute(`aria-expanded`,`false`),this.element.classList.remove(`dropdown--open`)}destroy(){document.removeEventListener(`click`,this.handleOutsideClick),document.removeEventListener(`keydown`,this.handleKeydown),super.destroy()}},ce=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
726<path d="M14 18L8 12L14 6L15.4 7.4L10.8 12L15.4 16.6L14 18Z" fill="currentColor"/>
727</svg>
728`,le=`<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
729<path d="M12.6 12L8 7.4L9.4 6L15.4 12L9.4 18L8 16.6L12.6 12Z" fill="currentColor"/>
730</svg>
731`,ue=575.98,de=4,fe=3,pe=class extends o{totalPages;onChange;mediaQuery=matchMedia(`(max-width: ${B(ue)})`);currentPage;handleBreakpointChange=()=>{this.buildStructure(),this.updateState()};handleClick=e=>{let t=e.target;if(!(t instanceof Element))return;let n=t.closest(`button`);if(!n||n.disabled)return;let r=n.dataset.action;if(r===`prev`){this.goTo(this.currentPage-1);return}if(r===`next`){this.goTo(this.currentPage+1);return}let i=Number(n.dataset.page);Number.isSafeInteger(i)&&this.goTo(i)};constructor({totalPages:e,currentPage:t=1,onChange:n}){super(`nav`,`pagination`),this.totalPages=Math.max(1,Math.floor(e)),this.currentPage=this.normalizePage(t),this.onChange=n,this.element.setAttribute(`aria-label`,`Pagination`),this.buildStructure(),this.updateState(),this.element.addEventListener(`click`,this.handleClick),this.mediaQuery.addEventListener(`change`,this.handleBreakpointChange)}buildStructure(){let e=this.getVisiblePagesCount(),t=Array.from({length:e},()=>`<button type="button" class="pagination__page"></button>`).join(``);this.element.innerHTML=`
732            <button
733                type="button"
734                class="pagination__arrow"
735                data-action="prev"
736                aria-label="Previous page"
737            >
738                ${ce}
739            </button>
740
741            <div class="pagination__pages">${t}</div>
742
743            <button
744                type="button"
745                class="pagination__arrow"
746                data-action="next"
747                aria-label="Next page"
748            >
749                ${le}
750            </button>
751        `}updateState(){let e=this.getVisiblePageNumbers(),t=this.element.querySelector(`[data-action="prev"]`),n=this.element.querySelector(`[data-action="next"]`);t&&(t.disabled=this.currentPage===1),n&&(n.disabled=this.currentPage===this.totalPages);let r=this.element.querySelectorAll(`.pagination__page`);for(let[t,n]of r.entries()){let r=e[t];n.textContent=String(r),n.dataset.page=String(r);let i=r===this.currentPage;n.classList.toggle(`pagination__page--active`,i),n.ariaCurrent=i?`page`:void 0}}getVisiblePagesCount(){let e=this.mediaQuery.matches?fe:de;return Math.min(e,this.totalPages)}getVisiblePageNumbers(){let e=this.getVisiblePagesCount(),t=this.totalPages-e+1,n=this.currentPage-Math.floor(e/2);return n=Math.max(1,Math.min(n,t)),Array.from({length:e},(e,t)=>n+t)}goTo(e){let t=this.normalizePage(e);t!==this.currentPage&&(this.currentPage=t,this.updateState(),this.onChange?.(this.currentPage))}normalizePage(e){return Math.min(Math.max(Math.floor(e),1),this.totalPages)}destroy(){this.element.removeEventListener(`click`,this.handleClick),this.mediaQuery.removeEventListener(`change`,this.handleBreakpointChange),super.destroy()}},me=class extends o{constructor(e){super(`article`,`game-card`);let t=e.price===`Free`;this.element.innerHTML=`
752            <div class="game-card__inner">
753                <img
754                    class="game-card__img"
755                    src="${e.cardImage}"
756                    alt="${e.name}"
757                    loading="lazy"
758                >
759                <div class="game-card__body">
760                    <div class="game-card__heading">
761                        <h3 class="game-card__title">${e.name}</h3>
762                        <div class="game-card__category">${e.category}</div>
763                        <div
764                            class="game-card__price game-card__price--desktop${t?` game-card__price--free`:``}"
765                        >
766                            ${e.price}
767                        </div>
768                    </div>
769                    <p class="game-card__description">
769${e.shortDescription}</p>
770                    <div class="game-card__footer">
771                        <div class="game-card__meta">
772                            <div class="game-card__meta-item meta-item meta-item--rating">
773                                ${R}
774                                <span class="meta-item__value">${e.rating}</span>
775                            </div>
776                            <div class="game-card__meta-item meta-item meta-item--likes">
777                                ${I}
778                                <span class="meta-item__value"
779                                    >${D(e.likesCount)}</span
780                                >
781                            </div>
782                        </div>
783                        <div
784                            class="game-card__price game-card__price--mobile${t?` game-card__price--free`:``}"
785                        >
786                            ${e.price}
787                        </div>
788                        <button
789                            type="button"
790                            class="game-card__details btn btn--medium btn--primary"
791                            data-game-slug="${e.slug}"
792                        >
793                            Details
794                        </button>
795                    </div>
796                </div>
797            </div>
798        `}},Q=class extends o{onGameDetailsClick;handleClick=e=>{let t=e.target;if(!(t instanceof HTMLElement))return;let n=t.closest(`.game-card__details`);if(!n||!this.element.contains(n))return;let r=n.dataset.gameSlug;r&&this.onGameDetailsClick?.(r)};constructor({games:e,onGameDetailsClick:t}){super(`ul`,`game-grid list-unstyled`),this.onGameDetailsClick=t,this.element.addEventListener(`click`,this.handleClick),this.render(e)}render(e){if(this.element.replaceChildren(),e.length===0){let e=document.createElement(`li`);e.className=`game-grid__item game-grid__item--empty`;let t=document.createElement(`p`);t.className=`game-grid__empty`,t.textContent=`No games found.`,e.append(t),this.element.append(e);return}for(let t of e){let e=document.createElement(`li`);e.className=`game-grid__item`,e.append(new me(t).element),this.element.append(e)}}update(e){this.render(e)}destroy(){this.element.removeEventListener(`click`,this.handleClick),super.destroy()}},$=[{id:`rating-asc`,label:`Rating ↑`},{id:`rating-desc`,label:`Rating ↓`},{id:`name-asc`,label:`Name A→Z`},{id:`name-desc`,label:`Name Z→A`}],he=class extends o{constructor(e,t){super(`section`,`section-catalog`),this.element.innerHTML=`
799            <h2 class="sr-only">Game catalog</h2>
800            <div class="catalog container">
801                <div class="catalog__controls"></div>
802                <div class="catalog__grid"></div>
803                <div class="catalog__pagination"></div>
804            </div>
805        `;let n=t.find(e=>e.isDefault),r=new ie({options:t.map(e=>({id:e.slug,label:e.label})),activeId:n?.slug??t[0]?.slug??``,modifier:`catalog__chip-group`}),i=new se({options:$,activeId:$[0].id,modifier:`catalog__sort`}),a=new pe({totalPages:Math.ceil(e.length/6),currentPage:1}),o=new Q({games:e.slice(0,6),onGameDetailsClick:async()=>{let[e,t]=await Promise.all([j(),A()]);new V({game:e,comments:t}).open()}});this.element.querySelector(`.catalog__controls`)?.append(r.element,i.element),this.element.querySelector(`.catalog__grid`)?.append(o.element),this.element.querySelector(`.catalog__pagination`)?.append(a.element)}},ge=class extends o{constructor(){super(`main`,`library-page`),this.element.append(new re({title:`Game Library`,subtitle:`Browse our collection of casual mini-games`}).element),this.loadLibrary()}async loadLibrary(){let[e,t]=await Promise.all([M(),Z()]);this.element.append(new he(e,t).element)}},_e=class{outlet;routes;current=void 0;listeners=[];constructor(e,t){this.outlet=e,this.routes=t}render(){let e=location.pathname,t=this.routes[e];this.current?.destroy(),this.current=t?new t:void 0,this.current?this.outlet.append(this.current.element):this.outlet.textContent=`404`;for(let t of this.listeners)t(e)}onRouteChange(e){this.listeners.push(e)}start(){addEventListener(`popstate`,()=>this.render()),document.addEventListener(`click`,e=>{let t=e.target;if(!(t instanceof HTMLElement))return;let n=t.closest(`a[data-link]`);n&&(e.preventDefault(),this.navigate(n.getAttribute(`href`)??`/`))}),this.render()}navigate(e){history.pushState(void 0,``,e),this.render(),window.scrollTo(0,0)}};function ve(){let e=document.createElement(`div`);e.className=`app`;let t=new C,n=new s,r=document.createElement(`div`);r.className=`app__outlet`,e.append(t.element,r,n.element),document.body.prepend(e);let i=new _e(r,{"/":X,"/library":ge});i.onRouteChange(e=>t.setActivePath(e)),i.start()}ve();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.