diff --git a/server/public/assets/index-kU9Gcmps.js b/server/public/assets/index-CYSD7A1h.js similarity index 93% rename from server/public/assets/index-kU9Gcmps.js rename to server/public/assets/index-CYSD7A1h.js index e00b7e41..4082a8b0 100644 --- a/server/public/assets/index-kU9Gcmps.js +++ b/server/public/assets/index-CYSD7A1h.js @@ -14,7 +14,7 @@ Please change the parent to r&&r>o){const u=Cr/100,f=1-u;if(n<=o)return 0;if(n<=r){const p=(n-o)/(r-o);return Math.round(Math.max(0,Math.min(1,p))*Cr)}if(n>=s)return 100;const h=(n-r)/(s-r);return Math.round((u+Math.max(0,Math.min(1,h))*f)*100)}return null}const XN=1600,QN=800;function Nn(...n){return n.filter(Boolean).join(" ")}function KN({visual:n,orientation:s="horizontal",variant:r="inline",compact:o=!1,showLabel:u,className:f=""}){const h=r==="background",p=s==="vertical",x=u??!h;if(!n?.available){if(h){const P=Cr,oe=Nn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!N&&"battery-tick-warn"),ie=p?{bottom:`${P}%`}:{left:`${P}%`},V=Nn("absolute inset-0 pointer-events-none",f);return l.jsxs("div",{className:V,children:[l.jsx("div",{className:"absolute inset-0 bg-slate-900/35"}),l.jsx("div",{className:oe,style:ie})]})}return p?null:l.jsx("p",{className:"text-xs text-slate-500",children:"Battery telemetry unavailable"})}const g=n.percentDisplay??0,b=Math.max(0,Math.min(100,g)),y=n.warnDisplayPercent??Cr,N=!!n.urgentActive,M=!!n.warnActive,k=N?`${QN}ms`:M?`${XN}ms`:void 0,w=h?N||M?"bg-red-500/45":"bg-emerald-500/45":N||M?"bg-red-500":"bg-emerald-500",j=N||M?"bg-red-900/35":"bg-slate-900/35",q=N||M?"bg-red-900/45":"bg-slate-900/35",E=Nn(h?"absolute inset-0 pointer-events-none":"relative pointer-events-auto",p&&!h?"flex flex-col items-center justify-center":"w-full",f);if(h){const P=p?{height:`${b}%`}:{width:`${b}%`},oe=Nn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",w,"transition-[width,height]",N&&"battery-urgent-flash"),ie=Nn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!N&&"battery-tick-warn"),V=p?{bottom:`${y}%`}:{left:`${y}%`};return l.jsxs("div",{className:E,children:[l.jsx("div",{className:Nn("absolute inset-0",j,N&&"battery-urgent-flash")}),l.jsx("div",{className:oe,style:{...P,animationDuration:k}}),l.jsx("div",{className:ie,style:V})]})}const C=Nn("relative overflow-hidden rounded-sm border border-slate-800",N||M?q:"bg-zinc-900/90",N&&"battery-urgent-flash",p?"w-full flex-1":o?"h-4":"h-5"),L=p?{height:`${b}%`}:{width:`${b}%`},G=Nn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",w,"transition-[width,height]",N&&"battery-urgent-flash"),O=Nn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!N&&"battery-tick-warn"),z=p?{bottom:`${y}%`}:{left:`${y}%`},K=`Battery ${g}%`,$=Nn("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"),X=Nn("rounded px-1.5 py-0.5",h?"bg-black/30 text-slate-100":"bg-black/50 text-slate-100");return l.jsxs("div",{className:E,children:[l.jsxs("div",{className:C,children:[l.jsx("div",{className:G,style:{...L,animationDuration:k}}),l.jsx("div",{className:O,style:z})]}),x&&!p?l.jsx("div",{className:$,children:l.jsx("span",{className:X,children:K})}):null,x&&p?l.jsx("div",{className:"mt-0.5 text-[0.65rem] font-semibold text-slate-100",children:l.jsxs("span",{className:X,children:[g,"%"]})}):null]})}const Yd=tn.memo(KN);function IN({mobileHud:n=!1,isActiveDriver:s=!1,idleSkipSeconds:r=null}){const o=n?"text-3xl":"text-5xl",u=n?"text-xs":"text-sm",f=n?"text-[0.55rem]":"text-[0.75rem]",h=n?"px-4 py-3":"px-6 py-4",p=s&&typeof r=="number";return l.jsx("div",{className:"pointer-events-none absolute inset-0 z-30 flex items-center justify-center bg-black/55",children:l.jsxs("div",{className:`flex flex-col items-center gap-0.5 rounded border border-amber-300/80 bg-black/70 ${h}`,children:[l.jsx("div",{className:`font-semibold text-amber-200 ${o}`,children:"IT IS YOUR TURN!"}),l.jsx("div",{className:`text-amber-200/80 ${u}`,children:"Start driving!"}),p?l.jsxs("div",{className:`text-red-100/90 ${f}`,children:["Idle skip in ",r,"s"]}):null]})})}function Uo(n){return Math.max(0,Math.min(1,n))}function Fg(n){return(n-90)*Math.PI/180}function vr(n,s,r,o){const u=Fg(o);return{x:n+r*Math.cos(u),y:s+r*Math.sin(u)}}function ZN(n,s,r,o,u){let f=o,h=u;h<=f&&(h+=360);const p=vr(n,s,r,f),x=vr(n,s,r,h);return["M",p.x,p.y,"A",r,r,0,0,1,x.x,x.y].join(" ")}function Sf(n,s){if(s)return"#ef4444";const r=Math.abs(n);return r>900?"#f59e0b":r>300?"#22c55e":"#64748b"}function JN(n,s){if(n==null||n<=0)return"hsl(200 60% 18%)";const o=Uo(n/(s||1));return`hsl(${(200+Math.pow(o,.45)*360)%360} 100% 60%)`}function PN(n,s){if(s)return"#ef4444";const r=Uo(n==null?0:n/4095),o=[47,55,69],u=[245,158,11],[f,h,p]=o.map((x,g)=>Math.round(x+(u[g]-x)*r));return`rgb(${f}, ${h}, ${p})`}function WN({count:n,totalSpan:s,gap:r,startAngle:o}){const f=(s-r*(n-1))/n,h=[];let p=o;for(let x=0;x0?.65:null;return l.jsxs("g",{style:{transformOrigin:`${n}px ${s}px`,animation:p?`spin ${p}s linear infinite`:"none",animationDirection:p?"reverse":"normal"},children:[l.jsx("circle",{cx:n,cy:s,r:10,fill:"#64748b",stroke:"#64748b",strokeWidth:"1"}),[0,120,240].map(g=>{const b=Fg(g),y=n+h*Math.cos(b),N=s+h*Math.sin(b);return l.jsx("line",{x1:n,y1:s,x2:y,y2:N,stroke:f,strokeWidth:"4",strokeLinecap:"round"},g)}),o?l.jsx("circle",{cx:n,cy:s,r:h+8,stroke:"#ef4444",strokeWidth:"3",fill:"none",className:"animate-pulse"}):null]})}function nw({cx:n,cy:s,current:r,overcurrent:o,variant:u,dirtLeft:f,dirtRight:h}){const p=Math.abs(r),x=Sf(r,o),g=1,b=96,y=12,N=`main-brush-pattern-a-${u}`,M=`main-brush-pattern-b-${u}`,k=p>0?.6:null,S=r>=0?1:-1;return l.jsxs("g",{children:[l.jsx("defs",{children:[N,M].map((w,j)=>l.jsxs("pattern",{id:w,patternUnits:"userSpaceOnUse",width:"6",height:"6",children:[l.jsx("rect",{width:"6",height:"6",fill:x,opacity:g}),l.jsx("path",{d:"M0 6 L6 0",stroke:"#0f172a",strokeWidth:"1"}),k?l.jsx("animateTransform",{attributeName:"patternTransform",type:"translate",from:"0 0",to:`0 ${S*(j===0?6:-6)}`,dur:`${k}s`,repeatCount:"indefinite"}):null]},w))}),l.jsx("rect",{x:n-b/2,y:s-14,width:b,height:y,rx:"3",fill:`url(#${N})`,stroke:"#64748b",strokeWidth:"1"}),l.jsx("rect",{x:n-b/2,y:s+4,width:b,height:y,rx:"3",fill:`url(#${M})`,stroke:"#64748b",strokeWidth:"1"}),l.jsx("circle",{cx:n-b/4,cy:s-8,r:3.5,fill:"#fbbf24"}),l.jsx("circle",{cx:n+b/4,cy:s+8,r:3.5,fill:"#fbbf24"}),o?l.jsx("rect",{x:n-b/2-4,y:s-16,width:b+8,height:y*2+16,rx:"6",stroke:"#ef4444",strokeWidth:"3",fill:"none",className:"animate-pulse"}):null]})}function aw({sensors:n={},variant:s="full",size:r,overlay:o=!1}){const u=r||(s==="mini"?190:260),f=u/2,h=u*.07,p=f,x=f+h,g=f*.8,b=g-4,y=g+4,N=g-14,M=g-6,k=g*.65,S=n?.bumpsAndWheelDrops||{},w=n?.wheelOvercurrents||{},j=n?.wheelLeftCurrentMa??0,q=n?.wheelRightCurrentMa??0,E=n?.sideBrushCurrentMa??0,C=n?.mainBrushCurrentMa??0,L=6,G=S.bumpLeft?L:0,O=S.bumpRight?L:0,z=WN({count:6,totalSpan:140,gap:6,startAngle:-70}),K=["L","FL","CL","CR","FR","R"],$=[n?.lightBumpLeftSignal,n?.lightBumpFrontLeftSignal,n?.lightBumpCenterLeftSignal,n?.lightBumpCenterRightSignal,n?.lightBumpFrontRightSignal,n?.lightBumpRightSignal],X=z.map((V,T)=>({label:K[T],start:V.start,end:V.end,value:$[T]})),P=[{label:"Cliff L",start:-60,end:-46,value:n?.cliffLeftSignal,active:n?.cliffLeft},{label:"Cliff FL",start:-32,end:-16,value:n?.cliffFrontLeftSignal,active:n?.cliffFrontLeft},{label:"Cliff FR",start:16,end:32,value:n?.cliffFrontRightSignal,active:n?.cliffFrontRight},{label:"Cliff R",start:46,end:60,value:n?.cliffRightSignal,active:n?.cliffRight}],oe=$.filter(V=>V!=null),ie=oe.length?Math.max(...oe,1200):1200;return l.jsxs("div",{className:`${o?"relative":"surface relative p-1"}`,style:o?{width:`${u}px`,height:`${u}px`}:{height:"100%",width:"100%",aspectRatio:"1 / 1"},children:[o?null:l.jsxs(l.Fragment,{children:[l.jsx("div",{className:"absolute left-1 top-1 text-xs text-slate-400",children:"Top-down"}),l.jsxs("div",{className:"absolute right-1 top-1 text-[0.65rem] text-slate-500",children:["0–",ie]})]}),l.jsxs("svg",{width:"100%",height:"100%",viewBox:`0 0 ${u} ${u}`,preserveAspectRatio:"xMidYMid meet",className:"mx-auto block",children:[l.jsx("circle",{cx:p,cy:x,r:g,fill:"#0f172a",stroke:"#334155",strokeWidth:"2"}),l.jsx(dx,{cx:p-k,cy:x,current:j,drop:S.wheelDropLeft,overcurrent:w.leftWheel,label:"L"}),l.jsx(dx,{cx:p+k,cy:x,current:q,drop:S.wheelDropRight,overcurrent:w.rightWheel,label:"R"}),l.jsx(tw,{cx:p+g*.65,cy:x-g*.55,current:E,overcurrent:w.sideBrush}),l.jsx(nw,{cx:p,cy:x,current:C,overcurrent:w.mainBrush,variant:s,dirtLeft:n?.dirtDetectLeft,dirtRight:n?.dirtDetect}),X.map(V=>{const T=JN(V.value,ie),H=y+4,J=H+28;return l.jsx(ew,{cx:p,cy:x,rBase:J,rTip:H,startDeg:V.start,endDeg:V.end,color:T,value:V.value,max:ie},V.label)}),P.map(V=>l.jsx(wd,{cx:p,cy:x,rInner:N,rOuter:M,startDeg:V.start,endDeg:V.end,color:PN(V.value,V.active),opacity:1,pulse:!!V.active},V.label)),l.jsx(wd,{cx:p,cy:x,rInner:b-G,rOuter:y-G,startDeg:-70,endDeg:-6,color:S.bumpLeft?"#ef4444":"#475569",opacity:1,pulse:!!S.bumpLeft}),l.jsx(wd,{cx:p,cy:x,rInner:b-O,rOuter:y-O,startDeg:6,endDeg:70,color:S.bumpRight?"#ef4444":"#475569",opacity:1,pulse:!!S.bumpRight})]})]})}const Xd=tn.memo(aw);function sw({sensors:n,label:s,roverColor:r=null,status:o,audioStatus:u,levelStatus:f,layoutFormat:h="desktop",variant:p="default",driverLabel:x=null,showTopDown:g=!1,mobileHud:b=!1,mapPosition:y="top-center",turnTimerText:N=null,turnTimerFlashActive:M=!1,labelScale:k=1}){const S=b,w=h==="mobile-portrait",j=S?"text-[0.45rem]":"text-[0.65rem]",q=S?"px-0.25 py-0.25":"px-1 py-0.5",E=S?"px-0.25 py-0.25":"px-0.5 py-0.5",C=S?"text-[0.55rem]":"text-[0.8rem]",L=S?"left-0.5 top-0.5":"left-1 top-1",G=S?"text-[0.5rem]":"text-[0.7rem]",O=S?"px-0.5 py-0.25":"px-1 py-0.5",z=S?"left-0.5 top-1/2":"left-1 top-1/2",K="bottom-0.5",$={transform:`translateX(-50%) scale(${k})`,transformOrigin:"center bottom"},X="240px",P=w?.3:S?.33:.7,ie={width:X,height:X,opacity:S?.6:.7,transform:y==="top-center"?`translateX(-50%) scale(${P})`:`scale(${P})`,transformOrigin:y==="bottom-left"?"bottom left":y==="top-center"?"top center":"top right",...y==="bottom-left"?{left:"0.25rem",bottom:"0.25rem"}:y==="top-center"?{left:"50%",top:"0.25rem"}:{right:"0.25rem",top:"0.25rem"}};if(p==="none")return null;if(p==="spectator"){const V=[["Voltage",n?.voltageMv!=null?`${(n.voltageMv/1e3).toFixed(2)} V`:"--"],["Current",n?.currentMa!=null?`${n.currentMa} mA`:"--"],["Charge",n?.batteryChargeMah!=null?`${n.batteryChargeMah}`:"--"],["OI",n?.oiMode?.label||"--"]],T=!!n?.chargingSources?.homeBase,H=n?.chargingState?.label||"",J=!!(H&&H.toLowerCase()!=="not charging"),ne=n?.oiMode?.label||"Unknown",de=ne.toLowerCase(),R=de==="full"?"bg-emerald-500/80 text-emerald-50":de==="safe"?"bg-amber-400/80 text-amber-950":de==="passive"?"bg-slate-700/80 text-slate-100":"bg-slate-700/60 text-slate-200",_=T?"bg-emerald-500/80 text-emerald-50":"bg-slate-700/70 text-slate-200",Z=J?"bg-emerald-500/80 text-emerald-50":T?"bg-amber-400/80 text-amber-950":"bg-slate-700/70 text-slate-200";return l.jsxs(l.Fragment,{children:[l.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[l.jsx("div",{className:`absolute ${L} font-medium text-slate-100 ${j}`,children:l.jsxs("div",{className:"flex flex-col gap-0.5 leading-none",children:[l.jsxs("span",{children:["Status: ",o]}),u?l.jsxs("span",{children:["Audio: ",u]}):null,f?l.jsx("span",{className:"text-cyan-300",children:f}):null]})}),l.jsx("div",{className:`absolute ${z} flex -translate-y-1/2 flex-col gap-0.5 bg-black/70 text-slate-100 ${j} ${q}`,children:l.jsxs("div",{className:"space-y-0.5 leading-tight",children:[l.jsxs("div",{className:"flex flex-col gap-0.5 text-[0.75rem] font-semibold uppercase tracking-wide",children:[l.jsx("span",{className:`rounded px-1.5 py-0.5 ${_}`,children:T?"Docked":"Undocked"}),l.jsx("span",{className:`rounded px-1.5 py-0.5 ${Z}`,children:J?"Charging":"Not charging"}),l.jsxs("span",{className:`rounded px-1.5 py-0.5 ${R}`,children:["OI: ",ne]})]}),V.map(([ee,fe])=>l.jsxs("span",{className:"flex items-center justify-between gap-0.5",children:[l.jsx("span",{className:"text-slate-400",children:ee}),l.jsx("span",{className:"font-semibold text-white",children:fe})]},ee))]})}),l.jsx("div",{className:`absolute ${K} left-1/2`,style:$,children:l.jsxs("div",{className:`flex items-center gap-0.5 bg-black/80 text-slate-100 ${E} ${C}`,children:[l.jsx("span",{className:"font-semibold text-white rounded px-1 py-[1px] border border-transparent",style:da(r,.18),children:s||"Unnamed Rover"}),x?l.jsxs("span",{className:"text-slate-300",children:["• ",x]}):null]})})]}),g?l.jsx("div",{className:"pointer-events-none absolute rounded",style:{...ie},children:l.jsx(Xd,{sensors:n,size:240,overlay:!0})}):null]})}return l.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[l.jsx("div",{className:`absolute ${L} font-medium text-slate-100 ${j}`,children:l.jsxs("div",{className:"flex flex-col gap-0.5 leading-none",children:[l.jsxs("span",{children:["Status: ",o]}),u?l.jsxs("span",{children:["Audio: ",u]}):null,f?l.jsx("span",{className:"text-cyan-300",children:f}):null]})}),N?l.jsx("div",{className:`absolute bottom-1 left-1 rounded border ${M?"border-red-300/90 bg-red-900/80 text-red-100":"border-amber-300/80 bg-black/75 text-amber-200"} ${O} ${G}`,children:N}):null,l.jsx("div",{className:`absolute ${K} left-1/2`,style:$,children:l.jsx("div",{className:`flex gap-0.5 bg-black/80 text-slate-100 ${E} ${C}`,children:l.jsxs("span",{children:["Rover:"," ",l.jsxs("span",{className:"rounded px-1 py-[1px] border border-transparent",style:da(r,.18),children:['"',s||"Unnamed Rover",'"']})]})})}),g&&p!=="spectator"?l.jsx("div",{className:"pointer-events-none absolute rounded",style:{...ie},children:l.jsx(Xd,{sensors:n,size:240,overlay:!0})}):null]})}const lw=tn.memo(sw),fx=6e3,rw=700;function iw({description:n,variant:s="default",mobileHud:r=!1,displayKey:o=""}){const[u,f]=m.useState(!1),[h,p]=m.useState(!1);return m.useEffect(()=>{if(s!=="default"||!n){f(!1),p(!1);return}f(!0),p(!1);const x=setTimeout(()=>p(!0),fx),g=setTimeout(()=>f(!1),fx+rw);return()=>{clearTimeout(x),clearTimeout(g)}},[n,o,s]),n?s==="spectator"?l.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-1 z-50 flex justify-center",children:l.jsx("div",{className:"surface max-w-[92%] border border-slate-600/80 px-1 py-0.5 text-center text-[0.62rem] leading-tight text-slate-100 shadow-lg",children:n})}):s!=="default"||!u?null:l.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-2 z-50 flex justify-center",children:l.jsx("div",{className:`surface max-w-[94%] border border-slate-500/85 px-2 py-1 text-center font-semibold text-slate-100 shadow-2xl transition-opacity duration-700 ${h?"opacity-0":"opacity-100"} ${r?"text-[1rem] leading-tight":"text-[1.5rem] leading-tight"}`,children:n})}):null}const mx=2e3,ow=3e3,cw=3e3,uw=40,dw=1e3,fw={leftWheel:"Left wheel",rightWheel:"Right wheel",mainBrush:"Main brush",sideBrush:"Side brush",limiter:"Overcurrent limit"};function mw({motors:n,fill:s=0,compact:r=!1}){if(!n?.length)return null;const o=n.map(b=>fw[b]||b),u=r?"w-[12rem] h-[3.5rem]":"w-[20rem] h-[7rem]",f=r?"px-2 py-1":"px-4 py-2",h=r?"text-lg":"text-4xl",p=r?"text-xs":"text-xl",x=Math.max(0,Math.min(1,s)),g=`${Math.round(x*100)}%`;return l.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 ${u}`,children:l.jsxs("div",{className:"relative h-full w-full",children:[l.jsx("div",{className:"absolute inset-0 overflow-hidden",children:l.jsx("div",{className:"h-full bg-red-700/60",style:{width:g}})}),l.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} ${f}`,children:[l.jsx("div",{children:"OVERCURRENT"}),l.jsx("div",{className:`mt-0 font-medium text-white ${p}`,children:o.join(", ")})]})]})})}const hw=tn.memo(mw);function pw({battery:n,compact:s=!1}){if(!n?.available||!n.warnActive&&!n.urgentActive)return null;const r=n.urgentActive?"BATTERY VERY LOW, DOCK THE ROVER AND CHARGE IMMEDIATELY!!":"Battery low! please dock and charge the rover soon.",o=s?"p-2 top-6":"p-4 top-10",u=s?"text-sm":"text-2xl";return l.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:l.jsx("div",{className:`text-center font-semibold text-white animate-pulse ${u}`,children:l.jsx("div",{children:r})})})}const xw=tn.memo(pw);function gw({sensors:n}){const s=[n?.lightBumpLeftSignal,n?.lightBumpFrontLeftSignal,n?.lightBumpCenterLeftSignal,n?.lightBumpCenterRightSignal,n?.lightBumpFrontRightSignal,n?.lightBumpRightSignal],r=s.filter(p=>p!=null).reduce((p,x)=>Math.max(p,x),1200),o=p=>Math.pow(Math.max(0,Math.min(1,(p??0)/r)),.35),u=p=>p==null||p<=0?"hsl(200 60% 18%)":`hsl(${(200+o(p)*360)%360} 100% 60%)`,f=6,h=12;return l.jsx("div",{className:"flex w-full items-center justify-center gap-0.5",children:s.map((p,x)=>{const g=o(p),b=xz.session?.role||null),r=pe(z=>z.session?.assignment?.roverId||null),o=pe(z=>z.session?.roster||[]),{sendMessage:u,onInputFocus:f,onInputBlur:h,blurChat:p,registerInputRef:x,setTypingActive:g}=pf(),{value:b}=Xe("tts",{engine:"flite",voice:"rms",pitch:50}),[y,N]=m.useState(""),[M,k]=m.useState(!1),S=s!=="spectator",w=s==="spectator",q=!!m.useMemo(()=>o.find(z=>String(z.id)===String(r))||null,[r,o])?.audio?.ttsEnabled,E=m.useMemo(()=>{if(!q)return null;const z=b?.engine==="espeak"?"espeak":"flite";if(z==="espeak"){let $=Number.isFinite(b?.pitch)?Math.round(b.pitch):void 0;return typeof $=="number"&&($=Math.max(0,Math.min(99,$))),{speak:!0,engine:z,pitch:$}}const K=typeof b?.voice=="string"?b.voice:void 0;return{speak:!0,engine:z,voice:K}},[b?.engine,b?.pitch,b?.voice,q]),C=n?"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",L=n?"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",G=n?"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(z){if(z.preventDefault(),!S)return;const K=y.trim();if(K){k(!0);try{await u(K,E),N(""),p(),g(!1)}catch($){alert($.message)}finally{k(!1)}}}return w?null:l.jsxs("form",{onSubmit:O,className:C,children:[l.jsx("input",{className:L,value:y,onChange:z=>{const K=z.target.value;N(K),g(!!K.trim())},onFocus:z=>{f(z),g(!!y.trim())},onBlur:z=>{h(z),g(!1)},onKeyDown:z=>{z.key==="Enter"&&!y.trim()&&(z.preventDefault(),p(),g(!1))},ref:z=>x(z,{target:"hud"}),placeholder:S?"Chat (TTS)":"Spectator",disabled:!S}),l.jsx("button",{type:"submit",disabled:!S||M,className:G,children:"Speak"})]})}const yw=m.memo(vw);function kr({sessionInfo:n,audioSessionInfo:s,videoMode:r="whep",snapshotFeed:o=null,qualityNotice:u=null,label:f,roverDescription:h=null,roverColor:p=null,forceMute:x=!1,telemetryFrame:g,batteryConfig:b,layoutFormat:y="desktop",hudVariant:N="default",driverLabel:M=null,hudForceMap:k=!1,hudMapPosition:S="top-center",hudLabelScale:w=1,fitParent:j=!1,overcurrentLimiter:q=null,showTurnCue:E=!1,turnTimerText:C=null,isActiveDriver:L=!1,idleSkipSeconds:G=null,showNotTurnNotice:O=!1,notTurnCountdownText:z=null,showPreviewReason:K=!1,notTurnFlashAt:$=0}){const X=pe(xe=>(xe.session?.socials||[]).find(Ee=>String(Ee?.id||Ee?.label||"").toLowerCase()==="discord")?.url||null||xe.session?.discord?.invite||null),P=m.useRef(null),oe=m.useRef(null),ie=m.useRef(null),V=m.useRef(null),T=m.useRef(null),H=m.useRef(null),J=m.useRef(null),ne=m.useRef(null),[de,R]=m.useState("idle"),[_,Z]=m.useState(null),[ee,fe]=m.useState("idle"),[ce,ue]=m.useState(null),[je,ve]=m.useState(0),[ye,Qe]=m.useState(0),[Ie,Re]=m.useState(!0),[Te,He]=m.useState(!1),dt=!!s?.url,le=r==="snapshot",se=g?.sensors,{value:be}=Xe("audio",ct),he=Number.isFinite(be?.masterVolume)?be.masterVolume:ct.masterVolume,Ce=Number.isFinite(be?.roverVolume)?be.roverVolume:ct.roverVolume,we=typeof be?.mainBrushDuckEnabled=="boolean"?be.mainBrushDuckEnabled:typeof be?.autoLevelEnabled=="boolean"?be.autoLevelEnabled:ct.mainBrushDuckEnabled,Ze=Number.isFinite(be?.mainBrushDuckAmount)?Math.max(0,Math.min(1,be.mainBrushDuckAmount)):ct.mainBrushDuckAmount,re=Math.max(0,Math.min(1,he*Ce)),me=se?.batteryChargeMah??null,at=!(y==="desktop"),Tt=at?"top-right":S,[pl]=$g(),an=k||at?!0:pl,ma=Gg({charge:me,config:b}),Ua=se?.wheelOvercurrents||null,Cn=m.useMemo(()=>Ua==null?[]:Object.entries(Ua).filter(([,xe])=>!!xe).map(([xe])=>xe),[Ua]),ft=q?.caps||null,bn=q?.overcurrent?.groups||null,Dt=m.useMemo(()=>{if(typeof window>"u")return{debugAudio:!1,debugHud:!1};const xe=new URLSearchParams(window.location.search);return{debugAudio:xe.has("debugAudio"),debugHud:xe.has("debugHud")}},[]),zr=Dt.debugAudio,xl=Dt.debugHud,Ur=m.useMemo(()=>{if(!ft)return null;const xe=Number.isFinite(ft?.drive?.cap)?ft.drive.cap:1,ke=Number.isFinite(ft?.aux?.cap)?ft.aux.cap:1;return Math.max(0,Math.min(1,1-Math.min(xe,ke)))},[ft]),On=!!q?.isActive,Lt=m.useMemo(()=>{const xe=Cn.length?Cn:On?["limiter"]:[],ke=Ur??(Cn.length?1:0);return{motors:xe,fill:ke,visible:!!xe.length}},[Cn,On,Ur]),vn=!!((Number(se?.mainBrushCurrentMa)||0)>uw||se?.wheelOvercurrents?.mainBrush),Bn=we&&vn?1-Ze:1,Ln=Math.max(0,Math.min(1,re*Bn)),Ha=we&&vn&&Ze>0?`Volume decreased ${Math.round(Ze*1e3)/10}%`:null,Hr=m.useRef({hasDedicatedAudio:!1,audioUrl:null,mainBrushDuckEnabled:!1,mainBrushDuckAmount:0,mainBrushActive:!1,baseRoverGain:0,effectiveRoverGain:0});m.useEffect(()=>{Hr.current={hasDedicatedAudio:dt,audioUrl:s?.url||null,mainBrushDuckEnabled:we,mainBrushDuckAmount:Ze,mainBrushActive:vn,baseRoverGain:re,effectiveRoverGain:Ln}},[dt,s?.url,we,Ze,vn,re,Ln]);const rt=m.useCallback((xe,ke={})=>{if(!zr)return;const _e=oe.current,Ee=Hr.current,Ge={event:xe,ts:Date.now(),roverLabel:f||null,hasDedicatedAudio:Ee.hasDedicatedAudio,audioUrl:Ee.audioUrl,mainBrushDuckEnabled:Ee.mainBrushDuckEnabled,mainBrushDuckAmount:Ee.mainBrushDuckAmount,mainBrushActive:Ee.mainBrushActive,baseRoverGain:Ee.baseRoverGain,effectiveRoverGain:Ee.effectiveRoverGain,element:_e?{muted:_e.muted,volume:_e.volume,paused:_e.paused,ended:_e.ended,readyState:_e.readyState,networkState:_e.networkState}:null,...ke};try{console.log(`[AudioDebug] ${xe} ${JSON.stringify(Ge)}`)}catch{console.log("[AudioDebug]",xe,Ge)}},[zr,f]);m.useEffect(()=>{xl&&console.log("[OvercurrentHUD]",{overlayVisible:Lt.visible,overlayMotors:Lt.motors,overlayFill:Lt.fill,limiterActive:On,limiterCaps:ft,limiterGroups:bn,wheelOvercurrents:Ua})},[xl,Lt,On,ft,bn,Ua]),m.useEffect(()=>{rt("settings/update")},[rt]);const zn=m.useCallback(()=>{clearTimeout(ie.current),ie.current=setTimeout(()=>ve(Date.now()),mx)},[]),Un=m.useCallback(()=>{clearTimeout(V.current),V.current=setTimeout(()=>Qe(Date.now()),mx)},[]),hs=m.useCallback(async()=>{const xe=P.current;if(xe)try{xe.muted=!0,await xe.play()}catch{}},[]),gl=m.useCallback((xe=0)=>{if(x||dt)return;clearTimeout(H.current);const ke=()=>{clearTimeout(H.current),H.current=setTimeout(()=>{x||_e()},ow)},_e=async()=>{const Ee=P.current;if(Ee)try{await hs(),Ee.muted=!1,await Ee.play(),Re(!1)}catch{Ee.muted=!0,Re(!0),ke()}};H.current=setTimeout(_e,xe)},[hs,x,dt]);m.useEffect(()=>()=>{clearTimeout(ie.current),clearTimeout(V.current),clearTimeout(H.current),clearInterval(T.current),J.current&&(cancelAnimationFrame(J.current),J.current=null)},[]),m.useEffect(()=>{if(!O||!$)return;He(!0);const xe=setTimeout(()=>He(!1),650);return()=>clearTimeout(xe)},[O,$]),m.useEffect(()=>{de==="playing"&&gl(0)},[de,gl]),m.useEffect(()=>{le&&(R("snapshot"),Z(null))},[le]),m.useEffect(()=>{if(le||!n?.url||!P.current)return;let xe=!0,ke;const _e=setTimeout(()=>Re(!0),0),Ee=(Ge,_t)=>{xe&&(rt("video/status",{nextStatus:Ge,info:_t||null}),R(Ge),Z(_t||null),Ge==="playing"&&hs(),["error","failed","disconnected","closed"].includes(Ge)&&zn())};return ke=new ux({url:n.url,token:n.token,video:P.current,receiveAudio:!dt,onStatus:Ee}),ke.start().catch(Ge=>{xe&&(R("error"),Z(Ge.message),zn())}),()=>{xe=!1,clearTimeout(_e),ke?.stop()}},[le,n?.url,n?.token,je,zn,hs,dt,rt]),m.useEffect(()=>{de==="stopped"&&n?.url&&zn()},[de,n?.url,zn]),m.useEffect(()=>{const xe=oe.current;if(!xe||!s?.url){rt("route/no-audio-url"),ne.current=null;return}const ke=Math.max(0,Math.min(1,Ln)),_e=ne.current==null?Math.max(0,Math.min(1,xe.volume)):ne.current;if(J.current&&(cancelAnimationFrame(J.current),J.current=null),ke>_e){const Ee=performance.now(),Ge=_e,_t=ke-Ge,Va=$a=>{const ot=Math.min(1,($a-Ee)/dw),Hn=Ge+_t*ot;xe.volume=Hn,ne.current=Hn,ot<1?J.current=requestAnimationFrame(Va):J.current=null};J.current=requestAnimationFrame(Va)}else xe.volume=ke,ne.current=ke;rt("route/direct",{elementVolume:ke,duckEnabled:we,mainBrushActive:vn,duckAmount:Ze})},[s?.url,Ln,we,vn,Ze,rt]),m.useEffect(()=>{if(!s?.url||!oe.current)return;let xe=!0,ke;const _e=(Ee,Ge)=>{xe&&(rt("audio/status",{nextStatus:Ee,info:Ge||null}),ue(Ge||(Ee==="connected"?"connected":null)),fe(_t=>Ee==="connected"&&(_t==="playing"||_t==="connecting")||Ee==="new"?_t:Ee),["error","failed"].includes(Ee)&&Un())};return ke=new ux({url:s.url,token:s.token,video:oe.current,audioOnly:!0,onStatus:_e}),ke.start().catch(Ee=>{xe&&(fe("error"),ue(Ee.message),Un())}),()=>{xe=!1,ke?.stop()}},[s?.url,s?.token,ye,Un,rt]),m.useEffect(()=>{const xe=oe.current;if(!s?.url||!xe){clearInterval(T.current);return}if(!["connecting","connected","playing","paused"].includes(ee)){clearInterval(T.current);return}const _e=async()=>{const Ee=oe.current;Ee&&(Ee.muted=!1,!(!Ee.paused&&!Ee.ended)&&(rt("retry/play-attempt"),Ee.play().then(()=>{rt("retry/play-ok"),fe(Ge=>Ge==="connected"?"playing":Ge),ue(Ge=>Ge==="paused"?null:Ge)}).catch(Ge=>{rt("retry/play-fail",{error:Ge?.message}),ue(_t=>_t||Ge?.message||"autoplay blocked")})))};return _e(),T.current=setInterval(_e,cw),()=>clearInterval(T.current)},[s?.url,ee,rt]),m.useEffect(()=>{const xe=oe.current;if(!xe)return;const ke=()=>{rt("element/play"),fe(ot=>ot==="error"?ot:"playing"),ue(null)},_e=()=>{rt("element/pause"),fe(ot=>["error","failed","disconnected","closed","stopped"].includes(ot)?ot:"paused"),ue(ot=>ot||"paused")},Ee=()=>{rt("element/ended"),fe(ot=>ot==="error"?ot:"stopped"),ue(ot=>ot||"ended")},Ge=()=>{const{error:ot}=xe,Hn=ot?.message||"audio error";rt("element/error",{error:Hn}),fe("error"),ue(Hn)},_t=()=>rt("element/waiting"),Va=()=>rt("element/canplay"),$a=()=>rt("element/stalled");return xe.addEventListener("play",ke),xe.addEventListener("pause",_e),xe.addEventListener("ended",Ee),xe.addEventListener("error",Ge),xe.addEventListener("waiting",_t),xe.addEventListener("canplay",Va),xe.addEventListener("stalled",$a),()=>{xe.removeEventListener("play",ke),xe.removeEventListener("pause",_e),xe.removeEventListener("ended",Ee),xe.removeEventListener("error",Ge),xe.removeEventListener("waiting",_t),xe.removeEventListener("canplay",Va),xe.removeEventListener("stalled",$a)}},[s?.url,rt]);const Vr=o?.error?`Error: ${o.error}`:o?.objectUrl?"snapshot":o?.status||"waiting",$r=le?Vr:n?.url?de==="error"?`Error: ${_||"unknown"}`:_?`${de} (${_})`:de:"waiting",bl=s?.error?`Error: ${s.error}`:s?.url?ee==="error"?`Error: ${ce||"unknown"}`:ce?`${ee} (${ce})`:ee:null,ps=N==="spectator",zt=N==="none",Gr=`${f||""}::${h||""}`;return l.jsxs("div",{className:`flex flex-col gap-0.5 ${j?"h-full":""}`,children:[l.jsxs("div",{className:`relative w-full overflow-hidden bg-black ${j?"h-full flex-1":"aspect-[4/3]"}`,children:[le?o?.objectUrl?l.jsx("img",{src:o.objectUrl,alt:f,className:"h-full w-full object-contain",draggable:!1}):l.jsx("div",{className:"flex h-full w-full items-center justify-center text-sm text-slate-300",children:"Waiting for frame…"}):l.jsx("video",{ref:P,muted:x||Ie||dt,playsInline:!0,autoPlay:!0,controls:!1,className:"h-full w-full object-contain"}),l.jsx("audio",{ref:oe,autoPlay:!0,hidden:!0}),!zt&&E?l.jsx(IN,{mobileHud:at,isActiveDriver:L,idleSkipSeconds:G}):null,zt?null:l.jsx(iw,{description:h,variant:N,mobileHud:at,displayKey:Gr}),zt?null:l.jsx(lw,{sensors:se,label:f,roverColor:p,status:$r,audioStatus:bl,levelStatus:Ha,layoutFormat:y,variant:N,driverLabel:M,showTopDown:an,mobileHud:at,mapPosition:Tt,turnTimerText:C,turnTimerFlashActive:Te,labelScale:w}),zt?null:l.jsx(yw,{compact:at}),!zt&&xl?l.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:${Lt.visible?1:0} motors:${Lt.motors.length} fill:${Math.round(Lt.fill*100)}%`}):null,zt?null:l.jsx(hw,{motors:Lt.motors,fill:Lt.fill,compact:at}),zt?null:l.jsx(xw,{battery:ma,compact:at}),!zt&&ps&&ma.available?l.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:l.jsx(Yd,{visual:ma,orientation:"vertical",variant:"inline",compact:at,className:"h-full w-4"})}):null,!zt&&u?l.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2",children:l.jsxs("div",{className:`mx-auto w-fit rounded border border-amber-300/80 bg-black/75 text-amber-200 ${at?"px-2 py-1 text-[0.6rem]":"px-3 py-1.5 text-sm"}`,children:[l.jsx("div",{className:"text-center",children:u}),l.jsx("div",{className:"pointer-events-auto mt-0",children:l.jsx(Ar,{id:"discord",label:"Join our Discord server while you wait!",url:X})})]})}):null,!zt&&O?l.jsx("div",{className:"pointer-events-none absolute bottom-1 left-1 z-40",children:l.jsxs("div",{className:`w-fit rounded border ${Te?"border-red-300/90 bg-red-900/80 text-red-100":"border-amber-300/80 bg-black/75 text-amber-200"} ${at?"px-2 py-1 text-[0.6rem]":"px-3 py-1.5 text-sm"}`,children:[l.jsx("div",{className:Te?"text-[0.82rem] font-semibold text-red-50":"text-[0.82rem] font-semibold text-white",children:"Not your turn to drive!"}),z?l.jsx("div",{className:Te?"text-red-100/95":"text-amber-100",children:z}):null,K?l.jsx("div",{className:Te?"text-red-100/90":"text-amber-200/85",children:"Video switched to preview mode to save bandwidth."}):null,l.jsx("div",{className:"pointer-events-auto mt-0.5",children:l.jsx(Ar,{id:"discord",label:"Join our Discord while you wait!",url:X})})]})}):null]}),!zt&&!ps&&l.jsxs("div",{className:"space-y-0.5",children:[l.jsx(bw,{sensors:se}),l.jsx("div",{className:"panel-section space-y-0.5 text-sm",children:l.jsx(Yd,{visual:ma,compact:at})})]})]})}function Sw(n=[]){const s=new Set;return n.forEach(r=>{if(String(r?.role||"")==="spectator")return;const u=String(r?.roverId||"").trim(),f=String(r?.socketId||"").trim();!u||!f||s.add(f)}),s.size}function jf({layoutFormat:n="desktop"}){const s=pe(se=>se.session?.mode||null),r=pe(se=>se.session?.assignment?.roverId??null),o=pe(se=>se.session?.roster??[]),u=pe(se=>se.session?.users??[]),f=pe(se=>se.session?.turnQueues??{}),h=pe(se=>se.session?.socketId||null),p=pe(se=>se.session?.activeDrivers??{}),{state:{song:x,lastControlIntentAt:g},overcurrentLimiter:b}=Ct(),[y,N]=m.useState(()=>Date.now()),[M,k]=m.useState(!1),[S,w]=m.useState(null),[j,q]=m.useState(0),E=m.useRef({initialized:!1,roverId:null,activeDriverId:null}),C=m.useRef(g||0);m.useEffect(()=>{if(s!=="turns")return;const se=setInterval(()=>N(Date.now()),250);return()=>clearInterval(se)},[s]);const G=!!(r&&o?o.find(se=>String(se.id)===String(r)):null)?.media?.audioPublishUrl,O=r?f?.[r]:null,z=r?p?.[r]:null,K=!!(h&&z===h),$=m.useMemo(()=>{const se=O?.queue||[];if(!se.length||!O?.current||se.length<=1)return null;const be=se.findIndex(he=>he===O.current);return be===-1?se[0]||null:se[(be+1)%se.length]||null},[O?.queue,O?.current]),X=!!(h&&$===h),P=O?.deadline||null,oe=O?.idleDeadline||null,ie=P?P-y:null,V=oe?oe-y:null,T=s==="turns",H=o.length,J=m.useMemo(()=>Sw(u),[u]),ne=T&&J>H,de=T&&X&&ie!=null&&ie<=5e3&&ie>0,R=T&&!K,_=R&&!de&&ne,Z=!_,ee=ie!=null&&Number.isFinite(ie)?Math.max(0,Math.ceil(ie/1e3)):null,fe=V!=null&&Number.isFinite(V)?Math.max(0,Math.ceil(V/1e3)):null,ce=m.useMemo(()=>!T||!K?null:ee!=null?`${ee}s left`:"Your turn",[T,K,ee]),ue=m.useMemo(()=>!R||!X||ee==null?null:`${ee} seconds until your turn.`,[R,X,ee]),je=r?[...Z?[{type:"rover",id:r,key:r}]:[],...G?[{type:"rover",id:`${r}-audio`,key:`${r}-audio`}]:[]]:[],ve=wr(je),ye=r&&Z?ve[r]:null,Qe=r&&G?ve[`${r}-audio`]:null,Ie=yf(r?[r]:[],{enabled:!!r,version:s}),Re=r&&Ie[r]||null,Te=hl(r),He=r&&o?o.find(se=>String(se.id)===String(r)):null,dt=He?.battery??null,le=He?.name||(r?`Rover ${r}`:"");return m.useEffect(()=>{if(s!=="turns"){k(!1),w(null),E.current={initialized:!1,roverId:null,activeDriverId:null};return}const se=E.current,be=z||null;if(!h||!r){k(!1),w(null),E.current={initialized:!1,roverId:null,activeDriverId:null};return}if(!se.initialized||se.roverId!==r){E.current={initialized:!0,roverId:r,activeDriverId:be};return}!!se.activeDriverId&&se.activeDriverId!==h&&be===h?(k(!0),w(Date.now())):be!==h&&M&&(k(!1),w(null)),E.current={initialized:!0,roverId:r,activeDriverId:be}},[z,s,r,h,M]),m.useEffect(()=>{!M||!S||g>S&&k(!1)},[g,S,M]),m.useEffect(()=>{const se=Number(C.current)||0,be=Number(g)||0;be>se&&R&&q(Date.now()),C.current=be},[R,g]),l.jsx("section",{className:"panel",children:r?l.jsx(kr,{sessionInfo:ye,videoMode:Z?"whep":"snapshot",snapshotFeed:Re,audioSessionInfo:Qe,label:le,roverDescription:He?.description,roverColor:He?.color||null,telemetryFrame:Te,batteryConfig:dt,layoutFormat:n,overcurrentLimiter:b,songNote:x?.note,qualityNotice:null,showTurnCue:M,turnTimerText:ce,turnSeconds:ee,isActiveDriver:K,idleSkipSeconds:fe,showNotTurnNotice:R,notTurnCountdownText:ue,showPreviewReason:_,notTurnFlashAt:j}):l.jsxs("div",{className:"panel-muted content-center text-center text-sm text-slate-400 aspect-[4/3]",children:[l.jsx("p",{children:"You are not assigned to a rover."}),l.jsx("p",{className:"mt-0",children:l.jsx("a",{href:"/spectate",className:"text-blue-400 underline hover:text-blue-500",children:"Click here to visit the spectator page."})})]})})}function qo({label:n,tone:s="muted"}){const r=s==="success"?"bg-emerald-900 text-emerald-100":s==="warn"?"bg-amber-900 text-amber-100":"bg-slate-800 text-slate-200";return l.jsx("span",{className:`rounded px-1 py-0.5 text-xs font-semibold leading-none ${r}`,children:n})}function Ho(n){if(!Number.isFinite(n))return 0;const s=n%360;return s<0?s+360:s}function jw(n){if(!Array.isArray(n)||n.length<3)return 0;const[s,r,o]=n,u=Math.max(0,Math.min(255,Number(s)))/255,f=Math.max(0,Math.min(255,Number(r)))/255,h=Math.max(0,Math.min(255,Number(o)))/255,p=Math.max(u,f,h),x=Math.min(u,f,h),g=p-x;if(g===0)return 0;let b=0;return p===u?b=(f-h)/g%6:p===f?b=(h-u)/g+2:b=(u-f)/g+4,Ho(Math.round(b*60))}function hx(n){const s=Ho(n),r=1,o=1-Math.abs(s/60%2-1);let u=0,f=0,h=0;return s<60?(u=r,f=o):s<120?(u=o,f=r):s<180?(f=r,h=o):s<240?(f=o,h=r):s<300?(u=o,h=r):(u=r,h=o),[Math.round(u*255),Math.round(f*255),Math.round(h*255)]}function px(n){return n?Array.isArray(n.hsColor)?Ho(Number(n.hsColor[0])):Array.isArray(n.rgbColor)?jw(n.rgbColor):0:0}function Nw({entity:n,connected:s,controlsLocked:r,onToggle:o,onSetColor:u,onSetWhite:f}){const h=n.state==="unavailable"||!n.available,p=n.state==="on",x=n.type==="light"&&n.supportsColor,g=h?"warn":p?"success":"muted",b=h?"Unavailable":p?"On":"Off",y=r||!s||h,N=y||!x,[M,k]=m.useState(()=>px(n)),S=m.useRef(M),w=m.useRef(!1),j=h?"border-slate-800 bg-slate-900 text-slate-400 cursor-not-allowed":r?"border-slate-800 bg-slate-900 text-slate-300 cursor-not-allowed":p?"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(!x||w.current)return;const z=px(n);S.current=z,k(z)},[n.rgbColor,n.hsColor,x]);const q=z=>{const K=Ho(Number(z.target.value));S.current=K,k(K)},E=()=>{N||!u||u(n.id,hx(S.current))},C=z=>{z.stopPropagation()},L=z=>{C(z),!(N||!f)&&f(n.id)},O=`rgb(${(x?hx(S.current):[255,255,255]).join(",")})`;return l.jsxs("button",{type:"button",onClick:()=>o(n.id),disabled:y,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 ${j} disabled:opacity-60 disabled:hover:bg-inherit`,children:[l.jsxs("div",{className:"min-w-0 flex-1",children:[l.jsxs("div",{className:"flex items-center gap-0.5 text-sm leading-normal",children:[l.jsx("span",{className:"truncate font-semibold text-white",children:n.name||n.id}),x&&l.jsxs(l.Fragment,{children:[l.jsx(qo,{label:b,tone:g}),!s&&l.jsx("span",{className:"text-xs text-amber-200",children:"Offline"})]})]}),x?l.jsx("div",{className:"-mt-0.5 w-full",onClick:C,onPointerDown:z=>{C(z),w.current=!0},onPointerUp:z=>{C(z),w.current=!1,E()},onPointerCancel:z=>{C(z),w.current=!1,E()},onKeyUp:z=>{C(z),E()},onBlur:E,children:l.jsx("div",{className:"relative w-full",children:l.jsx("input",{type:"range",min:"0",max:"360",step:"1",value:M,onChange:q,disabled:N,"aria-label":`Set color for ${n.name||n.id}`,className:"ha-hue-slider w-full"})})}):l.jsxs("div",{className:"flex items-center gap-0.5 text-xs text-slate-400",children:[l.jsx(qo,{label:b,tone:g}),!s&&l.jsx("span",{className:"text-amber-200",children:" · Offline"})]})]}),x&&l.jsxs("div",{className:"absolute right-1 top-1 flex items-center gap-0.5",children:[l.jsx("span",{role:"button",tabIndex:N?-1:0,onClick:L,onPointerDown:C,onKeyDown:z=>{N||(z.key==="Enter"||z.key===" ")&&(z.preventDefault(),L(z))},title:"Set white color temperature","aria-label":`Set ${n.name||n.id} to white`,"aria-disabled":N,className:`inline-flex items-center justify-center rounded border border-slate-200 bg-white px-1 py-0.5 text-xs font-semibold leading-none text-slate-900 ${N?"cursor-not-allowed opacity-60":"cursor-pointer hover:bg-slate-100"}`,children:"white"}),l.jsx("span",{className:"pointer-events-none h-2.5 w-2.5 rounded-full border border-white/60",style:{backgroundColor:O}})]}),!x&&l.jsx("div",{className:"self-center text-xs font-semibold text-white/90",children:p?"Turn off":"Turn on"})]})}function Yg(){const{state:{keymap:n}}=Ct(),s=pe(N=>N.session?.homeAssistant||null),{homeAssistantToggle:r,homeAssistantSetLightColor:o,homeAssistantSetLightWhite:u}=Yt(),f=m.useMemo(()=>s?.entities||[],[s?.entities]),h=s?.lightPolicy||null,p=!!(h?.locked||h?.lockedOn),x=h?.lockState||(h?.lockedOn?"on":null),g=qt(n?.homeAssistantOn?.[0]),b=qt(n?.homeAssistantOff?.[0]);if(!s?.enabled)return l.jsxs("section",{className:"panel-section space-y-0.5 text-sm text-slate-400",children:[l.jsx("p",{className:"text-slate-300",children:"Room Controls"}),l.jsx("p",{className:"text-slate-500",children:"Not configured on the server."})]});if(f.length===0)return l.jsxs("section",{className:"panel-section space-y-0.5 text-sm text-slate-400",children:[l.jsx("p",{className:"text-slate-300",children:"Room Controls"}),l.jsx("p",{className:"text-slate-500",children:"No lights or switches configured."})]});const y=!!s?.connected;return l.jsxs("section",{className:"panel-section space-y-0.5 text-base",children:[l.jsxs("header",{className:"flex items-center justify-between gap-0.5 text-sm text-slate-400",children:[l.jsxs("div",{className:"flex items-center gap-0.5",children:[l.jsx("p",{children:"Room Controls"}),l.jsx("span",{className:"text-xs text-slate-500",children:f.length}),p?l.jsx(qo,{label:x==="off"?"Locked Off":"Locked On",tone:"warn"}):null,l.jsxs("div",{className:"flex items-center gap-0.5 text-xs text-slate-300 background-black",children:[l.jsxs("span",{className:"flex items-center gap-0.5",children:[l.jsx("span",{children:"On"}),g?l.jsx(xx,{label:g}):null]}),l.jsxs("span",{className:"flex items-center gap-0.5",children:[l.jsx("span",{children:"Off"}),b?l.jsx(xx,{label:b}):null]})]})]}),l.jsx(qo,{label:y?"Connected":"Offline",tone:y?"success":"warn"})]}),p?l.jsx("p",{className:"rounded border border-amber-600/60 bg-amber-900/40 px-1 py-0.5 text-xs text-amber-100",children:x==="off"?"Lights are locked off. Room controls are disabled.":"Lights are locked on. Room controls are disabled."}):null,l.jsx("div",{className:"flex flex-wrap gap-0.5",children:f.map(N=>l.jsx(Nw,{entity:N,connected:y,controlsLocked:p,onToggle:r,onSetColor:o,onSetWhite:u},N.id))})]})}function xx({label:n}){return n?l.jsx("span",{className:"rounded border border-white/40 px-1 text-[0.7rem] text-white",children:n}):null}function Xg(){const{login:n,setRole:s}=Yt(),[r,o]=m.useState(""),[u,f]=m.useState(""),[h,p]=m.useState(!1);async function x(g){g.preventDefault(),p(!0);try{await n(r,u),o(""),f("")}catch(b){alert(b.message)}finally{p(!1)}}return l.jsxs("div",{className:"panel-section space-y-0.5 text-base",children:[l.jsx("p",{className:"text-sm text-slate-400",children:"Admin login"}),l.jsxs("form",{className:"flex flex-col gap-0.5",onSubmit:x,children:[l.jsx("input",{className:"field-input",placeholder:"Username",value:r,onChange:g=>o(g.target.value)}),l.jsx("input",{className:"field-input",placeholder:"Password",type:"password",value:u,onChange:g=>f(g.target.value)}),l.jsx("button",{type:"submit",disabled:h,className:"button-dark w-full disabled:opacity-50",children:h?"Logging in…":"Login"})]})]})}function gx(...n){return n.filter(Boolean).join(" ")}function ww(n){const s=n?.batteryState?.percentDisplay;return s==null?"--":`${s}%`}function Aw(n){return n?.batteryState?n.batteryState.urgentActive?"text-red-400":n.batteryState.warnActive?"text-amber-300":"text-emerald-300":"text-slate-400"}function Cw({title:n,roster:s=[],emptyText:r="No roster data.",renderActions:o=null}){return l.jsxs("div",{className:"space-y-0.5 text-sm",children:[n&&l.jsx("p",{className:"text-sm text-slate-400",children:n}),s.length===0?l.jsx("p",{className:"text-sm text-slate-500",children:r}):l.jsx("ul",{className:"space-y-0.5 text-sm",children:s.map(u=>{const f=!!(u?.private?.enabled&&u?.private?.open),h=!!u?.locked;return l.jsxs("li",{className:gx("surface flex flex-wrap items-center justify-between gap-0.5",h?"bg-red-900/40":f?"bg-amber-700/35 border border-amber-200/30":null),children:[l.jsxs("div",{children:[l.jsx("p",{className:"text-slate-200",children:l.jsx("span",{className:"rounded px-1 py-[1px] border border-transparent",style:da(u.color,.16),children:u.name})}),l.jsxs("p",{className:"text-xs text-slate-500 flex flex-wrap items-center gap-0.5",children:[l.jsx("span",{children:u.locked?"locked":"free"}),u.lockReason&&l.jsx("span",{className:"rounded bg-black/30 px-1",children:u.lockReason}),l.jsxs("span",{className:gx("font-semibold",Aw(u)),children:["Battery ",ww(u)]})]})]}),o?o(u):null]},u.id)})})]})}function kw(n){const s=n?.runtime||{},r=n?.output||{},o=n?.errors||{};return s.inFlight?{label:"IN FLIGHT",detail:s.reason||"Generating commentary now",className:"border-amber-400/60 bg-amber-700/20 text-amber-200"}:s.outcome==="posted"?{label:"POSTED",detail:r.posted?`Last: ${r.posted}`:"Commentary posted",className:"border-emerald-400/60 bg-emerald-700/20 text-emerald-200"}:s.outcome==="skipped"?{label:"SKIPPED",detail:s.reason||"Model chose to skip",className:"border-slate-400/60 bg-slate-700/30 text-slate-200"}:s.outcome==="failed"?{label:"FAILED",detail:o.message||s.reason||"Tick failed",className:"border-red-400/60 bg-red-700/20 text-red-200"}:{label:s.running?"IDLE":"STOPPED",detail:s.reason||"Waiting for next tick",className:"border-sky-400/50 bg-sky-700/20 text-sky-200"}}function Ew(n,s){const r=Date.now(),u=(Array.isArray(n)?n:[]).map((f,h)=>{const p=String(f?.role||"").toLowerCase(),x=typeof f?.content=="string"?f.content:JSON.stringify(f?.content??null,null,2),g=p==="system"?"LLM System":p==="assistant"?"LLM Context":p==="user"?"LLM Input":"LLM Message";return{id:`llm-msg-${h}`,message:{ts:r+h,nickname:g,text:x,role:"spectator",system:p==="system"}}});if(s!=null){const f=String(s);u.push({id:"llm-output",message:{ts:r+u.length+1,nickname:"LLM Output",text:f.trim()?f:"",role:"spectator",system:!0}})}return u}function Mw({state:n,onClearHistory:s,clearingHistory:r}){const[o,u]=m.useState(null);if(!n)return l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),l.jsx("div",{className:"surface text-xs text-slate-300",children:"No status received yet."})]});const f=n.runtime||{},h=n.counters||{},p=n.timings||{},x=n.input||{},g=n.output||{},b=n.errors||{},y=Array.isArray(n.history)?n.history:[],N=y.find(w=>w.runId===o)||(y.length?y[y.length-1]:null),M=kw(n),k=Ew(x.modelMessages,g.raw),S=[{label:"running",value:f.running?"yes":"no"},{label:"in flight",value:f.inFlight?"yes":"no"},{label:"phase",value:f.phase||"--"},{label:"run id",value:f.currentRunId??"--"},{label:"tick count",value:f.tickCount??0},{label:"last tick",value:f.lastTickAt?new Date(f.lastTickAt).toLocaleString():"never"},{label:"next run",value:f.nextRunAt?new Date(f.nextRunAt).toLocaleString():"n/a"},{label:"outcome",value:f.outcome||"--"},{label:"reason",value:f.reason||"--"},{label:"skip streak",value:h.skipStreak??0},{label:"clear count",value:h.clearCount??0},{label:"last gen",value:p.lastGenerationMs!=null?`${p.lastGenerationMs} ms`:"--"},{label:"avg gen",value:p.avgGenerationMs!=null?`${p.avgGenerationMs} ms`:"--"},{label:"gen count",value:p.generationCount??0},{label:"prompt chars",value:h.promptChars??0},{label:"active drivers",value:h.snapshotSummary?.activeDrivers??0},{label:"snapshot rovers",value:h.snapshotSummary?.rovers??0},{label:"snapshot chat",value:h.snapshotSummary?.chatMessages??0}];return l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),l.jsx("div",{className:"flex gap-0.5 text-xs",children:l.jsx("button",{type:"button",onClick:s,disabled:!!r,className:"button-danger disabled:cursor-not-allowed disabled:opacity-60",children:r?"Clearing...":"Clear LLM History"})}),l.jsxs("div",{className:`surface border text-center ${M.className}`,children:[l.jsx("div",{className:"text-[1.1rem] font-bold tracking-wide",children:M.label}),l.jsx("div",{className:"text-xs text-slate-200",children:M.detail})]}),l.jsx("div",{className:"surface flex flex-wrap gap-0.5 text-xs",children:S.map(w=>l.jsxs("span",{className:"rounded border border-slate-600/60 bg-slate-800/70 px-0.5 py-0.25 text-[0.72rem] leading-tight text-slate-200",children:[w.label,": ",w.value]},w.label))}),b.message?l.jsxs("div",{className:"surface text-xs text-red-300 break-words",children:["Error: ",b.message]}):null,b.details?l.jsxs("details",{className:"surface text-xs text-red-200",children:[l.jsx("summary",{className:"cursor-pointer select-none text-red-300",children:"Failure details"}),l.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-red-200",children:JSON.stringify(b.details,null,2)})]}):null,g.generated?l.jsxs("div",{className:"surface text-xs text-slate-200 break-words",children:["Generated: ",g.generated]}):null,g.posted?l.jsxs("div",{className:"surface text-xs text-emerald-200 break-words",children:["Posted: ",g.posted]}):null,l.jsxs("div",{className:"grid gap-0.5 md:grid-cols-2",children:[l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"Live Input Conversation"}),l.jsx("div",{className:"surface max-h-72 space-y-0.5 overflow-y-auto",children:k.length?k.map(w=>l.jsx(ff,{message:w.message},w.id)):l.jsx("div",{className:"text-xs text-slate-300",children:"No model conversation captured yet."})})]}),l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"Output + Error"}),l.jsxs("div",{className:"surface space-y-0.5 text-xs text-slate-200",children:[l.jsxs("div",{children:["Raw output: ",g.raw?.trim()?g.raw:""]}),l.jsxs("div",{children:["Posted: ",g.posted||""]}),l.jsxs("div",{children:["Output at: ",g.modelOutputAt?new Date(g.modelOutputAt).toLocaleString():"n/a"]}),l.jsxs("div",{children:["Failed at: ",b.failedAt?new Date(b.failedAt).toLocaleString():"n/a"]})]})]})]}),l.jsxs("details",{className:"surface text-xs text-slate-200",children:[l.jsx("summary",{className:"cursor-pointer select-none text-slate-300",children:"Full Monitor Payload"}),l.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-slate-200",children:JSON.stringify(n,null,2)})]}),l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"Recent Runs"}),l.jsx("div",{className:"surface max-h-52 space-y-0.5 overflow-y-auto text-xs",children:y.length?y.slice().reverse().map(w=>l.jsxs("button",{type:"button",onClick:()=>u(w.runId),className:`w-full text-left surface ${N?.runId===w.runId?"border border-sky-400/50":""}`,children:[l.jsxs("span",{className:"text-slate-300",children:["#",w.runId]})," ",l.jsx("span",{className:"text-slate-200",children:w.outcome||w.phase||"--"})," ",l.jsx("span",{className:"text-slate-400",children:w.durationMs!=null?`${w.durationMs}ms`:"--"})," ",l.jsx("span",{className:"text-slate-500",children:w.reason||""})]},w.runId)):l.jsx("div",{className:"text-slate-300",children:"No runs recorded yet."})})]}),N?l.jsxs("details",{className:"surface text-xs text-slate-200",open:!0,children:[l.jsxs("summary",{className:"cursor-pointer select-none text-slate-300",children:["Run #",N.runId," details"]}),l.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-slate-200",children:JSON.stringify(N,null,2)})]}):null]})}function Rw({state:n,onClearHistory:s,clearingHistory:r}){const[o,u]=m.useState(!1);if(!n)return l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"Overseer Control"}),l.jsx("div",{className:"surface text-xs text-slate-300",children:"No status received yet."})]});const f=n.runtime||{},h=n.config||{},p=n.output||{},x=n.timings||{},g=n.input||{},b=n.errors||{},y=()=>{const N=Array.isArray(g.modelMessages)?g.modelMessages:[];return N.length?N.map((M,k)=>{const S=String(M?.role||"unknown").toUpperCase(),w=String(M?.content||"");return`#${k+1} ${S} + `,document.head.appendChild(s)},[])}function FN(n,s){return typeof n=="string"&&n.trim()?n.trim().toLowerCase():typeof s=="string"&&s.trim()?s.trim().toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,""):""}function Ar({id:n,label:s,url:r,className:o=""}){if(!r)return null;GN();const u=FN(n,s),f=VN[u]||Aj,h=$N[u]||null,p=s||n||"Link";return l.jsxs("a",{href:r,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:[l.jsx(f,{className:"mr-0"}),p]})}const Cr=10;function Gg({batteryState:n=null,charge:s=null,config:r=null}){const o=n?.percentDisplay!=null&&Number.isFinite(n.percentDisplay)?Math.round(n.percentDisplay):null,u=n?.warnActive??null,f=n?.urgentActive??null,h=r?.Full??null,p=r?.Warn??null,x=r?.Urgent??null,g=s??n?.charge??null;let b=o;if(b==null&&(b=YN({charge:g,full:h,warn:p,urgent:x})),b==null)return{available:!1};const y=Math.max(0,Math.min(1,b/100)),N=u??(p!=null&&g!=null&&g<=p),M=f??(x!=null&&g!=null&&g<=x);return{available:!0,percent:y,percentDisplay:b,warnActive:N,urgentActive:M,warnDisplayPercent:Cr}}function YN({charge:n,full:s,warn:r,urgent:o}){if(n!=null&&s!=null&&r!=null&&o!=null&&s>r&&r>o){const u=Cr/100,f=1-u;if(n<=o)return 0;if(n<=r){const p=(n-o)/(r-o);return Math.round(Math.max(0,Math.min(1,p))*Cr)}if(n>=s)return 100;const h=(n-r)/(s-r);return Math.round((u+Math.max(0,Math.min(1,h))*f)*100)}return null}const XN=1600,QN=800;function Nn(...n){return n.filter(Boolean).join(" ")}function KN({visual:n,orientation:s="horizontal",variant:r="inline",compact:o=!1,showLabel:u,className:f=""}){const h=r==="background",p=s==="vertical",x=u??!h;if(!n?.available){if(h){const P=Cr,oe=Nn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!N&&"battery-tick-warn"),ie=p?{bottom:`${P}%`}:{left:`${P}%`},V=Nn("absolute inset-0 pointer-events-none",f);return l.jsxs("div",{className:V,children:[l.jsx("div",{className:"absolute inset-0 bg-slate-900/35"}),l.jsx("div",{className:oe,style:ie})]})}return p?null:l.jsx("p",{className:"text-xs text-slate-500",children:"Battery telemetry unavailable"})}const g=n.percentDisplay??0,b=Math.max(0,Math.min(100,g)),y=n.warnDisplayPercent??Cr,N=!!n.urgentActive,M=!!n.warnActive,k=N?`${QN}ms`:M?`${XN}ms`:void 0,w=h?N||M?"bg-red-500/45":"bg-emerald-500/45":N||M?"bg-red-500":"bg-emerald-500",j=N||M?"bg-red-900/35":"bg-slate-900/35",q=N||M?"bg-red-900/45":"bg-slate-900/35",E=Nn(h?"absolute inset-0 pointer-events-none":"relative pointer-events-auto",p&&!h?"flex flex-col items-center justify-center":"w-full",f);if(h){const P=p?{height:`${b}%`}:{width:`${b}%`},oe=Nn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",w,"transition-[width,height]",N&&"battery-urgent-flash"),ie=Nn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!N&&"battery-tick-warn"),V=p?{bottom:`${y}%`}:{left:`${y}%`};return l.jsxs("div",{className:E,children:[l.jsx("div",{className:Nn("absolute inset-0",j,N&&"battery-urgent-flash")}),l.jsx("div",{className:oe,style:{...P,animationDuration:k}}),l.jsx("div",{className:ie,style:V})]})}const C=Nn("relative overflow-hidden rounded-sm border border-slate-800",N||M?q:"bg-zinc-900/90",N&&"battery-urgent-flash",p?"w-full flex-1":o?"h-4":"h-5"),L=p?{height:`${b}%`}:{width:`${b}%`},G=Nn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",w,"transition-[width,height]",N&&"battery-urgent-flash"),O=Nn("absolute z-10",p?"left-0 right-0 h-[2px]":"top-0 bottom-0 w-[2px]","bg-black/70",M&&!N&&"battery-tick-warn"),z=p?{bottom:`${y}%`}:{left:`${y}%`},K=`Battery ${g}%`,$=Nn("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"),X=Nn("rounded px-1.5 py-0.5",h?"bg-black/30 text-slate-100":"bg-black/50 text-slate-100");return l.jsxs("div",{className:E,children:[l.jsxs("div",{className:C,children:[l.jsx("div",{className:G,style:{...L,animationDuration:k}}),l.jsx("div",{className:O,style:z})]}),x&&!p?l.jsx("div",{className:$,children:l.jsx("span",{className:X,children:K})}):null,x&&p?l.jsx("div",{className:"mt-0.5 text-[0.65rem] font-semibold text-slate-100",children:l.jsxs("span",{className:X,children:[g,"%"]})}):null]})}const Yd=tn.memo(KN);function IN({mobileHud:n=!1,isActiveDriver:s=!1,idleSkipSeconds:r=null}){const o=n?"text-3xl":"text-5xl",u=n?"text-xs":"text-sm",f=n?"text-[0.55rem]":"text-[0.75rem]",h=n?"px-4 py-3":"px-6 py-4",p=s&&typeof r=="number";return l.jsx("div",{className:"pointer-events-none absolute inset-0 z-30 flex items-center justify-center bg-black/55",children:l.jsxs("div",{className:`flex flex-col items-center gap-0.5 rounded border border-amber-300/80 bg-black/70 ${h}`,children:[l.jsx("div",{className:`font-semibold text-amber-200 ${o}`,children:"IT IS YOUR TURN!"}),l.jsx("div",{className:`text-amber-200/80 ${u}`,children:"Start driving!"}),p?l.jsxs("div",{className:`text-red-100/90 ${f}`,children:["Idle skip in ",r,"s"]}):null]})})}function Uo(n){return Math.max(0,Math.min(1,n))}function Fg(n){return(n-90)*Math.PI/180}function vr(n,s,r,o){const u=Fg(o);return{x:n+r*Math.cos(u),y:s+r*Math.sin(u)}}function ZN(n,s,r,o,u){let f=o,h=u;h<=f&&(h+=360);const p=vr(n,s,r,f),x=vr(n,s,r,h);return["M",p.x,p.y,"A",r,r,0,0,1,x.x,x.y].join(" ")}function Sf(n,s){if(s)return"#ef4444";const r=Math.abs(n);return r>900?"#f59e0b":r>300?"#22c55e":"#64748b"}function JN(n,s){if(n==null||n<=0)return"hsl(200 60% 18%)";const o=Uo(n/(s||1));return`hsl(${(200+Math.pow(o,.45)*360)%360} 100% 60%)`}function PN(n,s){if(s)return"#ef4444";const r=Uo(n==null?0:n/4095),o=[47,55,69],u=[245,158,11],[f,h,p]=o.map((x,g)=>Math.round(x+(u[g]-x)*r));return`rgb(${f}, ${h}, ${p})`}function WN({count:n,totalSpan:s,gap:r,startAngle:o}){const f=(s-r*(n-1))/n,h=[];let p=o;for(let x=0;x0?.65:null;return l.jsxs("g",{style:{transformOrigin:`${n}px ${s}px`,animation:p?`spin ${p}s linear infinite`:"none",animationDirection:p?"reverse":"normal"},children:[l.jsx("circle",{cx:n,cy:s,r:10,fill:"#64748b",stroke:"#64748b",strokeWidth:"1"}),[0,120,240].map(g=>{const b=Fg(g),y=n+h*Math.cos(b),N=s+h*Math.sin(b);return l.jsx("line",{x1:n,y1:s,x2:y,y2:N,stroke:f,strokeWidth:"4",strokeLinecap:"round"},g)}),o?l.jsx("circle",{cx:n,cy:s,r:h+8,stroke:"#ef4444",strokeWidth:"3",fill:"none",className:"animate-pulse"}):null]})}function nw({cx:n,cy:s,current:r,overcurrent:o,variant:u,dirtLeft:f,dirtRight:h}){const p=Math.abs(r),x=Sf(r,o),g=1,b=96,y=12,N=`main-brush-pattern-a-${u}`,M=`main-brush-pattern-b-${u}`,k=p>0?.6:null,S=r>=0?1:-1;return l.jsxs("g",{children:[l.jsx("defs",{children:[N,M].map((w,j)=>l.jsxs("pattern",{id:w,patternUnits:"userSpaceOnUse",width:"6",height:"6",children:[l.jsx("rect",{width:"6",height:"6",fill:x,opacity:g}),l.jsx("path",{d:"M0 6 L6 0",stroke:"#0f172a",strokeWidth:"1"}),k?l.jsx("animateTransform",{attributeName:"patternTransform",type:"translate",from:"0 0",to:`0 ${S*(j===0?6:-6)}`,dur:`${k}s`,repeatCount:"indefinite"}):null]},w))}),l.jsx("rect",{x:n-b/2,y:s-14,width:b,height:y,rx:"3",fill:`url(#${N})`,stroke:"#64748b",strokeWidth:"1"}),l.jsx("rect",{x:n-b/2,y:s+4,width:b,height:y,rx:"3",fill:`url(#${M})`,stroke:"#64748b",strokeWidth:"1"}),l.jsx("circle",{cx:n-b/4,cy:s-8,r:3.5,fill:"#fbbf24"}),l.jsx("circle",{cx:n+b/4,cy:s+8,r:3.5,fill:"#fbbf24"}),o?l.jsx("rect",{x:n-b/2-4,y:s-16,width:b+8,height:y*2+16,rx:"6",stroke:"#ef4444",strokeWidth:"3",fill:"none",className:"animate-pulse"}):null]})}function aw({sensors:n={},variant:s="full",size:r,overlay:o=!1}){const u=r||(s==="mini"?190:260),f=u/2,h=u*.07,p=f,x=f+h,g=f*.8,b=g-4,y=g+4,N=g-14,M=g-6,k=g*.65,S=n?.bumpsAndWheelDrops||{},w=n?.wheelOvercurrents||{},j=n?.wheelLeftCurrentMa??0,q=n?.wheelRightCurrentMa??0,E=n?.sideBrushCurrentMa??0,C=n?.mainBrushCurrentMa??0,L=6,G=S.bumpLeft?L:0,O=S.bumpRight?L:0,z=WN({count:6,totalSpan:140,gap:6,startAngle:-70}),K=["L","FL","CL","CR","FR","R"],$=[n?.lightBumpLeftSignal,n?.lightBumpFrontLeftSignal,n?.lightBumpCenterLeftSignal,n?.lightBumpCenterRightSignal,n?.lightBumpFrontRightSignal,n?.lightBumpRightSignal],X=z.map((V,T)=>({label:K[T],start:V.start,end:V.end,value:$[T]})),P=[{label:"Cliff L",start:-60,end:-46,value:n?.cliffLeftSignal,active:n?.cliffLeft},{label:"Cliff FL",start:-32,end:-16,value:n?.cliffFrontLeftSignal,active:n?.cliffFrontLeft},{label:"Cliff FR",start:16,end:32,value:n?.cliffFrontRightSignal,active:n?.cliffFrontRight},{label:"Cliff R",start:46,end:60,value:n?.cliffRightSignal,active:n?.cliffRight}],oe=$.filter(V=>V!=null),ie=oe.length?Math.max(...oe,1200):1200;return l.jsxs("div",{className:`${o?"relative":"surface relative p-1"}`,style:o?{width:`${u}px`,height:`${u}px`}:{height:"100%",width:"100%",aspectRatio:"1 / 1"},children:[o?null:l.jsxs(l.Fragment,{children:[l.jsx("div",{className:"absolute left-1 top-1 text-xs text-slate-400",children:"Top-down"}),l.jsxs("div",{className:"absolute right-1 top-1 text-[0.65rem] text-slate-500",children:["0–",ie]})]}),l.jsxs("svg",{width:"100%",height:"100%",viewBox:`0 0 ${u} ${u}`,preserveAspectRatio:"xMidYMid meet",className:"mx-auto block",children:[l.jsx("circle",{cx:p,cy:x,r:g,fill:"#0f172a",stroke:"#334155",strokeWidth:"2"}),l.jsx(dx,{cx:p-k,cy:x,current:j,drop:S.wheelDropLeft,overcurrent:w.leftWheel,label:"L"}),l.jsx(dx,{cx:p+k,cy:x,current:q,drop:S.wheelDropRight,overcurrent:w.rightWheel,label:"R"}),l.jsx(tw,{cx:p+g*.65,cy:x-g*.55,current:E,overcurrent:w.sideBrush}),l.jsx(nw,{cx:p,cy:x,current:C,overcurrent:w.mainBrush,variant:s,dirtLeft:n?.dirtDetectLeft,dirtRight:n?.dirtDetect}),X.map(V=>{const T=JN(V.value,ie),H=y+4,J=H+28;return l.jsx(ew,{cx:p,cy:x,rBase:J,rTip:H,startDeg:V.start,endDeg:V.end,color:T,value:V.value,max:ie},V.label)}),P.map(V=>l.jsx(wd,{cx:p,cy:x,rInner:N,rOuter:M,startDeg:V.start,endDeg:V.end,color:PN(V.value,V.active),opacity:1,pulse:!!V.active},V.label)),l.jsx(wd,{cx:p,cy:x,rInner:b-G,rOuter:y-G,startDeg:-70,endDeg:-6,color:S.bumpLeft?"#ef4444":"#475569",opacity:1,pulse:!!S.bumpLeft}),l.jsx(wd,{cx:p,cy:x,rInner:b-O,rOuter:y-O,startDeg:6,endDeg:70,color:S.bumpRight?"#ef4444":"#475569",opacity:1,pulse:!!S.bumpRight})]})]})}const Xd=tn.memo(aw);function sw({sensors:n,label:s,roverColor:r=null,status:o,audioStatus:u,levelStatus:f,layoutFormat:h="desktop",variant:p="default",driverLabel:x=null,showTopDown:g=!1,mobileHud:b=!1,mapPosition:y="top-center",turnTimerText:N=null,turnTimerFlashActive:M=!1,labelScale:k=1}){const S=b,w=h==="mobile-portrait",j=S?"text-[0.45rem]":"text-[0.65rem]",q=S?"px-0.25 py-0.25":"px-1 py-0.5",E=S?"px-0.25 py-0.25":"px-0.5 py-0.5",C=S?"text-[0.55rem]":"text-[0.8rem]",L=S?"left-0.5 top-0.5":"left-1 top-1",G=S?"text-[0.5rem]":"text-[0.7rem]",O=S?"px-0.5 py-0.25":"px-1 py-0.5",z=S?"left-0.5 top-1/2":"left-1 top-1/2",K="bottom-0.5",$={transform:`translateX(-50%) scale(${k})`,transformOrigin:"center bottom"},X="240px",P=w?.3:S?.33:.7,ie={width:X,height:X,opacity:S?.6:.7,transform:y==="top-center"?`translateX(-50%) scale(${P})`:`scale(${P})`,transformOrigin:y==="bottom-left"?"bottom left":y==="top-center"?"top center":"top right",...y==="bottom-left"?{left:"0.25rem",bottom:"0.25rem"}:y==="top-center"?{left:"50%",top:"0.25rem"}:{right:"0.25rem",top:"0.25rem"}};if(p==="none")return null;if(p==="spectator"){const V=[["Voltage",n?.voltageMv!=null?`${(n.voltageMv/1e3).toFixed(2)} V`:"--"],["Current",n?.currentMa!=null?`${n.currentMa} mA`:"--"],["Charge",n?.batteryChargeMah!=null?`${n.batteryChargeMah}`:"--"],["OI",n?.oiMode?.label||"--"]],T=!!n?.chargingSources?.homeBase,H=n?.chargingState?.label||"",J=!!(H&&H.toLowerCase()!=="not charging"),ne=n?.oiMode?.label||"Unknown",de=ne.toLowerCase(),R=de==="full"?"bg-emerald-500/80 text-emerald-50":de==="safe"?"bg-amber-400/80 text-amber-950":de==="passive"?"bg-slate-700/80 text-slate-100":"bg-slate-700/60 text-slate-200",_=T?"bg-emerald-500/80 text-emerald-50":"bg-slate-700/70 text-slate-200",Z=J?"bg-emerald-500/80 text-emerald-50":T?"bg-amber-400/80 text-amber-950":"bg-slate-700/70 text-slate-200";return l.jsxs(l.Fragment,{children:[l.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[l.jsx("div",{className:`absolute ${L} font-medium text-slate-100 ${j}`,children:l.jsxs("div",{className:"flex flex-col gap-0.5 leading-none",children:[l.jsxs("span",{children:["Status: ",o]}),u?l.jsxs("span",{children:["Audio: ",u]}):null,f?l.jsx("span",{className:"text-cyan-300",children:f}):null]})}),l.jsx("div",{className:`absolute ${z} flex -translate-y-1/2 flex-col gap-0.5 bg-black/70 text-slate-100 ${j} ${q}`,children:l.jsxs("div",{className:"space-y-0.5 leading-tight",children:[l.jsxs("div",{className:"flex flex-col gap-0.5 text-[0.75rem] font-semibold uppercase tracking-wide",children:[l.jsx("span",{className:`rounded px-1.5 py-0.5 ${_}`,children:T?"Docked":"Undocked"}),l.jsx("span",{className:`rounded px-1.5 py-0.5 ${Z}`,children:J?"Charging":"Not charging"}),l.jsxs("span",{className:`rounded px-1.5 py-0.5 ${R}`,children:["OI: ",ne]})]}),V.map(([ee,fe])=>l.jsxs("span",{className:"flex items-center justify-between gap-0.5",children:[l.jsx("span",{className:"text-slate-400",children:ee}),l.jsx("span",{className:"font-semibold text-white",children:fe})]},ee))]})}),l.jsx("div",{className:`absolute ${K} left-1/2`,style:$,children:l.jsxs("div",{className:`flex items-center gap-0.5 bg-black/80 text-slate-100 ${E} ${C}`,children:[l.jsx("span",{className:"font-semibold text-white rounded px-1 py-[1px] border border-transparent",style:da(r,.18),children:s||"Unnamed Rover"}),x?l.jsxs("span",{className:"text-slate-300",children:["• ",x]}):null]})})]}),g?l.jsx("div",{className:"pointer-events-none absolute rounded",style:{...ie},children:l.jsx(Xd,{sensors:n,size:240,overlay:!0})}):null]})}return l.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[l.jsx("div",{className:`absolute ${L} font-medium text-slate-100 ${j}`,children:l.jsxs("div",{className:"flex flex-col gap-0.5 leading-none",children:[l.jsxs("span",{children:["Status: ",o]}),u?l.jsxs("span",{children:["Audio: ",u]}):null,f?l.jsx("span",{className:"text-cyan-300",children:f}):null]})}),N?l.jsx("div",{className:`absolute bottom-1 left-1 rounded border ${M?"border-red-300/90 bg-red-900/80 text-red-100":"border-amber-300/80 bg-black/75 text-amber-200"} ${O} ${G}`,children:N}):null,l.jsx("div",{className:`absolute ${K} left-1/2`,style:$,children:l.jsx("div",{className:`flex gap-0.5 bg-black/80 text-slate-100 ${E} ${C}`,children:l.jsxs("span",{children:["Rover:"," ",l.jsxs("span",{className:"rounded px-1 py-[1px] border border-transparent",style:da(r,.18),children:['"',s||"Unnamed Rover",'"']})]})})}),g&&p!=="spectator"?l.jsx("div",{className:"pointer-events-none absolute rounded",style:{...ie},children:l.jsx(Xd,{sensors:n,size:240,overlay:!0})}):null]})}const lw=tn.memo(sw),fx=6e3,rw=700;function iw({description:n,variant:s="default",mobileHud:r=!1,displayKey:o=""}){const[u,f]=m.useState(!1),[h,p]=m.useState(!1);return m.useEffect(()=>{if(s!=="default"||!n){f(!1),p(!1);return}f(!0),p(!1);const x=setTimeout(()=>p(!0),fx),g=setTimeout(()=>f(!1),fx+rw);return()=>{clearTimeout(x),clearTimeout(g)}},[n,o,s]),n?s==="spectator"?l.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-1 z-50 flex justify-center",children:l.jsx("div",{className:"surface max-w-[92%] border border-slate-600/80 px-1 py-0.5 text-center text-[0.62rem] leading-tight text-slate-100 shadow-lg",children:n})}):s!=="default"||!u?null:l.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-2 z-50 flex justify-center",children:l.jsxs("div",{className:`surface max-w-[94%] border border-slate-500/85 px-2 py-1 text-center font-semibold text-slate-100 shadow-2xl transition-opacity duration-700 ${h?"opacity-0":"opacity-100"} ${r?"text-[1rem] leading-tight":"text-[1.5rem] leading-tight"}`,children:[l.jsx("p",{children:"Just so you know, this rover"}),n]})}):null}const mx=2e3,ow=3e3,cw=3e3,uw=40,dw=1e3,fw={leftWheel:"Left wheel",rightWheel:"Right wheel",mainBrush:"Main brush",sideBrush:"Side brush",limiter:"Overcurrent limit"};function mw({motors:n,fill:s=0,compact:r=!1}){if(!n?.length)return null;const o=n.map(b=>fw[b]||b),u=r?"w-[12rem] h-[3.5rem]":"w-[20rem] h-[7rem]",f=r?"px-2 py-1":"px-4 py-2",h=r?"text-lg":"text-4xl",p=r?"text-xs":"text-xl",x=Math.max(0,Math.min(1,s)),g=`${Math.round(x*100)}%`;return l.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 ${u}`,children:l.jsxs("div",{className:"relative h-full w-full",children:[l.jsx("div",{className:"absolute inset-0 overflow-hidden",children:l.jsx("div",{className:"h-full bg-red-700/60",style:{width:g}})}),l.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} ${f}`,children:[l.jsx("div",{children:"OVERCURRENT"}),l.jsx("div",{className:`mt-0 font-medium text-white ${p}`,children:o.join(", ")})]})]})})}const hw=tn.memo(mw);function pw({battery:n,compact:s=!1}){if(!n?.available||!n.warnActive&&!n.urgentActive)return null;const r=n.urgentActive?"BATTERY VERY LOW, DOCK THE ROVER AND CHARGE IMMEDIATELY!!":"Battery low! please dock and charge the rover soon.",o=s?"p-2 top-6":"p-4 top-10",u=s?"text-sm":"text-2xl";return l.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:l.jsx("div",{className:`text-center font-semibold text-white animate-pulse ${u}`,children:l.jsx("div",{children:r})})})}const xw=tn.memo(pw);function gw({sensors:n}){const s=[n?.lightBumpLeftSignal,n?.lightBumpFrontLeftSignal,n?.lightBumpCenterLeftSignal,n?.lightBumpCenterRightSignal,n?.lightBumpFrontRightSignal,n?.lightBumpRightSignal],r=s.filter(p=>p!=null).reduce((p,x)=>Math.max(p,x),1200),o=p=>Math.pow(Math.max(0,Math.min(1,(p??0)/r)),.35),u=p=>p==null||p<=0?"hsl(200 60% 18%)":`hsl(${(200+o(p)*360)%360} 100% 60%)`,f=6,h=12;return l.jsx("div",{className:"flex w-full items-center justify-center gap-0.5",children:s.map((p,x)=>{const g=o(p),b=xz.session?.role||null),r=pe(z=>z.session?.assignment?.roverId||null),o=pe(z=>z.session?.roster||[]),{sendMessage:u,onInputFocus:f,onInputBlur:h,blurChat:p,registerInputRef:x,setTypingActive:g}=pf(),{value:b}=Xe("tts",{engine:"flite",voice:"rms",pitch:50}),[y,N]=m.useState(""),[M,k]=m.useState(!1),S=s!=="spectator",w=s==="spectator",q=!!m.useMemo(()=>o.find(z=>String(z.id)===String(r))||null,[r,o])?.audio?.ttsEnabled,E=m.useMemo(()=>{if(!q)return null;const z=b?.engine==="espeak"?"espeak":"flite";if(z==="espeak"){let $=Number.isFinite(b?.pitch)?Math.round(b.pitch):void 0;return typeof $=="number"&&($=Math.max(0,Math.min(99,$))),{speak:!0,engine:z,pitch:$}}const K=typeof b?.voice=="string"?b.voice:void 0;return{speak:!0,engine:z,voice:K}},[b?.engine,b?.pitch,b?.voice,q]),C=n?"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",L=n?"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",G=n?"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(z){if(z.preventDefault(),!S)return;const K=y.trim();if(K){k(!0);try{await u(K,E),N(""),p(),g(!1)}catch($){alert($.message)}finally{k(!1)}}}return w?null:l.jsxs("form",{onSubmit:O,className:C,children:[l.jsx("input",{className:L,value:y,onChange:z=>{const K=z.target.value;N(K),g(!!K.trim())},onFocus:z=>{f(z),g(!!y.trim())},onBlur:z=>{h(z),g(!1)},onKeyDown:z=>{z.key==="Enter"&&!y.trim()&&(z.preventDefault(),p(),g(!1))},ref:z=>x(z,{target:"hud"}),placeholder:S?"Chat (TTS)":"Spectator",disabled:!S}),l.jsx("button",{type:"submit",disabled:!S||M,className:G,children:"Speak"})]})}const yw=m.memo(vw);function kr({sessionInfo:n,audioSessionInfo:s,videoMode:r="whep",snapshotFeed:o=null,qualityNotice:u=null,label:f,roverDescription:h=null,roverColor:p=null,forceMute:x=!1,telemetryFrame:g,batteryConfig:b,layoutFormat:y="desktop",hudVariant:N="default",driverLabel:M=null,hudForceMap:k=!1,hudMapPosition:S="top-center",hudLabelScale:w=1,fitParent:j=!1,overcurrentLimiter:q=null,showTurnCue:E=!1,turnTimerText:C=null,isActiveDriver:L=!1,idleSkipSeconds:G=null,showNotTurnNotice:O=!1,notTurnCountdownText:z=null,showPreviewReason:K=!1,notTurnFlashAt:$=0}){const X=pe(xe=>(xe.session?.socials||[]).find(Ee=>String(Ee?.id||Ee?.label||"").toLowerCase()==="discord")?.url||null||xe.session?.discord?.invite||null),P=m.useRef(null),oe=m.useRef(null),ie=m.useRef(null),V=m.useRef(null),T=m.useRef(null),H=m.useRef(null),J=m.useRef(null),ne=m.useRef(null),[de,R]=m.useState("idle"),[_,Z]=m.useState(null),[ee,fe]=m.useState("idle"),[ce,ue]=m.useState(null),[je,ve]=m.useState(0),[ye,Qe]=m.useState(0),[Ie,Re]=m.useState(!0),[Te,He]=m.useState(!1),dt=!!s?.url,le=r==="snapshot",se=g?.sensors,{value:be}=Xe("audio",ct),he=Number.isFinite(be?.masterVolume)?be.masterVolume:ct.masterVolume,Ce=Number.isFinite(be?.roverVolume)?be.roverVolume:ct.roverVolume,we=typeof be?.mainBrushDuckEnabled=="boolean"?be.mainBrushDuckEnabled:typeof be?.autoLevelEnabled=="boolean"?be.autoLevelEnabled:ct.mainBrushDuckEnabled,Ze=Number.isFinite(be?.mainBrushDuckAmount)?Math.max(0,Math.min(1,be.mainBrushDuckAmount)):ct.mainBrushDuckAmount,re=Math.max(0,Math.min(1,he*Ce)),me=se?.batteryChargeMah??null,at=!(y==="desktop"),Tt=at?"top-right":S,[pl]=$g(),an=k||at?!0:pl,ma=Gg({charge:me,config:b}),Ua=se?.wheelOvercurrents||null,Cn=m.useMemo(()=>Ua==null?[]:Object.entries(Ua).filter(([,xe])=>!!xe).map(([xe])=>xe),[Ua]),ft=q?.caps||null,bn=q?.overcurrent?.groups||null,Dt=m.useMemo(()=>{if(typeof window>"u")return{debugAudio:!1,debugHud:!1};const xe=new URLSearchParams(window.location.search);return{debugAudio:xe.has("debugAudio"),debugHud:xe.has("debugHud")}},[]),zr=Dt.debugAudio,xl=Dt.debugHud,Ur=m.useMemo(()=>{if(!ft)return null;const xe=Number.isFinite(ft?.drive?.cap)?ft.drive.cap:1,ke=Number.isFinite(ft?.aux?.cap)?ft.aux.cap:1;return Math.max(0,Math.min(1,1-Math.min(xe,ke)))},[ft]),On=!!q?.isActive,Lt=m.useMemo(()=>{const xe=Cn.length?Cn:On?["limiter"]:[],ke=Ur??(Cn.length?1:0);return{motors:xe,fill:ke,visible:!!xe.length}},[Cn,On,Ur]),vn=!!((Number(se?.mainBrushCurrentMa)||0)>uw||se?.wheelOvercurrents?.mainBrush),Bn=we&&vn?1-Ze:1,Ln=Math.max(0,Math.min(1,re*Bn)),Ha=we&&vn&&Ze>0?`Volume decreased ${Math.round(Ze*1e3)/10}%`:null,Hr=m.useRef({hasDedicatedAudio:!1,audioUrl:null,mainBrushDuckEnabled:!1,mainBrushDuckAmount:0,mainBrushActive:!1,baseRoverGain:0,effectiveRoverGain:0});m.useEffect(()=>{Hr.current={hasDedicatedAudio:dt,audioUrl:s?.url||null,mainBrushDuckEnabled:we,mainBrushDuckAmount:Ze,mainBrushActive:vn,baseRoverGain:re,effectiveRoverGain:Ln}},[dt,s?.url,we,Ze,vn,re,Ln]);const rt=m.useCallback((xe,ke={})=>{if(!zr)return;const _e=oe.current,Ee=Hr.current,Ge={event:xe,ts:Date.now(),roverLabel:f||null,hasDedicatedAudio:Ee.hasDedicatedAudio,audioUrl:Ee.audioUrl,mainBrushDuckEnabled:Ee.mainBrushDuckEnabled,mainBrushDuckAmount:Ee.mainBrushDuckAmount,mainBrushActive:Ee.mainBrushActive,baseRoverGain:Ee.baseRoverGain,effectiveRoverGain:Ee.effectiveRoverGain,element:_e?{muted:_e.muted,volume:_e.volume,paused:_e.paused,ended:_e.ended,readyState:_e.readyState,networkState:_e.networkState}:null,...ke};try{console.log(`[AudioDebug] ${xe} ${JSON.stringify(Ge)}`)}catch{console.log("[AudioDebug]",xe,Ge)}},[zr,f]);m.useEffect(()=>{xl&&console.log("[OvercurrentHUD]",{overlayVisible:Lt.visible,overlayMotors:Lt.motors,overlayFill:Lt.fill,limiterActive:On,limiterCaps:ft,limiterGroups:bn,wheelOvercurrents:Ua})},[xl,Lt,On,ft,bn,Ua]),m.useEffect(()=>{rt("settings/update")},[rt]);const zn=m.useCallback(()=>{clearTimeout(ie.current),ie.current=setTimeout(()=>ve(Date.now()),mx)},[]),Un=m.useCallback(()=>{clearTimeout(V.current),V.current=setTimeout(()=>Qe(Date.now()),mx)},[]),hs=m.useCallback(async()=>{const xe=P.current;if(xe)try{xe.muted=!0,await xe.play()}catch{}},[]),gl=m.useCallback((xe=0)=>{if(x||dt)return;clearTimeout(H.current);const ke=()=>{clearTimeout(H.current),H.current=setTimeout(()=>{x||_e()},ow)},_e=async()=>{const Ee=P.current;if(Ee)try{await hs(),Ee.muted=!1,await Ee.play(),Re(!1)}catch{Ee.muted=!0,Re(!0),ke()}};H.current=setTimeout(_e,xe)},[hs,x,dt]);m.useEffect(()=>()=>{clearTimeout(ie.current),clearTimeout(V.current),clearTimeout(H.current),clearInterval(T.current),J.current&&(cancelAnimationFrame(J.current),J.current=null)},[]),m.useEffect(()=>{if(!O||!$)return;He(!0);const xe=setTimeout(()=>He(!1),650);return()=>clearTimeout(xe)},[O,$]),m.useEffect(()=>{de==="playing"&&gl(0)},[de,gl]),m.useEffect(()=>{le&&(R("snapshot"),Z(null))},[le]),m.useEffect(()=>{if(le||!n?.url||!P.current)return;let xe=!0,ke;const _e=setTimeout(()=>Re(!0),0),Ee=(Ge,_t)=>{xe&&(rt("video/status",{nextStatus:Ge,info:_t||null}),R(Ge),Z(_t||null),Ge==="playing"&&hs(),["error","failed","disconnected","closed"].includes(Ge)&&zn())};return ke=new ux({url:n.url,token:n.token,video:P.current,receiveAudio:!dt,onStatus:Ee}),ke.start().catch(Ge=>{xe&&(R("error"),Z(Ge.message),zn())}),()=>{xe=!1,clearTimeout(_e),ke?.stop()}},[le,n?.url,n?.token,je,zn,hs,dt,rt]),m.useEffect(()=>{de==="stopped"&&n?.url&&zn()},[de,n?.url,zn]),m.useEffect(()=>{const xe=oe.current;if(!xe||!s?.url){rt("route/no-audio-url"),ne.current=null;return}const ke=Math.max(0,Math.min(1,Ln)),_e=ne.current==null?Math.max(0,Math.min(1,xe.volume)):ne.current;if(J.current&&(cancelAnimationFrame(J.current),J.current=null),ke>_e){const Ee=performance.now(),Ge=_e,_t=ke-Ge,Va=$a=>{const ot=Math.min(1,($a-Ee)/dw),Hn=Ge+_t*ot;xe.volume=Hn,ne.current=Hn,ot<1?J.current=requestAnimationFrame(Va):J.current=null};J.current=requestAnimationFrame(Va)}else xe.volume=ke,ne.current=ke;rt("route/direct",{elementVolume:ke,duckEnabled:we,mainBrushActive:vn,duckAmount:Ze})},[s?.url,Ln,we,vn,Ze,rt]),m.useEffect(()=>{if(!s?.url||!oe.current)return;let xe=!0,ke;const _e=(Ee,Ge)=>{xe&&(rt("audio/status",{nextStatus:Ee,info:Ge||null}),ue(Ge||(Ee==="connected"?"connected":null)),fe(_t=>Ee==="connected"&&(_t==="playing"||_t==="connecting")||Ee==="new"?_t:Ee),["error","failed"].includes(Ee)&&Un())};return ke=new ux({url:s.url,token:s.token,video:oe.current,audioOnly:!0,onStatus:_e}),ke.start().catch(Ee=>{xe&&(fe("error"),ue(Ee.message),Un())}),()=>{xe=!1,ke?.stop()}},[s?.url,s?.token,ye,Un,rt]),m.useEffect(()=>{const xe=oe.current;if(!s?.url||!xe){clearInterval(T.current);return}if(!["connecting","connected","playing","paused"].includes(ee)){clearInterval(T.current);return}const _e=async()=>{const Ee=oe.current;Ee&&(Ee.muted=!1,!(!Ee.paused&&!Ee.ended)&&(rt("retry/play-attempt"),Ee.play().then(()=>{rt("retry/play-ok"),fe(Ge=>Ge==="connected"?"playing":Ge),ue(Ge=>Ge==="paused"?null:Ge)}).catch(Ge=>{rt("retry/play-fail",{error:Ge?.message}),ue(_t=>_t||Ge?.message||"autoplay blocked")})))};return _e(),T.current=setInterval(_e,cw),()=>clearInterval(T.current)},[s?.url,ee,rt]),m.useEffect(()=>{const xe=oe.current;if(!xe)return;const ke=()=>{rt("element/play"),fe(ot=>ot==="error"?ot:"playing"),ue(null)},_e=()=>{rt("element/pause"),fe(ot=>["error","failed","disconnected","closed","stopped"].includes(ot)?ot:"paused"),ue(ot=>ot||"paused")},Ee=()=>{rt("element/ended"),fe(ot=>ot==="error"?ot:"stopped"),ue(ot=>ot||"ended")},Ge=()=>{const{error:ot}=xe,Hn=ot?.message||"audio error";rt("element/error",{error:Hn}),fe("error"),ue(Hn)},_t=()=>rt("element/waiting"),Va=()=>rt("element/canplay"),$a=()=>rt("element/stalled");return xe.addEventListener("play",ke),xe.addEventListener("pause",_e),xe.addEventListener("ended",Ee),xe.addEventListener("error",Ge),xe.addEventListener("waiting",_t),xe.addEventListener("canplay",Va),xe.addEventListener("stalled",$a),()=>{xe.removeEventListener("play",ke),xe.removeEventListener("pause",_e),xe.removeEventListener("ended",Ee),xe.removeEventListener("error",Ge),xe.removeEventListener("waiting",_t),xe.removeEventListener("canplay",Va),xe.removeEventListener("stalled",$a)}},[s?.url,rt]);const Vr=o?.error?`Error: ${o.error}`:o?.objectUrl?"snapshot":o?.status||"waiting",$r=le?Vr:n?.url?de==="error"?`Error: ${_||"unknown"}`:_?`${de} (${_})`:de:"waiting",bl=s?.error?`Error: ${s.error}`:s?.url?ee==="error"?`Error: ${ce||"unknown"}`:ce?`${ee} (${ce})`:ee:null,ps=N==="spectator",zt=N==="none",Gr=`${f||""}::${h||""}`;return l.jsxs("div",{className:`flex flex-col gap-0.5 ${j?"h-full":""}`,children:[l.jsxs("div",{className:`relative w-full overflow-hidden bg-black ${j?"h-full flex-1":"aspect-[4/3]"}`,children:[le?o?.objectUrl?l.jsx("img",{src:o.objectUrl,alt:f,className:"h-full w-full object-contain",draggable:!1}):l.jsx("div",{className:"flex h-full w-full items-center justify-center text-sm text-slate-300",children:"Waiting for frame…"}):l.jsx("video",{ref:P,muted:x||Ie||dt,playsInline:!0,autoPlay:!0,controls:!1,className:"h-full w-full object-contain"}),l.jsx("audio",{ref:oe,autoPlay:!0,hidden:!0}),!zt&&E?l.jsx(IN,{mobileHud:at,isActiveDriver:L,idleSkipSeconds:G}):null,zt?null:l.jsx(iw,{description:h,variant:N,mobileHud:at,displayKey:Gr}),zt?null:l.jsx(lw,{sensors:se,label:f,roverColor:p,status:$r,audioStatus:bl,levelStatus:Ha,layoutFormat:y,variant:N,driverLabel:M,showTopDown:an,mobileHud:at,mapPosition:Tt,turnTimerText:C,turnTimerFlashActive:Te,labelScale:w}),zt?null:l.jsx(yw,{compact:at}),!zt&&xl?l.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:${Lt.visible?1:0} motors:${Lt.motors.length} fill:${Math.round(Lt.fill*100)}%`}):null,zt?null:l.jsx(hw,{motors:Lt.motors,fill:Lt.fill,compact:at}),zt?null:l.jsx(xw,{battery:ma,compact:at}),!zt&&ps&&ma.available?l.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:l.jsx(Yd,{visual:ma,orientation:"vertical",variant:"inline",compact:at,className:"h-full w-4"})}):null,!zt&&u?l.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-1/2 -translate-y-1/2",children:l.jsxs("div",{className:`mx-auto w-fit rounded border border-amber-300/80 bg-black/75 text-amber-200 ${at?"px-2 py-1 text-[0.6rem]":"px-3 py-1.5 text-sm"}`,children:[l.jsx("div",{className:"text-center",children:u}),l.jsx("div",{className:"pointer-events-auto mt-0",children:l.jsx(Ar,{id:"discord",label:"Join our Discord server while you wait!",url:X})})]})}):null,!zt&&O?l.jsx("div",{className:"pointer-events-none absolute bottom-1 left-1 z-40",children:l.jsxs("div",{className:`w-fit rounded border ${Te?"border-red-300/90 bg-red-900/80 text-red-100":"border-amber-300/80 bg-black/75 text-amber-200"} ${at?"px-2 py-1 text-[0.6rem]":"px-3 py-1.5 text-sm"}`,children:[l.jsx("div",{className:Te?"text-[0.82rem] font-semibold text-red-50":"text-[0.82rem] font-semibold text-white",children:"Not your turn to drive!"}),z?l.jsx("div",{className:Te?"text-red-100/95":"text-amber-100",children:z}):null,K?l.jsx("div",{className:Te?"text-red-100/90":"text-amber-200/85",children:"Video switched to preview mode to save bandwidth."}):null,l.jsx("div",{className:"pointer-events-auto mt-0.5",children:l.jsx(Ar,{id:"discord",label:"Join our Discord while you wait!",url:X})})]})}):null]}),!zt&&!ps&&l.jsxs("div",{className:"space-y-0.5",children:[l.jsx(bw,{sensors:se}),l.jsx("div",{className:"panel-section space-y-0.5 text-sm",children:l.jsx(Yd,{visual:ma,compact:at})})]})]})}function Sw(n=[]){const s=new Set;return n.forEach(r=>{if(String(r?.role||"")==="spectator")return;const u=String(r?.roverId||"").trim(),f=String(r?.socketId||"").trim();!u||!f||s.add(f)}),s.size}function jf({layoutFormat:n="desktop"}){const s=pe(se=>se.session?.mode||null),r=pe(se=>se.session?.assignment?.roverId??null),o=pe(se=>se.session?.roster??[]),u=pe(se=>se.session?.users??[]),f=pe(se=>se.session?.turnQueues??{}),h=pe(se=>se.session?.socketId||null),p=pe(se=>se.session?.activeDrivers??{}),{state:{song:x,lastControlIntentAt:g},overcurrentLimiter:b}=Ct(),[y,N]=m.useState(()=>Date.now()),[M,k]=m.useState(!1),[S,w]=m.useState(null),[j,q]=m.useState(0),E=m.useRef({initialized:!1,roverId:null,activeDriverId:null}),C=m.useRef(g||0);m.useEffect(()=>{if(s!=="turns")return;const se=setInterval(()=>N(Date.now()),250);return()=>clearInterval(se)},[s]);const G=!!(r&&o?o.find(se=>String(se.id)===String(r)):null)?.media?.audioPublishUrl,O=r?f?.[r]:null,z=r?p?.[r]:null,K=!!(h&&z===h),$=m.useMemo(()=>{const se=O?.queue||[];if(!se.length||!O?.current||se.length<=1)return null;const be=se.findIndex(he=>he===O.current);return be===-1?se[0]||null:se[(be+1)%se.length]||null},[O?.queue,O?.current]),X=!!(h&&$===h),P=O?.deadline||null,oe=O?.idleDeadline||null,ie=P?P-y:null,V=oe?oe-y:null,T=s==="turns",H=o.length,J=m.useMemo(()=>Sw(u),[u]),ne=T&&J>H,de=T&&X&&ie!=null&&ie<=5e3&&ie>0,R=T&&!K,_=R&&!de&&ne,Z=!_,ee=ie!=null&&Number.isFinite(ie)?Math.max(0,Math.ceil(ie/1e3)):null,fe=V!=null&&Number.isFinite(V)?Math.max(0,Math.ceil(V/1e3)):null,ce=m.useMemo(()=>!T||!K?null:ee!=null?`${ee}s left`:"Your turn",[T,K,ee]),ue=m.useMemo(()=>!R||!X||ee==null?null:`${ee} seconds until your turn.`,[R,X,ee]),je=r?[...Z?[{type:"rover",id:r,key:r}]:[],...G?[{type:"rover",id:`${r}-audio`,key:`${r}-audio`}]:[]]:[],ve=wr(je),ye=r&&Z?ve[r]:null,Qe=r&&G?ve[`${r}-audio`]:null,Ie=yf(r?[r]:[],{enabled:!!r,version:s}),Re=r&&Ie[r]||null,Te=hl(r),He=r&&o?o.find(se=>String(se.id)===String(r)):null,dt=He?.battery??null,le=He?.name||(r?`Rover ${r}`:"");return m.useEffect(()=>{if(s!=="turns"){k(!1),w(null),E.current={initialized:!1,roverId:null,activeDriverId:null};return}const se=E.current,be=z||null;if(!h||!r){k(!1),w(null),E.current={initialized:!1,roverId:null,activeDriverId:null};return}if(!se.initialized||se.roverId!==r){E.current={initialized:!0,roverId:r,activeDriverId:be};return}!!se.activeDriverId&&se.activeDriverId!==h&&be===h?(k(!0),w(Date.now())):be!==h&&M&&(k(!1),w(null)),E.current={initialized:!0,roverId:r,activeDriverId:be}},[z,s,r,h,M]),m.useEffect(()=>{!M||!S||g>S&&k(!1)},[g,S,M]),m.useEffect(()=>{const se=Number(C.current)||0,be=Number(g)||0;be>se&&R&&q(Date.now()),C.current=be},[R,g]),l.jsx("section",{className:"panel",children:r?l.jsx(kr,{sessionInfo:ye,videoMode:Z?"whep":"snapshot",snapshotFeed:Re,audioSessionInfo:Qe,label:le,roverDescription:He?.description,roverColor:He?.color||null,telemetryFrame:Te,batteryConfig:dt,layoutFormat:n,overcurrentLimiter:b,songNote:x?.note,qualityNotice:null,showTurnCue:M,turnTimerText:ce,turnSeconds:ee,isActiveDriver:K,idleSkipSeconds:fe,showNotTurnNotice:R,notTurnCountdownText:ue,showPreviewReason:_,notTurnFlashAt:j}):l.jsxs("div",{className:"panel-muted content-center text-center text-sm text-slate-400 aspect-[4/3]",children:[l.jsx("p",{children:"You are not assigned to a rover."}),l.jsx("p",{className:"mt-0",children:l.jsx("a",{href:"/spectate",className:"text-blue-400 underline hover:text-blue-500",children:"Click here to visit the spectator page."})})]})})}function qo({label:n,tone:s="muted"}){const r=s==="success"?"bg-emerald-900 text-emerald-100":s==="warn"?"bg-amber-900 text-amber-100":"bg-slate-800 text-slate-200";return l.jsx("span",{className:`rounded px-1 py-0.5 text-xs font-semibold leading-none ${r}`,children:n})}function Ho(n){if(!Number.isFinite(n))return 0;const s=n%360;return s<0?s+360:s}function jw(n){if(!Array.isArray(n)||n.length<3)return 0;const[s,r,o]=n,u=Math.max(0,Math.min(255,Number(s)))/255,f=Math.max(0,Math.min(255,Number(r)))/255,h=Math.max(0,Math.min(255,Number(o)))/255,p=Math.max(u,f,h),x=Math.min(u,f,h),g=p-x;if(g===0)return 0;let b=0;return p===u?b=(f-h)/g%6:p===f?b=(h-u)/g+2:b=(u-f)/g+4,Ho(Math.round(b*60))}function hx(n){const s=Ho(n),r=1,o=1-Math.abs(s/60%2-1);let u=0,f=0,h=0;return s<60?(u=r,f=o):s<120?(u=o,f=r):s<180?(f=r,h=o):s<240?(f=o,h=r):s<300?(u=o,h=r):(u=r,h=o),[Math.round(u*255),Math.round(f*255),Math.round(h*255)]}function px(n){return n?Array.isArray(n.hsColor)?Ho(Number(n.hsColor[0])):Array.isArray(n.rgbColor)?jw(n.rgbColor):0:0}function Nw({entity:n,connected:s,controlsLocked:r,onToggle:o,onSetColor:u,onSetWhite:f}){const h=n.state==="unavailable"||!n.available,p=n.state==="on",x=n.type==="light"&&n.supportsColor,g=h?"warn":p?"success":"muted",b=h?"Unavailable":p?"On":"Off",y=r||!s||h,N=y||!x,[M,k]=m.useState(()=>px(n)),S=m.useRef(M),w=m.useRef(!1),j=h?"border-slate-800 bg-slate-900 text-slate-400 cursor-not-allowed":r?"border-slate-800 bg-slate-900 text-slate-300 cursor-not-allowed":p?"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(!x||w.current)return;const z=px(n);S.current=z,k(z)},[n.rgbColor,n.hsColor,x]);const q=z=>{const K=Ho(Number(z.target.value));S.current=K,k(K)},E=()=>{N||!u||u(n.id,hx(S.current))},C=z=>{z.stopPropagation()},L=z=>{C(z),!(N||!f)&&f(n.id)},O=`rgb(${(x?hx(S.current):[255,255,255]).join(",")})`;return l.jsxs("button",{type:"button",onClick:()=>o(n.id),disabled:y,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 ${j} disabled:opacity-60 disabled:hover:bg-inherit`,children:[l.jsxs("div",{className:"min-w-0 flex-1",children:[l.jsxs("div",{className:"flex items-center gap-0.5 text-sm leading-normal",children:[l.jsx("span",{className:"truncate font-semibold text-white",children:n.name||n.id}),x&&l.jsxs(l.Fragment,{children:[l.jsx(qo,{label:b,tone:g}),!s&&l.jsx("span",{className:"text-xs text-amber-200",children:"Offline"})]})]}),x?l.jsx("div",{className:"-mt-0.5 w-full",onClick:C,onPointerDown:z=>{C(z),w.current=!0},onPointerUp:z=>{C(z),w.current=!1,E()},onPointerCancel:z=>{C(z),w.current=!1,E()},onKeyUp:z=>{C(z),E()},onBlur:E,children:l.jsx("div",{className:"relative w-full",children:l.jsx("input",{type:"range",min:"0",max:"360",step:"1",value:M,onChange:q,disabled:N,"aria-label":`Set color for ${n.name||n.id}`,className:"ha-hue-slider w-full"})})}):l.jsxs("div",{className:"flex items-center gap-0.5 text-xs text-slate-400",children:[l.jsx(qo,{label:b,tone:g}),!s&&l.jsx("span",{className:"text-amber-200",children:" · Offline"})]})]}),x&&l.jsxs("div",{className:"absolute right-1 top-1 flex items-center gap-0.5",children:[l.jsx("span",{role:"button",tabIndex:N?-1:0,onClick:L,onPointerDown:C,onKeyDown:z=>{N||(z.key==="Enter"||z.key===" ")&&(z.preventDefault(),L(z))},title:"Set white color temperature","aria-label":`Set ${n.name||n.id} to white`,"aria-disabled":N,className:`inline-flex items-center justify-center rounded border border-slate-200 bg-white px-1 py-0.5 text-xs font-semibold leading-none text-slate-900 ${N?"cursor-not-allowed opacity-60":"cursor-pointer hover:bg-slate-100"}`,children:"white"}),l.jsx("span",{className:"pointer-events-none h-2.5 w-2.5 rounded-full border border-white/60",style:{backgroundColor:O}})]}),!x&&l.jsx("div",{className:"self-center text-xs font-semibold text-white/90",children:p?"Turn off":"Turn on"})]})}function Yg(){const{state:{keymap:n}}=Ct(),s=pe(N=>N.session?.homeAssistant||null),{homeAssistantToggle:r,homeAssistantSetLightColor:o,homeAssistantSetLightWhite:u}=Yt(),f=m.useMemo(()=>s?.entities||[],[s?.entities]),h=s?.lightPolicy||null,p=!!(h?.locked||h?.lockedOn),x=h?.lockState||(h?.lockedOn?"on":null),g=qt(n?.homeAssistantOn?.[0]),b=qt(n?.homeAssistantOff?.[0]);if(!s?.enabled)return l.jsxs("section",{className:"panel-section space-y-0.5 text-sm text-slate-400",children:[l.jsx("p",{className:"text-slate-300",children:"Room Controls"}),l.jsx("p",{className:"text-slate-500",children:"Not configured on the server."})]});if(f.length===0)return l.jsxs("section",{className:"panel-section space-y-0.5 text-sm text-slate-400",children:[l.jsx("p",{className:"text-slate-300",children:"Room Controls"}),l.jsx("p",{className:"text-slate-500",children:"No lights or switches configured."})]});const y=!!s?.connected;return l.jsxs("section",{className:"panel-section space-y-0.5 text-base",children:[l.jsxs("header",{className:"flex items-center justify-between gap-0.5 text-sm text-slate-400",children:[l.jsxs("div",{className:"flex items-center gap-0.5",children:[l.jsx("p",{children:"Room Controls"}),l.jsx("span",{className:"text-xs text-slate-500",children:f.length}),p?l.jsx(qo,{label:x==="off"?"Locked Off":"Locked On",tone:"warn"}):null,l.jsxs("div",{className:"flex items-center gap-0.5 text-xs text-slate-300 background-black",children:[l.jsxs("span",{className:"flex items-center gap-0.5",children:[l.jsx("span",{children:"On"}),g?l.jsx(xx,{label:g}):null]}),l.jsxs("span",{className:"flex items-center gap-0.5",children:[l.jsx("span",{children:"Off"}),b?l.jsx(xx,{label:b}):null]})]})]}),l.jsx(qo,{label:y?"Connected":"Offline",tone:y?"success":"warn"})]}),p?l.jsx("p",{className:"rounded border border-amber-600/60 bg-amber-900/40 px-1 py-0.5 text-xs text-amber-100",children:x==="off"?"Lights are locked off. Room controls are disabled.":"Lights are locked on. Room controls are disabled."}):null,l.jsx("div",{className:"flex flex-wrap gap-0.5",children:f.map(N=>l.jsx(Nw,{entity:N,connected:y,controlsLocked:p,onToggle:r,onSetColor:o,onSetWhite:u},N.id))})]})}function xx({label:n}){return n?l.jsx("span",{className:"rounded border border-white/40 px-1 text-[0.7rem] text-white",children:n}):null}function Xg(){const{login:n,setRole:s}=Yt(),[r,o]=m.useState(""),[u,f]=m.useState(""),[h,p]=m.useState(!1);async function x(g){g.preventDefault(),p(!0);try{await n(r,u),o(""),f("")}catch(b){alert(b.message)}finally{p(!1)}}return l.jsxs("div",{className:"panel-section space-y-0.5 text-base",children:[l.jsx("p",{className:"text-sm text-slate-400",children:"Admin login"}),l.jsxs("form",{className:"flex flex-col gap-0.5",onSubmit:x,children:[l.jsx("input",{className:"field-input",placeholder:"Username",value:r,onChange:g=>o(g.target.value)}),l.jsx("input",{className:"field-input",placeholder:"Password",type:"password",value:u,onChange:g=>f(g.target.value)}),l.jsx("button",{type:"submit",disabled:h,className:"button-dark w-full disabled:opacity-50",children:h?"Logging in…":"Login"})]})]})}function gx(...n){return n.filter(Boolean).join(" ")}function ww(n){const s=n?.batteryState?.percentDisplay;return s==null?"--":`${s}%`}function Aw(n){return n?.batteryState?n.batteryState.urgentActive?"text-red-400":n.batteryState.warnActive?"text-amber-300":"text-emerald-300":"text-slate-400"}function Cw({title:n,roster:s=[],emptyText:r="No roster data.",renderActions:o=null}){return l.jsxs("div",{className:"space-y-0.5 text-sm",children:[n&&l.jsx("p",{className:"text-sm text-slate-400",children:n}),s.length===0?l.jsx("p",{className:"text-sm text-slate-500",children:r}):l.jsx("ul",{className:"space-y-0.5 text-sm",children:s.map(u=>{const f=!!(u?.private?.enabled&&u?.private?.open),h=!!u?.locked;return l.jsxs("li",{className:gx("surface flex flex-wrap items-center justify-between gap-0.5",h?"bg-red-900/40":f?"bg-amber-700/35 border border-amber-200/30":null),children:[l.jsxs("div",{children:[l.jsx("p",{className:"text-slate-200",children:l.jsx("span",{className:"rounded px-1 py-[1px] border border-transparent",style:da(u.color,.16),children:u.name})}),l.jsxs("p",{className:"text-xs text-slate-500 flex flex-wrap items-center gap-0.5",children:[l.jsx("span",{children:u.locked?"locked":"free"}),u.lockReason&&l.jsx("span",{className:"rounded bg-black/30 px-1",children:u.lockReason}),l.jsxs("span",{className:gx("font-semibold",Aw(u)),children:["Battery ",ww(u)]})]})]}),o?o(u):null]},u.id)})})]})}function kw(n){const s=n?.runtime||{},r=n?.output||{},o=n?.errors||{};return s.inFlight?{label:"IN FLIGHT",detail:s.reason||"Generating commentary now",className:"border-amber-400/60 bg-amber-700/20 text-amber-200"}:s.outcome==="posted"?{label:"POSTED",detail:r.posted?`Last: ${r.posted}`:"Commentary posted",className:"border-emerald-400/60 bg-emerald-700/20 text-emerald-200"}:s.outcome==="skipped"?{label:"SKIPPED",detail:s.reason||"Model chose to skip",className:"border-slate-400/60 bg-slate-700/30 text-slate-200"}:s.outcome==="failed"?{label:"FAILED",detail:o.message||s.reason||"Tick failed",className:"border-red-400/60 bg-red-700/20 text-red-200"}:{label:s.running?"IDLE":"STOPPED",detail:s.reason||"Waiting for next tick",className:"border-sky-400/50 bg-sky-700/20 text-sky-200"}}function Ew(n,s){const r=Date.now(),u=(Array.isArray(n)?n:[]).map((f,h)=>{const p=String(f?.role||"").toLowerCase(),x=typeof f?.content=="string"?f.content:JSON.stringify(f?.content??null,null,2),g=p==="system"?"LLM System":p==="assistant"?"LLM Context":p==="user"?"LLM Input":"LLM Message";return{id:`llm-msg-${h}`,message:{ts:r+h,nickname:g,text:x,role:"spectator",system:p==="system"}}});if(s!=null){const f=String(s);u.push({id:"llm-output",message:{ts:r+u.length+1,nickname:"LLM Output",text:f.trim()?f:"",role:"spectator",system:!0}})}return u}function Mw({state:n,onClearHistory:s,clearingHistory:r}){const[o,u]=m.useState(null);if(!n)return l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),l.jsx("div",{className:"surface text-xs text-slate-300",children:"No status received yet."})]});const f=n.runtime||{},h=n.counters||{},p=n.timings||{},x=n.input||{},g=n.output||{},b=n.errors||{},y=Array.isArray(n.history)?n.history:[],N=y.find(w=>w.runId===o)||(y.length?y[y.length-1]:null),M=kw(n),k=Ew(x.modelMessages,g.raw),S=[{label:"running",value:f.running?"yes":"no"},{label:"in flight",value:f.inFlight?"yes":"no"},{label:"phase",value:f.phase||"--"},{label:"run id",value:f.currentRunId??"--"},{label:"tick count",value:f.tickCount??0},{label:"last tick",value:f.lastTickAt?new Date(f.lastTickAt).toLocaleString():"never"},{label:"next run",value:f.nextRunAt?new Date(f.nextRunAt).toLocaleString():"n/a"},{label:"outcome",value:f.outcome||"--"},{label:"reason",value:f.reason||"--"},{label:"skip streak",value:h.skipStreak??0},{label:"clear count",value:h.clearCount??0},{label:"last gen",value:p.lastGenerationMs!=null?`${p.lastGenerationMs} ms`:"--"},{label:"avg gen",value:p.avgGenerationMs!=null?`${p.avgGenerationMs} ms`:"--"},{label:"gen count",value:p.generationCount??0},{label:"prompt chars",value:h.promptChars??0},{label:"active drivers",value:h.snapshotSummary?.activeDrivers??0},{label:"snapshot rovers",value:h.snapshotSummary?.rovers??0},{label:"snapshot chat",value:h.snapshotSummary?.chatMessages??0}];return l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),l.jsx("div",{className:"flex gap-0.5 text-xs",children:l.jsx("button",{type:"button",onClick:s,disabled:!!r,className:"button-danger disabled:cursor-not-allowed disabled:opacity-60",children:r?"Clearing...":"Clear LLM History"})}),l.jsxs("div",{className:`surface border text-center ${M.className}`,children:[l.jsx("div",{className:"text-[1.1rem] font-bold tracking-wide",children:M.label}),l.jsx("div",{className:"text-xs text-slate-200",children:M.detail})]}),l.jsx("div",{className:"surface flex flex-wrap gap-0.5 text-xs",children:S.map(w=>l.jsxs("span",{className:"rounded border border-slate-600/60 bg-slate-800/70 px-0.5 py-0.25 text-[0.72rem] leading-tight text-slate-200",children:[w.label,": ",w.value]},w.label))}),b.message?l.jsxs("div",{className:"surface text-xs text-red-300 break-words",children:["Error: ",b.message]}):null,b.details?l.jsxs("details",{className:"surface text-xs text-red-200",children:[l.jsx("summary",{className:"cursor-pointer select-none text-red-300",children:"Failure details"}),l.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-red-200",children:JSON.stringify(b.details,null,2)})]}):null,g.generated?l.jsxs("div",{className:"surface text-xs text-slate-200 break-words",children:["Generated: ",g.generated]}):null,g.posted?l.jsxs("div",{className:"surface text-xs text-emerald-200 break-words",children:["Posted: ",g.posted]}):null,l.jsxs("div",{className:"grid gap-0.5 md:grid-cols-2",children:[l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"Live Input Conversation"}),l.jsx("div",{className:"surface max-h-72 space-y-0.5 overflow-y-auto",children:k.length?k.map(w=>l.jsx(ff,{message:w.message},w.id)):l.jsx("div",{className:"text-xs text-slate-300",children:"No model conversation captured yet."})})]}),l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"Output + Error"}),l.jsxs("div",{className:"surface space-y-0.5 text-xs text-slate-200",children:[l.jsxs("div",{children:["Raw output: ",g.raw?.trim()?g.raw:""]}),l.jsxs("div",{children:["Posted: ",g.posted||""]}),l.jsxs("div",{children:["Output at: ",g.modelOutputAt?new Date(g.modelOutputAt).toLocaleString():"n/a"]}),l.jsxs("div",{children:["Failed at: ",b.failedAt?new Date(b.failedAt).toLocaleString():"n/a"]})]})]})]}),l.jsxs("details",{className:"surface text-xs text-slate-200",children:[l.jsx("summary",{className:"cursor-pointer select-none text-slate-300",children:"Full Monitor Payload"}),l.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-slate-200",children:JSON.stringify(n,null,2)})]}),l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"Recent Runs"}),l.jsx("div",{className:"surface max-h-52 space-y-0.5 overflow-y-auto text-xs",children:y.length?y.slice().reverse().map(w=>l.jsxs("button",{type:"button",onClick:()=>u(w.runId),className:`w-full text-left surface ${N?.runId===w.runId?"border border-sky-400/50":""}`,children:[l.jsxs("span",{className:"text-slate-300",children:["#",w.runId]})," ",l.jsx("span",{className:"text-slate-200",children:w.outcome||w.phase||"--"})," ",l.jsx("span",{className:"text-slate-400",children:w.durationMs!=null?`${w.durationMs}ms`:"--"})," ",l.jsx("span",{className:"text-slate-500",children:w.reason||""})]},w.runId)):l.jsx("div",{className:"text-slate-300",children:"No runs recorded yet."})})]}),N?l.jsxs("details",{className:"surface text-xs text-slate-200",open:!0,children:[l.jsxs("summary",{className:"cursor-pointer select-none text-slate-300",children:["Run #",N.runId," details"]}),l.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-slate-200",children:JSON.stringify(N,null,2)})]}):null]})}function Rw({state:n,onClearHistory:s,clearingHistory:r}){const[o,u]=m.useState(!1);if(!n)return l.jsxs("div",{className:"space-y-0.5",children:[l.jsx("div",{className:"panel-muted text-xs uppercase",children:"Overseer Control"}),l.jsx("div",{className:"surface text-xs text-slate-300",children:"No status received yet."})]});const f=n.runtime||{},h=n.config||{},p=n.output||{},x=n.timings||{},g=n.input||{},b=n.errors||{},y=()=>{const N=Array.isArray(g.modelMessages)?g.modelMessages:[];return N.length?N.map((M,k)=>{const S=String(M?.role||"unknown").toUpperCase(),w=String(M?.content||"");return`#${k+1} ${S} ${w}`}).join(` ---------------------------------------- diff --git a/server/public/index.html b/server/public/index.html index c50a47bb..4210a1aa 100644 --- a/server/public/index.html +++ b/server/public/index.html @@ -11,7 +11,7 @@ Roomba Rover - + diff --git a/webui/src/components/VideoTile/RoverDescriptionOverlay.jsx b/webui/src/components/VideoTile/RoverDescriptionOverlay.jsx index 7b4bb892..18e3b2a0 100644 --- a/webui/src/components/VideoTile/RoverDescriptionOverlay.jsx +++ b/webui/src/components/VideoTile/RoverDescriptionOverlay.jsx @@ -49,6 +49,7 @@ export default function RoverDescriptionOverlay({ largeFading ? 'opacity-0' : 'opacity-100' } ${mobileHud ? 'text-[1rem] leading-tight' : 'text-[1.5rem] leading-tight'}`} > +

Just so you know, this rover

{description}