diff --git a/server/public/assets/index-DHSB5kNG.js b/server/public/assets/index-DGNxKAq1.js similarity index 93% rename from server/public/assets/index-DHSB5kNG.js rename to server/public/assets/index-DGNxKAq1.js index 624fa025..a4eaf830 100644 --- a/server/public/assets/index-DHSB5kNG.js +++ b/server/public/assets/index-DGNxKAq1.js @@ -14,7 +14,7 @@ Please change the parent to r&&r>o){const u=Er/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))*Er)}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 Cn(...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=Er,ce=Cn("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=Cn("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:ce,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)),v=n.warnDisplayPercent??Er,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",T=N||M?"bg-red-900/45":"bg-slate-900/35",E=Cn(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}%`},ce=Cn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",w,"transition-[width,height]",N&&"battery-urgent-flash"),ie=Cn("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:`${v}%`}:{left:`${v}%`};return l.jsxs("div",{className:E,children:[l.jsx("div",{className:Cn("absolute inset-0",j,N&&"battery-urgent-flash")}),l.jsx("div",{className:ce,style:{...P,animationDuration:k}}),l.jsx("div",{className:ie,style:V})]})}const C=Cn("relative overflow-hidden rounded-sm border border-slate-800",N||M?T:"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=Cn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",w,"transition-[width,height]",N&&"battery-urgent-flash"),O=Cn("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:`${v}%`}:{left:`${v}%`},K=`Battery ${g}%`,$=Cn("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=Cn("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=an.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 zo(n){return Math.max(0,Math.min(1,n))}function Fg(n){return(n-90)*Math.PI/180}function Sr(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=Sr(n,s,r,f),x=Sr(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=zo(n/(s||1));return`hsl(${(200+Math.pow(o,.45)*360)%360} 100% 60%)`}function PN(n,s){if(s)return"#ef4444";const r=zo(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),v=n+h*Math.cos(b),N=s+h*Math.sin(b);return l.jsx("line",{x1:n,y1:s,x2:v,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,v=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:v,rx:"3",fill:`url(#${N})`,stroke:"#64748b",strokeWidth:"1"}),l.jsx("rect",{x:n-b/2,y:s+4,width:b,height:v,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:v*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,v=g+4,N=g-14,M=g-6,k=g*.65,S=n?.bumpsAndWheelDrops||{},w=n?.wheelOvercurrents||{},j=n?.wheelLeftCurrentMa??0,T=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,q)=>({label:K[q],start:V.start,end:V.end,value:$[q]})),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}],ce=$.filter(V=>V!=null),ie=ce.length?Math.max(...ce,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:T,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 q=JN(V.value,ie),H=v+4,J=H+28;return l.jsx(ew,{cx:p,cy:x,rBase:J,rTip:H,startDeg:V.start,endDeg:V.end,color:q,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:v-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:v-O,startDeg:6,endDeg:70,color:S.bumpRight?"#ef4444":"#475569",opacity:1,pulse:!!S.bumpRight})]})]})}const Xd=an.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:v="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]",T=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:v==="top-center"?`translateX(-50%) scale(${P})`:`scale(${P})`,transformOrigin:v==="bottom-left"?"bottom left":v==="top-center"?"top center":"top right",...v==="bottom-left"?{left:"0.25rem",bottom:"0.25rem"}:v==="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||"--"]],q=!!n?.chargingSources?.homeBase,H=n?.chargingState?.label||"",J=!!(H&&H.toLowerCase()!=="not charging"),te=n?.oiMode?.label||"Unknown",de=te.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",_=q?"bg-emerald-500/80 text-emerald-50":"bg-slate-700/70 text-slate-200",Z=J?"bg-emerald-500/80 text-emerald-50":q?"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} ${T}`,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:q?"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: ",te]})]}),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=an.memo(sw),fx=5e3,rw=700;function iw({description:n,variant:s="default",mobileHud:r=!1,displayKey:o="",controlIntentAt:u=0}){const[f,h]=m.useState(!1),[p,x]=m.useState(!1),g=m.useRef(0),b=m.useRef(null),v=m.useRef(null);return m.useEffect(()=>()=>{clearTimeout(b.current),clearTimeout(v.current)},[]),m.useEffect(()=>{if(s!=="default"||!n){h(!1),x(!1),clearTimeout(b.current),clearTimeout(v.current);return}clearTimeout(b.current),clearTimeout(v.current),h(!0),x(!1),g.current=Number(u)||0},[u,n,o,s]),m.useEffect(()=>{s!=="default"||!n||!f||p||(Number(u)||0)<=g.current||b.current||v.current||(b.current=setTimeout(()=>{x(!0),b.current=null},fx),v.current=setTimeout(()=>{h(!1),v.current=null},fx+rw))},[u,n,p,f,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"||!f?null:l.jsx("div",{className:"pointer-events-none absolute inset-0 z-50 flex items-center justify-center",children:l.jsxs("div",{className:`surface max-w-[94%] border border-slate-400/70 bg-neutral-900/45 px-2 py-1 text-center font-semibold text-slate-100 shadow-xl transition-opacity duration-700 ${p?"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"}),l.jsx("p",{children:n}),l.jsx("p",{className:`${r?"text-[0.58rem]":"text-[0.72rem]"} mt-0.5 font-normal text-slate-300`,children:"This fades 5 seconds after your first control input."})]})}):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=an.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=an.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=xe(z=>z.session?.assignment?.roverId||null),o=xe(z=>z.session?.roster||[]),{sendMessage:u,onInputFocus:f,onInputBlur:h,blurChat:p,registerInputRef:x,setTypingActive:g}=pf(),{value:b}=Fe("tts",{engine:"flite",voice:"rms",pitch:50}),[v,N]=m.useState(""),[M,k]=m.useState(!1),S=s!=="spectator",w=s==="spectator",T=!!m.useMemo(()=>o.find(z=>String(z.id)===String(r))||null,[r,o])?.audio?.ttsEnabled,E=m.useMemo(()=>{if(!T)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,T]),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=v.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:v,onChange:z=>{const K=z.target.value;N(K),g(!!K.trim())},onFocus:z=>{f(z),g(!!v.trim())},onBlur:z=>{h(z),g(!1)},onKeyDown:z=>{z.key==="Enter"&&!v.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 Mr({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:v="desktop",hudVariant:N="default",driverLabel:M=null,hudForceMap:k=!1,hudMapPosition:S="top-center",hudLabelScale:w=1,fitParent:j=!1,overcurrentLimiter:T=null,showTurnCue:E=!1,turnTimerText:C=null,isActiveDriver:L=!1,idleSkipSeconds:G=null,showNotTurnNotice:O=!1,notTurnCountdownText:z=null,showPreviewReason:K=!1,notTurnFlashAt:$=0,controlIntentAt:X=0}){const P=xe(pe=>(pe.session?.socials||[]).find(Te=>String(Te?.id||Te?.label||"").toLowerCase()==="discord")?.url||null||pe.session?.discord?.invite||null),ce=m.useRef(null),ie=m.useRef(null),V=m.useRef(null),q=m.useRef(null),H=m.useRef(null),J=m.useRef(null),te=m.useRef(null),de=m.useRef(null),[R,_]=m.useState("idle"),[Z,ee]=m.useState(null),[fe,oe]=m.useState("idle"),[ue,ge]=m.useState(null),[ve,ye]=m.useState(0),[Ye,Ke]=m.useState(0),[Me,De]=m.useState(!0),[_e,Ct]=m.useState(!1),re=!!s?.url,se=r==="snapshot",je=g?.sensors,{value:me}=Fe("audio",ot),Ae=Number.isFinite(me?.masterVolume)?me.masterVolume:ot.masterVolume,Ce=Number.isFinite(me?.roverVolume)?me.roverVolume:ot.roverVolume,Pe=typeof me?.mainBrushDuckEnabled=="boolean"?me.mainBrushDuckEnabled:typeof me?.autoLevelEnabled=="boolean"?me.autoLevelEnabled:ot.mainBrushDuckEnabled,le=Number.isFinite(me?.mainBrushDuckAmount)?Math.max(0,Math.min(1,me.mainBrushDuckAmount)):ot.mainBrushDuckAmount,he=Math.max(0,Math.min(1,Ae*Ce)),Oe=je?.batteryChargeMah??null,nt=!(v==="desktop"),fl=nt?"top-right":S,[ln]=$g(),ml=k||nt?!0:ln,fs=Gg({charge:Oe,config:b}),Sn=je?.wheelOvercurrents||null,jt=m.useMemo(()=>Sn==null?[]:Object.entries(Sn).filter(([,pe])=>!!pe).map(([pe])=>pe),[Sn]),kt=T?.caps||null,Dt=T?.overcurrent?.groups||null,Hr=m.useMemo(()=>{if(typeof window>"u")return{debugAudio:!1,debugHud:!1};const pe=new URLSearchParams(window.location.search);return{debugAudio:pe.has("debugAudio"),debugHud:pe.has("debugHud")}},[]),Vr=Hr.debugAudio,hl=Hr.debugHud,Ua=m.useMemo(()=>{if(!kt)return null;const pe=Number.isFinite(kt?.drive?.cap)?kt.drive.cap:1,Re=Number.isFinite(kt?.aux?.cap)?kt.aux.cap:1;return Math.max(0,Math.min(1,1-Math.min(pe,Re)))},[kt]),Hn=!!T?.isActive,zt=m.useMemo(()=>{const pe=jt.length?jt:Hn?["limiter"]:[],Re=Ua??(jt.length?1:0);return{motors:pe,fill:Re,visible:!!pe.length}},[jt,Hn,Ua]),Ut=!!((Number(je?.mainBrushCurrentMa)||0)>uw||je?.wheelOvercurrents?.mainBrush),ms=Pe&&Ut?1-le:1,Mn=Math.max(0,Math.min(1,he*ms)),Fo=Pe&&Ut&&le>0?`Volume decreased ${Math.round(le*1e3)/10}%`:null,pl=m.useRef({hasDedicatedAudio:!1,audioUrl:null,mainBrushDuckEnabled:!1,mainBrushDuckAmount:0,mainBrushActive:!1,baseRoverGain:0,effectiveRoverGain:0});m.useEffect(()=>{pl.current={hasDedicatedAudio:re,audioUrl:s?.url||null,mainBrushDuckEnabled:Pe,mainBrushDuckAmount:le,mainBrushActive:Ut,baseRoverGain:he,effectiveRoverGain:Mn}},[re,s?.url,Pe,le,Ut,he,Mn]);const st=m.useCallback((pe,Re={})=>{if(!Vr)return;const Xe=ie.current,Te=pl.current,Ie={event:pe,ts:Date.now(),roverLabel:f||null,hasDedicatedAudio:Te.hasDedicatedAudio,audioUrl:Te.audioUrl,mainBrushDuckEnabled:Te.mainBrushDuckEnabled,mainBrushDuckAmount:Te.mainBrushDuckAmount,mainBrushActive:Te.mainBrushActive,baseRoverGain:Te.baseRoverGain,effectiveRoverGain:Te.effectiveRoverGain,element:Xe?{muted:Xe.muted,volume:Xe.volume,paused:Xe.paused,ended:Xe.ended,readyState:Xe.readyState,networkState:Xe.networkState}:null,...Re};try{console.log(`[AudioDebug] ${pe} ${JSON.stringify(Ie)}`)}catch{console.log("[AudioDebug]",pe,Ie)}},[Vr,f]);m.useEffect(()=>{hl&&console.log("[OvercurrentHUD]",{overlayVisible:zt.visible,overlayMotors:zt.motors,overlayFill:zt.fill,limiterActive:Hn,limiterCaps:kt,limiterGroups:Dt,wheelOvercurrents:Sn})},[hl,zt,Hn,kt,Dt,Sn]),m.useEffect(()=>{st("settings/update")},[st]);const jn=m.useCallback(()=>{clearTimeout(V.current),V.current=setTimeout(()=>ye(Date.now()),mx)},[]),xl=m.useCallback(()=>{clearTimeout(q.current),q.current=setTimeout(()=>Ke(Date.now()),mx)},[]),Ha=m.useCallback(async()=>{const pe=ce.current;if(pe)try{pe.muted=!0,await pe.play()}catch{}},[]),gl=m.useCallback((pe=0)=>{if(x||re)return;clearTimeout(J.current);const Re=()=>{clearTimeout(J.current),J.current=setTimeout(()=>{x||Xe()},ow)},Xe=async()=>{const Te=ce.current;if(Te)try{await Ha(),Te.muted=!1,await Te.play(),De(!1)}catch{Te.muted=!0,De(!0),Re()}};J.current=setTimeout(Xe,pe)},[Ha,x,re]);m.useEffect(()=>()=>{clearTimeout(V.current),clearTimeout(q.current),clearTimeout(J.current),clearInterval(H.current),te.current&&(cancelAnimationFrame(te.current),te.current=null)},[]),m.useEffect(()=>{if(!O||!$)return;Ct(!0);const pe=setTimeout(()=>Ct(!1),650);return()=>clearTimeout(pe)},[O,$]),m.useEffect(()=>{R==="playing"&&gl(0)},[R,gl]),m.useEffect(()=>{se&&(_("snapshot"),ee(null))},[se]),m.useEffect(()=>{if(se||!n?.url||!ce.current)return;let pe=!0,Re;const Xe=setTimeout(()=>De(!0),0),Te=(Ie,_t)=>{pe&&(st("video/status",{nextStatus:Ie,info:_t||null}),_(Ie),ee(_t||null),Ie==="playing"&&Ha(),["error","failed","disconnected","closed"].includes(Ie)&&jn())};return Re=new ux({url:n.url,token:n.token,video:ce.current,receiveAudio:!re,onStatus:Te}),Re.start().catch(Ie=>{pe&&(_("error"),ee(Ie.message),jn())}),()=>{pe=!1,clearTimeout(Xe),Re?.stop()}},[se,n?.url,n?.token,ve,jn,Ha,re,st]),m.useEffect(()=>{R==="stopped"&&n?.url&&jn()},[R,n?.url,jn]),m.useEffect(()=>{const pe=ie.current;if(!pe||!s?.url){st("route/no-audio-url"),de.current=null;return}const Re=Math.max(0,Math.min(1,Mn)),Xe=de.current==null?Math.max(0,Math.min(1,pe.volume)):de.current;if(te.current&&(cancelAnimationFrame(te.current),te.current=null),Re>Xe){const Te=performance.now(),Ie=Xe,_t=Re-Ie,ma=Tn=>{const mt=Math.min(1,(Tn-Te)/dw),rn=Ie+_t*mt;pe.volume=rn,de.current=rn,mt<1?te.current=requestAnimationFrame(ma):te.current=null};te.current=requestAnimationFrame(ma)}else pe.volume=Re,de.current=Re;st("route/direct",{elementVolume:Re,duckEnabled:Pe,mainBrushActive:Ut,duckAmount:le})},[s?.url,Mn,Pe,Ut,le,st]),m.useEffect(()=>{if(!s?.url||!ie.current)return;let pe=!0,Re;const Xe=(Te,Ie)=>{pe&&(st("audio/status",{nextStatus:Te,info:Ie||null}),ge(Ie||(Te==="connected"?"connected":null)),oe(_t=>Te==="connected"&&(_t==="playing"||_t==="connecting")||Te==="new"?_t:Te),["error","failed"].includes(Te)&&xl())};return Re=new ux({url:s.url,token:s.token,video:ie.current,audioOnly:!0,onStatus:Xe}),Re.start().catch(Te=>{pe&&(oe("error"),ge(Te.message),xl())}),()=>{pe=!1,Re?.stop()}},[s?.url,s?.token,Ye,xl,st]),m.useEffect(()=>{const pe=ie.current;if(!s?.url||!pe){clearInterval(H.current);return}if(!["connecting","connected","playing","paused"].includes(fe)){clearInterval(H.current);return}const Xe=async()=>{const Te=ie.current;Te&&(Te.muted=!1,!(!Te.paused&&!Te.ended)&&(st("retry/play-attempt"),Te.play().then(()=>{st("retry/play-ok"),oe(Ie=>Ie==="connected"?"playing":Ie),ge(Ie=>Ie==="paused"?null:Ie)}).catch(Ie=>{st("retry/play-fail",{error:Ie?.message}),ge(_t=>_t||Ie?.message||"autoplay blocked")})))};return Xe(),H.current=setInterval(Xe,cw),()=>clearInterval(H.current)},[s?.url,fe,st]),m.useEffect(()=>{const pe=ie.current;if(!pe)return;const Re=()=>{st("element/play"),oe(mt=>mt==="error"?mt:"playing"),ge(null)},Xe=()=>{st("element/pause"),oe(mt=>["error","failed","disconnected","closed","stopped"].includes(mt)?mt:"paused"),ge(mt=>mt||"paused")},Te=()=>{st("element/ended"),oe(mt=>mt==="error"?mt:"stopped"),ge(mt=>mt||"ended")},Ie=()=>{const{error:mt}=pe,rn=mt?.message||"audio error";st("element/error",{error:rn}),oe("error"),ge(rn)},_t=()=>st("element/waiting"),ma=()=>st("element/canplay"),Tn=()=>st("element/stalled");return pe.addEventListener("play",Re),pe.addEventListener("pause",Xe),pe.addEventListener("ended",Te),pe.addEventListener("error",Ie),pe.addEventListener("waiting",_t),pe.addEventListener("canplay",ma),pe.addEventListener("stalled",Tn),()=>{pe.removeEventListener("play",Re),pe.removeEventListener("pause",Xe),pe.removeEventListener("ended",Te),pe.removeEventListener("error",Ie),pe.removeEventListener("waiting",_t),pe.removeEventListener("canplay",ma),pe.removeEventListener("stalled",Tn)}},[s?.url,st]);const $r=o?.error?`Error: ${o.error}`:o?.objectUrl?"snapshot":o?.status||"waiting",bl=se?$r:n?.url?R==="error"?`Error: ${Z||"unknown"}`:Z?`${R} (${Z})`:R:"waiting",vl=s?.error?`Error: ${s.error}`:s?.url?fe==="error"?`Error: ${ue||"unknown"}`:ue?`${fe} (${ue})`:fe:null,yl=N==="spectator",Ht=N==="none",Rn=`${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:[se?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:ce,muted:x||Me||re,playsInline:!0,autoPlay:!0,controls:!1,className:"h-full w-full object-contain"}),l.jsx("audio",{ref:ie,autoPlay:!0,hidden:!0}),!Ht&&E?l.jsx(IN,{mobileHud:nt,isActiveDriver:L,idleSkipSeconds:G}):null,Ht?null:l.jsx(iw,{description:h,variant:N,mobileHud:nt,displayKey:Rn,controlIntentAt:X}),Ht?null:l.jsx(lw,{sensors:je,label:f,roverColor:p,status:bl,audioStatus:vl,levelStatus:Fo,layoutFormat:v,variant:N,driverLabel:M,showTopDown:ml,mobileHud:nt,mapPosition:fl,turnTimerText:C,turnTimerFlashActive:_e,labelScale:w}),Ht?null:l.jsx(yw,{compact:nt}),!Ht&&hl?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:${zt.visible?1:0} motors:${zt.motors.length} fill:${Math.round(zt.fill*100)}%`}):null,Ht?null:l.jsx(hw,{motors:zt.motors,fill:zt.fill,compact:nt}),Ht?null:l.jsx(xw,{battery:fs,compact:nt}),!Ht&&yl&&fs.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:fs,orientation:"vertical",variant:"inline",compact:nt,className:"h-full w-4"})}):null,!Ht&&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 ${nt?"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(kr,{id:"discord",label:"Join our Discord server while you wait!",url:P})})]})}):null,!Ht&&O?l.jsx("div",{className:"pointer-events-none absolute bottom-1 left-1 z-40",children:l.jsxs("div",{className:`w-fit rounded border ${_e?"border-red-300/90 bg-red-900/80 text-red-100":"border-amber-300/80 bg-black/75 text-amber-200"} ${nt?"px-2 py-1 text-[0.6rem]":"px-3 py-1.5 text-sm"}`,children:[l.jsx("div",{className:_e?"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:_e?"text-red-100/95":"text-amber-100",children:z}):null,K?l.jsx("div",{className:_e?"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(kr,{id:"discord",label:"Join our Discord while you wait!",url:P})})]})}):null]}),!Ht&&!yl&&l.jsxs("div",{className:"space-y-0.5",children:[l.jsx(bw,{sensors:je}),l.jsx("div",{className:"panel-section space-y-0.5 text-sm",children:l.jsx(Yd,{visual:fs,compact:nt})})]})]})}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=xe(se=>se.session?.mode||null),r=xe(se=>se.session?.assignment?.roverId??null),o=xe(se=>se.session?.roster??[]),u=xe(se=>se.session?.users??[]),f=xe(se=>se.session?.turnQueues??{}),h=xe(se=>se.session?.socketId||null),p=xe(se=>se.session?.activeDrivers??{}),{state:{song:x,lastControlIntentAt:g},overcurrentLimiter:b}=At(),[v,N]=m.useState(()=>Date.now()),[M,k]=m.useState(!1),[S,w]=m.useState(null),[j,T]=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 je=se.findIndex(me=>me===O.current);return je===-1?se[0]||null:se[(je+1)%se.length]||null},[O?.queue,O?.current]),X=!!(h&&$===h),P=O?.deadline||null,ce=O?.idleDeadline||null,ie=P?P-v:null,V=ce?ce-v:null,q=s==="turns",H=o.length,J=m.useMemo(()=>Sw(u),[u]),te=q&&J>H,de=q&&X&&ie!=null&&ie<=5e3&&ie>0,R=q&&!K,_=R&&!de&&te,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,oe=m.useMemo(()=>!q||!K?null:ee!=null?`${ee}s left`:"Your turn",[q,K,ee]),ue=m.useMemo(()=>!R||!X||ee==null?null:`${ee} seconds until your turn.`,[R,X,ee]),ge=r?[...Z?[{type:"rover",id:r,key:r}]:[],...G?[{type:"rover",id:`${r}-audio`,key:`${r}-audio`}]:[]]:[],ve=Cr(ge),ye=r&&Z?ve[r]:null,Ye=r&&G?ve[`${r}-audio`]:null,Ke=yf(r?[r]:[],{enabled:!!r,version:s}),Me=r&&Ke[r]||null,De=dl(r),_e=r&&o?o.find(se=>String(se.id)===String(r)):null,Ct=_e?.battery??null,re=_e?.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,je=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:je};return}!!se.activeDriverId&&se.activeDriverId!==h&&je===h?(k(!0),w(Date.now())):je!==h&&M&&(k(!1),w(null)),E.current={initialized:!0,roverId:r,activeDriverId:je}},[z,s,r,h,M]),m.useEffect(()=>{!M||!S||g>S&&k(!1)},[g,S,M]),m.useEffect(()=>{const se=Number(C.current)||0,je=Number(g)||0;je>se&&R&&T(Date.now()),C.current=je},[R,g]),l.jsx("section",{className:"panel",children:r?l.jsx(Mr,{sessionInfo:ye,videoMode:Z?"whep":"snapshot",snapshotFeed:Me,audioSessionInfo:Ye,label:re,roverDescription:_e?.description,roverColor:_e?.color||null,telemetryFrame:De,batteryConfig:Ct,layoutFormat:n,overcurrentLimiter:b,songNote:x?.note,qualityNotice:null,showTurnCue:M,turnTimerText:oe,turnSeconds:ee,isActiveDriver:K,idleSkipSeconds:fe,showNotTurnNotice:R,notTurnCountdownText:ue,showPreviewReason:_,notTurnFlashAt:j,controlIntentAt:g}):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 Ro({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 Uo(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,Uo(Math.round(b*60))}function hx(n){const s=Uo(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)?Uo(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",v=r||!s||h,N=v||!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 T=z=>{const K=Uo(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:v,className:`relative flex min-w-[12rem] flex-[1_1_12rem] items-start justify-between gap-0.5 rounded px-1 py-0.5 text-left transition-colors ${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(Ro,{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:T,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(Ro,{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}}=At(),s=xe(N=>N.session?.homeAssistant||null),{homeAssistantToggle:r,homeAssistantSetLightColor:o,homeAssistantSetLightWhite:u}=Qt(),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 v=!!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(Ro,{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(Ro,{label:v?"Connected":"Offline",tone:v?"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:v,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}=Qt(),[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||{},v=Array.isArray(n.history)?n.history:[],N=v.find(w=>w.runId===o)||(v.length?v[v.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:v.length?v.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||{},v=()=>{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 kr({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 Er=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 v=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:v,percentDisplay:b,warnActive:N,urgentActive:M,warnDisplayPercent:Er}}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=Er/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))*Er)}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 Cn(...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=Er,ce=Cn("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=Cn("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:ce,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)),v=n.warnDisplayPercent??Er,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",T=N||M?"bg-red-900/45":"bg-slate-900/35",E=Cn(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}%`},ce=Cn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",w,"transition-[width,height]",N&&"battery-urgent-flash"),ie=Cn("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:`${v}%`}:{left:`${v}%`};return l.jsxs("div",{className:E,children:[l.jsx("div",{className:Cn("absolute inset-0",j,N&&"battery-urgent-flash")}),l.jsx("div",{className:ce,style:{...P,animationDuration:k}}),l.jsx("div",{className:ie,style:V})]})}const C=Cn("relative overflow-hidden rounded-sm border border-slate-800",N||M?T:"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=Cn("absolute",p?"bottom-0 left-0 right-0":"left-0 top-0 bottom-0",w,"transition-[width,height]",N&&"battery-urgent-flash"),O=Cn("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:`${v}%`}:{left:`${v}%`},K=`Battery ${g}%`,$=Cn("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=Cn("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=an.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 zo(n){return Math.max(0,Math.min(1,n))}function Fg(n){return(n-90)*Math.PI/180}function Sr(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=Sr(n,s,r,f),x=Sr(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=zo(n/(s||1));return`hsl(${(200+Math.pow(o,.45)*360)%360} 100% 60%)`}function PN(n,s){if(s)return"#ef4444";const r=zo(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),v=n+h*Math.cos(b),N=s+h*Math.sin(b);return l.jsx("line",{x1:n,y1:s,x2:v,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,v=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:v,rx:"3",fill:`url(#${N})`,stroke:"#64748b",strokeWidth:"1"}),l.jsx("rect",{x:n-b/2,y:s+4,width:b,height:v,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:v*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,v=g+4,N=g-14,M=g-6,k=g*.65,S=n?.bumpsAndWheelDrops||{},w=n?.wheelOvercurrents||{},j=n?.wheelLeftCurrentMa??0,T=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,q)=>({label:K[q],start:V.start,end:V.end,value:$[q]})),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}],ce=$.filter(V=>V!=null),ie=ce.length?Math.max(...ce,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:T,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 q=JN(V.value,ie),H=v+4,J=H+28;return l.jsx(ew,{cx:p,cy:x,rBase:J,rTip:H,startDeg:V.start,endDeg:V.end,color:q,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:v-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:v-O,startDeg:6,endDeg:70,color:S.bumpRight?"#ef4444":"#475569",opacity:1,pulse:!!S.bumpRight})]})]})}const Xd=an.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:v="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]",T=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:v==="top-center"?`translateX(-50%) scale(${P})`:`scale(${P})`,transformOrigin:v==="bottom-left"?"bottom left":v==="top-center"?"top center":"top right",...v==="bottom-left"?{left:"0.25rem",bottom:"0.25rem"}:v==="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||"--"]],q=!!n?.chargingSources?.homeBase,H=n?.chargingState?.label||"",J=!!(H&&H.toLowerCase()!=="not charging"),te=n?.oiMode?.label||"Unknown",de=te.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",_=q?"bg-emerald-500/80 text-emerald-50":"bg-slate-700/70 text-slate-200",Z=J?"bg-emerald-500/80 text-emerald-50":q?"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} ${T}`,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:q?"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: ",te]})]}),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=an.memo(sw),fx=5e3,rw=700;function iw({description:n,variant:s="default",mobileHud:r=!1,displayKey:o="",controlIntentAt:u=0}){const[f,h]=m.useState(!1),[p,x]=m.useState(!1),g=m.useRef(0),b=m.useRef(null),v=m.useRef(null);return m.useEffect(()=>()=>{clearTimeout(b.current),clearTimeout(v.current)},[]),m.useEffect(()=>{if(s!=="default"||!n){h(!1),x(!1),clearTimeout(b.current),clearTimeout(v.current);return}clearTimeout(b.current),clearTimeout(v.current),h(!0),x(!1),g.current=Number(u)||0},[n,o,s]),m.useEffect(()=>{s!=="default"||!n||!f||p||(Number(u)||0)<=g.current||b.current||v.current||(b.current=setTimeout(()=>{x(!0),b.current=null},fx),v.current=setTimeout(()=>{h(!1),v.current=null},fx+rw))},[u,n,p,f,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"||!f?null:l.jsx("div",{className:"pointer-events-none absolute inset-0 z-50 flex items-center justify-center",children:l.jsxs("div",{className:`surface max-w-[94%] border border-slate-400/70 bg-neutral-900/45 px-2 py-1 text-center font-semibold text-slate-100 shadow-xl transition-opacity duration-700 ${p?"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"}),l.jsx("p",{children:n}),l.jsx("p",{className:`${r?"text-[0.58rem]":"text-[0.72rem]"} mt-0.5 font-normal text-slate-300`,children:"This fades 5 seconds after your first control input."})]})}):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=an.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=an.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=xe(z=>z.session?.assignment?.roverId||null),o=xe(z=>z.session?.roster||[]),{sendMessage:u,onInputFocus:f,onInputBlur:h,blurChat:p,registerInputRef:x,setTypingActive:g}=pf(),{value:b}=Fe("tts",{engine:"flite",voice:"rms",pitch:50}),[v,N]=m.useState(""),[M,k]=m.useState(!1),S=s!=="spectator",w=s==="spectator",T=!!m.useMemo(()=>o.find(z=>String(z.id)===String(r))||null,[r,o])?.audio?.ttsEnabled,E=m.useMemo(()=>{if(!T)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,T]),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=v.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:v,onChange:z=>{const K=z.target.value;N(K),g(!!K.trim())},onFocus:z=>{f(z),g(!!v.trim())},onBlur:z=>{h(z),g(!1)},onKeyDown:z=>{z.key==="Enter"&&!v.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 Mr({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:v="desktop",hudVariant:N="default",driverLabel:M=null,hudForceMap:k=!1,hudMapPosition:S="top-center",hudLabelScale:w=1,fitParent:j=!1,overcurrentLimiter:T=null,showTurnCue:E=!1,turnTimerText:C=null,isActiveDriver:L=!1,idleSkipSeconds:G=null,showNotTurnNotice:O=!1,notTurnCountdownText:z=null,showPreviewReason:K=!1,notTurnFlashAt:$=0,controlIntentAt:X=0}){const P=xe(pe=>(pe.session?.socials||[]).find(Te=>String(Te?.id||Te?.label||"").toLowerCase()==="discord")?.url||null||pe.session?.discord?.invite||null),ce=m.useRef(null),ie=m.useRef(null),V=m.useRef(null),q=m.useRef(null),H=m.useRef(null),J=m.useRef(null),te=m.useRef(null),de=m.useRef(null),[R,_]=m.useState("idle"),[Z,ee]=m.useState(null),[fe,oe]=m.useState("idle"),[ue,ge]=m.useState(null),[ve,ye]=m.useState(0),[Ye,Ke]=m.useState(0),[Me,De]=m.useState(!0),[_e,Ct]=m.useState(!1),re=!!s?.url,se=r==="snapshot",je=g?.sensors,{value:me}=Fe("audio",ot),Ae=Number.isFinite(me?.masterVolume)?me.masterVolume:ot.masterVolume,Ce=Number.isFinite(me?.roverVolume)?me.roverVolume:ot.roverVolume,Pe=typeof me?.mainBrushDuckEnabled=="boolean"?me.mainBrushDuckEnabled:typeof me?.autoLevelEnabled=="boolean"?me.autoLevelEnabled:ot.mainBrushDuckEnabled,le=Number.isFinite(me?.mainBrushDuckAmount)?Math.max(0,Math.min(1,me.mainBrushDuckAmount)):ot.mainBrushDuckAmount,he=Math.max(0,Math.min(1,Ae*Ce)),Oe=je?.batteryChargeMah??null,nt=!(v==="desktop"),fl=nt?"top-right":S,[ln]=$g(),ml=k||nt?!0:ln,fs=Gg({charge:Oe,config:b}),Sn=je?.wheelOvercurrents||null,jt=m.useMemo(()=>Sn==null?[]:Object.entries(Sn).filter(([,pe])=>!!pe).map(([pe])=>pe),[Sn]),kt=T?.caps||null,Dt=T?.overcurrent?.groups||null,Hr=m.useMemo(()=>{if(typeof window>"u")return{debugAudio:!1,debugHud:!1};const pe=new URLSearchParams(window.location.search);return{debugAudio:pe.has("debugAudio"),debugHud:pe.has("debugHud")}},[]),Vr=Hr.debugAudio,hl=Hr.debugHud,Ua=m.useMemo(()=>{if(!kt)return null;const pe=Number.isFinite(kt?.drive?.cap)?kt.drive.cap:1,Re=Number.isFinite(kt?.aux?.cap)?kt.aux.cap:1;return Math.max(0,Math.min(1,1-Math.min(pe,Re)))},[kt]),Hn=!!T?.isActive,zt=m.useMemo(()=>{const pe=jt.length?jt:Hn?["limiter"]:[],Re=Ua??(jt.length?1:0);return{motors:pe,fill:Re,visible:!!pe.length}},[jt,Hn,Ua]),Ut=!!((Number(je?.mainBrushCurrentMa)||0)>uw||je?.wheelOvercurrents?.mainBrush),ms=Pe&&Ut?1-le:1,Mn=Math.max(0,Math.min(1,he*ms)),Fo=Pe&&Ut&&le>0?`Volume decreased ${Math.round(le*1e3)/10}%`:null,pl=m.useRef({hasDedicatedAudio:!1,audioUrl:null,mainBrushDuckEnabled:!1,mainBrushDuckAmount:0,mainBrushActive:!1,baseRoverGain:0,effectiveRoverGain:0});m.useEffect(()=>{pl.current={hasDedicatedAudio:re,audioUrl:s?.url||null,mainBrushDuckEnabled:Pe,mainBrushDuckAmount:le,mainBrushActive:Ut,baseRoverGain:he,effectiveRoverGain:Mn}},[re,s?.url,Pe,le,Ut,he,Mn]);const st=m.useCallback((pe,Re={})=>{if(!Vr)return;const Xe=ie.current,Te=pl.current,Ie={event:pe,ts:Date.now(),roverLabel:f||null,hasDedicatedAudio:Te.hasDedicatedAudio,audioUrl:Te.audioUrl,mainBrushDuckEnabled:Te.mainBrushDuckEnabled,mainBrushDuckAmount:Te.mainBrushDuckAmount,mainBrushActive:Te.mainBrushActive,baseRoverGain:Te.baseRoverGain,effectiveRoverGain:Te.effectiveRoverGain,element:Xe?{muted:Xe.muted,volume:Xe.volume,paused:Xe.paused,ended:Xe.ended,readyState:Xe.readyState,networkState:Xe.networkState}:null,...Re};try{console.log(`[AudioDebug] ${pe} ${JSON.stringify(Ie)}`)}catch{console.log("[AudioDebug]",pe,Ie)}},[Vr,f]);m.useEffect(()=>{hl&&console.log("[OvercurrentHUD]",{overlayVisible:zt.visible,overlayMotors:zt.motors,overlayFill:zt.fill,limiterActive:Hn,limiterCaps:kt,limiterGroups:Dt,wheelOvercurrents:Sn})},[hl,zt,Hn,kt,Dt,Sn]),m.useEffect(()=>{st("settings/update")},[st]);const jn=m.useCallback(()=>{clearTimeout(V.current),V.current=setTimeout(()=>ye(Date.now()),mx)},[]),xl=m.useCallback(()=>{clearTimeout(q.current),q.current=setTimeout(()=>Ke(Date.now()),mx)},[]),Ha=m.useCallback(async()=>{const pe=ce.current;if(pe)try{pe.muted=!0,await pe.play()}catch{}},[]),gl=m.useCallback((pe=0)=>{if(x||re)return;clearTimeout(J.current);const Re=()=>{clearTimeout(J.current),J.current=setTimeout(()=>{x||Xe()},ow)},Xe=async()=>{const Te=ce.current;if(Te)try{await Ha(),Te.muted=!1,await Te.play(),De(!1)}catch{Te.muted=!0,De(!0),Re()}};J.current=setTimeout(Xe,pe)},[Ha,x,re]);m.useEffect(()=>()=>{clearTimeout(V.current),clearTimeout(q.current),clearTimeout(J.current),clearInterval(H.current),te.current&&(cancelAnimationFrame(te.current),te.current=null)},[]),m.useEffect(()=>{if(!O||!$)return;Ct(!0);const pe=setTimeout(()=>Ct(!1),650);return()=>clearTimeout(pe)},[O,$]),m.useEffect(()=>{R==="playing"&&gl(0)},[R,gl]),m.useEffect(()=>{se&&(_("snapshot"),ee(null))},[se]),m.useEffect(()=>{if(se||!n?.url||!ce.current)return;let pe=!0,Re;const Xe=setTimeout(()=>De(!0),0),Te=(Ie,_t)=>{pe&&(st("video/status",{nextStatus:Ie,info:_t||null}),_(Ie),ee(_t||null),Ie==="playing"&&Ha(),["error","failed","disconnected","closed"].includes(Ie)&&jn())};return Re=new ux({url:n.url,token:n.token,video:ce.current,receiveAudio:!re,onStatus:Te}),Re.start().catch(Ie=>{pe&&(_("error"),ee(Ie.message),jn())}),()=>{pe=!1,clearTimeout(Xe),Re?.stop()}},[se,n?.url,n?.token,ve,jn,Ha,re,st]),m.useEffect(()=>{R==="stopped"&&n?.url&&jn()},[R,n?.url,jn]),m.useEffect(()=>{const pe=ie.current;if(!pe||!s?.url){st("route/no-audio-url"),de.current=null;return}const Re=Math.max(0,Math.min(1,Mn)),Xe=de.current==null?Math.max(0,Math.min(1,pe.volume)):de.current;if(te.current&&(cancelAnimationFrame(te.current),te.current=null),Re>Xe){const Te=performance.now(),Ie=Xe,_t=Re-Ie,ma=Tn=>{const mt=Math.min(1,(Tn-Te)/dw),rn=Ie+_t*mt;pe.volume=rn,de.current=rn,mt<1?te.current=requestAnimationFrame(ma):te.current=null};te.current=requestAnimationFrame(ma)}else pe.volume=Re,de.current=Re;st("route/direct",{elementVolume:Re,duckEnabled:Pe,mainBrushActive:Ut,duckAmount:le})},[s?.url,Mn,Pe,Ut,le,st]),m.useEffect(()=>{if(!s?.url||!ie.current)return;let pe=!0,Re;const Xe=(Te,Ie)=>{pe&&(st("audio/status",{nextStatus:Te,info:Ie||null}),ge(Ie||(Te==="connected"?"connected":null)),oe(_t=>Te==="connected"&&(_t==="playing"||_t==="connecting")||Te==="new"?_t:Te),["error","failed"].includes(Te)&&xl())};return Re=new ux({url:s.url,token:s.token,video:ie.current,audioOnly:!0,onStatus:Xe}),Re.start().catch(Te=>{pe&&(oe("error"),ge(Te.message),xl())}),()=>{pe=!1,Re?.stop()}},[s?.url,s?.token,Ye,xl,st]),m.useEffect(()=>{const pe=ie.current;if(!s?.url||!pe){clearInterval(H.current);return}if(!["connecting","connected","playing","paused"].includes(fe)){clearInterval(H.current);return}const Xe=async()=>{const Te=ie.current;Te&&(Te.muted=!1,!(!Te.paused&&!Te.ended)&&(st("retry/play-attempt"),Te.play().then(()=>{st("retry/play-ok"),oe(Ie=>Ie==="connected"?"playing":Ie),ge(Ie=>Ie==="paused"?null:Ie)}).catch(Ie=>{st("retry/play-fail",{error:Ie?.message}),ge(_t=>_t||Ie?.message||"autoplay blocked")})))};return Xe(),H.current=setInterval(Xe,cw),()=>clearInterval(H.current)},[s?.url,fe,st]),m.useEffect(()=>{const pe=ie.current;if(!pe)return;const Re=()=>{st("element/play"),oe(mt=>mt==="error"?mt:"playing"),ge(null)},Xe=()=>{st("element/pause"),oe(mt=>["error","failed","disconnected","closed","stopped"].includes(mt)?mt:"paused"),ge(mt=>mt||"paused")},Te=()=>{st("element/ended"),oe(mt=>mt==="error"?mt:"stopped"),ge(mt=>mt||"ended")},Ie=()=>{const{error:mt}=pe,rn=mt?.message||"audio error";st("element/error",{error:rn}),oe("error"),ge(rn)},_t=()=>st("element/waiting"),ma=()=>st("element/canplay"),Tn=()=>st("element/stalled");return pe.addEventListener("play",Re),pe.addEventListener("pause",Xe),pe.addEventListener("ended",Te),pe.addEventListener("error",Ie),pe.addEventListener("waiting",_t),pe.addEventListener("canplay",ma),pe.addEventListener("stalled",Tn),()=>{pe.removeEventListener("play",Re),pe.removeEventListener("pause",Xe),pe.removeEventListener("ended",Te),pe.removeEventListener("error",Ie),pe.removeEventListener("waiting",_t),pe.removeEventListener("canplay",ma),pe.removeEventListener("stalled",Tn)}},[s?.url,st]);const $r=o?.error?`Error: ${o.error}`:o?.objectUrl?"snapshot":o?.status||"waiting",bl=se?$r:n?.url?R==="error"?`Error: ${Z||"unknown"}`:Z?`${R} (${Z})`:R:"waiting",vl=s?.error?`Error: ${s.error}`:s?.url?fe==="error"?`Error: ${ue||"unknown"}`:ue?`${fe} (${ue})`:fe:null,yl=N==="spectator",Ht=N==="none",Rn=`${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:[se?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:ce,muted:x||Me||re,playsInline:!0,autoPlay:!0,controls:!1,className:"h-full w-full object-contain"}),l.jsx("audio",{ref:ie,autoPlay:!0,hidden:!0}),!Ht&&E?l.jsx(IN,{mobileHud:nt,isActiveDriver:L,idleSkipSeconds:G}):null,Ht?null:l.jsx(iw,{description:h,variant:N,mobileHud:nt,displayKey:Rn,controlIntentAt:X}),Ht?null:l.jsx(lw,{sensors:je,label:f,roverColor:p,status:bl,audioStatus:vl,levelStatus:Fo,layoutFormat:v,variant:N,driverLabel:M,showTopDown:ml,mobileHud:nt,mapPosition:fl,turnTimerText:C,turnTimerFlashActive:_e,labelScale:w}),Ht?null:l.jsx(yw,{compact:nt}),!Ht&&hl?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:${zt.visible?1:0} motors:${zt.motors.length} fill:${Math.round(zt.fill*100)}%`}):null,Ht?null:l.jsx(hw,{motors:zt.motors,fill:zt.fill,compact:nt}),Ht?null:l.jsx(xw,{battery:fs,compact:nt}),!Ht&&yl&&fs.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:fs,orientation:"vertical",variant:"inline",compact:nt,className:"h-full w-4"})}):null,!Ht&&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 ${nt?"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(kr,{id:"discord",label:"Join our Discord server while you wait!",url:P})})]})}):null,!Ht&&O?l.jsx("div",{className:"pointer-events-none absolute bottom-1 left-1 z-40",children:l.jsxs("div",{className:`w-fit rounded border ${_e?"border-red-300/90 bg-red-900/80 text-red-100":"border-amber-300/80 bg-black/75 text-amber-200"} ${nt?"px-2 py-1 text-[0.6rem]":"px-3 py-1.5 text-sm"}`,children:[l.jsx("div",{className:_e?"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:_e?"text-red-100/95":"text-amber-100",children:z}):null,K?l.jsx("div",{className:_e?"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(kr,{id:"discord",label:"Join our Discord while you wait!",url:P})})]})}):null]}),!Ht&&!yl&&l.jsxs("div",{className:"space-y-0.5",children:[l.jsx(bw,{sensors:je}),l.jsx("div",{className:"panel-section space-y-0.5 text-sm",children:l.jsx(Yd,{visual:fs,compact:nt})})]})]})}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=xe(se=>se.session?.mode||null),r=xe(se=>se.session?.assignment?.roverId??null),o=xe(se=>se.session?.roster??[]),u=xe(se=>se.session?.users??[]),f=xe(se=>se.session?.turnQueues??{}),h=xe(se=>se.session?.socketId||null),p=xe(se=>se.session?.activeDrivers??{}),{state:{song:x,lastControlIntentAt:g},overcurrentLimiter:b}=At(),[v,N]=m.useState(()=>Date.now()),[M,k]=m.useState(!1),[S,w]=m.useState(null),[j,T]=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 je=se.findIndex(me=>me===O.current);return je===-1?se[0]||null:se[(je+1)%se.length]||null},[O?.queue,O?.current]),X=!!(h&&$===h),P=O?.deadline||null,ce=O?.idleDeadline||null,ie=P?P-v:null,V=ce?ce-v:null,q=s==="turns",H=o.length,J=m.useMemo(()=>Sw(u),[u]),te=q&&J>H,de=q&&X&&ie!=null&&ie<=5e3&&ie>0,R=q&&!K,_=R&&!de&&te,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,oe=m.useMemo(()=>!q||!K?null:ee!=null?`${ee}s left`:"Your turn",[q,K,ee]),ue=m.useMemo(()=>!R||!X||ee==null?null:`${ee} seconds until your turn.`,[R,X,ee]),ge=r?[...Z?[{type:"rover",id:r,key:r}]:[],...G?[{type:"rover",id:`${r}-audio`,key:`${r}-audio`}]:[]]:[],ve=Cr(ge),ye=r&&Z?ve[r]:null,Ye=r&&G?ve[`${r}-audio`]:null,Ke=yf(r?[r]:[],{enabled:!!r,version:s}),Me=r&&Ke[r]||null,De=dl(r),_e=r&&o?o.find(se=>String(se.id)===String(r)):null,Ct=_e?.battery??null,re=_e?.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,je=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:je};return}!!se.activeDriverId&&se.activeDriverId!==h&&je===h?(k(!0),w(Date.now())):je!==h&&M&&(k(!1),w(null)),E.current={initialized:!0,roverId:r,activeDriverId:je}},[z,s,r,h,M]),m.useEffect(()=>{!M||!S||g>S&&k(!1)},[g,S,M]),m.useEffect(()=>{const se=Number(C.current)||0,je=Number(g)||0;je>se&&R&&T(Date.now()),C.current=je},[R,g]),l.jsx("section",{className:"panel",children:r?l.jsx(Mr,{sessionInfo:ye,videoMode:Z?"whep":"snapshot",snapshotFeed:Me,audioSessionInfo:Ye,label:re,roverDescription:_e?.description,roverColor:_e?.color||null,telemetryFrame:De,batteryConfig:Ct,layoutFormat:n,overcurrentLimiter:b,songNote:x?.note,qualityNotice:null,showTurnCue:M,turnTimerText:oe,turnSeconds:ee,isActiveDriver:K,idleSkipSeconds:fe,showNotTurnNotice:R,notTurnCountdownText:ue,showPreviewReason:_,notTurnFlashAt:j,controlIntentAt:g}):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 Ro({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 Uo(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,Uo(Math.round(b*60))}function hx(n){const s=Uo(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)?Uo(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",v=r||!s||h,N=v||!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 T=z=>{const K=Uo(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:v,className:`relative flex min-w-[12rem] flex-[1_1_12rem] items-start justify-between gap-0.5 rounded px-1 py-0.5 text-left transition-colors ${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(Ro,{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:T,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(Ro,{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}}=At(),s=xe(N=>N.session?.homeAssistant||null),{homeAssistantToggle:r,homeAssistantSetLightColor:o,homeAssistantSetLightWhite:u}=Qt(),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 v=!!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(Ro,{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(Ro,{label:v?"Connected":"Offline",tone:v?"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:v,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}=Qt(),[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||{},v=Array.isArray(n.history)?n.history:[],N=v.find(w=>w.runId===o)||(v.length?v[v.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:v.length?v.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||{},v=()=>{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 9878f181..9c20ee58 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 e7196f4b..f6e1e704 100644 --- a/webui/src/components/VideoTile/RoverDescriptionOverlay.jsx +++ b/webui/src/components/VideoTile/RoverDescriptionOverlay.jsx @@ -38,7 +38,7 @@ export default function RoverDescriptionOverlay({ setLargeFading(false); baselineIntentRef.current = Number(controlIntentAt) || 0; return undefined; - }, [controlIntentAt, description, displayKey, variant]); + }, [description, displayKey, variant]); useEffect(() => { if (variant !== 'default' || !description || !largeVisible || largeFading) return;