From 49fc19f044886a0ee4f5a8ddc0b7a45185a9d137 Mon Sep 17 00:00:00 2001 From: legop3 Date: Tue, 24 Feb 2026 23:15:31 -0500 Subject: [PATCH] some tweaks --- server/prompts/commentary_system.txt | 1 - .../{index-DiXI9XEi.js => index-BJ-_H4qI.js} | 2 +- .../{index-BBp-2M2r.css => index-D2M34pit.css} | 2 +- server/public/index.html | 4 ++-- server/src/services/llmCommentaryService.js | 4 ++++ webui/src/components/AdminPanel.jsx | 14 ++++++++++++++ 6 files changed, 22 insertions(+), 5 deletions(-) rename server/public/assets/{index-DiXI9XEi.js => index-BJ-_H4qI.js} (91%) rename server/public/assets/{index-BBp-2M2r.css => index-D2M34pit.css} (60%) diff --git a/server/prompts/commentary_system.txt b/server/prompts/commentary_system.txt index 9c71ff3b..a7ef7eee 100644 --- a/server/prompts/commentary_system.txt +++ b/server/prompts/commentary_system.txt @@ -22,7 +22,6 @@ Content priorities: - Do not invent events, states, or user intent. Safety: -- Never provide driving instructions. - Never provide admin/security guidance. - Never mention personal/sensitive data. - Never impersonate a specific user. diff --git a/server/public/assets/index-DiXI9XEi.js b/server/public/assets/index-BJ-_H4qI.js similarity index 91% rename from server/public/assets/index-DiXI9XEi.js rename to server/public/assets/index-BJ-_H4qI.js index 563fcc8e..23fcfd46 100644 --- a/server/public/assets/index-DiXI9XEi.js +++ b/server/public/assets/index-BJ-_H4qI.js @@ -14,7 +14,7 @@ Please change the parent to i&&i>o){const f=oi/100,d=1-f;if(a<=o)return 0;if(a<=i){const p=(a-o)/(i-o);return Math.round(Math.max(0,Math.min(1,p))*oi)}if(a>=l)return 100;const h=(a-i)/(l-i);return Math.round((f+Math.max(0,Math.min(1,h))*d)*100)}return null}const fj=1600,dj=800;function fn(...a){return a.filter(Boolean).join(" ")}function yf({visual:a,orientation:l="horizontal",variant:i="inline",compact:o=!1,showLabel:f,className:d=""}){const h=i==="background",p=l==="vertical",g=f??!h;if(!a?.available){if(h){const ae=oi,oe=fn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!j&&"battery-tick-warn"),me=p?{bottom:`${ae}%`}:{left:`${ae}%`},G=fn("absolute inset-0 pointer-events-none",d);return r.jsxs("div",{className:G,children:[r.jsx("div",{className:"absolute inset-0 bg-slate-900/35"}),r.jsx("div",{className:oe,style:me})]})}return p?null:r.jsx("p",{className:"text-xs text-slate-500",children:"Battery telemetry unavailable"})}const v=a.percentDisplay??0,y=Math.max(0,Math.min(100,v)),b=a.warnDisplayPercent??oi,j=!!a.urgentActive,M=!!a.warnActive,w=j?`${dj}ms`:M?`${fj}ms`:void 0,N=h?j||M?"bg-red-500/45":"bg-emerald-500/45":j||M?"bg-red-500":"bg-emerald-500",E=j||M?"bg-red-900/35":"bg-slate-900/35",S=j||M?"bg-red-900/45":"bg-slate-900/35",T=fn(h?"absolute inset-0 pointer-events-none":"relative pointer-events-auto",p&&!h?"flex flex-col items-center justify-center":"w-full",d);if(h){const ae=p?{height:`${y}%`}:{width:`${y}%`},oe=fn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",N,"transition-[width,height]",j&&"battery-urgent-flash"),me=fn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!j&&"battery-tick-warn"),G=p?{bottom:`${b}%`}:{left:`${b}%`};return r.jsxs("div",{className:T,children:[r.jsx("div",{className:fn("absolute inset-0",E,j&&"battery-urgent-flash")}),r.jsx("div",{className:oe,style:{...ae,animationDuration:w}}),r.jsx("div",{className:me,style:G})]})}const z=fn("relative overflow-hidden rounded-sm border border-slate-800",j||M?S:"bg-zinc-900/90",j&&"battery-urgent-flash",p?"w-full flex-1":o?"h-4":"h-5"),L=p?{height:`${y}%`}:{width:`${y}%`},$=fn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",N,"transition-[width,height]",j&&"battery-urgent-flash"),O=fn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!j&&"battery-tick-warn"),V=p?{bottom:`${b}%`}:{left:`${b}%`},X=`Battery ${v}%`,Z=fn("pointer-events-none absolute inset-0 flex items-center justify-center text-center font-semibold",p?o?"text-[0.55rem]":"text-[0.65rem]":"text-xs"),F=fn("rounded px-1.5 py-0.5",h?"bg-black/30 text-slate-100":"bg-black/50 text-slate-100");return r.jsxs("div",{className:T,children:[r.jsxs("div",{className:z,children:[r.jsx("div",{className:$,style:{...L,animationDuration:w}}),r.jsx("div",{className:O,style:V})]}),g&&!p?r.jsx("div",{className:Z,children:r.jsx("span",{className:F,children:X})}):null,g&&p?r.jsx("div",{className:"mt-0.5 text-[0.65rem] font-semibold text-slate-100",children:r.jsxs("span",{className:F,children:[v,"%"]})}):null]})}const Dp=2e3,mj=3e3,hj=3e3,pj=40,xj=1e3;function ci({sessionInfo:a,audioSessionInfo:l,videoMode:i="whep",snapshotFeed:o=null,qualityNotice:f=null,label:d,forceMute:h=!1,telemetryFrame:p,batteryConfig:g,layoutFormat:v="desktop",hudVariant:y="default",driverLabel:b=null,hudForceMap:j=!1,hudMapPosition:M="top-center",hudLabelScale:w=1,fitParent:q=!1,overcurrentLimiter:N=null,showTurnCue:E=!1,turnTimerText:S=null,turnSeconds:T=null,isActiveDriver:z=!1,idleSkipSeconds:L=null}){const{session:$}=Ve(),O=m.useRef(null),V=m.useRef(null),X=m.useRef(null),Z=m.useRef(null),F=m.useRef(null),ae=m.useRef(null),oe=m.useRef(null),me=m.useRef(null),[G,k]=m.useState("idle"),[Q,P]=m.useState(null),[re,ce]=m.useState("idle"),[C,_]=m.useState(null),[W,te]=m.useState(0),[le,ie]=m.useState(0),[ue,ve]=m.useState(!0),he=!!l?.url,Ce=i==="snapshot",ne=p?.sensors,{value:se}=st("audio",jt),Se=Number.isFinite(se?.masterVolume)?se.masterVolume:jt.masterVolume,Oe=Number.isFinite(se?.roverVolume)?se.roverVolume:jt.roverVolume,Ne=typeof se?.mainBrushDuckEnabled=="boolean"?se.mainBrushDuckEnabled:typeof se?.autoLevelEnabled=="boolean"?se.autoLevelEnabled:jt.mainBrushDuckEnabled,ze=Number.isFinite(se?.mainBrushDuckAmount)?Math.max(0,Math.min(1,se.mainBrushDuckAmount)):jt.mainBrushDuckAmount,an=Math.max(0,Math.min(1,Se*Oe)),wa=ne?.batteryChargeMah??null,Wn=v==="desktop",it=!Wn,ln=it?"top-right":M,[fo]=lg(),mo=j||it?!0:fo,mt=sg({charge:wa,config:g}),Pa=ne?.wheelOvercurrents||null,el=Pa==null?[]:Object.entries(Pa).filter(([,xe])=>!!xe).map(([xe])=>xe),sn=N?.caps||null,Ea=N?.overcurrent?.groups||null,gi=typeof window<"u"&&new URLSearchParams(window.location.search).has("debugAudio"),tl=typeof window<"u"&&new URLSearchParams(window.location.search).has("debugHud"),ho=m.useMemo(()=>{if(!sn)return null;const xe=Number.isFinite(sn?.drive?.cap)?sn.drive.cap:1,Xe=Number.isFinite(sn?.aux?.cap)?sn.aux.cap:1;return Math.max(0,Math.min(1,1-Math.min(xe,Xe)))},[sn]),ts=!!N?.isActive,rn=el.length?el:ts?["limiter"]:[],pt=ho??(el.length?1:0),Yt=!!rn.length,rt=!!((Number(ne?.mainBrushCurrentMa)||0)>pj||ne?.wheelOvercurrents?.mainBrush),po=Ne&&rt?1-ze:1,nl=Math.max(0,Math.min(1,an*po)),xo=Ne&&rt&&ze>0?`Volume decreased ${Math.round(ze*1e3)/10}%`:null,Ca=m.useRef({hasDedicatedAudio:!1,audioUrl:null,mainBrushDuckEnabled:!1,mainBrushDuckAmount:0,mainBrushActive:!1,baseRoverGain:0,effectiveRoverGain:0});m.useEffect(()=>{Ca.current={hasDedicatedAudio:he,audioUrl:l?.url||null,mainBrushDuckEnabled:Ne,mainBrushDuckAmount:ze,mainBrushActive:rt,baseRoverGain:an,effectiveRoverGain:nl}},[he,l?.url,Ne,ze,rt,an,nl]);const Fe=m.useCallback((xe,Xe={})=>{if(!gi)return;const Qe=V.current,je=Ca.current,Le={event:xe,ts:Date.now(),roverLabel:d||null,hasDedicatedAudio:je.hasDedicatedAudio,audioUrl:je.audioUrl,mainBrushDuckEnabled:je.mainBrushDuckEnabled,mainBrushDuckAmount:je.mainBrushDuckAmount,mainBrushActive:je.mainBrushActive,baseRoverGain:je.baseRoverGain,effectiveRoverGain:je.effectiveRoverGain,element:Qe?{muted:Qe.muted,volume:Qe.volume,paused:Qe.paused,ended:Qe.ended,readyState:Qe.readyState,networkState:Qe.networkState}:null,...Xe};try{console.log(`[AudioDebug] ${xe} ${JSON.stringify(Le)}`)}catch{console.log("[AudioDebug]",xe,Le)}},[gi,d]),al=$?.socials?.find(xe=>String(xe?.id||xe?.label||"").toLowerCase()==="discord")?.url||$?.discord?.invite||null;m.useEffect(()=>{tl&&console.log("[OvercurrentHUD]",{overlayVisible:Yt,overlayMotors:rn,overlayFill:pt,limiterActive:ts,limiterCaps:sn,limiterGroups:Ea,wheelOvercurrents:Pa})},[tl,pt,rn,Yt,ts,sn,Ea,Pa]),m.useEffect(()=>{Fe("settings/update")},[Fe]);const _t=m.useCallback(()=>{clearTimeout(X.current),X.current=setTimeout(()=>te(Date.now()),Dp)},[]),Pn=m.useCallback(()=>{clearTimeout(Z.current),Z.current=setTimeout(()=>ie(Date.now()),Dp)},[]),xn=m.useCallback(async()=>{const xe=O.current;if(xe)try{xe.muted=!0,await xe.play()}catch{}},[]),vi=m.useCallback((xe=0)=>{if(h||he)return;clearTimeout(ae.current);const Xe=()=>{clearTimeout(ae.current),ae.current=setTimeout(()=>{h||Qe()},mj)},Qe=async()=>{const je=O.current;if(je)try{await xn(),je.muted=!1,await je.play(),ve(!1)}catch{je.muted=!0,ve(!0),Xe()}};ae.current=setTimeout(Qe,xe)},[xn,h,he]);m.useEffect(()=>()=>{clearTimeout(X.current),clearTimeout(Z.current),clearTimeout(ae.current),clearInterval(F.current),oe.current&&(cancelAnimationFrame(oe.current),oe.current=null)},[]),m.useEffect(()=>{G==="playing"&&vi(0)},[G,vi]),m.useEffect(()=>{Ce&&(k("snapshot"),P(null))},[Ce]),m.useEffect(()=>{if(Ce||!a?.url||!O.current)return;let xe=!0,Xe;const Qe=setTimeout(()=>ve(!0),0),je=(Le,vt)=>{xe&&(Fe("video/status",{nextStatus:Le,info:vt||null}),k(Le),P(vt||null),Le==="playing"&&xn(),["error","failed","disconnected","closed"].includes(Le)&&_t())};return Xe=new Rp({url:a.url,token:a.token,video:O.current,receiveAudio:!he,onStatus:je}),Xe.start().catch(Le=>{xe&&(k("error"),P(Le.message),_t())}),()=>{xe=!1,clearTimeout(Qe),Xe?.stop()}},[Ce,a?.url,a?.token,W,_t,xn,he,Fe]),m.useEffect(()=>{G==="stopped"&&a?.url&&_t()},[G,a?.url,_t]),m.useEffect(()=>{const xe=V.current;if(!xe||!l?.url){Fe("route/no-audio-url"),me.current=null;return}const Xe=Math.max(0,Math.min(1,nl)),Qe=me.current==null?Math.max(0,Math.min(1,xe.volume)):me.current;if(oe.current&&(cancelAnimationFrame(oe.current),oe.current=null),Xe>Qe){const je=performance.now(),Le=Qe,vt=Xe-Le,Et=Pe=>{const Te=Math.min(1,(Pe-je)/xj),Gt=Le+vt*Te;xe.volume=Gt,me.current=Gt,Te<1?oe.current=requestAnimationFrame(Et):oe.current=null};oe.current=requestAnimationFrame(Et)}else xe.volume=Xe,me.current=Xe;Fe("route/direct",{elementVolume:Xe,duckEnabled:Ne,mainBrushActive:rt,duckAmount:ze})},[l?.url,nl,Ne,rt,ze,Fe]),m.useEffect(()=>{if(!l?.url||!V.current)return;let xe=!0,Xe;const Qe=(je,Le)=>{xe&&(Fe("audio/status",{nextStatus:je,info:Le||null}),_(Le||(je==="connected"?"connected":null)),ce(vt=>je==="connected"&&(vt==="playing"||vt==="connecting")||je==="new"?vt:je),["error","failed"].includes(je)&&Pn())};return Xe=new Rp({url:l.url,token:l.token,video:V.current,audioOnly:!0,onStatus:Qe}),Xe.start().catch(je=>{xe&&(ce("error"),_(je.message),Pn())}),()=>{xe=!1,Xe?.stop()}},[l?.url,l?.token,le,Pn,Fe]),m.useEffect(()=>{const xe=V.current;if(!l?.url||!xe){clearInterval(F.current);return}if(!["connecting","connected","playing","paused"].includes(re)){clearInterval(F.current);return}const Qe=async()=>{const je=V.current;je&&(je.muted=!1,!(!je.paused&&!je.ended)&&(Fe("retry/play-attempt"),je.play().then(()=>{Fe("retry/play-ok"),ce(Le=>Le==="connected"?"playing":Le),_(Le=>Le==="paused"?null:Le)}).catch(Le=>{Fe("retry/play-fail",{error:Le?.message}),_(vt=>vt||Le?.message||"autoplay blocked")})))};return Qe(),F.current=setInterval(Qe,hj),()=>clearInterval(F.current)},[l?.url,re,Fe]),m.useEffect(()=>{const xe=V.current;if(!xe)return;const Xe=()=>{Fe("element/play"),ce(Te=>Te==="error"?Te:"playing"),_(null)},Qe=()=>{Fe("element/pause"),ce(Te=>["error","failed","disconnected","closed","stopped"].includes(Te)?Te:"paused"),_(Te=>Te||"paused")},je=()=>{Fe("element/ended"),ce(Te=>Te==="error"?Te:"stopped"),_(Te=>Te||"ended")},Le=()=>{const{error:Te}=xe,Gt=Te?.message||"audio error";Fe("element/error",{error:Gt}),ce("error"),_(Gt)},vt=()=>Fe("element/waiting"),Et=()=>Fe("element/canplay"),Pe=()=>Fe("element/stalled");return xe.addEventListener("play",Xe),xe.addEventListener("pause",Qe),xe.addEventListener("ended",je),xe.addEventListener("error",Le),xe.addEventListener("waiting",vt),xe.addEventListener("canplay",Et),xe.addEventListener("stalled",Pe),()=>{xe.removeEventListener("play",Xe),xe.removeEventListener("pause",Qe),xe.removeEventListener("ended",je),xe.removeEventListener("error",Le),xe.removeEventListener("waiting",vt),xe.removeEventListener("canplay",Et),xe.removeEventListener("stalled",Pe)}},[l?.url,Fe]);const yi=o?.error?`Error: ${o.error}`:o?.objectUrl?"snapshot":o?.status||"waiting",ns=Ce?yi:a?.url?G==="error"?`Error: ${Q||"unknown"}`:Q?`${G} (${Q})`:G:"waiting",qa=l?.error?`Error: ${l.error}`:l?.url?re==="error"?`Error: ${C||"unknown"}`:C?`${re} (${C})`:re:null,bi=y==="spectator",$t=y==="none";return r.jsxs("div",{className:`flex flex-col gap-0.5 ${q?"h-full":""}`,children:[r.jsxs("div",{className:`relative w-full overflow-hidden bg-black ${q?"h-full flex-1":"aspect-[4/3]"}`,children:[Ce?o?.objectUrl?r.jsx("img",{src:o.objectUrl,alt:d,className:"h-full w-full object-contain",draggable:!1}):r.jsx("div",{className:"flex h-full w-full items-center justify-center text-sm text-slate-300",children:"Waiting for frame…"}):r.jsx("video",{ref:O,muted:h||ue||he,playsInline:!0,autoPlay:!0,controls:!1,className:"h-full w-full object-contain"}),r.jsx("audio",{ref:V,autoPlay:!0,hidden:!0}),!$t&&E?r.jsx(yj,{mobileHud:it,turnSeconds:T,isActiveDriver:z,idleSkipSeconds:L}):null,$t?null:r.jsx(vj,{frame:p,sensors:ne,label:d,status:ns,audioStatus:qa,levelStatus:xo,desktopLayout:Wn,layoutFormat:v,variant:y,driverLabel:b,battery:mt,showTopDown:mo,mobileHud:it,mapPosition:ln,turnTimerText:S,labelScale:w}),$t?null:r.jsx(jj,{compact:it}),!$t&&tl?r.jsx("div",{className:"pointer-events-none absolute left-1 top-1 z-40 rounded bg-black/80 px-1 py-0.5 text-[0.6rem] text-lime-200",children:`OC vis:${Yt?1:0} motors:${rn.length} fill:${Math.round(pt*100)}%`}):null,$t?null:r.jsx(Sj,{motors:rn,fill:pt,compact:it}),$t?null:r.jsx(Aj,{battery:mt,compact:it}),!$t&&bi&&mt.available?r.jsx("div",{className:"pointer-events-none absolute right-1 top-1/2 flex h-[70%] -translate-y-1/2 flex-col items-center justify-center rounded bg-black/60 px-0.5 pb-1 pt-1",children:r.jsx(yf,{visual:mt,orientation:"vertical",variant:"inline",compact:it,className:"h-full w-4"})}):null,!$t&&f?r.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2",children:r.jsxs("div",{className:`mx-auto w-fit rounded border border-amber-300/80 bg-black/75 text-amber-200 ${it?"px-2 py-1 text-[0.6rem]":"px-3 py-1.5 text-sm"}`,children:[r.jsx("div",{className:"text-center",children:f}),r.jsx("div",{className:"pointer-events-auto mt-0",children:r.jsx(Xf,{id:"discord",label:"Join our Discord server while you wait!",url:al})})]})}):null]}),!$t&&!bi&&r.jsxs("div",{className:"space-y-0.5",children:[r.jsx(gj,{sensors:ne}),r.jsx("div",{className:"panel-section space-y-0.5 text-sm",children:r.jsx(yf,{visual:mt,compact:it})})]})]})}function gj({sensors:a}){const l=[a?.lightBumpLeftSignal,a?.lightBumpFrontLeftSignal,a?.lightBumpCenterLeftSignal,a?.lightBumpCenterRightSignal,a?.lightBumpFrontRightSignal,a?.lightBumpRightSignal],i=l.filter(p=>p!=null).reduce((p,g)=>Math.max(p,g),1200),o=p=>Math.pow(Math.max(0,Math.min(1,(p??0)/i)),.35),f=p=>p==null||p<=0?"hsl(200 60% 18%)":`hsl(${(200+o(p)*360)%360} 100% 60%)`,d=6,h=12;return r.jsx("div",{className:"flex w-full items-center justify-center gap-0.5",children:l.map((p,g)=>{const v=o(p),y=gDate.now());m.useEffect(()=>{const P=setInterval(()=>E(Date.now()),150);return()=>clearInterval(P)},[]),a?.receivedAt&&N-a.receivedAt<200;const S=j,T=p==="mobile-portrait",z=S?"text-[0.45rem]":"text-[0.65rem]",L=S?"px-0.25 py-0.25":"px-1 py-0.5",$=S?"px-0.25 py-0.25":"px-0.5 py-0.5",O=S?"text-[0.55rem]":"text-[0.8rem]",V=S?"left-0.5 top-0.5":"left-1 top-1",X=S?"text-[0.5rem]":"text-[0.7rem]",Z=S?"px-0.5 py-0.25":"px-1 py-0.5",F=S?"left-0.5 top-1/2":"left-1 top-1/2",ae="bottom-0.5",oe={transform:`translateX(-50%) scale(${q})`,transformOrigin:"center bottom"},me="240px",G=T?.3:S?.33:.7,Q={width:me,height:me,opacity:S?.6:.7,transform:M==="top-center"?`translateX(-50%) scale(${G})`:`scale(${G})`,transformOrigin:M==="bottom-left"?"bottom left":M==="top-center"?"top center":"top right",...M==="bottom-left"?{left:"0.25rem",bottom:"0.25rem"}:M==="top-center"?{left:"50%",top:"0.25rem"}:{right:"0.25rem",top:"0.25rem"}};if(g==="none")return null;if(g==="spectator"){const P=[["Voltage",l?.voltageMv!=null?`${(l.voltageMv/1e3).toFixed(2)} V`:"--"],["Current",l?.currentMa!=null?`${l.currentMa} mA`:"--"],["Charge",l?.batteryChargeMah!=null?`${l.batteryChargeMah}`:"--"],["OI",l?.oiMode?.label||"--"]],re=!!l?.chargingSources?.homeBase,ce=l?.chargingState?.label||"",C=!!(ce&&ce.toLowerCase()!=="not charging"),_=l?.oiMode?.label||"Unknown",W=_.toLowerCase(),te=W==="full"?"bg-emerald-500/80 text-emerald-50":W==="safe"?"bg-amber-400/80 text-amber-950":W==="passive"?"bg-slate-700/80 text-slate-100":"bg-slate-700/60 text-slate-200",le=re?"bg-emerald-500/80 text-emerald-50":"bg-slate-700/70 text-slate-200",ie=C?"bg-emerald-500/80 text-emerald-50":re?"bg-amber-400/80 text-amber-950":"bg-slate-700/70 text-slate-200";return r.jsxs(r.Fragment,{children:[r.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[r.jsx("div",{className:`absolute ${V} font-medium text-slate-100 ${z}`,children:r.jsxs("div",{className:"flex flex-col gap-0.5 leading-none",children:[r.jsxs("span",{children:["Status: ",o]}),f?r.jsxs("span",{children:["Audio: ",f]}):null,d?r.jsx("span",{className:"text-cyan-300",children:d}):null]})}),r.jsx("div",{className:`absolute ${F} flex -translate-y-1/2 flex-col gap-0.5 bg-black/70 text-slate-100 ${z} ${L}`,children:r.jsxs("div",{className:"space-y-0.5 leading-tight",children:[r.jsxs("div",{className:"flex flex-col gap-0.5 text-[0.75rem] font-semibold uppercase tracking-wide",children:[r.jsx("span",{className:`rounded px-1.5 py-0.5 ${le}`,children:re?"Docked":"Undocked"}),r.jsx("span",{className:`rounded px-1.5 py-0.5 ${ie}`,children:C?"Charging":"Not charging"}),r.jsxs("span",{className:`rounded px-1.5 py-0.5 ${te}`,children:["OI: ",_]})]}),P.map(([ue,ve])=>r.jsxs("span",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{className:"text-slate-400",children:ue}),r.jsx("span",{className:"font-semibold text-white",children:ve})]},ue))]})}),r.jsx("div",{className:`absolute ${ae} left-1/2`,style:oe,children:r.jsxs("div",{className:`flex items-center gap-0.5 bg-black/80 text-slate-100 ${$} ${O}`,children:[r.jsx("span",{className:"font-semibold text-white",children:i||"Unnamed Rover"}),v?r.jsxs("span",{className:"text-slate-300",children:["• ",v]}):null]})})]}),b?r.jsx("div",{className:"pointer-events-none absolute rounded",style:{...Q},children:r.jsx(vf,{sensors:l,size:240,overlay:!0})}):null]})}return r.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[r.jsx("div",{className:`absolute ${V} font-medium text-slate-100 ${z}`,children:r.jsxs("div",{className:"flex flex-col gap-0.5 leading-none",children:[r.jsxs("span",{children:["Status: ",o]}),f?r.jsxs("span",{children:["Audio: ",f]}):null,d?r.jsx("span",{className:"text-cyan-300",children:d}):null]})}),w?r.jsx("div",{className:`absolute left-1/2 top-0.5 -translate-x-1/2 rounded bg-black/70 text-slate-100 ${Z} ${X}`,children:w}):null,r.jsx("div",{className:`absolute ${ae} left-1/2`,style:oe,children:r.jsx("div",{className:`flex gap-0.5 bg-black/80 text-slate-100 ${$} ${O}`,children:r.jsxs("span",{children:['Rover: "',i||"Unnamed Rover",'"']})})}),b&&g!=="spectator"?r.jsx("div",{className:"pointer-events-none absolute rounded",style:{...Q},children:r.jsx(vf,{sensors:l,size:240,overlay:!0})}):null]})}function yj({mobileHud:a=!1,turnSeconds:l=null,isActiveDriver:i=!1,idleSkipSeconds:o=null}){const f=a?"text-3xl":"text-5xl",d=a?"text-xs":"text-sm",h=a?"text-[0.55rem]":"text-[0.75rem]",p=a?"px-4 py-3":"px-6 py-4",g=i&&typeof o=="number";return r.jsx("div",{className:"pointer-events-none absolute inset-0 z-30 flex items-center justify-center bg-black/55",children:r.jsxs("div",{className:`flex flex-col items-center gap-0.5 rounded border border-amber-300/80 bg-black/70 ${p}`,children:[r.jsx("div",{className:`font-semibold text-amber-200 ${f}`,children:"IT IS YOUR TURN!"}),r.jsx("div",{className:`text-amber-200/80 ${d}`,children:"Start driving!"}),g?r.jsxs("div",{className:`text-red-100/90 ${h}`,children:["Idle skip in ",o,"s"]}):null]})})}const bj={leftWheel:"Left wheel",rightWheel:"Right wheel",mainBrush:"Main brush",sideBrush:"Side brush",limiter:"Overcurrent limit"};function Sj({motors:a,fill:l=0,compact:i=!1}){if(!a?.length)return null;const o=a.map(y=>bj[y]||y),f=i?"w-[12rem] h-[3.5rem]":"w-[20rem] h-[7rem]",d=i?"px-2 py-1":"px-4 py-2",h=i?"text-lg":"text-4xl",p=i?"text-xs":"text-xl",g=Math.max(0,Math.min(1,l)),v=`${Math.round(g*100)}%`;return r.jsx("div",{className:`pointer-events-none absolute flex items-center justify-center bg-red-900/50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 ${f}`,children:r.jsxs("div",{className:"relative h-full w-full",children:[r.jsx("div",{className:"absolute inset-0 overflow-hidden",children:r.jsx("div",{className:"h-full bg-red-700/60",style:{width:v}})}),r.jsxs("div",{className:`relative z-10 flex h-full w-full flex-col items-center justify-center text-center font-semibold text-white animate-pulse ${h} ${d}`,children:[r.jsx("div",{children:"OVERCURRENT"}),r.jsx("div",{className:`mt-0 font-medium text-white ${p}`,children:o.join(", ")})]})]})})}function Aj({battery:a,compact:l=!1}){if(!a?.available||!a.warnActive&&!a.urgentActive)return null;const i=a.urgentActive?"BATTERY VERY LOW, DOCK THE ROVER AND CHARGE IMMEDIATELY!!":"Battery low! please dock and charge the rover soon.",o=l?"p-2 top-6":"p-4 top-10",f=l?"text-sm":"text-2xl";return r.jsx("div",{className:`pointer-events-none absolute flex items-center justify-center bg-amber-900/60 left-1/2 -translate-x-1/2 ${o}`,children:r.jsx("div",{className:`text-center font-semibold text-white animate-pulse ${f}`,children:r.jsx("div",{children:i})})})}function jj({compact:a=!1}){const{session:l}=Ve(),{sendMessage:i,onInputFocus:o,onInputBlur:f,blurChat:d,registerInputRef:h,setTypingActive:p}=Lf(),{value:g}=st("tts",{engine:"flite",voice:"rms",pitch:50}),[v,y]=m.useState(""),[b,j]=m.useState(!1),M=l?.role!=="spectator",w=l?.role==="spectator",q=l?.assignment?.roverId||null,E=!!m.useMemo(()=>l?.roster?.find(O=>String(O.id)===String(q))||null,[q,l?.roster])?.audio?.ttsEnabled,S=m.useMemo(()=>{if(!E)return null;const O=g?.engine==="espeak"?"espeak":"flite";if(O==="espeak"){let X=Number.isFinite(g?.pitch)?Math.round(g.pitch):void 0;return typeof X=="number"&&(X=Math.max(0,Math.min(99,X))),{speak:!0,engine:O,pitch:X}}const V=typeof g?.voice=="string"?g.voice:void 0;return{speak:!0,engine:O,voice:V}},[g?.engine,g?.pitch,g?.voice,E]),T=a?"pointer-events-auto absolute bottom-0.5 right-0.5 flex w-[9rem] max-w-[70vw] items-center gap-0.5 rounded bg-black/70 px-0.4 py-0.2":"pointer-events-auto absolute bottom-1 right-1 flex w-[12rem] max-w-[70vw] items-center gap-0.5 rounded bg-black/70 px-0.5 py-0.25",z=a?"min-w-0 flex-1 bg-transparent text-[0.55rem] text-slate-100 placeholder:text-slate-400 focus:outline-none":"min-w-0 flex-1 bg-transparent text-[0.7rem] text-slate-100 placeholder:text-slate-400 focus:outline-none",L=a?"rounded bg-cyan-500/80 px-0.35 py-0.2 text-[0.55rem] font-semibold text-black disabled:opacity-50":"rounded bg-cyan-500/80 px-0.5 py-0.25 text-[0.7rem] font-semibold text-black disabled:opacity-50";async function $(O){if(O.preventDefault(),!M)return;const V=v.trim();if(V){j(!0);try{await i(V,S),y(""),d(),p(!1)}catch(X){alert(X.message)}finally{j(!1)}}}return w?null:r.jsxs("form",{onSubmit:$,className:T,children:[r.jsx("input",{className:z,value:v,onChange:O=>{const V=O.target.value;y(V),p(!!V.trim())},onFocus:O=>{o(O),p(!!v.trim())},onBlur:O=>{f(O),p(!1)},onKeyDown:O=>{O.key==="Enter"&&!v.trim()&&(O.preventDefault(),d(),p(!1))},ref:O=>h(O,{target:"hud"}),placeholder:M?"Chat (TTS)":"Spectator",disabled:!M}),r.jsx("button",{type:"submit",disabled:!M||b,className:L,children:"Speak"})]})}function Qf({layoutFormat:a="desktop"}){const{session:l}=Ve(),{state:{song:i,lastControlIntentAt:o},overcurrentLimiter:f}=Dt(),[d,h]=m.useState(()=>Date.now()),[p,g]=m.useState(!1),[v,y]=m.useState(null),b=m.useRef({active:!1,roverId:null});m.useEffect(()=>{if(l?.mode!=="turns")return;const te=setInterval(()=>h(Date.now()),250);return()=>clearInterval(te)},[l?.mode]);const j=l?.assignment?.roverId,w=!!(j&&l?.roster?l.roster.find(te=>String(te.id)===String(j)):null)?.media?.audioPublishUrl,q=j?l?.turnQueues?.[j]:null,N=l?.socketId||null,E=j?l?.activeDrivers?.[j]:null,S=!!(N&&E===N),T=m.useMemo(()=>{const te=q?.queue||[];if(!te.length||!q?.current||te.length<=1)return null;const le=te.findIndex(ie=>ie===q.current);return le===-1?te[0]||null:te[(le+1)%te.length]||null},[q?.queue,q?.current]),z=!!(N&&T===N),L=q?.deadline||null,$=q?.idleDeadline||null,O=L?L-d:null,V=$?$-d:null,X=l?.mode==="turns"&&z&&O!=null&&O<=5e3&&O>0,Z=l?.mode!=="turns"||S||X,F=O!=null&&Number.isFinite(O)?Math.max(0,Math.ceil(O/1e3)):null,ae=V!=null&&Number.isFinite(V)?Math.max(0,Math.ceil(V/1e3)):null,oe=S?F!=null?`${F}s left`:null:z&&F!=null?`Your turn in ${F}s`:null,me=j?[...Z?[{type:"rover",id:j,key:j}]:[],...w?[{type:"rover",id:`${j}-audio`,key:`${j}-audio`}]:[]]:[],G=ri(me),k=j&&Z?G[j]:null,Q=j&&w?G[`${j}-audio`]:null,P=$f(j?[j]:[],{enabled:!!j,version:l?.mode}),re=j&&P[j]||null,ce=es(j),C=j&&l?.roster?l.roster.find(te=>String(te.id)===String(j)):null,_=C?.battery??null,W=C?.name||(j?`Rover ${j}`:"");return m.useEffect(()=>{if(l?.mode!=="turns"){g(!1),y(null),b.current={active:!1,roverId:null};return}const te=b.current,le=S&&!te.active,ie=S&&j&&j!==te.roverId;le||ie?(g(!0),y(Date.now())):!S&&te.active&&(g(!1),y(null)),b.current={active:S,roverId:j}},[S,j,l?.mode]),m.useEffect(()=>{!p||!v||o>v&&g(!1)},[o,v,p]),r.jsx("section",{className:"panel",children:j?r.jsx(ci,{sessionInfo:k,videoMode:Z?"whep":"snapshot",snapshotFeed:re,audioSessionInfo:Q,label:W,telemetryFrame:ce,batteryConfig:_,layoutFormat:a,overcurrentLimiter:f,songNote:i?.note,qualityNotice:Z?null:"Preview feed (low FPS) until your turn.",showTurnCue:p,turnTimerText:oe,turnSeconds:F,isActiveDriver:S,idleSkipSeconds:ae}):r.jsxs("div",{className:"panel-muted content-center text-center text-sm text-slate-400 aspect-[4/3]",children:[r.jsx("p",{children:"You are not assigned to a rover."}),r.jsx("p",{className:"mt-0",children:r.jsx("a",{href:"/spectate",className:"text-blue-400 underline hover:text-blue-500",children:"Click here to visit the spectator page."})})]})})}function bf({label:a,tone:l="muted"}){const i=l==="success"?"bg-emerald-900 text-emerald-100":l==="warn"?"bg-amber-900 text-amber-100":"bg-slate-800 text-slate-200";return r.jsx("span",{className:`rounded px-1 py-0.5 text-xs font-semibold leading-none ${i}`,children:a})}function ro(a){if(!Number.isFinite(a))return 0;const l=a%360;return l<0?l+360:l}function Nj(a){if(!Array.isArray(a)||a.length<3)return 0;const[l,i,o]=a,f=Math.max(0,Math.min(255,Number(l)))/255,d=Math.max(0,Math.min(255,Number(i)))/255,h=Math.max(0,Math.min(255,Number(o)))/255,p=Math.max(f,d,h),g=Math.min(f,d,h),v=p-g;if(v===0)return 0;let y=0;return p===f?y=(d-h)/v%6:p===d?y=(h-f)/v+2:y=(f-d)/v+4,ro(Math.round(y*60))}function _p(a){const l=ro(a),i=1,o=1-Math.abs(l/60%2-1);let f=0,d=0,h=0;return l<60?(f=i,d=o):l<120?(f=o,d=i):l<180?(d=i,h=o):l<240?(d=o,h=i):l<300?(f=o,h=i):(f=i,h=o),[Math.round(f*255),Math.round(d*255),Math.round(h*255)]}function Op(a){return a?Array.isArray(a.hsColor)?ro(Number(a.hsColor[0])):Array.isArray(a.rgbColor)?Nj(a.rgbColor):0:0}function wj({entity:a,connected:l,onToggle:i,onSetColor:o}){const f=a.state==="unavailable"||!a.available,d=a.state==="on",h=a.type==="light"&&a.supportsColor,p=f?"warn":d?"success":"muted",g=f?"Unavailable":d?"On":"Off",v=!l||f,y=v||!h,[b,j]=m.useState(()=>Op(a)),M=m.useRef(b),w=m.useRef(!1),q=f?"border-slate-800 bg-slate-900 text-slate-400 cursor-not-allowed":d?"border-emerald-700 bg-emerald-900/80 text-emerald-50 hover:bg-emerald-800":"border-rose-800 bg-rose-900/80 text-rose-50 hover:bg-rose-800";m.useEffect(()=>{if(!h||w.current)return;const L=Op(a);M.current=L,j(L)},[a.rgbColor,a.hsColor,h]);const N=L=>{const $=ro(Number(L.target.value));M.current=$,j($)},E=()=>{y||!o||o(a.id,_p(M.current))},S=L=>{L.stopPropagation()},z=`rgb(${(h?_p(M.current):[255,255,255]).join(",")})`;return r.jsxs("button",{type:"button",onClick:()=>i(a.id),disabled:v,className:`relative flex min-w-[12rem] flex-[1_1_12rem] items-start justify-between gap-0.5 rounded px-1 py-0.5 text-left transition-colors ${q} disabled:opacity-60 disabled:hover:bg-inherit`,children:[r.jsxs("div",{className:"min-w-0 flex-1",children:[r.jsxs("div",{className:"flex items-center gap-0.5 text-sm leading-normal",children:[r.jsx("span",{className:"truncate font-semibold text-white",children:a.name||a.id}),h&&r.jsxs(r.Fragment,{children:[r.jsx(bf,{label:g,tone:p}),!l&&r.jsx("span",{className:"text-xs text-amber-200",children:"Offline"})]})]}),h?r.jsx("div",{className:"-mt-0.5 w-full",onClick:S,onPointerDown:L=>{S(L),w.current=!0},onPointerUp:L=>{S(L),w.current=!1,E()},onPointerCancel:L=>{S(L),w.current=!1,E()},onKeyUp:L=>{S(L),E()},onBlur:E,children:r.jsx("div",{className:"relative w-full",children:r.jsx("input",{type:"range",min:"0",max:"360",step:"1",value:b,onChange:N,disabled:y,"aria-label":`Set color for ${a.name||a.id}`,className:"ha-hue-slider w-full"})})}):r.jsxs("div",{className:"flex items-center gap-0.5 text-xs text-slate-400",children:[r.jsx(bf,{label:g,tone:p}),!l&&r.jsx("span",{className:"text-amber-200",children:" · Offline"})]})]}),h&&r.jsx("span",{className:"pointer-events-none absolute right-1 top-1 h-2.5 w-2.5 rounded-full border border-white/60",style:{backgroundColor:z}}),!h&&r.jsx("div",{className:"self-center text-xs font-semibold text-white/90",children:d?"Turn off":"Turn on"})]})}function ig(){const{state:{keymap:a}}=Dt(),{session:l,homeAssistantToggle:i,homeAssistantSetLightColor:o}=Ve(),f=l?.homeAssistant,d=m.useMemo(()=>f?.entities||[],[f?.entities]),h=An(a?.homeAssistantOn?.[0]),p=An(a?.homeAssistantOff?.[0]);if(!f?.enabled)return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm text-slate-400",children:[r.jsx("p",{className:"text-slate-300",children:"Room Controls"}),r.jsx("p",{className:"text-slate-500",children:"Not configured on the server."})]});if(d.length===0)return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm text-slate-400",children:[r.jsx("p",{className:"text-slate-300",children:"Room Controls"}),r.jsx("p",{className:"text-slate-500",children:"No lights or switches configured."})]});const g=!!f?.connected;return r.jsxs("section",{className:"panel-section space-y-0.5 text-base",children:[r.jsxs("header",{className:"flex items-center justify-between gap-0.5 text-sm text-slate-400",children:[r.jsxs("div",{className:"flex items-center gap-0.5",children:[r.jsx("p",{children:"Room Controls"}),r.jsx("span",{className:"text-xs text-slate-500",children:d.length}),r.jsxs("div",{className:"flex items-center gap-0.5 text-xs text-slate-300 background-black",children:[r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx("span",{children:"On"}),h?r.jsx(Bp,{label:h}):null]}),r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx("span",{children:"Off"}),p?r.jsx(Bp,{label:p}):null]})]})]}),r.jsx(bf,{label:g?"Connected":"Offline",tone:g?"success":"warn"})]}),r.jsx("div",{className:"flex flex-wrap gap-0.5",children:d.map(v=>r.jsx(wj,{entity:v,connected:g,onToggle:i,onSetColor:o},v.id))})]})}function Bp({label:a}){return a?r.jsx("span",{className:"rounded border border-white/40 px-1 text-[0.7rem] text-white",children:a}):null}function rg(){const{login:a,setRole:l}=Ve(),[i,o]=m.useState(""),[f,d]=m.useState(""),[h,p]=m.useState(!1);async function g(v){v.preventDefault(),p(!0);try{await a(i,f),o(""),d("")}catch(y){alert(y.message)}finally{p(!1)}}return r.jsxs("div",{className:"panel-section space-y-0.5 text-base",children:[r.jsx("p",{className:"text-sm text-slate-400",children:"Admin login"}),r.jsxs("form",{className:"flex flex-col gap-0.5",onSubmit:g,children:[r.jsx("input",{className:"field-input",placeholder:"Username",value:i,onChange:v=>o(v.target.value)}),r.jsx("input",{className:"field-input",placeholder:"Password",type:"password",value:f,onChange:v=>d(v.target.value)}),r.jsx("button",{type:"submit",disabled:h,className:"button-dark w-full disabled:opacity-50",children:h?"Logging in…":"Login"})]})]})}function zp(...a){return a.filter(Boolean).join(" ")}function Ej(a){const l=a?.batteryState?.percentDisplay;return l==null?"--":`${l}%`}function Cj(a){return a?.batteryState?a.batteryState.urgentActive?"text-red-400":a.batteryState.warnActive?"text-amber-300":"text-emerald-300":"text-slate-400"}function qj({title:a,roster:l=[],emptyText:i="No roster data.",renderActions:o=null}){return r.jsxs("div",{className:"space-y-0.5 text-sm",children:[a&&r.jsx("p",{className:"text-sm text-slate-400",children:a}),l.length===0?r.jsx("p",{className:"text-sm text-slate-500",children:i}):r.jsx("ul",{className:"space-y-0.5 text-sm",children:l.map(f=>r.jsxs("li",{className:zp("surface flex flex-wrap items-center justify-between gap-0.5",f.locked&&"bg-red-900/40"),children:[r.jsxs("div",{children:[r.jsx("p",{className:"text-slate-200",children:f.name}),r.jsxs("p",{className:"text-xs text-slate-500 flex flex-wrap items-center gap-0.5",children:[r.jsx("span",{children:f.locked?"locked":"free"}),f.lockReason&&r.jsx("span",{className:"rounded bg-black/30 px-1",children:f.lockReason}),r.jsxs("span",{className:zp("font-semibold",Cj(f)),children:["Battery ",Ej(f)]})]})]}),o?o(f):null]},f.id))})]})}const Mj=[{key:"open",label:"Open"},{key:"turns",label:"Turns"},{key:"admin",label:"Admin"},{key:"lockdown",label:"Lockdown"}];function kj(){const{session:a,lockRover:l,setMode:i,requestControl:o,setCommunityGoal:f,setAdminReason:d,rebootRover:h,rebootServer:p,adminLogs:g,llmCommentaryStatus:v}=Ve(),y=m.useMemo(()=>a?.roster??[],[a?.roster]),[b,j]=m.useState({}),[M,w]=m.useState({}),[q,N]=m.useState(!1),E=a?.health||null,S=a?.communityGoal?.text||"",T=a?.communityGoal?.updatedAt||null,[z,L]=m.useState(S),$=a?.adminReason?.text||"",O=a?.adminReason?.updatedAt||null,[V,X]=m.useState($),Z=a?.role==="admin"||a?.role==="lockdown"||a?.role==="lockdown-admin",F=a?.mode??"open",ae=async(_,W)=>{try{await l(_,W),j(te=>({...te,[_]:W}))}catch(te){alert(te.message)}},oe=async _=>{const W=_.target.value;try{await i(W)}catch(te){alert(te.message)}},me=async _=>{try{await o(_,{force:!0})}catch(W){alert(W.message)}},G=async _=>{if(!(!_?.id||!window.confirm(`Reboot rover "${_.name||_.id}" now?`))){w(te=>({...te,[_.id]:!0}));try{await h(_.id)}catch(te){alert(te.message)}finally{w(te=>({...te,[_.id]:!1}))}}},k=async()=>{if(window.confirm("Reboot the server host now? This will disconnect all users.")){N(!0);try{await p()}catch(W){alert(W.message),N(!1)}}},Q=async()=>{try{await f(z)}catch(_){alert(_.message)}},P=async()=>{try{await f(null)}catch(_){alert(_.message)}},re=async()=>{try{await d(V)}catch(_){alert(_.message)}},ce=async()=>{try{await d(null)}catch(_){alert(_.message)}};m.useEffect(()=>{L(S)},[S]),m.useEffect(()=>{X($)},[$]);const C=m.useMemo(()=>{const _={};return y.forEach(W=>{_[W.id]=b[W.id]??W.locked}),_},[y,b]);return Z?r.jsxs("section",{className:"panel-section space-y-0.5 text-base",children:[r.jsxs("div",{className:"flex items-center justify-between gap-0.5 text-sm",children:[r.jsx("span",{children:"Admin controls"}),r.jsx("select",{value:F,onChange:oe,className:"field-input text-sm",children:Mj.map(_=>r.jsx("option",{value:_.key,children:_.label},_.key))})]}),r.jsx("div",{className:"flex gap-0.5 text-xs",children:r.jsx("button",{type:"button",onClick:k,disabled:q,className:"button-danger disabled:cursor-not-allowed disabled:opacity-60",children:q?"Server rebooting...":"Reboot Server"})}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-400",children:[r.jsx("span",{children:"Community goal"}),T?r.jsxs("span",{children:["Updated ",new Date(T).toLocaleString()]}):null]}),r.jsx("input",{type:"text",value:z,onChange:_=>L(_.target.value),placeholder:"Set a community goal",className:"field-input text-sm"}),r.jsxs("div",{className:"flex gap-0.5 text-xs",children:[r.jsx("button",{type:"button",onClick:Q,className:"button-dark",children:"Set goal"}),r.jsx("button",{type:"button",onClick:P,className:"button-danger",children:"Clear"})]})]}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-400",children:[r.jsx("span",{children:"Admin mode reason"}),O?r.jsxs("span",{children:["Updated ",new Date(O).toLocaleString()]}):null]}),r.jsx("textarea",{value:V,onChange:_=>X(_.target.value),placeholder:"Set an admin mode reason",className:"field-input text-sm min-h-[3.5rem]"}),r.jsxs("div",{className:"flex gap-0.5 text-xs",children:[r.jsx("button",{type:"button",onClick:re,className:"button-dark",children:"Set reason"}),r.jsx("button",{type:"button",onClick:ce,className:"button-danger",children:"Clear"})]})]}),r.jsx(qj,{roster:y,renderActions:_=>r.jsxs("div",{className:"flex flex-wrap gap-0.5 text-xs",children:[r.jsx("button",{type:"button",onClick:()=>ae(_.id,!C[_.id]),className:"button-dark",children:C[_.id]?"Unlock":"Lock"}),r.jsx("button",{type:"button",onClick:()=>me(_.id),className:"button-dark",children:"Force"}),r.jsx("button",{type:"button",onClick:()=>G(_),disabled:!!M[_.id],className:"button-danger disabled:cursor-not-allowed disabled:opacity-60",children:M[_.id]?"Rebooting...":"Reboot"})]})}),r.jsx(Tj,{health:E}),r.jsx(Rj,{status:v}),r.jsx(Dj,{entries:g})]}):null}function Rj({status:a}){if(!a)return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),r.jsx("div",{className:"surface text-xs text-slate-300",children:"No status received yet."})]});const l=a.lastTickAt?new Date(a.lastTickAt).toLocaleString():"never",i=a.nextRunAt?new Date(a.nextRunAt).toLocaleString():"n/a",o=a.lastPostedAt?new Date(a.lastPostedAt).toLocaleString():"never",f=a.lastSnapshotSummary||{},d=a.lastOutcome==="failed"?"text-red-300":a.lastOutcome==="posted"?"text-emerald-300":"text-slate-300";return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),r.jsxs("div",{className:"surface space-y-0.5 text-xs text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Enabled"}),r.jsx("span",{children:a.enabled?"yes":"no"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Running"}),r.jsx("span",{children:a.running?"yes":"no"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"In flight"}),r.jsx("span",{children:a.inFlight?"yes":"no"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Model"}),r.jsx("span",{className:"text-slate-300",children:a.model||"--"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Server"}),r.jsx("span",{className:"text-slate-300",children:a.ollamaUrl||"--"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Frequency"}),r.jsxs("span",{children:[a.frequencyMs," ms"]})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Tick count"}),r.jsx("span",{children:a.tickCount??0})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Last outcome"}),r.jsx("span",{className:d,children:a.lastOutcome||"--"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Last reason"}),r.jsx("span",{className:"text-slate-300",children:a.lastReason||"--"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Last tick"}),r.jsx("span",{className:"text-slate-300",children:l})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Next run"}),r.jsx("span",{className:"text-slate-300",children:i})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Last posted"}),r.jsx("span",{className:"text-slate-300",children:o})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Prompt chars"}),r.jsx("span",{children:a.lastPromptChars??0})]})]}),r.jsxs("div",{className:"surface space-y-0.5 text-xs text-slate-300",children:[r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Snapshot active drivers"}),r.jsx("span",{children:f.activeDrivers??0})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Snapshot rovers"}),r.jsx("span",{children:f.rovers??0})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Snapshot chat msgs"}),r.jsx("span",{children:f.chatMessages??0})]})]}),a.lastError?r.jsxs("div",{className:"surface text-xs text-red-300 break-words",children:["Error: ",a.lastError]}):null,a.lastGeneratedText?r.jsxs("div",{className:"surface text-xs text-slate-200 break-words",children:["Generated: ",a.lastGeneratedText]}):null,a.lastPostedText?r.jsxs("div",{className:"surface text-xs text-emerald-200 break-words",children:["Posted: ",a.lastPostedText]}):null]})}function Tj({health:a}){if(!a)return null;const l=a.replay||{sources:[],readyCount:0,totalCount:0},i=a.snapshots||{rovers:[],rooms:[]},o=`${l.readyCount}/${l.totalCount} sources ready`,f=i.rovers.filter(h=>h.stale).length,d=i.rooms.filter(h=>h.stale).length;return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"Health"}),r.jsxs("div",{className:"surface space-y-0.5 text-xs text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Replay segments"}),r.jsx("span",{className:"text-slate-400",children:o})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Rover snapshots"}),r.jsxs("span",{className:f?"text-amber-300":"text-emerald-300",children:[i.rovers.length-f,"/",i.rovers.length," ok"]})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Room cameras"}),r.jsxs("span",{className:d?"text-amber-300":"text-emerald-300",children:[i.rooms.length-d,"/",i.rooms.length," ok"]})]})]}),r.jsx("div",{className:"space-y-0.5 text-xs text-slate-300",children:l.sources.map(h=>r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:h.label}),r.jsxs("span",{className:h.ready?"text-emerald-300":"text-amber-300",children:[h.recentCount,"/",h.neededCount]})]},`${h.type}:${h.id}`))}),r.jsx("div",{className:"space-y-0.5 text-xs text-slate-300",children:i.rovers.map(h=>r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:h.name}),r.jsx("span",{className:h.stale?"text-amber-300":"text-emerald-300",children:h.stale?"stale":"ok"})]},`rover:${h.id}`))}),r.jsx("div",{className:"space-y-0.5 text-xs text-slate-300",children:i.rooms.map(h=>r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:h.name}),r.jsx("span",{className:h.stale?"text-amber-300":"text-emerald-300",children:h.error?"error":h.stale?"stale":"ok"})]},`room:${h.id}`))})]})}function Dj({entries:a}){const l=a||[];return r.jsxs("div",{className:"panel-section space-y-0.5 text-base",children:[r.jsxs("div",{className:"flex items-center justify-between text-sm text-slate-400",children:[r.jsx("span",{children:"Admin IP log"}),r.jsx("span",{children:l.length})]}),r.jsx("div",{className:"surface h-64 overflow-y-auto font-mono text-xs",children:l.length===0?r.jsx("p",{children:"No admin log entries yet."}):l.slice().reverse().map(i=>r.jsxs("div",{className:"surface",children:[r.jsx("span",{className:"text-amber-400",children:i.ts?new Date(i.ts).toLocaleTimeString():"--"})," ",i.label&&r.jsxs("span",{className:"text-teal-400",children:["[",i.label,"]"]})," ",r.jsx("span",{className:"text-slate-200",children:i.message})," ",i.ip&&r.jsx("span",{className:"text-cyan-300",children:i.ip})," ",i.meta&&r.jsx("span",{className:"text-slate-500",children:JSON.stringify(i.meta)})]},i.id))}),r.jsx("p",{className:"text-xs text-slate-500",children:"Admin-only log stream; IPs never appear in user data."})]})}const _j=[{id:"driveForward",label:"Drive Forward",group:"Driving"},{id:"driveBackward",label:"Drive Backward",group:"Driving"},{id:"driveLeft",label:"Turn Left",group:"Driving"},{id:"driveRight",label:"Turn Right",group:"Driving"},{id:"boostModifier",label:"Boost Modifier",group:"Driving"},{id:"slowModifier",label:"Slow Modifier",group:"Driving"},{id:"auxMainForward",label:"Main Brush Forward",group:"Aux Motors"},{id:"auxMainReverse",label:"Main Brush Reverse",group:"Aux Motors"},{id:"auxSideForward",label:"Side Brush Forward",group:"Aux Motors"},{id:"auxSideReverse",label:"Side Brush Reverse",group:"Aux Motors"},{id:"auxVacuumFast",label:"Vacuum Max",group:"Aux Motors"},{id:"auxVacuumSlow",label:"Vacuum Low",group:"Aux Motors"},{id:"auxAllForward",label:"All Aux Forward",group:"Aux Motors"},{id:"cameraUp",label:"Camera Up",group:"Camera"},{id:"cameraDown",label:"Camera Down",group:"Camera"},{id:"nightVisionToggle",label:"Toggle Night Vision",group:"Camera"},{id:"hornHonk",label:"Horn (Hold)",group:"Audio"},{id:"driveMacro",label:"Drive Macro",group:"Macros"},{id:"dockMacro",label:"Dock Macro",group:"Macros"},{id:"chatFocus",label:"Toggle Chat",group:"Chat"},{id:"songNoteUp",label:"Song Note Up",group:"Audio"},{id:"songNoteDown",label:"Song Note Down",group:"Audio"},{id:"homeAssistantOn",label:"Room Controls On (Cycle)",group:"Room Controls"},{id:"homeAssistantOff",label:"Room Controls Off (Cycle)",group:"Room Controls"}];function Oj(a){return a.reduce((l,i)=>((l[i.group]||(l[i.group]=[])).push(i),l),{})}function Bj(a,l){const i=Number(a);return Number.isFinite(i)?Math.max(0,Math.min(500,i)):l}const Kf=5,ui=500,fi=1,Ff=100;function zj(a,l){const i=Number(a);return Number.isFinite(i)?Math.max(Kf,Math.min(ui,i)):l}function Fr(a,l){const i=Number(a);return Number.isFinite(i)?Math.max(fi,Math.min(Ff,i)):l}function Lj(a){const i=(Fr(a,a)-fi)/(Ff-fi),o=ui-i*(ui-Kf);return Math.round(o)}function Uj(a){const l=zj(a,a),i=(ui-l)/(ui-Kf),o=fi+i*(Ff-fi);return Math.round(o)}function Hj(a){const[l,i]=m.useState(null);return m.useEffect(()=>{if(!l)return;function o(f){if(f.preventDefault(),f.key==="Escape"){i(null);return}const d=xi(f.key??"");d&&(a(l,d,f),i(null))}return window.addEventListener("keydown",o,{capture:!0}),()=>window.removeEventListener("keydown",o,{capture:!0})},[l,a]),{active:l,startCapture:i,cancel:()=>i(null)}}function Lr({label:a,description:l,value:i,onChange:o,min:f=0,max:d=500,step:h=5}){return r.jsxs("label",{className:"surface-muted block p-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-300",children:[r.jsx("span",{className:"font-semibold text-slate-100",children:a}),r.jsx("input",{type:"number",min:f,max:d,value:i,onChange:p=>o(p.target.value),className:"w-16 rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-right text-[0.75rem] font-mono text-slate-100"})]}),l&&r.jsx("p",{className:"text-[0.65rem] text-slate-500",children:l}),r.jsxs("div",{className:"mt-0 flex items-center gap-0.5",children:[r.jsx("input",{type:"range",min:f,max:d,step:h,value:i,onChange:p=>o(p.target.value),className:"h-2 flex-1 accent-emerald-400"}),r.jsx("span",{className:"w-12 text-right text-[0.75rem] font-mono text-slate-400",children:i})]})]})}function Vj(){const{state:{keymap:a},actions:{updateKeyBinding:l,resetKeyBindings:i}}=Dt(),{value:o,save:f}=st("inputs",Sn),d={...Sn.keyboard,...o.keyboard??{}},h=m.useMemo(()=>typeof d.tiltSpeed=="number"?Fr(d.tiltSpeed,Sn.keyboard.tiltSpeed):typeof d.tiltIntervalMs=="number"?Fr(Uj(d.tiltIntervalMs),Sn.keyboard.tiltSpeed):Sn.keyboard.tiltSpeed,[d.tiltIntervalMs,d.tiltSpeed]),p=m.useMemo(()=>Oj(_j),[]),{active:g,startCapture:v,cancel:y}=Hj((w,q)=>{l(w,q)}),b=m.useCallback(w=>a?.[w]?.[0]||ni[w]?.[0]||"",[a]),j=m.useCallback((w,q)=>{const N=Sn.keyboard,E=Bj(q,N[w]);f(S=>({...S??{},keyboard:{...S?.keyboard??N,[w]:E}}))},[f]),M=m.useCallback(w=>{const q=Sn.keyboard,N=Fr(w,q.tiltSpeed),E=Lj(N);f(S=>({...S??{},keyboard:{...S?.keyboard??q,tiltSpeed:N,tiltIntervalMs:E}}))},[f]);return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsxs("div",{children:[r.jsx("p",{className:"text-xs text-slate-400",children:"Keyboard layout"}),r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Per-browser · click to change a binding"})]}),r.jsx("button",{type:"button",onClick:()=>i(),className:"button-dark text-xs",children:"Reset defaults"})]}),r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Keyboard speeds"}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsx(Lr,{label:"Base speed",description:"Normal driving speed",value:d.baseSpeed,onChange:w=>j("baseSpeed",w)}),r.jsx(Lr,{label:"Turbo speed",description:"Used when holding the boost modifier",value:d.turboSpeed,onChange:w=>j("turboSpeed",w)}),r.jsx(Lr,{label:"Precision speed",description:"Used when holding the precision modifier",value:d.precisionSpeed,onChange:w=>j("precisionSpeed",w)})]})]}),r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Camera tilt"}),r.jsx(Lr,{label:"Tilt speed",description:"Higher = faster when holding tilt keys",value:h,onChange:M,min:1,max:100,step:1})]}),r.jsx("div",{className:"space-y-0.5",children:Object.entries(p).map(([w,q])=>r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.75rem] text-slate-400",children:w}),r.jsx("div",{className:"space-y-0.5",children:q.map(N=>{const E=b(N.id),S=g===N.id;return r.jsxs("div",{className:"surface-muted flex items-center justify-between text-xs",children:[r.jsxs("div",{children:[r.jsx("p",{className:"font-semibold text-slate-100",children:N.label}),r.jsx("p",{className:"text-[0.65rem] text-slate-400",children:An(E)})]}),r.jsxs("div",{className:"flex items-center gap-0.5",children:[S&&r.jsx("button",{type:"button",onClick:()=>y(),className:"button-danger text-[0.7rem]",children:"Cancel"}),r.jsx("button",{type:"button",onClick:()=>v(N.id),className:`${S?"px-0.5 py-0.5 bg-emerald-500 text-emerald-950 hover:bg-emerald-400":"button-dark"} text-[0.7rem] font-medium transition-colors`,children:S?"Press a key…":"Change"})]})]},N.id)})})]},w))})]})}const Kn=new Intl.NumberFormat(void 0,{maximumFractionDigits:2}),Yj=[{id:"drive",label:"Drive stick",kind:"axisPair",section:"Driving",invertDefaults:{invertX:!1,invertY:!0}},{id:"cameraTilt",label:"Camera tilt",kind:"axis",section:"Camera",invertDefaults:{invert:!0}},{id:"mainBrush",label:"Main brush",kind:"axis",section:"Brushes",invertDefaults:{invert:!1}},{id:"sideBrush",label:"Side brush",kind:"axis",section:"Brushes",invertDefaults:{invert:!1}},{id:"vacuum",label:"Vacuum",kind:"button",section:"Aux buttons"},{id:"allAux",label:"All aux",kind:"button",section:"Aux buttons"},{id:"mainReverse",label:"Main reverse toggle",kind:"button",section:"Brush toggles"},{id:"sideReverse",label:"Side reverse toggle",kind:"button",section:"Brush toggles"},{id:"driveMacro",label:"Drive macro",kind:"button",section:"Mode macros"},{id:"dockMacro",label:"Dock macro",kind:"button",section:"Mode macros"},{id:"nightVisionToggle",label:"Night vision toggle",kind:"button",section:"Camera"}],Lp=.45,$j=.6;function Ps({label:a,description:l,min:i,max:o,step:f,value:d,onChange:h}){return r.jsxs("label",{className:"surface-muted block p-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-300",children:[r.jsx("span",{className:"font-semibold text-slate-100",children:a}),r.jsx("span",{className:"font-mono text-slate-400",children:Kn.format(d)})]}),l&&r.jsx("p",{className:"text-[0.65rem] text-slate-500",children:l}),r.jsx("input",{type:"range",min:i,max:o,step:f,value:d,onChange:p=>h(Number(p.target.value)),className:"mt-0 w-full accent-emerald-400"})]})}function Gj(a){if(!a)return"Unassigned";if(a.kind==="axisPair"){const l=`${a.invertX?"X inv ":""}${a.invertY?"Y inv":""}`.trim();return`Axes ${a.x}/${a.y}${l?` (${l})`:""}`}if(a.kind==="axis")return`Axis ${a.index}${a.invert?" (inv)":""}`;if(a.kind==="button")return`Button ${a.index}`;if(a.kind==="buttonAxis")return`Button ${a.index} (analog)`;if(a.kind==="axisButton"){const l=a.direction<0?"<":">";return`Axis ${a.index} ${l} ${Kn.format(a.threshold??.6)}`}return"Unassigned"}function Xj(a){return a.reduce((l,i)=>((l[i.section]||(l[i.section]=[])).push(i),l),{})}function Qj(a,l){if(!a||a.length===0)return null;if(l){const i=a.find(o=>o.signature===l);if(i)return i}return a[0]}function Kj(a){return{axes:Array.from(a.axes??[]),buttons:(a.buttons??[]).map(l=>({pressed:!!l?.pressed,value:typeof l?.value=="number"?l.value:l?.pressed?1:0}))}}function Fj(a,l,i){const o=(a.axes??[]).map((d,h)=>({index:h,delta:Math.abs((d??0)-(l.axes?.[h]??0)),value:d}));if(o.sort((d,h)=>h.delta-d.delta),i.kind==="axisPair"){const d=o.filter(h=>h.delta>Lp).slice(0,2);return d.length<2?null:{kind:"axisPair",x:d[0].index,y:d[1].index,...i.invertDefaults??{}}}const f=o.find(d=>d.delta>Lp);return f?{kind:"axis",index:f.index,...i.invertDefaults??{}}:null}function Zj(a,l,i){const o=a.buttons??[];for(let d=0;d$j)return i.kind==="axis"?{kind:"buttonAxis",index:d}:{kind:"button",index:d}}const f=a.axes??[];for(let d=0;d.7&&p>.5)return i.kind==="axis"?{kind:"axis",index:d,...i.invertDefaults??{}}:{kind:"axisButton",index:d,direction:h>=0?1:-1,threshold:.6}}return null}function Jj(a,l,i){if(!a)return null;if(i.kind==="axis"||i.kind==="axisPair"){const o=Fj(a,l,i);if(o)return o}return Zj(a,l,i)}function Ij(){const a=qA(),{value:l,save:i}=st("gamepad",ja),[o,f]=m.useState(null),d=m.useRef(null),h=m.useMemo(()=>Xj(Yj),[]),p=m.useMemo(()=>Qj(a.pads,l.activeSignature),[a.pads,l.activeSignature]),g=p?.signature??null,v=m.useMemo(()=>g?l?.profiles?.[g]??l?.defaults?.profile??Fn:l?.defaults?.profile??Fn,[g,l?.defaults?.profile,l?.profiles]);m.useEffect(()=>{!p||!g||l?.profiles?.[g]||i(N=>{const E=N??ja;if(E.profiles?.[g])return E;const S=E?.defaults?.profile??Fn,T=Gx(p,S);return{...E,profiles:{...E.profiles??{},[g]:T}}})},[p,g,l?.profiles,i]),m.useEffect(()=>{d.current=null},[o,g]),m.useEffect(()=>{if(!o||!p)return;if(!d.current){d.current=Kj(p);return}const N=Jj(p,d.current,o);N&&(i(E=>{const S=E??ja,T=S.profiles?.[g]??S?.defaults?.profile??Fn,z={...T,bindings:{...T.bindings??{},[o.id]:{...T.bindings?.[o.id]??{},kind:o.kind,sources:[N]}}};return{...S,profiles:{...S.profiles??{},[g]:z}}}),f(null))},[p,g,o,i]);const y=m.useCallback(N=>{i(E=>({...E??ja,activeSignature:N||null}))},[i]),b=m.useCallback(N=>{i(E=>{const S=E??ja,T=(g&&S.profiles?.[g])??S?.defaults?.profile??Fn,z={...T,calibration:{...T.calibration??{},...N}};return g?{...S,profiles:{...S.profiles??{},[g]:z}}:{...S,defaults:{...S.defaults??{},profile:z}}})},[g,i]),j=m.useCallback((N,E)=>{i(S=>{const T=S??ja,z=(g&&T.profiles?.[g])??T?.defaults?.profile??Fn,L=E(z.bindings?.[N]??{}),$={...z,bindings:{...z.bindings??{},[N]:L}};return g?{...T,profiles:{...T.profiles??{},[g]:$}}:{...T,defaults:{...T.defaults??{},profile:$}}})},[g,i]),M=m.useCallback(N=>{j(N.id,E=>({...E,sources:[]}))},[j]),w=m.useCallback((N,E)=>{j(N.id,S=>{const T=Array.isArray(S.sources)?[...S.sources]:[];if(!T[0])return S;const z={...T[0]};return E==="invertX"?z.invertX=!z.invertX:E==="invertY"?z.invertY=!z.invertY:z.invert=!z.invert,T[0]=z,{...S,sources:T}})},[j]),q=m.useMemo(()=>p?{outputs:Xx(p,v)}:null,[p,v]);return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("div",{className:"flex items-center justify-between",children:r.jsxs("div",{children:[r.jsx("p",{className:"text-xs text-slate-400",children:"Controller"}),r.jsx("p",{className:"text-[0.65rem] text-slate-500",children:p?"Move sticks or press buttons to bind":"Connect a controller to configure."}),o&&r.jsxs("p",{className:"mt-0 text-[0.7rem] text-emerald-400",children:["Capturing ",o.label,"…"]})]})}),r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Connected controller"}),a.pads.length===0?r.jsx("p",{className:"text-[0.7rem] text-slate-400",children:"No controller detected."}):r.jsxs("div",{className:"flex items-center justify-between gap-0.5 text-xs",children:[r.jsx("select",{value:g??"",onChange:N=>y(N.target.value),className:"flex-1 rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-[0.75rem] text-slate-100",children:a.pads.map(N=>r.jsx("option",{value:N.signature,children:N.id||"Unknown controller"},N.signature))}),r.jsx("span",{className:"text-[0.7rem] text-slate-400",children:p?.mapping??"unknown"})]})]}),r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Calibration"}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsx(Ps,{label:"Drive deadzone",description:"Ignore small drive stick drift",min:0,max:.6,step:.01,value:v.calibration?.driveDeadzone??.18,onChange:N=>b({driveDeadzone:N})}),r.jsx(Ps,{label:"Camera deadzone",description:"Ignore small camera tilt drift",min:0,max:.4,step:.01,value:v.calibration?.cameraDeadzone??.08,onChange:N=>b({cameraDeadzone:N})}),r.jsx(Ps,{label:"Aux deadzone",description:"Ignore small trigger noise",min:0,max:.4,step:.01,value:v.calibration?.auxDeadzone??.05,onChange:N=>b({auxDeadzone:N})}),r.jsx(Ps,{label:"Side brush scale",description:"Scale side brush output",min:.3,max:1,step:.05,value:v.calibration?.auxSideScale??.55,onChange:N=>b({auxSideScale:N})}),r.jsxs("label",{className:"surface-muted block p-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-300",children:[r.jsx("span",{className:"font-semibold text-slate-100",children:"Camera mode"}),r.jsxs("select",{value:v.calibration?.cameraMode??"absolute",onChange:N=>b({cameraMode:N.target.value}),className:"rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-[0.75rem] text-slate-100",children:[r.jsx("option",{value:"absolute",children:"Absolute"}),r.jsx("option",{value:"velocity",children:"Velocity"})]})]}),r.jsx("p",{className:"text-[0.65rem] text-slate-500",children:"Absolute maps stick to angle; velocity moves over time."})]}),r.jsx(Ps,{label:"Camera sensitivity",description:"Velocity mode degrees per second",min:10,max:180,step:5,value:v.calibration?.cameraSensitivity??60,onChange:N=>b({cameraSensitivity:N})})]})]}),r.jsx("div",{className:"space-y-0.5",children:Object.entries(h).map(([N,E])=>r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:N}),r.jsx("div",{className:"space-y-0.5",children:E.map(S=>{const z=v.bindings?.[S.id]?.sources?.[0]??null;return r.jsxs("div",{className:"surface-muted flex items-center justify-between text-xs",children:[r.jsxs("div",{children:[r.jsx("p",{className:"font-semibold text-slate-100",children:S.label}),r.jsx("p",{className:"text-[0.65rem] text-slate-400",children:Gj(z)})]}),r.jsxs("div",{className:"flex items-center gap-0.5",children:[S.kind==="axisPair"&&r.jsxs(r.Fragment,{children:[r.jsx("button",{type:"button",disabled:!z,onClick:()=>w(S,"invertX"),className:"button-dark text-[0.7rem] font-medium disabled:opacity-50",children:"Invert X"}),r.jsx("button",{type:"button",disabled:!z,onClick:()=>w(S,"invertY"),className:"button-dark text-[0.7rem] font-medium disabled:opacity-50",children:"Invert Y"})]}),S.kind==="axis"&&r.jsx("button",{type:"button",disabled:!z,onClick:()=>w(S),className:"button-dark text-[0.7rem] font-medium disabled:opacity-50",children:"Invert"}),r.jsx("button",{type:"button",onClick:()=>M(S),className:"button-dark text-[0.7rem]",children:"Clear"}),r.jsx("button",{type:"button",onClick:()=>f(S),className:`${o?.id===S.id?"px-0.5 py-0.5 bg-emerald-500 text-emerald-950 hover:bg-emerald-400":"button-dark"} text-[0.7rem] font-medium`,children:o?.id===S.id?"Waiting…":"Capture"})]})]},S.id)})})]},N))}),r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Diagnostics"}),p?r.jsxs("div",{className:"space-y-0.5 text-[0.7rem] text-slate-300",children:[r.jsx("p",{className:"text-slate-400",children:"Raw axes"}),r.jsx("div",{className:"grid grid-cols-2 gap-0.5",children:p.axes.map((N,E)=>r.jsxs("span",{className:"font-mono text-slate-300",children:["A",E,": ",Kn.format(N)]},`axis-${E}`))}),r.jsx("p",{className:"text-slate-400",children:"Raw buttons"}),r.jsx("div",{className:"grid grid-cols-2 gap-0.5",children:p.buttons.map((N,E)=>r.jsxs("span",{className:"font-mono text-slate-300",children:["B",E,": ",Kn.format(N.value)," ",N.pressed?"●":""]},`btn-${E}`))}),q?.outputs&&r.jsxs(r.Fragment,{children:[r.jsx("p",{className:"text-slate-400",children:"Mapped outputs"}),r.jsxs("div",{className:"grid grid-cols-2 gap-0.5",children:[r.jsxs("span",{className:"font-mono text-slate-300",children:["Drive: ",Kn.format(q.outputs.driveVector.x),","," ",Kn.format(q.outputs.driveVector.y)]}),r.jsxs("span",{className:"font-mono text-slate-300",children:["Camera: ",Kn.format(q.outputs.cameraAxis)]}),r.jsxs("span",{className:"font-mono text-slate-300",children:["Main: ",Kn.format(q.outputs.auxAxis.main)]}),r.jsxs("span",{className:"font-mono text-slate-300",children:["Side: ",Kn.format(q.outputs.auxAxis.side)]})]})]})]}):r.jsx("p",{className:"text-[0.7rem] text-slate-400",children:"No controller detected."})]})]})}const Wj={drive:"Drive wheels",aux:"Aux motors"};function Up(a){return Number.isFinite(a)?`${Math.round(a*100)}%`:"--"}function Pj({value:a,color:l="bg-emerald-500"}){const i=`${Math.round(Math.max(0,Math.min(1,a))*100)}%`;return r.jsx("div",{className:"h-2 w-full overflow-hidden rounded bg-slate-800",children:r.jsx("div",{className:`h-full ${l}`,style:{width:i}})})}function eN(){const{state:{roverId:a},overcurrentLimiter:l}=Dt(),i=m.useMemo(()=>Ql.map(o=>o.key),[]);return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-400",children:[r.jsx("span",{children:"Overcurrent limiter"}),r.jsx("span",{children:l?.adminImmune?"Admin immune":"Active"})]}),a?r.jsxs("div",{className:"space-y-0.5",children:[i.map(o=>{const f=l?.caps?.[o]?.cap??0,d=l?.overcurrent?.groups?.[o]??!1,h=l?.scales?.perGroup?.[o]??1;return r.jsxs("div",{className:"surface space-y-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs",children:[r.jsx("span",{className:"text-slate-200",children:Wj[o]||o}),r.jsx("span",{className:d?"text-red-300":"text-slate-400",children:d?"overcurrent":"ok"})]}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-[0.7rem] text-slate-400",children:[r.jsx("span",{children:"Cap"}),r.jsx("span",{children:Up(f)})]}),r.jsx(Pj,{value:f,color:"bg-amber-500"}),r.jsxs("div",{className:"flex items-center justify-between text-[0.7rem] text-slate-400",children:[r.jsx("span",{children:"Scale"}),r.jsx("span",{children:Up(h)})]})]})]},o)}),r.jsxs("div",{className:"surface text-[0.7rem] text-slate-400",children:[r.jsx("div",{children:`Down rate ${l?.config?.downRatePerSec}/s · Up rate ${l?.config?.upRatePerSec}/s`}),r.jsx("div",{children:`Release delay ${l?.config?.releaseDelaySec}s`}),r.jsx("div",{children:`Output rate ${l?.config?.outputRateMs}ms`})]})]}):r.jsx("p",{className:"text-xs text-slate-500",children:"Assign a rover to view limiter status."})]})}const og=m.createContext(null);function cg(){const a=m.useContext(og);if(!a)throw new Error("Tabs components must be used within a provider.");return a}const Hp={primary:{base:"flex-1 px-0.5 py-0.5 text-sm font-medium transition-colors focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-slate-500 rounded-md",active:"bg-sky-600 text-white",inactive:"bg-zinc-900 text-slate-300 hover:bg-sky-500 hover:text-white"}},ug="primary";function Zf(...a){return a.filter(Boolean).join(" ")}function Jf({children:a,defaultTab:l,currentTab:i,onTabChange:o,variant:f=ug}){const[d,h]=m.useState(l??null),[p,g]=m.useState([]),v=m.useCallback(M=>M?(g(w=>w.includes(M)?w:[...w,M]),()=>g(w=>w.includes(M)?w.filter(q=>q!==M):w)):()=>{},[]),y=i??d??p[0]??null;m.useEffect(()=>{l&&i===void 0&&h(l)},[l,i]);const b=m.useCallback(M=>{M&&(i===void 0&&h(M),o&&o(M))},[i,o]),j=m.useMemo(()=>({activeTab:y,setActiveTab:b,registerTab:v,variant:f}),[y,b,v,f]);return r.jsx(og.Provider,{value:j,children:a})}function If({children:a,className:l=""}){return r.jsx("div",{className:Zf("flex gap-0.5",l),children:a})}function mn({id:a,children:l,className:i="",disabled:o=!1}){const{activeTab:f,setActiveTab:d,registerTab:h,variant:p}=cg();m.useEffect(()=>h(a),[a,h]);const g=Hp[p]??Hp[ug],v=f===a,y=Zf(g.base,v?g.active:g.inactive,o?"cursor-not-allowed opacity-50":"",i);return r.jsx("button",{type:"button",className:y,onClick:()=>!o&&d(a),"aria-pressed":v,"aria-disabled":o,children:l})}function Wf({children:a,className:l=""}){return r.jsx("div",{className:Zf("mt-0 space-y-0.5",l),children:a})}function hn({id:a,children:l,keepMounted:i=!1}){const{activeTab:o}=cg(),f=o===a;return!f&&!i?null:!f&&i?r.jsx("div",{hidden:!0,"aria-hidden":"true",children:l}):r.jsx(r.Fragment,{children:l})}function tN(){const{session:a}=Ve(),l=m.useMemo(()=>JSON.stringify(a??{},null,2),[a]);return r.jsxs("div",{className:"panel-section flex min-h-0 flex-col gap-0.5 text-xs",children:[r.jsx("p",{className:"text-sm text-slate-400",children:"Session snapshot"}),r.jsx("pre",{className:"surface min-h-0 flex-1 overflow-y-auto font-mono text-[0.7rem] text-lime-300",children:l})]})}const Vp=300,Yp=240;function nN(a,l){if(a===void 0)return"undefined";if(a===null)return"null";if(typeof a=="string")return a;if(typeof a=="number"||typeof a=="boolean")return String(a);if(typeof a=="function")return"[Function]";if(a instanceof Error)return`${a.name}: ${a.message}`;if(a instanceof Date)return a.toISOString();if(l||(l=new WeakSet),typeof a=="object"){if(l.has(a))return"[Circular]";l.add(a)}try{return JSON.stringify(a,(i,o)=>typeof o=="function"?"[Function]":o instanceof Error?`${o.name}: ${o.message}`:o,0)}catch{return String(a)}}function aN(a){const i=a.map(o=>nN(o)).join(" ");return i.length>Yp?`${i.slice(0,Yp)}…`:i}function lN(){const a=En(),[l,i]=m.useState([]),o=m.useMemo(()=>l.reduce((f,d)=>(d.direction==="in"&&(f.in+=1),d.direction==="out"&&(f.out+=1),f),{in:0,out:0}),[l]);return m.useEffect(()=>{const f=(g,v,y)=>{i(b=>{const j=[...b,{id:`${Date.now()}-${Math.random().toString(16).slice(2)}`,direction:g,event:v,payload:aN(y),timestamp:new Date().toLocaleTimeString()}];return j.length>Vp?j.slice(-Vp):j})},d=(g,...v)=>f("in",g,v),h=(g,...v)=>f("out",g,v);a.onAny(d);let p=null;if(typeof a.onAnyOutgoing=="function")a.onAnyOutgoing(h),p=()=>a.offAnyOutgoing(h);else{const g=a.emit.bind(a);a.emit=(v,...y)=>(h(v,...y),g(v,...y)),p=()=>{a.emit=g}}return()=>{a.offAny(d),p&&p()}},[a]),r.jsxs("section",{className:"panel-section space-y-0.5 text-base",children:[r.jsxs("div",{className:"flex items-center justify-between text-sm text-slate-400",children:[r.jsx("span",{children:"Socket activity"}),r.jsxs("div",{className:"flex items-center gap-0.5 text-xs text-slate-400",children:[r.jsxs("span",{className:"surface-muted",children:["in ",o.in]}),r.jsxs("span",{className:"surface-muted",children:["out ",o.out]}),r.jsx("button",{type:"button",className:"button-dark text-xs",onClick:()=>i([]),children:"Clear"})]})]}),r.jsx("div",{className:"surface h-64 overflow-y-auto font-mono text-xs",children:l.length===0?r.jsx("p",{children:"No socket activity yet."}):l.slice().reverse().map(f=>r.jsxs("div",{className:"surface",children:[r.jsx("span",{className:"text-slate-400",children:f.timestamp})," ",r.jsxs("span",{className:f.direction==="in"?"text-emerald-400":"text-amber-400",children:["[",f.direction.toUpperCase(),"]"]})," ",r.jsx("span",{className:"text-cyan-300",children:f.event})," ",r.jsx("span",{className:"text-slate-200",children:f.payload})]},f.id))}),r.jsx("p",{className:"text-xs text-slate-500",children:"Logs are collected only while this panel is open."})]})}const sN=[{key:"start",label:"Start OI"},{key:"safe",label:"Safe"},{key:"full",label:"Full"},{key:"passive",label:"Passive"},{key:"dock",label:"Dock"}];function fg(){const{state:{roverId:a},actions:{sendOiCommand:l,setSensorStream:i}}=Dt(),o=!!a,[f,d]=lg(),h=En(),{value:p,save:g}=st("page",{hudMapDesktop:!1,connectionTransport:"websocket"}),{value:v,save:y}=st("audio",jt),b=p?.connectionTransport||"websocket",j=Number.isFinite(v?.masterVolume)?v.masterVolume:jt.masterVolume,M=Number.isFinite(v?.alertVolume)?v.alertVolume:jt.alertVolume,w=Number.isFinite(v?.roverVolume)?v.roverVolume:jt.roverVolume,q=typeof v?.mainBrushDuckEnabled=="boolean"?v.mainBrushDuckEnabled:typeof v?.autoLevelEnabled=="boolean"?v.autoLevelEnabled:jt.mainBrushDuckEnabled,N=Number.isFinite(v?.mainBrushDuckAmount)?Math.max(0,Math.min(1,v.mainBrushDuckAmount)):jt.mainBrushDuckAmount,E=m.useMemo(()=>[{key:"start",label:"Enable stream",enable:!0},{key:"stop",label:"Disable stream",enable:!1}],[]),S=$=>{a&&i($)},T=$=>{const O=$.target.value;g(V=>({...V??{},connectionTransport:O})),h?.io?.opts&&(h.io.opts.transports=O==="polling"?["polling"]:["websocket","polling"],h.disconnect(),h.connect())},z=$=>O=>{const V=Number(O.target.value),X=Number.isFinite(V)?Math.max(0,Math.min(1,V)):0;y(Z=>({...Z??{},[$]:X}))},L=$=>{const O=!!$.target.checked;y(V=>({...V??{},mainBrushDuckEnabled:O}))};return r.jsxs(Jf,{defaultTab:"keybindings",children:[r.jsxs(If,{children:[r.jsx(mn,{id:"keybindings",children:"Keybindings"}),r.jsx(mn,{id:"controller",children:"Controller"}),r.jsx(mn,{id:"page",children:"Page settings"}),r.jsx(mn,{id:"admin",children:"Admin"})]}),r.jsxs(Wf,{children:[r.jsx(hn,{id:"keybindings",children:r.jsx("div",{className:"space-y-0.5",children:r.jsx(Vj,{})})}),r.jsx(hn,{id:"controller",children:r.jsx("div",{className:"space-y-0.5",children:r.jsx(Ij,{})})}),r.jsx(hn,{id:"page",children:r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-slate-400",children:"HUD"}),r.jsxs("label",{className:"flex items-center gap-0.5 text-slate-200",children:[r.jsx("input",{type:"checkbox",className:"accent-emerald-500",checked:f,onChange:$=>d($.target.checked)}),r.jsx("span",{children:"Show top-down map in HUD (desktop)"})]}),r.jsx("p",{className:"text-xs text-slate-500",children:"Mobile HUD keeps the map on by default."})]}),r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-slate-400",children:"Audio"}),r.jsxs("label",{className:"grid gap-0.5 text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{children:"Master volume"}),r.jsxs("span",{className:"text-xs text-slate-400",children:[Math.round(j*100),"%"]})]}),r.jsx("input",{type:"range",min:"0",max:"1",step:"0.01",value:j,onChange:z("masterVolume"),className:"w-full accent-emerald-500"})]}),r.jsxs("label",{className:"grid gap-0.5 text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{children:"Alert/page sounds"}),r.jsxs("span",{className:"text-xs text-slate-400",children:[Math.round(M*100),"%"]})]}),r.jsx("input",{type:"range",min:"0",max:"1",step:"0.01",value:M,onChange:z("alertVolume"),className:"w-full accent-emerald-500"})]}),r.jsxs("label",{className:"grid gap-0.5 text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{children:"Rover audio"}),r.jsxs("span",{className:"text-xs text-slate-400",children:[Math.round(w*100),"%"]})]}),r.jsx("input",{type:"range",min:"0",max:"1",step:"0.01",value:w,onChange:z("roverVolume"),className:"w-full accent-emerald-500"})]}),r.jsxs("label",{className:"flex items-center justify-between gap-0.5 text-slate-200",children:[r.jsx("span",{children:"Main brush ducking"}),r.jsx("input",{type:"checkbox",className:"accent-emerald-500",checked:q,onChange:L})]}),r.jsxs("label",{className:"grid gap-0.5 text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{children:"Main brush duck amount"}),r.jsxs("span",{className:"text-xs text-slate-400",children:[Math.round(N*100),"%"]})]}),r.jsx("input",{type:"range",min:"0",max:"1",step:"0.01",value:N,onChange:z("mainBrushDuckAmount"),className:"w-full accent-emerald-500",disabled:!q})]}),r.jsx("p",{className:"text-xs text-slate-500",children:"Lowers rover audio only while the main brush is running."})]}),r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-slate-400",children:"Connection"}),r.jsxs("label",{className:"flex items-center justify-between gap-0.5 text-slate-200",children:[r.jsx("span",{children:"Transport"}),r.jsxs("select",{value:b,onChange:T,className:"field-input text-sm",children:[r.jsx("option",{value:"websocket",children:"WebSocket"}),r.jsx("option",{value:"polling",children:"Polling"})]})]}),r.jsx("p",{className:"text-xs text-slate-500",children:"Switching reconnects your session."})]})]})}),r.jsx(hn,{id:"admin",children:r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-slate-400",children:"Manual OI commands"}),r.jsx("div",{className:"surface flex flex-wrap gap-0.5",children:sN.map($=>r.jsx("button",{type:"button",onClick:()=>l($.key),disabled:!o,className:"button-dark text-xs disabled:opacity-30",children:$.label},$.key))})]}),r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-slate-400",children:"Sensor stream"}),r.jsx("div",{className:"surface flex gap-0.5",children:E.map($=>r.jsx("button",{type:"button",onClick:()=>S($.enable),disabled:!o,className:"flex-1 button-dark text-xs disabled:opacity-30",children:$.label},$.key))}),!o&&r.jsx("p",{className:"text-xs text-slate-500",children:"Assign a rover to toggle streams."})]}),r.jsx(rg,{}),r.jsx(eN,{}),r.jsx(kj,{}),r.jsx(tN,{}),r.jsx(lN,{})]})})]})]})}const $p={desktop:{main:[{type:"list",title:"Chat and nicknames",items:["Set a nickname in the user list panel, on the bottom left of the page below the rover video.",{segments:["Toggle chat focus with ",{action:"chatFocus"},". Press ",{action:"chatFocus"}," again to send."]}]},{type:"list",title:"Driving the rover",items:[{segments:['Press the "Start Driving" button onscreen, or press ',{action:"driveMacro"}," on your keyboard to put the rover into driving mode."]},"Refer to the controls for the controls for the rover."]},{type:"list",title:"Docking the rover",items:["Line up the rover to the dock, about a foot away, then:",{segments:['Press the "Dock and Charge" button onscreen, or press ',{action:"dockMacro"}," on your keyboard to start docking."]},"Wait for the rover to confirm it is docked and charging before leaving it unattended."]}],aside:[{type:"keyboard",title:"Keyboard controls",footnote:"Per-browser; adjust bindings and speeds in Settings → Keybindings.",groups:[{id:"movement",title:"Movement",items:[{action:"driveForward",label:"Forward"},{action:"driveBackward",label:"Backward"},{action:"driveLeft",label:"Turn left"},{action:"driveRight",label:"Turn right"},{action:"boostModifier",label:"Boost speed"},{action:"slowModifier",label:"Precision speed"}]},{id:"macros",title:"Rover modes & chat",items:[{action:"driveMacro",label:"Drive macro"},{action:"dockMacro",label:"Dock macro"},{action:"chatFocus",label:"Chat focus"}]},{id:"camera",title:"Camera",items:[{action:"cameraUp",label:"Tilt up"},{action:"cameraDown",label:"Tilt down"},{action:"nightVisionToggle",label:"Toggle night vision"}]},{id:"motors",title:"Rover Aux Motors",items:[{action:"auxMainForward",label:"Main brush forward"},{action:"auxMainReverse",label:"Main brush reverse"},{action:"auxSideForward",label:"Side brush forward"},{action:"auxSideReverse",label:"Side brush reverse"},{action:"auxVacuumFast",label:"Vacuum max"},{action:"auxVacuumSlow",label:"Vacuum low"},{action:"auxAllForward",label:"All motors forward"}]},{id:"audio",title:"Audio / Song",items:[{action:"songNoteUp",label:"Song note up"},{action:"songNoteDown",label:"Song note down"}]},{id:"room-controls",title:"Room Controls",items:[{action:"homeAssistantOn",label:"Next room control on"},{action:"homeAssistantOff",label:"Next room control off (reverse)"}]}]},{type:"gamepad",title:"Gamepad / joystick",items:["Gamepad controls are fully configurable to handle inconsistent browser mappings.","Use Settings → Controller to bind inputs, calibrate deadzones, and view diagnostics.","If inputs behave oddly, the diagnostics panel will show raw axis/button values."]}]},"mobile-portrait":{main:[{type:"list",title:"Chat and nicknames",items:["Set a nickname in the user list panel below.","Tap in the chat box to send messages in the chat."]},{type:"list",title:"Driving the rover",items:[{segments:['Press the "Start Driving" button onscreen to put the rover into driving mode.']},"Look below the rover video. Use the joystick on the right to move the rover, and hold the buttons on the left to run the aux motors."]},{type:"list",title:"Docking the rover",items:["Line up the rover to the dock, about a foot away, then:",{segments:['Press the "Dock and Charge" button onscreen to start docking.']},"Wait for the rover to confirm it is docked and charging before leaving it unattended."]}]},"mobile-landscape":{main:[{type:"list",title:"Chat and nicknames",items:["Scroll down to see more of the page.","Set a nickname in the user list panel below.","Tap in the chat box to send messages in the chat."]},{type:"list",title:"Driving the rover",items:[{segments:['Press the "Start Driving" button, or the "Drive" button to put the rover into driving mode.']},"Use the joystick to the right of the video feed to move the rover, and hold the buttons on the left to run the aux motors."]},{type:"list",title:"Docking the rover",items:["Line up the rover to the dock, about a foot away, then:",{segments:['Press the "Dock and Charge" or the "Dock" button onscreen to start docking.']},"Wait for the rover to confirm it is docked and charging before leaving it unattended."]}]}};function iN(a){return $p[a]||$p.desktop}function dg({actionId:a,keymap:l}){const i=l?.[a]?.[0]??"";return r.jsx("span",{className:"rounded border border-slate-600 bg-slate-900/40 px-1 text-[0.7rem] text-slate-200",children:An(i)})}function Gp(a,l){return a.map((i,o)=>typeof i=="string"?r.jsx("span",{children:i},`text-${o}`):i?.action?r.jsx(dg,{actionId:i.action,keymap:l},`pill-${i.action}-${o}`):i?.text?r.jsx("span",{children:i.text},`span-${o}`):null)}function oo(a,l,i){if(typeof a=="string")return a;if(Array.isArray(a?.segments))return Gp(a.segments,l);if(a&&typeof a=="object"){if(typeof a.text=="string")return a.text;if(Array.isArray(a))return Gp(a,l)}return String(a??"")}function rN({hero:a,keymap:l}){return a?r.jsxs("div",{className:"surface space-y-0.5 px-0.5 py-0.5",children:[r.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-0.5",children:[r.jsxs("div",{children:[r.jsx("p",{className:"text-sm font-semibold text-white",children:a.title}),a.subtitle&&r.jsx("p",{className:"text-xs text-slate-300",children:a.subtitle})]}),a.chips&&r.jsx("div",{className:"flex flex-wrap gap-0.5 text-[0.7rem] text-slate-200",children:a.chips.map(i=>r.jsx("span",{className:"rounded border border-slate-700 px-1 py-[2px]",children:i},i))})]}),a.bullets&&r.jsx("ul",{className:"space-y-0.5 text-[0.85rem] text-slate-200",children:a.bullets.map((i,o)=>{const f=Array.isArray(i?.segments)?`hero-${o}`:`hero-${o}`;return r.jsx("li",{className:"surface-muted px-0.5 py-0.25",children:oo(i,l)},f)})})]}):null}function oN({block:a,keymap:l}){return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("p",{className:"text-xs font-semibold text-slate-200",children:a.title}),r.jsx("ul",{className:"space-y-0.5 text-[0.8rem] text-slate-300",children:a.items.map((i,o)=>{const f=`item-${o}`;return r.jsx("li",{className:"surface-muted flex flex-wrap items-center gap-0.5 px-0.5 py-0.25",children:oo(i,l)},f)})})]})}function cN({block:a}){const l=a.tone==="info"?"border-cyan-500/40":"border-slate-700";return r.jsxs("div",{className:`surface space-y-0.5 border ${l} px-0.5 py-0.5`,children:[r.jsx("p",{className:"text-xs font-semibold text-slate-100",children:a.title}),a.body&&r.jsx("ul",{className:"space-y-0.5 text-[0.8rem] text-slate-300",children:a.body.map((i,o)=>r.jsx("li",{className:"surface-muted px-0.5 py-0.25",children:oo(i,{})},`callout-${o}`))})]})}function uN({group:a,keymap:l}){return r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"px-0.5 py-0.25 text-[0.75rem] font-semibold text-slate-200",children:a.title}),r.jsx("div",{className:"space-y-0.5 px-0.5 pb-0.25",children:a.items.map(i=>r.jsxs("div",{className:"surface-muted flex items-center justify-between gap-0.5 px-0.5 py-0.25 text-[0.8rem]",children:[r.jsx("span",{className:"text-slate-200",children:i.label}),r.jsx(dg,{actionId:i.action,keymap:l})]},i.action))})]})}function fN({block:a,keymap:l}){return a?r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-200",children:[r.jsx("span",{className:"font-semibold",children:a.title}),a.footnote&&r.jsx("span",{className:"text-[0.7rem] text-slate-400",children:a.footnote})]}),r.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-0.5",children:a.groups?.map(i=>r.jsx(uN,{group:i,keymap:l},i.id))})]}):null}function dN({block:a}){return a?r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("p",{className:"text-xs font-semibold text-slate-200",children:a.title}),r.jsx("ul",{className:"space-y-0.5 text-[0.8rem] text-slate-300",children:a.items?.map((l,i)=>r.jsx("li",{className:"surface-muted px-0.5 py-0.25",children:oo(l,{})},`gamepad-${i}`))})]}):null}function Xp({block:a,keymap:l}){if(!a)return null;switch(a.type){case"list":return r.jsx(oN,{block:a,keymap:l});case"callout":return r.jsx(cN,{block:a});case"keyboard":return r.jsx(fN,{block:a,keymap:l});case"gamepad":return r.jsx(dN,{block:a});default:return null}}function mg({layout:a,keymap:l}){const i=m.useMemo(()=>iN(a),[a]),o=l||{},f=i.main||[],d=i.aside||[];return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx(rN,{hero:i.hero,keymap:o}),r.jsxs("div",{className:"grid gap-0.5",style:{gridTemplateColumns:"repeat(auto-fit, minmax(360px, 1fr))"},children:[r.jsx("div",{className:"space-y-0.5",children:f.map((h,p)=>r.jsx(Xp,{block:h,keymap:o},h.title||p))}),r.jsx("div",{className:"space-y-0.5",children:d.map((h,p)=>r.jsx(Xp,{block:h,keymap:o},h.title||p))})]})]})}function hg({layout:a,onOpenOverlay:l}){const{state:i}=Dt();return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-400",children:[r.jsx("span",{children:"Help"}),r.jsx("button",{type:"button",onClick:l,className:"button-dark px-1 py-0.25 text-[0.75rem]",children:"Open full help"})]}),r.jsx(mg,{layout:a,keymap:i?.keymap||{}})]})}const mN=["kal","rms","slt","ksp","bdl"],hN=Array.from({length:10},(a,l)=>l*10);function co({hideInput:a=!1,hideSpectatorNotice:l=!1,fillHeight:i=!1,allowSpectatorInput:o=!1}){const{session:f}=Ve(),{messages:d,typing:h,sendMessage:p,registerInputRef:g,onInputFocus:v,onInputBlur:y,blurChat:b,setTypingActive:j}=Lf(),{value:M,save:w}=st("tts",{engine:"flite",voice:"rms",pitch:50}),[q,N]=m.useState(""),[E,S]=m.useState(!1),[T,z]=m.useState(!1),[L,$]=m.useState(()=>M?.engine||"flite"),[O,V]=m.useState(()=>M?.voice||"rms"),[X,Z]=m.useState(()=>Number.isFinite(M?.pitch)?M.pitch:50),F=f?.role!=="spectator"||o,ae=m.useRef(null),oe=f?.assignment?.roverId||null,G=!!m.useMemo(()=>f?.roster?.find(C=>String(C.id)===String(oe))||null,[oe,f?.roster])?.audio?.ttsEnabled,k=m.useMemo(()=>d.slice(-200),[d]),Q=m.useMemo(()=>h||[],[h]);m.useEffect(()=>{ae.current&&(ae.current.scrollTop=ae.current.scrollHeight)},[k,Q]),m.useEffect(()=>{const C=M?.engine||"flite",_=M?.voice||"rms",W=Number.isFinite(M?.pitch)?M.pitch:50;L!==C&&$(C),O!==_&&V(_),X!==W&&Z(W)},[L,X,M?.engine,M?.pitch,M?.voice,O]),m.useEffect(()=>{z(!!G)},[G]);const P=m.useMemo(()=>!G||!T?null:L==="espeak"?{speak:!0,engine:L,pitch:X}:{speak:!0,engine:L,voice:O},[L,X,T,G,O]);async function re(C){if(C.preventDefault(),!F||a)return;const W=q.replace(/\\n/g,` + `,document.head.appendChild(l)},[])}function cj(a,l){return typeof a=="string"&&a.trim()?a.trim().toLowerCase():typeof l=="string"&&l.trim()?l.trim().toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,""):""}function Xf({id:a,label:l,url:i,className:o=""}){if(!i)return null;oj();const f=cj(a,l),d=ij[f]||_S,h=rj[f]||null,p=l||a||"Link";return r.jsxs("a",{href:i,target:"_blank",rel:"noopener noreferrer","aria-label":p,className:`inline-flex items-center w-full px-0.5 py-0.5 text-sm font-medium text-white transition justify-center gap-1 rounded-md ${h?"":"bg-slate-700 hover:bg-slate-600"} ${o}`,style:h||void 0,children:[r.jsx(d,{className:"mr-0"}),p]})}const oi=10;function sg({batteryState:a=null,charge:l=null,config:i=null}){const o=a?.percentDisplay!=null&&Number.isFinite(a.percentDisplay)?Math.round(a.percentDisplay):null,f=a?.warnActive??null,d=a?.urgentActive??null,h=i?.Full??null,p=i?.Warn??null,g=i?.Urgent??null,v=l??a?.charge??null;let y=o;if(y==null&&(y=uj({charge:v,full:h,warn:p,urgent:g})),y==null)return{available:!1};const b=Math.max(0,Math.min(1,y/100)),j=f??(p!=null&&v!=null&&v<=p),M=d??(g!=null&&v!=null&&v<=g);return{available:!0,percent:b,percentDisplay:y,warnActive:j,urgentActive:M,warnDisplayPercent:oi}}function uj({charge:a,full:l,warn:i,urgent:o}){if(a!=null&&l!=null&&i!=null&&o!=null&&l>i&&i>o){const f=oi/100,d=1-f;if(a<=o)return 0;if(a<=i){const p=(a-o)/(i-o);return Math.round(Math.max(0,Math.min(1,p))*oi)}if(a>=l)return 100;const h=(a-i)/(l-i);return Math.round((f+Math.max(0,Math.min(1,h))*d)*100)}return null}const fj=1600,dj=800;function fn(...a){return a.filter(Boolean).join(" ")}function yf({visual:a,orientation:l="horizontal",variant:i="inline",compact:o=!1,showLabel:f,className:d=""}){const h=i==="background",p=l==="vertical",g=f??!h;if(!a?.available){if(h){const ae=oi,oe=fn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!j&&"battery-tick-warn"),me=p?{bottom:`${ae}%`}:{left:`${ae}%`},G=fn("absolute inset-0 pointer-events-none",d);return r.jsxs("div",{className:G,children:[r.jsx("div",{className:"absolute inset-0 bg-slate-900/35"}),r.jsx("div",{className:oe,style:me})]})}return p?null:r.jsx("p",{className:"text-xs text-slate-500",children:"Battery telemetry unavailable"})}const v=a.percentDisplay??0,y=Math.max(0,Math.min(100,v)),b=a.warnDisplayPercent??oi,j=!!a.urgentActive,M=!!a.warnActive,w=j?`${dj}ms`:M?`${fj}ms`:void 0,N=h?j||M?"bg-red-500/45":"bg-emerald-500/45":j||M?"bg-red-500":"bg-emerald-500",E=j||M?"bg-red-900/35":"bg-slate-900/35",S=j||M?"bg-red-900/45":"bg-slate-900/35",T=fn(h?"absolute inset-0 pointer-events-none":"relative pointer-events-auto",p&&!h?"flex flex-col items-center justify-center":"w-full",d);if(h){const ae=p?{height:`${y}%`}:{width:`${y}%`},oe=fn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",N,"transition-[width,height]",j&&"battery-urgent-flash"),me=fn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!j&&"battery-tick-warn"),G=p?{bottom:`${b}%`}:{left:`${b}%`};return r.jsxs("div",{className:T,children:[r.jsx("div",{className:fn("absolute inset-0",E,j&&"battery-urgent-flash")}),r.jsx("div",{className:oe,style:{...ae,animationDuration:w}}),r.jsx("div",{className:me,style:G})]})}const z=fn("relative overflow-hidden rounded-sm border border-slate-800",j||M?S:"bg-zinc-900/90",j&&"battery-urgent-flash",p?"w-full flex-1":o?"h-4":"h-5"),L=p?{height:`${y}%`}:{width:`${y}%`},$=fn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",N,"transition-[width,height]",j&&"battery-urgent-flash"),O=fn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!j&&"battery-tick-warn"),V=p?{bottom:`${b}%`}:{left:`${b}%`},X=`Battery ${v}%`,Z=fn("pointer-events-none absolute inset-0 flex items-center justify-center text-center font-semibold",p?o?"text-[0.55rem]":"text-[0.65rem]":"text-xs"),F=fn("rounded px-1.5 py-0.5",h?"bg-black/30 text-slate-100":"bg-black/50 text-slate-100");return r.jsxs("div",{className:T,children:[r.jsxs("div",{className:z,children:[r.jsx("div",{className:$,style:{...L,animationDuration:w}}),r.jsx("div",{className:O,style:V})]}),g&&!p?r.jsx("div",{className:Z,children:r.jsx("span",{className:F,children:X})}):null,g&&p?r.jsx("div",{className:"mt-0.5 text-[0.65rem] font-semibold text-slate-100",children:r.jsxs("span",{className:F,children:[v,"%"]})}):null]})}const Dp=2e3,mj=3e3,hj=3e3,pj=40,xj=1e3;function ci({sessionInfo:a,audioSessionInfo:l,videoMode:i="whep",snapshotFeed:o=null,qualityNotice:f=null,label:d,forceMute:h=!1,telemetryFrame:p,batteryConfig:g,layoutFormat:v="desktop",hudVariant:y="default",driverLabel:b=null,hudForceMap:j=!1,hudMapPosition:M="top-center",hudLabelScale:w=1,fitParent:q=!1,overcurrentLimiter:N=null,showTurnCue:E=!1,turnTimerText:S=null,turnSeconds:T=null,isActiveDriver:z=!1,idleSkipSeconds:L=null}){const{session:$}=Ve(),O=m.useRef(null),V=m.useRef(null),X=m.useRef(null),Z=m.useRef(null),F=m.useRef(null),ae=m.useRef(null),oe=m.useRef(null),me=m.useRef(null),[G,k]=m.useState("idle"),[Q,P]=m.useState(null),[re,ce]=m.useState("idle"),[C,_]=m.useState(null),[W,te]=m.useState(0),[le,ie]=m.useState(0),[ue,ve]=m.useState(!0),he=!!l?.url,Ce=i==="snapshot",ne=p?.sensors,{value:se}=st("audio",jt),Se=Number.isFinite(se?.masterVolume)?se.masterVolume:jt.masterVolume,Oe=Number.isFinite(se?.roverVolume)?se.roverVolume:jt.roverVolume,Ne=typeof se?.mainBrushDuckEnabled=="boolean"?se.mainBrushDuckEnabled:typeof se?.autoLevelEnabled=="boolean"?se.autoLevelEnabled:jt.mainBrushDuckEnabled,ze=Number.isFinite(se?.mainBrushDuckAmount)?Math.max(0,Math.min(1,se.mainBrushDuckAmount)):jt.mainBrushDuckAmount,an=Math.max(0,Math.min(1,Se*Oe)),wa=ne?.batteryChargeMah??null,Wn=v==="desktop",it=!Wn,ln=it?"top-right":M,[fo]=lg(),mo=j||it?!0:fo,mt=sg({charge:wa,config:g}),Pa=ne?.wheelOvercurrents||null,el=Pa==null?[]:Object.entries(Pa).filter(([,xe])=>!!xe).map(([xe])=>xe),sn=N?.caps||null,Ea=N?.overcurrent?.groups||null,gi=typeof window<"u"&&new URLSearchParams(window.location.search).has("debugAudio"),tl=typeof window<"u"&&new URLSearchParams(window.location.search).has("debugHud"),ho=m.useMemo(()=>{if(!sn)return null;const xe=Number.isFinite(sn?.drive?.cap)?sn.drive.cap:1,Xe=Number.isFinite(sn?.aux?.cap)?sn.aux.cap:1;return Math.max(0,Math.min(1,1-Math.min(xe,Xe)))},[sn]),ts=!!N?.isActive,rn=el.length?el:ts?["limiter"]:[],pt=ho??(el.length?1:0),Yt=!!rn.length,rt=!!((Number(ne?.mainBrushCurrentMa)||0)>pj||ne?.wheelOvercurrents?.mainBrush),po=Ne&&rt?1-ze:1,nl=Math.max(0,Math.min(1,an*po)),xo=Ne&&rt&&ze>0?`Volume decreased ${Math.round(ze*1e3)/10}%`:null,Ca=m.useRef({hasDedicatedAudio:!1,audioUrl:null,mainBrushDuckEnabled:!1,mainBrushDuckAmount:0,mainBrushActive:!1,baseRoverGain:0,effectiveRoverGain:0});m.useEffect(()=>{Ca.current={hasDedicatedAudio:he,audioUrl:l?.url||null,mainBrushDuckEnabled:Ne,mainBrushDuckAmount:ze,mainBrushActive:rt,baseRoverGain:an,effectiveRoverGain:nl}},[he,l?.url,Ne,ze,rt,an,nl]);const Fe=m.useCallback((xe,Xe={})=>{if(!gi)return;const Qe=V.current,je=Ca.current,Le={event:xe,ts:Date.now(),roverLabel:d||null,hasDedicatedAudio:je.hasDedicatedAudio,audioUrl:je.audioUrl,mainBrushDuckEnabled:je.mainBrushDuckEnabled,mainBrushDuckAmount:je.mainBrushDuckAmount,mainBrushActive:je.mainBrushActive,baseRoverGain:je.baseRoverGain,effectiveRoverGain:je.effectiveRoverGain,element:Qe?{muted:Qe.muted,volume:Qe.volume,paused:Qe.paused,ended:Qe.ended,readyState:Qe.readyState,networkState:Qe.networkState}:null,...Xe};try{console.log(`[AudioDebug] ${xe} ${JSON.stringify(Le)}`)}catch{console.log("[AudioDebug]",xe,Le)}},[gi,d]),al=$?.socials?.find(xe=>String(xe?.id||xe?.label||"").toLowerCase()==="discord")?.url||$?.discord?.invite||null;m.useEffect(()=>{tl&&console.log("[OvercurrentHUD]",{overlayVisible:Yt,overlayMotors:rn,overlayFill:pt,limiterActive:ts,limiterCaps:sn,limiterGroups:Ea,wheelOvercurrents:Pa})},[tl,pt,rn,Yt,ts,sn,Ea,Pa]),m.useEffect(()=>{Fe("settings/update")},[Fe]);const _t=m.useCallback(()=>{clearTimeout(X.current),X.current=setTimeout(()=>te(Date.now()),Dp)},[]),Pn=m.useCallback(()=>{clearTimeout(Z.current),Z.current=setTimeout(()=>ie(Date.now()),Dp)},[]),xn=m.useCallback(async()=>{const xe=O.current;if(xe)try{xe.muted=!0,await xe.play()}catch{}},[]),vi=m.useCallback((xe=0)=>{if(h||he)return;clearTimeout(ae.current);const Xe=()=>{clearTimeout(ae.current),ae.current=setTimeout(()=>{h||Qe()},mj)},Qe=async()=>{const je=O.current;if(je)try{await xn(),je.muted=!1,await je.play(),ve(!1)}catch{je.muted=!0,ve(!0),Xe()}};ae.current=setTimeout(Qe,xe)},[xn,h,he]);m.useEffect(()=>()=>{clearTimeout(X.current),clearTimeout(Z.current),clearTimeout(ae.current),clearInterval(F.current),oe.current&&(cancelAnimationFrame(oe.current),oe.current=null)},[]),m.useEffect(()=>{G==="playing"&&vi(0)},[G,vi]),m.useEffect(()=>{Ce&&(k("snapshot"),P(null))},[Ce]),m.useEffect(()=>{if(Ce||!a?.url||!O.current)return;let xe=!0,Xe;const Qe=setTimeout(()=>ve(!0),0),je=(Le,vt)=>{xe&&(Fe("video/status",{nextStatus:Le,info:vt||null}),k(Le),P(vt||null),Le==="playing"&&xn(),["error","failed","disconnected","closed"].includes(Le)&&_t())};return Xe=new Rp({url:a.url,token:a.token,video:O.current,receiveAudio:!he,onStatus:je}),Xe.start().catch(Le=>{xe&&(k("error"),P(Le.message),_t())}),()=>{xe=!1,clearTimeout(Qe),Xe?.stop()}},[Ce,a?.url,a?.token,W,_t,xn,he,Fe]),m.useEffect(()=>{G==="stopped"&&a?.url&&_t()},[G,a?.url,_t]),m.useEffect(()=>{const xe=V.current;if(!xe||!l?.url){Fe("route/no-audio-url"),me.current=null;return}const Xe=Math.max(0,Math.min(1,nl)),Qe=me.current==null?Math.max(0,Math.min(1,xe.volume)):me.current;if(oe.current&&(cancelAnimationFrame(oe.current),oe.current=null),Xe>Qe){const je=performance.now(),Le=Qe,vt=Xe-Le,Et=Pe=>{const Te=Math.min(1,(Pe-je)/xj),Gt=Le+vt*Te;xe.volume=Gt,me.current=Gt,Te<1?oe.current=requestAnimationFrame(Et):oe.current=null};oe.current=requestAnimationFrame(Et)}else xe.volume=Xe,me.current=Xe;Fe("route/direct",{elementVolume:Xe,duckEnabled:Ne,mainBrushActive:rt,duckAmount:ze})},[l?.url,nl,Ne,rt,ze,Fe]),m.useEffect(()=>{if(!l?.url||!V.current)return;let xe=!0,Xe;const Qe=(je,Le)=>{xe&&(Fe("audio/status",{nextStatus:je,info:Le||null}),_(Le||(je==="connected"?"connected":null)),ce(vt=>je==="connected"&&(vt==="playing"||vt==="connecting")||je==="new"?vt:je),["error","failed"].includes(je)&&Pn())};return Xe=new Rp({url:l.url,token:l.token,video:V.current,audioOnly:!0,onStatus:Qe}),Xe.start().catch(je=>{xe&&(ce("error"),_(je.message),Pn())}),()=>{xe=!1,Xe?.stop()}},[l?.url,l?.token,le,Pn,Fe]),m.useEffect(()=>{const xe=V.current;if(!l?.url||!xe){clearInterval(F.current);return}if(!["connecting","connected","playing","paused"].includes(re)){clearInterval(F.current);return}const Qe=async()=>{const je=V.current;je&&(je.muted=!1,!(!je.paused&&!je.ended)&&(Fe("retry/play-attempt"),je.play().then(()=>{Fe("retry/play-ok"),ce(Le=>Le==="connected"?"playing":Le),_(Le=>Le==="paused"?null:Le)}).catch(Le=>{Fe("retry/play-fail",{error:Le?.message}),_(vt=>vt||Le?.message||"autoplay blocked")})))};return Qe(),F.current=setInterval(Qe,hj),()=>clearInterval(F.current)},[l?.url,re,Fe]),m.useEffect(()=>{const xe=V.current;if(!xe)return;const Xe=()=>{Fe("element/play"),ce(Te=>Te==="error"?Te:"playing"),_(null)},Qe=()=>{Fe("element/pause"),ce(Te=>["error","failed","disconnected","closed","stopped"].includes(Te)?Te:"paused"),_(Te=>Te||"paused")},je=()=>{Fe("element/ended"),ce(Te=>Te==="error"?Te:"stopped"),_(Te=>Te||"ended")},Le=()=>{const{error:Te}=xe,Gt=Te?.message||"audio error";Fe("element/error",{error:Gt}),ce("error"),_(Gt)},vt=()=>Fe("element/waiting"),Et=()=>Fe("element/canplay"),Pe=()=>Fe("element/stalled");return xe.addEventListener("play",Xe),xe.addEventListener("pause",Qe),xe.addEventListener("ended",je),xe.addEventListener("error",Le),xe.addEventListener("waiting",vt),xe.addEventListener("canplay",Et),xe.addEventListener("stalled",Pe),()=>{xe.removeEventListener("play",Xe),xe.removeEventListener("pause",Qe),xe.removeEventListener("ended",je),xe.removeEventListener("error",Le),xe.removeEventListener("waiting",vt),xe.removeEventListener("canplay",Et),xe.removeEventListener("stalled",Pe)}},[l?.url,Fe]);const yi=o?.error?`Error: ${o.error}`:o?.objectUrl?"snapshot":o?.status||"waiting",ns=Ce?yi:a?.url?G==="error"?`Error: ${Q||"unknown"}`:Q?`${G} (${Q})`:G:"waiting",qa=l?.error?`Error: ${l.error}`:l?.url?re==="error"?`Error: ${C||"unknown"}`:C?`${re} (${C})`:re:null,bi=y==="spectator",$t=y==="none";return r.jsxs("div",{className:`flex flex-col gap-0.5 ${q?"h-full":""}`,children:[r.jsxs("div",{className:`relative w-full overflow-hidden bg-black ${q?"h-full flex-1":"aspect-[4/3]"}`,children:[Ce?o?.objectUrl?r.jsx("img",{src:o.objectUrl,alt:d,className:"h-full w-full object-contain",draggable:!1}):r.jsx("div",{className:"flex h-full w-full items-center justify-center text-sm text-slate-300",children:"Waiting for frame…"}):r.jsx("video",{ref:O,muted:h||ue||he,playsInline:!0,autoPlay:!0,controls:!1,className:"h-full w-full object-contain"}),r.jsx("audio",{ref:V,autoPlay:!0,hidden:!0}),!$t&&E?r.jsx(yj,{mobileHud:it,turnSeconds:T,isActiveDriver:z,idleSkipSeconds:L}):null,$t?null:r.jsx(vj,{frame:p,sensors:ne,label:d,status:ns,audioStatus:qa,levelStatus:xo,desktopLayout:Wn,layoutFormat:v,variant:y,driverLabel:b,battery:mt,showTopDown:mo,mobileHud:it,mapPosition:ln,turnTimerText:S,labelScale:w}),$t?null:r.jsx(jj,{compact:it}),!$t&&tl?r.jsx("div",{className:"pointer-events-none absolute left-1 top-1 z-40 rounded bg-black/80 px-1 py-0.5 text-[0.6rem] text-lime-200",children:`OC vis:${Yt?1:0} motors:${rn.length} fill:${Math.round(pt*100)}%`}):null,$t?null:r.jsx(Sj,{motors:rn,fill:pt,compact:it}),$t?null:r.jsx(Aj,{battery:mt,compact:it}),!$t&&bi&&mt.available?r.jsx("div",{className:"pointer-events-none absolute right-1 top-1/2 flex h-[70%] -translate-y-1/2 flex-col items-center justify-center rounded bg-black/60 px-0.5 pb-1 pt-1",children:r.jsx(yf,{visual:mt,orientation:"vertical",variant:"inline",compact:it,className:"h-full w-4"})}):null,!$t&&f?r.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2",children:r.jsxs("div",{className:`mx-auto w-fit rounded border border-amber-300/80 bg-black/75 text-amber-200 ${it?"px-2 py-1 text-[0.6rem]":"px-3 py-1.5 text-sm"}`,children:[r.jsx("div",{className:"text-center",children:f}),r.jsx("div",{className:"pointer-events-auto mt-0",children:r.jsx(Xf,{id:"discord",label:"Join our Discord server while you wait!",url:al})})]})}):null]}),!$t&&!bi&&r.jsxs("div",{className:"space-y-0.5",children:[r.jsx(gj,{sensors:ne}),r.jsx("div",{className:"panel-section space-y-0.5 text-sm",children:r.jsx(yf,{visual:mt,compact:it})})]})]})}function gj({sensors:a}){const l=[a?.lightBumpLeftSignal,a?.lightBumpFrontLeftSignal,a?.lightBumpCenterLeftSignal,a?.lightBumpCenterRightSignal,a?.lightBumpFrontRightSignal,a?.lightBumpRightSignal],i=l.filter(p=>p!=null).reduce((p,g)=>Math.max(p,g),1200),o=p=>Math.pow(Math.max(0,Math.min(1,(p??0)/i)),.35),f=p=>p==null||p<=0?"hsl(200 60% 18%)":`hsl(${(200+o(p)*360)%360} 100% 60%)`,d=6,h=12;return r.jsx("div",{className:"flex w-full items-center justify-center gap-0.5",children:l.map((p,g)=>{const v=o(p),y=gDate.now());m.useEffect(()=>{const P=setInterval(()=>E(Date.now()),150);return()=>clearInterval(P)},[]),a?.receivedAt&&N-a.receivedAt<200;const S=j,T=p==="mobile-portrait",z=S?"text-[0.45rem]":"text-[0.65rem]",L=S?"px-0.25 py-0.25":"px-1 py-0.5",$=S?"px-0.25 py-0.25":"px-0.5 py-0.5",O=S?"text-[0.55rem]":"text-[0.8rem]",V=S?"left-0.5 top-0.5":"left-1 top-1",X=S?"text-[0.5rem]":"text-[0.7rem]",Z=S?"px-0.5 py-0.25":"px-1 py-0.5",F=S?"left-0.5 top-1/2":"left-1 top-1/2",ae="bottom-0.5",oe={transform:`translateX(-50%) scale(${q})`,transformOrigin:"center bottom"},me="240px",G=T?.3:S?.33:.7,Q={width:me,height:me,opacity:S?.6:.7,transform:M==="top-center"?`translateX(-50%) scale(${G})`:`scale(${G})`,transformOrigin:M==="bottom-left"?"bottom left":M==="top-center"?"top center":"top right",...M==="bottom-left"?{left:"0.25rem",bottom:"0.25rem"}:M==="top-center"?{left:"50%",top:"0.25rem"}:{right:"0.25rem",top:"0.25rem"}};if(g==="none")return null;if(g==="spectator"){const P=[["Voltage",l?.voltageMv!=null?`${(l.voltageMv/1e3).toFixed(2)} V`:"--"],["Current",l?.currentMa!=null?`${l.currentMa} mA`:"--"],["Charge",l?.batteryChargeMah!=null?`${l.batteryChargeMah}`:"--"],["OI",l?.oiMode?.label||"--"]],re=!!l?.chargingSources?.homeBase,ce=l?.chargingState?.label||"",C=!!(ce&&ce.toLowerCase()!=="not charging"),_=l?.oiMode?.label||"Unknown",W=_.toLowerCase(),te=W==="full"?"bg-emerald-500/80 text-emerald-50":W==="safe"?"bg-amber-400/80 text-amber-950":W==="passive"?"bg-slate-700/80 text-slate-100":"bg-slate-700/60 text-slate-200",le=re?"bg-emerald-500/80 text-emerald-50":"bg-slate-700/70 text-slate-200",ie=C?"bg-emerald-500/80 text-emerald-50":re?"bg-amber-400/80 text-amber-950":"bg-slate-700/70 text-slate-200";return r.jsxs(r.Fragment,{children:[r.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[r.jsx("div",{className:`absolute ${V} font-medium text-slate-100 ${z}`,children:r.jsxs("div",{className:"flex flex-col gap-0.5 leading-none",children:[r.jsxs("span",{children:["Status: ",o]}),f?r.jsxs("span",{children:["Audio: ",f]}):null,d?r.jsx("span",{className:"text-cyan-300",children:d}):null]})}),r.jsx("div",{className:`absolute ${F} flex -translate-y-1/2 flex-col gap-0.5 bg-black/70 text-slate-100 ${z} ${L}`,children:r.jsxs("div",{className:"space-y-0.5 leading-tight",children:[r.jsxs("div",{className:"flex flex-col gap-0.5 text-[0.75rem] font-semibold uppercase tracking-wide",children:[r.jsx("span",{className:`rounded px-1.5 py-0.5 ${le}`,children:re?"Docked":"Undocked"}),r.jsx("span",{className:`rounded px-1.5 py-0.5 ${ie}`,children:C?"Charging":"Not charging"}),r.jsxs("span",{className:`rounded px-1.5 py-0.5 ${te}`,children:["OI: ",_]})]}),P.map(([ue,ve])=>r.jsxs("span",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{className:"text-slate-400",children:ue}),r.jsx("span",{className:"font-semibold text-white",children:ve})]},ue))]})}),r.jsx("div",{className:`absolute ${ae} left-1/2`,style:oe,children:r.jsxs("div",{className:`flex items-center gap-0.5 bg-black/80 text-slate-100 ${$} ${O}`,children:[r.jsx("span",{className:"font-semibold text-white",children:i||"Unnamed Rover"}),v?r.jsxs("span",{className:"text-slate-300",children:["• ",v]}):null]})})]}),b?r.jsx("div",{className:"pointer-events-none absolute rounded",style:{...Q},children:r.jsx(vf,{sensors:l,size:240,overlay:!0})}):null]})}return r.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[r.jsx("div",{className:`absolute ${V} font-medium text-slate-100 ${z}`,children:r.jsxs("div",{className:"flex flex-col gap-0.5 leading-none",children:[r.jsxs("span",{children:["Status: ",o]}),f?r.jsxs("span",{children:["Audio: ",f]}):null,d?r.jsx("span",{className:"text-cyan-300",children:d}):null]})}),w?r.jsx("div",{className:`absolute left-1/2 top-0.5 -translate-x-1/2 rounded bg-black/70 text-slate-100 ${Z} ${X}`,children:w}):null,r.jsx("div",{className:`absolute ${ae} left-1/2`,style:oe,children:r.jsx("div",{className:`flex gap-0.5 bg-black/80 text-slate-100 ${$} ${O}`,children:r.jsxs("span",{children:['Rover: "',i||"Unnamed Rover",'"']})})}),b&&g!=="spectator"?r.jsx("div",{className:"pointer-events-none absolute rounded",style:{...Q},children:r.jsx(vf,{sensors:l,size:240,overlay:!0})}):null]})}function yj({mobileHud:a=!1,turnSeconds:l=null,isActiveDriver:i=!1,idleSkipSeconds:o=null}){const f=a?"text-3xl":"text-5xl",d=a?"text-xs":"text-sm",h=a?"text-[0.55rem]":"text-[0.75rem]",p=a?"px-4 py-3":"px-6 py-4",g=i&&typeof o=="number";return r.jsx("div",{className:"pointer-events-none absolute inset-0 z-30 flex items-center justify-center bg-black/55",children:r.jsxs("div",{className:`flex flex-col items-center gap-0.5 rounded border border-amber-300/80 bg-black/70 ${p}`,children:[r.jsx("div",{className:`font-semibold text-amber-200 ${f}`,children:"IT IS YOUR TURN!"}),r.jsx("div",{className:`text-amber-200/80 ${d}`,children:"Start driving!"}),g?r.jsxs("div",{className:`text-red-100/90 ${h}`,children:["Idle skip in ",o,"s"]}):null]})})}const bj={leftWheel:"Left wheel",rightWheel:"Right wheel",mainBrush:"Main brush",sideBrush:"Side brush",limiter:"Overcurrent limit"};function Sj({motors:a,fill:l=0,compact:i=!1}){if(!a?.length)return null;const o=a.map(y=>bj[y]||y),f=i?"w-[12rem] h-[3.5rem]":"w-[20rem] h-[7rem]",d=i?"px-2 py-1":"px-4 py-2",h=i?"text-lg":"text-4xl",p=i?"text-xs":"text-xl",g=Math.max(0,Math.min(1,l)),v=`${Math.round(g*100)}%`;return r.jsx("div",{className:`pointer-events-none absolute flex items-center justify-center bg-red-900/50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 ${f}`,children:r.jsxs("div",{className:"relative h-full w-full",children:[r.jsx("div",{className:"absolute inset-0 overflow-hidden",children:r.jsx("div",{className:"h-full bg-red-700/60",style:{width:v}})}),r.jsxs("div",{className:`relative z-10 flex h-full w-full flex-col items-center justify-center text-center font-semibold text-white animate-pulse ${h} ${d}`,children:[r.jsx("div",{children:"OVERCURRENT"}),r.jsx("div",{className:`mt-0 font-medium text-white ${p}`,children:o.join(", ")})]})]})})}function Aj({battery:a,compact:l=!1}){if(!a?.available||!a.warnActive&&!a.urgentActive)return null;const i=a.urgentActive?"BATTERY VERY LOW, DOCK THE ROVER AND CHARGE IMMEDIATELY!!":"Battery low! please dock and charge the rover soon.",o=l?"p-2 top-6":"p-4 top-10",f=l?"text-sm":"text-2xl";return r.jsx("div",{className:`pointer-events-none absolute flex items-center justify-center bg-amber-900/60 left-1/2 -translate-x-1/2 ${o}`,children:r.jsx("div",{className:`text-center font-semibold text-white animate-pulse ${f}`,children:r.jsx("div",{children:i})})})}function jj({compact:a=!1}){const{session:l}=Ve(),{sendMessage:i,onInputFocus:o,onInputBlur:f,blurChat:d,registerInputRef:h,setTypingActive:p}=Lf(),{value:g}=st("tts",{engine:"flite",voice:"rms",pitch:50}),[v,y]=m.useState(""),[b,j]=m.useState(!1),M=l?.role!=="spectator",w=l?.role==="spectator",q=l?.assignment?.roverId||null,E=!!m.useMemo(()=>l?.roster?.find(O=>String(O.id)===String(q))||null,[q,l?.roster])?.audio?.ttsEnabled,S=m.useMemo(()=>{if(!E)return null;const O=g?.engine==="espeak"?"espeak":"flite";if(O==="espeak"){let X=Number.isFinite(g?.pitch)?Math.round(g.pitch):void 0;return typeof X=="number"&&(X=Math.max(0,Math.min(99,X))),{speak:!0,engine:O,pitch:X}}const V=typeof g?.voice=="string"?g.voice:void 0;return{speak:!0,engine:O,voice:V}},[g?.engine,g?.pitch,g?.voice,E]),T=a?"pointer-events-auto absolute bottom-0.5 right-0.5 flex w-[9rem] max-w-[70vw] items-center gap-0.5 rounded bg-black/70 px-0.4 py-0.2":"pointer-events-auto absolute bottom-1 right-1 flex w-[12rem] max-w-[70vw] items-center gap-0.5 rounded bg-black/70 px-0.5 py-0.25",z=a?"min-w-0 flex-1 bg-transparent text-[0.55rem] text-slate-100 placeholder:text-slate-400 focus:outline-none":"min-w-0 flex-1 bg-transparent text-[0.7rem] text-slate-100 placeholder:text-slate-400 focus:outline-none",L=a?"rounded bg-cyan-500/80 px-0.35 py-0.2 text-[0.55rem] font-semibold text-black disabled:opacity-50":"rounded bg-cyan-500/80 px-0.5 py-0.25 text-[0.7rem] font-semibold text-black disabled:opacity-50";async function $(O){if(O.preventDefault(),!M)return;const V=v.trim();if(V){j(!0);try{await i(V,S),y(""),d(),p(!1)}catch(X){alert(X.message)}finally{j(!1)}}}return w?null:r.jsxs("form",{onSubmit:$,className:T,children:[r.jsx("input",{className:z,value:v,onChange:O=>{const V=O.target.value;y(V),p(!!V.trim())},onFocus:O=>{o(O),p(!!v.trim())},onBlur:O=>{f(O),p(!1)},onKeyDown:O=>{O.key==="Enter"&&!v.trim()&&(O.preventDefault(),d(),p(!1))},ref:O=>h(O,{target:"hud"}),placeholder:M?"Chat (TTS)":"Spectator",disabled:!M}),r.jsx("button",{type:"submit",disabled:!M||b,className:L,children:"Speak"})]})}function Qf({layoutFormat:a="desktop"}){const{session:l}=Ve(),{state:{song:i,lastControlIntentAt:o},overcurrentLimiter:f}=Dt(),[d,h]=m.useState(()=>Date.now()),[p,g]=m.useState(!1),[v,y]=m.useState(null),b=m.useRef({active:!1,roverId:null});m.useEffect(()=>{if(l?.mode!=="turns")return;const te=setInterval(()=>h(Date.now()),250);return()=>clearInterval(te)},[l?.mode]);const j=l?.assignment?.roverId,w=!!(j&&l?.roster?l.roster.find(te=>String(te.id)===String(j)):null)?.media?.audioPublishUrl,q=j?l?.turnQueues?.[j]:null,N=l?.socketId||null,E=j?l?.activeDrivers?.[j]:null,S=!!(N&&E===N),T=m.useMemo(()=>{const te=q?.queue||[];if(!te.length||!q?.current||te.length<=1)return null;const le=te.findIndex(ie=>ie===q.current);return le===-1?te[0]||null:te[(le+1)%te.length]||null},[q?.queue,q?.current]),z=!!(N&&T===N),L=q?.deadline||null,$=q?.idleDeadline||null,O=L?L-d:null,V=$?$-d:null,X=l?.mode==="turns"&&z&&O!=null&&O<=5e3&&O>0,Z=l?.mode!=="turns"||S||X,F=O!=null&&Number.isFinite(O)?Math.max(0,Math.ceil(O/1e3)):null,ae=V!=null&&Number.isFinite(V)?Math.max(0,Math.ceil(V/1e3)):null,oe=S?F!=null?`${F}s left`:null:z&&F!=null?`Your turn in ${F}s`:null,me=j?[...Z?[{type:"rover",id:j,key:j}]:[],...w?[{type:"rover",id:`${j}-audio`,key:`${j}-audio`}]:[]]:[],G=ri(me),k=j&&Z?G[j]:null,Q=j&&w?G[`${j}-audio`]:null,P=$f(j?[j]:[],{enabled:!!j,version:l?.mode}),re=j&&P[j]||null,ce=es(j),C=j&&l?.roster?l.roster.find(te=>String(te.id)===String(j)):null,_=C?.battery??null,W=C?.name||(j?`Rover ${j}`:"");return m.useEffect(()=>{if(l?.mode!=="turns"){g(!1),y(null),b.current={active:!1,roverId:null};return}const te=b.current,le=S&&!te.active,ie=S&&j&&j!==te.roverId;le||ie?(g(!0),y(Date.now())):!S&&te.active&&(g(!1),y(null)),b.current={active:S,roverId:j}},[S,j,l?.mode]),m.useEffect(()=>{!p||!v||o>v&&g(!1)},[o,v,p]),r.jsx("section",{className:"panel",children:j?r.jsx(ci,{sessionInfo:k,videoMode:Z?"whep":"snapshot",snapshotFeed:re,audioSessionInfo:Q,label:W,telemetryFrame:ce,batteryConfig:_,layoutFormat:a,overcurrentLimiter:f,songNote:i?.note,qualityNotice:Z?null:"Preview feed (low FPS) until your turn.",showTurnCue:p,turnTimerText:oe,turnSeconds:F,isActiveDriver:S,idleSkipSeconds:ae}):r.jsxs("div",{className:"panel-muted content-center text-center text-sm text-slate-400 aspect-[4/3]",children:[r.jsx("p",{children:"You are not assigned to a rover."}),r.jsx("p",{className:"mt-0",children:r.jsx("a",{href:"/spectate",className:"text-blue-400 underline hover:text-blue-500",children:"Click here to visit the spectator page."})})]})})}function bf({label:a,tone:l="muted"}){const i=l==="success"?"bg-emerald-900 text-emerald-100":l==="warn"?"bg-amber-900 text-amber-100":"bg-slate-800 text-slate-200";return r.jsx("span",{className:`rounded px-1 py-0.5 text-xs font-semibold leading-none ${i}`,children:a})}function ro(a){if(!Number.isFinite(a))return 0;const l=a%360;return l<0?l+360:l}function Nj(a){if(!Array.isArray(a)||a.length<3)return 0;const[l,i,o]=a,f=Math.max(0,Math.min(255,Number(l)))/255,d=Math.max(0,Math.min(255,Number(i)))/255,h=Math.max(0,Math.min(255,Number(o)))/255,p=Math.max(f,d,h),g=Math.min(f,d,h),v=p-g;if(v===0)return 0;let y=0;return p===f?y=(d-h)/v%6:p===d?y=(h-f)/v+2:y=(f-d)/v+4,ro(Math.round(y*60))}function _p(a){const l=ro(a),i=1,o=1-Math.abs(l/60%2-1);let f=0,d=0,h=0;return l<60?(f=i,d=o):l<120?(f=o,d=i):l<180?(d=i,h=o):l<240?(d=o,h=i):l<300?(f=o,h=i):(f=i,h=o),[Math.round(f*255),Math.round(d*255),Math.round(h*255)]}function Op(a){return a?Array.isArray(a.hsColor)?ro(Number(a.hsColor[0])):Array.isArray(a.rgbColor)?Nj(a.rgbColor):0:0}function wj({entity:a,connected:l,onToggle:i,onSetColor:o}){const f=a.state==="unavailable"||!a.available,d=a.state==="on",h=a.type==="light"&&a.supportsColor,p=f?"warn":d?"success":"muted",g=f?"Unavailable":d?"On":"Off",v=!l||f,y=v||!h,[b,j]=m.useState(()=>Op(a)),M=m.useRef(b),w=m.useRef(!1),q=f?"border-slate-800 bg-slate-900 text-slate-400 cursor-not-allowed":d?"border-emerald-700 bg-emerald-900/80 text-emerald-50 hover:bg-emerald-800":"border-rose-800 bg-rose-900/80 text-rose-50 hover:bg-rose-800";m.useEffect(()=>{if(!h||w.current)return;const L=Op(a);M.current=L,j(L)},[a.rgbColor,a.hsColor,h]);const N=L=>{const $=ro(Number(L.target.value));M.current=$,j($)},E=()=>{y||!o||o(a.id,_p(M.current))},S=L=>{L.stopPropagation()},z=`rgb(${(h?_p(M.current):[255,255,255]).join(",")})`;return r.jsxs("button",{type:"button",onClick:()=>i(a.id),disabled:v,className:`relative flex min-w-[12rem] flex-[1_1_12rem] items-start justify-between gap-0.5 rounded px-1 py-0.5 text-left transition-colors ${q} disabled:opacity-60 disabled:hover:bg-inherit`,children:[r.jsxs("div",{className:"min-w-0 flex-1",children:[r.jsxs("div",{className:"flex items-center gap-0.5 text-sm leading-normal",children:[r.jsx("span",{className:"truncate font-semibold text-white",children:a.name||a.id}),h&&r.jsxs(r.Fragment,{children:[r.jsx(bf,{label:g,tone:p}),!l&&r.jsx("span",{className:"text-xs text-amber-200",children:"Offline"})]})]}),h?r.jsx("div",{className:"-mt-0.5 w-full",onClick:S,onPointerDown:L=>{S(L),w.current=!0},onPointerUp:L=>{S(L),w.current=!1,E()},onPointerCancel:L=>{S(L),w.current=!1,E()},onKeyUp:L=>{S(L),E()},onBlur:E,children:r.jsx("div",{className:"relative w-full",children:r.jsx("input",{type:"range",min:"0",max:"360",step:"1",value:b,onChange:N,disabled:y,"aria-label":`Set color for ${a.name||a.id}`,className:"ha-hue-slider w-full"})})}):r.jsxs("div",{className:"flex items-center gap-0.5 text-xs text-slate-400",children:[r.jsx(bf,{label:g,tone:p}),!l&&r.jsx("span",{className:"text-amber-200",children:" · Offline"})]})]}),h&&r.jsx("span",{className:"pointer-events-none absolute right-1 top-1 h-2.5 w-2.5 rounded-full border border-white/60",style:{backgroundColor:z}}),!h&&r.jsx("div",{className:"self-center text-xs font-semibold text-white/90",children:d?"Turn off":"Turn on"})]})}function ig(){const{state:{keymap:a}}=Dt(),{session:l,homeAssistantToggle:i,homeAssistantSetLightColor:o}=Ve(),f=l?.homeAssistant,d=m.useMemo(()=>f?.entities||[],[f?.entities]),h=An(a?.homeAssistantOn?.[0]),p=An(a?.homeAssistantOff?.[0]);if(!f?.enabled)return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm text-slate-400",children:[r.jsx("p",{className:"text-slate-300",children:"Room Controls"}),r.jsx("p",{className:"text-slate-500",children:"Not configured on the server."})]});if(d.length===0)return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm text-slate-400",children:[r.jsx("p",{className:"text-slate-300",children:"Room Controls"}),r.jsx("p",{className:"text-slate-500",children:"No lights or switches configured."})]});const g=!!f?.connected;return r.jsxs("section",{className:"panel-section space-y-0.5 text-base",children:[r.jsxs("header",{className:"flex items-center justify-between gap-0.5 text-sm text-slate-400",children:[r.jsxs("div",{className:"flex items-center gap-0.5",children:[r.jsx("p",{children:"Room Controls"}),r.jsx("span",{className:"text-xs text-slate-500",children:d.length}),r.jsxs("div",{className:"flex items-center gap-0.5 text-xs text-slate-300 background-black",children:[r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx("span",{children:"On"}),h?r.jsx(Bp,{label:h}):null]}),r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx("span",{children:"Off"}),p?r.jsx(Bp,{label:p}):null]})]})]}),r.jsx(bf,{label:g?"Connected":"Offline",tone:g?"success":"warn"})]}),r.jsx("div",{className:"flex flex-wrap gap-0.5",children:d.map(v=>r.jsx(wj,{entity:v,connected:g,onToggle:i,onSetColor:o},v.id))})]})}function Bp({label:a}){return a?r.jsx("span",{className:"rounded border border-white/40 px-1 text-[0.7rem] text-white",children:a}):null}function rg(){const{login:a,setRole:l}=Ve(),[i,o]=m.useState(""),[f,d]=m.useState(""),[h,p]=m.useState(!1);async function g(v){v.preventDefault(),p(!0);try{await a(i,f),o(""),d("")}catch(y){alert(y.message)}finally{p(!1)}}return r.jsxs("div",{className:"panel-section space-y-0.5 text-base",children:[r.jsx("p",{className:"text-sm text-slate-400",children:"Admin login"}),r.jsxs("form",{className:"flex flex-col gap-0.5",onSubmit:g,children:[r.jsx("input",{className:"field-input",placeholder:"Username",value:i,onChange:v=>o(v.target.value)}),r.jsx("input",{className:"field-input",placeholder:"Password",type:"password",value:f,onChange:v=>d(v.target.value)}),r.jsx("button",{type:"submit",disabled:h,className:"button-dark w-full disabled:opacity-50",children:h?"Logging in…":"Login"})]})]})}function zp(...a){return a.filter(Boolean).join(" ")}function Ej(a){const l=a?.batteryState?.percentDisplay;return l==null?"--":`${l}%`}function Cj(a){return a?.batteryState?a.batteryState.urgentActive?"text-red-400":a.batteryState.warnActive?"text-amber-300":"text-emerald-300":"text-slate-400"}function qj({title:a,roster:l=[],emptyText:i="No roster data.",renderActions:o=null}){return r.jsxs("div",{className:"space-y-0.5 text-sm",children:[a&&r.jsx("p",{className:"text-sm text-slate-400",children:a}),l.length===0?r.jsx("p",{className:"text-sm text-slate-500",children:i}):r.jsx("ul",{className:"space-y-0.5 text-sm",children:l.map(f=>r.jsxs("li",{className:zp("surface flex flex-wrap items-center justify-between gap-0.5",f.locked&&"bg-red-900/40"),children:[r.jsxs("div",{children:[r.jsx("p",{className:"text-slate-200",children:f.name}),r.jsxs("p",{className:"text-xs text-slate-500 flex flex-wrap items-center gap-0.5",children:[r.jsx("span",{children:f.locked?"locked":"free"}),f.lockReason&&r.jsx("span",{className:"rounded bg-black/30 px-1",children:f.lockReason}),r.jsxs("span",{className:zp("font-semibold",Cj(f)),children:["Battery ",Ej(f)]})]})]}),o?o(f):null]},f.id))})]})}const Mj=[{key:"open",label:"Open"},{key:"turns",label:"Turns"},{key:"admin",label:"Admin"},{key:"lockdown",label:"Lockdown"}];function kj(){const{session:a,lockRover:l,setMode:i,requestControl:o,setCommunityGoal:f,setAdminReason:d,rebootRover:h,rebootServer:p,adminLogs:g,llmCommentaryStatus:v}=Ve(),y=m.useMemo(()=>a?.roster??[],[a?.roster]),[b,j]=m.useState({}),[M,w]=m.useState({}),[q,N]=m.useState(!1),E=a?.health||null,S=a?.communityGoal?.text||"",T=a?.communityGoal?.updatedAt||null,[z,L]=m.useState(S),$=a?.adminReason?.text||"",O=a?.adminReason?.updatedAt||null,[V,X]=m.useState($),Z=a?.role==="admin"||a?.role==="lockdown"||a?.role==="lockdown-admin",F=a?.mode??"open",ae=async(_,W)=>{try{await l(_,W),j(te=>({...te,[_]:W}))}catch(te){alert(te.message)}},oe=async _=>{const W=_.target.value;try{await i(W)}catch(te){alert(te.message)}},me=async _=>{try{await o(_,{force:!0})}catch(W){alert(W.message)}},G=async _=>{if(!(!_?.id||!window.confirm(`Reboot rover "${_.name||_.id}" now?`))){w(te=>({...te,[_.id]:!0}));try{await h(_.id)}catch(te){alert(te.message)}finally{w(te=>({...te,[_.id]:!1}))}}},k=async()=>{if(window.confirm("Reboot the server host now? This will disconnect all users.")){N(!0);try{await p()}catch(W){alert(W.message),N(!1)}}},Q=async()=>{try{await f(z)}catch(_){alert(_.message)}},P=async()=>{try{await f(null)}catch(_){alert(_.message)}},re=async()=>{try{await d(V)}catch(_){alert(_.message)}},ce=async()=>{try{await d(null)}catch(_){alert(_.message)}};m.useEffect(()=>{L(S)},[S]),m.useEffect(()=>{X($)},[$]);const C=m.useMemo(()=>{const _={};return y.forEach(W=>{_[W.id]=b[W.id]??W.locked}),_},[y,b]);return Z?r.jsxs("section",{className:"panel-section space-y-0.5 text-base",children:[r.jsxs("div",{className:"flex items-center justify-between gap-0.5 text-sm",children:[r.jsx("span",{children:"Admin controls"}),r.jsx("select",{value:F,onChange:oe,className:"field-input text-sm",children:Mj.map(_=>r.jsx("option",{value:_.key,children:_.label},_.key))})]}),r.jsx("div",{className:"flex gap-0.5 text-xs",children:r.jsx("button",{type:"button",onClick:k,disabled:q,className:"button-danger disabled:cursor-not-allowed disabled:opacity-60",children:q?"Server rebooting...":"Reboot Server"})}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-400",children:[r.jsx("span",{children:"Community goal"}),T?r.jsxs("span",{children:["Updated ",new Date(T).toLocaleString()]}):null]}),r.jsx("input",{type:"text",value:z,onChange:_=>L(_.target.value),placeholder:"Set a community goal",className:"field-input text-sm"}),r.jsxs("div",{className:"flex gap-0.5 text-xs",children:[r.jsx("button",{type:"button",onClick:Q,className:"button-dark",children:"Set goal"}),r.jsx("button",{type:"button",onClick:P,className:"button-danger",children:"Clear"})]})]}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-400",children:[r.jsx("span",{children:"Admin mode reason"}),O?r.jsxs("span",{children:["Updated ",new Date(O).toLocaleString()]}):null]}),r.jsx("textarea",{value:V,onChange:_=>X(_.target.value),placeholder:"Set an admin mode reason",className:"field-input text-sm min-h-[3.5rem]"}),r.jsxs("div",{className:"flex gap-0.5 text-xs",children:[r.jsx("button",{type:"button",onClick:re,className:"button-dark",children:"Set reason"}),r.jsx("button",{type:"button",onClick:ce,className:"button-danger",children:"Clear"})]})]}),r.jsx(qj,{roster:y,renderActions:_=>r.jsxs("div",{className:"flex flex-wrap gap-0.5 text-xs",children:[r.jsx("button",{type:"button",onClick:()=>ae(_.id,!C[_.id]),className:"button-dark",children:C[_.id]?"Unlock":"Lock"}),r.jsx("button",{type:"button",onClick:()=>me(_.id),className:"button-dark",children:"Force"}),r.jsx("button",{type:"button",onClick:()=>G(_),disabled:!!M[_.id],className:"button-danger disabled:cursor-not-allowed disabled:opacity-60",children:M[_.id]?"Rebooting...":"Reboot"})]})}),r.jsx(Tj,{health:E}),r.jsx(Rj,{status:v}),r.jsx(Dj,{entries:g})]}):null}function Rj({status:a}){if(!a)return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),r.jsx("div",{className:"surface text-xs text-slate-300",children:"No status received yet."})]});const l=a.lastTickAt?new Date(a.lastTickAt).toLocaleString():"never",i=a.nextRunAt?new Date(a.nextRunAt).toLocaleString():"n/a",o=a.lastPostedAt?new Date(a.lastPostedAt).toLocaleString():"never",f=a.lastSnapshotSummary||{},d=a.lastOutcome==="failed"?"text-red-300":a.lastOutcome==="posted"?"text-emerald-300":"text-slate-300";return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),r.jsxs("div",{className:"surface space-y-0.5 text-xs text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Enabled"}),r.jsx("span",{children:a.enabled?"yes":"no"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Running"}),r.jsx("span",{children:a.running?"yes":"no"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"In flight"}),r.jsx("span",{children:a.inFlight?"yes":"no"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Model"}),r.jsx("span",{className:"text-slate-300",children:a.model||"--"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Server"}),r.jsx("span",{className:"text-slate-300",children:a.ollamaUrl||"--"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Frequency"}),r.jsxs("span",{children:[a.frequencyMs," ms"]})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Tick count"}),r.jsx("span",{children:a.tickCount??0})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Last outcome"}),r.jsx("span",{className:d,children:a.lastOutcome||"--"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Last reason"}),r.jsx("span",{className:"text-slate-300",children:a.lastReason||"--"})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Last tick"}),r.jsx("span",{className:"text-slate-300",children:l})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Next run"}),r.jsx("span",{className:"text-slate-300",children:i})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Last posted"}),r.jsx("span",{className:"text-slate-300",children:o})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Prompt chars"}),r.jsx("span",{children:a.lastPromptChars??0})]})]}),r.jsxs("div",{className:"surface space-y-0.5 text-xs text-slate-300",children:[r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Snapshot active drivers"}),r.jsx("span",{children:f.activeDrivers??0})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Snapshot rovers"}),r.jsx("span",{children:f.rovers??0})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Snapshot chat msgs"}),r.jsx("span",{children:f.chatMessages??0})]})]}),a.lastError?r.jsxs("div",{className:"surface text-xs text-red-300 break-words",children:["Error: ",a.lastError]}):null,a.lastGeneratedText?r.jsxs("div",{className:"surface text-xs text-slate-200 break-words",children:["Generated: ",a.lastGeneratedText]}):null,a.lastPostedText?r.jsxs("div",{className:"surface text-xs text-emerald-200 break-words",children:["Posted: ",a.lastPostedText]}):null,r.jsxs("details",{className:"surface text-xs text-slate-200",children:[r.jsx("summary",{className:"cursor-pointer select-none text-slate-300",children:"Most recent system prompt"}),r.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-slate-200",children:a.lastSystemPrompt||"No prompt read yet."})]}),r.jsxs("details",{className:"surface text-xs text-slate-200",children:[r.jsx("summary",{className:"cursor-pointer select-none text-slate-300",children:"Most recent info snapshot"}),r.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-slate-200",children:a.lastInfoSnapshot?JSON.stringify(a.lastInfoSnapshot,null,2):"No snapshot captured yet."})]})]})}function Tj({health:a}){if(!a)return null;const l=a.replay||{sources:[],readyCount:0,totalCount:0},i=a.snapshots||{rovers:[],rooms:[]},o=`${l.readyCount}/${l.totalCount} sources ready`,f=i.rovers.filter(h=>h.stale).length,d=i.rooms.filter(h=>h.stale).length;return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"Health"}),r.jsxs("div",{className:"surface space-y-0.5 text-xs text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Replay segments"}),r.jsx("span",{className:"text-slate-400",children:o})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Rover snapshots"}),r.jsxs("span",{className:f?"text-amber-300":"text-emerald-300",children:[i.rovers.length-f,"/",i.rovers.length," ok"]})]}),r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:"Room cameras"}),r.jsxs("span",{className:d?"text-amber-300":"text-emerald-300",children:[i.rooms.length-d,"/",i.rooms.length," ok"]})]})]}),r.jsx("div",{className:"space-y-0.5 text-xs text-slate-300",children:l.sources.map(h=>r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:h.label}),r.jsxs("span",{className:h.ready?"text-emerald-300":"text-amber-300",children:[h.recentCount,"/",h.neededCount]})]},`${h.type}:${h.id}`))}),r.jsx("div",{className:"space-y-0.5 text-xs text-slate-300",children:i.rovers.map(h=>r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:h.name}),r.jsx("span",{className:h.stale?"text-amber-300":"text-emerald-300",children:h.stale?"stale":"ok"})]},`rover:${h.id}`))}),r.jsx("div",{className:"space-y-0.5 text-xs text-slate-300",children:i.rooms.map(h=>r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsx("span",{children:h.name}),r.jsx("span",{className:h.stale?"text-amber-300":"text-emerald-300",children:h.error?"error":h.stale?"stale":"ok"})]},`room:${h.id}`))})]})}function Dj({entries:a}){const l=a||[];return r.jsxs("div",{className:"panel-section space-y-0.5 text-base",children:[r.jsxs("div",{className:"flex items-center justify-between text-sm text-slate-400",children:[r.jsx("span",{children:"Admin IP log"}),r.jsx("span",{children:l.length})]}),r.jsx("div",{className:"surface h-64 overflow-y-auto font-mono text-xs",children:l.length===0?r.jsx("p",{children:"No admin log entries yet."}):l.slice().reverse().map(i=>r.jsxs("div",{className:"surface",children:[r.jsx("span",{className:"text-amber-400",children:i.ts?new Date(i.ts).toLocaleTimeString():"--"})," ",i.label&&r.jsxs("span",{className:"text-teal-400",children:["[",i.label,"]"]})," ",r.jsx("span",{className:"text-slate-200",children:i.message})," ",i.ip&&r.jsx("span",{className:"text-cyan-300",children:i.ip})," ",i.meta&&r.jsx("span",{className:"text-slate-500",children:JSON.stringify(i.meta)})]},i.id))}),r.jsx("p",{className:"text-xs text-slate-500",children:"Admin-only log stream; IPs never appear in user data."})]})}const _j=[{id:"driveForward",label:"Drive Forward",group:"Driving"},{id:"driveBackward",label:"Drive Backward",group:"Driving"},{id:"driveLeft",label:"Turn Left",group:"Driving"},{id:"driveRight",label:"Turn Right",group:"Driving"},{id:"boostModifier",label:"Boost Modifier",group:"Driving"},{id:"slowModifier",label:"Slow Modifier",group:"Driving"},{id:"auxMainForward",label:"Main Brush Forward",group:"Aux Motors"},{id:"auxMainReverse",label:"Main Brush Reverse",group:"Aux Motors"},{id:"auxSideForward",label:"Side Brush Forward",group:"Aux Motors"},{id:"auxSideReverse",label:"Side Brush Reverse",group:"Aux Motors"},{id:"auxVacuumFast",label:"Vacuum Max",group:"Aux Motors"},{id:"auxVacuumSlow",label:"Vacuum Low",group:"Aux Motors"},{id:"auxAllForward",label:"All Aux Forward",group:"Aux Motors"},{id:"cameraUp",label:"Camera Up",group:"Camera"},{id:"cameraDown",label:"Camera Down",group:"Camera"},{id:"nightVisionToggle",label:"Toggle Night Vision",group:"Camera"},{id:"hornHonk",label:"Horn (Hold)",group:"Audio"},{id:"driveMacro",label:"Drive Macro",group:"Macros"},{id:"dockMacro",label:"Dock Macro",group:"Macros"},{id:"chatFocus",label:"Toggle Chat",group:"Chat"},{id:"songNoteUp",label:"Song Note Up",group:"Audio"},{id:"songNoteDown",label:"Song Note Down",group:"Audio"},{id:"homeAssistantOn",label:"Room Controls On (Cycle)",group:"Room Controls"},{id:"homeAssistantOff",label:"Room Controls Off (Cycle)",group:"Room Controls"}];function Oj(a){return a.reduce((l,i)=>((l[i.group]||(l[i.group]=[])).push(i),l),{})}function Bj(a,l){const i=Number(a);return Number.isFinite(i)?Math.max(0,Math.min(500,i)):l}const Kf=5,ui=500,fi=1,Ff=100;function zj(a,l){const i=Number(a);return Number.isFinite(i)?Math.max(Kf,Math.min(ui,i)):l}function Fr(a,l){const i=Number(a);return Number.isFinite(i)?Math.max(fi,Math.min(Ff,i)):l}function Lj(a){const i=(Fr(a,a)-fi)/(Ff-fi),o=ui-i*(ui-Kf);return Math.round(o)}function Uj(a){const l=zj(a,a),i=(ui-l)/(ui-Kf),o=fi+i*(Ff-fi);return Math.round(o)}function Hj(a){const[l,i]=m.useState(null);return m.useEffect(()=>{if(!l)return;function o(f){if(f.preventDefault(),f.key==="Escape"){i(null);return}const d=xi(f.key??"");d&&(a(l,d,f),i(null))}return window.addEventListener("keydown",o,{capture:!0}),()=>window.removeEventListener("keydown",o,{capture:!0})},[l,a]),{active:l,startCapture:i,cancel:()=>i(null)}}function Lr({label:a,description:l,value:i,onChange:o,min:f=0,max:d=500,step:h=5}){return r.jsxs("label",{className:"surface-muted block p-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-300",children:[r.jsx("span",{className:"font-semibold text-slate-100",children:a}),r.jsx("input",{type:"number",min:f,max:d,value:i,onChange:p=>o(p.target.value),className:"w-16 rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-right text-[0.75rem] font-mono text-slate-100"})]}),l&&r.jsx("p",{className:"text-[0.65rem] text-slate-500",children:l}),r.jsxs("div",{className:"mt-0 flex items-center gap-0.5",children:[r.jsx("input",{type:"range",min:f,max:d,step:h,value:i,onChange:p=>o(p.target.value),className:"h-2 flex-1 accent-emerald-400"}),r.jsx("span",{className:"w-12 text-right text-[0.75rem] font-mono text-slate-400",children:i})]})]})}function Vj(){const{state:{keymap:a},actions:{updateKeyBinding:l,resetKeyBindings:i}}=Dt(),{value:o,save:f}=st("inputs",Sn),d={...Sn.keyboard,...o.keyboard??{}},h=m.useMemo(()=>typeof d.tiltSpeed=="number"?Fr(d.tiltSpeed,Sn.keyboard.tiltSpeed):typeof d.tiltIntervalMs=="number"?Fr(Uj(d.tiltIntervalMs),Sn.keyboard.tiltSpeed):Sn.keyboard.tiltSpeed,[d.tiltIntervalMs,d.tiltSpeed]),p=m.useMemo(()=>Oj(_j),[]),{active:g,startCapture:v,cancel:y}=Hj((w,q)=>{l(w,q)}),b=m.useCallback(w=>a?.[w]?.[0]||ni[w]?.[0]||"",[a]),j=m.useCallback((w,q)=>{const N=Sn.keyboard,E=Bj(q,N[w]);f(S=>({...S??{},keyboard:{...S?.keyboard??N,[w]:E}}))},[f]),M=m.useCallback(w=>{const q=Sn.keyboard,N=Fr(w,q.tiltSpeed),E=Lj(N);f(S=>({...S??{},keyboard:{...S?.keyboard??q,tiltSpeed:N,tiltIntervalMs:E}}))},[f]);return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsxs("div",{className:"flex items-center justify-between",children:[r.jsxs("div",{children:[r.jsx("p",{className:"text-xs text-slate-400",children:"Keyboard layout"}),r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Per-browser · click to change a binding"})]}),r.jsx("button",{type:"button",onClick:()=>i(),className:"button-dark text-xs",children:"Reset defaults"})]}),r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Keyboard speeds"}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsx(Lr,{label:"Base speed",description:"Normal driving speed",value:d.baseSpeed,onChange:w=>j("baseSpeed",w)}),r.jsx(Lr,{label:"Turbo speed",description:"Used when holding the boost modifier",value:d.turboSpeed,onChange:w=>j("turboSpeed",w)}),r.jsx(Lr,{label:"Precision speed",description:"Used when holding the precision modifier",value:d.precisionSpeed,onChange:w=>j("precisionSpeed",w)})]})]}),r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Camera tilt"}),r.jsx(Lr,{label:"Tilt speed",description:"Higher = faster when holding tilt keys",value:h,onChange:M,min:1,max:100,step:1})]}),r.jsx("div",{className:"space-y-0.5",children:Object.entries(p).map(([w,q])=>r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.75rem] text-slate-400",children:w}),r.jsx("div",{className:"space-y-0.5",children:q.map(N=>{const E=b(N.id),S=g===N.id;return r.jsxs("div",{className:"surface-muted flex items-center justify-between text-xs",children:[r.jsxs("div",{children:[r.jsx("p",{className:"font-semibold text-slate-100",children:N.label}),r.jsx("p",{className:"text-[0.65rem] text-slate-400",children:An(E)})]}),r.jsxs("div",{className:"flex items-center gap-0.5",children:[S&&r.jsx("button",{type:"button",onClick:()=>y(),className:"button-danger text-[0.7rem]",children:"Cancel"}),r.jsx("button",{type:"button",onClick:()=>v(N.id),className:`${S?"px-0.5 py-0.5 bg-emerald-500 text-emerald-950 hover:bg-emerald-400":"button-dark"} text-[0.7rem] font-medium transition-colors`,children:S?"Press a key…":"Change"})]})]},N.id)})})]},w))})]})}const Kn=new Intl.NumberFormat(void 0,{maximumFractionDigits:2}),Yj=[{id:"drive",label:"Drive stick",kind:"axisPair",section:"Driving",invertDefaults:{invertX:!1,invertY:!0}},{id:"cameraTilt",label:"Camera tilt",kind:"axis",section:"Camera",invertDefaults:{invert:!0}},{id:"mainBrush",label:"Main brush",kind:"axis",section:"Brushes",invertDefaults:{invert:!1}},{id:"sideBrush",label:"Side brush",kind:"axis",section:"Brushes",invertDefaults:{invert:!1}},{id:"vacuum",label:"Vacuum",kind:"button",section:"Aux buttons"},{id:"allAux",label:"All aux",kind:"button",section:"Aux buttons"},{id:"mainReverse",label:"Main reverse toggle",kind:"button",section:"Brush toggles"},{id:"sideReverse",label:"Side reverse toggle",kind:"button",section:"Brush toggles"},{id:"driveMacro",label:"Drive macro",kind:"button",section:"Mode macros"},{id:"dockMacro",label:"Dock macro",kind:"button",section:"Mode macros"},{id:"nightVisionToggle",label:"Night vision toggle",kind:"button",section:"Camera"}],Lp=.45,$j=.6;function Ps({label:a,description:l,min:i,max:o,step:f,value:d,onChange:h}){return r.jsxs("label",{className:"surface-muted block p-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-300",children:[r.jsx("span",{className:"font-semibold text-slate-100",children:a}),r.jsx("span",{className:"font-mono text-slate-400",children:Kn.format(d)})]}),l&&r.jsx("p",{className:"text-[0.65rem] text-slate-500",children:l}),r.jsx("input",{type:"range",min:i,max:o,step:f,value:d,onChange:p=>h(Number(p.target.value)),className:"mt-0 w-full accent-emerald-400"})]})}function Gj(a){if(!a)return"Unassigned";if(a.kind==="axisPair"){const l=`${a.invertX?"X inv ":""}${a.invertY?"Y inv":""}`.trim();return`Axes ${a.x}/${a.y}${l?` (${l})`:""}`}if(a.kind==="axis")return`Axis ${a.index}${a.invert?" (inv)":""}`;if(a.kind==="button")return`Button ${a.index}`;if(a.kind==="buttonAxis")return`Button ${a.index} (analog)`;if(a.kind==="axisButton"){const l=a.direction<0?"<":">";return`Axis ${a.index} ${l} ${Kn.format(a.threshold??.6)}`}return"Unassigned"}function Xj(a){return a.reduce((l,i)=>((l[i.section]||(l[i.section]=[])).push(i),l),{})}function Qj(a,l){if(!a||a.length===0)return null;if(l){const i=a.find(o=>o.signature===l);if(i)return i}return a[0]}function Kj(a){return{axes:Array.from(a.axes??[]),buttons:(a.buttons??[]).map(l=>({pressed:!!l?.pressed,value:typeof l?.value=="number"?l.value:l?.pressed?1:0}))}}function Fj(a,l,i){const o=(a.axes??[]).map((d,h)=>({index:h,delta:Math.abs((d??0)-(l.axes?.[h]??0)),value:d}));if(o.sort((d,h)=>h.delta-d.delta),i.kind==="axisPair"){const d=o.filter(h=>h.delta>Lp).slice(0,2);return d.length<2?null:{kind:"axisPair",x:d[0].index,y:d[1].index,...i.invertDefaults??{}}}const f=o.find(d=>d.delta>Lp);return f?{kind:"axis",index:f.index,...i.invertDefaults??{}}:null}function Zj(a,l,i){const o=a.buttons??[];for(let d=0;d$j)return i.kind==="axis"?{kind:"buttonAxis",index:d}:{kind:"button",index:d}}const f=a.axes??[];for(let d=0;d.7&&p>.5)return i.kind==="axis"?{kind:"axis",index:d,...i.invertDefaults??{}}:{kind:"axisButton",index:d,direction:h>=0?1:-1,threshold:.6}}return null}function Jj(a,l,i){if(!a)return null;if(i.kind==="axis"||i.kind==="axisPair"){const o=Fj(a,l,i);if(o)return o}return Zj(a,l,i)}function Ij(){const a=qA(),{value:l,save:i}=st("gamepad",ja),[o,f]=m.useState(null),d=m.useRef(null),h=m.useMemo(()=>Xj(Yj),[]),p=m.useMemo(()=>Qj(a.pads,l.activeSignature),[a.pads,l.activeSignature]),g=p?.signature??null,v=m.useMemo(()=>g?l?.profiles?.[g]??l?.defaults?.profile??Fn:l?.defaults?.profile??Fn,[g,l?.defaults?.profile,l?.profiles]);m.useEffect(()=>{!p||!g||l?.profiles?.[g]||i(N=>{const E=N??ja;if(E.profiles?.[g])return E;const S=E?.defaults?.profile??Fn,T=Gx(p,S);return{...E,profiles:{...E.profiles??{},[g]:T}}})},[p,g,l?.profiles,i]),m.useEffect(()=>{d.current=null},[o,g]),m.useEffect(()=>{if(!o||!p)return;if(!d.current){d.current=Kj(p);return}const N=Jj(p,d.current,o);N&&(i(E=>{const S=E??ja,T=S.profiles?.[g]??S?.defaults?.profile??Fn,z={...T,bindings:{...T.bindings??{},[o.id]:{...T.bindings?.[o.id]??{},kind:o.kind,sources:[N]}}};return{...S,profiles:{...S.profiles??{},[g]:z}}}),f(null))},[p,g,o,i]);const y=m.useCallback(N=>{i(E=>({...E??ja,activeSignature:N||null}))},[i]),b=m.useCallback(N=>{i(E=>{const S=E??ja,T=(g&&S.profiles?.[g])??S?.defaults?.profile??Fn,z={...T,calibration:{...T.calibration??{},...N}};return g?{...S,profiles:{...S.profiles??{},[g]:z}}:{...S,defaults:{...S.defaults??{},profile:z}}})},[g,i]),j=m.useCallback((N,E)=>{i(S=>{const T=S??ja,z=(g&&T.profiles?.[g])??T?.defaults?.profile??Fn,L=E(z.bindings?.[N]??{}),$={...z,bindings:{...z.bindings??{},[N]:L}};return g?{...T,profiles:{...T.profiles??{},[g]:$}}:{...T,defaults:{...T.defaults??{},profile:$}}})},[g,i]),M=m.useCallback(N=>{j(N.id,E=>({...E,sources:[]}))},[j]),w=m.useCallback((N,E)=>{j(N.id,S=>{const T=Array.isArray(S.sources)?[...S.sources]:[];if(!T[0])return S;const z={...T[0]};return E==="invertX"?z.invertX=!z.invertX:E==="invertY"?z.invertY=!z.invertY:z.invert=!z.invert,T[0]=z,{...S,sources:T}})},[j]),q=m.useMemo(()=>p?{outputs:Xx(p,v)}:null,[p,v]);return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("div",{className:"flex items-center justify-between",children:r.jsxs("div",{children:[r.jsx("p",{className:"text-xs text-slate-400",children:"Controller"}),r.jsx("p",{className:"text-[0.65rem] text-slate-500",children:p?"Move sticks or press buttons to bind":"Connect a controller to configure."}),o&&r.jsxs("p",{className:"mt-0 text-[0.7rem] text-emerald-400",children:["Capturing ",o.label,"…"]})]})}),r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Connected controller"}),a.pads.length===0?r.jsx("p",{className:"text-[0.7rem] text-slate-400",children:"No controller detected."}):r.jsxs("div",{className:"flex items-center justify-between gap-0.5 text-xs",children:[r.jsx("select",{value:g??"",onChange:N=>y(N.target.value),className:"flex-1 rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-[0.75rem] text-slate-100",children:a.pads.map(N=>r.jsx("option",{value:N.signature,children:N.id||"Unknown controller"},N.signature))}),r.jsx("span",{className:"text-[0.7rem] text-slate-400",children:p?.mapping??"unknown"})]})]}),r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Calibration"}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsx(Ps,{label:"Drive deadzone",description:"Ignore small drive stick drift",min:0,max:.6,step:.01,value:v.calibration?.driveDeadzone??.18,onChange:N=>b({driveDeadzone:N})}),r.jsx(Ps,{label:"Camera deadzone",description:"Ignore small camera tilt drift",min:0,max:.4,step:.01,value:v.calibration?.cameraDeadzone??.08,onChange:N=>b({cameraDeadzone:N})}),r.jsx(Ps,{label:"Aux deadzone",description:"Ignore small trigger noise",min:0,max:.4,step:.01,value:v.calibration?.auxDeadzone??.05,onChange:N=>b({auxDeadzone:N})}),r.jsx(Ps,{label:"Side brush scale",description:"Scale side brush output",min:.3,max:1,step:.05,value:v.calibration?.auxSideScale??.55,onChange:N=>b({auxSideScale:N})}),r.jsxs("label",{className:"surface-muted block p-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-300",children:[r.jsx("span",{className:"font-semibold text-slate-100",children:"Camera mode"}),r.jsxs("select",{value:v.calibration?.cameraMode??"absolute",onChange:N=>b({cameraMode:N.target.value}),className:"rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-[0.75rem] text-slate-100",children:[r.jsx("option",{value:"absolute",children:"Absolute"}),r.jsx("option",{value:"velocity",children:"Velocity"})]})]}),r.jsx("p",{className:"text-[0.65rem] text-slate-500",children:"Absolute maps stick to angle; velocity moves over time."})]}),r.jsx(Ps,{label:"Camera sensitivity",description:"Velocity mode degrees per second",min:10,max:180,step:5,value:v.calibration?.cameraSensitivity??60,onChange:N=>b({cameraSensitivity:N})})]})]}),r.jsx("div",{className:"space-y-0.5",children:Object.entries(h).map(([N,E])=>r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:N}),r.jsx("div",{className:"space-y-0.5",children:E.map(S=>{const z=v.bindings?.[S.id]?.sources?.[0]??null;return r.jsxs("div",{className:"surface-muted flex items-center justify-between text-xs",children:[r.jsxs("div",{children:[r.jsx("p",{className:"font-semibold text-slate-100",children:S.label}),r.jsx("p",{className:"text-[0.65rem] text-slate-400",children:Gj(z)})]}),r.jsxs("div",{className:"flex items-center gap-0.5",children:[S.kind==="axisPair"&&r.jsxs(r.Fragment,{children:[r.jsx("button",{type:"button",disabled:!z,onClick:()=>w(S,"invertX"),className:"button-dark text-[0.7rem] font-medium disabled:opacity-50",children:"Invert X"}),r.jsx("button",{type:"button",disabled:!z,onClick:()=>w(S,"invertY"),className:"button-dark text-[0.7rem] font-medium disabled:opacity-50",children:"Invert Y"})]}),S.kind==="axis"&&r.jsx("button",{type:"button",disabled:!z,onClick:()=>w(S),className:"button-dark text-[0.7rem] font-medium disabled:opacity-50",children:"Invert"}),r.jsx("button",{type:"button",onClick:()=>M(S),className:"button-dark text-[0.7rem]",children:"Clear"}),r.jsx("button",{type:"button",onClick:()=>f(S),className:`${o?.id===S.id?"px-0.5 py-0.5 bg-emerald-500 text-emerald-950 hover:bg-emerald-400":"button-dark"} text-[0.7rem] font-medium`,children:o?.id===S.id?"Waiting…":"Capture"})]})]},S.id)})})]},N))}),r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"Diagnostics"}),p?r.jsxs("div",{className:"space-y-0.5 text-[0.7rem] text-slate-300",children:[r.jsx("p",{className:"text-slate-400",children:"Raw axes"}),r.jsx("div",{className:"grid grid-cols-2 gap-0.5",children:p.axes.map((N,E)=>r.jsxs("span",{className:"font-mono text-slate-300",children:["A",E,": ",Kn.format(N)]},`axis-${E}`))}),r.jsx("p",{className:"text-slate-400",children:"Raw buttons"}),r.jsx("div",{className:"grid grid-cols-2 gap-0.5",children:p.buttons.map((N,E)=>r.jsxs("span",{className:"font-mono text-slate-300",children:["B",E,": ",Kn.format(N.value)," ",N.pressed?"●":""]},`btn-${E}`))}),q?.outputs&&r.jsxs(r.Fragment,{children:[r.jsx("p",{className:"text-slate-400",children:"Mapped outputs"}),r.jsxs("div",{className:"grid grid-cols-2 gap-0.5",children:[r.jsxs("span",{className:"font-mono text-slate-300",children:["Drive: ",Kn.format(q.outputs.driveVector.x),","," ",Kn.format(q.outputs.driveVector.y)]}),r.jsxs("span",{className:"font-mono text-slate-300",children:["Camera: ",Kn.format(q.outputs.cameraAxis)]}),r.jsxs("span",{className:"font-mono text-slate-300",children:["Main: ",Kn.format(q.outputs.auxAxis.main)]}),r.jsxs("span",{className:"font-mono text-slate-300",children:["Side: ",Kn.format(q.outputs.auxAxis.side)]})]})]})]}):r.jsx("p",{className:"text-[0.7rem] text-slate-400",children:"No controller detected."})]})]})}const Wj={drive:"Drive wheels",aux:"Aux motors"};function Up(a){return Number.isFinite(a)?`${Math.round(a*100)}%`:"--"}function Pj({value:a,color:l="bg-emerald-500"}){const i=`${Math.round(Math.max(0,Math.min(1,a))*100)}%`;return r.jsx("div",{className:"h-2 w-full overflow-hidden rounded bg-slate-800",children:r.jsx("div",{className:`h-full ${l}`,style:{width:i}})})}function eN(){const{state:{roverId:a},overcurrentLimiter:l}=Dt(),i=m.useMemo(()=>Ql.map(o=>o.key),[]);return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-400",children:[r.jsx("span",{children:"Overcurrent limiter"}),r.jsx("span",{children:l?.adminImmune?"Admin immune":"Active"})]}),a?r.jsxs("div",{className:"space-y-0.5",children:[i.map(o=>{const f=l?.caps?.[o]?.cap??0,d=l?.overcurrent?.groups?.[o]??!1,h=l?.scales?.perGroup?.[o]??1;return r.jsxs("div",{className:"surface space-y-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs",children:[r.jsx("span",{className:"text-slate-200",children:Wj[o]||o}),r.jsx("span",{className:d?"text-red-300":"text-slate-400",children:d?"overcurrent":"ok"})]}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-[0.7rem] text-slate-400",children:[r.jsx("span",{children:"Cap"}),r.jsx("span",{children:Up(f)})]}),r.jsx(Pj,{value:f,color:"bg-amber-500"}),r.jsxs("div",{className:"flex items-center justify-between text-[0.7rem] text-slate-400",children:[r.jsx("span",{children:"Scale"}),r.jsx("span",{children:Up(h)})]})]})]},o)}),r.jsxs("div",{className:"surface text-[0.7rem] text-slate-400",children:[r.jsx("div",{children:`Down rate ${l?.config?.downRatePerSec}/s · Up rate ${l?.config?.upRatePerSec}/s`}),r.jsx("div",{children:`Release delay ${l?.config?.releaseDelaySec}s`}),r.jsx("div",{children:`Output rate ${l?.config?.outputRateMs}ms`})]})]}):r.jsx("p",{className:"text-xs text-slate-500",children:"Assign a rover to view limiter status."})]})}const og=m.createContext(null);function cg(){const a=m.useContext(og);if(!a)throw new Error("Tabs components must be used within a provider.");return a}const Hp={primary:{base:"flex-1 px-0.5 py-0.5 text-sm font-medium transition-colors focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-slate-500 rounded-md",active:"bg-sky-600 text-white",inactive:"bg-zinc-900 text-slate-300 hover:bg-sky-500 hover:text-white"}},ug="primary";function Zf(...a){return a.filter(Boolean).join(" ")}function Jf({children:a,defaultTab:l,currentTab:i,onTabChange:o,variant:f=ug}){const[d,h]=m.useState(l??null),[p,g]=m.useState([]),v=m.useCallback(M=>M?(g(w=>w.includes(M)?w:[...w,M]),()=>g(w=>w.includes(M)?w.filter(q=>q!==M):w)):()=>{},[]),y=i??d??p[0]??null;m.useEffect(()=>{l&&i===void 0&&h(l)},[l,i]);const b=m.useCallback(M=>{M&&(i===void 0&&h(M),o&&o(M))},[i,o]),j=m.useMemo(()=>({activeTab:y,setActiveTab:b,registerTab:v,variant:f}),[y,b,v,f]);return r.jsx(og.Provider,{value:j,children:a})}function If({children:a,className:l=""}){return r.jsx("div",{className:Zf("flex gap-0.5",l),children:a})}function mn({id:a,children:l,className:i="",disabled:o=!1}){const{activeTab:f,setActiveTab:d,registerTab:h,variant:p}=cg();m.useEffect(()=>h(a),[a,h]);const g=Hp[p]??Hp[ug],v=f===a,y=Zf(g.base,v?g.active:g.inactive,o?"cursor-not-allowed opacity-50":"",i);return r.jsx("button",{type:"button",className:y,onClick:()=>!o&&d(a),"aria-pressed":v,"aria-disabled":o,children:l})}function Wf({children:a,className:l=""}){return r.jsx("div",{className:Zf("mt-0 space-y-0.5",l),children:a})}function hn({id:a,children:l,keepMounted:i=!1}){const{activeTab:o}=cg(),f=o===a;return!f&&!i?null:!f&&i?r.jsx("div",{hidden:!0,"aria-hidden":"true",children:l}):r.jsx(r.Fragment,{children:l})}function tN(){const{session:a}=Ve(),l=m.useMemo(()=>JSON.stringify(a??{},null,2),[a]);return r.jsxs("div",{className:"panel-section flex min-h-0 flex-col gap-0.5 text-xs",children:[r.jsx("p",{className:"text-sm text-slate-400",children:"Session snapshot"}),r.jsx("pre",{className:"surface min-h-0 flex-1 overflow-y-auto font-mono text-[0.7rem] text-lime-300",children:l})]})}const Vp=300,Yp=240;function nN(a,l){if(a===void 0)return"undefined";if(a===null)return"null";if(typeof a=="string")return a;if(typeof a=="number"||typeof a=="boolean")return String(a);if(typeof a=="function")return"[Function]";if(a instanceof Error)return`${a.name}: ${a.message}`;if(a instanceof Date)return a.toISOString();if(l||(l=new WeakSet),typeof a=="object"){if(l.has(a))return"[Circular]";l.add(a)}try{return JSON.stringify(a,(i,o)=>typeof o=="function"?"[Function]":o instanceof Error?`${o.name}: ${o.message}`:o,0)}catch{return String(a)}}function aN(a){const i=a.map(o=>nN(o)).join(" ");return i.length>Yp?`${i.slice(0,Yp)}…`:i}function lN(){const a=En(),[l,i]=m.useState([]),o=m.useMemo(()=>l.reduce((f,d)=>(d.direction==="in"&&(f.in+=1),d.direction==="out"&&(f.out+=1),f),{in:0,out:0}),[l]);return m.useEffect(()=>{const f=(g,v,y)=>{i(b=>{const j=[...b,{id:`${Date.now()}-${Math.random().toString(16).slice(2)}`,direction:g,event:v,payload:aN(y),timestamp:new Date().toLocaleTimeString()}];return j.length>Vp?j.slice(-Vp):j})},d=(g,...v)=>f("in",g,v),h=(g,...v)=>f("out",g,v);a.onAny(d);let p=null;if(typeof a.onAnyOutgoing=="function")a.onAnyOutgoing(h),p=()=>a.offAnyOutgoing(h);else{const g=a.emit.bind(a);a.emit=(v,...y)=>(h(v,...y),g(v,...y)),p=()=>{a.emit=g}}return()=>{a.offAny(d),p&&p()}},[a]),r.jsxs("section",{className:"panel-section space-y-0.5 text-base",children:[r.jsxs("div",{className:"flex items-center justify-between text-sm text-slate-400",children:[r.jsx("span",{children:"Socket activity"}),r.jsxs("div",{className:"flex items-center gap-0.5 text-xs text-slate-400",children:[r.jsxs("span",{className:"surface-muted",children:["in ",o.in]}),r.jsxs("span",{className:"surface-muted",children:["out ",o.out]}),r.jsx("button",{type:"button",className:"button-dark text-xs",onClick:()=>i([]),children:"Clear"})]})]}),r.jsx("div",{className:"surface h-64 overflow-y-auto font-mono text-xs",children:l.length===0?r.jsx("p",{children:"No socket activity yet."}):l.slice().reverse().map(f=>r.jsxs("div",{className:"surface",children:[r.jsx("span",{className:"text-slate-400",children:f.timestamp})," ",r.jsxs("span",{className:f.direction==="in"?"text-emerald-400":"text-amber-400",children:["[",f.direction.toUpperCase(),"]"]})," ",r.jsx("span",{className:"text-cyan-300",children:f.event})," ",r.jsx("span",{className:"text-slate-200",children:f.payload})]},f.id))}),r.jsx("p",{className:"text-xs text-slate-500",children:"Logs are collected only while this panel is open."})]})}const sN=[{key:"start",label:"Start OI"},{key:"safe",label:"Safe"},{key:"full",label:"Full"},{key:"passive",label:"Passive"},{key:"dock",label:"Dock"}];function fg(){const{state:{roverId:a},actions:{sendOiCommand:l,setSensorStream:i}}=Dt(),o=!!a,[f,d]=lg(),h=En(),{value:p,save:g}=st("page",{hudMapDesktop:!1,connectionTransport:"websocket"}),{value:v,save:y}=st("audio",jt),b=p?.connectionTransport||"websocket",j=Number.isFinite(v?.masterVolume)?v.masterVolume:jt.masterVolume,M=Number.isFinite(v?.alertVolume)?v.alertVolume:jt.alertVolume,w=Number.isFinite(v?.roverVolume)?v.roverVolume:jt.roverVolume,q=typeof v?.mainBrushDuckEnabled=="boolean"?v.mainBrushDuckEnabled:typeof v?.autoLevelEnabled=="boolean"?v.autoLevelEnabled:jt.mainBrushDuckEnabled,N=Number.isFinite(v?.mainBrushDuckAmount)?Math.max(0,Math.min(1,v.mainBrushDuckAmount)):jt.mainBrushDuckAmount,E=m.useMemo(()=>[{key:"start",label:"Enable stream",enable:!0},{key:"stop",label:"Disable stream",enable:!1}],[]),S=$=>{a&&i($)},T=$=>{const O=$.target.value;g(V=>({...V??{},connectionTransport:O})),h?.io?.opts&&(h.io.opts.transports=O==="polling"?["polling"]:["websocket","polling"],h.disconnect(),h.connect())},z=$=>O=>{const V=Number(O.target.value),X=Number.isFinite(V)?Math.max(0,Math.min(1,V)):0;y(Z=>({...Z??{},[$]:X}))},L=$=>{const O=!!$.target.checked;y(V=>({...V??{},mainBrushDuckEnabled:O}))};return r.jsxs(Jf,{defaultTab:"keybindings",children:[r.jsxs(If,{children:[r.jsx(mn,{id:"keybindings",children:"Keybindings"}),r.jsx(mn,{id:"controller",children:"Controller"}),r.jsx(mn,{id:"page",children:"Page settings"}),r.jsx(mn,{id:"admin",children:"Admin"})]}),r.jsxs(Wf,{children:[r.jsx(hn,{id:"keybindings",children:r.jsx("div",{className:"space-y-0.5",children:r.jsx(Vj,{})})}),r.jsx(hn,{id:"controller",children:r.jsx("div",{className:"space-y-0.5",children:r.jsx(Ij,{})})}),r.jsx(hn,{id:"page",children:r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-slate-400",children:"HUD"}),r.jsxs("label",{className:"flex items-center gap-0.5 text-slate-200",children:[r.jsx("input",{type:"checkbox",className:"accent-emerald-500",checked:f,onChange:$=>d($.target.checked)}),r.jsx("span",{children:"Show top-down map in HUD (desktop)"})]}),r.jsx("p",{className:"text-xs text-slate-500",children:"Mobile HUD keeps the map on by default."})]}),r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-slate-400",children:"Audio"}),r.jsxs("label",{className:"grid gap-0.5 text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{children:"Master volume"}),r.jsxs("span",{className:"text-xs text-slate-400",children:[Math.round(j*100),"%"]})]}),r.jsx("input",{type:"range",min:"0",max:"1",step:"0.01",value:j,onChange:z("masterVolume"),className:"w-full accent-emerald-500"})]}),r.jsxs("label",{className:"grid gap-0.5 text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{children:"Alert/page sounds"}),r.jsxs("span",{className:"text-xs text-slate-400",children:[Math.round(M*100),"%"]})]}),r.jsx("input",{type:"range",min:"0",max:"1",step:"0.01",value:M,onChange:z("alertVolume"),className:"w-full accent-emerald-500"})]}),r.jsxs("label",{className:"grid gap-0.5 text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{children:"Rover audio"}),r.jsxs("span",{className:"text-xs text-slate-400",children:[Math.round(w*100),"%"]})]}),r.jsx("input",{type:"range",min:"0",max:"1",step:"0.01",value:w,onChange:z("roverVolume"),className:"w-full accent-emerald-500"})]}),r.jsxs("label",{className:"flex items-center justify-between gap-0.5 text-slate-200",children:[r.jsx("span",{children:"Main brush ducking"}),r.jsx("input",{type:"checkbox",className:"accent-emerald-500",checked:q,onChange:L})]}),r.jsxs("label",{className:"grid gap-0.5 text-slate-200",children:[r.jsxs("div",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{children:"Main brush duck amount"}),r.jsxs("span",{className:"text-xs text-slate-400",children:[Math.round(N*100),"%"]})]}),r.jsx("input",{type:"range",min:"0",max:"1",step:"0.01",value:N,onChange:z("mainBrushDuckAmount"),className:"w-full accent-emerald-500",disabled:!q})]}),r.jsx("p",{className:"text-xs text-slate-500",children:"Lowers rover audio only while the main brush is running."})]}),r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-slate-400",children:"Connection"}),r.jsxs("label",{className:"flex items-center justify-between gap-0.5 text-slate-200",children:[r.jsx("span",{children:"Transport"}),r.jsxs("select",{value:b,onChange:T,className:"field-input text-sm",children:[r.jsx("option",{value:"websocket",children:"WebSocket"}),r.jsx("option",{value:"polling",children:"Polling"})]})]}),r.jsx("p",{className:"text-xs text-slate-500",children:"Switching reconnects your session."})]})]})}),r.jsx(hn,{id:"admin",children:r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-slate-400",children:"Manual OI commands"}),r.jsx("div",{className:"surface flex flex-wrap gap-0.5",children:sN.map($=>r.jsx("button",{type:"button",onClick:()=>l($.key),disabled:!o,className:"button-dark text-xs disabled:opacity-30",children:$.label},$.key))})]}),r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-slate-400",children:"Sensor stream"}),r.jsx("div",{className:"surface flex gap-0.5",children:E.map($=>r.jsx("button",{type:"button",onClick:()=>S($.enable),disabled:!o,className:"flex-1 button-dark text-xs disabled:opacity-30",children:$.label},$.key))}),!o&&r.jsx("p",{className:"text-xs text-slate-500",children:"Assign a rover to toggle streams."})]}),r.jsx(rg,{}),r.jsx(eN,{}),r.jsx(kj,{}),r.jsx(tN,{}),r.jsx(lN,{})]})})]})]})}const $p={desktop:{main:[{type:"list",title:"Chat and nicknames",items:["Set a nickname in the user list panel, on the bottom left of the page below the rover video.",{segments:["Toggle chat focus with ",{action:"chatFocus"},". Press ",{action:"chatFocus"}," again to send."]}]},{type:"list",title:"Driving the rover",items:[{segments:['Press the "Start Driving" button onscreen, or press ',{action:"driveMacro"}," on your keyboard to put the rover into driving mode."]},"Refer to the controls for the controls for the rover."]},{type:"list",title:"Docking the rover",items:["Line up the rover to the dock, about a foot away, then:",{segments:['Press the "Dock and Charge" button onscreen, or press ',{action:"dockMacro"}," on your keyboard to start docking."]},"Wait for the rover to confirm it is docked and charging before leaving it unattended."]}],aside:[{type:"keyboard",title:"Keyboard controls",footnote:"Per-browser; adjust bindings and speeds in Settings → Keybindings.",groups:[{id:"movement",title:"Movement",items:[{action:"driveForward",label:"Forward"},{action:"driveBackward",label:"Backward"},{action:"driveLeft",label:"Turn left"},{action:"driveRight",label:"Turn right"},{action:"boostModifier",label:"Boost speed"},{action:"slowModifier",label:"Precision speed"}]},{id:"macros",title:"Rover modes & chat",items:[{action:"driveMacro",label:"Drive macro"},{action:"dockMacro",label:"Dock macro"},{action:"chatFocus",label:"Chat focus"}]},{id:"camera",title:"Camera",items:[{action:"cameraUp",label:"Tilt up"},{action:"cameraDown",label:"Tilt down"},{action:"nightVisionToggle",label:"Toggle night vision"}]},{id:"motors",title:"Rover Aux Motors",items:[{action:"auxMainForward",label:"Main brush forward"},{action:"auxMainReverse",label:"Main brush reverse"},{action:"auxSideForward",label:"Side brush forward"},{action:"auxSideReverse",label:"Side brush reverse"},{action:"auxVacuumFast",label:"Vacuum max"},{action:"auxVacuumSlow",label:"Vacuum low"},{action:"auxAllForward",label:"All motors forward"}]},{id:"audio",title:"Audio / Song",items:[{action:"songNoteUp",label:"Song note up"},{action:"songNoteDown",label:"Song note down"}]},{id:"room-controls",title:"Room Controls",items:[{action:"homeAssistantOn",label:"Next room control on"},{action:"homeAssistantOff",label:"Next room control off (reverse)"}]}]},{type:"gamepad",title:"Gamepad / joystick",items:["Gamepad controls are fully configurable to handle inconsistent browser mappings.","Use Settings → Controller to bind inputs, calibrate deadzones, and view diagnostics.","If inputs behave oddly, the diagnostics panel will show raw axis/button values."]}]},"mobile-portrait":{main:[{type:"list",title:"Chat and nicknames",items:["Set a nickname in the user list panel below.","Tap in the chat box to send messages in the chat."]},{type:"list",title:"Driving the rover",items:[{segments:['Press the "Start Driving" button onscreen to put the rover into driving mode.']},"Look below the rover video. Use the joystick on the right to move the rover, and hold the buttons on the left to run the aux motors."]},{type:"list",title:"Docking the rover",items:["Line up the rover to the dock, about a foot away, then:",{segments:['Press the "Dock and Charge" button onscreen to start docking.']},"Wait for the rover to confirm it is docked and charging before leaving it unattended."]}]},"mobile-landscape":{main:[{type:"list",title:"Chat and nicknames",items:["Scroll down to see more of the page.","Set a nickname in the user list panel below.","Tap in the chat box to send messages in the chat."]},{type:"list",title:"Driving the rover",items:[{segments:['Press the "Start Driving" button, or the "Drive" button to put the rover into driving mode.']},"Use the joystick to the right of the video feed to move the rover, and hold the buttons on the left to run the aux motors."]},{type:"list",title:"Docking the rover",items:["Line up the rover to the dock, about a foot away, then:",{segments:['Press the "Dock and Charge" or the "Dock" button onscreen to start docking.']},"Wait for the rover to confirm it is docked and charging before leaving it unattended."]}]}};function iN(a){return $p[a]||$p.desktop}function dg({actionId:a,keymap:l}){const i=l?.[a]?.[0]??"";return r.jsx("span",{className:"rounded border border-slate-600 bg-slate-900/40 px-1 text-[0.7rem] text-slate-200",children:An(i)})}function Gp(a,l){return a.map((i,o)=>typeof i=="string"?r.jsx("span",{children:i},`text-${o}`):i?.action?r.jsx(dg,{actionId:i.action,keymap:l},`pill-${i.action}-${o}`):i?.text?r.jsx("span",{children:i.text},`span-${o}`):null)}function oo(a,l,i){if(typeof a=="string")return a;if(Array.isArray(a?.segments))return Gp(a.segments,l);if(a&&typeof a=="object"){if(typeof a.text=="string")return a.text;if(Array.isArray(a))return Gp(a,l)}return String(a??"")}function rN({hero:a,keymap:l}){return a?r.jsxs("div",{className:"surface space-y-0.5 px-0.5 py-0.5",children:[r.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-0.5",children:[r.jsxs("div",{children:[r.jsx("p",{className:"text-sm font-semibold text-white",children:a.title}),a.subtitle&&r.jsx("p",{className:"text-xs text-slate-300",children:a.subtitle})]}),a.chips&&r.jsx("div",{className:"flex flex-wrap gap-0.5 text-[0.7rem] text-slate-200",children:a.chips.map(i=>r.jsx("span",{className:"rounded border border-slate-700 px-1 py-[2px]",children:i},i))})]}),a.bullets&&r.jsx("ul",{className:"space-y-0.5 text-[0.85rem] text-slate-200",children:a.bullets.map((i,o)=>{const f=Array.isArray(i?.segments)?`hero-${o}`:`hero-${o}`;return r.jsx("li",{className:"surface-muted px-0.5 py-0.25",children:oo(i,l)},f)})})]}):null}function oN({block:a,keymap:l}){return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("p",{className:"text-xs font-semibold text-slate-200",children:a.title}),r.jsx("ul",{className:"space-y-0.5 text-[0.8rem] text-slate-300",children:a.items.map((i,o)=>{const f=`item-${o}`;return r.jsx("li",{className:"surface-muted flex flex-wrap items-center gap-0.5 px-0.5 py-0.25",children:oo(i,l)},f)})})]})}function cN({block:a}){const l=a.tone==="info"?"border-cyan-500/40":"border-slate-700";return r.jsxs("div",{className:`surface space-y-0.5 border ${l} px-0.5 py-0.5`,children:[r.jsx("p",{className:"text-xs font-semibold text-slate-100",children:a.title}),a.body&&r.jsx("ul",{className:"space-y-0.5 text-[0.8rem] text-slate-300",children:a.body.map((i,o)=>r.jsx("li",{className:"surface-muted px-0.5 py-0.25",children:oo(i,{})},`callout-${o}`))})]})}function uN({group:a,keymap:l}){return r.jsxs("div",{className:"space-y-0.5 surface",children:[r.jsx("p",{className:"px-0.5 py-0.25 text-[0.75rem] font-semibold text-slate-200",children:a.title}),r.jsx("div",{className:"space-y-0.5 px-0.5 pb-0.25",children:a.items.map(i=>r.jsxs("div",{className:"surface-muted flex items-center justify-between gap-0.5 px-0.5 py-0.25 text-[0.8rem]",children:[r.jsx("span",{className:"text-slate-200",children:i.label}),r.jsx(dg,{actionId:i.action,keymap:l})]},i.action))})]})}function fN({block:a,keymap:l}){return a?r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-200",children:[r.jsx("span",{className:"font-semibold",children:a.title}),a.footnote&&r.jsx("span",{className:"text-[0.7rem] text-slate-400",children:a.footnote})]}),r.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-0.5",children:a.groups?.map(i=>r.jsx(uN,{group:i,keymap:l},i.id))})]}):null}function dN({block:a}){return a?r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("p",{className:"text-xs font-semibold text-slate-200",children:a.title}),r.jsx("ul",{className:"space-y-0.5 text-[0.8rem] text-slate-300",children:a.items?.map((l,i)=>r.jsx("li",{className:"surface-muted px-0.5 py-0.25",children:oo(l,{})},`gamepad-${i}`))})]}):null}function Xp({block:a,keymap:l}){if(!a)return null;switch(a.type){case"list":return r.jsx(oN,{block:a,keymap:l});case"callout":return r.jsx(cN,{block:a});case"keyboard":return r.jsx(fN,{block:a,keymap:l});case"gamepad":return r.jsx(dN,{block:a});default:return null}}function mg({layout:a,keymap:l}){const i=m.useMemo(()=>iN(a),[a]),o=l||{},f=i.main||[],d=i.aside||[];return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx(rN,{hero:i.hero,keymap:o}),r.jsxs("div",{className:"grid gap-0.5",style:{gridTemplateColumns:"repeat(auto-fit, minmax(360px, 1fr))"},children:[r.jsx("div",{className:"space-y-0.5",children:f.map((h,p)=>r.jsx(Xp,{block:h,keymap:o},h.title||p))}),r.jsx("div",{className:"space-y-0.5",children:d.map((h,p)=>r.jsx(Xp,{block:h,keymap:o},h.title||p))})]})]})}function hg({layout:a,onOpenOverlay:l}){const{state:i}=Dt();return r.jsxs("section",{className:"panel-section space-y-0.5 text-sm",children:[r.jsxs("div",{className:"flex items-center justify-between text-xs text-slate-400",children:[r.jsx("span",{children:"Help"}),r.jsx("button",{type:"button",onClick:l,className:"button-dark px-1 py-0.25 text-[0.75rem]",children:"Open full help"})]}),r.jsx(mg,{layout:a,keymap:i?.keymap||{}})]})}const mN=["kal","rms","slt","ksp","bdl"],hN=Array.from({length:10},(a,l)=>l*10);function co({hideInput:a=!1,hideSpectatorNotice:l=!1,fillHeight:i=!1,allowSpectatorInput:o=!1}){const{session:f}=Ve(),{messages:d,typing:h,sendMessage:p,registerInputRef:g,onInputFocus:v,onInputBlur:y,blurChat:b,setTypingActive:j}=Lf(),{value:M,save:w}=st("tts",{engine:"flite",voice:"rms",pitch:50}),[q,N]=m.useState(""),[E,S]=m.useState(!1),[T,z]=m.useState(!1),[L,$]=m.useState(()=>M?.engine||"flite"),[O,V]=m.useState(()=>M?.voice||"rms"),[X,Z]=m.useState(()=>Number.isFinite(M?.pitch)?M.pitch:50),F=f?.role!=="spectator"||o,ae=m.useRef(null),oe=f?.assignment?.roverId||null,G=!!m.useMemo(()=>f?.roster?.find(C=>String(C.id)===String(oe))||null,[oe,f?.roster])?.audio?.ttsEnabled,k=m.useMemo(()=>d.slice(-200),[d]),Q=m.useMemo(()=>h||[],[h]);m.useEffect(()=>{ae.current&&(ae.current.scrollTop=ae.current.scrollHeight)},[k,Q]),m.useEffect(()=>{const C=M?.engine||"flite",_=M?.voice||"rms",W=Number.isFinite(M?.pitch)?M.pitch:50;L!==C&&$(C),O!==_&&V(_),X!==W&&Z(W)},[L,X,M?.engine,M?.pitch,M?.voice,O]),m.useEffect(()=>{z(!!G)},[G]);const P=m.useMemo(()=>!G||!T?null:L==="espeak"?{speak:!0,engine:L,pitch:X}:{speak:!0,engine:L,voice:O},[L,X,T,G,O]);async function re(C){if(C.preventDefault(),!F||a)return;const W=q.replace(/\\n/g,` `).trim();if(W){S(!0);try{await p(W,P),N(""),b(),j(!1)}catch(te){alert(te.message)}finally{S(!1)}}}const ce=i?"flex-1 min-h-0 overflow-y-auto":"h-48 overflow-y-auto";return r.jsxs("section",{className:`panel-section space-y-0.5 text-base ${i?"flex h-full flex-col overflow-hidden":""}`,children:[r.jsxs("div",{className:`surface overflow-y-auto space-y-0.5 px-0 ${ce}`,ref:ae,children:[k.length===0&&Q.length===0?r.jsx("p",{className:"text-sm text-slate-500",children:"No messages yet."}):k.map(C=>r.jsx(Ox,{message:C},C.id)),Q.map(C=>r.jsx(Bx,{message:C},`typing-${C.typingId||C.id}`))]}),!a&&r.jsxs("form",{className:"flex flex-wrap items-stretch gap-0.5",onSubmit:re,children:[r.jsx("input",{className:"field-input flex-1 min-w-[10rem]",value:q,onChange:C=>{const _=C.target.value;N(_),j(!!_.trim())},onFocus:C=>{v(C),j(!!q.trim())},onBlur:C=>{y(C),j(!1)},onKeyDown:C=>{C.key==="Enter"&&!q.trim()&&(C.preventDefault(),b(),j(!1))},ref:C=>g(C,{target:"panel"}),placeholder:F?"Type a message…":l?"":"Spectators cannot chat",disabled:!F}),G&&r.jsxs("div",{className:"flex flex-wrap items-center gap-0.5 basis-full sm:basis-auto",children:[r.jsxs("label",{className:"flex items-center gap-0.5 text-xs text-slate-300",children:[r.jsx("input",{type:"checkbox",checked:T,onChange:C=>z(C.target.checked),className:"accent-cyan-500"}),r.jsx("span",{children:"Speak"})]}),r.jsxs("select",{value:L,onChange:C=>{const _=C.target.value;$(_),w(W=>({...W||{},engine:_}))},className:"field-input text-xs",children:[r.jsx("option",{value:"flite",children:"flite"}),r.jsx("option",{value:"espeak",children:"espeak"})]}),L==="flite"?r.jsx("select",{value:O,onChange:C=>{const _=C.target.value;V(_),w(W=>({...W||{},voice:_}))},className:"field-input text-xs",children:mN.map(C=>r.jsx("option",{value:C,children:C},C))}):r.jsx("select",{value:X,onChange:C=>{const _=Number(C.target.value);Z(_),w(W=>({...W||{},pitch:_}))},className:"field-input text-xs",children:hN.map(C=>r.jsxs("option",{value:C,children:["pitch ",C]},C))})]}),r.jsx("button",{type:"submit",disabled:!F||E,className:"button-dark h-full disabled:opacity-50 self-stretch",children:E?"...":"Send"})]})]})}function Pf({compact:a=!1}){const{session:l,setNickname:i}=Ve(),{value:o,save:f}=st("profile",{nickname:""}),[d,h]=m.useState(o.nickname||""),[p,g]=m.useState(!1),v=l?.role!=="spectator";m.useEffect(()=>{h(o.nickname||"")},[o.nickname]);async function y(b){if(b.preventDefault(),!v)return;const j=(d||"").trim().slice(0,32);if(j){g(!0);try{await i(j),f({nickname:j})}catch(M){alert(M.message)}finally{g(!1)}}}return r.jsxs("form",{className:"grid w-full min-w-0 grid-cols-[minmax(0,1fr)_auto] items-stretch gap-0.5",onSubmit:y,children:[r.jsx("input",{className:"field-input flex-1 min-w-0",value:d,onChange:b=>h(b.target.value),maxLength:32,placeholder:"Enter a nickname",disabled:!v}),r.jsx("button",{type:"submit",disabled:!v||p,className:"button-dark h-full shrink-0 whitespace-nowrap px-0.5 py-0 disabled:opacity-50",children:p?"Saving…":a?"Set":"Save"})]})}function pN(a){const l=Array.isArray(a?.socials)?a.socials:null;if(l&&l.length)return l;const i=[];return a?.discord?.invite&&i.push({id:"discord",label:"Discord",url:a.discord.invite}),a?.kofi?.link&&i.push({id:"kofi",label:"Ko-fi",url:a.kofi.link}),i}function xN(a){if(!a||typeof a!="object")return null;const l=a.id||a.service||a.key||a.name||null,i=a.label||a.title||a.name||l||"Link",o=a.url||a.link||a.href||null;return o?{id:l,label:i,url:o}:null}function pg({className:a=""}){const{session:l}=Ve(),i=pN(l).map(xN).filter(Boolean).slice(0,4);return i.length?r.jsx("div",{className:`grid grid-cols-2 grid-rows-2 gap-0.5 ${a}`,children:i.map(o=>r.jsx(Xf,{...o},`${o.id||o.label}-${o.url}`))}):null}function gN({compact:a=!1}){return r.jsx("section",{className:"panel-section flex h-full min-h-0 flex-col gap-0.5 text-base",children:r.jsx("div",{className:"surface flex w-full items-center px-0 py-0",children:r.jsx(Pf,{compact:a})})})}function vN(){return r.jsx("section",{className:"panel-section flex h-full min-h-0 flex-col gap-0.5 text-base",children:r.jsx(pg,{className:"flex-1 min-h-0"})})}function Pu(...a){return a.filter(Boolean).join(" ")}function yN(a){const l=a?.batteryState?.percentDisplay;return l==null?"--":`${l}%`}function bN(a){return a?.batteryState?a.batteryState.urgentActive?"text-red-400":a.batteryState.warnActive?"text-amber-300":"text-emerald-300":"text-slate-400"}function SN(a){switch(a){case"admin":case"lockdown":case"lockdown-admin":return"text-amber-300";case"spectator":return"text-slate-400";default:return"text-sky-300"}}function AN(a,l){if(!a)return"";const i=a.nickname||a.socketId?.slice(0,6)||"unknown";return a.socketId&&a.socketId===l?`${i} (you)`:i}function uo({title:a="Rovers"}){const{session:l,requestControl:i}=Ve(),[o,f]=m.useState({}),[d,h]=m.useState(()=>Date.now()),p=m.useMemo(()=>l?.role&&l.role!=="spectator",[l?.role]),g=l?.roster??[],v=l?.turnQueues??{},y=l?.users??[],b=l?.socketId||null,j=m.useMemo(()=>Object.values(v||{}).some(N=>N?.deadline||N?.idleDeadline),[v]);m.useEffect(()=>{if(!j)return;const N=setInterval(()=>{h(Date.now())},1e3);return()=>clearInterval(N)},[j]);const M=m.useMemo(()=>{const N=new Set(g.map(S=>String(S.id))),E=Object.keys(v||{}).filter(S=>!N.has(String(S))).map(S=>({id:S,name:S,locked:!1,batteryState:null}));return[...g,...E]},[g,v]);async function w(N){if(N){f(E=>({...E,[N]:!0}));try{await i(N)}catch(E){alert(E.message)}finally{f(E=>({...E,[N]:!1}))}}}const q=N=>y.find(E=>E.socketId===N)||{socketId:N,nickname:null,role:null};return r.jsxs("div",{className:"space-y-0.5 text-sm",children:[a&&r.jsx("p",{className:"text-sm text-slate-400",children:a}),M.length===0?r.jsx("p",{className:"text-sm text-slate-500",children:"No rovers registered."}):r.jsx("ul",{className:"space-y-0.5 text-sm",children:M.map(N=>{const E=String(N.id),S=v?.[E]||null,T=S?.queue||[],z=S?.idleDeadline||S?.deadline||null,L=z&&z>d?Math.ceil((z-d)/1e3):z?0:null,$=S?.current||null,O=$?T.findIndex(k=>k===$):-1,V=T.length>1?O>=0?T[(O+1)%T.length]:T[0]:null,X=!!(b&&$&&$===b),Z=!!(b&&V&&V===b),F=L!=null&&(X||Z),ae=!!N.locked,oe=N.lockReason?`locked: ${N.lockReason}`:"locked",me=ae?oe:o[E]?"...":"request",G=p&&!ae&&!o[E];return r.jsxs("li",{className:Pu("surface flex flex-wrap items-start justify-between gap-0.5",G&&"cursor-pointer",ae&&"bg-red-900/40"),onClick:()=>{G&&w(N.id)},children:[r.jsxs("div",{className:"flex min-w-0 flex-1 flex-col gap-0.5",children:[r.jsxs("div",{className:"flex items-center justify-between gap-0.5",children:[r.jsxs("div",{className:"flex items-center gap-0.5",children:[r.jsx("p",{className:"text-slate-200",children:N.name}),F?r.jsx("span",{className:"rounded bg-slate-800 px-1 text-[0.7rem] text-slate-200",children:X?`${L}s left`:`Your turn in ${L}s`}):null]}),r.jsx("span",{className:Pu("text-[0.75rem] font-semibold",bN(N)),children:yN(N)})]}),T.length===0?r.jsx("p",{className:"text-[0.7rem] text-slate-500",children:"No queue."}):r.jsx("div",{className:"flex flex-wrap items-center gap-0.5",children:T.map((k,Q)=>{const P=q(k),re=k===$,ce=!!(V&&k===V&&!re),C=re?"bg-sky-600 text-white ring-2 ring-amber-300":ce?"bg-emerald-700/60 text-emerald-100 ring-1 ring-emerald-300/70":"bg-slate-800 text-slate-200";return r.jsxs("span",{className:`flex items-center gap-0.5 rounded px-1 text-[0.7rem] ${C}`,children:[r.jsx("span",{className:`${SN(P.role)} font-semibold`,children:AN(P,b)}),re&&r.jsx("span",{className:"text-[0.65rem] text-slate-200",children:"now"}),ce&&r.jsx("span",{className:"text-[0.65rem] text-emerald-100",children:"next"})]},`${E}-${k}-${Q}`)})})]}),p?r.jsx("button",{type:"button",onClick:k=>{k.stopPropagation(),w(N.id)},disabled:o[E]||ae,className:Pu("button-dark disabled:opacity-40",ae&&"bg-red-600/70 text-white hover:bg-red-600"),children:me}):null]},N.id)})})]})}function jN(a){switch(a){case"admin":case"lockdown":case"lockdown-admin":return"text-amber-300";case"spectator":return"text-slate-400";default:return"text-sky-300"}}function NN(a,l){if(!a)return"";const i=a.nickname||a.socketId?.slice(0,6)||"unknown";return a.socketId&&a.socketId===l?`${i} (you)`:i}function eo({hideNicknameForm:a=!1,hideHeader:l=!1,className:i="",fillHeight:o=!1,compact:f=!1}){const{session:d,setNickname:h}=Ve(),{value:p}=st("profile",{nickname:""}),g=m.useRef(null),v=En(),y=d?.role!=="spectator",b=d?.users??[],j=d?.socketId||null;m.useEffect(()=>{if(!y||!d?.socketId)return;const q=p.nickname||"";if(!q||d.socketId===g.current)return;const N=d.socketId;h(q).then(()=>{g.current=N}).catch(()=>{})},[y,d?.socketId,h,p.nickname]),m.useEffect(()=>{if(!v)return;const q=()=>{if(!y)return;const N=(p.nickname||"").trim();N&&h(N).then(()=>{g.current=d?.socketId||null}).catch(()=>{})};return v.on("connect",q),()=>v.off("connect",q)},[y,h,v,p.nickname,d?.socketId]);const M=m.useMemo(()=>[...b].sort((q,N)=>q.socketId===j?-1:N.socketId===j?1:(q.nickname||"").localeCompare(N.nickname||"")),[j,b]),w=o?"flex-1 min-h-0 overflow-y-auto":f?"h-28 overflow-y-auto":"h-48 overflow-y-auto";return r.jsxs("section",{className:`panel-section space-y-0.5 text-base ${o?"flex h-full min-h-0 flex-col overflow-hidden":""} ${i}`,children:[!a&&r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("div",{className:"grid gap-0.5 md:grid-cols-[minmax(0,1.4fr)_minmax(0,1fr)]",children:[r.jsx("div",{className:"min-w-0",children:r.jsx("div",{className:"surface flex w-full items-center px-0 py-0",children:r.jsx(Pf,{compact:f})})}),r.jsx(pg,{})]}),!y&&r.jsx("p",{className:"text-xs text-slate-500",children:"Spectators cannot set nicknames."})]}),r.jsxs("div",{className:`space-y-0.5 ${o?"flex flex-1 min-h-0 flex-col":""}`,children:[!l&&r.jsxs("div",{className:`flex items-center justify-between text-sm text-slate-400 ${f?"text-xs":""}`,children:[r.jsx("span",{children:"Users"}),r.jsx("span",{className:"text-xs text-slate-500",children:M.length})]}),r.jsx("div",{className:`surface flex flex-wrap content-start items-start gap-0.5 px-0 pb-0 ${w} ${f?"text-[0.8rem]":""}`,children:M.length===0?r.jsx("p",{className:"text-sm text-slate-500",children:"Waiting for users…"}):M.map(q=>r.jsx("span",{className:`rounded bg-slate-800/80 px-1 py-0.25 text-[0.7rem] ${jN(q.role)}`,children:NN(q,j)},q.socketId))})]})]})}function wN(){const{state:{roverId:a}}=Dt(),i=es(a)?.sensors||{};return r.jsx("section",{className:"panel-section",children:r.jsx("div",{className:"aspect-square w-full",children:r.jsx(vf,{sensors:i})})})}function EN(){const{state:{roverId:a,keymap:l,camera:i,horn:o},pipeline:f,actions:{setServoAngle:d,setNightVision:h,startHorn:p,stopHorn:g}}=Dt(),v=Zx(a),y=v.docked&&!v.driving,b=i?.config,j=!!(a&&i?.enabled&&b),M=!!(a&&f?.nightVision),w=f?.nightVisionState,q=!!(a&&f?.horn),N=o?.overheated,E=typeof b?.minAngle=="number"?b.minAngle:-30,S=typeof b?.maxAngle=="number"?b.maxAngle:30,T=typeof i?.angle=="number"?i.angle:typeof b?.homeAngle=="number"?b.homeAngle:(E+S)/2,z=An(l?.nightVisionToggle?.[0]),L=An(l?.hornHonk?.[0]),$=An(l?.cameraUp?.[0]),O=An(l?.cameraDown?.[0]);return r.jsxs("section",{className:"panel-section grid h-full min-h-0 grid-rows-[minmax(0,1fr)_auto] gap-0.5",children:[r.jsx(Jx,{layout:"desktop",expand:!0,driveDockState:v}),y?null:r.jsxs("div",{className:"surface space-y-0.5 p-0 text-sm text-slate-200",children:[M&&r.jsx(Ix,{nightVisionOn:w?.nightVisionOn,disabled:!a,onToggle:h,keyLabel:z}),q&&r.jsx(Wx,{disabled:!a||N,onStart:p,onStop:g,keyLabel:L,active:o?.active,heat:o?.heat}),j&&r.jsx(Px,{value:T,min:E,max:S,onChange:d,keyDownLabel:O,keyUpLabel:$,className:"space-y-0.5 px-1 py-1",labelRowClass:"text-xs text-slate-300",labelClass:"",valueClass:"font-mono text-slate-100",sliderClass:"w-full",accentClass:"accent-emerald-400",endpointClass:"text-[0.7rem] text-slate-400"})]})]})}function CN({layout:a,onOpenHelpOverlay:l}){return r.jsx("section",{className:"panel text-base",children:r.jsxs(Jf,{defaultTab:"telemetry",children:[r.jsxs(If,{children:[r.jsx(mn,{id:"telemetry",children:"Controls"}),r.jsx(mn,{id:"help",children:"Help"}),r.jsx(mn,{id:"settings",children:"Settings"})]}),r.jsxs(Wf,{children:[r.jsx(hn,{id:"telemetry",children:r.jsxs("div",{className:"space-y-0.5",children:[r.jsxs("div",{className:"grid items-stretch gap-0.5 grid-cols-[minmax(0,1.35fr)_minmax(0,0.95fr)]",children:[r.jsx(wN,{}),r.jsx(EN,{})]}),r.jsxs("div",{className:"grid gap-0.5 grid-cols-[minmax(0,1fr)_minmax(0,0.9fr)_minmax(0,0.75fr)]",children:[r.jsx(uo,{}),r.jsx(_f,{panelId:"replay-sources-desktop",fillHeight:!0}),r.jsx(vN,{})]}),r.jsxs("div",{className:"grid items-stretch gap-0.5 grid-cols-[minmax(0,1.3fr)_minmax(0,0.22fr)] h-[14rem]",children:[r.jsx(co,{fillHeight:!0}),r.jsxs("div",{className:"grid min-h-0 gap-0.5 grid-rows-[minmax(0,1fr)_auto]",children:[r.jsx(eo,{compact:!0,hideNicknameForm:!0,fillHeight:!0}),r.jsx(gN,{compact:!0})]})]}),r.jsx(ig,{}),r.jsx(Vf,{defaultOrientation:"horizontal",panelId:"rightpane-telemetry"})]})}),r.jsx(hn,{id:"help",children:r.jsx(hg,{layout:a,onOpenOverlay:l})}),r.jsx(hn,{id:"settings",children:r.jsx(fg,{})})]})]})})}const qN=new Set(["admin","lockdown","lockdown-admin"]),MN=new Set(["lockdown","lockdown-admin"]),kN=new Set(["admin","lockdown"]);function RN(a="admin"){return a==="lockdown"?{title:"Lockdown mode active",description:"Only the server owners can access the interface at this time."}:{title:"Admin mode active"}}function TN(){const{session:a}=Ve(),l=a?.mode,i=a?.role,o=a?.adminReason?.text||"";a?.adminReason?.updatedAt;const f=a?.timezone||"UTC",d=a?.socials?.find(j=>String(j?.id||j?.label||"").toLowerCase()==="discord")?.url||a?.discord?.invite||null,h=kN.has(l),p=l==="lockdown"?MN.has(i):qN.has(i),[g,v]=m.useState(()=>new Date),y=m.useMemo(()=>{try{return new Intl.DateTimeFormat("en-US",{timeZone:f,hour:"numeric",minute:"2-digit",second:"2-digit"}).format(g)}catch{return g.toLocaleTimeString()}},[g,f]);if(m.useEffect(()=>{const j=setInterval(()=>v(new Date),1e3);return()=>clearInterval(j)},[]),!h||p)return null;const b=RN(l);return r.jsx("div",{className:"pointer-events-auto fixed inset-0 z-50 flex items-center justify-center bg-black/85 px-0.5 py-0.5",children:r.jsxs("div",{className:"surface w-full max-w-md space-y-0.5 text-slate-100 shadow-2xl",children:[r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("p",{className:"text-lg font-semibold",children:b.title}),r.jsx("p",{className:"text-sm text-slate-300",children:b.description})]}),r.jsxs("div",{className:"surface-muted space-y-0.5",children:[r.jsx("p",{className:"text-[0.7rem] tracking-wide text-slate-400",children:"Reason for locking:"}),r.jsx("p",{className:"text-lg font-semibold text-slate-100",children:o||"No reason set."}),r.jsxs("p",{className:"text-center text-sm text-slate-300",children:["Server time: ",y]})]}),r.jsx("div",{className:"surface-muted",children:r.jsx(rg,{})}),r.jsx("div",{className:"w-full justify-center items-center",children:r.jsx(Xf,{id:"discord",label:"Join our Discord server for updates!",url:d})}),"You can still use the chat while the server is locked:",r.jsxs("div",{className:"max-h-80 overflow-y-auto",children:[r.jsx(co,{}),r.jsx(Pf,{})]})]})})}const DN="/assets/turn_alert-DVO8EZJa.mp3";function _N(a,l=1){const i=m.useRef(null);return m.useEffect(()=>{i.current=new Audio(a),i.current.volume=l,i.current.load()},[a,l]),()=>{i.current&&(i.current.volume=l,i.current.currentTime=0,i.current.play().catch(()=>{}))}}function ON(){const{session:a,pushAlert:l}=Ve(),{value:i}=st("audio",jt),o=Number.isFinite(i?.masterVolume)?i.masterVolume:jt.masterVolume,f=Number.isFinite(i?.alertVolume)?i.alertVolume:jt.alertVolume,d=Math.max(0,Math.min(1,o*f)),h=_N(DN,d),p=m.useRef(new Set),g=m.useMemo(()=>a?.turnQueues||{},[a?.turnQueues]),v=a?.socketId||null;return m.useEffect(()=>{if(!v)return;const y=[];Object.entries(g).forEach(([b,j])=>{!j||!j.current||j.current!==v||p.current.has(b)||(y.push(b),p.current.add(b))}),Object.keys(g).forEach(b=>{(!g[b]||g[b].current!==v)&&p.current.delete(b)}),y.length!==0&&(y.forEach(b=>{const j=a?.roster?.find(M=>String(M.id)===String(b))?.name||b;l({title:"Your turn!",message:`You now control ${j}.`,color:"#ff5722"})}),h())},[g,h,l,a?.roster,v]),null}function BN({visible:a,mode:l,onEnterFullscreen:i,onDismiss:o}){if(!a)return null;const f=l==="pwa-hint";return r.jsx("div",{className:"fixed inset-0 z-40 flex items-end justify-center p-2 pointer-events-none sm:items-center",children:r.jsx("div",{className:"pointer-events-auto w-full max-w-sm rounded-lg border border-cyan-500/40 bg-zinc-950/95 shadow-xl",children:r.jsxs("div",{className:"space-y-0.5 p-4 text-sm text-slate-100",children:[r.jsx("h2",{className:"text-base font-semibold text-white",children:"Better in fullscreen"}),f?r.jsxs("p",{className:"text-slate-300",children:["For fullscreen on iOS, open Safari's share menu and pick ",r.jsx("strong",{children:"Add to Home Screen"}),". Launching from the home screen removes the browser chrome."]}):r.jsx("p",{className:"text-slate-300",children:"Enable fullscreen to free up more space for the video feed and controls. You can exit fullscreen at any time via the system back or home gesture."}),r.jsxs("div",{className:"flex justify-end gap-0.5 pt-1 text-sm",children:[r.jsx("button",{type:"button",className:"rounded border border-slate-600 px-3 py-1 text-slate-200",onClick:o,children:f?"Got it":"Not now"}),!f&&r.jsx("button",{type:"button",className:"rounded bg-cyan-500 px-3 py-1 font-semibold text-black hover:bg-cyan-400",onClick:i,children:"Enter fullscreen"})]})]})})})}const xg="fullscreenPromptDismissed",zN=new Set(["mobile-portrait","mobile-landscape"]),gg=()=>{if(typeof window>"u")return null;try{return window.sessionStorage}catch{return null}},LN=()=>{const a=gg();if(!a)return!1;try{return a.getItem(xg)==="1"}catch{return!1}},Qp=()=>{const a=gg();if(a)try{a.setItem(xg,"1")}catch{}},UN=()=>{if(typeof navigator>"u")return!1;const a=navigator.userAgent||navigator.platform||"";return/iphone|ipad|ipod/i.test(a)},HN=()=>{if(typeof document>"u")return!1;const a=document;return!!(a.fullscreenEnabled||a.webkitFullscreenEnabled||a.mozFullScreenEnabled||a.msFullscreenEnabled)};function VN(a){const l=zN.has(a),[i,o]=m.useState(!1),[f,d]=m.useState("native"),h=m.useMemo(()=>UN(),[]),p=m.useCallback(()=>{if(!l){o(!1);return}if(LN()){o(!1);return}if(h){d("pwa-hint"),o(!0);return}if(!HN()){o(!1);return}if(typeof document<"u"&&document.fullscreenElement){o(!1);return}d("native"),o(!0)},[h,l]);m.useEffect(()=>{p()},[p]),m.useEffect(()=>{if(typeof document>"u")return;const y=()=>{if(document.fullscreenElement){o(!1);return}p()};return document.addEventListener("fullscreenchange",y),document.addEventListener("webkitfullscreenchange",y),()=>{document.removeEventListener("fullscreenchange",y),document.removeEventListener("webkitfullscreenchange",y)}},[p]);const g=m.useCallback(()=>{Qp(),o(!1)},[]),v=m.useCallback(async()=>{if(!l||h||typeof document>"u")return!1;const y=document.documentElement;if(!y)return!1;const b=y.requestFullscreen||y.webkitRequestFullscreen||y.mozRequestFullScreen||y.msRequestFullscreen;if(!b)return!1;try{const j=b.call(y);return j&&typeof j.then=="function"&&await j,Qp(),o(!1),!0}catch(j){return console.warn("Failed to enter fullscreen",j),!1}},[h,l]);return m.useEffect(()=>{l||o(!1)},[l]),{visible:i,mode:f,enterFullscreen:v,dismiss:g}}function YN({visible:a,layout:l,onClose:i,showOnLoad:o,onToggleShowOnLoad:f}){if(!a)return null;const{state:d}=Dt(),h=p=>{const g=!p.target.checked;f?.(g)};return r.jsx("div",{className:"fixed inset-0 z-30 flex items-center justify-center bg-black/80 px-0.5 py-0.5",children:r.jsxs("div",{className:"pointer-events-auto surface w-full max-w-4xl max-h-[90vh] overflow-hidden shadow-2xl",children:[r.jsxs("div",{className:"flex items-center justify-between border-b border-slate-700 px-0.5 py-0.25 text-sm text-slate-200",children:[r.jsx("span",{className:"font-semibold",children:"Help & controls"}),r.jsxs("div",{className:"flex items-center gap-0.5 text-[0.8rem] text-slate-300",children:[r.jsxs("label",{className:"flex items-center gap-0.5",children:[r.jsx("input",{type:"checkbox",checked:!o,onChange:h,className:"accent-cyan-500"}),r.jsx("span",{children:"Don't show again"})]}),r.jsx("button",{type:"button",onClick:i,className:"button-dark px-2 py-0.25 text-[0.8rem]",children:"Close"})]})]}),r.jsx("div",{className:"max-h-[85vh] overflow-y-auto p-0.5",children:r.jsx(mg,{layout:l,keymap:d?.keymap||{}})})]})})}const $N=`aroma bagel batter diff --git a/server/public/assets/index-BBp-2M2r.css b/server/public/assets/index-D2M34pit.css similarity index 60% rename from server/public/assets/index-BBp-2M2r.css rename to server/public/assets/index-D2M34pit.css index cdae6e37..f79c596a 100644 --- a/server/public/assets/index-BBp-2M2r.css +++ b/server/public/assets/index-D2M34pit.css @@ -1 +1 @@ -*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.panel{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity));padding:0;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.panel-section{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(23 23 23 / var(--tw-bg-opacity));padding:0;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.panel-muted{border-radius:.375rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.surface{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(38 38 38 / var(--tw-bg-opacity));padding:.125rem;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.surface-muted{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(64 64 64 / var(--tw-bg-opacity));padding:.125rem;--tw-text-opacity: 1;color:rgb(245 245 245 / var(--tw-text-opacity))}.field-input{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(38 38 38 / var(--tw-bg-opacity));padding:.125rem;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.field-input:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-opacity: 1;--tw-ring-color: rgb(14 165 233 / var(--tw-ring-opacity))}.button-dark{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(2 132 199 / var(--tw-bg-opacity));padding:.125rem;font-size:.875rem;line-height:1.25rem;font-weight:500;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.button-dark:hover{--tw-bg-opacity: 1;background-color:rgb(14 165 233 / var(--tw-bg-opacity))}.button-danger{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(225 29 72 / var(--tw-bg-opacity));padding:.125rem;font-size:.875rem;line-height:1.25rem;font-weight:500;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.button-danger:hover{--tw-bg-opacity: 1;background-color:rgb(244 63 94 / var(--tw-bg-opacity))}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.\!visible{visibility:visible!important}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.inset-x-0{left:0;right:0}.bottom-0{bottom:0}.bottom-0\.5{bottom:.125rem}.bottom-1{bottom:.25rem}.left-0{left:0}.left-0\.5{left:.125rem}.left-1{left:.25rem}.left-1\/2{left:50%}.right-0{right:0}.right-0\.5{right:.125rem}.right-1{right:.25rem}.top-0{top:0}.top-0\.5{top:.125rem}.top-1{top:.25rem}.top-1\/2{top:50%}.top-10{top:2.5rem}.top-6{top:1.5rem}.z-10{z-index:10}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.order-1{order:1}.order-2{order:2}.col-span-full{grid-column:1 / -1}.m-0{margin:0}.mx-auto{margin-left:auto;margin-right:auto}.-mt-0\.5{margin-top:-.125rem}.mr-0{margin-right:0}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-auto{margin-top:auto}.\!block{display:block!important}.block{display:block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.aspect-\[4\/3\]{aspect-ratio:4/3}.aspect-square{aspect-ratio:1 / 1}.h-12{height:3rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-28{height:7rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-40{height:10rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-64{height:16rem}.h-\[14rem\]{height:14rem}.h-\[2px\]{height:2px}.h-\[3\.5rem\]{height:3.5rem}.h-\[70\%\]{height:70%}.h-\[7rem\]{height:7rem}.h-\[min\(100svh\,32rem\)\]{height:min(100svh,32rem)}.h-\[min\(60svh\,24rem\)\]{height:min(60svh,24rem)}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-32{max-height:8rem}.max-h-40{max-height:10rem}.max-h-80{max-height:20rem}.max-h-\[85vh\]{max-height:85vh}.max-h-\[90vh\]{max-height:90vh}.max-h-screen{max-height:100vh}.min-h-0{min-height:0px}.min-h-\[14rem\]{min-height:14rem}.min-h-\[16rem\]{min-height:16rem}.min-h-\[3\.5rem\]{min-height:3.5rem}.min-h-\[5rem\]{min-height:5rem}.min-h-screen{min-height:100vh}.w-1\/2{width:50%}.w-12{width:3rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-28{width:7rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-7{width:1.75rem}.w-\[12rem\]{width:12rem}.w-\[20rem\]{width:20rem}.w-\[2px\]{width:2px}.w-\[9rem\]{width:9rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-screen{width:100vw}.min-w-0{min-width:0px}.min-w-\[0\]{min-width:0}.min-w-\[10rem\]{min-width:10rem}.min-w-\[12rem\]{min-width:12rem}.max-w-4xl{max-width:56rem}.max-w-\[70vw\]{max-width:70vw}.max-w-\[80vw\]{max-width:80vw}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-\[1\.1\]{flex:1.1}.flex-\[1\.22\]{flex:1.22}.flex-\[1_1_12rem\]{flex:1 1 12rem}.shrink-0{flex-shrink:0}.basis-full{flex-basis:100%}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize{resize:both}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[minmax\(0\,0\.7fr\)_minmax\(0\,2\.1fr\)_minmax\(0\,0\.7fr\)\]{grid-template-columns:minmax(0,.7fr) minmax(0,2.1fr) minmax(0,.7fr)}.grid-cols-\[minmax\(0\,1\.2fr\)_repeat\(4\,minmax\(0\,1fr\)\)\]{grid-template-columns:minmax(0,1.2fr) repeat(4,minmax(0,1fr))}.grid-cols-\[minmax\(0\,1\.35fr\)_minmax\(0\,0\.95fr\)\]{grid-template-columns:minmax(0,1.35fr) minmax(0,.95fr)}.grid-cols-\[minmax\(0\,1\.3fr\)_minmax\(0\,0\.22fr\)\]{grid-template-columns:minmax(0,1.3fr) minmax(0,.22fr)}.grid-cols-\[minmax\(0\,1fr\)_auto\]{grid-template-columns:minmax(0,1fr) auto}.grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,0\.7fr\)_minmax\(0\,1\.9fr\)_minmax\(0\,0\.7fr\)\]{grid-template-columns:minmax(0,1fr) minmax(0,.7fr) minmax(0,1.9fr) minmax(0,.7fr)}.grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,0\.9fr\)_minmax\(0\,0\.75fr\)\]{grid-template-columns:minmax(0,1fr) minmax(0,.9fr) minmax(0,.75fr)}.grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,1\.4fr\)\]{grid-template-columns:minmax(0,1fr) minmax(0,1.4fr)}.grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}.grid-rows-\[minmax\(0\,1fr\)_auto\]{grid-template-rows:minmax(0,1fr) auto}.grid-rows-\[minmax\(0\,1fr\)_minmax\(0\,1fr\)_minmax\(0\,1fr\)\]{grid-template-rows:minmax(0,1fr) minmax(0,1fr) minmax(0,1fr)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.content-center{align-content:center}.content-start{align-content:flex-start}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-4{gap:1rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.self-start{align-self:flex-start}.self-center{align-self:center}.self-stretch{align-self:stretch}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-sm{border-radius:.125rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-amber-200{--tw-border-opacity: 1;border-color:rgb(253 230 138 / var(--tw-border-opacity))}.border-amber-200\/70{border-color:#fde68ab3}.border-amber-300\/70{border-color:#fcd34db3}.border-amber-300\/80{border-color:#fcd34dcc}.border-amber-400\/30{border-color:#fbbf244d}.border-amber-700\/60{border-color:#b4530999}.border-cyan-300\/70{border-color:#67e8f9b3}.border-cyan-500\/40{border-color:#06b6d466}.border-emerald-200{--tw-border-opacity: 1;border-color:rgb(167 243 208 / var(--tw-border-opacity))}.border-emerald-200\/70{border-color:#a7f3d0b3}.border-emerald-300\/70{border-color:#6ee7b7b3}.border-emerald-500\/40{border-color:#10b98166}.border-emerald-700{--tw-border-opacity: 1;border-color:rgb(4 120 87 / var(--tw-border-opacity))}.border-emerald-700\/60{border-color:#04785799}.border-fuchsia-300\/70{border-color:#f0abfcb3}.border-indigo-200\/70{border-color:#c7d2feb3}.border-indigo-300\/70{border-color:#a5b4fcb3}.border-indigo-400\/30{border-color:#818cf84d}.border-indigo-700{--tw-border-opacity: 1;border-color:rgb(67 56 202 / var(--tw-border-opacity))}.border-indigo-700\/60{border-color:#4338ca99}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity))}.border-rose-800{--tw-border-opacity: 1;border-color:rgb(159 18 57 / var(--tw-border-opacity))}.border-slate-200\/30{border-color:#e2e8f04d}.border-slate-600{--tw-border-opacity: 1;border-color:rgb(71 85 105 / var(--tw-border-opacity))}.border-slate-600\/40{border-color:#47556966}.border-slate-700{--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}.border-slate-700\/60{border-color:#33415599}.border-slate-700\/80{border-color:#334155cc}.border-slate-800{--tw-border-opacity: 1;border-color:rgb(30 41 59 / var(--tw-border-opacity))}.border-slate-800\/60{border-color:#1e293b99}.border-white\/40{border-color:#fff6}.border-white\/60{border-color:#fff9}.bg-amber-400\/80{background-color:#fbbf24cc}.bg-amber-500{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity))}.bg-amber-500\/30{background-color:#f59e0b4d}.bg-amber-600{--tw-bg-opacity: 1;background-color:rgb(217 119 6 / var(--tw-bg-opacity))}.bg-amber-600\/70{background-color:#d97706b3}.bg-amber-900{--tw-bg-opacity: 1;background-color:rgb(120 53 15 / var(--tw-bg-opacity))}.bg-amber-900\/60{background-color:#78350f99}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity))}.bg-black\/20{background-color:#0003}.bg-black\/30{background-color:#0000004d}.bg-black\/40{background-color:#0006}.bg-black\/50{background-color:#00000080}.bg-black\/55{background-color:#0000008c}.bg-black\/60{background-color:#0009}.bg-black\/70{background-color:#000000b3}.bg-black\/75{background-color:#000000bf}.bg-black\/80{background-color:#000c}.bg-black\/85{background-color:#000000d9}.bg-cyan-300\/80{background-color:#67e8f9cc}.bg-cyan-400\/10{background-color:#22d3ee1a}.bg-cyan-500{--tw-bg-opacity: 1;background-color:rgb(6 182 212 / var(--tw-bg-opacity))}.bg-cyan-500\/80{background-color:#06b6d4cc}.bg-cyan-900{--tw-bg-opacity: 1;background-color:rgb(22 78 99 / var(--tw-bg-opacity))}.bg-emerald-400{--tw-bg-opacity: 1;background-color:rgb(52 211 153 / var(--tw-bg-opacity))}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity))}.bg-emerald-500\/45{background-color:#10b98173}.bg-emerald-500\/80{background-color:#10b981cc}.bg-emerald-600{--tw-bg-opacity: 1;background-color:rgb(5 150 105 / var(--tw-bg-opacity))}.bg-emerald-600\/70{background-color:#059669b3}.bg-emerald-700\/60{background-color:#04785799}.bg-emerald-800{--tw-bg-opacity: 1;background-color:rgb(6 95 70 / var(--tw-bg-opacity))}.bg-emerald-900{--tw-bg-opacity: 1;background-color:rgb(6 78 59 / var(--tw-bg-opacity))}.bg-emerald-900\/15{background-color:#064e3b26}.bg-emerald-900\/60{background-color:#064e3b99}.bg-emerald-900\/80{background-color:#064e3bcc}.bg-fuchsia-200{--tw-bg-opacity: 1;background-color:rgb(245 208 254 / var(--tw-bg-opacity))}.bg-fuchsia-600{--tw-bg-opacity: 1;background-color:rgb(192 38 211 / var(--tw-bg-opacity))}.bg-fuchsia-700{--tw-bg-opacity: 1;background-color:rgb(162 28 175 / var(--tw-bg-opacity))}.bg-fuchsia-800{--tw-bg-opacity: 1;background-color:rgb(134 25 143 / var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity: 1;background-color:rgb(79 70 229 / var(--tw-bg-opacity))}.bg-indigo-600\/70{background-color:#4f46e5b3}.bg-indigo-900{--tw-bg-opacity: 1;background-color:rgb(49 46 129 / var(--tw-bg-opacity))}.bg-indigo-900\/20{background-color:#312e8133}.bg-indigo-900\/60{background-color:#312e8199}.bg-indigo-950\/90{background-color:#1e1b4be6}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}.bg-red-500\/45{background-color:#ef444473}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.bg-red-600\/70{background-color:#dc2626b3}.bg-red-700\/60{background-color:#b91c1c99}.bg-red-900\/35{background-color:#7f1d1d59}.bg-red-900\/40{background-color:#7f1d1d66}.bg-red-900\/45{background-color:#7f1d1d73}.bg-red-900\/50{background-color:#7f1d1d80}.bg-rose-900\/80{background-color:#881337cc}.bg-sky-600{--tw-bg-opacity: 1;background-color:rgb(2 132 199 / var(--tw-bg-opacity))}.bg-slate-500{--tw-bg-opacity: 1;background-color:rgb(100 116 139 / var(--tw-bg-opacity))}.bg-slate-600{--tw-bg-opacity: 1;background-color:rgb(71 85 105 / var(--tw-bg-opacity))}.bg-slate-700{--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}.bg-slate-700\/60{background-color:#33415599}.bg-slate-700\/70{background-color:#334155b3}.bg-slate-700\/80{background-color:#334155cc}.bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}.bg-slate-800\/80{background-color:#1e293bcc}.bg-slate-900{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}.bg-slate-900\/35{background-color:#0f172a59}.bg-slate-900\/40{background-color:#0f172a66}.bg-slate-900\/70{background-color:#0f172ab3}.bg-slate-950\/90{background-color:#020617e6}.bg-transparent{background-color:transparent}.bg-white\/10{background-color:#ffffff1a}.bg-zinc-900{--tw-bg-opacity: 1;background-color:rgb(24 24 27 / var(--tw-bg-opacity))}.bg-zinc-900\/90{background-color:#18181be6}.bg-zinc-950{--tw-bg-opacity: 1;background-color:rgb(9 9 11 / var(--tw-bg-opacity))}.bg-zinc-950\/95{background-color:#09090bf2}.bg-cover{background-size:cover}.fill-slate-200{fill:#e2e8f0}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-0{padding-left:0;padding-right:0}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-\[2px\]{padding-top:2px;padding-bottom:2px}.pb-0{padding-bottom:0}.pb-1{padding-bottom:.25rem}.pr-0{padding-right:0}.pt-0\.5{padding-top:.125rem}.pt-1{padding-top:.25rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-\[0\.45rem\]{font-size:.45rem}.text-\[0\.55em\]{font-size:.55em}.text-\[0\.55rem\]{font-size:.55rem}.text-\[0\.5rem\]{font-size:.5rem}.text-\[0\.65rem\]{font-size:.65rem}.text-\[0\.6rem\]{font-size:.6rem}.text-\[0\.75rem\]{font-size:.75rem}.text-\[0\.7rem\]{font-size:.7rem}.text-\[0\.85rem\]{font-size:.85rem}.text-\[0\.8rem\]{font-size:.8rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.leading-none{line-height:1}.leading-normal{line-height:1.5}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.text-amber-100{--tw-text-opacity: 1;color:rgb(254 243 199 / var(--tw-text-opacity))}.text-amber-200{--tw-text-opacity: 1;color:rgb(253 230 138 / var(--tw-text-opacity))}.text-amber-200\/80{color:#fde68acc}.text-amber-300{--tw-text-opacity: 1;color:rgb(252 211 77 / var(--tw-text-opacity))}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity))}.text-amber-50{--tw-text-opacity: 1;color:rgb(255 251 235 / var(--tw-text-opacity))}.text-amber-50\/90{color:#fffbebe6}.text-amber-950{--tw-text-opacity: 1;color:rgb(69 26 3 / var(--tw-text-opacity))}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity))}.text-cyan-300{--tw-text-opacity: 1;color:rgb(103 232 249 / var(--tw-text-opacity))}.text-cyan-50{--tw-text-opacity: 1;color:rgb(236 254 255 / var(--tw-text-opacity))}.text-emerald-100{--tw-text-opacity: 1;color:rgb(209 250 229 / var(--tw-text-opacity))}.text-emerald-200{--tw-text-opacity: 1;color:rgb(167 243 208 / var(--tw-text-opacity))}.text-emerald-300{--tw-text-opacity: 1;color:rgb(110 231 183 / var(--tw-text-opacity))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity))}.text-emerald-50{--tw-text-opacity: 1;color:rgb(236 253 245 / var(--tw-text-opacity))}.text-emerald-50\/90{color:#ecfdf5e6}.text-emerald-950{--tw-text-opacity: 1;color:rgb(2 44 34 / var(--tw-text-opacity))}.text-fuchsia-50{--tw-text-opacity: 1;color:rgb(253 244 255 / var(--tw-text-opacity))}.text-fuchsia-900{--tw-text-opacity: 1;color:rgb(112 26 117 / var(--tw-text-opacity))}.text-indigo-100\/80{color:#e0e7ffcc}.text-indigo-200{--tw-text-opacity: 1;color:rgb(199 210 254 / var(--tw-text-opacity))}.text-indigo-50{--tw-text-opacity: 1;color:rgb(238 242 255 / var(--tw-text-opacity))}.text-indigo-50\/90{color:#eef2ffe6}.text-lime-200{--tw-text-opacity: 1;color:rgb(217 249 157 / var(--tw-text-opacity))}.text-lime-300{--tw-text-opacity: 1;color:rgb(190 242 100 / var(--tw-text-opacity))}.text-lime-400{--tw-text-opacity: 1;color:rgb(163 230 53 / var(--tw-text-opacity))}.text-red-100\/90{color:#fee2e2e6}.text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}.text-rose-50{--tw-text-opacity: 1;color:rgb(255 241 242 / var(--tw-text-opacity))}.text-sky-300{--tw-text-opacity: 1;color:rgb(125 211 252 / var(--tw-text-opacity))}.text-slate-100{--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}.text-slate-200{--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity))}.text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.text-slate-400\/60{color:#94a3b899}.text-slate-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity))}.text-slate-900{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity))}.text-teal-400{--tw-text-opacity: 1;color:rgb(45 212 191 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.text-white\/90{color:#ffffffe6}.underline{text-decoration-line:underline}.accent-cyan-400{accent-color:#22d3ee}.accent-cyan-500{accent-color:#06b6d4}.accent-emerald-400{accent-color:#34d399}.accent-emerald-500{accent-color:#10b981}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-inner{--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-black\/30{--tw-shadow-color: rgb(0 0 0 / .3);--tw-shadow: var(--tw-shadow-colored)}.shadow-black\/40{--tw-shadow-color: rgb(0 0 0 / .4);--tw-shadow: var(--tw-shadow-colored)}.outline{outline-style:solid}.outline-2{outline-width:2px}.outline-cyan-400\/60{outline-color:#22d3ee99}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-amber-300{--tw-ring-opacity: 1;--tw-ring-color: rgb(252 211 77 / var(--tw-ring-opacity))}.ring-emerald-300\/70{--tw-ring-color: rgb(110 231 183 / .7)}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert: invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\[width\,height\]{transition-property:width,height;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}@keyframes batteryTickWarn{0%,49%{background-color:#fffffff2}50%,to{background-color:#ef4444f2}}.battery-tick-warn{animation:batteryTickWarn .4s steps(2,end) infinite}@keyframes batteryUrgentFlash{0%,49%{opacity:1}50%,to{opacity:.25}}.battery-urgent-flash{animation:batteryUrgentFlash .4s steps(2,end) infinite}.no-touch-select{-moz-user-select:none;user-select:none;-webkit-user-select:none;-ms-user-select:none;-webkit-touch-callout:none}.\[clip-path\:circle\(50\%\)\]{clip-path:circle(50%)}.\[writing-mode\:vertical-rl\]{writing-mode:vertical-rl}:root{font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}body{margin:0;min-height:100vh;--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}*{scrollbar-width:thin;scrollbar-color:#3b82f6 rgba(255,255,255,.08)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}*::-webkit-scrollbar{width:1px;height:1px}*::-webkit-scrollbar-track{background:#ffffff14}*::-webkit-scrollbar-thumb{background-color:#3b82f6;border-radius:9999px}.ha-hue-slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:.45rem;border-radius:9999px;background:linear-gradient(90deg,red,#ff0,#0f0,#0ff,#00f,#f0f,red);cursor:pointer}.ha-hue-slider:disabled{opacity:.6;cursor:not-allowed}.ha-hue-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:.75rem;height:.75rem;border-radius:9999px;border:1px solid rgba(255,255,255,.7);background:#fff}.ha-hue-slider::-webkit-slider-runnable-track{height:.45rem;border-radius:9999px;background:linear-gradient(90deg,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.ha-hue-slider::-moz-range-thumb{width:.75rem;height:.75rem;border-radius:9999px;border:1px solid rgba(255,255,255,.7);background:#fff}.ha-hue-slider::-moz-range-track{height:.45rem;border-radius:9999px;background:linear-gradient(90deg,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.placeholder\:text-slate-400::-moz-placeholder{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.placeholder\:text-slate-400::placeholder{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.hover\:-translate-y-0\.5:hover{--tw-translate-y: -.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:bg-amber-800:hover{--tw-bg-opacity: 1;background-color:rgb(146 64 14 / var(--tw-bg-opacity))}.hover\:bg-cyan-400:hover{--tw-bg-opacity: 1;background-color:rgb(34 211 238 / var(--tw-bg-opacity))}.hover\:bg-cyan-800:hover{--tw-bg-opacity: 1;background-color:rgb(21 94 117 / var(--tw-bg-opacity))}.hover\:bg-emerald-400:hover{--tw-bg-opacity: 1;background-color:rgb(52 211 153 / var(--tw-bg-opacity))}.hover\:bg-emerald-700:hover{--tw-bg-opacity: 1;background-color:rgb(4 120 87 / var(--tw-bg-opacity))}.hover\:bg-emerald-800:hover{--tw-bg-opacity: 1;background-color:rgb(6 95 70 / var(--tw-bg-opacity))}.hover\:bg-indigo-500:hover{--tw-bg-opacity: 1;background-color:rgb(99 102 241 / var(--tw-bg-opacity))}.hover\:bg-indigo-800:hover{--tw-bg-opacity: 1;background-color:rgb(55 48 163 / var(--tw-bg-opacity))}.hover\:bg-red-600:hover{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.hover\:bg-rose-800:hover{--tw-bg-opacity: 1;background-color:rgb(159 18 57 / var(--tw-bg-opacity))}.hover\:bg-sky-500:hover{--tw-bg-opacity: 1;background-color:rgb(14 165 233 / var(--tw-bg-opacity))}.hover\:bg-slate-600:hover{--tw-bg-opacity: 1;background-color:rgb(71 85 105 / var(--tw-bg-opacity))}.hover\:text-blue-500:hover{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.hover\:shadow-xl:hover{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:brightness-110:hover{--tw-brightness: brightness(1.1);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:outline:focus-visible{outline-style:solid}.focus-visible\:outline-1:focus-visible{outline-width:1px}.focus-visible\:outline-offset-1:focus-visible{outline-offset:1px}.focus-visible\:outline-slate-500:focus-visible{outline-color:#64748b}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-amber-300:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: rgb(252 211 77 / var(--tw-ring-opacity))}.focus-visible\:ring-emerald-300:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: rgb(110 231 183 / var(--tw-ring-opacity))}.focus-visible\:ring-indigo-300:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: rgb(165 180 252 / var(--tw-ring-opacity))}.active\:scale-\[0\.99\]:active{--tw-scale-x: .99;--tw-scale-y: .99;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.active\:brightness-125:active{--tw-brightness: brightness(1.25);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.disabled\:hover\:bg-inherit:hover:disabled{background-color:inherit}@media(min-width:640px){.sm\:min-h-\[18rem\]{min-height:18rem}.sm\:basis-auto{flex-basis:auto}.sm\:items-center{align-items:center}}@media(min-width:768px){.md\:h-full{height:100%}.md\:h-screen{height:100vh}.md\:min-h-0{min-height:0px}.md\:min-h-\[18rem\]{min-height:18rem}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-\[minmax\(0\,1\.1fr\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1.1fr) minmax(0,1fr)}.md\:grid-cols-\[minmax\(0\,1\.4fr\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr)}.md\:grid-cols-\[minmax\(0\,1fr\)_18rem\]{grid-template-columns:minmax(0,1fr) 18rem}.md\:overflow-hidden{overflow:hidden}.md\:overflow-y-auto{overflow-y:auto}.md\:text-lg{font-size:1.125rem;line-height:1.75rem}}@media(min-width:1024px){.lg\:grid-cols-\[minmax\(0\,1fr\)_20rem\]{grid-template-columns:minmax(0,1fr) 20rem}} +*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.panel{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity));padding:0;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.panel-section{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(23 23 23 / var(--tw-bg-opacity));padding:0;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.panel-muted{border-radius:.375rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.surface{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(38 38 38 / var(--tw-bg-opacity));padding:.125rem;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.surface-muted{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(64 64 64 / var(--tw-bg-opacity));padding:.125rem;--tw-text-opacity: 1;color:rgb(245 245 245 / var(--tw-text-opacity))}.field-input{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(38 38 38 / var(--tw-bg-opacity));padding:.125rem;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.field-input:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-opacity: 1;--tw-ring-color: rgb(14 165 233 / var(--tw-ring-opacity))}.button-dark{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(2 132 199 / var(--tw-bg-opacity));padding:.125rem;font-size:.875rem;line-height:1.25rem;font-weight:500;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.button-dark:hover{--tw-bg-opacity: 1;background-color:rgb(14 165 233 / var(--tw-bg-opacity))}.button-danger{border-radius:.375rem;--tw-bg-opacity: 1;background-color:rgb(225 29 72 / var(--tw-bg-opacity));padding:.125rem;font-size:.875rem;line-height:1.25rem;font-weight:500;--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity));transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.button-danger:hover{--tw-bg-opacity: 1;background-color:rgb(244 63 94 / var(--tw-bg-opacity))}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.\!visible{visibility:visible!important}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.inset-x-0{left:0;right:0}.bottom-0{bottom:0}.bottom-0\.5{bottom:.125rem}.bottom-1{bottom:.25rem}.left-0{left:0}.left-0\.5{left:.125rem}.left-1{left:.25rem}.left-1\/2{left:50%}.right-0{right:0}.right-0\.5{right:.125rem}.right-1{right:.25rem}.top-0{top:0}.top-0\.5{top:.125rem}.top-1{top:.25rem}.top-1\/2{top:50%}.top-10{top:2.5rem}.top-6{top:1.5rem}.z-10{z-index:10}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.order-1{order:1}.order-2{order:2}.col-span-full{grid-column:1 / -1}.m-0{margin:0}.mx-auto{margin-left:auto;margin-right:auto}.-mt-0\.5{margin-top:-.125rem}.mr-0{margin-right:0}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-auto{margin-top:auto}.\!block{display:block!important}.block{display:block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.aspect-\[4\/3\]{aspect-ratio:4/3}.aspect-square{aspect-ratio:1 / 1}.h-12{height:3rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-28{height:7rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-40{height:10rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-64{height:16rem}.h-\[14rem\]{height:14rem}.h-\[2px\]{height:2px}.h-\[3\.5rem\]{height:3.5rem}.h-\[70\%\]{height:70%}.h-\[7rem\]{height:7rem}.h-\[min\(100svh\,32rem\)\]{height:min(100svh,32rem)}.h-\[min\(60svh\,24rem\)\]{height:min(60svh,24rem)}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-32{max-height:8rem}.max-h-40{max-height:10rem}.max-h-80{max-height:20rem}.max-h-\[85vh\]{max-height:85vh}.max-h-\[90vh\]{max-height:90vh}.max-h-screen{max-height:100vh}.min-h-0{min-height:0px}.min-h-\[14rem\]{min-height:14rem}.min-h-\[16rem\]{min-height:16rem}.min-h-\[3\.5rem\]{min-height:3.5rem}.min-h-\[5rem\]{min-height:5rem}.min-h-screen{min-height:100vh}.w-1\/2{width:50%}.w-12{width:3rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-28{width:7rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-7{width:1.75rem}.w-\[12rem\]{width:12rem}.w-\[20rem\]{width:20rem}.w-\[2px\]{width:2px}.w-\[9rem\]{width:9rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-screen{width:100vw}.min-w-0{min-width:0px}.min-w-\[0\]{min-width:0}.min-w-\[10rem\]{min-width:10rem}.min-w-\[12rem\]{min-width:12rem}.max-w-4xl{max-width:56rem}.max-w-\[70vw\]{max-width:70vw}.max-w-\[80vw\]{max-width:80vw}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-\[1\.1\]{flex:1.1}.flex-\[1\.22\]{flex:1.22}.flex-\[1_1_12rem\]{flex:1 1 12rem}.shrink-0{flex-shrink:0}.basis-full{flex-basis:100%}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize{resize:both}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[minmax\(0\,0\.7fr\)_minmax\(0\,2\.1fr\)_minmax\(0\,0\.7fr\)\]{grid-template-columns:minmax(0,.7fr) minmax(0,2.1fr) minmax(0,.7fr)}.grid-cols-\[minmax\(0\,1\.2fr\)_repeat\(4\,minmax\(0\,1fr\)\)\]{grid-template-columns:minmax(0,1.2fr) repeat(4,minmax(0,1fr))}.grid-cols-\[minmax\(0\,1\.35fr\)_minmax\(0\,0\.95fr\)\]{grid-template-columns:minmax(0,1.35fr) minmax(0,.95fr)}.grid-cols-\[minmax\(0\,1\.3fr\)_minmax\(0\,0\.22fr\)\]{grid-template-columns:minmax(0,1.3fr) minmax(0,.22fr)}.grid-cols-\[minmax\(0\,1fr\)_auto\]{grid-template-columns:minmax(0,1fr) auto}.grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,0\.7fr\)_minmax\(0\,1\.9fr\)_minmax\(0\,0\.7fr\)\]{grid-template-columns:minmax(0,1fr) minmax(0,.7fr) minmax(0,1.9fr) minmax(0,.7fr)}.grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,0\.9fr\)_minmax\(0\,0\.75fr\)\]{grid-template-columns:minmax(0,1fr) minmax(0,.9fr) minmax(0,.75fr)}.grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,1\.4fr\)\]{grid-template-columns:minmax(0,1fr) minmax(0,1.4fr)}.grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}.grid-rows-\[minmax\(0\,1fr\)_auto\]{grid-template-rows:minmax(0,1fr) auto}.grid-rows-\[minmax\(0\,1fr\)_minmax\(0\,1fr\)_minmax\(0\,1fr\)\]{grid-template-rows:minmax(0,1fr) minmax(0,1fr) minmax(0,1fr)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.content-center{align-content:center}.content-start{align-content:flex-start}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-4{gap:1rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.self-start{align-self:flex-start}.self-center{align-self:center}.self-stretch{align-self:stretch}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-sm{border-radius:.125rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-amber-200{--tw-border-opacity: 1;border-color:rgb(253 230 138 / var(--tw-border-opacity))}.border-amber-200\/70{border-color:#fde68ab3}.border-amber-300\/70{border-color:#fcd34db3}.border-amber-300\/80{border-color:#fcd34dcc}.border-amber-400\/30{border-color:#fbbf244d}.border-amber-700\/60{border-color:#b4530999}.border-cyan-300\/70{border-color:#67e8f9b3}.border-cyan-500\/40{border-color:#06b6d466}.border-emerald-200{--tw-border-opacity: 1;border-color:rgb(167 243 208 / var(--tw-border-opacity))}.border-emerald-200\/70{border-color:#a7f3d0b3}.border-emerald-300\/70{border-color:#6ee7b7b3}.border-emerald-500\/40{border-color:#10b98166}.border-emerald-700{--tw-border-opacity: 1;border-color:rgb(4 120 87 / var(--tw-border-opacity))}.border-emerald-700\/60{border-color:#04785799}.border-fuchsia-300\/70{border-color:#f0abfcb3}.border-indigo-200\/70{border-color:#c7d2feb3}.border-indigo-300\/70{border-color:#a5b4fcb3}.border-indigo-400\/30{border-color:#818cf84d}.border-indigo-700{--tw-border-opacity: 1;border-color:rgb(67 56 202 / var(--tw-border-opacity))}.border-indigo-700\/60{border-color:#4338ca99}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity))}.border-rose-800{--tw-border-opacity: 1;border-color:rgb(159 18 57 / var(--tw-border-opacity))}.border-slate-200\/30{border-color:#e2e8f04d}.border-slate-600{--tw-border-opacity: 1;border-color:rgb(71 85 105 / var(--tw-border-opacity))}.border-slate-600\/40{border-color:#47556966}.border-slate-700{--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}.border-slate-700\/60{border-color:#33415599}.border-slate-700\/80{border-color:#334155cc}.border-slate-800{--tw-border-opacity: 1;border-color:rgb(30 41 59 / var(--tw-border-opacity))}.border-slate-800\/60{border-color:#1e293b99}.border-white\/40{border-color:#fff6}.border-white\/60{border-color:#fff9}.bg-amber-400\/80{background-color:#fbbf24cc}.bg-amber-500{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity))}.bg-amber-500\/30{background-color:#f59e0b4d}.bg-amber-600{--tw-bg-opacity: 1;background-color:rgb(217 119 6 / var(--tw-bg-opacity))}.bg-amber-600\/70{background-color:#d97706b3}.bg-amber-900{--tw-bg-opacity: 1;background-color:rgb(120 53 15 / var(--tw-bg-opacity))}.bg-amber-900\/60{background-color:#78350f99}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity))}.bg-black\/20{background-color:#0003}.bg-black\/30{background-color:#0000004d}.bg-black\/40{background-color:#0006}.bg-black\/50{background-color:#00000080}.bg-black\/55{background-color:#0000008c}.bg-black\/60{background-color:#0009}.bg-black\/70{background-color:#000000b3}.bg-black\/75{background-color:#000000bf}.bg-black\/80{background-color:#000c}.bg-black\/85{background-color:#000000d9}.bg-cyan-300\/80{background-color:#67e8f9cc}.bg-cyan-400\/10{background-color:#22d3ee1a}.bg-cyan-500{--tw-bg-opacity: 1;background-color:rgb(6 182 212 / var(--tw-bg-opacity))}.bg-cyan-500\/80{background-color:#06b6d4cc}.bg-cyan-900{--tw-bg-opacity: 1;background-color:rgb(22 78 99 / var(--tw-bg-opacity))}.bg-emerald-400{--tw-bg-opacity: 1;background-color:rgb(52 211 153 / var(--tw-bg-opacity))}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity))}.bg-emerald-500\/45{background-color:#10b98173}.bg-emerald-500\/80{background-color:#10b981cc}.bg-emerald-600{--tw-bg-opacity: 1;background-color:rgb(5 150 105 / var(--tw-bg-opacity))}.bg-emerald-600\/70{background-color:#059669b3}.bg-emerald-700\/60{background-color:#04785799}.bg-emerald-800{--tw-bg-opacity: 1;background-color:rgb(6 95 70 / var(--tw-bg-opacity))}.bg-emerald-900{--tw-bg-opacity: 1;background-color:rgb(6 78 59 / var(--tw-bg-opacity))}.bg-emerald-900\/15{background-color:#064e3b26}.bg-emerald-900\/60{background-color:#064e3b99}.bg-emerald-900\/80{background-color:#064e3bcc}.bg-fuchsia-200{--tw-bg-opacity: 1;background-color:rgb(245 208 254 / var(--tw-bg-opacity))}.bg-fuchsia-600{--tw-bg-opacity: 1;background-color:rgb(192 38 211 / var(--tw-bg-opacity))}.bg-fuchsia-700{--tw-bg-opacity: 1;background-color:rgb(162 28 175 / var(--tw-bg-opacity))}.bg-fuchsia-800{--tw-bg-opacity: 1;background-color:rgb(134 25 143 / var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity: 1;background-color:rgb(79 70 229 / var(--tw-bg-opacity))}.bg-indigo-600\/70{background-color:#4f46e5b3}.bg-indigo-900{--tw-bg-opacity: 1;background-color:rgb(49 46 129 / var(--tw-bg-opacity))}.bg-indigo-900\/20{background-color:#312e8133}.bg-indigo-900\/60{background-color:#312e8199}.bg-indigo-950\/90{background-color:#1e1b4be6}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}.bg-red-500\/45{background-color:#ef444473}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.bg-red-600\/70{background-color:#dc2626b3}.bg-red-700\/60{background-color:#b91c1c99}.bg-red-900\/35{background-color:#7f1d1d59}.bg-red-900\/40{background-color:#7f1d1d66}.bg-red-900\/45{background-color:#7f1d1d73}.bg-red-900\/50{background-color:#7f1d1d80}.bg-rose-900\/80{background-color:#881337cc}.bg-sky-600{--tw-bg-opacity: 1;background-color:rgb(2 132 199 / var(--tw-bg-opacity))}.bg-slate-500{--tw-bg-opacity: 1;background-color:rgb(100 116 139 / var(--tw-bg-opacity))}.bg-slate-600{--tw-bg-opacity: 1;background-color:rgb(71 85 105 / var(--tw-bg-opacity))}.bg-slate-700{--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}.bg-slate-700\/60{background-color:#33415599}.bg-slate-700\/70{background-color:#334155b3}.bg-slate-700\/80{background-color:#334155cc}.bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}.bg-slate-800\/80{background-color:#1e293bcc}.bg-slate-900{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}.bg-slate-900\/35{background-color:#0f172a59}.bg-slate-900\/40{background-color:#0f172a66}.bg-slate-900\/70{background-color:#0f172ab3}.bg-slate-950\/90{background-color:#020617e6}.bg-transparent{background-color:transparent}.bg-white\/10{background-color:#ffffff1a}.bg-zinc-900{--tw-bg-opacity: 1;background-color:rgb(24 24 27 / var(--tw-bg-opacity))}.bg-zinc-900\/90{background-color:#18181be6}.bg-zinc-950{--tw-bg-opacity: 1;background-color:rgb(9 9 11 / var(--tw-bg-opacity))}.bg-zinc-950\/95{background-color:#09090bf2}.bg-cover{background-size:cover}.fill-slate-200{fill:#e2e8f0}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-0{padding-left:0;padding-right:0}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-\[2px\]{padding-top:2px;padding-bottom:2px}.pb-0{padding-bottom:0}.pb-1{padding-bottom:.25rem}.pr-0{padding-right:0}.pt-0\.5{padding-top:.125rem}.pt-1{padding-top:.25rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-\[0\.45rem\]{font-size:.45rem}.text-\[0\.55em\]{font-size:.55em}.text-\[0\.55rem\]{font-size:.55rem}.text-\[0\.5rem\]{font-size:.5rem}.text-\[0\.65rem\]{font-size:.65rem}.text-\[0\.6rem\]{font-size:.6rem}.text-\[0\.72rem\]{font-size:.72rem}.text-\[0\.75rem\]{font-size:.75rem}.text-\[0\.7rem\]{font-size:.7rem}.text-\[0\.85rem\]{font-size:.85rem}.text-\[0\.8rem\]{font-size:.8rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.leading-none{line-height:1}.leading-normal{line-height:1.5}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.text-amber-100{--tw-text-opacity: 1;color:rgb(254 243 199 / var(--tw-text-opacity))}.text-amber-200{--tw-text-opacity: 1;color:rgb(253 230 138 / var(--tw-text-opacity))}.text-amber-200\/80{color:#fde68acc}.text-amber-300{--tw-text-opacity: 1;color:rgb(252 211 77 / var(--tw-text-opacity))}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity))}.text-amber-50{--tw-text-opacity: 1;color:rgb(255 251 235 / var(--tw-text-opacity))}.text-amber-50\/90{color:#fffbebe6}.text-amber-950{--tw-text-opacity: 1;color:rgb(69 26 3 / var(--tw-text-opacity))}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity))}.text-cyan-300{--tw-text-opacity: 1;color:rgb(103 232 249 / var(--tw-text-opacity))}.text-cyan-50{--tw-text-opacity: 1;color:rgb(236 254 255 / var(--tw-text-opacity))}.text-emerald-100{--tw-text-opacity: 1;color:rgb(209 250 229 / var(--tw-text-opacity))}.text-emerald-200{--tw-text-opacity: 1;color:rgb(167 243 208 / var(--tw-text-opacity))}.text-emerald-300{--tw-text-opacity: 1;color:rgb(110 231 183 / var(--tw-text-opacity))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity))}.text-emerald-50{--tw-text-opacity: 1;color:rgb(236 253 245 / var(--tw-text-opacity))}.text-emerald-50\/90{color:#ecfdf5e6}.text-emerald-950{--tw-text-opacity: 1;color:rgb(2 44 34 / var(--tw-text-opacity))}.text-fuchsia-50{--tw-text-opacity: 1;color:rgb(253 244 255 / var(--tw-text-opacity))}.text-fuchsia-900{--tw-text-opacity: 1;color:rgb(112 26 117 / var(--tw-text-opacity))}.text-indigo-100\/80{color:#e0e7ffcc}.text-indigo-200{--tw-text-opacity: 1;color:rgb(199 210 254 / var(--tw-text-opacity))}.text-indigo-50{--tw-text-opacity: 1;color:rgb(238 242 255 / var(--tw-text-opacity))}.text-indigo-50\/90{color:#eef2ffe6}.text-lime-200{--tw-text-opacity: 1;color:rgb(217 249 157 / var(--tw-text-opacity))}.text-lime-300{--tw-text-opacity: 1;color:rgb(190 242 100 / var(--tw-text-opacity))}.text-lime-400{--tw-text-opacity: 1;color:rgb(163 230 53 / var(--tw-text-opacity))}.text-red-100\/90{color:#fee2e2e6}.text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}.text-rose-50{--tw-text-opacity: 1;color:rgb(255 241 242 / var(--tw-text-opacity))}.text-sky-300{--tw-text-opacity: 1;color:rgb(125 211 252 / var(--tw-text-opacity))}.text-slate-100{--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}.text-slate-200{--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity))}.text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.text-slate-400\/60{color:#94a3b899}.text-slate-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity))}.text-slate-900{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity))}.text-teal-400{--tw-text-opacity: 1;color:rgb(45 212 191 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.text-white\/90{color:#ffffffe6}.underline{text-decoration-line:underline}.accent-cyan-400{accent-color:#22d3ee}.accent-cyan-500{accent-color:#06b6d4}.accent-emerald-400{accent-color:#34d399}.accent-emerald-500{accent-color:#10b981}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-inner{--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-black\/30{--tw-shadow-color: rgb(0 0 0 / .3);--tw-shadow: var(--tw-shadow-colored)}.shadow-black\/40{--tw-shadow-color: rgb(0 0 0 / .4);--tw-shadow: var(--tw-shadow-colored)}.outline{outline-style:solid}.outline-2{outline-width:2px}.outline-cyan-400\/60{outline-color:#22d3ee99}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-amber-300{--tw-ring-opacity: 1;--tw-ring-color: rgb(252 211 77 / var(--tw-ring-opacity))}.ring-emerald-300\/70{--tw-ring-color: rgb(110 231 183 / .7)}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert: invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\[width\,height\]{transition-property:width,height;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}@keyframes batteryTickWarn{0%,49%{background-color:#fffffff2}50%,to{background-color:#ef4444f2}}.battery-tick-warn{animation:batteryTickWarn .4s steps(2,end) infinite}@keyframes batteryUrgentFlash{0%,49%{opacity:1}50%,to{opacity:.25}}.battery-urgent-flash{animation:batteryUrgentFlash .4s steps(2,end) infinite}.no-touch-select{-moz-user-select:none;user-select:none;-webkit-user-select:none;-ms-user-select:none;-webkit-touch-callout:none}.\[clip-path\:circle\(50\%\)\]{clip-path:circle(50%)}.\[writing-mode\:vertical-rl\]{writing-mode:vertical-rl}:root{font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}body{margin:0;min-height:100vh;--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity));--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}*{scrollbar-width:thin;scrollbar-color:#3b82f6 rgba(255,255,255,.08)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}*::-webkit-scrollbar{width:1px;height:1px}*::-webkit-scrollbar-track{background:#ffffff14}*::-webkit-scrollbar-thumb{background-color:#3b82f6;border-radius:9999px}.ha-hue-slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:.45rem;border-radius:9999px;background:linear-gradient(90deg,red,#ff0,#0f0,#0ff,#00f,#f0f,red);cursor:pointer}.ha-hue-slider:disabled{opacity:.6;cursor:not-allowed}.ha-hue-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:.75rem;height:.75rem;border-radius:9999px;border:1px solid rgba(255,255,255,.7);background:#fff}.ha-hue-slider::-webkit-slider-runnable-track{height:.45rem;border-radius:9999px;background:linear-gradient(90deg,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.ha-hue-slider::-moz-range-thumb{width:.75rem;height:.75rem;border-radius:9999px;border:1px solid rgba(255,255,255,.7);background:#fff}.ha-hue-slider::-moz-range-track{height:.45rem;border-radius:9999px;background:linear-gradient(90deg,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.placeholder\:text-slate-400::-moz-placeholder{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.placeholder\:text-slate-400::placeholder{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.hover\:-translate-y-0\.5:hover{--tw-translate-y: -.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:bg-amber-800:hover{--tw-bg-opacity: 1;background-color:rgb(146 64 14 / var(--tw-bg-opacity))}.hover\:bg-cyan-400:hover{--tw-bg-opacity: 1;background-color:rgb(34 211 238 / var(--tw-bg-opacity))}.hover\:bg-cyan-800:hover{--tw-bg-opacity: 1;background-color:rgb(21 94 117 / var(--tw-bg-opacity))}.hover\:bg-emerald-400:hover{--tw-bg-opacity: 1;background-color:rgb(52 211 153 / var(--tw-bg-opacity))}.hover\:bg-emerald-700:hover{--tw-bg-opacity: 1;background-color:rgb(4 120 87 / var(--tw-bg-opacity))}.hover\:bg-emerald-800:hover{--tw-bg-opacity: 1;background-color:rgb(6 95 70 / var(--tw-bg-opacity))}.hover\:bg-indigo-500:hover{--tw-bg-opacity: 1;background-color:rgb(99 102 241 / var(--tw-bg-opacity))}.hover\:bg-indigo-800:hover{--tw-bg-opacity: 1;background-color:rgb(55 48 163 / var(--tw-bg-opacity))}.hover\:bg-red-600:hover{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.hover\:bg-rose-800:hover{--tw-bg-opacity: 1;background-color:rgb(159 18 57 / var(--tw-bg-opacity))}.hover\:bg-sky-500:hover{--tw-bg-opacity: 1;background-color:rgb(14 165 233 / var(--tw-bg-opacity))}.hover\:bg-slate-600:hover{--tw-bg-opacity: 1;background-color:rgb(71 85 105 / var(--tw-bg-opacity))}.hover\:text-blue-500:hover{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.hover\:shadow-xl:hover{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:brightness-110:hover{--tw-brightness: brightness(1.1);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:outline:focus-visible{outline-style:solid}.focus-visible\:outline-1:focus-visible{outline-width:1px}.focus-visible\:outline-offset-1:focus-visible{outline-offset:1px}.focus-visible\:outline-slate-500:focus-visible{outline-color:#64748b}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-amber-300:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: rgb(252 211 77 / var(--tw-ring-opacity))}.focus-visible\:ring-emerald-300:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: rgb(110 231 183 / var(--tw-ring-opacity))}.focus-visible\:ring-indigo-300:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: rgb(165 180 252 / var(--tw-ring-opacity))}.active\:scale-\[0\.99\]:active{--tw-scale-x: .99;--tw-scale-y: .99;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.active\:brightness-125:active{--tw-brightness: brightness(1.25);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.disabled\:hover\:bg-inherit:hover:disabled{background-color:inherit}@media(min-width:640px){.sm\:min-h-\[18rem\]{min-height:18rem}.sm\:basis-auto{flex-basis:auto}.sm\:items-center{align-items:center}}@media(min-width:768px){.md\:h-full{height:100%}.md\:h-screen{height:100vh}.md\:min-h-0{min-height:0px}.md\:min-h-\[18rem\]{min-height:18rem}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-\[minmax\(0\,1\.1fr\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1.1fr) minmax(0,1fr)}.md\:grid-cols-\[minmax\(0\,1\.4fr\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr)}.md\:grid-cols-\[minmax\(0\,1fr\)_18rem\]{grid-template-columns:minmax(0,1fr) 18rem}.md\:overflow-hidden{overflow:hidden}.md\:overflow-y-auto{overflow-y:auto}.md\:text-lg{font-size:1.125rem;line-height:1.75rem}}@media(min-width:1024px){.lg\:grid-cols-\[minmax\(0\,1fr\)_20rem\]{grid-template-columns:minmax(0,1fr) 20rem}} diff --git a/server/public/index.html b/server/public/index.html index 0759d4b7..902b0509 100644 --- a/server/public/index.html +++ b/server/public/index.html @@ -11,8 +11,8 @@ Multi Roomba Rover - - + +
diff --git a/server/src/services/llmCommentaryService.js b/server/src/services/llmCommentaryService.js index b00c06ef..a422d9cb 100644 --- a/server/src/services/llmCommentaryService.js +++ b/server/src/services/llmCommentaryService.js @@ -59,6 +59,8 @@ let status = { lastError: null, lastPromptReadAt: null, lastPromptChars: 0, + lastSystemPrompt: null, + lastInfoSnapshot: null, lastSnapshotSummary: null, lastGeneratedText: null, lastPostedText: null, @@ -241,6 +243,7 @@ async function readSystemPrompt() { updateStatus({ lastPromptReadAt: Date.now(), lastPromptChars: trimmed.length, + lastSystemPrompt: trimmed, }); return trimmed; } @@ -322,6 +325,7 @@ async function runTick() { }); updateStatus({ lastSnapshotSummary: snapshotSummary, + lastInfoSnapshot: snapshot, }); const systemPrompt = await readSystemPrompt(); const text = await generateCommentary(systemPrompt, snapshot); diff --git a/webui/src/components/AdminPanel.jsx b/webui/src/components/AdminPanel.jsx index e50a0303..d0ddd4b2 100644 --- a/webui/src/components/AdminPanel.jsx +++ b/webui/src/components/AdminPanel.jsx @@ -350,6 +350,20 @@ function LlmCommentaryPanel({ status }) { Posted: {status.lastPostedText} ) : null} +
+ Most recent system prompt +
+          {status.lastSystemPrompt || 'No prompt read yet.'}
+        
+
+
+ Most recent info snapshot +
+          {status.lastInfoSnapshot
+            ? JSON.stringify(status.lastInfoSnapshot, null, 2)
+            : 'No snapshot captured yet.'}
+        
+
); }