diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-08 03:32:24 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-08 03:32:24 +0100 |
| commit | fda24c47a8262388ada92722850a362da65aaa6e (patch) | |
| tree | 13363fa1461ae4e10087acba562a527b8bde4228 /web/play/app.js | |
| parent | v5.0.0: protocol v5 and the browser frontend (diff) | |
| download | zagan-bet-fda24c47a8262388ada92722850a362da65aaa6e.tar.gz zagan-bet-fda24c47a8262388ada92722850a362da65aaa6e.zip | |
web: accept the serialized reels array and stop game loops on navigation
The Rust SlotsView serializes reels as an array of chars, so the browser joins it instead of String(array). The crash chart, reel animation and roulette observer now stop when another screen takes over, and a returning crash screen rebuilds its detached canvas. Action buttons ignore a double click before the server view arrives.
Also tightens the gateway session registry with a generation token, caps WebSocket messages at 64 KiB, uses the __Host- cookie prefix on HTTPS, and ships the systemd unit.
Diffstat (limited to '')
| -rw-r--r-- | web/play/app.js | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/web/play/app.js b/web/play/app.js index 3320693..4950c5e 100644 --- a/web/play/app.js +++ b/web/play/app.js | |||
| @@ -1 +1 @@ | |||
| "use strict";(()=>{function k(e){let n=document.getElementById(e);if(!n)throw new Error(`missing #${e}`);return n}function o(e,n,t){let s=document.createElement(e);return n&&(s.className=n),t!==void 0&&(s.textContent=t),s}function H(e){e.replaceChildren()}function Oe(e){let n=e<0,t=String(Math.abs(Math.trunc(e))),s="";for(let a=0;a<t.length;a+=1)a>0&&(t.length-a)%3===0&&(s+=" "),s+=t[a];return n?`-${s}`:s}function L(e){return e==null||Number.isNaN(e)?"— Kr":`${Oe(e)} Kr`}function me(e){return`${e<0?"-":"+"}${L(Math.abs(e))}`}function J(e,n="info"){let t=document.getElementById("toasts");if(!t||!e)return;let s=o("div",`toast ${n}`,e);for(t.append(s),window.setTimeout(()=>{s.style.opacity="0",s.style.transition="opacity 220ms ease",window.setTimeout(()=>s.remove(),240)},4200);t.children.length>4;)t.firstElementChild?.remove()}function he(e){let n=e.toLowerCase();return e.startsWith("ERROR")||n.includes("failed")||n.includes("lost")||n.includes("invalid")||n.includes("forfeit")?"bad":e.startsWith("Logged in")||e.startsWith("Account created")||n.includes("won")||n.includes("cashed")?"good":"info"}async function fe(e){let n=new TextEncoder().encode(e),t=await crypto.subtle.digest("SHA-256",n);return[...new Uint8Array(t)].map(s=>s.toString(16).padStart(2,"0")).join("")}function O(e,n=10){return e.length<=n*2?e:`${e.slice(0,n)}…${e.slice(-n)}`}function be(e){let n=Date.parse(e.includes("T")?e:e.replace(" ","T")+"Z");return Number.isNaN(n)?e:new Date(n).toLocaleString()}function ge(e){if(e==="?"||!e)return{rank:"?",suit:"",red:!1};let n=e.slice(-1);return{rank:e.slice(0,-1),suit:n==="C"?"♣":n==="D"?"♦":n==="H"?"♥":n==="S"?"♠":n,red:n==="D"||n==="H"}}var j=class{constructor(n,t){this.url=n;this.handlers=t;this.socket=null;this.stopped=!1;this.replaced=!1;this.attempts=0}connect(){if(this.stopped)return;this.clearTimer();let n;try{n=new WebSocket(this.url)}catch{this.scheduleReconnect()||this.handlers.onClosed(!1);return}this.socket=n,n.addEventListener("open",()=>{this.attempts=0,this.handlers.onOpen()}),n.addEventListener("message",t=>{let s;try{s=JSON.parse(String(t.data))}catch{return}switch(s.type){case"hello":this.handlers.onHello(s);break;case"view":this.handlers.onView(s.view);break;case"notice":this.handlers.onNotice(String(s.text??""));break;case"error":this.handlers.onError(String(s.text??""));break;case"replaced":this.replaced=!0,this.handlers.onReplaced();break;case"pong":this.handlers.onPong();break}}),n.addEventListener("close",()=>{if(this.socket===n&&(this.socket=null),this.replaced||this.stopped){this.handlers.onClosed(!1);return}let s=this.scheduleReconnect();this.handlers.onClosed(s)}),n.addEventListener("error",()=>{})}send(n){this.socket?.readyState===WebSocket.OPEN&&this.socket.send(JSON.stringify({type:"command",command:n}))}ping(){this.socket?.readyState===WebSocket.OPEN&&this.socket.send(JSON.stringify({type:"ping"}))}close(){this.stopped=!0,this.clearTimer(),this.socket?.close()}scheduleReconnect(){if(this.stopped||this.replaced||this.attempts>=6)return!1;this.attempts+=1;let n=Math.min(250*2**(this.attempts-1),4e3);return this.timer=window.setTimeout(()=>this.connect(),n),!0}clearTimer(){this.timer!==void 0&&(window.clearTimeout(this.timer),this.timer=void 0)}};function ze(e){if(e==="?"){let s=o("div","card back");return s.append(o("span","rank","?"),o("span","suit","")),s}let n=ge(e),t=o("div","card");return n.red&&t.classList.add("red"),t.append(o("span","rank",n.rank),o("span","suit",n.suit)),t}function ye(e,n,t){let s=o("div","hand");s.append(o("div","label",e));let a=o("div","cards");for(let d of n)a.append(ze(d));let r=o("div","total");return r.append(document.createTextNode("Total "),o("strong",void 0,String(t))),s.append(a,r),s}function Ve(e,n){let t=String(n?.result??""),s=Number(n?.winnings??0);switch(t){case"blackjack":return`Blackjack — won ${L(s)}`;case"win":return`You win — ${L(s)}`;case"push":return`Push — ${L(s)} returned`;case"bust":return"Bust — the bet is lost";case"lose":return"Dealer wins — the bet is lost";case"forfeit":return"Hand forfeited — the bet is lost";case"playing":return e.status==="player"?"Your move.":"Dealing…";default:return"Ready to deal."}}function ke(e,n,t,s){H(e),H(n);let a=t.hand,r=a?.phase==="player"||t.status==="player",d=a?.phase==="done"||t.status==="done",i=!a||d;if(e.append(o("h2",void 0,"Blackjack")),e.append(o("p","note","Six decks. Dealer stands on all 17. Blackjack pays 3:2.")),a)e.append(ye("Dealer",a.dealer??[],Number(a.dealer_total??0))),e.append(ye("You",a.player??[],Number(a.player_total??0)));else{let h=o("div","outcome");h.textContent="Press DEAL to start a hand.",e.append(h)}if(d||a&&!r){let h=o("div","outcome");h.textContent=Ve(t,a),(String(a?.result)==="win"||String(a?.result)==="blackjack"||String(a?.result)==="push")&&h.classList.add("win-text"),e.append(h)}t.error&&e.append(o("p","error-text",String(t.error))),n.append(o("div","label","Blackjack"));let m=Number(a?.bet??t.bet??0),p=t.balance??t.hand?.balance;if(n.append(o("p","note","Hit, stand or double. Forfeiting loses the reserved bet.")),i){let h=o("div","row"),v=o("button","btn small","−10"),y=o("strong","mono",L(m)),w=o("button","btn small","+10");v.addEventListener("click",()=>s({AdjustBet:-10})),w.addEventListener("click",()=>s({AdjustBet:10})),h.append(v,y,w),n.append(o("div","label","Bet"),h)}else{let h=o("div","stat");h.append(o("span","muted","Bet"),o("strong",void 0,L(m))),n.append(h)}if(p!==void 0){let h=o("div","stat");h.append(o("span","muted","Balance"),o("strong",void 0,L(Number(p)))),n.append(h)}let u=o("div","actions");if(r){let h=o("div","row wrap");for(let y of a?.actions??[]){let w=y==="hit"?"HIT":y==="stand"?"STAND":"DOUBLE",E=y==="stand"?o("button","btn primary",w):o("button","btn",w);E.addEventListener("click",()=>{s(y==="hit"?"Hit":y==="stand"?"Stand":"Double")}),h.append(E)}u.append(h);let v=o("button","btn danger wide","Forfeit hand");v.addEventListener("click",()=>{window.confirm("Forfeit this hand? The reserved bet is lost.")&&s("Forfeit")}),u.append(v)}else if(i){let h=o("button","btn primary wide big","DEAL");h.addEventListener("click",()=>s("Deal")),u.append(h)}let g=o("button","btn ghost wide",r?"Leave (forfeits)":"Leave table");g.addEventListener("click",()=>{r&&!window.confirm("Leaving forfeits this hand. Continue?")||s("Leave")}),u.append(g),n.append(u)}var q=Math.LN2/5,R=null,z=null,ve=null,P=null,W,Le=0,Y="";function _e(e,n,t,s){H(e),H(n),P=t,ve=s,e.append(o("h2",void 0,"Crash")),e.append(o("p","note","The multiplier rises from 1.00×. Cash out before it crashes."));let a=o("div","crash-wrap"),r=o("div","crash-number","1.00×"),d=o("div","crash-meta"),i=o("canvas","crash-canvas"),m=o("div","verify","Waiting for a round commitment.");a.append(r,d,i,m),e.append(a),n.append(o("div","label","Crash")),n.append(o("p","note","The server commits to a seed before the round. The seed is revealed when it ends."));let p=o("div","row"),u=o("button","btn small","−10"),g=o("strong","mono","—"),h=o("button","btn small","+10");u.addEventListener("click",()=>P?.({AdjustBet:-10})),h.addEventListener("click",()=>P?.({AdjustBet:10})),p.append(u,g,h),n.append(o("div","label","Bet"),p);let v=o("strong","mono","—"),y=o("strong","mono","—");for(let[M,N]of[["Potential",v],["Balance",y]]){let b=o("div","stat");b.append(o("span","muted",M),N),n.append(b)}let w=o("p","note","Ready."),E=o("p","note",""),S=o("p","error-text");n.append(w,E,S);let l=o("div","actions"),c=o("button","btn primary wide big","START"),f=o("button","btn ghost wide","Leave table");return c.addEventListener("click",()=>{z?.status==="running"?P?.("CashOut"):P?.("Start")}),f.addEventListener("click",()=>{z?.status==="running"&&!window.confirm("Forfeit this round? The bet is lost.")||P?.("Leave")}),l.append(c,f),n.append(l),{board:e,side:n,number:r,meta:d,verify:m,canvas:i,bet:g,potential:v,balance:y,status:w,lastCrash:E,error:S,primary:c,leave:f,minus:u,plus:h}}function we(e,n,t,s,a){(!R||R.board!==e)&&(R=_e(e,n,s,a),Y="");let r=R;P=s,ve=a,z=t,t.status!==Y&&((t.status==="starting"||t.status==="running")&&Y!=="running"&&(r.verify.className="verify",r.verify.textContent="Round committed; seed hidden until the round ends."),Y=String(t.status));let d=t.status==="running",i=t.status==="starting",m=d||i;r.bet.textContent=L(Number(t.bet??0)),r.potential.textContent=L(Number(t.potential??t.bet??0)),r.balance.textContent=t.balance===null||t.balance===void 0?"—":L(Number(t.balance)),r.error.textContent=t.error?String(t.error):"",r.minus.disabled=m,r.plus.disabled=m,r.primary.textContent=d?"CASH OUT":i?"STARTING…":"START",r.primary.disabled=i,r.primary.className="btn primary wide big",r.leave.textContent=d?"Forfeit round":"Leave table",d?(r.status.textContent="Rising — cash out before the crash.",r.status.className="note win-text"):i?(r.status.textContent="Starting the round…",r.status.className="note"):t.status==="cashed"?(r.status.textContent=`Cashed out at ${Number(t.multiplier??0).toFixed(2)}× for ${L(Number(t.payout??0))}.`,r.status.className="note win-text"):t.status==="crashed"?(r.status.textContent=`Crashed at ${Number(t.crash_point??t.multiplier??0).toFixed(2)}×. The bet is lost.`,r.status.className="note error-text"):t.status==="forfeit"?(r.status.textContent="Round forfeited.",r.status.className="note error-text"):(r.status.textContent="Ready. Start a round when you want.",r.status.className="note"),t.crash_point!==null&&t.crash_point!==void 0&&t.status==="crashed"&&(r.lastCrash.textContent=`Last crash: ${Number(t.crash_point).toFixed(2)}×`);let p=t.commit?String(t.commit):"";if(r.meta.textContent=p?`commit ${O(p,12)}`:"no commitment yet",t.seed&&p){let u=++Le,g=String(t.seed),h=Number(t.crash_point??0);Xe(g,p,h).then(([v,y])=>{if(u!==Le||!R)return;let w=v&&y;R.verify.className=`verify ${w?"ok":"bad"}`,R.verify.textContent=w?`Seed ${O(g,12)} · sha256 matches commit · crash point recomputed`:`VERIFICATION FAILED · seed ${O(g,12)} · commit ${O(p,12)}`})}else!m&&!p&&(r.verify.className="verify",r.verify.textContent="Waiting for a round commitment.");if(W!==void 0&&(cancelAnimationFrame(W),W=void 0),d){let u=()=>{if(!R||z?.status!=="running"){W=void 0;return}xe(R,z,a),W=requestAnimationFrame(u)};W=requestAnimationFrame(u)}else xe(r,t,a)}function je(e,n){if(e.status==="running"){let t=Math.max(0,(n.now()-Number(e.started_at??0))/1e3),s=Math.min(1e3,Math.exp(q*t));return Math.max(s,Number(e.multiplier??1))}return e.status==="cashed"?Number(e.multiplier??1):e.status==="crashed"?Number(e.crash_point??e.multiplier??1):1}function xe(e,n,t){let s=je(n,t);e.number.textContent=`${s.toFixed(2)}×`,e.number.className=`crash-number ${n.status==="running"?"running":n.status==="cashed"?"cashed":n.status==="crashed"?"crashed":""}`,e.potential.textContent=L(Math.floor(Number(n.bet??0)*s)),Ye(e.canvas,n,s,t)}function Ye(e,n,t,s){let a=e.clientWidth||600,r=e.clientHeight||360,d=window.devicePixelRatio||1;(e.width!==Math.round(a*d)||e.height!==Math.round(r*d))&&(e.width=Math.round(a*d),e.height=Math.round(r*d));let i=e.getContext("2d");if(!i)return;i.setTransform(d,0,0,d,0,0),i.clearRect(0,0,a,r);let m=54,p=16,u=18,g=34,h=Math.max(1,a-m-p),v=Math.max(1,r-u-g),y=n.status==="running"?Math.max(.25,(s.now()-Number(n.started_at??0))/1e3):t>1?Math.log(t)/q:1,w=Math.max(5,y*1.08),E=Math.max(2,Math.ceil(t*1.15*2)/2),S=b=>m+b/w*h,l=b=>u+v-(b-1)/(E-1)*v;i.strokeStyle="#242e38",i.fillStyle="#8a98a6",i.font="11px ui-monospace, monospace",i.lineWidth=1;for(let b=0;b<=4;b+=1){let T=1+(E-1)*b/4,C=l(T);i.beginPath(),i.moveTo(m,C),i.lineTo(a-p,C),i.stroke(),i.fillText(`${T.toFixed(1)}×`,6,C+4)}for(let b=0;b<=4;b+=1){let T=w*b/4,C=S(T);i.beginPath(),i.moveTo(C,u),i.lineTo(C,u+v),i.strokeStyle="#1b232c",i.stroke(),i.fillStyle="#5b6773",i.fillText(`${T.toFixed(0)}s`,C-10,r-12)}let c=n.status==="crashed"?"#e05a5a":n.status==="cashed"?"#4ec27b":"#e0b64a";i.beginPath();let f=180;for(let b=0;b<=f;b+=1){let T=y*b/f,C=Math.min(E,Math.exp(q*T)),ue=S(T),pe=l(C);b===0?i.moveTo(ue,pe):i.lineTo(ue,pe)}i.strokeStyle=c,i.lineWidth=2.4,i.stroke();let M=S(y),N=l(Math.min(E,t));i.beginPath(),i.arc(M,N,4.5,0,Math.PI*2),i.fillStyle=c,i.fill(),i.fillStyle=c,i.font="600 12px ui-monospace, monospace",i.fillText(`${t.toFixed(2)}×`,Math.min(M+8,a-70),Math.max(u+12,N-10))}async function Xe(e,n,t){let s=new Uint8Array(e.length/2);for(let u=0;u<s.length;u+=1)s[u]=Number.parseInt(e.slice(u*2,u*2+2),16);let a=await crypto.subtle.digest("SHA-256",s),d=[...new Uint8Array(a)].map(u=>u.toString(16).padStart(2,"0")).join("")===n.toLowerCase(),i=0;for(let u=0;u<8;u+=1)i=i*256+s[u];i/=2**64;let m=Math.max(1,Math.min(1e3,(1-.01)/(1-i))),p=Math.abs(m-t)<1e-6;return[d,p]}function Ge(e){let n=e.details??{};switch(e.game){case"slots":return String(n.win_type??"spin");case"roulette":return`${n.number??"?"} ${n.color??""}`.trim();case"blackjack":return String(n.result??"");case"crash":{let t=String(n.result??""),s=n.crash_point;return s==null?t:`${t} @ ${Number(s).toFixed(2)}×`}default:return""}}function Te(e,n){H(e);let t=n.records??[];if(t.length===0){let m=o("div","board");m.append(o("h2",void 0,"No plays yet"),o("p","muted","Your settled plays will appear here.")),e.append(m);return}let s=o("div","table-wrap"),a=o("table"),r=o("thead"),d=o("tr");for(let m of["Time","Game","Bet","Result","Net","Balance"])d.append(o("th",void 0,m));r.append(d);let i=o("tbody");for(let m of t){let p=o("tr");p.append(o("td","mono",be(String(m.at??"")))),p.append(o("td",void 0,String(m.game??""))),p.append(o("td","num",L(Number(m.bet??0)))),p.append(o("td","muted",Ge(m)));let u=Number(m.winnings??0)-Number(m.bet??0),g=o("td",`num ${u>0?"pos":u<0?"neg":""}`,u===0?"0 Kr":me(u));p.append(g),p.append(o("td","num",L(Number(m.balance_after??0)))),i.append(p)}a.append(r,i),s.append(a),e.append(s)}var Ke="#b0313a",Ue="#151b21",Ee="#106b45",Ze="#0d5c39",Je="#09472c",qe="#1f7d52",Qe="#ecf7f0",et="#e0b64a";function tt(e){return e===0?"green":[1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36].includes(e)?"red":"black"}function nt(e,n){let s=Math.max(38,e*.055),a=Math.max(34,e*.05),r=Math.max(30,n*.07),d=6,i=e-28-s-a,m=i/12,p=(n-28-r*2-d*2)/3,u=14+s,g=14,h=g+p*3+d,v=h+r+d,y=[];for(let l=0;l<12;l+=1)for(let c=0;c<3;c+=1){let f=l*3+(3-c);y.push({x:u+l*m,y:g+c*p,w:m,h:p,target:{bet:"straight",number:f},label:String(f),kind:"number",number:f})}y.push({x:14,y:g,w:s,h:p*3,target:{bet:"straight",number:0},label:"0",kind:"zero",number:0});for(let l=0;l<3;l+=1){let c=2-l;y.push({x:u+i,y:g+l*p,w:a,h:p,target:{bet:"column",index:c},label:"2:1",kind:"column"})}for(let l=0;l<3;l+=1)y.push({x:u+i/3*l,y:h,w:i/3,h:r,target:{bet:"dozen",index:l},label:["1st 12","2nd 12","3rd 12"][l],kind:"dozen"});[{kind:"low",label:"1–18"},{kind:"even",label:"EVEN"},{kind:"red",label:"RED"},{kind:"black",label:"BLACK"},{kind:"odd",label:"ODD"},{kind:"high",label:"19–36"}].forEach((l,c)=>{y.push({x:u+i/6*c,y:v,w:i/6,h:r,target:{bet:"outside",kind:l.kind},label:l.label,kind:"outside"})});let E=[],S=l=>{let c=y.find(f=>f.kind==="number"&&f.number===l);return c?{x:c.x+c.w/2,y:c.y+c.h/2}:null};for(let l=0;l<11;l+=1)for(let c=0;c<2;c+=1){let f=l*3+(3-c);E.push({x:u+(l+1)*m,y:g+(c+1)*p,radius:12,rank:0,target:{bet:"corner",numbers:[f,f-1,f+3,f+2]}})}for(let l=0;l<12;l+=1)for(let c=0;c<2;c+=1){let f=l*3+(3-c),M=S(f);M&&E.push({x:M.x,y:g+(c+1)*p,radius:10,rank:1,target:{bet:"split",a:f,b:f-1}})}for(let l=0;l<11;l+=1)for(let c=0;c<3;c+=1){let f=l*3+(3-c);E.push({x:u+(l+1)*m,y:g+c*p+p/2,radius:10,rank:1,target:{bet:"split",a:f,b:f+3}})}for(let l=0;l<3;l+=1){let c=3-l;E.push({x:u,y:g+l*p+p/2,radius:10,rank:1,target:{bet:"split",a:0,b:c}})}return{width:e,height:n,cellW:m,cellH:p,zeroX:14,zeroW:s,gridX:u,gridY:g,gridW:i,columnX:u+i,dozensY:h,outsideY:v,outsideH:r,zones:y,hotspots:E}}function Me(e,n,t,s,a,r){let d=Math.min(r,s/2,a/2);e.beginPath(),e.moveTo(n+d,t),e.arcTo(n+s,t,n+s,t+a,d),e.arcTo(n+s,t+a,n,t+a,d),e.arcTo(n,t+a,n,t,d),e.arcTo(n,t,n+s,t,d),e.closePath()}function Ce(e,n){let t=e.clientWidth||800,s=e.clientHeight||540,a=window.devicePixelRatio||1;(e.width!==Math.round(t*a)||e.height!==Math.round(s*a))&&(e.width=Math.round(t*a),e.height=Math.round(s*a));let r=e.getContext("2d"),d=nt(t,s);if(!r)return d;r.setTransform(a,0,0,a,0,0),r.clearRect(0,0,t,s),r.fillStyle=Je,Me(r,0,0,t,s,10),r.fill();for(let i of d.zones){let m=Ze;i.kind==="number"?m=i.number===0?Ee:tt(i.number)==="red"?Ke:Ue:i.kind==="zero"&&(m=Ee),r.fillStyle=m,r.strokeStyle=qe,r.lineWidth=1,Me(r,i.x+1,i.y+1,i.w-2,i.h-2,3),r.fill(),r.stroke(),r.fillStyle=Qe,r.textAlign="center",r.textBaseline="middle",i.kind==="number"||i.kind==="zero"?r.font=`700 ${Math.min(24,d.cellH*.3)}px ui-monospace, monospace`:r.font=`600 ${Math.min(12,d.outsideH*.4)}px ui-monospace, monospace`,r.fillText(i.label,i.x+i.w/2,i.y+i.h/2)}return st(r,d,n),d}function Se(e){return JSON.stringify(e)}function ot(e,n){let t=Se(n),s=e.zones.find(a=>Se(a.target)===t);if(s)return{x:s.x+s.w/2,y:s.y+s.h/2};if(n?.bet==="split"||n?.bet==="corner"){let a=n.bet==="split"?[n.a,n.b]:n.numbers,r=e.zones.filter(d=>(d.kind==="number"||d.kind==="zero")&&a.includes(d.number));if(r.length>0)return{x:r.reduce((d,i)=>d+i.x+i.w/2,0)/r.length,y:r.reduce((d,i)=>d+i.y+i.h/2,0)/r.length}}return null}function st(e,n,t){let s=t.bets?.chips??[];for(let a of s){let r=ot(n,a.target);if(!r)continue;let d=Math.max(12,Math.min(18,n.cellW*.26));e.beginPath(),e.arc(r.x,r.y,d,0,Math.PI*2),e.fillStyle=et,e.fill(),e.strokeStyle="#7a5a12",e.lineWidth=2,e.stroke(),e.fillStyle="#221a05",e.textAlign="center",e.textBaseline="middle",e.font=`700 ${d>15?11:10}px ui-monospace, monospace`,e.fillText(String(a.amount),r.x,r.y+.5)}}function Ne(e,n,t,s){H(e),H(n);let a=t.phase==="spinning";e.append(o("h2",void 0,"Roulette")),e.append(o("p","note","European single-zero wheel. Click a number, line or corner to add a chip; right-click takes one back."));let r=o("div","roulette-wrap"),d=o("canvas","roulette-canvas");if(r.append(d),t.phase==="result"&&t.number!==null&&t.number!==void 0){let l=o("div",`wheel-result ${t.color??""}`);l.append(o("div","label","Result")),l.append(o("div","num",String(t.number)));let c=Number(t.winnings??0);l.append(o("div","note",c>0?`Won ${L(c)}`:"No win")),r.append(l)}e.append(r);let m=Ce(d,t),p=(l,c)=>{let f=d.getBoundingClientRect(),M=l-f.left,N=c-f.top,b=null;for(let T of m.hotspots){let C=Math.hypot(M-T.x,N-T.y);C>T.radius||(!b||T.rank<b.rank||T.rank===b.rank&&C<Math.hypot(M-b.x,N-b.y))&&(b=T)}if(b)return{x:b.x-b.radius,y:b.y-b.radius,w:b.radius*2,h:b.radius*2,target:b.target,label:"",kind:"number"};for(let T=m.zones.length-1;T>=0;T-=1){let C=m.zones[T];if(M>=C.x&&M<=C.x+C.w&&N>=C.y&&N<=C.y+C.h)return C}return null};d.addEventListener("click",l=>{if(a)return;let c=p(l.clientX,l.clientY);c&&s({PlaceBetAt:c.target})}),d.addEventListener("contextmenu",l=>{if(l.preventDefault(),a)return;let c=p(l.clientX,l.clientY);c&&s({RemoveBetAt:c.target})}),d.addEventListener("mousemove",l=>{let c=p(l.clientX,l.clientY);d.style.cursor=c&&!a?"pointer":"default"}),new ResizeObserver(()=>{m=Ce(d,t)}).observe(d),n.append(o("div","label","Roulette")),n.append(o("p","note","Chips sit on the felt. The total is reserved when you spin.")),n.append(o("div","label","Chip"));let u=o("div","chip-row");for(let l of[10,25,50,100,500]){let c=o("button",`chip-btn ${Number(t.chip)===l?"active":""}`,String(l));c.disabled=a,c.addEventListener("click",()=>s({SetChip:l})),u.append(c)}n.append(u);let g=(t.bets?.chips??[]).reduce((l,c)=>l+Number(c.amount??0),0),h=o("div","stat");if(h.append(o("span","muted","On the felt"),o("strong","mono",L(g))),n.append(h),t.balance!==null&&t.balance!==void 0){let l=o("div","stat");l.append(o("span","muted","Balance"),o("strong","mono",L(Number(t.balance)))),n.append(l)}t.error&&n.append(o("p","error-text",String(t.error)));let v=o("p","note");if(a)v.textContent="Spinning…";else if(t.phase==="result"){let l=Number(t.winnings??0);v.textContent=`${t.number} ${t.color} · ${l>0?`won ${L(l)}`:"no win"}`,v.className=l>0?"note win-text":"note"}else v.textContent=g>0?"Ready to spin.":"Place at least one chip.";n.append(v);let y=o("div","actions"),w=o("button","btn primary wide big",a?"SPINNING…":"SPIN WHEEL");w.disabled=a||g===0,w.addEventListener("click",()=>s("Spin"));let E=o("button","btn wide","Clear bets");E.disabled=a||g===0,E.addEventListener("click",()=>s("ClearBets"));let S=o("button","btn ghost wide","Leave table");S.disabled=a,S.addEventListener("click",()=>{a||s("Leave")}),y.append(w,E,S),n.append(y)}var Q=5,ee=3,D="CLOGDS",rt=["top","middle","bottom","V","inverted V"],oe=0,I,te=null,ne=null;function at(){oe=Date.now()+900}function it(e){return e.phase==="spinning"||Date.now()<oe}function se(e,n,t,s){te=t,ne=e,I!==void 0&&(window.clearInterval(I),I=void 0);let a=it(t);H(e),H(n);let r=o("h2",void 0,"Slots"),d=o("p","note","Match three or more symbols from the left. Five paylines.");e.append(r,d);let i=o("div","reels"),m=[],p=String(t.reels??"");for(let c=0;c<Q;c+=1){let f=o("div","reel");for(let M=0;M<ee;M+=1){let N=c*ee+M,b=a?D[(N*3+Math.floor(Date.now()/70))%D.length]:p.length===Q*ee?p[N]:p.length===Q?p[c]:D[(N*5+c)%D.length],T=o("div","tile",b);T.classList.add(`sym-${b}`),a&&T.classList.add("spinning"),!a&&(t.win_cells??[]).includes(N)&&T.classList.add("win"),m.push(T),f.append(T)}i.append(f)}e.append(i);let u=o("div","win-lines");if(!a&&t.phase==="result"){let c=Number(t.winnings??0);if(c>0){let f=(t.win_lines??[]).map(M=>`${M} (${rt[M-1]??"line"})`).join(" · ");u.textContent=`${t.win_type==="mega"?"MEGA WIN":t.win_type==="big"?"BIG WIN":"WIN"} ${L(c)}${f?` · ${f}`:""}`,u.classList.add("win-text")}else u.textContent="No win — spin again."}else a?u.textContent="Spinning…":u.textContent="Pick a bet and spin.";if(e.append(u),a){let c=0;I=window.setInterval(()=>{c+=1;for(let f=0;f<m.length;f+=1){let M=D[(f*3+c)%D.length];m[f].textContent=M,m[f].className=`tile spinning sym-${M}`}Date.now()>=oe&&te&&ne&&(window.clearInterval(I),I=void 0,se(ne,n,te,s))},70)}n.append(o("div","label","Slots")),n.append(o("p","note","5 reels × 3 rows, 5 paylines."));let g=o("div","row"),h=o("button","btn small","−10"),v=o("strong","mono",L(Number(t.bet??0))),y=o("button","btn small","+10");h.disabled=a,y.disabled=a,h.addEventListener("click",()=>s({AdjustBet:-10})),y.addEventListener("click",()=>s({AdjustBet:10})),g.append(h,v,y),n.append(o("div","label","Bet"),g),t.error&&n.append(o("p","error-text",String(t.error)));let w=o("p","note");if(a)w.textContent="Spinning…";else if(t.phase==="result"){let c=Number(t.winnings??0);w.textContent=c>0?`Won ${L(c)}`:"No win this spin.",c>0&&w.classList.add("win-text")}else w.textContent="Ready when you are.";n.append(w);let E=o("div","actions"),S=o("button","btn primary wide big",a?"SPINNING…":"SPIN");S.disabled=a,S.addEventListener("click",()=>{at(),s("Spin")});let l=o("button","btn ghost wide","Leave machine");l.disabled=a,l.addEventListener("click",()=>s("Leave")),E.append(S,l),n.append(E)}var lt=k("auth-screen"),ct=k("lobby-screen"),dt=k("game-screen"),ut=k("history-screen"),He=k("session-bar"),pt=k("account-name"),mt=k("account-balance"),re=k("game-grid"),X=k("game-board"),G=k("game-side"),ht=k("game-title"),$e=k("game-badge"),ft=k("history-body"),bt=k("auth-form"),Ae=k("auth-user"),U=k("auth-pass"),F=k("auth-error"),A=k("auth-submit"),Pe=k("tab-login"),We=k("tab-register"),K=k("reconnect-overlay"),Be=k("reconnect-message"),Re=k("replaced-overlay"),x=null,$=null,ce=null,_="login",ae=null,De=0,ie=0,le=new Map([["slots",10],["roulette",10],["blackjack",10],["crash",10]]),Ie={slots:"Slots",roulette:"Roulette",blackjack:"Blackjack",crash:"Crash"},gt={slots:"Five reels, five paylines. Match symbols from the left.",roulette:"European single-zero wheel with inside and outside bets.",blackjack:"Six-deck shoe. Blackjack pays 3:2.",crash:"A rising multiplier. Cash out before it crashes."},yt=location.pathname.includes("/play/")?location.pathname.slice(0,location.pathname.indexOf("/play/")):"",kt=`${location.protocol==="https:"?"wss":"ws"}://${location.host}${yt}/ws`,Z=new j(kt,{onHello(e){De=e.time-Date.now(),$=e.user??null,$e.textContent=`v${e.version}`},onView(e){x=e,typeof e.balance=="number"&&(ce=e.balance),e.screen==="lobby"&&"user"in e&&($=e.user??null,$?U.value="":ce=null),ie=0,K.hidden=!0,Fe(),$&&x.balance===null&&ae!==$&&(ae=$,Z.send("Info")),$||(ae=null)},onNotice(e){e.startsWith("Connected to:")||e.startsWith("Fingerprint:")||e.startsWith("User:")||e.startsWith("Account:")||e.startsWith("Balance:")||(J(e,he(e)),e.startsWith("Account created")&&(de("login"),U.value="",Ae.focus()),A.disabled=!1,A.textContent=_==="login"?"Log in":"Create account")},onError(e){J(e,"bad"),A.disabled=!1,A.textContent=_==="login"?"Log in":"Create account"},onReplaced(){Re.hidden=!1},onPong(){},onOpen(){K.hidden=!0},onClosed(e){if(Re.hidden!==!1){if(!e){Be.textContent="The connection could not be restored. Reload the page to try again.",K.hidden=!1;return}ie+=1,Be.textContent=ie>1?"Still trying to reach the game server…":"Trying to reach the game server…",K.hidden=!1}}});function B(e){Z.send(e)}function Lt(){return Date.now()+De}function de(e){_=e,Pe.classList.toggle("active",e==="login"),We.classList.toggle("active",e==="register"),A.textContent=e==="login"?"Log in":"Create account",U.autocomplete=e==="login"?"current-password":"new-password",F.textContent=""}function V(e){lt.hidden=e!=="auth",ct.hidden=e!=="lobby",dt.hidden=e!=="game",ut.hidden=e!=="history"}function xt(e){mt.textContent=L(e??null)}function Fe(){if(!x)return;let e=$;if(e?(He.hidden=!1,pt.textContent=String(e)):He.hidden=!0,xt(ce),!e){V("auth"),F.textContent=x.login_error?String(x.login_error):"",x.screen==="lobby"&&x.connected===!1&&(F.textContent="The game server is not reachable yet. Retrying…");return}switch(x.screen){case"lobby":V("lobby"),wt(x);break;case"history":V("history"),Te(ft,x);break;case"slots":case"roulette":case"blackjack":case"crash":V("game"),ht.textContent=Ie[x.screen]??x.screen,$e.textContent=vt(x),x.screen==="slots"?se(X,G,x,B):x.screen==="roulette"?Ne(X,G,x,B):x.screen==="blackjack"?ke(X,G,x,B):we(X,G,x,B,{now:Lt});break;default:V("auth")}}function vt(e){return e.screen==="crash"||e.screen==="blackjack"?String(e.status??""):e.screen==="slots"||e.screen==="roulette"?String(e.phase??""):""}function wt(e){re.replaceChildren();let n=e.games??[];for(let[t,s]of n){let a=o("article",`game-card ${t}`);a.append(o("h3",void 0,s||Ie[t]||t)),a.append(o("p",void 0,gt[t]??"Play a round."));let r=o("div","row wrap"),d=o("label","field");d.style.flex="1",d.append(o("span","label","Bet"));let i=o("input","input bet-input");i.type="number",i.min="1",i.step="10",i.value=String(le.get(t)??10),i.addEventListener("change",()=>{let p=Math.max(1,Math.floor(Number(i.value)||1));i.value=String(p),le.set(t,p)}),d.append(i);let m=o("button","btn primary",t==="roulette"?"Open table":"Play");m.addEventListener("click",()=>{let p=Math.max(1,Math.floor(Number(i.value)||1));le.set(t,p),B({Play:{game:t,bet:p}})}),r.append(d,m),a.append(r),re.append(a)}n.length===0&&re.append(o("p","muted","The server did not advertise any games."))}Pe.addEventListener("click",()=>de("login"));We.addEventListener("click",()=>de("register"));bt.addEventListener("submit",async e=>{e.preventDefault();let n=Ae.value.trim(),t=U.value;if(!n||!t){F.textContent="Enter a username and a password.";return}A.disabled=!0,A.textContent="Working…",F.textContent="";try{let s=await fe(t);B(_==="login"?{Login:{user:n,credential:s}}:{Register:{user:n,credential:s}})}catch{F.textContent="This browser cannot hash the password (needs a secure context).",A.disabled=!1,A.textContent=_==="login"?"Log in":"Create account"}});k("logout").addEventListener("click",()=>B("Logout"));k("show-history").addEventListener("click",()=>B({History:{limit:50}}));k("refresh-lobby").addEventListener("click",()=>B("Info"));k("history-back").addEventListener("click",()=>B("ShowLobby"));k("leave-game").addEventListener("click",()=>{!x||(x.screen==="blackjack"&&x.status==="player"||x.screen==="crash"&&x.status==="running")&&!window.confirm("Leaving now forfeits the active bet. Continue?")||B("Leave")});k("reload-replaced").addEventListener("click",()=>location.reload());k("reload-reconnect").addEventListener("click",()=>location.reload());window.addEventListener("resize",()=>{window.clearTimeout(window.__resizeTimer),window.__resizeTimer=window.setTimeout(()=>{x&&Fe()},140)});window.setInterval(()=>{$&&Z.ping()},25e3);Z.connect();})(); | "use strict";(()=>{function k(e){let n=document.getElementById(e);if(!n)throw new Error(`missing #${e}`);return n}function o(e,n,t){let s=document.createElement(e);return n&&(s.className=n),t!==void 0&&(s.textContent=t),s}function H(e){e.replaceChildren()}function Ke(e){let n=e<0,t=String(Math.abs(Math.trunc(e))),s="";for(let a=0;a<t.length;a+=1)a>0&&(t.length-a)%3===0&&(s+=" "),s+=t[a];return n?`-${s}`:s}function L(e){return e==null||Number.isNaN(e)?"— Kr":`${Ke(e)} Kr`}function he(e){return`${e<0?"-":"+"}${L(Math.abs(e))}`}function ee(e,n="info"){let t=document.getElementById("toasts");if(!t||!e)return;let s=o("div",`toast ${n}`,e);for(t.append(s),window.setTimeout(()=>{s.style.opacity="0",s.style.transition="opacity 220ms ease",window.setTimeout(()=>s.remove(),240)},4200);t.children.length>4;)t.firstElementChild?.remove()}function be(e){let n=e.toLowerCase();return e.startsWith("ERROR")||n.includes("failed")||n.includes("lost")||n.includes("invalid")||n.includes("forfeit")?"bad":e.startsWith("Logged in")||e.startsWith("Account created")||n.includes("won")||n.includes("cashed")?"good":"info"}async function ge(e){let n=new TextEncoder().encode(e),t=await crypto.subtle.digest("SHA-256",n);return[...new Uint8Array(t)].map(s=>s.toString(16).padStart(2,"0")).join("")}function z(e,n=10){return e.length<=n*2?e:`${e.slice(0,n)}…${e.slice(-n)}`}function ye(e){let n=Date.parse(e.includes("T")?e:e.replace(" ","T")+"Z");return Number.isNaN(n)?e:new Date(n).toLocaleString()}function ke(e){if(e==="?"||!e)return{rank:"?",suit:"",red:!1};let n=e.slice(-1);return{rank:e.slice(0,-1),suit:n==="C"?"♣":n==="D"?"♦":n==="H"?"♥":n==="S"?"♠":n,red:n==="D"||n==="H"}}var j=class{constructor(n,t){this.url=n;this.handlers=t;this.socket=null;this.stopped=!1;this.replaced=!1;this.attempts=0}connect(){if(this.stopped)return;this.clearTimer();let n;try{n=new WebSocket(this.url)}catch{this.scheduleReconnect()||this.handlers.onClosed(!1);return}this.socket=n,n.addEventListener("open",()=>{this.attempts=0,this.handlers.onOpen()}),n.addEventListener("message",t=>{let s;try{s=JSON.parse(String(t.data))}catch{return}switch(s.type){case"hello":this.handlers.onHello(s);break;case"view":this.handlers.onView(s.view);break;case"notice":this.handlers.onNotice(String(s.text??""));break;case"error":this.handlers.onError(String(s.text??""));break;case"replaced":this.replaced=!0,this.handlers.onReplaced();break;case"pong":this.handlers.onPong();break}}),n.addEventListener("close",()=>{if(this.socket===n&&(this.socket=null),this.replaced||this.stopped){this.handlers.onClosed(!1);return}let s=this.scheduleReconnect();this.handlers.onClosed(s)}),n.addEventListener("error",()=>{})}send(n){this.socket?.readyState===WebSocket.OPEN&&this.socket.send(JSON.stringify({type:"command",command:n}))}ping(){this.socket?.readyState===WebSocket.OPEN&&this.socket.send(JSON.stringify({type:"ping"}))}close(){this.stopped=!0,this.clearTimer(),this.socket?.close()}scheduleReconnect(){if(this.stopped||this.replaced||this.attempts>=6)return!1;this.attempts+=1;let n=Math.min(250*2**(this.attempts-1),4e3);return this.timer=window.setTimeout(()=>this.connect(),n),!0}clearTimer(){this.timer!==void 0&&(window.clearTimeout(this.timer),this.timer=void 0)}};var Le=0;function te(){return Date.now()-Le<400?!1:(Le=Date.now(),!0)}function Ue(e){if(e==="?"){let s=o("div","card back");return s.append(o("span","rank","?"),o("span","suit","")),s}let n=ke(e),t=o("div","card");return n.red&&t.classList.add("red"),t.append(o("span","rank",n.rank),o("span","suit",n.suit)),t}function xe(e,n,t){let s=o("div","hand");s.append(o("div","label",e));let a=o("div","cards");for(let d of n)a.append(Ue(d));let r=o("div","total");return r.append(document.createTextNode("Total "),o("strong",void 0,String(t))),s.append(a,r),s}function Ze(e,n){let t=String(n?.result??""),s=Number(n?.winnings??0);switch(t){case"blackjack":return`Blackjack — won ${L(s)}`;case"win":return`You win — ${L(s)}`;case"push":return`Push — ${L(s)} returned`;case"bust":return"Bust — the bet is lost";case"lose":return"Dealer wins — the bet is lost";case"forfeit":return"Hand forfeited — the bet is lost";case"playing":return e.status==="player"?"Your move.":"Dealing…";default:return"Ready to deal."}}function we(e,n,t,s){H(e),H(n);let a=t.hand,r=a?.phase==="player"||t.status==="player",d=a?.phase==="done"||t.status==="done",i=!a||d;if(e.append(o("h2",void 0,"Blackjack")),e.append(o("p","note","Six decks. Dealer stands on all 17. Blackjack pays 3:2.")),a)e.append(xe("Dealer",a.dealer??[],Number(a.dealer_total??0))),e.append(xe("You",a.player??[],Number(a.player_total??0)));else{let f=o("div","outcome");f.textContent="Press DEAL to start a hand.",e.append(f)}if(d||a&&!r){let f=o("div","outcome");f.textContent=Ze(t,a),(String(a?.result)==="win"||String(a?.result)==="blackjack"||String(a?.result)==="push")&&f.classList.add("win-text"),e.append(f)}t.error&&e.append(o("p","error-text",String(t.error))),n.append(o("div","label","Blackjack"));let m=Number(a?.bet??t.bet??0),p=t.balance??t.hand?.balance;if(n.append(o("p","note","Hit, stand or double. Forfeiting loses the reserved bet.")),i){let f=o("div","row"),w=o("button","btn small","−10"),y=o("strong","mono",L(m)),v=o("button","btn small","+10");w.addEventListener("click",()=>s({AdjustBet:-10})),v.addEventListener("click",()=>s({AdjustBet:10})),f.append(w,y,v),n.append(o("div","label","Bet"),f)}else{let f=o("div","stat");f.append(o("span","muted","Bet"),o("strong",void 0,L(m))),n.append(f)}if(p!==void 0){let f=o("div","stat");f.append(o("span","muted","Balance"),o("strong",void 0,L(Number(p)))),n.append(f)}let u=o("div","actions");if(r){let f=o("div","row wrap");for(let y of a?.actions??[]){let v=y==="hit"?"HIT":y==="stand"?"STAND":"DOUBLE",E=y==="stand"?o("button","btn primary",v):o("button","btn",v);E.addEventListener("click",()=>{te()&&s(y==="hit"?"Hit":y==="stand"?"Stand":"Double")}),f.append(E)}u.append(f);let w=o("button","btn danger wide","Forfeit hand");w.addEventListener("click",()=>{te()&&window.confirm("Forfeit this hand? The reserved bet is lost.")&&s("Forfeit")}),u.append(w)}else if(i){let f=o("button","btn primary wide big","DEAL");f.addEventListener("click",()=>{te()&&s("Deal")}),u.append(f)}let g=o("button","btn ghost wide",r?"Leave (forfeits)":"Leave table");g.addEventListener("click",()=>{r&&!window.confirm("Leaving forfeits this hand. Continue?")||s("Leave")}),u.append(g),n.append(u)}var ne=Math.LN2/5,R=null,I=null,Me=null,W=null,$,ve=0,Y="",Te=0;function Je(e,n,t,s){H(e),H(n),W=t,Me=s,e.append(o("h2",void 0,"Crash")),e.append(o("p","note","The multiplier rises from 1.00×. Cash out before it crashes."));let a=o("div","crash-wrap"),r=o("div","crash-number","1.00×"),d=o("div","crash-meta"),i=o("canvas","crash-canvas"),m=o("div","verify","Waiting for a round commitment.");a.append(r,d,i,m),e.append(a),n.append(o("div","label","Crash")),n.append(o("p","note","The server commits to a seed before the round. The seed is revealed when it ends."));let p=o("div","row"),u=o("button","btn small","−10"),g=o("strong","mono","—"),f=o("button","btn small","+10");u.addEventListener("click",()=>W?.({AdjustBet:-10})),f.addEventListener("click",()=>W?.({AdjustBet:10})),p.append(u,g,f),n.append(o("div","label","Bet"),p);let w=o("strong","mono","—"),y=o("strong","mono","—");for(let[M,N]of[["Potential",w],["Balance",y]]){let b=o("div","stat");b.append(o("span","muted",M),N),n.append(b)}let v=o("p","note","Ready."),E=o("p","note",""),S=o("p","error-text");n.append(v,E,S);let l=o("div","actions"),c=o("button","btn primary wide big","START"),h=o("button","btn ghost wide","Leave table");return c.addEventListener("click",()=>{Date.now()-Te<500||(Te=Date.now(),I?.status==="running"?W?.("CashOut"):W?.("Start"))}),h.addEventListener("click",()=>{I?.status==="running"&&!window.confirm("Forfeit this round? The bet is lost.")||W?.("Leave")}),l.append(c,h),n.append(l),{board:e,side:n,number:r,meta:d,verify:m,canvas:i,bet:g,potential:w,balance:y,status:v,lastCrash:E,error:S,primary:c,leave:h,minus:u,plus:f}}function Ce(){$!==void 0&&(cancelAnimationFrame($),$=void 0),I=null}function Se(e,n,t,s,a){(!R||R.board!==e||!R.canvas.isConnected)&&(R=Je(e,n,s,a),Y="");let r=R;W=s,Me=a,I=t,t.status!==Y&&((t.status==="starting"||t.status==="running")&&Y!=="running"&&(r.verify.className="verify",r.verify.textContent="Round committed; seed hidden until the round ends."),Y=String(t.status));let d=t.status==="running",i=t.status==="starting",m=d||i;r.bet.textContent=L(Number(t.bet??0)),r.potential.textContent=L(Number(t.potential??t.bet??0)),r.balance.textContent=t.balance===null||t.balance===void 0?"—":L(Number(t.balance)),r.error.textContent=t.error?String(t.error):"",r.minus.disabled=m,r.plus.disabled=m,r.primary.textContent=d?"CASH OUT":i?"STARTING…":"START",r.primary.disabled=i,r.primary.className="btn primary wide big",r.leave.textContent=d?"Forfeit round":"Leave table",d?(r.status.textContent="Rising — cash out before the crash.",r.status.className="note win-text"):i?(r.status.textContent="Starting the round…",r.status.className="note"):t.status==="cashed"?(r.status.textContent=`Cashed out at ${Number(t.multiplier??0).toFixed(2)}× for ${L(Number(t.payout??0))}.`,r.status.className="note win-text"):t.status==="crashed"?(r.status.textContent=`Crashed at ${Number(t.crash_point??t.multiplier??0).toFixed(2)}×. The bet is lost.`,r.status.className="note error-text"):t.status==="forfeit"?(r.status.textContent="Round forfeited.",r.status.className="note error-text"):(r.status.textContent="Ready. Start a round when you want.",r.status.className="note"),t.crash_point!==null&&t.crash_point!==void 0&&t.status==="crashed"&&(r.lastCrash.textContent=`Last crash: ${Number(t.crash_point).toFixed(2)}×`);let p=t.commit?String(t.commit):"";if(r.meta.textContent=p?`commit ${z(p,12)}`:"no commitment yet",t.seed&&p){let u=++ve,g=String(t.seed),f=Number(t.crash_point??0);et(g,p,f).then(([w,y])=>{if(u!==ve||!R)return;let v=w&&y;R.verify.className=`verify ${v?"ok":"bad"}`,R.verify.textContent=v?`Seed ${z(g,12)} · sha256 matches commit · crash point recomputed`:`VERIFICATION FAILED · seed ${z(g,12)} · commit ${z(p,12)}`})}else!m&&!p&&(r.verify.className="verify",r.verify.textContent="Waiting for a round commitment.");if($!==void 0&&(cancelAnimationFrame($),$=void 0),d){let u=()=>{if(!R||I?.status!=="running"){$=void 0;return}Ee(R,I,a),$=requestAnimationFrame(u)};$=requestAnimationFrame(u)}else Ee(r,t,a)}function qe(e,n){if(e.status==="running"){let t=Math.max(0,(n.now()-Number(e.started_at??0))/1e3),s=Math.min(1e3,Math.exp(ne*t));return Math.max(s,Number(e.multiplier??1))}return e.status==="cashed"?Number(e.multiplier??1):e.status==="crashed"?Number(e.crash_point??e.multiplier??1):1}function Ee(e,n,t){let s=qe(n,t);e.number.textContent=`${s.toFixed(2)}×`,e.number.className=`crash-number ${n.status==="running"?"running":n.status==="cashed"?"cashed":n.status==="crashed"?"crashed":""}`,e.potential.textContent=L(Math.floor(Number(n.bet??0)*s)),Qe(e.canvas,n,s,t)}function Qe(e,n,t,s){let a=e.clientWidth||600,r=e.clientHeight||360,d=window.devicePixelRatio||1;(e.width!==Math.round(a*d)||e.height!==Math.round(r*d))&&(e.width=Math.round(a*d),e.height=Math.round(r*d));let i=e.getContext("2d");if(!i)return;i.setTransform(d,0,0,d,0,0),i.clearRect(0,0,a,r);let m=54,p=16,u=18,g=34,f=Math.max(1,a-m-p),w=Math.max(1,r-u-g),y=n.status==="running"?Math.max(.25,(s.now()-Number(n.started_at??0))/1e3):t>1?Math.log(t)/ne:1,v=Math.max(5,y*1.08),E=Math.max(2,Math.ceil(t*1.15*2)/2),S=b=>m+b/v*f,l=b=>u+w-(b-1)/(E-1)*w;i.strokeStyle="#242e38",i.fillStyle="#8a98a6",i.font="11px ui-monospace, monospace",i.lineWidth=1;for(let b=0;b<=4;b+=1){let T=1+(E-1)*b/4,C=l(T);i.beginPath(),i.moveTo(m,C),i.lineTo(a-p,C),i.stroke(),i.fillText(`${T.toFixed(1)}×`,6,C+4)}for(let b=0;b<=4;b+=1){let T=v*b/4,C=S(T);i.beginPath(),i.moveTo(C,u),i.lineTo(C,u+w),i.strokeStyle="#1b232c",i.stroke(),i.fillStyle="#5b6773",i.fillText(`${T.toFixed(0)}s`,C-10,r-12)}let c=n.status==="crashed"?"#e05a5a":n.status==="cashed"?"#4ec27b":"#e0b64a";i.beginPath();let h=180;for(let b=0;b<=h;b+=1){let T=y*b/h,C=Math.min(E,Math.exp(ne*T)),me=S(T),fe=l(C);b===0?i.moveTo(me,fe):i.lineTo(me,fe)}i.strokeStyle=c,i.lineWidth=2.4,i.stroke();let M=S(y),N=l(Math.min(E,t));i.beginPath(),i.arc(M,N,4.5,0,Math.PI*2),i.fillStyle=c,i.fill(),i.fillStyle=c,i.font="600 12px ui-monospace, monospace",i.fillText(`${t.toFixed(2)}×`,Math.min(M+8,a-70),Math.max(u+12,N-10))}async function et(e,n,t){let s=new Uint8Array(e.length/2);for(let u=0;u<s.length;u+=1)s[u]=Number.parseInt(e.slice(u*2,u*2+2),16);let a=await crypto.subtle.digest("SHA-256",s),d=[...new Uint8Array(a)].map(u=>u.toString(16).padStart(2,"0")).join("")===n.toLowerCase(),i=0;for(let u=0;u<8;u+=1)i=i*256+s[u];i/=2**64;let m=Math.max(1,Math.min(1e3,(1-.01)/(1-i))),p=Math.abs(m-t)<1e-6;return[d,p]}function tt(e){let n=e.details??{};switch(e.game){case"slots":return String(n.win_type??"spin");case"roulette":return`${n.number??"?"} ${n.color??""}`.trim();case"blackjack":return String(n.result??"");case"crash":{let t=String(n.result??""),s=n.crash_point;return s==null?t:`${t} @ ${Number(s).toFixed(2)}×`}default:return""}}function Ne(e,n){H(e);let t=n.records??[];if(t.length===0){let m=o("div","board");m.append(o("h2",void 0,"No plays yet"),o("p","muted","Your settled plays will appear here.")),e.append(m);return}let s=o("div","table-wrap"),a=o("table"),r=o("thead"),d=o("tr");for(let m of["Time","Game","Bet","Result","Net","Balance"])d.append(o("th",void 0,m));r.append(d);let i=o("tbody");for(let m of t){let p=o("tr");p.append(o("td","mono",ye(String(m.at??"")))),p.append(o("td",void 0,String(m.game??""))),p.append(o("td","num",L(Number(m.bet??0)))),p.append(o("td","muted",tt(m)));let u=Number(m.winnings??0)-Number(m.bet??0),g=o("td",`num ${u>0?"pos":u<0?"neg":""}`,u===0?"0 Kr":he(u));p.append(g),p.append(o("td","num",L(Number(m.balance_after??0)))),i.append(p)}a.append(r,i),s.append(a),e.append(s)}var oe=null,He=0,nt="#b0313a",ot="#151b21",Be="#106b45",st="#0d5c39",rt="#09472c",at="#1f7d52",it="#ecf7f0",lt="#e0b64a";function ct(e){return e===0?"green":[1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36].includes(e)?"red":"black"}function dt(e,n){let s=Math.max(38,e*.055),a=Math.max(34,e*.05),r=Math.max(30,n*.07),d=6,i=e-28-s-a,m=i/12,p=(n-28-r*2-d*2)/3,u=14+s,g=14,f=g+p*3+d,w=f+r+d,y=[];for(let l=0;l<12;l+=1)for(let c=0;c<3;c+=1){let h=l*3+(3-c);y.push({x:u+l*m,y:g+c*p,w:m,h:p,target:{bet:"straight",number:h},label:String(h),kind:"number",number:h})}y.push({x:14,y:g,w:s,h:p*3,target:{bet:"straight",number:0},label:"0",kind:"zero",number:0});for(let l=0;l<3;l+=1){let c=2-l;y.push({x:u+i,y:g+l*p,w:a,h:p,target:{bet:"column",index:c},label:"2:1",kind:"column"})}for(let l=0;l<3;l+=1)y.push({x:u+i/3*l,y:f,w:i/3,h:r,target:{bet:"dozen",index:l},label:["1st 12","2nd 12","3rd 12"][l],kind:"dozen"});[{kind:"low",label:"1–18"},{kind:"even",label:"EVEN"},{kind:"red",label:"RED"},{kind:"black",label:"BLACK"},{kind:"odd",label:"ODD"},{kind:"high",label:"19–36"}].forEach((l,c)=>{y.push({x:u+i/6*c,y:w,w:i/6,h:r,target:{bet:"outside",kind:l.kind},label:l.label,kind:"outside"})});let E=[],S=l=>{let c=y.find(h=>h.kind==="number"&&h.number===l);return c?{x:c.x+c.w/2,y:c.y+c.h/2}:null};for(let l=0;l<11;l+=1)for(let c=0;c<2;c+=1){let h=l*3+(3-c);E.push({x:u+(l+1)*m,y:g+(c+1)*p,radius:12,rank:0,target:{bet:"corner",numbers:[h,h-1,h+3,h+2]}})}for(let l=0;l<12;l+=1)for(let c=0;c<2;c+=1){let h=l*3+(3-c),M=S(h);M&&E.push({x:M.x,y:g+(c+1)*p,radius:10,rank:1,target:{bet:"split",a:h,b:h-1}})}for(let l=0;l<11;l+=1)for(let c=0;c<3;c+=1){let h=l*3+(3-c);E.push({x:u+(l+1)*m,y:g+c*p+p/2,radius:10,rank:1,target:{bet:"split",a:h,b:h+3}})}for(let l=0;l<3;l+=1){let c=3-l;E.push({x:u,y:g+l*p+p/2,radius:10,rank:1,target:{bet:"split",a:0,b:c}})}return{width:e,height:n,cellW:m,cellH:p,zeroX:14,zeroW:s,gridX:u,gridY:g,gridW:i,columnX:u+i,dozensY:f,outsideY:w,outsideH:r,zones:y,hotspots:E}}function Re(e,n,t,s,a,r){let d=Math.min(r,s/2,a/2);e.beginPath(),e.moveTo(n+d,t),e.arcTo(n+s,t,n+s,t+a,d),e.arcTo(n+s,t+a,n,t+a,d),e.arcTo(n,t+a,n,t,d),e.arcTo(n,t,n+s,t,d),e.closePath()}function $e(e,n){let t=e.clientWidth||800,s=e.clientHeight||540,a=window.devicePixelRatio||1;(e.width!==Math.round(t*a)||e.height!==Math.round(s*a))&&(e.width=Math.round(t*a),e.height=Math.round(s*a));let r=e.getContext("2d"),d=dt(t,s);if(!r)return d;r.setTransform(a,0,0,a,0,0),r.clearRect(0,0,t,s),r.fillStyle=rt,Re(r,0,0,t,s,10),r.fill();for(let i of d.zones){let m=st;i.kind==="number"?m=i.number===0?Be:ct(i.number)==="red"?nt:ot:i.kind==="zero"&&(m=Be),r.fillStyle=m,r.strokeStyle=at,r.lineWidth=1,Re(r,i.x+1,i.y+1,i.w-2,i.h-2,3),r.fill(),r.stroke(),r.fillStyle=it,r.textAlign="center",r.textBaseline="middle",i.kind==="number"||i.kind==="zero"?r.font=`700 ${Math.min(24,d.cellH*.3)}px ui-monospace, monospace`:r.font=`600 ${Math.min(12,d.outsideH*.4)}px ui-monospace, monospace`,r.fillText(i.label,i.x+i.w/2,i.y+i.h/2)}return pt(r,d,n),d}function Ae(e){return JSON.stringify(e)}function ut(e,n){let t=Ae(n),s=e.zones.find(a=>Ae(a.target)===t);if(s)return{x:s.x+s.w/2,y:s.y+s.h/2};if(n?.bet==="split"||n?.bet==="corner"){let a=n.bet==="split"?[n.a,n.b]:n.numbers,r=e.zones.filter(d=>(d.kind==="number"||d.kind==="zero")&&a.includes(d.number));if(r.length>0)return{x:r.reduce((d,i)=>d+i.x+i.w/2,0)/r.length,y:r.reduce((d,i)=>d+i.y+i.h/2,0)/r.length}}return null}function pt(e,n,t){let s=t.bets?.chips??[];for(let a of s){let r=ut(n,a.target);if(!r)continue;let d=Math.max(12,Math.min(18,n.cellW*.26));e.beginPath(),e.arc(r.x,r.y,d,0,Math.PI*2),e.fillStyle=lt,e.fill(),e.strokeStyle="#7a5a12",e.lineWidth=2,e.stroke(),e.fillStyle="#221a05",e.textAlign="center",e.textBaseline="middle",e.font=`700 ${d>15?11:10}px ui-monospace, monospace`,e.fillText(String(a.amount),r.x,r.y+.5)}}function De(e,n,t,s){H(e),H(n);let a=t.phase==="spinning";e.append(o("h2",void 0,"Roulette")),e.append(o("p","note","European single-zero wheel. Click a number, line or corner to add a chip; right-click takes one back."));let r=o("div","roulette-wrap"),d=o("canvas","roulette-canvas");if(r.append(d),t.phase==="result"&&t.number!==null&&t.number!==void 0){let l=o("div",`wheel-result ${t.color??""}`);l.append(o("div","label","Result")),l.append(o("div","num",String(t.number)));let c=Number(t.winnings??0);l.append(o("div","note",c>0?`Won ${L(c)}`:"No win")),r.append(l)}e.append(r);let m=$e(d,t),p=(l,c)=>{let h=d.getBoundingClientRect(),M=l-h.left,N=c-h.top,b=null;for(let T of m.hotspots){let C=Math.hypot(M-T.x,N-T.y);C>T.radius||(!b||T.rank<b.rank||T.rank===b.rank&&C<Math.hypot(M-b.x,N-b.y))&&(b=T)}if(b)return{x:b.x-b.radius,y:b.y-b.radius,w:b.radius*2,h:b.radius*2,target:b.target,label:"",kind:"number"};for(let T=m.zones.length-1;T>=0;T-=1){let C=m.zones[T];if(M>=C.x&&M<=C.x+C.w&&N>=C.y&&N<=C.y+C.h)return C}return null};d.addEventListener("click",l=>{if(a)return;let c=p(l.clientX,l.clientY);c&&s({PlaceBetAt:c.target})}),d.addEventListener("contextmenu",l=>{if(l.preventDefault(),a)return;let c=p(l.clientX,l.clientY);c&&s({RemoveBetAt:c.target})}),d.addEventListener("mousemove",l=>{let c=p(l.clientX,l.clientY);d.style.cursor=c&&!a?"pointer":"default"}),oe?.disconnect(),oe=new ResizeObserver(()=>{m=$e(d,t)}),oe.observe(d),n.append(o("div","label","Roulette")),n.append(o("p","note","Chips sit on the felt. The total is reserved when you spin.")),n.append(o("div","label","Chip"));let u=o("div","chip-row");for(let l of[10,25,50,100,500]){let c=o("button",`chip-btn ${Number(t.chip)===l?"active":""}`,String(l));c.disabled=a,c.addEventListener("click",()=>s({SetChip:l})),u.append(c)}n.append(u);let g=(t.bets?.chips??[]).reduce((l,c)=>l+Number(c.amount??0),0),f=o("div","stat");if(f.append(o("span","muted","On the felt"),o("strong","mono",L(g))),n.append(f),t.balance!==null&&t.balance!==void 0){let l=o("div","stat");l.append(o("span","muted","Balance"),o("strong","mono",L(Number(t.balance)))),n.append(l)}t.error&&n.append(o("p","error-text",String(t.error)));let w=o("p","note");if(a)w.textContent="Spinning…";else if(t.phase==="result"){let l=Number(t.winnings??0);w.textContent=`${t.number} ${t.color} · ${l>0?`won ${L(l)}`:"no win"}`,w.className=l>0?"note win-text":"note"}else w.textContent=g>0?"Ready to spin.":"Place at least one chip.";n.append(w);let y=o("div","actions"),v=o("button","btn primary wide big",a?"SPINNING…":"SPIN WHEEL");v.disabled=a||g===0,v.addEventListener("click",()=>{Date.now()-He<600||(He=Date.now(),s("Spin"))});let E=o("button","btn wide","Clear bets");E.disabled=a||g===0,E.addEventListener("click",()=>s("ClearBets"));let S=o("button","btn ghost wide","Leave table");S.disabled=a,S.addEventListener("click",()=>{a||s("Leave")}),y.append(v,E,S),n.append(y)}var se=5,re=3,F="CLOGDS",mt=["top","middle","bottom","V","inverted V"],K=0,Pe=0,A,X=null,G=null;function ft(){K=Date.now()+900}function We(){A!==void 0&&(window.clearInterval(A),A=void 0),X=null,G=null,K=0}function ht(e){return e.phase==="spinning"||Date.now()<K}function ae(e,n,t,s){X=t,G=e,A!==void 0&&(window.clearInterval(A),A=void 0);let a=ht(t);H(e),H(n);let r=o("h2",void 0,"Slots"),d=o("p","note","Match three or more symbols from the left. Five paylines.");e.append(r,d);let i=o("div","reels"),m=[],p=Array.isArray(t.reels)?t.reels.join(""):String(t.reels??"");for(let c=0;c<se;c+=1){let h=o("div","reel");for(let M=0;M<re;M+=1){let N=c*re+M,b=a?F[(N*3+Math.floor(Date.now()/70))%F.length]:p.length===se*re?p[N]:p.length===se?p[c]:F[(N*5+c)%F.length],T=o("div","tile",b);T.classList.add(`sym-${b}`),a&&T.classList.add("spinning"),!a&&(t.win_cells??[]).includes(N)&&T.classList.add("win"),m.push(T),h.append(T)}i.append(h)}e.append(i);let u=o("div","win-lines");if(!a&&t.phase==="result"){let c=Number(t.winnings??0);if(c>0){let h=(t.win_lines??[]).map(M=>`${M} (${mt[M-1]??"line"})`).join(" · ");u.textContent=`${t.win_type==="mega"?"MEGA WIN":t.win_type==="big"?"BIG WIN":"WIN"} ${L(c)}${h?` · ${h}`:""}`,u.classList.add("win-text")}else u.textContent="No win — spin again."}else a?u.textContent="Spinning…":u.textContent="Pick a bet and spin.";if(e.append(u),a){let c=0;A=window.setInterval(()=>{c+=1;for(let h=0;h<m.length;h+=1){let M=F[(h*3+c)%F.length];m[h].textContent=M,m[h].className=`tile spinning sym-${M}`}Date.now()>=K&&X&&G&&(window.clearInterval(A),A=void 0,ae(G,n,X,s))},70)}n.append(o("div","label","Slots")),n.append(o("p","note","5 reels × 3 rows, 5 paylines."));let g=o("div","row"),f=o("button","btn small","−10"),w=o("strong","mono",L(Number(t.bet??0))),y=o("button","btn small","+10");f.disabled=a,y.disabled=a,f.addEventListener("click",()=>s({AdjustBet:-10})),y.addEventListener("click",()=>s({AdjustBet:10})),g.append(f,w,y),n.append(o("div","label","Bet"),g),t.error&&n.append(o("p","error-text",String(t.error)));let v=o("p","note");if(a)v.textContent="Spinning…";else if(t.phase==="result"){let c=Number(t.winnings??0);v.textContent=c>0?`Won ${L(c)}`:"No win this spin.",c>0&&v.classList.add("win-text")}else v.textContent="Ready when you are.";n.append(v);let E=o("div","actions"),S=o("button","btn primary wide big",a?"SPINNING…":"SPIN");S.disabled=a,S.addEventListener("click",()=>{Date.now()-Pe<900||(Pe=Date.now(),ft(),s("Spin"))});let l=o("button","btn ghost wide","Leave machine");l.disabled=a,l.addEventListener("click",()=>s("Leave")),E.append(S,l),n.append(E)}var bt=k("auth-screen"),gt=k("lobby-screen"),yt=k("game-screen"),kt=k("history-screen"),Ie=k("session-bar"),Lt=k("account-name"),xt=k("account-balance"),ie=k("game-grid"),U=k("game-board"),Z=k("game-side"),wt=k("game-title"),ze=k("game-badge"),vt=k("history-body"),Tt=k("auth-form"),Ve=k("auth-user"),q=k("auth-pass"),O=k("auth-error"),P=k("auth-submit"),_e=k("tab-login"),je=k("tab-register"),J=k("reconnect-overlay"),Fe=k("reconnect-message"),Oe=k("replaced-overlay"),x=null,D=null,ue=null,_="login",le=null,Ye=0,ce=0,de=new Map([["slots",10],["roulette",10],["blackjack",10],["crash",10]]),Xe={slots:"Slots",roulette:"Roulette",blackjack:"Blackjack",crash:"Crash"},Et={slots:"Five reels, five paylines. Match symbols from the left.",roulette:"European single-zero wheel with inside and outside bets.",blackjack:"Six-deck shoe. Blackjack pays 3:2.",crash:"A rising multiplier. Cash out before it crashes."},Mt=location.pathname.includes("/play/")?location.pathname.slice(0,location.pathname.indexOf("/play/")):"",Ct=`${location.protocol==="https:"?"wss":"ws"}://${location.host}${Mt}/ws`,Q=new j(Ct,{onHello(e){Ye=e.time-Date.now(),D=e.user??null,ze.textContent=`v${e.version}`},onView(e){x=e,e.screen!=="slots"&&We(),e.screen!=="crash"&&Ce(),typeof e.balance=="number"&&(ue=e.balance),e.screen==="lobby"&&"user"in e&&(D=e.user??null,D?q.value="":ue=null),ce=0,J.hidden=!0,Ge(),D&&x.balance===null&&le!==D&&(le=D,Q.send("Info")),D||(le=null)},onNotice(e){e.startsWith("Connected to:")||e.startsWith("Fingerprint:")||e.startsWith("User:")||e.startsWith("Account:")||e.startsWith("Balance:")||(ee(e,be(e)),e.startsWith("Account created")&&(pe("login"),q.value="",Ve.focus()),P.disabled=!1,P.textContent=_==="login"?"Log in":"Create account")},onError(e){ee(e,"bad"),P.disabled=!1,P.textContent=_==="login"?"Log in":"Create account"},onReplaced(){Oe.hidden=!1},onPong(){},onOpen(){J.hidden=!0},onClosed(e){if(Oe.hidden!==!1){if(!e){Fe.textContent="The connection could not be restored. Reload the page to try again.",J.hidden=!1;return}ce+=1,Fe.textContent=ce>1?"Still trying to reach the game server…":"Trying to reach the game server…",J.hidden=!1}}});function B(e){Q.send(e)}function St(){return Date.now()+Ye}function pe(e){_=e,_e.classList.toggle("active",e==="login"),je.classList.toggle("active",e==="register"),P.textContent=e==="login"?"Log in":"Create account",q.autocomplete=e==="login"?"current-password":"new-password",O.textContent=""}function V(e){bt.hidden=e!=="auth",gt.hidden=e!=="lobby",yt.hidden=e!=="game",kt.hidden=e!=="history"}function Nt(e){xt.textContent=L(e??null)}function Ge(){if(!x)return;let e=D;if(e?(Ie.hidden=!1,Lt.textContent=String(e)):Ie.hidden=!0,Nt(ue),!e){V("auth"),O.textContent=x.login_error?String(x.login_error):"",x.screen==="lobby"&&x.connected===!1&&(O.textContent="The game server is not reachable yet. Retrying…");return}switch(x.screen){case"lobby":V("lobby"),Bt(x);break;case"history":V("history"),Ne(vt,x);break;case"slots":case"roulette":case"blackjack":case"crash":V("game"),wt.textContent=Xe[x.screen]??x.screen,ze.textContent=Ht(x),x.screen==="slots"?ae(U,Z,x,B):x.screen==="roulette"?De(U,Z,x,B):x.screen==="blackjack"?we(U,Z,x,B):Se(U,Z,x,B,{now:St});break;default:V("auth")}}function Ht(e){return e.screen==="crash"||e.screen==="blackjack"?String(e.status??""):e.screen==="slots"||e.screen==="roulette"?String(e.phase??""):""}function Bt(e){ie.replaceChildren();let n=e.games??[];for(let[t,s]of n){let a=o("article",`game-card ${t}`);a.append(o("h3",void 0,s||Xe[t]||t)),a.append(o("p",void 0,Et[t]??"Play a round."));let r=o("div","row wrap"),d=o("label","field");d.style.flex="1",d.append(o("span","label","Bet"));let i=o("input","input bet-input");i.type="number",i.min="1",i.step="10",i.value=String(de.get(t)??10),i.addEventListener("change",()=>{let p=Math.max(1,Math.floor(Number(i.value)||1));i.value=String(p),de.set(t,p)}),d.append(i);let m=o("button","btn primary",t==="roulette"?"Open table":"Play");m.addEventListener("click",()=>{let p=Math.max(1,Math.floor(Number(i.value)||1));de.set(t,p),B({Play:{game:t,bet:p}})}),r.append(d,m),a.append(r),ie.append(a)}n.length===0&&ie.append(o("p","muted","The server did not advertise any games."))}_e.addEventListener("click",()=>pe("login"));je.addEventListener("click",()=>pe("register"));Tt.addEventListener("submit",async e=>{e.preventDefault();let n=Ve.value.trim(),t=q.value;if(!n||!t){O.textContent="Enter a username and a password.";return}P.disabled=!0,P.textContent="Working…",O.textContent="";try{let s=await ge(t);B(_==="login"?{Login:{user:n,credential:s}}:{Register:{user:n,credential:s}})}catch{O.textContent="This browser cannot hash the password (needs a secure context).",P.disabled=!1,P.textContent=_==="login"?"Log in":"Create account"}});k("logout").addEventListener("click",()=>B("Logout"));k("show-history").addEventListener("click",()=>B({History:{limit:50}}));k("refresh-lobby").addEventListener("click",()=>B("Info"));k("history-back").addEventListener("click",()=>B("ShowLobby"));k("leave-game").addEventListener("click",()=>{!x||(x.screen==="blackjack"&&x.status==="player"||x.screen==="crash"&&x.status==="running")&&!window.confirm("Leaving now forfeits the active bet. Continue?")||B("Leave")});k("reload-replaced").addEventListener("click",()=>location.reload());k("reload-reconnect").addEventListener("click",()=>location.reload());window.addEventListener("resize",()=>{window.clearTimeout(window.__resizeTimer),window.__resizeTimer=window.setTimeout(()=>{x&&Ge()},140)});window.setInterval(()=>{D&&Q.ping()},25e3);Q.connect();})(); | ||
