speakid-build-a-sentence 1.0.14 → 1.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Game.d.ts +2 -2
- package/dist/Game.d.ts.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/speakid-build-a-sentence.cjs.js +61 -0
- package/dist/speakid-build-a-sentence.cjs.js.map +1 -0
- package/dist/speakid-build-a-sentence.es.js +377 -654
- package/dist/speakid-build-a-sentence.es.js.map +1 -1
- package/package.json +3 -3
- package/dist/speakid-build-a-sentence.umd.js +0 -82
- package/dist/speakid-build-a-sentence.umd.js.map +0 -1
package/dist/Game.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
1
|
export interface GameProps {
|
|
3
2
|
logoUrl?: string;
|
|
4
3
|
showLogo?: boolean;
|
|
5
4
|
baseURL?: string;
|
|
6
5
|
}
|
|
7
|
-
|
|
6
|
+
declare function GameComponent(props?: GameProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default GameComponent;
|
|
8
8
|
//# sourceMappingURL=Game.d.ts.map
|
package/dist/Game.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Game.d.ts","sourceRoot":"","sources":["../src/Game.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Game.d.ts","sourceRoot":"","sources":["../src/Game.tsx"],"names":[],"mappings":"AAmDA,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,iBAAS,aAAa,CAAC,KAAK,GAAE,SAAc,2CA09B3C;AAED,eAAe,aAAa,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
export default
|
|
3
|
-
export { GameComponent as Game };
|
|
1
|
+
export { default } from "./Game";
|
|
2
|
+
export { default as Game } from "./Game";
|
|
4
3
|
export { ErrorBoundary } from "./components/ErrorBoundary";
|
|
5
4
|
export { useValidation } from "./hooks/useValidation";
|
|
6
5
|
export { createAriaLabel, handleKeyDown, announceToScreenReader } from "./utils/accessibility";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEjC,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGzC,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAG/F,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,YAAY,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const o=require("react/jsx-runtime"),s=require("react"),Ye=`
|
|
2
|
+
@keyframes magic-sentence-spin {
|
|
3
|
+
from { transform: rotate(0deg); }
|
|
4
|
+
to { transform: rotate(360deg); }
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
@keyframes magic-sentence-pulse {
|
|
8
|
+
0%, 100% { transform: scale(1); }
|
|
9
|
+
50% { transform: scale(1.05); }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@keyframes magic-sentence-shake {
|
|
13
|
+
0%, 100% { transform: translateX(0); }
|
|
14
|
+
25% { transform: translateX(-5px); }
|
|
15
|
+
75% { transform: translateX(5px); }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@keyframes magic-sentence-slideIn {
|
|
19
|
+
from { transform: translateY(-20px); opacity: 0; }
|
|
20
|
+
to { transform: translateY(0); opacity: 1; }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@keyframes magic-sentence-bounce {
|
|
24
|
+
0%, 20%, 53%, 80%, 100% { transform: translate3d(0,0,0); }
|
|
25
|
+
40%, 43% { transform: translate3d(0, -8px, 0); }
|
|
26
|
+
70% { transform: translate3d(0, -4px, 0); }
|
|
27
|
+
90% { transform: translate3d(0, -2px, 0); }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@keyframes magic-sentence-glow {
|
|
31
|
+
0%, 100% { box-shadow: 0 0 5px rgba(76, 175, 80, 0.5); }
|
|
32
|
+
50% { box-shadow: 0 0 20px rgba(76, 175, 80, 0.8), 0 0 30px rgba(76, 175, 80, 0.6); }
|
|
33
|
+
}
|
|
34
|
+
`;if(typeof document<"u"&&!document.getElementById("magic-sentence-keyframes")){const h=document.createElement("style");h.id="magic-sentence-keyframes",h.innerHTML=Ye,document.head.appendChild(h)}const xe={spin:{animation:"magic-sentence-spin 1.4s linear infinite"},pulse:{animation:"magic-sentence-pulse 0.6s ease-in-out"},shake:{animation:"magic-sentence-shake 0.4s ease-in-out"},slideIn:{animation:"magic-sentence-slideIn 0.3s ease-out"},bounce:{animation:"magic-sentence-bounce 0.6s ease-in-out"},glow:{animation:"magic-sentence-glow 1s ease-in-out infinite"}},g={gmCenterScreen:{position:"relative",zIndex:1,minHeight:"100%",width:"100%",display:"flex",flexDirection:"column",justifyContent:"center",alignItems:"center",textAlign:"center",color:"#1f2937",padding:"24px 16px",boxSizing:"border-box",transform:"translateY(20px)"},gmHeadline1:{fontWeight:700,fontSize:"clamp(28px, 4vw, 40px)",lineHeight:"110%"},gmHeadline2:{fontWeight:600,fontSize:"24px",lineHeight:"120%"},gmBodyM:{fontWeight:400,fontSize:"16px",lineHeight:"140%"},gmBodyS:{fontWeight:400,fontSize:"14px",lineHeight:"140%",color:"#6b7280"},gmButton:{fontFamily:'"Geist", system-ui, -apple-system, "Segoe UI", Roboto, Arial, "Noto Sans"',fontWeight:600,fontSize:"16px",padding:"10px 16px",borderRadius:"12px",border:"1px solid #e5e7eb",background:"#ec4c44",color:"#ffffff",cursor:"pointer",boxShadow:"0 6px 18px rgba(236, 76, 68, .18)",transition:"transform .06s ease, box-shadow .2s ease, background .2s ease, opacity .2s ease"},gmGameLayout:{position:"relative",width:"100%",maxWidth:"none",minHeight:"100%",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",textAlign:"center",color:"#1f2937",padding:"16px 8px",margin:"0 auto"},gmInput:{padding:"6px 10px",borderRadius:"6px",border:"1px solid #ccc",fontSize:"16px",fontFamily:'"Geist", system-ui',width:"160px"},gmLogoFixed:{position:"absolute",top:"16px",left:"16px",width:"120px",zIndex:30,pointerEvents:"none",background:"transparent",transform:"none",willChange:"auto"},gmLogoImg:{height:"clamp(28px, 5vw, 40px)",width:"auto",background:"transparent",backgroundImage:"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjQwIiB2aWV3Qm94PSIwIDAgMTAwIDQwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8dGV4dCB4PSI1MCIgeT0iMjUiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIyMCIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbGw9IiNlYzRjNDQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPlNQRUFLSUQ8L3RleHQ+Cjwvc3ZnPgo=')",backgroundSize:"contain",backgroundRepeat:"no-repeat",backgroundPosition:"center",transform:"translateZ(0)",backfaceVisibility:"hidden",WebkitFontSmoothing:"antialiased",objectFit:"contain",imageRendering:"auto"},gmReadyWrapper:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",height:"60%",gap:"16px"},gmHourglass:{fontSize:"42px",...xe.spin},...xe},ye=()=>{const[h,a]=s.useState([]),x=s.useCallback((S,E,I)=>{const p=[];S.trim()||p.push({type:"empty",message:"Sentence cannot be empty"}),S.length>41&&p.push({type:"length",message:`Sentence is too long (${S.length}/41 characters)`}),S&&!/^[a-zA-Z0-9\s.,!?;:'"-]*$/.test(S)&&p.push({type:"characters",message:"Only Latin characters, numbers, spaces and punctuation are allowed"});const m=I.findIndex((v,H)=>H!==E&&v.toLowerCase().trim()===S.toLowerCase().trim());return m!==-1&&p.push({type:"duplicate",message:`Duplicate sentence (same as sentence ${m+1})`}),a(p),{isValid:p.length===0,errors:p}},[]),z=s.useCallback(S=>{const E=[];return S.forEach((I,p)=>{const C=x(I,p,S);E.push(...C.errors.map(m=>({...m,message:`Sentence ${p+1}: ${m.message}`})))}),{isValid:E.length===0,errors:E}},[x]),_=s.useCallback(()=>{a([])},[]);return{errors:h,validateSentence:x,validateAllSentences:z,clearErrors:_}},be=(h,a,x)=>a&&x?`${h} word "${a}" ${x}`:a?`${h} word "${a}"`:h,Se=(h,a,x=["Enter"," "])=>{x.includes(h.key)&&(h.preventDefault(),a())},P=h=>{const a=document.createElement("div");a.setAttribute("aria-live","polite"),a.setAttribute("aria-atomic","true"),a.style.position="absolute",a.style.left="-10000px",a.style.width="1px",a.style.height="1px",a.style.overflow="hidden",document.body.appendChild(a),a.textContent=h,setTimeout(()=>{document.body.removeChild(a)},1e3)},Ke=()=>{const h=document.createElement("style");h.textContent=`
|
|
35
|
+
#magic-sentence-root, #magic-sentence-root * {
|
|
36
|
+
box-sizing: border-box;
|
|
37
|
+
font-family: "Geist", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
|
|
38
|
+
}
|
|
39
|
+
#magic-sentence-root img {
|
|
40
|
+
max-width: 100%;
|
|
41
|
+
height: auto;
|
|
42
|
+
display: block;
|
|
43
|
+
user-select: none;
|
|
44
|
+
}
|
|
45
|
+
html, body {
|
|
46
|
+
margin: 0 !important;
|
|
47
|
+
padding: 0 !important;
|
|
48
|
+
width: 100% !important;
|
|
49
|
+
height: 100% !important;
|
|
50
|
+
overflow: hidden !important;
|
|
51
|
+
zoom: 1 !important;
|
|
52
|
+
}
|
|
53
|
+
#root {
|
|
54
|
+
margin: 0 !important;
|
|
55
|
+
padding: 0 !important;
|
|
56
|
+
width: 100% !important;
|
|
57
|
+
height: 100% !important;
|
|
58
|
+
overflow: hidden !important;
|
|
59
|
+
}
|
|
60
|
+
`,document.head.appendChild(h)},_e=h=>[...h].sort(()=>Math.random()-.5);function We(h={}){const{logoUrl:a,showLogo:x=!0,baseURL:z}=h,_=s.useRef(null),{validateAllSentences:S,errors:E}=ye(),I=()=>c||window.innerWidth<768,p=()=>c||window.innerWidth<768||window.innerWidth>=320&&window.innerWidth<=932&&window.innerHeight>=390&&window.innerHeight<=932,C=(e="medium")=>{if(!p())return{padding:"12px 24px",fontSize:"16px",minWidth:"auto"};switch(e){case"small":return{padding:"4px 6px",fontSize:"9px",minWidth:"40px"};case"medium":return{padding:"5px 8px",fontSize:"10px",minWidth:"50px"};case"large":return{padding:"6px 10px",fontSize:"11px",minWidth:"60px"}}};s.useEffect(()=>(Ke(),()=>{document.body.style.overflow=""}),[]);const[m,v]=s.useState("select"),[H,de]=s.useState(null),[le,ce]=s.useState(null),[k,U]=s.useState([]),[j,pe]=s.useState(0),[ee,ge]=s.useState([]),[W,ne]=s.useState([]),[B,ue]=s.useState(20),[X,V]=s.useState(0),[nn,he]=s.useState(null),[M,R]=s.useState(null),[l,q]=s.useState(!1),[te,ve]=s.useState(Number(localStorage.getItem("magicSentenceBest"))||0),J=s.useRef(null),[y,D]=s.useState({list:null,index:null,side:null}),[c,ke]=s.useState(!1),[tn,ie]=s.useState(1),[we,oe]=s.useState(null),[He,Ie]=s.useState(!1),[L,Ce]=s.useState(!1),[A,je]=s.useState(!1),[$,De]=s.useState(!1),[G,Te]=s.useState(!1),[N,Pe]=s.useState(!1),[O,Re]=s.useState(!1),[F,ze]=s.useState(!1),[Z,Ee]=s.useState(!1);s.useEffect(()=>{const e=()=>{const t=window.innerWidth,n=window.innerHeight,i=t<768||t===926&&n===428||t===932&&n===430,r=n<700,w=t===768&&n===1024,f=t===1024&&n===768,d=t===820&&n===1180,u=t===1180&&n===820,Q=t===540&&n===720,b=t===720&&n===540,ae=t===1024&&n===1366,Ue=t===1366&&n===1024,Ve=t>=1200&&n>=600&&!i;if(Ie(Ve),Ce(w),je(f),De(d),Te(u),Pe(Q),Re(b),ze(ae),Ee(Ue),ke(i),i)oe(null),ie(1);else if(r)oe(null),ie(1);else{const qe=Math.min(1e3,Math.min(t,n)*.9);oe(qe),ie(1)}};return e(),window.addEventListener("resize",e),()=>window.removeEventListener("resize",e)},[]);const Y=(e,t,n,i)=>{if(l)return;let r=[...ee],w=[...W];const f=e==="bank"?r:w,d=t==="bank"?r:w,u=f.findIndex(ae=>ae.id===n);if(u===-1)return;const[Q]=f.splice(u,1);let b=i;e===t&&b!==null&&b!==void 0&&b>u&&(b=b-1),b==null||b<0||b>d.length?d.push(Q):d.splice(b,0,Q),e==="bank"?r=f:w=f,t==="bank"?r=d:w=d,ge(r),ne(w)},K=(e,t,n)=>{if(e.preventDefault(),l){D({list:null,index:null,side:null});return}const i=e.dataTransfer.getData("application/x-token")||(()=>{const r=e.dataTransfer.getData("text/plain");if(!r)return"";const w=ee.some(u=>u.id===r),f=W.some(u=>u.id===r),d=w?"bank":f?"selected":null;return d?JSON.stringify({from:d,id:r}):""})();if(i){try{const r=JSON.parse(i);if(!r||!r.id||!r.from)return;Y(r.from,t,r.id,n)}catch{}D({list:null,index:null,side:null})}},Be=e=>{de(e),U(Array(e).fill("")),v("time")},Me=e=>{ce(e),v("type")},Le=(e,t)=>{if(t.length>41||t&&!/^[a-zA-Z0-9\s.,!?;:'"-]*$/.test(t))return;const i=[...k];i[e]=t,U(i);const r=S(i);r.isValid||console.warn("Validation errors:",r.errors)},Ae=e=>e.trim().replace(/\s+/g," "),me=e=>e<=3?20:e<=5?18:e<=7?16:e<=9?14:12,$e=()=>{k.some(t=>t.trim().length===0)||(U(t=>t.map(n=>Ae(n))),V(0),pe(0),he(null),v("getready"))};s.useEffect(()=>{if(m==="getready"){const e=setTimeout(()=>re(0),3e3);return()=>clearTimeout(e)}},[m]);const re=e=>{const t=k[e];if(!t)return;const i=_e(t.trim().split(/\s+/).filter(Boolean)).map((r,w)=>({id:`${Date.now()}-${e}-${w}-${Math.random().toString(36).slice(2)}`,text:r}));ge(i),ne([]),pe(e),ue(le||20),R(null),q(!1),v("play")};s.useEffect(()=>{if(m==="play"&&!l)if(J.current!==null&&window.clearTimeout(J.current),B>0)J.current=window.setTimeout(()=>ue(e=>e-1),1e3);else{q(!0);const t=k[j].trim().split(/\s+/),n=W.map(d=>d.text),i=t.filter(d=>!n.includes(d)).length,r=n.filter(d=>!t.includes(d)).length,w=t.filter((d,u)=>d!==n[u]).length,f=i+r+w;f===0?(R("correct"),T("correct"),P("Correct! Well done!")):f===1?(R("almost"),T("half"),P("Almost correct! Just one mistake.")):(R("wrong"),T("wrong"),P("Not quite right. Keep trying!"))}return()=>{J.current!==null&&window.clearTimeout(J.current)}},[m,B,l,k,j,W]);const Ge=(e=!0)=>{if(l&&e){j+1<(H||0)?re(j+1):(v("results"),setTimeout(()=>se(),600));return}if(e&&!l){const n=k[j].trim().split(/\s+/),i=W.map(u=>u.text),r=n.filter(u=>!i.includes(u)).length,w=i.filter(u=>!n.includes(u)).length,f=n.filter((u,Q)=>u!==i[Q]).length,d=r+w+f;d===0&&B>0?(V(u=>u+1),R("correct"),T("correct"),P("Correct! Well done!")):d===1?(V(u=>u+.5),R("almost"),T("half"),P("Almost correct! Just one mistake.")):(R("wrong"),T("wrong"),P("Not quite right. Keep trying!")),j+1<(H||0)?setTimeout(()=>re(j+1),800):(v("results"),setTimeout(()=>se(),600))}};s.useEffect(()=>{m==="results"&&X>te&&(ve(X),localStorage.setItem("magicSentenceBest",String(X)))},[m,X,te]);const T=e=>{const t=new(window.AudioContext||window.webkitAudioContext),n=t.createOscillator(),i=t.createGain();switch(n.connect(i),i.connect(t.destination),e){case"start":n.frequency.value=500;break;case"click":n.frequency.value=800;break;case"correct":n.frequency.value=1e3;break;case"half":n.frequency.value=700;break;case"wrong":n.frequency.value=200;break}i.gain.setValueAtTime(.1,t.currentTime),n.start(),n.stop(t.currentTime+.2)},se=()=>{const t=Date.now()+2500,n=["#ec4c44","#f7c948","#6fcf97","#56ccf2","#bb6bd9"],i=document.createElement("canvas"),r=i.getContext("2d");i.width=window.innerWidth,i.height=window.innerHeight,i.style.position="fixed",i.style.top="0",i.style.left="0",i.style.pointerEvents="none",document.body.appendChild(i);const w=Array.from({length:100}).map(()=>({x:Math.random()*i.width,y:Math.random()*i.height-i.height,size:6+Math.random()*6,color:n[Math.floor(Math.random()*n.length)],speed:2+Math.random()*4,tilt:Math.random()*2*Math.PI})),f=()=>{r.clearRect(0,0,i.width,i.height),w.forEach(d=>{r.fillStyle=d.color,r.beginPath(),r.ellipse(d.x,d.y,d.size,d.size/2,d.tilt,0,2*Math.PI),r.fill(),d.y+=d.speed,d.x+=Math.sin(d.tilt)}),Date.now()<t?requestAnimationFrame(f):document.body.removeChild(i)};f()},Ne=()=>o.jsxs("div",{style:g.gmCenterScreen,children:[o.jsx("h1",{style:g.gmHeadline1,children:"MAGIC SENTENCE"}),o.jsx("p",{style:g.gmBodyM,children:"Select number of rounds"}),o.jsx("div",{style:{display:"flex",gap:p()?"8px":"16px",justifyContent:"center"},children:[3,4,5].map(e=>o.jsxs("button",{onClick:()=>Be(e),style:{...g.gmButton,...C("medium")},children:[e," ROUNDS"]},e))})]}),Oe=()=>o.jsxs("div",{style:g.gmCenterScreen,children:[o.jsx("h1",{style:g.gmHeadline1,children:"MAGIC SENTENCE"}),o.jsx("p",{style:g.gmBodyM,children:"Select time per round"}),o.jsx("div",{style:{display:"flex",gap:p()?"8px":"16px",justifyContent:"center"},children:[15,20,30].map(e=>o.jsxs("button",{onClick:()=>Me(e),style:{...g.gmButton,...C("medium")},children:[e,"s"]},e))})]}),Fe=()=>o.jsxs("div",{style:g.gmCenterScreen,children:[o.jsxs("h2",{style:{...g.gmBodyM,marginBottom:"0px"},children:["Type down ",H," sentence",H&&H>1?"s":""," for your student"]}),o.jsx("p",{style:{...g.gmBodyS,marginBottom:"16px",marginTop:"0px",color:"#6b7280"},children:"Maximum 41 characters per sentence"}),o.jsx("div",{style:{display:"flex",flexDirection:"column",gap:12,width:"auto",minWidth:"fit-content",maxWidth:"600px"},children:k.map((e,t)=>o.jsx("input",{value:e,placeholder:`Sentence ${t+1}`,onChange:n=>Le(t,n.target.value),style:{...g.gmInput,padding:p()?"8px 12px":"12px 16px",fontSize:p()?"14px":"16px",width:"100%",textAlign:"center"}},t))}),o.jsx("button",{onClick:$e,disabled:k.some(e=>e.trim().length===0),style:{...g.gmButton,marginTop:30,background:k.some(e=>e.trim().length===0)?"#ccc":"#ec4c44",cursor:k.some(e=>e.trim().length===0)?"not-allowed":"pointer",...C("large")},children:"PLAY"})]}),Ze=()=>o.jsxs("div",{style:g.gmReadyWrapper,children:[o.jsx("h1",{style:{...g.gmHeadline1,fontSize:p()?"36px":"72px",color:"#ec4c44",marginBottom:"20px",animation:"pulse 1s ease-in-out infinite"},children:"GET READY"}),o.jsx("div",{style:g.gmHourglass,children:"⏳"})]}),Qe=()=>o.jsxs("div",{style:g.gmGameLayout,children:[o.jsxs("h2",{style:{marginBottom:p()?"5px":"10px",fontSize:p()?"16px":"20px"},children:["Round ",j+1,"/",H," — ",l?"TIME'S UP!":`Time: ${B}s`]}),o.jsx("div",{style:{width:"60%",height:p()?"8px":"14px",borderRadius:8,background:"#eee",overflow:"hidden",marginBottom:p()?"10px":"20px"},children:o.jsx("div",{style:{height:"100%",width:`${B/(le||20)*100}%`,background:B<=5?"#ec4c44":"#4caf50",transition:"width 1s linear"}})}),o.jsx("div",{onDragOver:e=>e.preventDefault(),onDrop:e=>K(e,"bank",null),style:{display:"flex",flexWrap:I()?"wrap":"nowrap",gap:c||window.innerWidth<768?"6px":"10px",justifyContent:"center",marginBottom:c||window.innerWidth<768?"15px":"30px",padding:c||window.innerWidth<768?"5px":"10px",width:"100%",boxSizing:"border-box"},children:ee.map((e,t)=>o.jsx("div",{draggable:!l,role:"button",tabIndex:l?-1:0,"aria-label":l?`Word: ${e.text} (time expired)`:be("Drag word",e.text,"to build sentence"),onDragStart:n=>{if(l){n.preventDefault();return}n.dataTransfer.setData("application/x-token",JSON.stringify({from:"bank",id:e.id})),n.dataTransfer.setData("text/plain",e.id),P(`Dragging word: ${e.text}`)},onKeyDown:n=>{l||Se(n,()=>Y("bank","selected",e.id,null))},onDragOver:n=>n.preventDefault(),onDrop:n=>{const i=n.currentTarget.getBoundingClientRect(),r=i.left+i.width/2,w=n.clientX>r?t+1:t;D({list:null,index:null,side:null}),n.stopPropagation(),K(n,"bank",w)},onDragEnter:n=>{if(l)return;const i=n.currentTarget.getBoundingClientRect(),r=i.left+i.width/2;D({list:"bank",index:t,side:n.clientX>r?"right":"left"})},onDragLeave:()=>D({list:null,index:null,side:null}),onClick:()=>{l||Y("bank","selected",e.id,null)},style:{padding:c||window.innerWidth<768?"6px 10px":"10px 16px",borderRadius:c||window.innerWidth<768?"6px":"10px",border:"1px solid #ccc",background:l?"#f0f0f0":"#f9f9f9",cursor:l?"not-allowed":"pointer",fontSize:c||window.innerWidth<768?"12px":"18px",borderLeft:y.list==="bank"&&y.index===t&&y.side==="left"?"3px solid #3b82f6":"1px solid #ccc",borderRight:y.list==="bank"&&y.index===t&&y.side==="right"?"3px solid #3b82f6":"1px solid #ccc",flexShrink:0,flexBasis:"auto",opacity:l?.6:1,transition:"opacity 0.3s ease"},children:e.text},e.id))}),o.jsx("div",{onDragOver:e=>e.preventDefault(),onDrop:e=>K(e,"selected",null),style:{minHeight:c||window.innerWidth<768?"50px":"70px",width:"auto",maxWidth:"none",minWidth:"245px",border:M==="correct"?"2px dashed #4caf50":M==="almost"?"2px dashed #ff9800":M==="wrong"?"2px dashed #f44336":"2px dashed #ccc",borderRadius:c||window.innerWidth<768?"8px":"12px",padding:c||window.innerWidth<768?"8px":"12px",display:"flex",flexWrap:I()?"wrap":"nowrap",alignItems:"center",justifyContent:"center",fontSize:`${me(W.length)}px`,background:M==="correct"?"#e8f5e8":M==="almost"?"#fff3e0":M==="wrong"?"#ffebee":"#fafafa",overflowX:I()?"hidden":"auto",whiteSpace:I()?"normal":"nowrap"},children:W.map((e,t)=>o.jsx("span",{draggable:!l,onDragStart:n=>{if(l){n.preventDefault();return}n.dataTransfer.setData("application/x-token",JSON.stringify({from:"selected",id:e.id})),n.dataTransfer.setData("text/plain",e.id)},onDragOver:n=>n.preventDefault(),onDrop:n=>{const i=n.currentTarget.getBoundingClientRect(),r=i.left+i.width/2,w=n.clientX>r?t+1:t;D({list:null,index:null,side:null}),n.stopPropagation(),K(n,"selected",w)},onDragEnter:n=>{if(l)return;const i=n.currentTarget.getBoundingClientRect(),r=i.left+i.width/2;D({list:"selected",index:t,side:n.clientX>r?"right":"left"})},onDragLeave:()=>D({list:null,index:null,side:null}),onClick:()=>{l||Y("selected","bank",e.id,null)},title:l?"Time expired":"Click to remove back to bank",style:{padding:p()?"4px 6px":"6px 10px",margin:p()?"2px":"4px",borderRadius:p()?"4px":"8px",background:l?"#f0f0f0":"#ffe9e7",border:l?"1px solid #ccc":"1px solid #ec4c44",borderLeft:y.list==="selected"&&y.index===t&&y.side==="left"?"3px solid #3b82f6":void 0,borderRight:y.list==="selected"&&y.index===t&&y.side==="right"?"3px solid #3b82f6":void 0,cursor:l?"not-allowed":"pointer",userSelect:"none",fontSize:`${me(W.length)}px`,fontFamily:'"Roboto", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif',whiteSpace:"nowrap",opacity:l?.6:1,transition:"opacity 0.3s ease"},children:e.text},e.id))}),o.jsx("button",{onClick:()=>Ge(!0),disabled:!l&&W.length===0,style:{marginTop:p()?"15px":"30px",fontSize:p()?"14px":"20px",padding:p()?"6px 12px":"10px 24px",borderRadius:p()?"8px":"12px",background:l||W.length>0?"#ec4c44":"#ccc",color:"white",border:"none",cursor:l||W.length>0?"pointer":"not-allowed"},children:"NEXT"})]}),Xe=()=>o.jsxs("div",{style:g.gmCenterScreen,children:[o.jsx("h1",{style:{...g.gmHeadline1,marginTop:(c&&window.innerWidth>window.innerHeight||window.innerWidth===896&&window.innerHeight===414||window.innerWidth===844&&window.innerHeight===390||window.innerWidth===926&&window.innerHeight===428||window.innerWidth===932&&window.innerHeight===430||L||A||$||G||N||O||F||Z,"0px"),marginBottom:c&&window.innerWidth>window.innerHeight||window.innerWidth===896&&window.innerHeight===414||window.innerWidth===844&&window.innerHeight===390||window.innerWidth===926&&window.innerHeight===428||window.innerWidth===932&&window.innerHeight===430||L||A||$||G||N||O||F||Z?"2px":"10px",fontSize:c&&window.innerWidth<=375&&window.innerHeight<=667||window.innerWidth===896&&window.innerHeight===414||window.innerWidth===844&&window.innerHeight===390||window.innerWidth===926&&window.innerHeight===428||window.innerWidth===932&&window.innerHeight===430?"32px":"clamp(28px, 4vw, 40px)"},children:"Game Over 🎯"}),o.jsxs("h2",{style:{...g.gmHeadline2,marginTop:(c&&window.innerWidth>window.innerHeight||window.innerWidth===896&&window.innerHeight===414||window.innerWidth===844&&window.innerHeight===390||window.innerWidth===926&&window.innerHeight===428||window.innerWidth===932&&window.innerHeight===430||L||A||$||G||N||O||F||Z,"0px"),marginBottom:c&&window.innerWidth>window.innerHeight||window.innerWidth===896&&window.innerHeight===414||window.innerWidth===844&&window.innerHeight===390||window.innerWidth===926&&window.innerHeight===428||window.innerWidth===932&&window.innerHeight===430||L||A||$||G||N||O||F||Z?"2px":"16px",fontSize:c&&window.innerWidth<=375&&window.innerHeight<=667||window.innerWidth===896&&window.innerHeight===414||window.innerWidth===844&&window.innerHeight===390||window.innerWidth===926&&window.innerHeight===428||window.innerWidth===932&&window.innerHeight===430?"18px":"24px"},children:["Your score: ",X," out of ",H]}),o.jsxs("p",{style:{...g.gmBodyM,color:"#10b981",marginTop:c&&window.innerWidth>window.innerHeight||window.innerWidth===896&&window.innerHeight===414||window.innerWidth===844&&window.innerHeight===390||window.innerWidth===926&&window.innerHeight===428||window.innerWidth===932&&window.innerHeight===430||L||A||$||G||N||O||F||Z?"0px":"12px",marginBottom:c&&window.innerWidth>window.innerHeight||window.innerWidth===896&&window.innerHeight===414||window.innerWidth===844&&window.innerHeight===390||window.innerWidth===926&&window.innerHeight===428||window.innerWidth===932&&window.innerHeight===430||L||A||$||G||N||O||F||Z?"2px":"16px",fontSize:c&&window.innerWidth<=375&&window.innerHeight<=667||window.innerWidth===896&&window.innerHeight===414||window.innerWidth===844&&window.innerHeight===390||window.innerWidth===926&&window.innerHeight===428||window.innerWidth===932&&window.innerHeight===430?"14px":"16px"},children:["Best score: ",te]}),o.jsxs("div",{style:{display:"flex",gap:c&&window.innerWidth>window.innerHeight||c&&window.innerWidth<=375&&window.innerHeight<=667||window.innerWidth===896&&window.innerHeight===414||window.innerWidth===844&&window.innerHeight===390||window.innerWidth===926&&window.innerHeight===428||window.innerWidth===932&&window.innerHeight===430?"6px":"12px",marginTop:c&&window.innerWidth>window.innerHeight||c&&window.innerWidth<=375&&window.innerHeight<=667||window.innerWidth===896&&window.innerHeight===414||window.innerWidth===844&&window.innerHeight===390||window.innerWidth===926&&window.innerHeight===428||window.innerWidth===932&&window.innerHeight===430?"2px":window.innerWidth===1366&&window.innerHeight===766||window.innerWidth===1366&&window.innerHeight===768||window.innerWidth===1280&&window.innerHeight===720||window.innerWidth===1440&&window.innerHeight===900||He?"12px":"24px"},children:[o.jsx("button",{onClick:()=>{se(),T("start"),setTimeout(()=>{v("getready"),he(null),q(!1)},800)},style:{...g.gmButton,...C("medium")},children:"🔁 Play again"}),o.jsx("button",{onClick:()=>{T("click"),v("select"),de(null),ce(null),U([]),V(0),ne([]),q(!1)},style:{...g.gmButton,...C("medium")},children:"⬅️ Exit"})]})]}),fe=a||(z?`${z.endsWith("/")?z.slice(0,-1):z}/logo.svg`:typeof window<"u"&&window.origin?`${window.origin}/browser/speakid/games/magic%20sentence/logo.svg`:null),Je=!c&&x&&!(window.innerWidth>window.innerHeight)&&window.innerHeight>=700;return o.jsx("div",{ref:_,style:{width:"100%",height:"100%",display:"flex",justifyContent:"center",alignItems:"center",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",transition:"background 0.3s ease",overflow:"hidden",position:"absolute",top:0,left:0,right:0,bottom:0},children:o.jsx("div",{style:{width:c?"100%":we||1e3,height:c?"100%":we||1e3,display:"flex",justifyContent:"center",alignItems:"center",overflow:"hidden",borderRadius:c?0:"20px",background:"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)",boxShadow:c?"none":"0 0 40px rgba(0,0,0,0.1)",margin:c?"0 auto":"unset",position:"relative"},children:o.jsx("div",{style:{transform:"none",width:"100%",height:"100%",display:"flex",justifyContent:"center",alignItems:"center"},children:o.jsxs("div",{id:"magic-sentence-root",children:[Je?o.jsx("div",{style:{...g.gmLogoFixed,display:"block"},children:fe?o.jsx("img",{src:fe,alt:"SPEAKID Logo",style:g.gmLogoImg,loading:"lazy"}):o.jsx("div",{style:g.gmLogoImg,children:"SPEAKID"})}):null,m==="select"?Ne():null,m==="time"?Oe():null,m==="type"?Fe():null,m==="getready"?Ze():null,m==="play"?Qe():null,m==="results"?Xe():null]})})})})}class en extends s.Component{constructor(a){super(a),this.state={hasError:!1}}static getDerivedStateFromError(a){return{hasError:!0,error:a}}componentDidCatch(a,x){console.error("Game Error:",a,x),this.setState({error:a,errorInfo:x})}handleReset=()=>{this.setState({hasError:!1,error:void 0,errorInfo:void 0})};render(){return this.state.hasError?this.props.fallback?this.props.fallback:o.jsxs("div",{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",minHeight:"100vh",padding:"20px",textAlign:"center",backgroundColor:"#fef2f2",color:"#dc2626",fontFamily:"system-ui, sans-serif"},children:[o.jsx("h1",{style:{fontSize:"24px",marginBottom:"16px"},children:"🚨 Oops! Something went wrong"}),o.jsx("p",{style:{fontSize:"16px",marginBottom:"24px",maxWidth:"500px"},children:"The game encountered an unexpected error. Don't worry, your progress is saved!"}),o.jsx("button",{onClick:this.handleReset,style:{padding:"12px 24px",fontSize:"16px",backgroundColor:"#dc2626",color:"white",border:"none",borderRadius:"8px",cursor:"pointer",transition:"background-color 0.2s"},onMouseOver:a=>a.currentTarget.style.backgroundColor="#b91c1c",onMouseOut:a=>a.currentTarget.style.backgroundColor="#dc2626",children:"🔄 Restart Game"}),typeof process<"u"&&process.env.NODE_ENV==="development"&&this.state.error&&o.jsxs("details",{style:{marginTop:"20px",textAlign:"left",maxWidth:"600px"},children:[o.jsx("summary",{style:{cursor:"pointer",fontSize:"14px"},children:"Technical Details (Development Only)"}),o.jsxs("pre",{style:{backgroundColor:"#f3f4f6",padding:"12px",borderRadius:"4px",fontSize:"12px",overflow:"auto",marginTop:"8px"},children:[this.state.error.toString(),this.state.errorInfo?.componentStack]})]})]}):this.props.children}}exports.ErrorBoundary=en;exports.Game=We;exports.announceToScreenReader=P;exports.createAriaLabel=be;exports.default=We;exports.handleKeyDown=Se;exports.useValidation=ye;
|
|
61
|
+
//# sourceMappingURL=speakid-build-a-sentence.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speakid-build-a-sentence.cjs.js","sources":["../src/Game.styles.ts","../src/hooks/useValidation.ts","../src/utils/accessibility.ts","../src/Game.tsx","../src/components/ErrorBoundary.tsx"],"sourcesContent":["import { CSSProperties } from \"react\";\n\n// ===== Добавляем анимации в <head> с уникальным ID =====\nconst keyframes = `\n @keyframes magic-sentence-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n \n @keyframes magic-sentence-pulse {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(1.05); }\n }\n \n @keyframes magic-sentence-shake {\n 0%, 100% { transform: translateX(0); }\n 25% { transform: translateX(-5px); }\n 75% { transform: translateX(5px); }\n }\n \n @keyframes magic-sentence-slideIn {\n from { transform: translateY(-20px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n }\n \n @keyframes magic-sentence-bounce {\n 0%, 20%, 53%, 80%, 100% { transform: translate3d(0,0,0); }\n 40%, 43% { transform: translate3d(0, -8px, 0); }\n 70% { transform: translate3d(0, -4px, 0); }\n 90% { transform: translate3d(0, -2px, 0); }\n }\n \n @keyframes magic-sentence-glow {\n 0%, 100% { box-shadow: 0 0 5px rgba(76, 175, 80, 0.5); }\n 50% { box-shadow: 0 0 20px rgba(76, 175, 80, 0.8), 0 0 30px rgba(76, 175, 80, 0.6); }\n }\n`;\n\nif (typeof document !== \"undefined\" && !document.getElementById(\"magic-sentence-keyframes\")) {\n const styleTag = document.createElement(\"style\");\n styleTag.id = \"magic-sentence-keyframes\";\n styleTag.innerHTML = keyframes;\n document.head.appendChild(styleTag);\n}\n\n// ===== Анимации =====\nconst animations = {\n spin: {\n animation: \"magic-sentence-spin 1.4s linear infinite\",\n },\n pulse: {\n animation: \"magic-sentence-pulse 0.6s ease-in-out\",\n },\n shake: {\n animation: \"magic-sentence-shake 0.4s ease-in-out\",\n },\n slideIn: {\n animation: \"magic-sentence-slideIn 0.3s ease-out\",\n },\n bounce: {\n animation: \"magic-sentence-bounce 0.6s ease-in-out\",\n },\n glow: {\n animation: \"magic-sentence-glow 1s ease-in-out infinite\",\n },\n};\n\n// ===== Основные стили =====\nexport const styles: Record<string, CSSProperties> = {\n gmCenterScreen: {\n position: \"relative\",\n zIndex: 1,\n // use percent so the component fits inside the centered square container\n // (100vh caused overflow on tablets because it measured the viewport, not the container)\n minHeight: \"100%\",\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n textAlign: \"center\",\n color: \"#1f2937\",\n padding: \"24px 16px\",\n boxSizing: \"border-box\",\n transform: \"translateY(20px)\", // чуть вниз, чтобы компенсировать логотип\n },\n\n gmHeadline1: {\n fontWeight: 700,\n fontSize: \"clamp(28px, 4vw, 40px)\",\n lineHeight: \"110%\",\n },\n\n gmHeadline2: {\n fontWeight: 600,\n fontSize: \"24px\",\n lineHeight: \"120%\",\n },\n\n gmHeadline3: {\n fontWeight: 600,\n fontSize: \"18px\",\n lineHeight: \"130%\",\n },\n\n gmBodyL: {\n fontWeight: 400,\n fontSize: \"18px\",\n lineHeight: \"140%\",\n },\n\n gmBodyM: {\n fontWeight: 400,\n fontSize: \"16px\",\n lineHeight: \"140%\",\n },\n\n gmBodyS: {\n fontWeight: 400,\n fontSize: \"14px\",\n lineHeight: \"140%\",\n color: \"#6b7280\",\n },\n\n gmButton: {\n fontFamily:\n '\"Geist\", system-ui, -apple-system, \"Segoe UI\", Roboto, Arial, \"Noto Sans\"',\n fontWeight: 600,\n fontSize: \"16px\",\n padding: \"10px 16px\",\n borderRadius: \"12px\",\n border: \"1px solid #e5e7eb\",\n background: \"#ec4c44\",\n color: \"#ffffff\",\n cursor: \"pointer\",\n boxShadow: \"0 6px 18px rgba(236, 76, 68, .18)\",\n transition:\n \"transform .06s ease, box-shadow .2s ease, background .2s ease, opacity .2s ease\",\n },\n\n gmButtonActive: {\n background: \"#333\",\n color: \"#fff\",\n },\n\n gmGameLayout: {\n position: \"relative\",\n width: \"100%\",\n // allow the layout to expand within the square container for tablets/laptops\n maxWidth: \"none\",\n // should fill the parent square, not the full viewport\n minHeight: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n textAlign: \"center\",\n color: \"#1f2937\",\n padding: \"16px 8px\",\n margin: \"0 auto\",\n },\n\n gmGrid: {\n width: \"100%\",\n // let the grid use all available space; sizing is controlled in Game.tsx\n maxWidth: \"none\",\n margin: \"0 auto\",\n display: \"grid\",\n // defaults; overridden responsively in Game.tsx\n gridTemplateColumns: \"repeat(3, 210px)\",\n gridAutoRows: \"210px\",\n gap: \"20px\",\n justifyContent: \"center\",\n },\n\n gmCard: {\n border: \"1px solid #e5e7eb\",\n borderRadius: \"16px\",\n background: \"#f9f9f9\",\n aspectRatio: \"1 / 1\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n overflow: \"hidden\",\n transition:\n \"transform .2s ease, box-shadow .2s ease, border-color .2s ease\",\n },\n\n gmCorrect: {\n border: \"2px solid #10b981\",\n boxShadow: \"0 0 18px rgba(16,185,129,.45)\",\n background: \"#ecfdf5\",\n },\n\n gmWrong: {\n border: \"2px solid #ec4c44\",\n boxShadow: \"0 0 18px rgba(236,76,68,.35)\",\n background: \"#fef2f2\",\n },\n\n gmInput: {\n padding: \"6px 10px\",\n borderRadius: \"6px\",\n border: \"1px solid #ccc\",\n fontSize: \"16px\",\n fontFamily: '\"Geist\", system-ui',\n width: \"160px\",\n },\n\n gmTable: {\n marginTop: \"20px\",\n marginBottom: \"32px\",\n borderCollapse: \"collapse\",\n width: \"100%\",\n maxWidth: \"520px\",\n tableLayout: \"fixed\",\n textAlign: \"center\",\n },\n\n gmTableCell: {\n padding: \"8px 12px\",\n borderBottom: \"1px solid #e5e7eb\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n },\n\n // ✅ Обновлено под стандарты SPEAKID\n gmLogoFixed: {\n position: \"absolute\",\n top: \"16px\",\n left: \"16px\",\n width: \"120px\",\n zIndex: 30,\n pointerEvents: \"none\",\n background: \"transparent\",\n transform: \"none\",\n willChange: \"auto\",\n },\n\n gmLogoImg: {\n height: \"clamp(28px, 5vw, 40px)\",\n width: \"auto\",\n background: \"transparent\",\n backgroundImage: \"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjQwIiB2aWV3Qm94PSIwIDAgMTAwIDQwIiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8dGV4dCB4PSI1MCIgeT0iMjUiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIyMCIgZm9udC13ZWlnaHQ9ImJvbGQiIGZpbGw9IiNlYzRjNDQiIHRleHQtYW5jaG9yPSJtaWRkbGUiPlNQRUFLSUQ8L3RleHQ+Cjwvc3ZnPgo=')\",\n backgroundSize: \"contain\",\n backgroundRepeat: \"no-repeat\",\n backgroundPosition: \"center\",\n transform: \"translateZ(0)\",\n backfaceVisibility: \"hidden\",\n WebkitFontSmoothing: \"antialiased\",\n objectFit: \"contain\",\n imageRendering: \"auto\",\n },\n\n gmReadyWrapper: {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n // use percent so the wrapper scales with the container square\n height: \"60%\",\n gap: \"16px\",\n },\n\n gmHourglass: {\n fontSize: \"42px\",\n ...animations.spin,\n },\n\n // ===== Анимационные стили =====\n ...animations,\n};","import { useState, useCallback } from 'react';\n\nexport interface ValidationError {\n type: 'length' | 'characters' | 'empty' | 'duplicate';\n message: string;\n}\n\nexport interface ValidationResult {\n isValid: boolean;\n errors: ValidationError[];\n}\n\nexport const useValidation = () => {\n const [errors, setErrors] = useState<ValidationError[]>([]);\n\n const validateSentence = useCallback((sentence: string, index: number, allSentences: string[]): ValidationResult => {\n const newErrors: ValidationError[] = [];\n\n // Проверка на пустоту\n if (!sentence.trim()) {\n newErrors.push({\n type: 'empty',\n message: 'Sentence cannot be empty'\n });\n }\n\n // Проверка длины\n if (sentence.length > 41) {\n newErrors.push({\n type: 'length',\n message: `Sentence is too long (${sentence.length}/41 characters)`\n });\n }\n\n // Проверка символов (только латиница)\n const latinRegex = /^[a-zA-Z0-9\\s.,!?;:'\"-]*$/;\n if (sentence && !latinRegex.test(sentence)) {\n newErrors.push({\n type: 'characters',\n message: 'Only Latin characters, numbers, spaces and punctuation are allowed'\n });\n }\n\n // Проверка на дубликаты\n const duplicateIndex = allSentences.findIndex((s, i) => i !== index && s.toLowerCase().trim() === sentence.toLowerCase().trim());\n if (duplicateIndex !== -1) {\n newErrors.push({\n type: 'duplicate',\n message: `Duplicate sentence (same as sentence ${duplicateIndex + 1})`\n });\n }\n\n setErrors(newErrors);\n return {\n isValid: newErrors.length === 0,\n errors: newErrors\n };\n }, []);\n\n const validateAllSentences = useCallback((sentences: string[]): ValidationResult => {\n const allErrors: ValidationError[] = [];\n \n sentences.forEach((sentence, index) => {\n const result = validateSentence(sentence, index, sentences);\n allErrors.push(...result.errors.map(error => ({\n ...error,\n message: `Sentence ${index + 1}: ${error.message}`\n })));\n });\n\n return {\n isValid: allErrors.length === 0,\n errors: allErrors\n };\n }, [validateSentence]);\n\n const clearErrors = useCallback(() => {\n setErrors([]);\n }, []);\n\n return {\n errors,\n validateSentence,\n validateAllSentences,\n clearErrors,\n };\n};\n\n","// Утилиты для улучшения доступности\n\nexport const createAriaLabel = (action: string, word?: string, context?: string): string => {\n if (word && context) {\n return `${action} word \"${word}\" ${context}`;\n }\n if (word) {\n return `${action} word \"${word}\"`;\n }\n return action;\n};\n\nexport const getRoleForElement = (type: 'button' | 'draggable' | 'droppable' | 'input'): string => {\n const roles = {\n button: 'button',\n draggable: 'button',\n droppable: 'region',\n input: 'textbox'\n };\n return roles[type];\n};\n\nexport const handleKeyDown = (\n event: React.KeyboardEvent,\n action: () => void,\n allowedKeys: string[] = ['Enter', ' ']\n) => {\n if (allowedKeys.includes(event.key)) {\n event.preventDefault();\n action();\n }\n};\n\nexport const announceToScreenReader = (message: string) => {\n // Создаем временный элемент для объявления\n const announcement = document.createElement('div');\n announcement.setAttribute('aria-live', 'polite');\n announcement.setAttribute('aria-atomic', 'true');\n announcement.style.position = 'absolute';\n announcement.style.left = '-10000px';\n announcement.style.width = '1px';\n announcement.style.height = '1px';\n announcement.style.overflow = 'hidden';\n \n document.body.appendChild(announcement);\n announcement.textContent = message;\n \n // Удаляем элемент после объявления\n setTimeout(() => {\n document.body.removeChild(announcement);\n }, 1000);\n};\n\nexport const getFocusableElements = (container: HTMLElement): HTMLElement[] => {\n const focusableSelectors = [\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n '[role=\"button\"]:not([disabled])'\n ].join(', ');\n \n return Array.from(container.querySelectorAll(focusableSelectors));\n};\n\nexport const trapFocus = (container: HTMLElement) => {\n const focusableElements = getFocusableElements(container);\n \n if (focusableElements.length === 0) return;\n \n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n \n const handleTabKey = (e: KeyboardEvent) => {\n if (e.key === 'Tab') {\n if (e.shiftKey) {\n if (document.activeElement === firstElement) {\n lastElement.focus();\n e.preventDefault();\n }\n } else {\n if (document.activeElement === lastElement) {\n firstElement.focus();\n e.preventDefault();\n }\n }\n }\n };\n \n container.addEventListener('keydown', handleTabKey);\n \n // Фокусируем первый элемент\n firstElement.focus();\n \n // Возвращаем функцию для очистки\n return () => {\n container.removeEventListener('keydown', handleTabKey);\n };\n};\n\n","// ======================\n// MAGIC SENTENCE GAME (SPEAKID)\n// React 18 + TypeScript + Vite\n// Адаптивная верстка для всех устройств\n// ======================\n\nimport * as React from \"react\";\nimport { useState, useEffect, useRef } from \"react\";\nimport { styles } from \"./Game.styles\";\nimport { ErrorBoundary } from \"./components/ErrorBoundary\";\nimport { useValidation } from \"./hooks/useValidation\";\nimport { createAriaLabel, handleKeyDown, announceToScreenReader } from \"./utils/accessibility\";\n\ntype Stage = \"select\" | \"time\" | \"type\" | \"getready\" | \"play\" | \"results\";\ntype Token = { id: string; text: string };\n\n// ✅ базовый reset\nconst globalReset = () => {\n const style = document.createElement(\"style\");\n style.textContent = `\n #magic-sentence-root, #magic-sentence-root * {\n box-sizing: border-box;\n font-family: \"Geist\", system-ui, -apple-system, \"Segoe UI\", Roboto, Arial, sans-serif;\n }\n #magic-sentence-root img {\n max-width: 100%;\n height: auto;\n display: block;\n user-select: none;\n }\n html, body {\n margin: 0 !important;\n padding: 0 !important;\n width: 100% !important;\n height: 100% !important;\n overflow: hidden !important;\n zoom: 1 !important;\n }\n #root {\n margin: 0 !important;\n padding: 0 !important;\n width: 100% !important;\n height: 100% !important;\n overflow: hidden !important;\n }\n `;\n document.head.appendChild(style);\n};\n\nconst shuffle = (arr: string[]) => [...arr].sort(() => Math.random() - 0.5);\n\nexport interface GameProps {\n logoUrl?: string;\n showLogo?: boolean;\n baseURL?: string;\n}\n\nfunction GameComponent(props: GameProps = {}) {\n const { logoUrl, showLogo = true, baseURL } = props;\n const containerRef = useRef<HTMLDivElement>(null);\n \n // Новые хуки\n const { validateAllSentences, errors: validationErrors } = useValidation();\n\n // Функция для определения нужно ли переносить слова\n const shouldWrapWords = () => {\n // Переносим слова на всех мобильных устройствах\n return isMobile || window.innerWidth < 768;\n };\n\n // Универсальная функция для определения мобильных устройств\n const isMobileDevice = () => {\n return isMobile || \n window.innerWidth < 768 || \n (window.innerWidth >= 320 && window.innerWidth <= 932 && window.innerHeight >= 390 && window.innerHeight <= 932);\n };\n\n // Вспомогательная функция для мобильных размеров кнопок\n const getMobileButtonStyles = (type: 'small' | 'medium' | 'large' = 'medium') => {\n if (!isMobileDevice()) {\n return {\n padding: \"12px 24px\",\n fontSize: \"16px\",\n minWidth: \"auto\"\n };\n }\n\n switch (type) {\n case 'small':\n return {\n padding: \"4px 6px\",\n fontSize: \"9px\",\n minWidth: \"40px\"\n };\n case 'medium':\n return {\n padding: \"5px 8px\",\n fontSize: \"10px\",\n minWidth: \"50px\"\n };\n case 'large':\n return {\n padding: \"6px 10px\",\n fontSize: \"11px\",\n minWidth: \"60px\"\n };\n }\n };\n\n useEffect(() => {\n globalReset();\n return () => {\n document.body.style.overflow = \"\";\n };\n }, []);\n\n const [stage, setStage] = useState<Stage>(\"select\");\n const [rounds, setRounds] = useState<number | null>(null);\n const [timePerRound, setTimePerRound] = useState<number | null>(null);\n const [sentences, setSentences] = useState<string[]>([]);\n const [currentRound, setCurrentRound] = useState(0);\n const [words, setWords] = useState<Token[]>([]);\n const [selected, setSelected] = useState<Token[]>([]);\n const [timeLeft, setTimeLeft] = useState(20);\n const [score, setScore] = useState(0);\n const [countdown, setCountdown] = useState<number | null>(null);\n const [resultType, setResultType] = useState<\"correct\" | \"almost\" | \"wrong\" | null>(null);\n const [timeExpired, setTimeExpired] = useState(false);\n const [bestScore, setBestScore] = useState<number>(\n Number(localStorage.getItem(\"magicSentenceBest\")) || 0\n );\n const timerRef = useRef<number | null>(null);\n const [hover, setHover] = useState<{ list: ListName | null; index: number | null; side: \"left\" | \"right\" | null }>({ list: null, index: null, side: null });\n\n // Адаптивность\n const [isMobile, setIsMobile] = useState(false);\n const [scale, setScale] = useState(1);\n const [containerSize, setContainerSize] = useState<number | null>(null);\n const [isDesktopLayout, setIsDesktopLayout] = useState(false);\n const [isIPadMiniPortrait, setIsIPadMiniPortrait] = useState(false);\n const [isIPadMiniLandscape, setIsIPadMiniLandscape] = useState(false);\n const [isIPadAirPortrait, setIsIPadAirPortrait] = useState(false);\n const [isIPadAirLandscape, setIsIPadAirLandscape] = useState(false);\n const [isSurfaceDuoPortrait, setIsSurfaceDuoPortrait] = useState(false);\n const [isSurfaceDuoLandscape, setIsSurfaceDuoLandscape] = useState(false);\n const [isIPadProPortrait, setIsIPadProPortrait] = useState(false);\n const [isIPadProLandscape, setIsIPadProLandscape] = useState(false);\n\n // ✅ адаптив под мобилки, планшеты и десктоп\n useEffect(() => {\n const resize = () => {\n const width = window.innerWidth;\n const height = window.innerHeight;\n const mobile = width < 768 || (width === 926 && height === 428) || (width === 932 && height === 430);\n const isLandscape = (width > height && mobile) || (width === 926 && height === 428) || (width === 932 && height === 430);\n const isSmallHeight = height < 700;\n \n // iPad размеры\n const isIPadMiniPortrait = width === 768 && height === 1024;\n const isIPadMiniLandscape = width === 1024 && height === 768;\n const isIPadAirPortrait = width === 820 && height === 1180;\n const isIPadAirLandscape = width === 1180 && height === 820;\n \n // Surface DUO размеры\n const isSurfaceDuoPortrait = width === 540 && height === 720;\n const isSurfaceDuoLandscape = width === 720 && height === 540;\n \n // iPad Pro размеры\n const isIPadProPortrait = width === 1024 && height === 1366;\n const isIPadProLandscape = width === 1366 && height === 1024;\n \n // Десктопные разрешения\n const desktopLayout = width >= 1200 && height >= 600 && !mobile;\n setIsDesktopLayout(desktopLayout);\n \n // Установка состояний для iPad и Surface DUO\n setIsIPadMiniPortrait(isIPadMiniPortrait);\n setIsIPadMiniLandscape(isIPadMiniLandscape);\n setIsIPadAirPortrait(isIPadAirPortrait);\n setIsIPadAirLandscape(isIPadAirLandscape);\n setIsSurfaceDuoPortrait(isSurfaceDuoPortrait);\n setIsSurfaceDuoLandscape(isSurfaceDuoLandscape);\n setIsIPadProPortrait(isIPadProPortrait);\n setIsIPadProLandscape(isIPadProLandscape);\n \n setIsMobile(mobile);\n\n // ✅ Адаптивные размеры контейнера\n if (mobile) {\n setContainerSize(null);\n setScale(1);\n } else if (isSmallHeight) {\n setContainerSize(null);\n setScale(1);\n } else {\n const minSize = 400;\n const maxSize = 1200;\n const finalSize = Math.min(1000, Math.min(width, height) * 0.9);\n setContainerSize(finalSize);\n setScale(1);\n }\n };\n resize();\n window.addEventListener(\"resize\", resize);\n return () => window.removeEventListener(\"resize\", resize);\n }, []);\n\n // =========================\n // DND HELPERS\n // =========================\n type ListName = \"bank\" | \"selected\";\n type DragPayload = { from: ListName; id: string };\n\n const moveToken = (\n from: ListName,\n to: ListName,\n id: string,\n insertIndex: number | null\n ) => {\n // Блокируем перемещение если время истекло\n if (timeExpired) return;\n\n let nextWords = [...words];\n let nextSelected = [...selected];\n\n const takeFrom = from === \"bank\" ? nextWords : nextSelected;\n const putTo = to === \"bank\" ? nextWords : nextSelected;\n\n const idx = takeFrom.findIndex((t) => t.id === id);\n if (idx === -1) return;\n const [token] = takeFrom.splice(idx, 1);\n\n let targetIndex = insertIndex;\n if (\n from === to &&\n targetIndex !== null &&\n targetIndex !== undefined\n ) {\n if (targetIndex > idx) targetIndex = targetIndex - 1;\n }\n\n if (\n targetIndex === null ||\n targetIndex === undefined ||\n targetIndex < 0 ||\n targetIndex > putTo.length\n ) {\n putTo.push(token);\n } else {\n putTo.splice(targetIndex, 0, token);\n }\n\n if (from === \"bank\") nextWords = takeFrom; else nextSelected = takeFrom;\n if (to === \"bank\") nextWords = putTo; else nextSelected = putTo;\n\n setWords(nextWords);\n setSelected(nextSelected);\n };\n\n const handleDropTo = (\n e: React.DragEvent,\n to: ListName,\n insertIndex: number | null\n ) => {\n e.preventDefault();\n \n // Блокируем drop если время истекло\n if (timeExpired) {\n setHover({ list: null, index: null, side: null });\n return;\n }\n\n const raw = e.dataTransfer.getData(\"application/x-token\") ||\n (() => {\n const fallbackId = e.dataTransfer.getData(\"text/plain\");\n if (!fallbackId) return \"\";\n const inBank = words.some((t) => t.id === fallbackId);\n const inSelected = selected.some((t) => t.id === fallbackId);\n const from: ListName | null = inBank ? \"bank\" : inSelected ? \"selected\" : null;\n return from ? JSON.stringify({ from, id: fallbackId }) : \"\";\n })();\n if (!raw) return;\n try {\n const payload = JSON.parse(raw) as DragPayload;\n if (!payload || !payload.id || !payload.from) return;\n moveToken(payload.from, to, payload.id, insertIndex);\n } catch {\n // ignore bad payload\n }\n setHover({ list: null, index: null, side: null });\n };\n\n // =========================\n // START / SETUP\n // =========================\n const handleSelect = (num: number) => {\n setRounds(num);\n setSentences(Array(num).fill(\"\"));\n setStage(\"time\");\n };\n\n const handleTimeSelect = (time: number) => {\n setTimePerRound(time);\n setStage(\"type\");\n };\n\n const handleChange = (index: number, value: string) => {\n // Ограничение на 41 символ (включая пробелы и точку)\n if (value.length > 41) {\n return;\n }\n \n // Проверка на латинские символы (a-z, A-Z, пробелы, цифры, знаки препинания)\n const latinRegex = /^[a-zA-Z0-9\\s.,!?;:'\"-]*$/;\n if (value && !latinRegex.test(value)) {\n return; // Не сохраняем, если есть нелатинские символы\n }\n \n const updated = [...sentences];\n updated[index] = value;\n setSentences(updated);\n \n // Валидация при вводе\n const validation = validateAllSentences(updated);\n if (!validation.isValid) {\n console.warn('Validation errors:', validation.errors);\n }\n };\n\n const normalizeSentence = (s: string) => s.trim().replace(/\\s+/g, \" \");\n\n // Адаптивный размер шрифта в зависимости от количества слов\n const getAdaptiveFontSize = (wordCount: number) => {\n if (wordCount <= 3) return 20;\n if (wordCount <= 5) return 18;\n if (wordCount <= 7) return 16;\n if (wordCount <= 9) return 14;\n return 12;\n };\n\n const startGame = () => {\n const hasEmpty = sentences.some((s) => s.trim().length === 0);\n if (hasEmpty) {\n return;\n }\n setSentences((prev) => prev.map((s) => normalizeSentence(s)));\n setScore(0);\n setCurrentRound(0);\n setCountdown(null); // Убираем цифровой отсчет\n setStage(\"getready\");\n };\n\n // GET READY с 3-секундной задержкой\n useEffect(() => {\n if (stage === \"getready\") {\n const t = setTimeout(() => startRound(0), 3000); // 3 секунды задержки\n return () => clearTimeout(t);\n }\n }, [stage]);\n\n const startRound = (index: number) => {\n const target = sentences[index];\n if (!target) return;\n const shuffled = shuffle(target\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n );\n const tokens: Token[] = shuffled.map((w, i) => ({\n id: `${Date.now()}-${index}-${i}-${Math.random().toString(36).slice(2)}`,\n text: w,\n }));\n setWords(tokens);\n setSelected([]);\n setCurrentRound(index);\n setTimeLeft(timePerRound || 20); // Используем выбранное время\n setResultType(null); // Сбрасываем результат\n setTimeExpired(false); // Сбрасываем состояние истечения времени\n setStage(\"play\");\n };\n\n // TIMER\n useEffect(() => {\n if (stage === \"play\" && !timeExpired) {\n if (timerRef.current !== null) window.clearTimeout(timerRef.current);\n if (timeLeft > 0) {\n timerRef.current = window.setTimeout(() => setTimeLeft((t) => t - 1), 1000);\n } else {\n // Время истекло - показываем результат и кнопку NEXT\n setTimeExpired(true);\n // Вызываем handleNext с manual=false для подсчета результата\n const correct = sentences[currentRound];\n const correctWords = correct.trim().split(/\\s+/);\n const selectedTexts = selected.map((t) => t.text);\n \n // Считаем ошибки: недостающие слова + лишние слова + неправильный порядок\n const missingWords = correctWords.filter(word => !selectedTexts.includes(word)).length;\n const extraWords = selectedTexts.filter(word => !correctWords.includes(word)).length;\n const wrongOrder = correctWords.filter((w, i) => w !== selectedTexts[i]).length;\n \n // Общее количество ошибок = недостающие + лишние + неправильный порядок\n const errors = missingWords + extraWords + wrongOrder;\n\n // Показываем результат\n if (errors === 0) {\n setResultType(\"correct\");\n playSound(\"correct\");\n announceToScreenReader(\"Correct! Well done!\");\n } else if (errors === 1) {\n setResultType(\"almost\");\n playSound(\"half\");\n announceToScreenReader(\"Almost correct! Just one mistake.\");\n } else {\n setResultType(\"wrong\");\n playSound(\"wrong\");\n announceToScreenReader(\"Not quite right. Keep trying!\");\n }\n }\n }\n return () => {\n if (timerRef.current !== null) window.clearTimeout(timerRef.current);\n };\n }, [stage, timeLeft, timeExpired, sentences, currentRound, selected]);\n\n // =========================\n // SCORING / NEXT ROUND\n // =========================\n const handleNext = (manual = true) => {\n // Если время истекло и это ручное нажатие NEXT, переходим к следующему раунду\n if (timeExpired && manual) {\n if (currentRound + 1 < (rounds || 0)) {\n startRound(currentRound + 1);\n } else {\n setStage(\"results\");\n setTimeout(() => triggerConfetti(), 600);\n }\n return;\n }\n\n // Если время не истекло, обрабатываем ручное нажатие\n if (manual && !timeExpired) {\n const correct = sentences[currentRound];\n const correctWords = correct.trim().split(/\\s+/);\n const selectedTexts = selected.map((t) => t.text);\n \n // Считаем ошибки: недостающие слова + лишние слова + неправильный порядок\n const missingWords = correctWords.filter(word => !selectedTexts.includes(word)).length;\n const extraWords = selectedTexts.filter(word => !correctWords.includes(word)).length;\n const wrongOrder = correctWords.filter((w, i) => w !== selectedTexts[i]).length;\n \n // Общее количество ошибок = недостающие + лишние + неправильный порядок\n const errors = missingWords + extraWords + wrongOrder;\n\n if (errors === 0 && timeLeft > 0) {\n setScore((s) => s + 1);\n setResultType(\"correct\");\n playSound(\"correct\");\n announceToScreenReader(\"Correct! Well done!\");\n } else if (errors === 1) {\n setScore((s) => s + 0.5);\n setResultType(\"almost\");\n playSound(\"half\");\n announceToScreenReader(\"Almost correct! Just one mistake.\");\n } else {\n setResultType(\"wrong\");\n playSound(\"wrong\");\n announceToScreenReader(\"Not quite right. Keep trying!\");\n }\n\n // Переходим к следующему раунду\n if (currentRound + 1 < (rounds || 0)) {\n setTimeout(() => startRound(currentRound + 1), 800);\n } else {\n setStage(\"results\");\n setTimeout(() => triggerConfetti(), 600);\n }\n }\n };\n\n // =========================\n // SAVE BEST SCORE\n // =========================\n useEffect(() => {\n if (stage === \"results\" && score > bestScore) {\n setBestScore(score);\n localStorage.setItem(\"magicSentenceBest\", String(score));\n }\n }, [stage, score, bestScore]);\n\n // =========================\n // SOUND EFFECTS\n // =========================\n const playSound = (type: \"start\" | \"click\" | \"correct\" | \"half\" | \"wrong\") => {\n const ctx = new (window.AudioContext || (window as any).webkitAudioContext)();\n const osc = ctx.createOscillator();\n const gain = ctx.createGain();\n osc.connect(gain);\n gain.connect(ctx.destination);\n\n switch (type) {\n case \"start\": osc.frequency.value = 500; break;\n case \"click\": osc.frequency.value = 800; break;\n case \"correct\": osc.frequency.value = 1000; break;\n case \"half\": osc.frequency.value = 700; break;\n case \"wrong\": osc.frequency.value = 200; break;\n }\n gain.gain.setValueAtTime(0.1, ctx.currentTime);\n osc.start();\n osc.stop(ctx.currentTime + 0.2);\n };\n\n // =========================\n // CONFETTI EFFECT\n // =========================\n const triggerConfetti = () => {\n const duration = 2500;\n const end = Date.now() + duration;\n const colors = [\"#ec4c44\", \"#f7c948\", \"#6fcf97\", \"#56ccf2\", \"#bb6bd9\"];\n\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\")!;\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n canvas.style.position = \"fixed\";\n canvas.style.top = \"0\";\n canvas.style.left = \"0\";\n canvas.style.pointerEvents = \"none\";\n document.body.appendChild(canvas);\n\n const pieces = Array.from({ length: 100 }).map(() => ({\n x: Math.random() * canvas.width,\n y: Math.random() * canvas.height - canvas.height,\n size: 6 + Math.random() * 6,\n color: colors[Math.floor(Math.random() * colors.length)],\n speed: 2 + Math.random() * 4,\n tilt: Math.random() * 2 * Math.PI,\n }));\n\n const draw = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n pieces.forEach((p) => {\n ctx.fillStyle = p.color;\n ctx.beginPath();\n ctx.ellipse(p.x, p.y, p.size, p.size / 2, p.tilt, 0, 2 * Math.PI);\n ctx.fill();\n p.y += p.speed;\n p.x += Math.sin(p.tilt);\n });\n if (Date.now() < end) requestAnimationFrame(draw);\n else document.body.removeChild(canvas);\n };\n draw();\n };\n\n // =========================\n // RENDER SCREENS\n // =========================\n const renderSelect = () => (\n <div style={styles.gmCenterScreen}>\n <h1 style={styles.gmHeadline1}>MAGIC SENTENCE</h1>\n <p style={styles.gmBodyM}>Select number of rounds</p>\n <div style={{ \n display: \"flex\", \n gap: isMobileDevice() ? \"8px\" : \"16px\",\n justifyContent: \"center\" \n }}>\n {[3, 4, 5].map((num) => (\n <button \n key={num} \n onClick={() => handleSelect(num)} \n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n {num} ROUNDS\n </button>\n ))}\n </div>\n </div>\n );\n\n const renderTime = () => (\n <div style={styles.gmCenterScreen}>\n <h1 style={styles.gmHeadline1}>MAGIC SENTENCE</h1>\n <p style={styles.gmBodyM}>Select time per round</p>\n <div style={{ \n display: \"flex\", \n gap: isMobileDevice() ? \"8px\" : \"16px\",\n justifyContent: \"center\" \n }}>\n {[15, 20, 30].map((time) => (\n <button \n key={time} \n onClick={() => handleTimeSelect(time)} \n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n {time}s\n </button>\n ))}\n </div>\n </div>\n );\n\n const renderType = () => (\n <div style={styles.gmCenterScreen}>\n <h2 style={{...styles.gmBodyM, marginBottom: \"0px\"}}>\n Type down {rounds} sentence{rounds && rounds > 1 ? \"s\" : \"\"} for your student\n </h2>\n <p style={{...styles.gmBodyS, marginBottom: \"16px\", marginTop: \"0px\", color: \"#6b7280\"}}>\n Maximum 41 characters per sentence\n </p>\n <div style={{ \n display: \"flex\", \n flexDirection: \"column\", \n gap: 12, \n width: \"auto\", // Автоматическая ширина по содержимому\n minWidth: \"fit-content\", // Минимальная ширина по содержимому\n maxWidth: \"600px\" // Ограничиваем максимальную ширину\n }}>\n {sentences.map((text, i) => (\n <input\n key={i}\n value={text}\n placeholder={`Sentence ${i + 1}`}\n onChange={(e) => handleChange(i, e.target.value)}\n style={{\n ...styles.gmInput,\n padding: isMobileDevice() ? \"8px 12px\" : \"12px 16px\",\n fontSize: isMobileDevice() ? \"14px\" : \"16px\",\n width: \"100%\", // Поля теперь будут шире благодаря увеличенной ширине контейнера\n textAlign: \"center\" // Центрируем placeholder текст\n }}\n />\n ))}\n </div>\n <button\n onClick={startGame}\n disabled={sentences.some((s) => s.trim().length === 0)}\n style={{\n ...styles.gmButton,\n marginTop: 30,\n background: sentences.some((s) => s.trim().length === 0) ? \"#ccc\" : \"#ec4c44\",\n cursor: sentences.some((s) => s.trim().length === 0) ? \"not-allowed\" : \"pointer\",\n ...getMobileButtonStyles('large')\n }}\n >\n PLAY\n </button>\n </div>\n );\n\n const renderGetReady = () => (\n <div style={styles.gmReadyWrapper}>\n <h1 style={{ \n ...styles.gmHeadline1,\n fontSize: isMobileDevice() ? \"36px\" : \"72px\", \n color: \"#ec4c44\", \n marginBottom: \"20px\",\n animation: \"pulse 1s ease-in-out infinite\"\n }}>\n GET READY\n </h1>\n <div style={styles.gmHourglass}>⏳</div>\n </div>\n );\n\n const renderPlay = () => (\n <div style={styles.gmGameLayout}>\n <h2 style={{ \n marginBottom: isMobileDevice() ? \"5px\" : \"10px\",\n fontSize: isMobileDevice() ? \"16px\" : \"20px\"\n }}>\n Round {currentRound + 1}/{rounds} — {timeExpired ? \"TIME'S UP!\" : `Time: ${timeLeft}s`}\n </h2>\n\n {/* Progress bar */}\n <div\n style={{\n width: \"60%\",\n height: isMobileDevice() ? \"8px\" : \"14px\",\n borderRadius: 8,\n background: \"#eee\",\n overflow: \"hidden\",\n marginBottom: isMobileDevice() ? \"10px\" : \"20px\",\n }}\n >\n <div\n style={{\n height: \"100%\",\n width: `${(timeLeft / (timePerRound || 20)) * 100}%`,\n background: timeLeft <= 5 ? \"#ec4c44\" : \"#4caf50\",\n transition: \"width 1s linear\",\n }}\n ></div>\n </div>\n\n {/* Word bank */}\n <div\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => handleDropTo(e, \"bank\", null)}\n style={{\n display: \"flex\",\n flexWrap: shouldWrapWords() ? \"wrap\" : \"nowrap\",\n gap: isMobile || window.innerWidth < 768 ? \"6px\" : \"10px\",\n justifyContent: \"center\",\n marginBottom: isMobile || window.innerWidth < 768 ? \"15px\" : \"30px\",\n padding: isMobile || window.innerWidth < 768 ? \"5px\" : \"10px\",\n width: \"100%\",\n boxSizing: \"border-box\"\n }}\n >\n {words.map((t, idx) => (\n <div\n key={t.id}\n draggable={!timeExpired}\n role=\"button\"\n tabIndex={timeExpired ? -1 : 0}\n aria-label={timeExpired ? `Word: ${t.text} (time expired)` : createAriaLabel(\"Drag word\", t.text, \"to build sentence\")}\n onDragStart={(e) => {\n if (timeExpired) {\n e.preventDefault();\n return;\n }\n e.dataTransfer.setData(\n \"application/x-token\",\n JSON.stringify({ from: \"bank\", id: t.id })\n );\n e.dataTransfer.setData(\"text/plain\", t.id);\n announceToScreenReader(`Dragging word: ${t.text}`);\n }}\n onKeyDown={(e) => {\n if (timeExpired) return;\n handleKeyDown(e, () => moveToken(\"bank\", \"selected\", t.id, null));\n }}\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => {\n const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n const insertIndex = e.clientX > mid ? idx + 1 : idx;\n setHover({ list: null, index: null, side: null });\n e.stopPropagation();\n handleDropTo(e, \"bank\", insertIndex);\n }}\n onDragEnter={(e) => {\n if (timeExpired) return;\n const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n setHover({ list: \"bank\", index: idx, side: e.clientX > mid ? \"right\" : \"left\" });\n }}\n onDragLeave={() => setHover({ list: null, index: null, side: null })}\n onClick={() => {\n if (timeExpired) return;\n moveToken(\"bank\", \"selected\", t.id, null);\n }}\n style={{\n padding: isMobile || window.innerWidth < 768 ? \"6px 10px\" : \"10px 16px\",\n borderRadius: isMobile || window.innerWidth < 768 ? \"6px\" : \"10px\",\n border: \"1px solid #ccc\",\n background: timeExpired ? \"#f0f0f0\" : \"#f9f9f9\",\n cursor: timeExpired ? \"not-allowed\" : \"pointer\",\n fontSize: isMobile || window.innerWidth < 768 ? \"12px\" : \"18px\",\n borderLeft: hover.list === \"bank\" && hover.index === idx && hover.side === \"left\" ? \"3px solid #3b82f6\" : \"1px solid #ccc\",\n borderRight: hover.list === \"bank\" && hover.index === idx && hover.side === \"right\" ? \"3px solid #3b82f6\" : \"1px solid #ccc\",\n flexShrink: 0,\n flexBasis: \"auto\",\n opacity: timeExpired ? 0.6 : 1,\n transition: \"opacity 0.3s ease\",\n }}\n >\n {t.text}\n </div>\n ))}\n </div>\n\n {/* Selected sentence */}\n <div\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => handleDropTo(e, \"selected\", null)}\n style={{\n minHeight: isMobile || window.innerWidth < 768 ? \"50px\" : \"70px\",\n width: \"auto\", // Автоматическая ширина в зависимости от содержимого\n maxWidth: \"none\", // Убираем ограничение максимальной ширины\n minWidth: \"245px\", // Минимальная ширина для растягивания\n border: resultType === \"correct\" ? \"2px dashed #4caf50\" : \n resultType === \"almost\" ? \"2px dashed #ff9800\" : \n resultType === \"wrong\" ? \"2px dashed #f44336\" : \"2px dashed #ccc\",\n borderRadius: isMobile || window.innerWidth < 768 ? \"8px\" : \"12px\",\n padding: isMobile || window.innerWidth < 768 ? \"8px\" : \"12px\",\n display: \"flex\",\n flexWrap: shouldWrapWords() ? \"wrap\" : \"nowrap\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: `${getAdaptiveFontSize(selected.length)}px`,\n background: resultType === \"correct\" ? \"#e8f5e8\" : \n resultType === \"almost\" ? \"#fff3e0\" : \n resultType === \"wrong\" ? \"#ffebee\" : \"#fafafa\",\n overflowX: shouldWrapWords() ? \"hidden\" : \"auto\",\n whiteSpace: shouldWrapWords() ? \"normal\" : \"nowrap\",\n }}\n >\n {selected.map((t, idx) => (\n <span\n key={t.id}\n draggable={!timeExpired}\n onDragStart={(e) => {\n if (timeExpired) {\n e.preventDefault();\n return;\n }\n e.dataTransfer.setData(\n \"application/x-token\",\n JSON.stringify({ from: \"selected\", id: t.id })\n );\n e.dataTransfer.setData(\"text/plain\", t.id);\n }}\n onDragOver={(e) => e.preventDefault()}\n onDrop={(e) => {\n const rect = (e.currentTarget as HTMLSpanElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n const insertIndex = e.clientX > mid ? idx + 1 : idx;\n setHover({ list: null, index: null, side: null });\n e.stopPropagation();\n handleDropTo(e, \"selected\", insertIndex);\n }}\n onDragEnter={(e) => {\n if (timeExpired) return;\n const rect = (e.currentTarget as HTMLSpanElement).getBoundingClientRect();\n const mid = rect.left + rect.width / 2;\n setHover({ list: \"selected\", index: idx, side: e.clientX > mid ? \"right\" : \"left\" });\n }}\n onDragLeave={() => setHover({ list: null, index: null, side: null })}\n onClick={() => {\n if (timeExpired) return;\n moveToken(\"selected\", \"bank\", t.id, null);\n }}\n title={timeExpired ? \"Time expired\" : \"Click to remove back to bank\"}\n style={{\n padding: isMobileDevice() ? \"4px 6px\" : \"6px 10px\",\n margin: isMobileDevice() ? \"2px\" : \"4px\",\n borderRadius: isMobileDevice() ? \"4px\" : \"8px\",\n background: timeExpired ? \"#f0f0f0\" : \"#ffe9e7\",\n border: timeExpired ? \"1px solid #ccc\" : \"1px solid #ec4c44\",\n borderLeft: hover.list === \"selected\" && hover.index === idx && hover.side === \"left\" ? \"3px solid #3b82f6\" : undefined,\n borderRight: hover.list === \"selected\" && hover.index === idx && hover.side === \"right\" ? \"3px solid #3b82f6\" : undefined,\n cursor: timeExpired ? \"not-allowed\" : \"pointer\",\n userSelect: \"none\",\n fontSize: `${getAdaptiveFontSize(selected.length)}px`, // Адаптивный размер шрифта для слов\n fontFamily: '\"Roboto\", system-ui, -apple-system, \"Segoe UI\", Roboto, Arial, sans-serif', // Более плотный шрифт\n whiteSpace: \"nowrap\", // Запрещаем перенос слов\n opacity: timeExpired ? 0.6 : 1,\n transition: \"opacity 0.3s ease\",\n }}\n >\n {t.text}\n </span>\n ))}\n </div>\n\n <button\n onClick={() => handleNext(true)}\n disabled={!timeExpired && selected.length === 0}\n style={{\n marginTop: isMobileDevice() ? \"15px\" : \"30px\",\n fontSize: isMobileDevice() ? \"14px\" : \"20px\",\n padding: isMobileDevice() ? \"6px 12px\" : \"10px 24px\",\n borderRadius: isMobileDevice() ? \"8px\" : \"12px\",\n background: (timeExpired || selected.length > 0) ? \"#ec4c44\" : \"#ccc\",\n color: \"white\",\n border: \"none\",\n cursor: (timeExpired || selected.length > 0) ? \"pointer\" : \"not-allowed\",\n }}\n >\n {timeExpired ? \"NEXT\" : \"NEXT\"}\n </button>\n </div>\n );\n\n const renderResults = () => (\n <div style={styles.gmCenterScreen}>\n <h1 style={{\n ...styles.gmHeadline1,\n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"0px\" : \"0px\",\n marginBottom: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"2px\" : \"10px\",\n fontSize: (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"32px\" : \"clamp(28px, 4vw, 40px)\"\n }}>\n Game Over 🎯\n </h1>\n <h2 style={{\n ...styles.gmHeadline2,\n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"0px\" : \"0px\",\n marginBottom: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"2px\" : \"16px\",\n fontSize: (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"18px\" : \"24px\"\n }}>\n Your score: {score} out of {rounds}\n </h2>\n <p style={{ \n ...styles.gmBodyM, \n color: \"#10b981\", \n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"0px\" : \"12px\",\n marginBottom: (isMobile && window.innerWidth > window.innerHeight) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) || isIPadMiniPortrait || isIPadMiniLandscape || isIPadAirPortrait || isIPadAirLandscape || isSurfaceDuoPortrait || isSurfaceDuoLandscape || isIPadProPortrait || isIPadProLandscape ? \"2px\" : \"16px\",\n fontSize: (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"14px\" : \"16px\"\n }}>\n Best score: {bestScore}\n </p>\n\n <div style={{ \n display: \"flex\", \n gap: (isMobile && window.innerWidth > window.innerHeight) || (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"6px\" : \"12px\", \n marginTop: (isMobile && window.innerWidth > window.innerHeight) || (isMobile && window.innerWidth <= 375 && window.innerHeight <= 667) || (window.innerWidth === 896 && window.innerHeight === 414) || (window.innerWidth === 844 && window.innerHeight === 390) || (window.innerWidth === 926 && window.innerHeight === 428) || (window.innerWidth === 932 && window.innerHeight === 430) ? \"2px\" : (window.innerWidth === 1366 && window.innerHeight === 766) || (window.innerWidth === 1366 && window.innerHeight === 768) || (window.innerWidth === 1280 && window.innerHeight === 720) || (window.innerWidth === 1440 && window.innerHeight === 900) || isDesktopLayout ? \"12px\" : \"24px\"\n }}>\n <button\n onClick={() => {\n triggerConfetti();\n playSound(\"start\");\n setTimeout(() => {\n setStage(\"getready\");\n setCountdown(null);\n setTimeExpired(false);\n }, 800);\n }}\n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n 🔁 Play again\n </button>\n\n <button\n onClick={() => {\n playSound(\"click\");\n setStage(\"select\");\n setRounds(null);\n setTimePerRound(null);\n setSentences([]);\n setScore(0);\n setSelected([]);\n setTimeExpired(false);\n }}\n style={{\n ...styles.gmButton,\n ...getMobileButtonStyles('medium')\n }}\n >\n ⬅️ Exit\n </button>\n </div>\n </div>\n );\n\n // Определяем URL логотипа\n const logoSrc = logoUrl || \n (baseURL \n ? `${baseURL.endsWith('/') ? baseURL.slice(0, -1) : baseURL}/logo.svg`\n : (typeof window !== 'undefined' && window.origin\n ? `${window.origin}/browser/speakid/games/magic%20sentence/logo.svg`\n : null));\n\n // Условие для отображения логотипа\n const shouldShowLogo = !isMobile && \n showLogo && \n !(window.innerWidth > window.innerHeight) && \n window.innerHeight >= 700;\n\n return (\n <div\n ref={containerRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n background: \"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)\",\n transition: \"background 0.3s ease\",\n overflow: \"hidden\",\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0\n }}\n >\n <div\n style={{\n width: isMobile ? \"100%\" : (containerSize || 1000),\n height: isMobile ? \"100%\" : (containerSize || 1000),\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n overflow: \"hidden\",\n borderRadius: isMobile ? 0 : \"20px\",\n background: \"linear-gradient(to bottom, #fff8f8 0%, #f9fafb 100%)\",\n boxShadow: isMobile ? \"none\" : \"0 0 40px rgba(0,0,0,0.1)\",\n margin: isMobile ? \"0 auto\" : \"unset\",\n position: \"relative\",\n }}\n >\n <div\n style={{\n transform: \"none\",\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n }}\n >\n <div id=\"magic-sentence-root\">\n {shouldShowLogo ? (\n <div style={{\n ...styles.gmLogoFixed,\n display: 'block'\n }}>\n {logoSrc ? (\n <img\n src={logoSrc}\n alt=\"SPEAKID Logo\"\n style={styles.gmLogoImg}\n loading=\"lazy\"\n />\n ) : (\n <div style={styles.gmLogoImg}>\n SPEAKID\n </div>\n )}\n </div>\n ) : null}\n {stage === \"select\" ? renderSelect() : null}\n {stage === \"time\" ? renderTime() : null}\n {stage === \"type\" ? renderType() : null}\n {stage === \"getready\" ? renderGetReady() : null}\n {stage === \"play\" ? renderPlay() : null}\n {stage === \"results\" ? renderResults() : null}\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nexport default GameComponent;","import React, { Component, ErrorInfo, ReactNode } from 'react';\n\ninterface Props {\n children: ReactNode;\n fallback?: ReactNode;\n}\n\ninterface State {\n hasError: boolean;\n error?: Error;\n errorInfo?: ErrorInfo;\n}\n\nexport class ErrorBoundary extends Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(error: Error): State {\n return {\n hasError: true,\n error,\n };\n }\n\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n console.error('Game Error:', error, errorInfo);\n \n // В реальном приложении здесь можно отправить ошибку в аналитику\n // analytics.track('game_error', { error: error.message, stack: error.stack });\n \n this.setState({\n error,\n errorInfo,\n });\n }\n\n handleReset = () => {\n this.setState({ hasError: false, error: undefined, errorInfo: undefined });\n };\n\n render() {\n if (this.state.hasError) {\n if (this.props.fallback) {\n return this.props.fallback;\n }\n\n return (\n <div style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '100vh',\n padding: '20px',\n textAlign: 'center',\n backgroundColor: '#fef2f2',\n color: '#dc2626',\n fontFamily: 'system-ui, sans-serif'\n }}>\n <h1 style={{ fontSize: '24px', marginBottom: '16px' }}>\n 🚨 Oops! Something went wrong\n </h1>\n <p style={{ fontSize: '16px', marginBottom: '24px', maxWidth: '500px' }}>\n The game encountered an unexpected error. Don't worry, your progress is saved!\n </p>\n \n <button\n onClick={this.handleReset}\n style={{\n padding: '12px 24px',\n fontSize: '16px',\n backgroundColor: '#dc2626',\n color: 'white',\n border: 'none',\n borderRadius: '8px',\n cursor: 'pointer',\n transition: 'background-color 0.2s'\n }}\n onMouseOver={(e) => e.currentTarget.style.backgroundColor = '#b91c1c'}\n onMouseOut={(e) => e.currentTarget.style.backgroundColor = '#dc2626'}\n >\n 🔄 Restart Game\n </button>\n \n {typeof process !== 'undefined' && process.env.NODE_ENV === 'development' && this.state.error && (\n <details style={{ marginTop: '20px', textAlign: 'left', maxWidth: '600px' }}>\n <summary style={{ cursor: 'pointer', fontSize: '14px' }}>\n Technical Details (Development Only)\n </summary>\n <pre style={{\n backgroundColor: '#f3f4f6',\n padding: '12px',\n borderRadius: '4px',\n fontSize: '12px',\n overflow: 'auto',\n marginTop: '8px'\n }}>\n {this.state.error.toString()}\n {this.state.errorInfo?.componentStack}\n </pre>\n </details>\n )}\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n\n"],"names":["keyframes","styleTag","animations","styles","useValidation","errors","setErrors","useState","validateSentence","useCallback","sentence","index","allSentences","newErrors","duplicateIndex","s","i","validateAllSentences","sentences","allErrors","result","error","clearErrors","createAriaLabel","action","word","context","handleKeyDown","event","allowedKeys","announceToScreenReader","message","announcement","globalReset","style","shuffle","arr","GameComponent","props","logoUrl","showLogo","baseURL","containerRef","useRef","validationErrors","shouldWrapWords","isMobile","isMobileDevice","getMobileButtonStyles","type","useEffect","stage","setStage","rounds","setRounds","timePerRound","setTimePerRound","setSentences","currentRound","setCurrentRound","words","setWords","selected","setSelected","timeLeft","setTimeLeft","score","setScore","countdown","setCountdown","resultType","setResultType","timeExpired","setTimeExpired","bestScore","setBestScore","timerRef","hover","setHover","setIsMobile","scale","setScale","containerSize","setContainerSize","isDesktopLayout","setIsDesktopLayout","isIPadMiniPortrait","setIsIPadMiniPortrait","isIPadMiniLandscape","setIsIPadMiniLandscape","isIPadAirPortrait","setIsIPadAirPortrait","isIPadAirLandscape","setIsIPadAirLandscape","isSurfaceDuoPortrait","setIsSurfaceDuoPortrait","isSurfaceDuoLandscape","setIsSurfaceDuoLandscape","isIPadProPortrait","setIsIPadProPortrait","isIPadProLandscape","setIsIPadProLandscape","resize","width","height","mobile","isSmallHeight","desktopLayout","finalSize","moveToken","from","to","id","insertIndex","nextWords","nextSelected","takeFrom","putTo","idx","t","token","targetIndex","handleDropTo","raw","fallbackId","inBank","inSelected","payload","handleSelect","num","handleTimeSelect","time","handleChange","value","updated","validation","normalizeSentence","getAdaptiveFontSize","wordCount","startGame","prev","startRound","target","tokens","w","correctWords","selectedTexts","missingWords","extraWords","wrongOrder","playSound","handleNext","manual","triggerConfetti","ctx","osc","gain","end","colors","canvas","pieces","draw","p","renderSelect","jsxs","jsx","renderTime","renderType","text","e","renderGetReady","renderPlay","rect","mid","renderResults","logoSrc","shouldShowLogo","ErrorBoundary","Component","errorInfo"],"mappings":"oKAGMA,GAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmClB,GAAI,OAAO,SAAa,KAAe,CAAC,SAAS,eAAe,0BAA0B,EAAG,CAC3F,MAAMC,EAAW,SAAS,cAAc,OAAO,EAC/CA,EAAS,GAAK,2BACdA,EAAS,UAAYD,GACrB,SAAS,KAAK,YAAYC,CAAQ,CACpC,CAGA,MAAMC,GAAa,CACjB,KAAM,CACJ,UAAW,0CAAA,EAEb,MAAO,CACL,UAAW,uCAAA,EAEb,MAAO,CACL,UAAW,uCAAA,EAEb,QAAS,CACP,UAAW,sCAAA,EAEb,OAAQ,CACN,UAAW,wCAAA,EAEb,KAAM,CACJ,UAAW,6CAAA,CAEf,EAGaC,EAAwC,CACnD,eAAgB,CACd,SAAU,WACV,OAAQ,EAGR,UAAW,OACX,MAAO,OACP,QAAS,OACT,cAAe,SACf,eAAgB,SAChB,WAAY,SACZ,UAAW,SACX,MAAO,UACP,QAAS,YACT,UAAW,aACX,UAAW,kBAAA,EAGb,YAAa,CACX,WAAY,IACZ,SAAU,yBACV,WAAY,MAAA,EAGd,YAAa,CACX,WAAY,IACZ,SAAU,OACV,WAAY,MAAA,EAed,QAAS,CACP,WAAY,IACZ,SAAU,OACV,WAAY,MAAA,EAGd,QAAS,CACP,WAAY,IACZ,SAAU,OACV,WAAY,OACZ,MAAO,SAAA,EAGT,SAAU,CACR,WACE,4EACF,WAAY,IACZ,SAAU,OACV,QAAS,YACT,aAAc,OACd,OAAQ,oBACR,WAAY,UACZ,MAAO,UACP,OAAQ,UACR,UAAW,oCACX,WACE,iFAAA,EAQJ,aAAc,CACZ,SAAU,WACV,MAAO,OAEP,SAAU,OAEV,UAAW,OACX,QAAS,OACT,cAAe,SACf,WAAY,SACZ,eAAgB,SAChB,UAAW,SACX,MAAO,UACP,QAAS,WACT,OAAQ,QAAA,EAyCV,QAAS,CACP,QAAS,WACT,aAAc,MACd,OAAQ,iBACR,SAAU,OACV,WAAY,qBACZ,MAAO,OAAA,EAsBT,YAAa,CACX,SAAU,WACV,IAAK,OACL,KAAM,OACN,MAAO,QACP,OAAQ,GACR,cAAe,OACf,WAAY,cACZ,UAAW,OACX,WAAY,MAAA,EAGd,UAAW,CACT,OAAQ,yBACR,MAAO,OACP,WAAY,cACZ,gBAAiB,wWACjB,eAAgB,UAChB,iBAAkB,YAClB,mBAAoB,SACpB,UAAW,gBACX,mBAAoB,SACpB,oBAAqB,cACrB,UAAW,UACX,eAAgB,MAAA,EAGlB,eAAgB,CACd,QAAS,OACT,cAAe,SACf,WAAY,SACZ,eAAgB,SAEhB,OAAQ,MACR,IAAK,MAAA,EAGP,YAAa,CACX,SAAU,OACV,GAAGD,GAAW,IAAA,EAIhB,GAAGA,EACL,ECpQaE,GAAgB,IAAM,CACjC,KAAM,CAACC,EAAQC,CAAS,EAAIC,EAAAA,SAA4B,CAAA,CAAE,EAEpDC,EAAmBC,EAAAA,YAAY,CAACC,EAAkBC,EAAeC,IAA6C,CAClH,MAAMC,EAA+B,CAAA,EAGhCH,EAAS,QACZG,EAAU,KAAK,CACb,KAAM,QACN,QAAS,0BAAA,CACV,EAICH,EAAS,OAAS,IACpBG,EAAU,KAAK,CACb,KAAM,SACN,QAAS,yBAAyBH,EAAS,MAAM,iBAAA,CAClD,EAKCA,GAAY,CADG,4BACS,KAAKA,CAAQ,GACvCG,EAAU,KAAK,CACb,KAAM,aACN,QAAS,oEAAA,CACV,EAIH,MAAMC,EAAiBF,EAAa,UAAU,CAACG,EAAGC,IAAMA,IAAML,GAASI,EAAE,YAAA,EAAc,KAAA,IAAWL,EAAS,YAAA,EAAc,MAAM,EAC/H,OAAII,IAAmB,IACrBD,EAAU,KAAK,CACb,KAAM,YACN,QAAS,wCAAwCC,EAAiB,CAAC,GAAA,CACpE,EAGHR,EAAUO,CAAS,EACZ,CACL,QAASA,EAAU,SAAW,EAC9B,OAAQA,CAAA,CAEZ,EAAG,CAAA,CAAE,EAECI,EAAuBR,cAAaS,GAA0C,CAClF,MAAMC,EAA+B,CAAA,EAErC,OAAAD,EAAU,QAAQ,CAACR,EAAUC,IAAU,CACrC,MAAMS,EAASZ,EAAiBE,EAAUC,EAAOO,CAAS,EAC1DC,EAAU,KAAK,GAAGC,EAAO,OAAO,IAAIC,IAAU,CAC5C,GAAGA,EACH,QAAS,YAAYV,EAAQ,CAAC,KAAKU,EAAM,OAAO,EAAA,EAChD,CAAC,CACL,CAAC,EAEM,CACL,QAASF,EAAU,SAAW,EAC9B,OAAQA,CAAA,CAEZ,EAAG,CAACX,CAAgB,CAAC,EAEfc,EAAcb,EAAAA,YAAY,IAAM,CACpCH,EAAU,CAAA,CAAE,CACd,EAAG,CAAA,CAAE,EAEL,MAAO,CACL,OAAAD,EACA,iBAAAG,EACA,qBAAAS,EACA,YAAAK,CAAA,CAEJ,ECpFaC,GAAkB,CAACC,EAAgBC,EAAeC,IACzDD,GAAQC,EACH,GAAGF,CAAM,UAAUC,CAAI,KAAKC,CAAO,GAExCD,EACK,GAAGD,CAAM,UAAUC,CAAI,IAEzBD,EAaIG,GAAgB,CAC3BC,EACAJ,EACAK,EAAwB,CAAC,QAAS,GAAG,IAClC,CACCA,EAAY,SAASD,EAAM,GAAG,IAChCA,EAAM,eAAA,EACNJ,EAAA,EAEJ,EAEaM,EAA0BC,GAAoB,CAEzD,MAAMC,EAAe,SAAS,cAAc,KAAK,EACjDA,EAAa,aAAa,YAAa,QAAQ,EAC/CA,EAAa,aAAa,cAAe,MAAM,EAC/CA,EAAa,MAAM,SAAW,WAC9BA,EAAa,MAAM,KAAO,WAC1BA,EAAa,MAAM,MAAQ,MAC3BA,EAAa,MAAM,OAAS,MAC5BA,EAAa,MAAM,SAAW,SAE9B,SAAS,KAAK,YAAYA,CAAY,EACtCA,EAAa,YAAcD,EAG3B,WAAW,IAAM,CACf,SAAS,KAAK,YAAYC,CAAY,CACxC,EAAG,GAAI,CACT,EClCMC,GAAc,IAAM,CACxB,MAAMC,EAAQ,SAAS,cAAc,OAAO,EAC5CA,EAAM,YAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA2BpB,SAAS,KAAK,YAAYA,CAAK,CACjC,EAEMC,GAAWC,GAAkB,CAAC,GAAGA,CAAG,EAAE,KAAK,IAAM,KAAK,OAAA,EAAW,EAAG,EAQ1E,SAASC,GAAcC,EAAmB,GAAI,CAC5C,KAAM,CAAE,QAAAC,EAAS,SAAAC,EAAW,GAAM,QAAAC,GAAYH,EACxCI,EAAeC,EAAAA,OAAuB,IAAI,EAG1C,CAAE,qBAAA1B,EAAsB,OAAQ2B,CAAA,EAAqBxC,GAAA,EAGrDyC,EAAkB,IAEfC,GAAY,OAAO,WAAa,IAInCC,EAAiB,IACdD,GACA,OAAO,WAAa,KACnB,OAAO,YAAc,KAAO,OAAO,YAAc,KAAO,OAAO,aAAe,KAAO,OAAO,aAAe,IAI/GE,EAAwB,CAACC,EAAqC,WAAa,CAC/E,GAAI,CAACF,IACH,MAAO,CACL,QAAS,YACT,SAAU,OACV,SAAU,MAAA,EAId,OAAQE,EAAA,CACN,IAAK,QACH,MAAO,CACL,QAAS,UACT,SAAU,MACV,SAAU,MAAA,EAEd,IAAK,SACH,MAAO,CACL,QAAS,UACT,SAAU,OACV,SAAU,MAAA,EAEd,IAAK,QACH,MAAO,CACL,QAAS,WACT,SAAU,OACV,SAAU,MAAA,CACZ,CAEN,EAEAC,EAAAA,UAAU,KACRjB,GAAA,EACO,IAAM,CACX,SAAS,KAAK,MAAM,SAAW,EACjC,GACC,CAAA,CAAE,EAEL,KAAM,CAACkB,EAAOC,CAAQ,EAAI7C,EAAAA,SAAgB,QAAQ,EAC5C,CAAC8C,EAAQC,EAAS,EAAI/C,EAAAA,SAAwB,IAAI,EAClD,CAACgD,GAAcC,EAAe,EAAIjD,EAAAA,SAAwB,IAAI,EAC9D,CAACW,EAAWuC,CAAY,EAAIlD,EAAAA,SAAmB,CAAA,CAAE,EACjD,CAACmD,EAAcC,EAAe,EAAIpD,EAAAA,SAAS,CAAC,EAC5C,CAACqD,GAAOC,EAAQ,EAAItD,EAAAA,SAAkB,CAAA,CAAE,EACxC,CAACuD,EAAUC,EAAW,EAAIxD,EAAAA,SAAkB,CAAA,CAAE,EAC9C,CAACyD,EAAUC,EAAW,EAAI1D,EAAAA,SAAS,EAAE,EACrC,CAAC2D,EAAOC,CAAQ,EAAI5D,EAAAA,SAAS,CAAC,EAC9B,CAAC6D,GAAWC,EAAY,EAAI9D,EAAAA,SAAwB,IAAI,EACxD,CAAC+D,EAAYC,CAAa,EAAIhE,EAAAA,SAAgD,IAAI,EAClF,CAACiE,EAAaC,CAAc,EAAIlE,EAAAA,SAAS,EAAK,EAC9C,CAACmE,GAAWC,EAAY,EAAIpE,EAAAA,SAChC,OAAO,aAAa,QAAQ,mBAAmB,CAAC,GAAK,CAAA,EAEjDqE,EAAWjC,EAAAA,OAAsB,IAAI,EACrC,CAACkC,EAAOC,CAAQ,EAAIvE,EAAAA,SAAyF,CAAE,KAAM,KAAM,MAAO,KAAM,KAAM,IAAA,CAAM,EAGpJ,CAACuC,EAAUiC,EAAW,EAAIxE,EAAAA,SAAS,EAAK,EACxC,CAACyE,GAAOC,EAAQ,EAAI1E,EAAAA,SAAS,CAAC,EAC9B,CAAC2E,GAAeC,EAAgB,EAAI5E,EAAAA,SAAwB,IAAI,EAChE,CAAC6E,GAAiBC,EAAkB,EAAI9E,EAAAA,SAAS,EAAK,EACtD,CAAC+E,EAAoBC,EAAqB,EAAIhF,EAAAA,SAAS,EAAK,EAC5D,CAACiF,EAAqBC,EAAsB,EAAIlF,EAAAA,SAAS,EAAK,EAC9D,CAACmF,EAAmBC,EAAoB,EAAIpF,EAAAA,SAAS,EAAK,EAC1D,CAACqF,EAAoBC,EAAqB,EAAItF,EAAAA,SAAS,EAAK,EAC5D,CAACuF,EAAsBC,EAAuB,EAAIxF,EAAAA,SAAS,EAAK,EAChE,CAACyF,EAAuBC,EAAwB,EAAI1F,EAAAA,SAAS,EAAK,EAClE,CAAC2F,EAAmBC,EAAoB,EAAI5F,EAAAA,SAAS,EAAK,EAC1D,CAAC6F,EAAoBC,EAAqB,EAAI9F,EAAAA,SAAS,EAAK,EAGlE2C,EAAAA,UAAU,IAAM,CACd,MAAMoD,EAAS,IAAM,CACnB,MAAMC,EAAQ,OAAO,WACfC,EAAS,OAAO,YAChBC,EAASF,EAAQ,KAAQA,IAAU,KAAOC,IAAW,KAASD,IAAU,KAAOC,IAAW,IAE1FE,EAAgBF,EAAS,IAGzBlB,EAAqBiB,IAAU,KAAOC,IAAW,KACjDhB,EAAsBe,IAAU,MAAQC,IAAW,IACnDd,EAAoBa,IAAU,KAAOC,IAAW,KAChDZ,EAAqBW,IAAU,MAAQC,IAAW,IAGlDV,EAAuBS,IAAU,KAAOC,IAAW,IACnDR,EAAwBO,IAAU,KAAOC,IAAW,IAGpDN,GAAoBK,IAAU,MAAQC,IAAW,KACjDJ,GAAqBG,IAAU,MAAQC,IAAW,KAGlDG,GAAgBJ,GAAS,MAAQC,GAAU,KAAO,CAACC,EAgBzD,GAfApB,GAAmBsB,EAAa,EAGhCpB,GAAsBD,CAAkB,EACxCG,GAAuBD,CAAmB,EAC1CG,GAAqBD,CAAiB,EACtCG,GAAsBD,CAAkB,EACxCG,GAAwBD,CAAoB,EAC5CG,GAAyBD,CAAqB,EAC9CG,GAAqBD,EAAiB,EACtCG,GAAsBD,EAAkB,EAExCrB,GAAY0B,CAAM,EAGdA,EACFtB,GAAiB,IAAI,EACrBF,GAAS,CAAC,UACDyB,EACTvB,GAAiB,IAAI,EACrBF,GAAS,CAAC,MACL,CAGL,MAAM2B,GAAY,KAAK,IAAI,IAAM,KAAK,IAAIL,EAAOC,CAAM,EAAI,EAAG,EAC9DrB,GAAiByB,EAAS,EAC1B3B,GAAS,CAAC,CACZ,CACF,EACA,OAAAqB,EAAA,EACA,OAAO,iBAAiB,SAAUA,CAAM,EACjC,IAAM,OAAO,oBAAoB,SAAUA,CAAM,CAC1D,EAAG,CAAA,CAAE,EAQL,MAAMO,EAAY,CAChBC,EACAC,EACAC,EACAC,IACG,CAEH,GAAIzC,EAAa,OAEjB,IAAI0C,EAAY,CAAC,GAAGtD,EAAK,EACrBuD,EAAe,CAAC,GAAGrD,CAAQ,EAE/B,MAAMsD,EAAWN,IAAS,OAASI,EAAYC,EACzCE,EAAQN,IAAO,OAASG,EAAYC,EAEpCG,EAAMF,EAAS,UAAWG,IAAMA,GAAE,KAAOP,CAAE,EACjD,GAAIM,IAAQ,GAAI,OAChB,KAAM,CAACE,CAAK,EAAIJ,EAAS,OAAOE,EAAK,CAAC,EAEtC,IAAIG,EAAcR,EAEhBH,IAASC,GACTU,IAAgB,MAChBA,IAAgB,QAEZA,EAAcH,IAAKG,EAAcA,EAAc,GAInDA,GAAgB,MAEhBA,EAAc,GACdA,EAAcJ,EAAM,OAEpBA,EAAM,KAAKG,CAAK,EAEhBH,EAAM,OAAOI,EAAa,EAAGD,CAAK,EAGhCV,IAAS,OAAQI,EAAYE,EAAeD,EAAeC,EAC3DL,IAAO,OAAQG,EAAYG,EAAYF,EAAeE,EAE1DxD,GAASqD,CAAS,EAClBnD,GAAYoD,CAAY,CAC1B,EAEMO,EAAe,CACnB,EACAX,EACAE,IACG,CAIH,GAHA,EAAE,eAAA,EAGEzC,EAAa,CACfM,EAAS,CAAE,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,EAChD,MACF,CAEA,MAAM6C,EAAM,EAAE,aAAa,QAAQ,qBAAqB,IACrD,IAAM,CACL,MAAMC,EAAa,EAAE,aAAa,QAAQ,YAAY,EACtD,GAAI,CAACA,EAAY,MAAO,GACxB,MAAMC,EAASjE,GAAM,KAAM2D,GAAMA,EAAE,KAAOK,CAAU,EAC9CE,EAAahE,EAAS,KAAMyD,GAAMA,EAAE,KAAOK,CAAU,EACrDd,EAAwBe,EAAS,OAASC,EAAa,WAAa,KAC1E,OAAOhB,EAAO,KAAK,UAAU,CAAE,KAAAA,EAAM,GAAIc,CAAA,CAAY,EAAI,EAC3D,GAAA,EACF,GAAKD,EACL,IAAI,CACF,MAAMI,EAAU,KAAK,MAAMJ,CAAG,EAC9B,GAAI,CAACI,GAAW,CAACA,EAAQ,IAAM,CAACA,EAAQ,KAAM,OAC9ClB,EAAUkB,EAAQ,KAAMhB,EAAIgB,EAAQ,GAAId,CAAW,CACrD,MAAQ,CAER,CACAnC,EAAS,CAAE,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,EAClD,EAKMkD,GAAgBC,GAAgB,CACpC3E,GAAU2E,CAAG,EACbxE,EAAa,MAAMwE,CAAG,EAAE,KAAK,EAAE,CAAC,EAChC7E,EAAS,MAAM,CACjB,EAEM8E,GAAoBC,GAAiB,CACzC3E,GAAgB2E,CAAI,EACpB/E,EAAS,MAAM,CACjB,EAEMgF,GAAe,CAACzH,EAAe0H,IAAkB,CAQrD,GANIA,EAAM,OAAS,IAMfA,GAAS,CADM,4BACM,KAAKA,CAAK,EACjC,OAGF,MAAMC,EAAU,CAAC,GAAGpH,CAAS,EAC7BoH,EAAQ3H,CAAK,EAAI0H,EACjB5E,EAAa6E,CAAO,EAGpB,MAAMC,EAAatH,EAAqBqH,CAAO,EAC1CC,EAAW,SACd,QAAQ,KAAK,qBAAsBA,EAAW,MAAM,CAExD,EAEMC,GAAqBzH,GAAcA,EAAE,OAAO,QAAQ,OAAQ,GAAG,EAG/D0H,GAAuBC,GACvBA,GAAa,EAAU,GACvBA,GAAa,EAAU,GACvBA,GAAa,EAAU,GACvBA,GAAa,EAAU,GACpB,GAGHC,GAAY,IAAM,CACLzH,EAAU,KAAMH,GAAMA,EAAE,KAAA,EAAO,SAAW,CAAC,IAI5D0C,EAAcmF,GAASA,EAAK,IAAK7H,GAAMyH,GAAkBzH,CAAC,CAAC,CAAC,EAC5DoD,EAAS,CAAC,EACVR,GAAgB,CAAC,EACjBU,GAAa,IAAI,EACjBjB,EAAS,UAAU,EACrB,EAGAF,EAAAA,UAAU,IAAM,CACd,GAAIC,IAAU,WAAY,CACxB,MAAMoE,EAAI,WAAW,IAAMsB,GAAW,CAAC,EAAG,GAAI,EAC9C,MAAO,IAAM,aAAatB,CAAC,CAC7B,CACF,EAAG,CAACpE,CAAK,CAAC,EAEV,MAAM0F,GAAclI,GAAkB,CACpC,MAAMmI,EAAS5H,EAAUP,CAAK,EAC9B,GAAI,CAACmI,EAAQ,OAMb,MAAMC,EALW5G,GAAQ2G,EACtB,KAAA,EACA,MAAM,KAAK,EACX,OAAO,OAAO,CAAA,EAEgB,IAAI,CAACE,EAAGhI,KAAO,CAC9C,GAAI,GAAG,KAAK,KAAK,IAAIL,CAAK,IAAIK,CAAC,IAAI,KAAK,SAAS,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC,GACtE,KAAMgI,CAAA,EACN,EACFnF,GAASkF,CAAM,EACfhF,GAAY,CAAA,CAAE,EACdJ,GAAgBhD,CAAK,EACrBsD,GAAYV,IAAgB,EAAE,EAC9BgB,EAAc,IAAI,EAClBE,EAAe,EAAK,EACpBrB,EAAS,MAAM,CACjB,EAGAF,EAAAA,UAAU,IAAM,CACd,GAAIC,IAAU,QAAU,CAACqB,EAEvB,GADII,EAAS,UAAY,MAAM,OAAO,aAAaA,EAAS,OAAO,EAC/DZ,EAAW,EACbY,EAAS,QAAU,OAAO,WAAW,IAAMX,GAAasD,GAAMA,EAAI,CAAC,EAAG,GAAI,MACrE,CAEL9C,EAAe,EAAI,EAGnB,MAAMwE,EADU/H,EAAUwC,CAAY,EACT,KAAA,EAAO,MAAM,KAAK,EACzCwF,EAAgBpF,EAAS,IAAKyD,GAAMA,EAAE,IAAI,EAG1C4B,EAAeF,EAAa,OAAOxH,GAAQ,CAACyH,EAAc,SAASzH,CAAI,CAAC,EAAE,OAC1E2H,EAAaF,EAAc,OAAOzH,GAAQ,CAACwH,EAAa,SAASxH,CAAI,CAAC,EAAE,OACxE4H,EAAaJ,EAAa,OAAO,CAACD,EAAGhI,IAAMgI,IAAME,EAAclI,CAAC,CAAC,EAAE,OAGnEX,EAAS8I,EAAeC,EAAaC,EAGvChJ,IAAW,GACbkE,EAAc,SAAS,EACvB+E,EAAU,SAAS,EACnBxH,EAAuB,qBAAqB,GACnCzB,IAAW,GACpBkE,EAAc,QAAQ,EACtB+E,EAAU,MAAM,EAChBxH,EAAuB,mCAAmC,IAE1DyC,EAAc,OAAO,EACrB+E,EAAU,OAAO,EACjBxH,EAAuB,+BAA+B,EAE1D,CAEF,MAAO,IAAM,CACP8C,EAAS,UAAY,MAAM,OAAO,aAAaA,EAAS,OAAO,CACrE,CACF,EAAG,CAACzB,EAAOa,EAAUQ,EAAatD,EAAWwC,EAAcI,CAAQ,CAAC,EAKpE,MAAMyF,GAAa,CAACC,EAAS,KAAS,CAEpC,GAAIhF,GAAegF,EAAQ,CACrB9F,EAAe,GAAKL,GAAU,GAChCwF,GAAWnF,EAAe,CAAC,GAE3BN,EAAS,SAAS,EAClB,WAAW,IAAMqG,GAAA,EAAmB,GAAG,GAEzC,MACF,CAGA,GAAID,GAAU,CAAChF,EAAa,CAE1B,MAAMyE,EADU/H,EAAUwC,CAAY,EACT,KAAA,EAAO,MAAM,KAAK,EACzCwF,EAAgBpF,EAAS,IAAKyD,GAAMA,EAAE,IAAI,EAG1C4B,EAAeF,EAAa,OAAOxH,GAAQ,CAACyH,EAAc,SAASzH,CAAI,CAAC,EAAE,OAC1E2H,EAAaF,EAAc,OAAOzH,GAAQ,CAACwH,EAAa,SAASxH,CAAI,CAAC,EAAE,OACxE4H,EAAaJ,EAAa,OAAO,CAACD,EAAGhI,IAAMgI,IAAME,EAAclI,CAAC,CAAC,EAAE,OAGnEX,EAAS8I,EAAeC,EAAaC,EAEvChJ,IAAW,GAAK2D,EAAW,GAC7BG,EAAUpD,GAAMA,EAAI,CAAC,EACrBwD,EAAc,SAAS,EACvB+E,EAAU,SAAS,EACnBxH,EAAuB,qBAAqB,GACnCzB,IAAW,GACpB8D,EAAUpD,GAAMA,EAAI,EAAG,EACvBwD,EAAc,QAAQ,EACtB+E,EAAU,MAAM,EAChBxH,EAAuB,mCAAmC,IAE1DyC,EAAc,OAAO,EACrB+E,EAAU,OAAO,EACjBxH,EAAuB,+BAA+B,GAIpD4B,EAAe,GAAKL,GAAU,GAChC,WAAW,IAAMwF,GAAWnF,EAAe,CAAC,EAAG,GAAG,GAElDN,EAAS,SAAS,EAClB,WAAW,IAAMqG,GAAA,EAAmB,GAAG,EAE3C,CACF,EAKAvG,EAAAA,UAAU,IAAM,CACVC,IAAU,WAAae,EAAQQ,KACjCC,GAAaT,CAAK,EAClB,aAAa,QAAQ,oBAAqB,OAAOA,CAAK,CAAC,EAE3D,EAAG,CAACf,EAAOe,EAAOQ,EAAS,CAAC,EAK5B,MAAM4E,EAAarG,GAA2D,CAC5E,MAAMyG,EAAM,IAAK,OAAO,cAAiB,OAAe,oBAClDC,EAAMD,EAAI,iBAAA,EACVE,EAAOF,EAAI,WAAA,EAIjB,OAHAC,EAAI,QAAQC,CAAI,EAChBA,EAAK,QAAQF,EAAI,WAAW,EAEpBzG,EAAA,CACN,IAAK,QAAS0G,EAAI,UAAU,MAAQ,IAAK,MACzC,IAAK,QAASA,EAAI,UAAU,MAAQ,IAAK,MACzC,IAAK,UAAWA,EAAI,UAAU,MAAQ,IAAM,MAC5C,IAAK,OAAQA,EAAI,UAAU,MAAQ,IAAK,MACxC,IAAK,QAASA,EAAI,UAAU,MAAQ,IAAK,KAAA,CAE3CC,EAAK,KAAK,eAAe,GAAKF,EAAI,WAAW,EAC7CC,EAAI,MAAA,EACJA,EAAI,KAAKD,EAAI,YAAc,EAAG,CAChC,EAKMD,GAAkB,IAAM,CAE5B,MAAMI,EAAM,KAAK,IAAA,EAAQ,KACnBC,EAAS,CAAC,UAAW,UAAW,UAAW,UAAW,SAAS,EAE/DC,EAAS,SAAS,cAAc,QAAQ,EACxCL,EAAMK,EAAO,WAAW,IAAI,EAClCA,EAAO,MAAQ,OAAO,WACtBA,EAAO,OAAS,OAAO,YACvBA,EAAO,MAAM,SAAW,QACxBA,EAAO,MAAM,IAAM,IACnBA,EAAO,MAAM,KAAO,IACpBA,EAAO,MAAM,cAAgB,OAC7B,SAAS,KAAK,YAAYA,CAAM,EAEhC,MAAMC,EAAS,MAAM,KAAK,CAAE,OAAQ,GAAA,CAAK,EAAE,IAAI,KAAO,CACpD,EAAG,KAAK,OAAA,EAAWD,EAAO,MAC1B,EAAG,KAAK,OAAA,EAAWA,EAAO,OAASA,EAAO,OAC1C,KAAM,EAAI,KAAK,OAAA,EAAW,EAC1B,MAAOD,EAAO,KAAK,MAAM,KAAK,OAAA,EAAWA,EAAO,MAAM,CAAC,EACvD,MAAO,EAAI,KAAK,OAAA,EAAW,EAC3B,KAAM,KAAK,SAAW,EAAI,KAAK,EAAA,EAC/B,EAEIG,EAAO,IAAM,CACjBP,EAAI,UAAU,EAAG,EAAGK,EAAO,MAAOA,EAAO,MAAM,EAC/CC,EAAO,QAASE,GAAM,CACpBR,EAAI,UAAYQ,EAAE,MAClBR,EAAI,UAAA,EACJA,EAAI,QAAQQ,EAAE,EAAGA,EAAE,EAAGA,EAAE,KAAMA,EAAE,KAAO,EAAGA,EAAE,KAAM,EAAG,EAAI,KAAK,EAAE,EAChER,EAAI,KAAA,EACJQ,EAAE,GAAKA,EAAE,MACTA,EAAE,GAAK,KAAK,IAAIA,EAAE,IAAI,CACxB,CAAC,EACG,KAAK,IAAA,EAAQL,wBAA2BI,CAAI,EAC3C,SAAS,KAAK,YAAYF,CAAM,CACvC,EACAE,EAAA,CACF,EAKME,GAAe,IACnBC,EAAAA,KAAC,MAAA,CAAI,MAAOjK,EAAO,eACjB,SAAA,CAAAkK,EAAAA,IAAC,KAAA,CAAG,MAAOlK,EAAO,YAAa,SAAA,iBAAc,EAC7CkK,EAAAA,IAAC,IAAA,CAAE,MAAOlK,EAAO,QAAS,SAAA,0BAAuB,EACjDkK,MAAC,OAAI,MAAO,CACV,QAAS,OACT,IAAKtH,IAAmB,MAAQ,OAChC,eAAgB,QAAA,EAEf,UAAC,EAAG,EAAG,CAAC,EAAE,IAAKkF,GACdmC,EAAAA,KAAC,SAAA,CAEC,QAAS,IAAMpC,GAAaC,CAAG,EAC/B,MAAO,CACL,GAAG9H,EAAO,SACV,GAAG6C,EAAsB,QAAQ,CAAA,EAGlC,SAAA,CAAAiF,EAAI,SAAA,CAAA,EAPAA,CAAA,CASR,CAAA,CACH,CAAA,EACF,EAGIqC,GAAa,IACjBF,EAAAA,KAAC,MAAA,CAAI,MAAOjK,EAAO,eACjB,SAAA,CAAAkK,EAAAA,IAAC,KAAA,CAAG,MAAOlK,EAAO,YAAa,SAAA,iBAAc,EAC7CkK,EAAAA,IAAC,IAAA,CAAE,MAAOlK,EAAO,QAAS,SAAA,wBAAqB,EAC/CkK,MAAC,OAAI,MAAO,CACV,QAAS,OACT,IAAKtH,IAAmB,MAAQ,OAChC,eAAgB,QAAA,EAEf,UAAC,GAAI,GAAI,EAAE,EAAE,IAAKoF,GACjBiC,EAAAA,KAAC,SAAA,CAEC,QAAS,IAAMlC,GAAiBC,CAAI,EACpC,MAAO,CACL,GAAGhI,EAAO,SACV,GAAG6C,EAAsB,QAAQ,CAAA,EAGlC,SAAA,CAAAmF,EAAK,GAAA,CAAA,EAPDA,CAAA,CASR,CAAA,CACH,CAAA,EACF,EAGIoC,GAAa,IACjBH,EAAAA,KAAC,MAAA,CAAI,MAAOjK,EAAO,eACjB,SAAA,CAAAiK,OAAC,KAAA,CAAG,MAAO,CAAC,GAAGjK,EAAO,QAAS,aAAc,OAAQ,SAAA,CAAA,aACxCkD,EAAO,YAAUA,GAAUA,EAAS,EAAI,IAAM,GAAG,mBAAA,EAC9D,EACAgH,EAAAA,IAAC,IAAA,CAAE,MAAO,CAAC,GAAGlK,EAAO,QAAS,aAAc,OAAQ,UAAW,MAAO,MAAO,SAAA,EAAY,SAAA,qCAEzF,EACAkK,MAAC,OAAI,MAAO,CACV,QAAS,OACT,cAAe,SACf,IAAK,GACL,MAAO,OACP,SAAU,cACV,SAAU,OAAA,EAET,SAAAnJ,EAAU,IAAI,CAACsJ,EAAMxJ,IACpBqJ,EAAAA,IAAC,QAAA,CAEC,MAAOG,EACP,YAAa,YAAYxJ,EAAI,CAAC,GAC9B,SAAWyJ,GAAMrC,GAAapH,EAAGyJ,EAAE,OAAO,KAAK,EAC/C,MAAO,CACL,GAAGtK,EAAO,QACV,QAAS4C,IAAmB,WAAa,YACzC,SAAUA,IAAmB,OAAS,OACtC,MAAO,OACP,UAAW,QAAA,CACb,EAVK/B,CAAA,CAYR,EACH,EACAqJ,EAAAA,IAAC,SAAA,CACC,QAAS1B,GACT,SAAUzH,EAAU,KAAMH,GAAMA,EAAE,KAAA,EAAO,SAAW,CAAC,EACrD,MAAO,CACL,GAAGZ,EAAO,SACV,UAAW,GACX,WAAYe,EAAU,KAAMH,GAAMA,EAAE,KAAA,EAAO,SAAW,CAAC,EAAI,OAAS,UACpE,OAAQG,EAAU,KAAMH,GAAMA,EAAE,KAAA,EAAO,SAAW,CAAC,EAAI,cAAgB,UACvE,GAAGiC,EAAsB,OAAO,CAAA,EAEnC,SAAA,MAAA,CAAA,CAED,EACF,EAGI0H,GAAiB,IACrBN,EAAAA,KAAC,MAAA,CAAI,MAAOjK,EAAO,eACjB,SAAA,CAAAkK,MAAC,MAAG,MAAO,CACT,GAAGlK,EAAO,YACV,SAAU4C,IAAmB,OAAS,OACtC,MAAO,UACP,aAAc,OACd,UAAW,+BAAA,EACV,SAAA,YAEH,EACAsH,EAAAA,IAAC,MAAA,CAAI,MAAOlK,EAAO,YAAa,SAAA,GAAA,CAAC,CAAA,EACnC,EAGIwK,GAAa,IACjBP,EAAAA,KAAC,MAAA,CAAI,MAAOjK,EAAO,aACjB,SAAA,CAAAiK,OAAC,MAAG,MAAO,CACT,aAAcrH,IAAmB,MAAQ,OACzC,SAAUA,EAAA,EAAmB,OAAS,MAAA,EACrC,SAAA,CAAA,SACMW,EAAe,EAAE,IAAEL,EAAO,MAAImB,EAAc,aAAe,SAASR,CAAQ,GAAA,EACrF,EAGAqG,EAAAA,IAAC,MAAA,CACC,MAAO,CACL,MAAO,MACP,OAAQtH,IAAmB,MAAQ,OACnC,aAAc,EACd,WAAY,OACZ,SAAU,SACV,aAAcA,EAAA,EAAmB,OAAS,MAAA,EAG5C,SAAAsH,EAAAA,IAAC,MAAA,CACC,MAAO,CACL,OAAQ,OACR,MAAO,GAAIrG,GAAYT,IAAgB,IAAO,GAAG,IACjD,WAAYS,GAAY,EAAI,UAAY,UACxC,WAAY,iBAAA,CACd,CAAA,CACD,CAAA,EAIHqG,EAAAA,IAAC,MAAA,CACC,WAAa,GAAM,EAAE,eAAA,EACrB,OAAS,GAAM3C,EAAa,EAAG,OAAQ,IAAI,EAC3C,MAAO,CACL,QAAS,OACT,SAAU7E,IAAoB,OAAS,SACvC,IAAKC,GAAY,OAAO,WAAa,IAAM,MAAQ,OACnD,eAAgB,SAChB,aAAcA,GAAY,OAAO,WAAa,IAAM,OAAS,OAC7D,QAASA,GAAY,OAAO,WAAa,IAAM,MAAQ,OACvD,MAAO,OACP,UAAW,YAAA,EAGZ,SAAAc,GAAM,IAAI,CAAC2D,EAAGD,IACb+C,EAAAA,IAAC,MAAA,CAEC,UAAW,CAAC7F,EACZ,KAAK,SACL,SAAUA,EAAc,GAAK,EAC7B,aAAYA,EAAc,SAAS+C,EAAE,IAAI,kBAAoBhG,GAAgB,YAAagG,EAAE,KAAM,mBAAmB,EACrH,YAAckD,GAAM,CAClB,GAAIjG,EAAa,CACfiG,EAAE,eAAA,EACF,MACF,CACAA,EAAE,aAAa,QACb,sBACA,KAAK,UAAU,CAAE,KAAM,OAAQ,GAAIlD,EAAE,GAAI,CAAA,EAE3CkD,EAAE,aAAa,QAAQ,aAAclD,EAAE,EAAE,EACzCzF,EAAuB,kBAAkByF,EAAE,IAAI,EAAE,CACnD,EACA,UAAYkD,GAAM,CACZjG,GACJ7C,GAAc8I,EAAG,IAAM5D,EAAU,OAAQ,WAAYU,EAAE,GAAI,IAAI,CAAC,CAClE,EACA,WAAakD,GAAMA,EAAE,eAAA,EACrB,OAASA,GAAM,CACb,MAAMG,EAAQH,EAAE,cAAiC,sBAAA,EAC3CI,EAAMD,EAAK,KAAOA,EAAK,MAAQ,EAC/B3D,EAAcwD,EAAE,QAAUI,EAAMvD,EAAM,EAAIA,EAChDxC,EAAS,CAAE,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,EAChD2F,EAAE,gBAAA,EACF/C,EAAa+C,EAAG,OAAQxD,CAAW,CACrC,EACA,YAAcwD,GAAM,CAClB,GAAIjG,EAAa,OACjB,MAAMoG,EAAQH,EAAE,cAAiC,sBAAA,EAC3CI,EAAMD,EAAK,KAAOA,EAAK,MAAQ,EACrC9F,EAAS,CAAE,KAAM,OAAQ,MAAOwC,EAAK,KAAMmD,EAAE,QAAUI,EAAM,QAAU,MAAA,CAAQ,CACjF,EACA,YAAa,IAAM/F,EAAS,CAAE,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,EACnE,QAAS,IAAM,CACTN,GACJqC,EAAU,OAAQ,WAAYU,EAAE,GAAI,IAAI,CAC1C,EACA,MAAO,CACL,QAASzE,GAAY,OAAO,WAAa,IAAM,WAAa,YAC5D,aAAcA,GAAY,OAAO,WAAa,IAAM,MAAQ,OAC5D,OAAQ,iBACR,WAAY0B,EAAc,UAAY,UACtC,OAAQA,EAAc,cAAgB,UACtC,SAAU1B,GAAY,OAAO,WAAa,IAAM,OAAS,OACzD,WAAY+B,EAAM,OAAS,QAAUA,EAAM,QAAUyC,GAAOzC,EAAM,OAAS,OAAS,oBAAsB,iBAC1G,YAAaA,EAAM,OAAS,QAAUA,EAAM,QAAUyC,GAAOzC,EAAM,OAAS,QAAU,oBAAsB,iBAC5G,WAAY,EACZ,UAAW,OACX,QAASL,EAAc,GAAM,EAC7B,WAAY,mBAAA,EAGb,SAAA+C,EAAE,IAAA,EAxDEA,EAAE,EAAA,CA0DV,CAAA,CAAA,EAIH8C,EAAAA,IAAC,MAAA,CACC,WAAa,GAAM,EAAE,eAAA,EACrB,OAAS,GAAM3C,EAAa,EAAG,WAAY,IAAI,EAC/C,MAAO,CACL,UAAW5E,GAAY,OAAO,WAAa,IAAM,OAAS,OAC1D,MAAO,OACP,SAAU,OACV,SAAU,QACV,OAAQwB,IAAe,UAAY,qBAC3BA,IAAe,SAAW,qBAC1BA,IAAe,QAAU,qBAAuB,kBACxD,aAAcxB,GAAY,OAAO,WAAa,IAAM,MAAQ,OAC5D,QAASA,GAAY,OAAO,WAAa,IAAM,MAAQ,OACvD,QAAS,OACT,SAAUD,IAAoB,OAAS,SACvC,WAAY,SACZ,eAAgB,SAChB,SAAU,GAAG4F,GAAoB3E,EAAS,MAAM,CAAC,KACjD,WAAYQ,IAAe,UAAY,UAC3BA,IAAe,SAAW,UAC1BA,IAAe,QAAU,UAAY,UACjD,UAAWzB,IAAoB,SAAW,OAC1C,WAAYA,EAAA,EAAoB,SAAW,QAAA,EAG5C,SAAAiB,EAAS,IAAI,CAACyD,EAAGD,IAChB+C,EAAAA,IAAC,OAAA,CAEC,UAAW,CAAC7F,EACZ,YAAciG,GAAM,CAClB,GAAIjG,EAAa,CACfiG,EAAE,eAAA,EACF,MACF,CACAA,EAAE,aAAa,QACb,sBACA,KAAK,UAAU,CAAE,KAAM,WAAY,GAAIlD,EAAE,GAAI,CAAA,EAE/CkD,EAAE,aAAa,QAAQ,aAAclD,EAAE,EAAE,CAC3C,EACA,WAAakD,GAAMA,EAAE,eAAA,EACrB,OAASA,GAAM,CACb,MAAMG,EAAQH,EAAE,cAAkC,sBAAA,EAC5CI,EAAMD,EAAK,KAAOA,EAAK,MAAQ,EAC/B3D,EAAcwD,EAAE,QAAUI,EAAMvD,EAAM,EAAIA,EAChDxC,EAAS,CAAE,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,EAChD2F,EAAE,gBAAA,EACF/C,EAAa+C,EAAG,WAAYxD,CAAW,CACzC,EACA,YAAcwD,GAAM,CAClB,GAAIjG,EAAa,OACjB,MAAMoG,EAAQH,EAAE,cAAkC,sBAAA,EAC5CI,EAAMD,EAAK,KAAOA,EAAK,MAAQ,EACrC9F,EAAS,CAAE,KAAM,WAAY,MAAOwC,EAAK,KAAMmD,EAAE,QAAUI,EAAM,QAAU,MAAA,CAAQ,CACrF,EACA,YAAa,IAAM/F,EAAS,CAAE,KAAM,KAAM,MAAO,KAAM,KAAM,KAAM,EACnE,QAAS,IAAM,CACTN,GACJqC,EAAU,WAAY,OAAQU,EAAE,GAAI,IAAI,CAC1C,EACA,MAAO/C,EAAc,eAAiB,+BACtC,MAAO,CACL,QAASzB,IAAmB,UAAY,WACxC,OAAQA,IAAmB,MAAQ,MACnC,aAAcA,IAAmB,MAAQ,MACzC,WAAYyB,EAAc,UAAY,UACtC,OAAQA,EAAc,iBAAmB,oBACzC,WAAYK,EAAM,OAAS,YAAcA,EAAM,QAAUyC,GAAOzC,EAAM,OAAS,OAAS,oBAAsB,OAC9G,YAAaA,EAAM,OAAS,YAAcA,EAAM,QAAUyC,GAAOzC,EAAM,OAAS,QAAU,oBAAsB,OAChH,OAAQL,EAAc,cAAgB,UACtC,WAAY,OACZ,SAAU,GAAGiE,GAAoB3E,EAAS,MAAM,CAAC,KACjD,WAAY,4EACZ,WAAY,SACZ,QAASU,EAAc,GAAM,EAC7B,WAAY,mBAAA,EAGb,SAAA+C,EAAE,IAAA,EAnDEA,EAAE,EAAA,CAqDV,CAAA,CAAA,EAGH8C,EAAAA,IAAC,SAAA,CACC,QAAS,IAAMd,GAAW,EAAI,EAC9B,SAAU,CAAC/E,GAAeV,EAAS,SAAW,EAC9C,MAAO,CACL,UAAWf,IAAmB,OAAS,OACvC,SAAUA,IAAmB,OAAS,OACtC,QAASA,IAAmB,WAAa,YACzC,aAAcA,IAAmB,MAAQ,OACzC,WAAayB,GAAeV,EAAS,OAAS,EAAK,UAAY,OAC/D,MAAO,QACP,OAAQ,OACR,OAASU,GAAeV,EAAS,OAAS,EAAK,UAAY,aAAA,EAG5D,SAAc,MAAS,CAAA,CAC1B,EACF,EAGIgH,GAAgB,IACpBV,EAAAA,KAAC,MAAA,CAAI,MAAOjK,EAAO,eACjB,SAAA,CAAAkK,MAAC,MAAG,MAAO,CACT,GAAGlK,EAAO,YACV,WAAY2C,GAAY,OAAO,WAAa,OAAO,aAAiB,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAQwC,GAAsBE,GAAuBE,GAAqBE,GAAsBE,GAAwBE,GAAyBE,GAAqBE,EAAqB,OAC1e,aAAetD,GAAY,OAAO,WAAa,OAAO,aAAiB,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAQwC,GAAsBE,GAAuBE,GAAqBE,GAAsBE,GAAwBE,GAAyBE,GAAqBE,EAAqB,MAAQ,OACrf,SAAWtD,GAAY,OAAO,YAAc,KAAO,OAAO,aAAe,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,IAAO,OAAS,wBAAA,EAC5U,SAAA,eAEH,EACAsH,OAAC,MAAG,MAAO,CACT,GAAGjK,EAAO,YACV,WAAY2C,GAAY,OAAO,WAAa,OAAO,aAAiB,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAQwC,GAAsBE,GAAuBE,GAAqBE,GAAsBE,GAAwBE,GAAyBE,GAAqBE,EAAqB,OAC1e,aAAetD,GAAY,OAAO,WAAa,OAAO,aAAiB,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAQwC,GAAsBE,GAAuBE,GAAqBE,GAAsBE,GAAwBE,GAAyBE,GAAqBE,EAAqB,MAAQ,OACrf,SAAWtD,GAAY,OAAO,YAAc,KAAO,OAAO,aAAe,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,IAAO,OAAS,MAAA,EAC5U,SAAA,CAAA,eACYoB,EAAM,WAASb,CAAA,EAC9B,EACA+G,OAAC,KAAE,MAAO,CACR,GAAGjK,EAAO,QACV,MAAO,UACP,UAAY2C,GAAY,OAAO,WAAa,OAAO,aAAiB,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAQwC,GAAsBE,GAAuBE,GAAqBE,GAAsBE,GAAwBE,GAAyBE,GAAqBE,EAAqB,MAAQ,OAClf,aAAetD,GAAY,OAAO,WAAa,OAAO,aAAiB,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAQwC,GAAsBE,GAAuBE,GAAqBE,GAAsBE,GAAwBE,GAAyBE,GAAqBE,EAAqB,MAAQ,OACrf,SAAWtD,GAAY,OAAO,YAAc,KAAO,OAAO,aAAe,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,IAAO,OAAS,MAAA,EAC5U,SAAA,CAAA,eACY4B,EAAA,EACf,EAEA0F,OAAC,OAAI,MAAO,CACV,QAAS,OACT,IAAMtH,GAAY,OAAO,WAAa,OAAO,aAAiBA,GAAY,OAAO,YAAc,KAAO,OAAO,aAAe,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,IAAO,MAAQ,OAC/X,UAAYA,GAAY,OAAO,WAAa,OAAO,aAAiBA,GAAY,OAAO,YAAc,KAAO,OAAO,aAAe,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,KAAS,OAAO,aAAe,KAAO,OAAO,cAAgB,IAAO,MAAS,OAAO,aAAe,MAAQ,OAAO,cAAgB,KAAS,OAAO,aAAe,MAAQ,OAAO,cAAgB,KAAS,OAAO,aAAe,MAAQ,OAAO,cAAgB,KAAS,OAAO,aAAe,MAAQ,OAAO,cAAgB,KAAQsC,GAAkB,OAAS,MAAA,EAExpB,SAAA,CAAAiF,EAAAA,IAAC,SAAA,CACC,QAAS,IAAM,CACbZ,GAAA,EACAH,EAAU,OAAO,EACjB,WAAW,IAAM,CACflG,EAAS,UAAU,EACnBiB,GAAa,IAAI,EACjBI,EAAe,EAAK,CACtB,EAAG,GAAG,CACR,EACA,MAAO,CACL,GAAGtE,EAAO,SACV,GAAG6C,EAAsB,QAAQ,CAAA,EAEpC,SAAA,eAAA,CAAA,EAIDqH,EAAAA,IAAC,SAAA,CACC,QAAS,IAAM,CACbf,EAAU,OAAO,EACjBlG,EAAS,QAAQ,EACjBE,GAAU,IAAI,EACdE,GAAgB,IAAI,EACpBC,EAAa,CAAA,CAAE,EACfU,EAAS,CAAC,EACVJ,GAAY,CAAA,CAAE,EACdU,EAAe,EAAK,CACtB,EACA,MAAO,CACL,GAAGtE,EAAO,SACV,GAAG6C,EAAsB,QAAQ,CAAA,EAEpC,SAAA,SAAA,CAAA,CAED,CAAA,CACF,CAAA,EACF,EAII+H,GAAUxI,IACbE,EACG,GAAGA,EAAQ,SAAS,GAAG,EAAIA,EAAQ,MAAM,EAAG,EAAE,EAAIA,CAAO,YACxD,OAAO,OAAW,KAAe,OAAO,OACrC,GAAG,OAAO,MAAM,mDAChB,MAGJuI,GAAiB,CAAClI,GACtBN,GACA,EAAE,OAAO,WAAa,OAAO,cAC7B,OAAO,aAAe,IAExB,OACE6H,EAAAA,IAAC,MAAA,CACC,IAAK3H,EACL,MAAO,CACL,MAAO,OACP,OAAQ,OACR,QAAS,OACT,eAAgB,SAChB,WAAY,SACZ,WAAY,uDACZ,WAAY,uBACZ,SAAU,SACV,SAAU,WACV,IAAK,EACL,KAAM,EACN,MAAO,EACP,OAAQ,CAAA,EAGV,SAAA2H,EAAAA,IAAC,MAAA,CACC,MAAO,CACL,MAAOvH,EAAW,OAAUoC,IAAiB,IAC7C,OAAQpC,EAAW,OAAUoC,IAAiB,IAC9C,QAAS,OACT,eAAgB,SAChB,WAAY,SACZ,SAAU,SACV,aAAcpC,EAAW,EAAI,OAC7B,WAAY,uDACZ,UAAWA,EAAW,OAAS,2BAC/B,OAAQA,EAAW,SAAW,QAC9B,SAAU,UAAA,EAGZ,SAAAuH,EAAAA,IAAC,MAAA,CACC,MAAO,CACL,UAAW,OACX,MAAO,OACP,OAAQ,OACR,QAAS,OACT,eAAgB,SAChB,WAAY,QAAA,EAGd,SAAAD,EAAAA,KAAC,MAAA,CAAI,GAAG,sBACL,SAAA,CAAAY,GACCX,EAAAA,IAAC,OAAI,MAAO,CACV,GAAGlK,EAAO,YACV,QAAS,OAAA,EAER,SAAA4K,GACCV,EAAAA,IAAC,MAAA,CACC,IAAKU,GACL,IAAI,eACJ,MAAO5K,EAAO,UACd,QAAQ,MAAA,CAAA,QAGT,MAAA,CAAI,MAAOA,EAAO,UAAW,SAAA,SAAA,CAE9B,EAEJ,EACE,KACHgD,IAAU,SAAWgH,GAAA,EAAiB,KACtChH,IAAU,OAASmH,GAAA,EAAe,KAClCnH,IAAU,OAASoH,GAAA,EAAe,KAClCpH,IAAU,WAAauH,GAAA,EAAmB,KAC1CvH,IAAU,OAASwH,GAAA,EAAe,KAClCxH,IAAU,UAAY2H,KAAkB,IAAA,CAAA,CAC3C,CAAA,CAAA,CACF,CAAA,CACF,CAAA,CAGN,CCtgCO,MAAMG,WAAsBC,EAAAA,SAAwB,CACzD,YAAY5I,EAAc,CACxB,MAAMA,CAAK,EACX,KAAK,MAAQ,CAAE,SAAU,EAAA,CAC3B,CAEA,OAAO,yBAAyBjB,EAAqB,CACnD,MAAO,CACL,SAAU,GACV,MAAAA,CAAA,CAEJ,CAEA,kBAAkBA,EAAc8J,EAAsB,CACpD,QAAQ,MAAM,cAAe9J,EAAO8J,CAAS,EAK7C,KAAK,SAAS,CACZ,MAAA9J,EACA,UAAA8J,CAAA,CACD,CACH,CAEA,YAAc,IAAM,CAClB,KAAK,SAAS,CAAE,SAAU,GAAO,MAAO,OAAW,UAAW,OAAW,CAC3E,EAEA,QAAS,CACP,OAAI,KAAK,MAAM,SACT,KAAK,MAAM,SACN,KAAK,MAAM,SAIlBf,EAAAA,KAAC,OAAI,MAAO,CACV,QAAS,OACT,cAAe,SACf,WAAY,SACZ,eAAgB,SAChB,UAAW,QACX,QAAS,OACT,UAAW,SACX,gBAAiB,UACjB,MAAO,UACP,WAAY,uBAAA,EAEZ,SAAA,CAAAC,EAAAA,IAAC,KAAA,CAAG,MAAO,CAAE,SAAU,OAAQ,aAAc,MAAA,EAAU,SAAA,+BAAA,CAEvD,EACAA,EAAAA,IAAC,IAAA,CAAE,MAAO,CAAE,SAAU,OAAQ,aAAc,OAAQ,SAAU,OAAA,EAAW,SAAA,gFAAA,CAEzE,EAEAA,EAAAA,IAAC,SAAA,CACC,QAAS,KAAK,YACd,MAAO,CACL,QAAS,YACT,SAAU,OACV,gBAAiB,UACjB,MAAO,QACP,OAAQ,OACR,aAAc,MACd,OAAQ,UACR,WAAY,uBAAA,EAEd,YAAcI,GAAMA,EAAE,cAAc,MAAM,gBAAkB,UAC5D,WAAaA,GAAMA,EAAE,cAAc,MAAM,gBAAkB,UAC5D,SAAA,iBAAA,CAAA,EAIA,OAAO,QAAY,KAAe,QAAQ,IAAI,WAAa,eAAiB,KAAK,MAAM,cACrF,UAAA,CAAQ,MAAO,CAAE,UAAW,OAAQ,UAAW,OAAQ,SAAU,SAChE,SAAA,CAAAJ,EAAAA,IAAC,UAAA,CAAQ,MAAO,CAAE,OAAQ,UAAW,SAAU,MAAA,EAAU,SAAA,sCAAA,CAEzD,EACAD,OAAC,OAAI,MAAO,CACV,gBAAiB,UACjB,QAAS,OACT,aAAc,MACd,SAAU,OACV,SAAU,OACV,UAAW,KAAA,EAEV,SAAA,CAAA,KAAK,MAAM,MAAM,SAAA,EACjB,KAAK,MAAM,WAAW,cAAA,CAAA,CACzB,CAAA,CAAA,CACF,CAAA,EAEJ,EAIG,KAAK,MAAM,QACpB,CACF"}
|