From 0a351b9a4690e028ef3e647321d946117ab75812 Mon Sep 17 00:00:00 2001 From: legop3 Date: Mon, 22 Jun 2026 16:05:14 -0400 Subject: [PATCH] fixing idle skips no longer happening! --- .../{index-CTOqrTOu.js => index-BjmvF4mq.js} | 2 +- server/public/index.html | 2 +- server/src/services/commandService/index.js | 74 +++++++++++++++++-- webui/src/controls/ControlContext.jsx | 2 +- 4 files changed, 72 insertions(+), 8 deletions(-) rename server/public/assets/{index-CTOqrTOu.js => index-BjmvF4mq.js} (93%) diff --git a/server/public/assets/index-CTOqrTOu.js b/server/public/assets/index-BjmvF4mq.js similarity index 93% rename from server/public/assets/index-CTOqrTOu.js rename to server/public/assets/index-BjmvF4mq.js index 7b850197..ce1ff82d 100644 --- a/server/public/assets/index-CTOqrTOu.js +++ b/server/public/assets/index-BjmvF4mq.js @@ -20,7 +20,7 @@ Please change the parent to setTimeout(a,t))}function tY(t={}){const{driveTransform:a,auxTransform:l}=t,s=R2(),u=u1(T=>T.session?.assignment?.roverId??null),f=u1(T=>T.session?.roster??[]),v=d.useMemo(()=>!u||!Array.isArray(f)?null:f.find(T=>String(T.id)===String(u))||null,[u,f]),p=d.useMemo(()=>!v?.cameraServo||!v.cameraServo.enabled?null:v.cameraServo,[v]),g=d.useMemo(()=>!v?.nightVision||!v.nightVision.enabled?null:v.nightVision,[v]),x=d.useMemo(()=>!v?.horn||!v.horn.enabled?null:v.horn,[v]),z=d.useMemo(()=>v?.nightVision?.state??null,[v]),b=d.useCallback((T,R)=>{u&&s.emit("command",{roverId:u,...T},R)},[s,u]),y=d.useCallback(()=>{u&&b({type:"sensorStream",data:{sensorStream:{enable:!0}}})},[b,u]),H=d.useCallback(T=>{if(!u)return null;const R={left:C4(T?.left??0,[-500,500]),right:C4(T?.right??0,[-500,500])},j=a?a(R):R,F={left:C4(j?.left??0,[-500,500]),right:C4(j?.right??0,[-500,500])};return b({type:"drive",data:{driveDirect:F}}),F},[a,b,u]),S=d.useCallback(({main:T=0,side:R=0,vacuum:j=0}={})=>{if(!u)return null;const F={main:C4(T,r0.main),side:C4(R,r0.side),vacuum:C4(j,r0.vacuum)},U=l?l(F):F,O={main:C4(U?.main??0,r0.main),side:C4(U?.side??0,r0.side),vacuum:C4(U?.vacuum??0,r0.vacuum)};return b({type:"motors",data:{motorPwm:O}}),O},[l,b,u]),C=d.useCallback(T=>!u||!p?null:(b({type:"servo",data:{servo:{angle:T}}}),T),[b,u,p]),w=d.useCallback(T=>{if(!u)return!1;const R=Array.isArray(T)?T:typeof T=="string"?YP[T]:null;return R?(b({type:"raw",data:{raw:WP(R)}}),y(),!0):!1},[b,y,u]),L=d.useCallback(async T=>{if(!(!T||!Array.isArray(T.steps)||!u))for(const R of T.steps){if(!u)break;switch(R.type){case"oi":w(R.command);break;case"drive":H(R.speeds??{left:0,right:0});break;case"motors":S(R.values??{});break;case"servo":C(R.angle);break;case"pause":await Ji(R.duration??zc);break}if(R.delay||R.delayMs){const j=R.delayMs??R.delay;typeof j=="number"&&j>0&&await Ji(j)}}},[u,w,H,S,C]),A=d.useCallback((T="toggle")=>!u||!g?null:(b({type:"nightVision",data:{nightVision:{action:T}}}),T),[b,g,u]),V=d.useCallback(T=>u?(b({type:"horn",data:{horn:T}}),T):null,[b,u]),N=d.useCallback((T=[],R={})=>{if(!u)return null;const F=(Array.isArray(T)&&T.length>0?T:[{note:x0,duration:bc}]).slice(0,16).map(U=>({note:C4(Math.round(U?.note??x0),Wc),duration:C4(Math.round(U?.duration??bc),[1,255])}));return b({type:"song",data:{song:{notes:F,slot:R.slot,loop:R.loop}}}),F},[b,u]);return d.useMemo(()=>({roverId:u,rosterEntry:v,servoConfig:p,nightVision:g,nightVisionState:z,horn:x,emitCommand:b,enableSensorStream:y,sendDriveDirect:H,sendAuxMotors:S,sendServoAngle:C,sendOiCommand:w,sendNightVision:A,sendHorn:V,sendSong:N,runMacroSteps:L}),[u,v,p,g,z,x,b,y,H,S,C,w,A,V,L])}const eY={"{":"[","}":"]",":":";",'"':"'","<":",",">":".","?":"/","|":"\\",_:"-","+":"="},Wi={"[":"BracketLeft","]":"BracketRight","\\":"Backslash",";":"Semicolon","'":"Quote",",":"Comma",".":"Period","/":"Slash","-":"Minus","=":"Equal","`":"Backquote"};function $8(t){if(typeof t!="string")return"";const a=t.toLowerCase();return eY[a]??a}function cY(t){const a=$8(t);if(!a)return null;if(Wi[a])return Wi[a];if(a.length===1){if(/[a-z]/.test(a))return`Key${a.toUpperCase()}`;if(/[0-9]/.test(a))return`Digit${a}`}return null}function eu(t){const a=$8(t);return a?`key:${a}`:null}function aY(t){const a=cY(t);return a?`code:${a}`:null}function ts(t){const a=new Set,l=eu(t?.key??"");l&&a.add(l);const s=t?.code?`code:${t.code}`:null;return s&&a.add(s),Array.from(a)}function cu(t={}){return Object.fromEntries(Object.entries(t).map(([a,l])=>{const s=Array.isArray(l)?l:[l],u=new Set;return s.forEach(f=>{const v=eu(String(f));v&&u.add(v);const p=aY(String(f));p&&u.add(p)}),[a,u]}))}function _2(t){const a=$8(t);return a?a===" "?"Space":a==="\\"?"Backslash":a==="`"?"Backtick":a==="["?"[ or {":a==="]"?"] or }":a===";"?"; or :":a==="'"?`' or "`:a===","?", or <":a==="."?". or >":a==="/"?"/ or ?":a==="-"?"- or _":a==="="?"= or +":a==="arrowup"?"Arrow Up":a==="arrowdown"?"Arrow Down":a==="arrowleft"?"Arrow Left":a==="arrowright"?"Arrow Right":a.length===1?a.toUpperCase():a:"—"}const R4={keyboard:{baseSpeed:250,turboSpeed:500,precisionSpeed:125,tiltSpeed:90,tiltIntervalMs:110}},d3={label:"Default",calibration:{driveDeadzone:.18,cameraDeadzone:.08,auxDeadzone:.05,driveCurve:"linear",cameraCurve:"linear",auxCurve:"linear",cameraMode:"absolute",cameraSensitivity:60,auxSideScale:.55},bindings:{drive:{kind:"axisPair",sources:[{kind:"axisPair",x:0,y:1,invertX:!1,invertY:!0}]},cameraTilt:{kind:"axis",sources:[{kind:"axis",index:3,invert:!0},{kind:"axis",index:1,invert:!0}]},mainBrush:{kind:"axis",sources:[{kind:"buttonAxis",index:6},{kind:"axis",index:2,invert:!1}]},sideBrush:{kind:"axis",sources:[{kind:"buttonAxis",index:7},{kind:"axis",index:5,invert:!1}]},vacuum:{kind:"button",sources:[{kind:"button",index:0}]},allAux:{kind:"button",sources:[{kind:"button",index:1}]},mainReverse:{kind:"button",sources:[{kind:"button",index:4}]},sideReverse:{kind:"button",sources:[{kind:"button",index:5}]},driveMacro:{kind:"button",sources:[{kind:"button",index:2}]},dockMacro:{kind:"button",sources:[{kind:"button",index:3}]},nightVisionToggle:{kind:"button",sources:[{kind:"button",index:9}]}}},Z3={activeSignature:null,profiles:{},defaults:{profile:d3}},g6={waveform:"saw",freqs:[440,550,660,0]},x2={masterVolume:1,alertVolume:.5,roverVolume:1,mainBrushDuckEnabled:!0,mainBrushDuckAmount:.75},H0={colorFilter:"none"},v6=[{key:"drive",motors:["leftWheel","rightWheel"]},{key:"aux",motors:["mainBrush","sideBrush"]}],nY={downRatePerSec:.15,upRatePerSec:.7,releaseDelaySec:1,outputRateMs:250};function es(){return v6.reduce((t,a)=>(t[a.key]={cap:1,clearSec:0},t),{})}function cs(t){return Number.isFinite(t)?Math.max(0,Math.min(1,t)):0}function au(t,a={}){const l=u1(C=>C.session?.role||null),s=b6(t,qo,_o),u=d.useMemo(()=>({...nY,...a.config||{}}),[a.config]),[f,v]=d.useState(()=>es()),p=d.useRef(0),g=d.useRef(s);d.useEffect(()=>{g.current=s||{}},[s]),d.useEffect(()=>{v(es()),p.current=0},[t]);const x=d.useMemo(()=>v6.some(C=>C.motors.some(w=>!!s?.[w])),[s]),z=d.useMemo(()=>Object.values(f||{}).some(C=>(Number.isFinite(C?.cap)?C.cap:1)<.999),[f]),b=!!t&&(x||z);d.useEffect(()=>{if(!b)return;p.current=typeof performance<"u"?performance.now():Date.now();const C=setInterval(()=>{const w=typeof performance<"u"?performance.now():Date.now(),L=Math.max(0,w-p.current);p.current=w;const A=Math.min(.25,L/1e3);A<=0||v(V=>{let N=!1;const T={},R=Number.isFinite(u.downRatePerSec)?Math.max(0,u.downRatePerSec):0,j=Number.isFinite(u.upRatePerSec)?Math.max(0,u.upRatePerSec):0,F=Number.isFinite(u.releaseDelaySec)?Math.max(0,u.releaseDelaySec):0;return v6.forEach(U=>{const O=V[U.key]||{cap:1,clearSec:0},q=Number.isFinite(O.cap)?O.cap:1,$=Number.isFinite(O.clearSec)?O.clearSec:0,e1=U.motors.some(I=>!!g.current?.[I]),n1=e1?0:$+A,J=!e1&&n1>=F,k=cs(e1?q-R*A:J?q+j*A:q);(Math.abs(k-q)>1e-4||Math.abs(n1-$)>1e-4)&&(N=!0),T[U.key]={cap:k,clearSec:n1}}),N?T:V})},100);return()=>clearInterval(C)},[u.downRatePerSec,u.releaseDelaySec,u.upRatePerSec,t,b]);const y=d.useMemo(()=>{const C=v6.reduce((w,L)=>{const A=f?.[L.key],V=Number.isFinite(A?.cap)?A.cap:1;return w[L.key]=cs(V),w},{});return{perGroup:C,drive:{left:C.drive??1,right:C.drive??1},aux:{main:C.aux??1,side:C.aux??1,vacuum:1}}},[f]),H=d.useMemo(()=>{const C={};v6.forEach(L=>{L.motors.forEach(A=>{C[A]=!!s?.[A]})});const w=v6.reduce((L,A)=>(L[A.key]=A.motors.some(V=>!!s?.[V]),L),{});return{motors:C,groups:w}},[s]),S=l==="admin"||l==="lockdown"||l==="lockdown-admin";return d.useMemo(()=>({caps:f,overcurrent:H,scales:y,isActive:(y?.drive?.left??1)<1||(y?.drive?.right??1)<1||(y?.aux?.main??1)<1||(y?.aux?.side??1)<1,config:u,adminImmune:S}),[f,H,y,u,S])}function lY(t={},a,l=!1){if(l||!a?.drive)return t;const s=typeof a.drive.left=="number"?a.drive.left:1,u=typeof a.drive.right=="number"?a.drive.right:1;return s>=.999&&u>=.999?t:{left:Math.round((t.left??0)*s),right:Math.round((t.right??0)*u)}}function rY(t={},a,l=!1){if(l||!a?.aux)return t;const s=typeof a.aux.main=="number"?a.aux.main:1,u=typeof a.aux.side=="number"?a.aux.side:1,f=typeof a.aux.vacuum=="number"?a.aux.vacuum:1;return s>=.999&&u>=.999&&f>=.999?t:{main:Math.round((t.main??0)*s),side:Math.round((t.side??0)*u),vacuum:Math.round((t.vacuum??0)*f)}}const ta=d.createContext(null);function iY(t){return typeof t=="function"?t:a=>a}const sY=["setMode","setDriveVector","setAuxMotors","setServoAngle","nudgeServo","goServoHome","runMacro","stopAllMotion","sendOiCommand","setSensorStream","setNightVision","toggleNightVision","updateKeyBinding","resetKeyBindings","registerInputState","setManualDockAssistActive","toggleManualDockAssist","setSongNote","sendSong","startHorn","stopHorn","setMicPttActive"];function as(t){return Object.fromEntries(Object.entries(t||{}).map(([a,l])=>[a,Array.isArray(l)?[...l]:[]]))}function oY(t,a){if(!t)return a;const l=typeof t.minAngle=="number"?t.minAngle:-45,s=typeof t.maxAngle=="number"?t.maxAngle:45;return z0(a,l,s)}function uY(t=[]){if(!Array.isArray(t)||t.length<3)return t;const a=t.slice(-3),[l,s,u]=a,f=l?.type==="drive"&&Number(l?.speeds?.left)===-300&&Number(l?.speeds?.right)===-300,v=s?.type==="pause"&&Number(s?.duration)===600,p=u?.type==="drive"&&Number(u?.speeds?.left)===0&&Number(u?.speeds?.right)===0;return!f||!v||!p?t:t.slice(0,-3)}function hY({children:t}){const[a,l]=d.useReducer(QP,Qi),s=d.useRef(null),u=d.useRef(new Set),f=d.useRef({}),[v]=d.useState(()=>Object.fromEntries(sY.map(o1=>[o1,(...P)=>f.current[o1]?.(...P)])),[]),p=d.useCallback(()=>s.current,[]),g=d.useCallback((o1,P,c1=Object.is)=>{const z1=iY(o1),r2=s.current,i2={selector:z1,equalityFn:c1,listener:P,current:z1(r2)};return u.current.add(i2),()=>{u.current.delete(i2)}},[]),x=d.useCallback(o1=>{u.current.forEach(P=>{const c1=P.selector(o1);P.equalityFn(P.current,c1)||(P.current=c1,P.listener(c1))})},[]),z=d.useRef(null),b=d.useRef(!1),y=d.useRef(Qi.camera.angle),H=d.useRef(null),S=d.useRef(0),C=d.useRef(0),{value:w,save:L}=T1("controls",{keymap:B8,macros:tu}),{value:A}=T1("page",{driveMacroBackoffEnabled:!0}),{value:V}=T1("horn",g6),N=typeof A?.driveMacroBackoffEnabled=="boolean"?A.driveMacroBackoffEnabled:!0,T=u1(o1=>o1.session?.assignment?.roverId??null),R=u1(o1=>o1.session?.homeAssistant?.entities??[]),{homeAssistantSetState:j}=I2(),F=au(T),U=d.useCallback(o1=>lY(o1,F.scales,F.adminImmune),[F.adminImmune,F.scales]),O=d.useCallback(o1=>rY(o1,F.scales,F.adminImmune),[F.adminImmune,F.scales]),q=tY({driveTransform:U,auxTransform:O}),$=d.useCallback(()=>{const P=(R||[]).filter(c1=>(c1.type==="light"||c1.type==="switch")&&c1.available!==!1&&c1.state!=="on");if(P.length===0){b.current=!1;return}b.current=!0,P.forEach(c1=>{j(c1.id,"on").catch(()=>{})}),b.current=!1},[R,j]);d.useEffect(()=>{l({type:"control/set-rover",payload:q.roverId})},[q.roverId]),d.useEffect(()=>{const o1=z.current;z.current=a.mode,o1!=="drive"&&a.mode==="drive"&&R?.length?$():o1!=="drive"&&a.mode==="drive"&&(b.current=!0)},[a.mode,R,$]),d.useEffect(()=>{b.current&&R?.length&&$()},[R,$]),d.useEffect(()=>{const o1={...B8,...w?.keymap||{}};l({type:"control/set-keymap",payload:o1}),w?.macros&&l({type:"control/set-macros",payload:w.macros})},[w?.keymap,w?.macros]),d.useEffect(()=>{const o1=q.servoConfig;if(!o1){l({type:"control/set-camera-config",payload:{config:null}}),y.current=null;return}const P=typeof o1.minAngle=="number"?o1.minAngle:-45,c1=typeof o1.maxAngle=="number"?o1.maxAngle:45,z1=typeof o1.homeAngle=="number"?o1.homeAngle:(P+c1)/2,r2=typeof y.current=="number"?z0(y.current,P,c1):null,i2=r2??z0(z1,P,c1);l({type:"control/set-camera-config",payload:{config:o1,angle:i2}}),y.current=i2},[q.servoConfig]),d.useEffect(()=>{y.current=typeof a.camera.angle=="number"?a.camera.angle:y.current},[a.camera.angle]),d.useEffect(()=>{q.roverId&&q.enableSensorStream()},[q]);const e1=d.useCallback(o1=>{l({type:"control/set-mode",payload:o1})},[]),n1=d.useCallback(()=>{l({type:"control/record-intent"})},[]),J=d.useRef(a.drive.speeds),k=d.useRef(a.aux),I=d.useMemo(()=>JSON.stringify(F.scales),[F.scales]),t1=d.useRef(0),f1=d.useRef(0);d.useEffect(()=>{J.current=a.drive.speeds},[a.drive.speeds]),d.useEffect(()=>{k.current=a.aux},[a.aux]),d.useEffect(()=>{if(!q.roverId||F.adminImmune||!F.isActive)return;const o1=Math.max(0,Number(F?.config?.outputRateMs)||0),P=typeof performance<"u"?performance.now():Date.now(),c1=J.current||{left:0,right:0},z1=k.current||{main:0,side:0,vacuum:0},r2=!!(c1.left||c1.right),i2=!!(z1.main||z1.side||z1.vacuum);!r2&&!i2||(r2&&P-t1.current>=o1&&(t1.current=P,q.sendDriveDirect(c1)),i2&&P-f1.current>=o1&&(f1.current=P,q.sendAuxMotors(z1)))},[I,F.adminImmune,F.config,F.isActive,q]);const m1=d.useCallback((o1,P={})=>{const c1={...P.speedOptions||{}};if(a.manualDockAssist?.active){const r2=Math.max(1,Math.min($P,500));c1.maxSpeed=Math.min(typeof c1.maxSpeed=="number"?c1.maxSpeed:r2,r2),c1.baseSpeed=Math.min(typeof c1.baseSpeed=="number"?c1.baseSpeed:r2,r2),c1.boostSpeed=Math.min(typeof c1.boostSpeed=="number"?c1.boostSpeed:r2,r2)}const z1=JP(o1,c1);l({type:"control/update-drive",payload:{...z1,source:P.source??null}}),n1(),q.sendDriveDirect(z1.speeds)},[q,n1,a.manualDockAssist?.active]),E=d.useCallback((o1={})=>{const P=q.sendAuxMotors(o1)??o1;l({type:"control/set-aux-motors",payload:P}),n1()},[q,n1]),_=d.useCallback((o1,P)=>{if(!o1)return!1;const c1=$8(P);if(!c1)return!1;const z1=as(a.keymap);return z1[o1]=[c1],l({type:"control/set-keymap",payload:z1}),L(r2=>({...r2??{},keymap:z1})),!0},[a.keymap,L]),K=d.useCallback(()=>{const o1=as(B8);l({type:"control/set-keymap",payload:o1}),L(P=>({...P??{},keymap:o1}))},[L]),r1=d.useCallback((o1,P={})=>{if(!q.servoConfig)return;const c1=!!P?.force;if(a.manualDockAssist?.active&&!c1)return;const z1=oY(q.servoConfig,o1);l({type:"control/set-camera-angle",payload:z1}),q.sendServoAngle(z1),y.current=z1,n1()},[q,n1,a.manualDockAssist?.active]),v1=d.useCallback((o1=0)=>{const P=q.servoConfig;if(!P)return;const c1=typeof o1=="number"&&o1!==0?o1:P.nudgeDegrees||1,z1=typeof y.current=="number"?y.current:typeof P.homeAngle=="number"?P.homeAngle:0;r1(z1+c1)},[q.servoConfig,r1]),g1=d.useCallback(()=>{const o1=q.servoConfig;if(!o1)return;const P=typeof o1.homeAngle=="number"?o1.homeAngle:typeof o1.minAngle=="number"&&typeof o1.maxAngle=="number"?(o1.minAngle+o1.maxAngle)/2:0;r1(P)},[q.servoConfig,r1]),V1=d.useCallback(async o1=>{const P=a.macros.find(z1=>z1.id===o1)||null;if(!P)return;let c1=P;o1==="drive-sequence"&&($(),R?.length||(b.current=!0),n1(),N||(c1={...P,steps:uY(P.steps)})),await q.runMacroSteps(c1)},[N,q,n1,R,a.macros,$]),S1=d.useCallback(()=>{l({type:"control/update-drive",payload:{vector:{x:0,y:0,boost:!1},speeds:{left:0,right:0},source:"system-stop"}}),q.sendDriveDirect({left:0,right:0}),q.sendAuxMotors({main:0,side:0,vacuum:0})},[q]),N1=d.useCallback(o1=>{q.sendOiCommand(o1)},[q]),P1=d.useCallback(o1=>{q.roverId&&q.emitCommand({type:"sensorStream",data:{sensorStream:{enable:o1}}})},[q]),Y1=d.useCallback(o1=>{if(q.nightVision){if(typeof o1=="boolean"){const P=o1?"off":"on";q.sendNightVision(P)}else q.sendNightVision("toggle");n1()}},[q,n1]),R1=d.useCallback(()=>{Y1()},[Y1]),p2=d.useCallback(o1=>{const P=typeof o1=="number"?o1:x0;return l({type:"control/set-song-note",payload:P}),P},[]),s1=d.useCallback((o1,P)=>q.sendSong(o1,P),[q]),H1=d.useMemo(()=>{const o1=V??g6,P=o1.waveform==="sine"?"sine":"saw",z1=[...Array.isArray(o1.freqs)?o1.freqs:g6.freqs,0,0,0,0].slice(0,4).map(r2=>{const i2=Number(r2);return Number.isFinite(i2)?i2<=0?0:Math.min($t,Math.round(i2)):0});return{waveform:P,freqs:z1}},[V]),p1=d.useRef(null),x1=d.useCallback(()=>{if(!q.horn)return;if(a.horn?.overheated||(a.horn?.heat??0)>=1||a.horn?.active)return!1;const o1=Date.now();return q.sendHorn({action:"start",...H1}),l({type:"control/set-horn-active",payload:!0}),S.current=o1,C.current=o1,H.current&&(clearTimeout(H.current),H.current=null),H.current=setTimeout(()=>{p1.current?.()},GP),n1(),!0},[l,H1,q,n1,a.horn?.active,a.horn?.heat,a.horn?.overheated]),L1=d.useCallback(()=>{if(!q.horn)return;q.sendHorn({action:"stop"}),l({type:"control/set-horn-active",payload:!1}),H.current&&(clearTimeout(H.current),H.current=null);const o1=Date.now(),P=S.current||o1,c1=Math.max(0,o1-P);if(S.current=0,c1>0){const z1=a.horn?.heat??0,r2=c1/1e3*Ki;let i2=Math.max(0,Math.min(1,z1+r2)),M2=a.horn?.overheated??!1;i2>=1&&(i2=1,M2=!0),l({type:"control/set-horn-heat",payload:{heat:i2,overheated:M2}})}},[l,q,a.horn?.heat,a.horn?.overheated]),F1=d.useRef({active:!!a.horn?.active,heat:a.horn?.heat??0,overheated:!!a.horn?.overheated});d.useEffect(()=>{F1.current={active:!!a.horn?.active,heat:a.horn?.heat??0,overheated:!!a.horn?.overheated}},[a.horn?.active,a.horn?.heat,a.horn?.overheated]),d.useEffect(()=>{p1.current=L1},[L1]);const h1=!!a.horn?.active||(a.horn?.heat??0)>0||!!a.horn?.overheated;d.useEffect(()=>{if(!h1)return;const P=setInterval(()=>{const c1=Date.now(),z1=C.current||c1;C.current=c1;const r2=Math.min(1e3,Math.max(0,c1-z1))/1e3,i2=F1.current,M2=i2.heat??0,n4=!!i2.active,b1=!!i2.overheated,h2=r2*(n4?Ki:-.2);let c2=Math.max(0,Math.min(1,M2+h2)),U1=b1;c2>=1?(c2=1,U1=!0,n4&&p1.current()):U1&&c2<=PP&&(U1=!1),(c2!==M2||U1!==b1)&&l({type:"control/set-horn-heat",payload:{heat:c2,overheated:U1}})},100);return()=>clearInterval(P)},[l,h1]);const y1=d.useCallback(o1=>{const P=!!o1;if(!!a.manualDockAssist?.active===P)return;if(l({type:"control/set-manual-dock-assist",payload:P}),!P){q.sendSong([{note:83,duration:10},{note:76,duration:10}],{slot:0}),r1(0,{force:!0});return}const z1=typeof q.servoConfig?.minAngle=="number"?q.servoConfig.minAngle:-45;r1(z1,{force:!0}),q.sendSong([{note:76,duration:10},{note:83,duration:10}],{slot:0}),n1()},[q,n1,r1,a.manualDockAssist?.active]),k1=d.useCallback(()=>{y1(!a.manualDockAssist?.active)},[y1,a.manualDockAssist?.active]),X1=d.useCallback((o1,P)=>{l({type:"control/register-input-state",payload:{source:o1,state:P}})},[]),C1=d.useCallback(o1=>{l({type:"control/set-mic-ptt",payload:!!o1})},[]),g2=d.useMemo(()=>({setMode:e1,setDriveVector:m1,setAuxMotors:E,setServoAngle:r1,nudgeServo:v1,goServoHome:g1,runMacro:V1,stopAllMotion:S1,sendOiCommand:N1,setSensorStream:P1,setNightVision:Y1,toggleNightVision:R1,updateKeyBinding:_,resetKeyBindings:K,registerInputState:X1,setManualDockAssistActive:y1,toggleManualDockAssist:k1,setSongNote:p2,sendSong:s1,startHorn:x1,stopHorn:L1,setMicPttActive:C1}),[e1,m1,E,r1,v1,g1,V1,S1,N1,P1,Y1,R1,_,K,X1,y1,k1,p2,s1,x1,L1,C1]),t2=d.useMemo(()=>({state:a,dispatch:l,pipeline:q,overcurrentLimiter:F,actions:v}),[a,q,F,v]);s.current==null&&(s.current=t2),d.useLayoutEffect(()=>{f.current=g2},[g2]),d.useLayoutEffect(()=>{s.current!==t2&&(s.current=t2,x(t2))},[x,t2]);const e2=d.useMemo(()=>({getSnapshot:p,subscribe:g,actions:v}),[p,v,g]);return r.jsx(ta.Provider,{value:e2,children:t})}function q1(t,a=Object.is){const l=d.useContext(ta);if(!l)throw new Error("useControlSelector must be used within ControlSystemProvider");const s=d.useRef(t),u=d.useRef(a),[f,v]=d.useState(()=>t(l.getSnapshot()));return d.useEffect(()=>{s.current=t,u.current=a},[a,t]),d.useEffect(()=>(v(p=>{const g=s.current(l.getSnapshot());return u.current(p,g)?p:g}),l.subscribe(p=>s.current(p),p=>{v(g=>u.current(g,p)?g:p)},(p,g)=>u.current(p,g))),[l]),f}function x3(){const t=d.useContext(ta);if(!t)throw new Error("useControlActions must be used within ControlSystemProvider");return t.actions}const dY="data:audio/mpeg;base64,//uQxAAAAAAAAAAAAAAAAAAAAAAAWGluZwAAAA8AAAANAAAIpQBKSkpKSkpKXFxcXFxcXFxra2tra2tra3p6enp6enqJiYmJiYmJiZiYmJiYmJiYpqampqamprW1tbW1tbW1xMTExMTExMTT09PT09PT4uLi4uLi4uLx8fHx8fHx8f////////8AAABQTEFNRTMuMTAwBLkAAAAAAAAAABUgJAUYQQAB4AAACKVpqtMZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//ugxAAAwqQPR8CIwCh0BCj5jDwlIAAjW87wAACcOsAKPMk8ARj8w9OAWwNlV/gCgQMHEhAOVnFaNzWWAPI2zyjHjd8FAoKqyAa88AAAAABNjEd9CQOglIY9dtC+a51bGZrZgTewD3c+AAYx5hxIMheIcudKAyaykG1/h5EsPB0iTEFNRTMuMTAwqqqqqqrIBZqvAAAAAC9JXFIAHrCgAp0D0hUYOInIluqg1TNdKCzMeAAFQCKKsxUmVfireKILLBgSVgb4qBVtPWpMQU1FMy4xMDCqqqqqqqqqqqqqqqqpApm/AAAAAC7QYaHPHoCjkCysmc+QY9NNWRbKE+mqowNobwAAoSQQMLGChDlOrKMqVMC/6xy/CXbFaL7AZUxBTUUzLjEwMFVVVVVVVVVVVacDqZ8AAAAAMgzaYFBPNgIOnVCQfFfwmBBhLVNJQSdxdQRofwAGxF9xAAYs4AZDuE87li0YCASIBwaCiXUj+2BqTEFNRTMuMTAwqqqqqqqqlwOonwAAAAAtkABQSEZ1INNDgx8HeaaLCXiu5dqSciylQNXjv8GdmACQ5ogYKbnsmxkoChog+w9IhU6GsgzCIQBSxFpMQQAAMBiHjgAAAAv6FQQILmJmGLltnax9HszIVEAoEq1p8olpcPLlGpXFastuWosKNFlmlqADJbwAEFRI4iJJy0oDumUW//sgxOEAw5wfU8fnAGBvg6n5nDxUh7QuwcEzkK5Ztz7AZUxBTUUzLjEwMFVVVVVVVZUAhd8AAAAALZAAamQMWKtC7Avib0WLplt2IAp0SKV0pFFxCADLX6AIPFrWJIBQqPGW/x0QDTRLGaQYCRAZzKeoU6uqTEFN6AB3n/7wAAAxq//7EMT0AMPUHU/MawJgc4PpuYy8VQZjocBw2OgQQyQyECnbABEUC/ZoM0J56Jm0tqzNJaq8KospqUAQ5/QBghnCqQAhR4Mz1D1gJPstYsI1sYIg079I5cYjY6pMQU1FMy4xMDCqqqqq//sQxPUAw+AdT8zvAih6hCk5nWBFqqqWAFOf4AAAAEAIQZPkMcwUzFVE51cSBjIHpJRIEIjWgGar9VhgCUvwAFAUMk0RCpMkwXjPQDcoLBU+n5RuR4ZrPQLPckxBTUUzLjEwMKqqqqr/+xDE9oDEAB1NzG8CKIGEKPmd5EWqxgBWn9AAAAAKIiC5GcLJIczCEvNbWsF31jo4Bw0rXktvJF5YRyABlj+ABIQ2RGsHgdc0XsPntoEDUzaQOjTBqblFPUE1TEFNRckAt68AAAAALv/7EMT4AMQIHU3M7wIojwUo+Y2MZfAgKcwITAQIYN1TosJeLtDA0ubWNrFSADJoln4AC0hVaLiIIUChs+4HST4BgCpQHITPMBQkEnj73ORZfylh+sRLEGUiNIpMQU1FMy4xMDCqqqqq//sQxP6AxlgtK+13Yih3hCj5neBNqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrIkT7UNAZ7NS7yMqcihSKLMn8DlKYq8ZdPCVEoJBuWqkxBTUUzLjEwMKqqqqr/+xDE+ADEXCVHzGjDIIQEqLm9PIWqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv/7EMT+AMWoL0XNcwJoiASoeY3gVaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//sQxPgAxHAnRcxvAmiBBKj5jehEqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqr/+xDE+IDEmCVDzPMCKH6EqLmNYE2qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv/7EMT9gEPgI0vMZwQgvYWlPY5gFaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//sQxOYDw+gpIIfgwWgAADSAAAAEqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo=",fY=80,mY=80,vY=240,ns=new Map;function nu(){return typeof window>"u"?null:window.roverAnalytics&&typeof window.roverAnalytics=="object"?window.roverAnalytics:null}function lu(t){if(typeof t!="string")return null;const a=t.trim().toLowerCase().replace(/[^a-z0-9_:-]+/g,"_");return a?a.slice(0,fY):null}function ru(t){if(t!=null){if(typeof t=="boolean")return t;if(typeof t=="number")return Number.isFinite(t)?t:void 0;if(typeof t=="string"){const a=t.trim();return a?a.slice(0,vY):void 0}if(Array.isArray(t)){const a=t.map(l=>ru(l)).filter(l=>l!==void 0).map(l=>String(l));return a.length?a.slice(0,12).join(","):void 0}}}function ea(t={}){return!t||typeof t!="object"||Array.isArray(t)?{}:Object.entries(t).reduce((a,[l,s])=>{if(typeof l!="string")return a;const u=l.trim().replace(/[^a-zA-Z0-9_:-]+/g,"_").slice(0,mY);if(!u)return a;const f=ru(s);return f===void 0||(a[u]=f),a},{})}function d1(t,a={}){const l=lu(t);if(!l)return;const s=nu();if(!s||typeof s.track!="function")return;const u=ea(a);try{Object.keys(u).length?s.track(l,u):s.track(l)}catch(f){console.warn("Analytics event failed",f)}}function pY(t={}){const a=nu();if(!(!a||typeof a.identify!="function"))try{a.identify(ea(t))}catch(l){console.warn("Analytics identify failed",l)}}function v3(t,a={},l={}){const s=lu(t);if(!s)return;const u=Number.isFinite(l?.throttleMs)?Math.max(0,l.throttleMs):30*1e3,f=`${s}:${typeof l?.key=="string"?l.key:JSON.stringify(ea(a))}`,v=Date.now(),p=ns.get(f)||0;v-p{},focusChat:()=>{},blurChat:()=>{},registerInputRef:()=>{},onInputFocus:()=>{},onInputBlur:()=>{},setTypingActive:()=>{}},ou={isChatFocused:!1,selfSocketId:null},uu=d.createContext(iu),hu=d.createContext(su),du=d.createContext(ou),gY=d.createContext({...iu,...su,...ou});function xY({children:t}){const a=R2(),l=u1(E=>E.session),{pushAlert:s}=I2(),{value:u}=T1("audio",x2),{value:f}=T1("profile",{nickname:"",profileImageUrl:""}),[v,p]=d.useState([]),[g,x]=d.useState([]),[z,b]=d.useState(!1),y=d.useRef(null),H=d.useRef(null),S=d.useRef(null),C=d.useRef(new Map),w=d.useRef(new Map),L=d.useRef({isTyping:!1,lastSent:0}),A=Number.isFinite(u?.masterVolume)?u.masterVolume:x2.masterVolume,V=Number.isFinite(u?.alertVolume)?u.alertVolume:x2.alertVolume,N=Math.max(0,Math.min(1,A*V)),R=!!l?.isVerified?String(f?.profileImageUrl||"").trim():"",j=d.useCallback(()=>{const E=Array.from(C.current.values()).sort((_,K)=>_.lastUpdate-K.lastUpdate).map(_=>_.payload);x(E)},[]),F=d.useCallback(E=>!E||typeof E!="object"?null:E.typingId?E.typingId:E.fromDiscord?`discord:${E.discordUserId||E.discordUserName||E.nickname||"unknown"}`:`socket:${E.socketId||E.nickname||"unknown"}`,[]);d.useEffect(()=>{S.current=new Audio(dY),S.current.volume=N,S.current.load()},[N]);const U=d.useCallback(()=>{const E=S.current;E&&(E.volume=N,E.currentTime=0,E.play().catch(()=>{}))},[N]);d.useEffect(()=>{function E(_={}){p(K=>[...K.slice(-99),_]),!(_?.socketId&&l?.socketId&&_.socketId===l.socketId)&&(U(),s?.({kind:"chat",payload:_,id:`chat-${_.id||Math.random().toString(36).slice(2)}`,receivedAt:Date.now()}))}return a.on("chat:message",E),()=>{a.off("chat:message",E)}},[U,s,l?.socketId,a]),d.useEffect(()=>{function E(_={}){const K=F(_);if(!K)return;const r1=Date.now();if(_?.socketId&&l?.socketId&&_.socketId===l.socketId){_.isTyping||(C.current.delete(K),j());return}if(_.isTyping){C.current.set(K,{payload:_,expiresAt:r1+6e3,lastUpdate:r1});const v1=w.current.get(K)||0;r1-v1>=2500&&(w.current.set(K,r1),s?.({kind:"chat-typing",payload:_,id:`chat-typing-${K}-${_.id||Math.random().toString(36).slice(2)}`,receivedAt:r1}))}else C.current.delete(K);j()}return a.on("chat:typing",E),()=>{a.off("chat:typing",E)}},[s,j,F,l?.socketId,a]),d.useEffect(()=>{const E=setInterval(()=>{const _=Date.now();let K=!1;C.current.forEach((r1,v1)=>{r1.expiresAt<=_&&(C.current.delete(v1),K=!0)}),K&&j()},2e3);return()=>clearInterval(E)},[j]),d.useEffect(()=>{function E(_=[]){Array.isArray(_)&&p(K=>{if(K.length===0)return _.slice(-100);const r1=new Set(_.map(g1=>g1?.id));return[..._,...K.filter(g1=>g1?.id&&!r1.has(g1.id))].slice(-100)})}return a.on("chat:init",E),()=>{a.off("chat:init",E)}},[a]);const O=d.useCallback(E=>{const _=!!E,K=Date.now(),r1=L.current,v1=!_&&r1.isTyping;!(_&&(!r1.isTyping||K-r1.lastSent>=3500))&&!v1||(L.current={isTyping:_,lastSent:K},a.emit("chat:typing",{isTyping:_}))},[a]),q=d.useCallback((E,_=null)=>new Promise((K,r1)=>{const v1={text:E,tts:_};R&&(v1.profileImage=R),a.emit("chat:send",v1,(g1={})=>{g1.error?r1(new Error(g1.error)):(d1("chat_send",{hasTts:!!_,length:typeof E=="string"?E.trim().length:0}),K(g1))})}),[R,a]),$=d.useCallback((E,_={})=>{(_?.target==="hud"?"hud":"panel")==="hud"?H.current=E:y.current=E},[]),e1=d.useCallback(()=>{b(!0),(H.current||y.current)?.focus()},[]),n1=d.useCallback(()=>{b(!1),H.current?.blur(),y.current?.blur()},[]),J=d.useCallback(()=>b(!0),[]),k=d.useCallback(()=>b(!1),[]),I=d.useMemo(()=>({messages:v,typing:g}),[v,g]),t1=d.useMemo(()=>({sendMessage:q,focusChat:e1,blurChat:n1,registerInputRef:$,onInputFocus:J,onInputBlur:k,setTypingActive:O}),[n1,e1,k,J,$,q,O]),f1=d.useMemo(()=>({isChatFocused:z,selfSocketId:l?.socketId||null}),[z,l?.socketId]),m1=d.useMemo(()=>({...I,...t1,...f1}),[t1,f1,I]);return r.jsx(uu.Provider,{value:I,children:r.jsx(hu.Provider,{value:t1,children:r.jsx(du.Provider,{value:f1,children:r.jsx(gY.Provider,{value:m1,children:t})})})})}function zY(){const t=d.useContext(uu);if(!t)throw new Error("useChatTimeline must be used inside ChatProvider");return t}function ca(){const t=d.useContext(hu);if(!t)throw new Error("useChatActions must be used inside ChatProvider");return t}function bY(){const t=d.useContext(du);if(!t)throw new Error("useChatFocus must be used inside ChatProvider");return t}let fu=!1;function U9(t){fu=!!t}function ls(){return fu}const MY=new Set(["","text","search","email","password","url","tel","number","date","datetime-local","month","time","week"]);function mu(t){if(!t||t.nodeType!==1)return!1;const a=t.tagName;if(a==="TEXTAREA"||t.isContentEditable)return!0;if(a!=="INPUT")return!1;const l=t.type?t.type.toLowerCase():"";return MY.has(l)}function yY(){return typeof document>"u"?!1:mu(document.activeElement)}function A0(t={}){const{manageLifecycle:a=!1}=t,l=q1(w=>w.state.roverId),s=q1(w=>!!w.state.manualDockAssist?.active),u=x3(),f=b6(l,Gc,$c),v=f.chargingStateLabel||"",p=!!f.homeBase,g=p&&v.toLowerCase()!=="not charging"&&v!=="",x=d.useRef(!1),z=d.useCallback(()=>{u.setManualDockAssistActive(!0)},[u]),b=d.useCallback(()=>{u.setManualDockAssistActive(!1)},[u]),y=d.useCallback(()=>{u.toggleManualDockAssist()},[u]);d.useEffect(()=>{if(!a)return;const w=p&&!x.current,L=!p&&x.current;s&&w?u.sendSong([{note:84,duration:6}],{slot:1}):s&&L&&u.sendSong([{note:72,duration:6}],{slot:1}),x.current=p},[u,s,p,a]),d.useEffect(()=>{!a||!s||!g||b()},[s,g,b,a]);const H=g?"Docked and charging":p?"Docked":"Docking assist active",S=g?"good":p?"warn":"active",C=s||p;return d.useMemo(()=>({active:s,docked:p,charging:g,cameraLocked:s,visible:C,statusLabel:H,statusTone:S,enterAssist:z,exitAssist:b,toggleAssist:y}),[s,g,p,z,b,H,S,y,C])}function Z9(t,a){const l=Number(t);return Number.isFinite(l)?Math.max(0,Math.min(500,l)):a}function vu(t){const a=R4.keyboard,l=t?.keyboard??{};return{baseSpeed:Z9(l.baseSpeed,a.baseSpeed),turboSpeed:Z9(l.turboSpeed,a.turboSpeed),precisionSpeed:Z9(l.precisionSpeed,a.precisionSpeed)}}function L2(t,a){if(!t||t.size===0)return!1;for(const l of a)if(t.has(l))return!0;return!1}function pu(t,a){const l=L2(a.driveForward,t),s=L2(a.driveBackward,t),u=L2(a.driveLeft,t),f=L2(a.driveRight,t),v=L2(a.boostModifier,t),p=L2(a.slowModifier,t);let g=0;l&&!s?g=1:s&&!l&&(g=-1);let x=0;u&&!f?x=-1:f&&!u&&(x=1);const z=p?.4:1;return{x:x*z,y:g*z,boost:v&&!p}}function wY(t,a){if(L2(a.auxAllForward,t))return{main:127,side:127,vacuum:127};const s=L2(a.auxMainForward,t)?127:L2(a.auxMainReverse,t)?-127:0,u=L2(a.auxSideForward,t)?127:L2(a.auxSideReverse,t)?-70:0,f=L2(a.auxVacuumFast,t)?127:L2(a.auxVacuumSlow,t)?50:0;return{main:s,side:u,vacuum:f}}function gu(t,a,l){return L2(a.slowModifier,t)?{baseSpeed:l.precisionSpeed,boostSpeed:l.precisionSpeed}:{baseSpeed:l.baseSpeed,boostSpeed:l.turboSpeed}}const $9="keyboard",I9={x:0,y:0,boost:!1},G9={main:0,side:0,vacuum:0},rs=Wc[0],is=Wc[1],aa=5,k8=500,R8=1,na=100,Et=["none","grayscale","greenscale"];function xu(t){return Et.includes(t)?t:H0.colorFilter}function CY(t){const a=xu(t),l=Et.indexOf(a);return Et[(l+1)%Et.length]}function SY(t,a){const l=Number(t);return Number.isFinite(l)?Math.max(aa,Math.min(k8,l)):a}function zu(t,a){const l=Number(t);return Number.isFinite(l)?Math.max(R8,Math.min(na,l)):a}function HY(t){const l=(zu(t,t)-R8)/(na-R8),s=k8-l*(k8-aa);return Math.round(s)}function AY(t){const a=SY(t,t),l=(k8-a)/(k8-aa),s=R8+l*(na-R8);return Math.round(s)}function VY(t){return mu(t?.target)}function LY(){const{setMode:t,setDriveVector:a,setAuxMotors:l,nudgeServo:s,runMacro:u,stopAllMotion:f,registerInputState:v,toggleNightVision:p,startHorn:g,stopHorn:x,setMicPttActive:z,setSongNote:b,sendSong:y}=x3(),H=q1(p1=>p1.state.keymap),S=q1(p1=>p1.state.camera?.config?.nudgeDegrees),C=q1(p1=>p1.state.song?.note),w=q1(p1=>p1.state.roverId),L=q1(p1=>!!p1.state.horn?.active),A=u1(p1=>p1.session?.homeAssistant||null),V=A0(),{homeAssistantSetState:N,pushAlert:T}=I2(),{focusChat:R}=ca(),{isChatFocused:j}=bY(),{value:F}=T1("inputs",R4),{value:U,save:O}=T1("video",H0),q=xu(U?.colorFilter),$=d.useMemo(()=>cu(H),[H]),e1=d.useMemo(()=>{const p1=new Set;return Object.values($).forEach(x1=>{x1&&x1.forEach(L1=>p1.add(L1))}),p1},[$]),n1=d.useMemo(()=>vu(F),[F]),J=d.useMemo(()=>{const p1=R4.keyboard,x1=F?.keyboard??{},L1=zu(typeof x1.tiltSpeed=="number"?x1.tiltSpeed:typeof x1.tiltIntervalMs=="number"?AY(x1.tiltIntervalMs):p1.tiltSpeed,p1.tiltSpeed);return HY(L1)},[F?.keyboard]),k=d.useMemo(()=>Math.abs(S||1),[S]),I=d.useRef(new Set),t1=d.useRef(I9),f1=d.useRef(G9),m1=d.useRef(null),E=d.useRef(null),_=d.useRef(!1),K=d.useRef(null),r1=d.useCallback(()=>{const p1=K.current;if(!p1)return;const x1=new Set(I.current),L1=gu(x1,p1.keymap,p1.keyboardSpeeds),F1=pu(x1,p1.keymap),h1=wY(x1,p1.keymap);(F1.x!==t1.current.x||F1.y!==t1.current.y||F1.boost!==t1.current.boost)&&(t1.current=F1,p1.setDriveVector(F1,{source:$9,speedOptions:L1})),(h1.main!==f1.current.main||h1.side!==f1.current.side||h1.vacuum!==f1.current.vacuum)&&(f1.current=h1,p1.setAuxMotors(h1)),p1.registerInputState($9,{keys:Array.from(x1),vector:F1,aux:h1})},[]),v1=d.useCallback(()=>{m1.current&&(clearTimeout(m1.current),m1.current=null)},[]),g1=d.useCallback(()=>{const p1=K.current;if(!p1)return 0;const x1=new Set(I.current),L1=L2(p1.keymap.cameraUp,x1),F1=L2(p1.keymap.cameraDown,x1);return(L1?1:0)-(F1?1:0)},[]),V1=d.useCallback(()=>{if(g1()===0){v1();return}if(m1.current)return;const x1=()=>{const L1=g1();if(L1===0){v1();return}const F1=K.current;if(!F1){v1();return}F1.nudgeServo(L1*F1.servoStep),m1.current=setTimeout(x1,F1.servoRepeatMs)};m1.current=setTimeout(x1,0)},[g1,v1]),S1=d.useCallback(()=>{E.current&&(clearTimeout(E.current),E.current=null)},[]),N1=d.useCallback(()=>{const p1=K.current;if(!p1)return 0;const x1=new Set(I.current),L1=L2(p1.keymap.songNoteUp,x1),F1=L2(p1.keymap.songNoteDown,x1);return(L1?1:0)-(F1?1:0)},[]),P1=d.useCallback(p1=>{const x1=K.current;if(!x1||p1===0)return;let F1=(typeof x1.songNote=="number"?x1.songNote:x0)+p1;F1>is?F1=rs:F1{if(N1()===0){S1();return}if(E.current)return;const x1=()=>{const L1=N1();if(L1===0){S1();return}P1(L1),E.current=setTimeout(x1,IP)};E.current=setTimeout(x1,0)},[N1,S1,P1]),R1=d.useCallback(()=>{const p1=K.current;I.current.clear(),t1.current=I9,f1.current=G9,v1(),S1(),_.current&&(_.current=!1,p1?.stopHorn()),p1?.setMicPttActive(!1),p1?.stopAllMotion(),p1?.registerInputState($9,{keys:[],vector:I9,aux:G9})},[v1,S1]),p2=d.useCallback(p1=>{const x1=K.current,L1=x1?.homeAssistant;if(!L1?.enabled||!L1?.connected||L1?.lightPolicy?.locked||L1?.lightPolicy?.lockedOn)return;const h1=(L1.entities||[]).filter(y1=>(y1.type==="light"||y1.type==="switch")&&y1.available!==!1&&y1.state!=="unavailable");if(h1.length!==0){if(p1==="on"){const y1=h1.find(k1=>k1.state!=="on");y1&&x1.homeAssistantSetState(y1.id,"on").catch(()=>{});return}if(p1==="off")for(let y1=h1.length-1;y1>=0;y1-=1){const k1=h1[y1];if(k1.state==="on"){x1.homeAssistantSetState(k1.id,"off").catch(()=>{});break}}}},[]),s1=d.useCallback(()=>{const p1=K.current;if(!p1)return;const x1=CY(p1.videoColorFilter);p1.saveVideoSettings(L1=>({...L1??{},colorFilter:x1})),p1.pushAlert({id:"video-filter-active",title:"Video filter",message:`Rover video filter: ${x1}`,color:"#38bdf8",lifetimeMs:1600})},[]);d.useLayoutEffect(()=>{K.current={actionTokens:e1,dockAssist:V,focusChat:R,homeAssistant:A,homeAssistantSetState:N,isChatFocused:j,keyboardSpeeds:n1,keymap:$,nudgeServo:s,pushAlert:T,registerInputState:v,roverId:w,runMacro:u,saveVideoSettings:O,sendSong:y,servoRepeatMs:J,servoStep:k,setAuxMotors:l,setDriveVector:a,setMicPttActive:z,setMode:t,setSongNote:b,songNote:C,startHorn:g,stopAllMotion:f,stopHorn:x,toggleNightVision:p,videoColorFilter:q}}),d.useEffect(()=>{function p1(F1){const h1=K.current;if(!h1||ls()||VY(F1))return;const y1=ts(F1);if(y1.length===0)return;const k1=new Set(y1);if(L2(h1.keymap.chatFocus,k1)){F1.preventDefault(),R1(),h1.isChatFocused||h1.focusChat();return}y1.some(C1=>h1.actionTokens.has(C1))&&F1.preventDefault();const X1=y1.filter(C1=>!I.current.has(C1));if(X1.forEach(C1=>I.current.add(C1)),X1.length>0)if(X1.some(C1=>h1.keymap.driveMacro?.has(C1)))d1("drive_start",{roverId:h1.roverId||"",source:"keyboard"}),h1.dockAssist.exitAssist(),h1.setMode("drive"),h1.runMacro("drive-sequence");else if(X1.some(C1=>h1.keymap.dockMacro?.has(C1)))d1("dock_assist_toggle",{roverId:h1.roverId||"",source:"keyboard"}),h1.dockAssist.toggleAssist();else if(X1.some(C1=>h1.keymap.nightVisionToggle?.has(C1)))d1("night_vision_toggle",{roverId:h1.roverId||"",source:"keyboard"}),h1.toggleNightVision();else if(X1.some(C1=>h1.keymap.videoFilterCycle?.has(C1)))s1();else if(X1.some(C1=>h1.keymap.hornHonk?.has(C1))){if(!_.current){const C1=h1.startHorn();_.current=!!C1}}else X1.some(C1=>h1.keymap.micPtt?.has(C1))?h1.setMicPttActive(!0):X1.some(C1=>h1.keymap.homeAssistantOn?.has(C1))?p2("on"):X1.some(C1=>h1.keymap.homeAssistantOff?.has(C1))&&p2("off");V1(),Y1(),r1()}function x1(F1){const h1=K.current;if(!h1||ls())return;ts(F1).forEach(k1=>I.current.delete(k1)),_.current&&!L2(h1.keymap.hornHonk,I.current)&&(_.current=!1,h1.stopHorn()),L2(h1.keymap.micPtt,I.current)||h1.setMicPttActive(!1),V1(),Y1(),r1()}function L1(){R1()}return window.addEventListener("keydown",p1,{capture:!0}),window.addEventListener("keyup",x1,{capture:!0}),window.addEventListener("blur",L1),()=>{window.removeEventListener("keydown",p1,{capture:!0}),window.removeEventListener("keyup",x1,{capture:!0}),window.removeEventListener("blur",L1)}},[s1,r1,V1,Y1,R1,p2]);const H1=d.useRef(R1);return d.useEffect(()=>{H1.current=R1},[R1]),d.useEffect(()=>{H1.current()},[w]),d.useEffect(()=>{_.current=L},[L]),d.useEffect(()=>()=>{v1(),S1()},[v1,S1]),null}const BY=1.6;function bu(t){if(!t)return"unknown::none::0::0";const a=t.id||"unknown",l=t.mapping||"none",s=Array.isArray(t.axes)?t.axes.length:0,u=Array.isArray(t.buttons)?t.buttons.length:0;return`${a}::${l}::${s}::${u}`}function jY(t){return JSON.parse(JSON.stringify(t??{}))}function Mu(t,a){const l=jY(a);return l.meta={id:t?.id??"Unknown",mapping:t?.mapping??"none",axes:t?.axes?.length??0,buttons:t?.buttons?.length??0},l}function p6(t){return Number.isFinite(t)?Math.max(-1,Math.min(1,t)):0}function C8(t,a){if(!t)return 0;const l=Math.abs(t);return a==="expo"?Math.sign(t)*Math.pow(l,BY):t}function P9(t,a){const l=Math.abs(t);if(l<=a)return 0;const s=(l-a)/(1-a);return Math.sign(t)*s}function NY(t,a,l){const s=Math.hypot(t,a);if(s<=l)return{x:0,y:0};const f=(s-l)/(1-l)/s;return{x:t*f,y:a*f}}function It(t,a){if(!t||!Array.isArray(t.axes))return null;const l=t.axes[a];return Number.isFinite(l)?p6(l):null}function Cc(t,a){if(!t||!Array.isArray(t.buttons))return null;const l=t.buttons[a];if(!l)return null;const s=typeof l.value=="number"?l.value:l.pressed?1:0;return{pressed:!!(l.pressed||s>.5),value:Math.max(0,Math.min(1,s))}}function Y9(t,a=[]){for(const l of a)if(l){if(l.kind==="axis"){const s=It(t,l.index);if(s===null)continue;return{value:l.invert?-s:s,source:l}}if(l.kind==="buttonAxis"){const s=Cc(t,l.index);if(!s)continue;return{value:p6(s.value),source:l}}}return{value:0,source:null}}function FY(t,a=[]){for(const l of a){if(!l||l.kind!=="axisPair")continue;const s=It(t,l.x),u=It(t,l.y);if(s===null||u===null)continue;const f=l.invertX?-s:s,v=l.invertY?-u:u;return{x:f,y:v,source:l}}return{x:0,y:0,source:null}}function u6(t,a=[]){for(const l of a)if(l){if(l.kind==="button"){const s=Cc(t,l.index);if(!s)continue;return{pressed:s.pressed,source:l}}if(l.kind==="axisButton"){const s=It(t,l.index);if(s===null)continue;const u=l.direction||1,f=typeof l.threshold=="number"?l.threshold:.6;return{pressed:s*u>f,source:l}}if(l.kind==="buttonAxis"){const s=Cc(t,l.index);if(!s)continue;return{pressed:s.value>.5,source:l}}}return{pressed:!1,source:null}}function yu(t,a){const l=a?.bindings??{},s=a?.calibration??{},u=l.drive??{},f=FY(t,u.sources);let v=p6(f.x),p=p6(f.y);const g=Math.min(Math.max(s.driveDeadzone??.18,0),.8),x=NY(v,p,g);v=C8(x.x,s.driveCurve),p=C8(x.y,s.driveCurve);const z=l.cameraTilt??{},b=Y9(t,z.sources),y=Math.min(Math.max(s.cameraDeadzone??.08,0),.8);let H=P9(p6(b.value),y);H=C8(H,s.cameraCurve);const S=Math.min(Math.max(s.auxDeadzone??.05,0),.6),C=l.mainBrush??{},w=Y9(t,C.sources);let L=P9(p6(w.value),S);L=C8(L,s.auxCurve);const A=l.sideBrush??{},V=Y9(t,A.sources);let N=P9(p6(V.value),S);N=C8(N,s.auxCurve);const T=u6(t,l.vacuum?.sources),R=u6(t,l.allAux?.sources),j=u6(t,l.mainReverse?.sources),F=u6(t,l.sideReverse?.sources),U=u6(t,l.driveMacro?.sources),O=u6(t,l.dockMacro?.sources),q=u6(t,l.nightVisionToggle?.sources);return{driveVector:{x:v,y:p,boost:!1},cameraAxis:H,auxAxis:{main:L,side:N},buttons:{vacuum:T.pressed,allAux:R.pressed,mainReverse:j.pressed,sideReverse:F.pressed,driveMacro:U.pressed,dockMacro:O.pressed,nightVisionToggle:q.pressed},sources:{drive:f.source,cameraTilt:b.source,mainBrush:w.source,sideBrush:V.source,vacuum:T.source,allAux:R.source,mainReverse:j.source,sideReverse:F.source,driveMacro:U.source,dockMacro:O.source,nightVisionToggle:q.source}}}const L8=new Set;let p0=null,b0={pads:[],timestamp:0},ft=!1,mt=null;function ss(){return wu().some(t=>t?.connected!==!1)}function wu(){if(typeof navigator>"u"||!navigator.getGamepads)return[];const t=navigator.getGamepads();return t?Array.from(t).filter(Boolean):[]}function kY(t){return{index:t.index,id:t.id,mapping:t.mapping,connected:t.connected!==!1,timestamp:t.timestamp,axes:Array.from(t.axes??[]),buttons:(t.buttons??[]).map(a=>({pressed:!!a?.pressed,value:typeof a?.value=="number"?a.value:a?.pressed?1:0})),signature:bu(t)}}function Gt(){b0={pads:wu().map(kY),timestamp:typeof performance<"u"?performance.now():Date.now()},L8.forEach(a=>a(b0))}function Cu(){if(Gt(),b0.pads.length===0){Sc();return}p0=requestAnimationFrame(Cu)}function os(){p0||(Gt(),b0.pads.length!==0&&(p0=requestAnimationFrame(Cu)))}function Sc(){p0&&(cancelAnimationFrame(p0),p0=null)}function Su(t){if(L8.add(t),!ft&&typeof window<"u"){const a=()=>{Gt(),L8.size!==0&&(ss()?os():Sc())};window.addEventListener("gamepadconnected",a),window.addEventListener("gamepaddisconnected",a),mt=a,ft=!0}return ss()?os():Gt(),t(b0),()=>{L8.delete(t),L8.size===0&&(Sc(),ft&&typeof window<"u"&&(window.removeEventListener("gamepadconnected",mt),window.removeEventListener("gamepaddisconnected",mt),mt=null,ft=!1))}}function RY(){const[t,a]=d.useState(b0);return d.useEffect(()=>Su(a),[]),t}const i0="gamepad",h6={x:0,y:0,boost:!1},d6={main:0,side:0,vacuum:0},EY=100,TY=100;function K9(t,a){return t&&a&&t.x===a.x&&t.y===a.y&&t.boost===a.boost}function Q9(t,a){return t&&a&&t.main===a.main&&t.side===a.side&&t.vacuum===a.vacuum}function qY(t){return t?Math.hypot(t.x||0,t.y||0):0}function _Y(t){return t?!t.main&&!t.side&&!t.vacuum:!0}function DY(t,a){if(!t||t.length===0)return null;if(a){const l=t.find(s=>s.signature===a);if(l)return l}return t[0]}function OY(){const{setMode:t,setDriveVector:a,setAuxMotors:l,setServoAngle:s,runMacro:u,toggleNightVision:f,registerInputState:v}=x3(),p=q1(q=>q.state.camera?.angle),g=q1(q=>q.state.camera?.config),x=q1(q=>q.state.roverId),z=A0(),{value:b,save:y}=T1("gamepad",Z3),H=d.useRef(new Set),S=d.useRef(h6),C=d.useRef(d6),w=d.useRef({main:!1,side:!1}),L=d.useRef(new Map),A=d.useRef(0),V=d.useRef(0),N=d.useRef(0),T=d.useRef(null),R=d.useRef(null),j=d.useCallback(q=>{const $=R.current;if(!$)return;const e1=q.signature??bu(q);$.gamepadSettings?.profiles?.[e1]||H.current.has(e1)||(H.current.add(e1),$.saveGamepadSettings(n1=>{const J=n1??Z3;if(J.profiles?.[e1])return J;const k=J?.defaults?.profile??d3,I=Mu(q,k);return{...J,profiles:{...J.profiles??{},[e1]:I}}}))},[]),F=d.useCallback((q,$)=>{const e1=L.current.get(q)||!1;return L.current.set(q,$),$&&!e1},[]),U=d.useCallback((q,$)=>{const e1=R.current,n1=e1?.cameraConfig;if(!e1||!n1)return;const J=typeof performance<"u"?performance.now():Date.now(),k=$?.cameraMode??"absolute",I=Math.max(1,Math.min(180,$?.cameraSensitivity??60));if(k==="velocity"){const _=Math.min(50,J-N.current||16),K=q*I*(_/1e3);if(Math.abs(K)<.01)return;const v1=(typeof T.current=="number"?T.current:typeof e1.cameraAngle=="number"?e1.cameraAngle:typeof n1.homeAngle=="number"?n1.homeAngle:0)+K;e1.setServoAngle(v1),T.current=v1,N.current=J;return}const t1=typeof n1.minAngle=="number"?n1.minAngle:-45,f1=typeof n1.maxAngle=="number"?n1.maxAngle:45,m1=typeof n1.homeAngle=="number"?n1.homeAngle:(t1+f1)/2,E=q<0?m1+q*(m1-t1):m1+q*(f1-m1);typeof T.current=="number"&&Math.abs(T.current-E)<.35&&J-N.current<80||(N.current=J,T.current=E,e1.setServoAngle(E))},[]),O=d.useMemo(()=>b?.activeSignature??null,[b?.activeSignature]);return d.useLayoutEffect(()=>{R.current={activeSignature:O,cameraAngle:p,cameraConfig:g,dockAssist:z,gamepadSettings:b,registerInputState:v,roverId:x,runMacro:u,saveGamepadSettings:y,setAuxMotors:l,setDriveVector:a,setMode:t,setServoAngle:s,toggleNightVision:f}}),d.useEffect(()=>Su(q=>{const $=R.current;if(!$)return;const e1=DY(q.pads,$.activeSignature);if(!e1){K9(S.current,h6)||(S.current=h6,$.setDriveVector(h6,{source:i0})),Q9(C.current,d6)||(C.current=d6,$.setAuxMotors(d6)),L.current=new Map,w.current={main:!1,side:!1},A.current=0,V.current=0,$.registerInputState(i0,{connected:!1});return}if(yY()){K9(S.current,h6)||(S.current=h6,$.setDriveVector(h6,{source:i0})),Q9(C.current,d6)||(C.current=d6,$.setAuxMotors(d6)),L.current=new Map,w.current={main:!1,side:!1},$.registerInputState(i0,{connected:!0,blocked:!0});return}j(e1);const n1=e1.signature,J=$.gamepadSettings?.profiles?.[n1]??$.gamepadSettings?.defaults?.profile??d3,k=yu(e1,J);if(!K9(k.driveVector,S.current)){const K=typeof performance<"u"?performance.now():Date.now();(qY(k.driveVector)<.02||K-A.current>=EY)&&(S.current=k.driveVector,A.current=K,$.setDriveVector(k.driveVector,{source:i0}))}const I=J.calibration?.auxSideScale??.55,t1=Math.round(Math.min(Math.abs(k.auxAxis.main),1)*127),f1=Math.round(Math.min(Math.abs(k.auxAxis.side),1)*127),m1=w.current.main?-t1:t1,E=w.current.side?-Math.round(f1*I):Math.round(f1*I);let _={main:k.auxAxis.main!==0?m1:0,side:k.auxAxis.side!==0?E:0,vacuum:k.buttons.vacuum?127:0};if(k.buttons.allAux&&(_={main:127,side:127,vacuum:127}),!Q9(_,C.current)){const K=typeof performance<"u"?performance.now():Date.now();(_Y(_)||K-V.current>=TY)&&(C.current=_,V.current=K,$.setAuxMotors(_))}k.buttons.mainReverse&&F("mainReverse",!0)?w.current.main=!w.current.main:k.buttons.mainReverse||F("mainReverse",!1),k.buttons.sideReverse&&F("sideReverse",!0)?w.current.side=!w.current.side:k.buttons.sideReverse||F("sideReverse",!1),k.buttons.driveMacro&&F("driveMacro",!0)?(d1("drive_start",{roverId:$.roverId||"",source:"gamepad"}),$.dockAssist.exitAssist(),$.setMode("drive"),$.runMacro("drive-sequence")):k.buttons.driveMacro||F("driveMacro",!1),k.buttons.dockMacro&&F("dockMacro",!0)?(d1("dock_assist_toggle",{roverId:$.roverId||"",source:"gamepad"}),$.dockAssist.toggleAssist()):k.buttons.dockMacro||F("dockMacro",!1),k.buttons.nightVisionToggle&&F("nightVisionToggle",!0)?(d1("night_vision_toggle",{roverId:$.roverId||"",source:"gamepad"}),$.toggleNightVision()):k.buttons.nightVisionToggle||F("nightVisionToggle",!1),Math.abs(k.cameraAxis)>.001&&U(k.cameraAxis,J.calibration),$.registerInputState(i0,{connected:!0,signature:n1,id:e1.id,index:e1.index,axes:e1.axes,buttons:e1.buttons,drive:k.driveVector,aux:_,cameraAxis:k.cameraAxis,bindings:k.sources})}),[j,F,U]),null}function X9(t){const a=Number(t);return!Number.isFinite(a)||a<=0?0:Math.min($t,Math.round(a))}function Hu({disabled:t,onStart:a,onStop:l,keyLabel:s,active:u,heat:f=0,className:v="",defaultShowSettings:p=!0,showSettingsToggle:g=!1,compactSettings:x=!1}){const[z,b]=d.useState(p),{value:y,save:H}=T1("horn",g6),[S,C]=d.useState(y?.waveform||g6.waveform),w=d.useRef(null),L=d.useRef(null),[A,V]=d.useState(()=>[...Array.isArray(y?.freqs)?y.freqs:g6.freqs,0,0,0,0].slice(0,4).map(k=>X9(k)));d.useEffect(()=>{C(y?.waveform||g6.waveform),Array.isArray(y?.freqs)&&V([...y.freqs,0,0,0,0].slice(0,4).map(J=>X9(J)))},[y?.freqs,y?.waveform]);const N=!!u,T=Math.max(0,Math.min(1,Number(f)||0)),R=d.useMemo(()=>["mobile-touch-control group relative flex w-full flex-col gap-0.5 overflow-hidden rounded-xl border-2 px-1 py-1.5 text-xs font-semibold select-none no-touch-select",N?"border-fuchsia-300/70 bg-fuchsia-700 text-fuchsia-50":"border-cyan-300/70 bg-cyan-900 text-cyan-50 hover:bg-cyan-800","disabled:opacity-50",v].filter(Boolean).join(" "),[v,N]),j=S==="sine"?"sine":"saw",F=d.useCallback(J=>{const k=J.target.value==="sine"?"sine":"saw";C(k),H(I=>({...I??{},waveform:k}))},[H]),U=d.useCallback((J,k)=>{V(I=>{const t1=[...I];return t1[J]=X9(k),H(f1=>({...f1??{},freqs:t1})),t1})},[H]);d.useEffect(()=>{const J=w.current;if(!J)return;const k=I=>{const t1=I.target;if(!(t1 instanceof Element))return;const f1=t1.closest("input[data-horn-freq-index]");if(!f1)return;const m1=Number(f1.dataset.hornFreqIndex);if(!Number.isInteger(m1)||m1<0||m1>=A.length)return;I.preventDefault(),I.stopPropagation();const E=I.deltaY<0?1:-1,_=Number(A[m1])||0;U(m1,_+E*25)};return J.addEventListener("wheel",k,{passive:!1,capture:!0}),()=>{J.removeEventListener("wheel",k,{capture:!0})}},[A,U]);const O=J=>{if(t||L.current!==null)return;const k=J.target?.tagName?.toLowerCase();k==="input"||k==="select"||k==="option"||k==="label"||k==="button"||(J.preventDefault(),L.current=J.pointerId,J.currentTarget.setPointerCapture?.(J.pointerId),a?.())},q=J=>{if(L.current!==J.pointerId)return;const k=J.target?.tagName?.toLowerCase();k==="input"||k==="select"||k==="option"||k==="label"||k==="button"||(J.preventDefault(),L.current=null,J.currentTarget.releasePointerCapture?.(J.pointerId),l?.())},$=J=>{L.current===J.pointerId&&(L.current=null,l?.())},e1=()=>{L.current!==null&&(L.current=null,l?.())},n1=g?r.jsx("button",{type:"button",onClick:J=>{J.preventDefault(),b(k=>!k)},className:"mobile-touch-control rounded bg-black/40 px-1 py-0.5 text-[0.6rem] font-semibold text-white/90 hover:text-white",children:z?"Hide":"Settings"}):null;return r.jsxs("div",{role:"button",tabIndex:0,"aria-pressed":N,onPointerDown:O,onPointerUp:q,onPointerCancel:$,onLostPointerCapture:J=>{L.current===J.pointerId&&(L.current=null,l?.())},onContextMenu:J=>J.preventDefault(),onBlur:e1,className:R,children:[r.jsx("div",{className:"pointer-events-none absolute inset-0 opacity-70",style:{background:`linear-gradient(90deg, rgba(14,116,144,0.7) ${T*100}%, rgba(0,0,0,0) ${T*100}%)`}}),r.jsx("div",{className:`pointer-events-none absolute inset-0 transition-opacity ${N?"opacity-40":"opacity-0"}`,style:{background:"linear-gradient(90deg, rgba(217,70,239,0.75), rgba(244,114,182,0.35))"}}),r.jsxs("div",{className:"relative z-10 flex items-center justify-between gap-0.5",children:[r.jsxs("span",{className:"flex items-center gap-0.5 text-sm font-semibold",children:[r.jsx("span",{children:"Horn"}),s?r.jsx("span",{className:"rounded bg-black/40 px-1 py-0.5 text-[0.6rem] font-semibold text-white",children:s}):null]}),n1,r.jsx("span",{className:`rounded px-1 py-0.5 text-[0.65rem] font-semibold ${N?"bg-fuchsia-200 text-fuchsia-900":"bg-slate-800 text-slate-200"}`,children:N?"Honk":"Hold"})]}),z?x?r.jsxs("div",{ref:w,className:"relative z-10 flex flex-col gap-0.5 text-[0.65rem]",children:[r.jsxs("label",{className:"flex items-center justify-between gap-0.5 text-slate-200",children:[r.jsx("span",{className:"text-slate-300",children:"Wave"}),r.jsxs("select",{value:j,onChange:F,className:"rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-[0.65rem] text-slate-100",children:[r.jsx("option",{value:"saw",children:"Saw"}),r.jsx("option",{value:"sine",children:"Sine"})]})]}),r.jsx("div",{className:"grid grid-cols-2 gap-0.5",children:A.map((J,k)=>r.jsxs("label",{className:"flex items-center gap-0.5 text-slate-200",children:[r.jsx("span",{className:"text-[0.6rem] text-slate-400",children:k+1}),r.jsx("input",{type:"number",min:0,max:$t,step:1,value:J,"data-horn-freq-index":k,onChange:I=>U(k,I.target.value),className:"w-full rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-right text-[0.65rem] font-mono text-slate-100"})]},`horn-freq-${k}`))})]}):r.jsxs("div",{ref:w,className:"relative z-10 grid grid-cols-[minmax(0,1.2fr)_repeat(4,minmax(0,1fr))] items-center gap-0.5 text-[0.65rem]",children:[r.jsxs("label",{className:"flex items-center gap-0.5 text-slate-200",children:[r.jsx("span",{className:"text-slate-300",children:"Wave"}),r.jsxs("select",{value:j,onChange:F,className:"rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-[0.65rem] text-slate-100",children:[r.jsx("option",{value:"saw",children:"Saw"}),r.jsx("option",{value:"sine",children:"Sine"})]})]}),A.map((J,k)=>r.jsxs("label",{className:"flex items-center gap-0.5 text-slate-200",children:[r.jsx("span",{className:"text-[0.6rem] text-slate-400",children:k+1}),r.jsx("input",{type:"number",min:0,max:$t,step:1,value:J,"data-horn-freq-index":k,onChange:I=>U(k,I.target.value),className:"w-full rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-right text-[0.65rem] font-mono text-slate-100"})]},`horn-freq-${k}`))]}):null]})}function J9(t){return typeof t=="boolean"}function Au({nightVisionOn:t,disabled:a,onToggle:l,keyLabel:s,className:u="",heightClass:f=""}){const[v,p]=d.useState(J9(t)?t:null),g=d.useRef(!1),x=d.useRef(null);d.useEffect(()=>{J9(t)&&p(t)},[t]),d.useEffect(()=>()=>{x.current&&clearTimeout(x.current)},[]);const z=J9(v),b=z?v:!1,y=z?b?"On":"Off":"—",H=b?"bg-emerald-500 text-emerald-950":"bg-slate-700 text-slate-200",S=()=>{if(a)return;const A=z?!b:!0;p(A),l?.(A)},C=A=>{a||A.pointerType!=="mouse"&&(A.preventDefault(),g.current=!0,x.current&&clearTimeout(x.current),x.current=window.setTimeout(()=>{g.current=!1,x.current=null},800),S())},w=A=>{if(g.current){A.preventDefault(),g.current=!1,x.current&&(clearTimeout(x.current),x.current=null);return}S()},L=d.useMemo(()=>["mobile-touch-control group flex w-full flex-col items-center justify-center gap-0.35 rounded-xl border-2 px-1 py-0.75 text-center select-none no-touch-select",b?"border-emerald-300/70 bg-emerald-800 text-emerald-50 hover:bg-emerald-700":"border-amber-300/70 bg-amber-900 text-amber-50 hover:bg-amber-800","disabled:opacity-50",f,u].filter(Boolean).join(" "),[u,b,f]);return r.jsxs("button",{type:"button",onPointerDown:C,onClick:w,onContextMenu:A=>A.preventDefault(),disabled:a,"aria-pressed":b,className:L,children:[r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx("span",{className:"text-sm font-semibold",children:"Night Vision"}),s?r.jsx("span",{className:"rounded bg-slate-800 px-1 py-0.5 text-[0.6rem] font-semibold text-slate-200",children:s}):null]}),r.jsx("span",{className:`rounded px-1 py-0.5 text-[0.7rem] font-semibold ${H}`,children:y})]})}const us="mobile-drive-pad",UY=100,Hc=[{id:"precision",label:"precision",modifierAction:"slowModifier"},{id:"normal",label:"normal",modifierAction:null},{id:"turbo",label:"turbo",modifierAction:"boostModifier"}],ZY={main:0,side:0,vacuum:0},$Y={main:127,side:127,vacuum:127},IY={main:-127,side:-127,vacuum:-127};function hs({id:t,label:a,values:l,color:s,disabled:u,onPress:f,onRelease:v}){return r.jsx("button",{type:"button",disabled:u,onPointerDown:p=>{p.preventDefault(),f(t,l)},onPointerUp:()=>v(t),onPointerLeave:()=>v(t),onPointerCancel:()=>v(t),onContextMenu:p=>p.preventDefault(),className:`mobile-touch-control flex h-full w-full items-center justify-center rounded-xl border-2 px-1 py-0.75 text-center text-sm font-semibold text-white transition select-none no-touch-select ${s} hover:brightness-110 active:brightness-125 active:scale-[0.99] disabled:opacity-30`,children:a})}function GY({disabled:t,onPress:a,onRelease:l}){return r.jsxs("div",{className:"mobile-touch-control grid min-h-0 grid-rows-2 gap-0.5",children:[r.jsx(hs,{id:"aux-vac-forward",label:"Vacuum Forward",values:$Y,color:"bg-fuchsia-600",disabled:t,onPress:a,onRelease:l}),r.jsx(hs,{id:"aux-vac-backward",label:"Vacuum Backward",values:IY,color:"bg-fuchsia-800",disabled:t,onPress:a,onRelease:l})]})}function W9(t,a,l){return Number.isFinite(t)?Math.max(a,Math.min(l,t)):a}function PY(t){return typeof t!="number"||Number.isNaN(t)?"—":`${t>0?"+":""}${t.toFixed(1)}°`}function YY({value:t,min:a,max:l,step:s=.5,disabled:u=!1,onChange:f}){const v=d.useRef(null),p=d.useRef(null),g=d.useMemo(()=>l===a?50:(W9(t,a,l)-a)/(l-a)*100,[l,a,t]),x=u?"opacity-50":"",z=d.useCallback(C=>{const w=v.current;if(!w)return t;const L=w.getBoundingClientRect(),A=Math.max(1,L.height),V=1-(C.clientY-L.top)/A,N=a+W9(V,0,1)*(l-a),T=Math.round(N/s)*s;return W9(T,a,l)},[l,a,s,t]),b=d.useCallback(C=>{const w=z(C);f?.(w)},[f,z]),y=d.useCallback(C=>{u||p.current===null&&(C.preventDefault(),p.current=C.pointerId,v.current?.setPointerCapture?.(C.pointerId),b(C))},[u,b]),H=d.useCallback(C=>{p.current===C.pointerId&&(C.preventDefault(),b(C))},[b]),S=d.useCallback(C=>{p.current===C.pointerId&&(C.preventDefault(),p.current=null,v.current?.releasePointerCapture?.(C.pointerId))},[]);return r.jsxs("div",{className:"mobile-touch-control flex h-full items-center justify-center gap-0.5",children:[r.jsx("span",{className:"mobile-touch-control text-sm font-semibold text-emerald-50 [writing-mode:vertical-rl] rotate-180",children:"Camera tilt"}),r.jsxs("div",{ref:v,role:"slider","aria-label":"Camera tilt","aria-valuemin":a,"aria-valuemax":l,"aria-valuenow":Number.isFinite(t)?t:a,"aria-valuetext":PY(t),"aria-disabled":u,tabIndex:u?-1:0,onPointerDown:y,onPointerMove:H,onPointerUp:S,onPointerCancel:S,onLostPointerCapture:C=>{p.current===C.pointerId&&(p.current=null)},onContextMenu:C=>C.preventDefault(),style:{touchAction:"none"},className:`mobile-touch-control mobile-drag-control relative h-full w-6 rounded-full border border-emerald-100/80 bg-emerald-950 shadow-inner focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-200 ${x}`.trim(),children:[r.jsx("div",{className:"pointer-events-none absolute inset-x-1 bottom-1 rounded-full bg-emerald-400",style:{height:`${g}%`}}),r.jsx("div",{className:"pointer-events-none absolute left-1/2 h-3.5 w-3.5 -translate-x-1/2 rounded-full border border-emerald-950 bg-emerald-200 shadow",style:{bottom:`clamp(0.25rem, calc(${g}% - 0.4375rem), calc(100% - 1.125rem))`}})]})]})}function KY(){const t=q1(q=>q.state.roverId),a=q1(q=>q.state.camera),l=q1(q=>q.state.horn),s=q1(q=>q.pipeline?.nightVision),u=q1(q=>q.pipeline?.nightVisionState),f=q1(q=>q.pipeline?.horn),{setServoAngle:v,setNightVision:p,setAuxMotors:g,startHorn:x,stopHorn:z}=x3(),b=A0(),y=!t,H=d.useRef(null),S=a?.config,C=!!(t&&a?.enabled&&S),w=!!(t&&s),L=!!(t&&f),A=l?.overheated,V=typeof S?.minAngle=="number"?S.minAngle:-45,N=typeof S?.maxAngle=="number"?S.maxAngle:45,T=typeof a?.angle=="number"?a.angle:typeof S?.homeAngle=="number"?S.homeAngle:(V+N)/2,R=!!(y||b.cameraLocked),j=d.useCallback(q=>{w&&(d1("night_vision_toggle",{roverId:t,source:"mobile_control",enabled:!!q}),p(q))},[w,t,p]),F=d.useCallback(()=>(d1("horn_start",{roverId:t,source:"mobile_control"}),x()),[t,x]),U=d.useCallback((q,$)=>{y||(H.current=q,g($))},[y,g]),O=d.useCallback(q=>{y||H.current===q&&(H.current=null,g(ZY))},[y,g]);return r.jsxs("div",{className:"mobile-touch-control grid h-full min-h-0 w-full grid-rows-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)] gap-0.5 text-slate-100",children:[r.jsx(GY,{disabled:y,onPress:U,onRelease:O}),r.jsxs("div",{className:"mobile-touch-control flex min-h-0 items-stretch gap-0.5",children:[C?r.jsx("div",{className:"mobile-touch-control flex-1 min-h-0 rounded-xl border-2 border-emerald-300/70 bg-emerald-900 px-1 py-1 text-emerald-50",children:r.jsx(YY,{value:T,min:V,max:N,step:.5,disabled:R,onChange:v})}):null,w?r.jsx(Au,{nightVisionOn:u?.nightVisionOn,disabled:y,onToggle:j,heightClass:"h-full"}):null]}),r.jsx("div",{className:"mobile-touch-control min-h-0",children:L?r.jsx(Hu,{disabled:y||A,onStart:F,onStop:z,active:l?.active,heat:l?.heat,defaultShowSettings:!1,showSettingsToggle:!0,compactSettings:!0,className:"h-full"}):null})]})}function Pt({layout:t,className:a=""}){return r.jsx("div",{className:`mobile-touch-control flex flex-col gap-0.5 ${a}`.trim(),"data-mobile-layout":t,children:r.jsx(KY,{})})}function Vu(t){const a=t?.oiModeLabel||"Unknown",l=a.toLowerCase(),s=t?.chargingStateLabel||"",u=!!t?.homeBase,f=u&&s.toLowerCase()!=="not charging"&&s!=="";return{driving:l==="full",docked:u,charging:f,dockedNotCharging:u&&!f,dockingInProgress:!u&&!f&&l==="passive",oiLabel:a,chargingLabel:s}}function Lu(t){const a=b6(t,Gc,$c);return d.useMemo(()=>Vu(a),[a])}function s0({value:t,tone:a="neutral"}){const l=a==="good"?"border-emerald-200 bg-emerald-600 text-white":a==="warn"?"border-amber-200 bg-amber-600 text-white":a==="bad"?"border-red-200 bg-red-600 text-white":"border-slate-200/30 bg-slate-700 text-slate-100";return r.jsx("div",{className:`flex flex-1 flex-col items-center justify-center rounded-lg border px-0.75 py-0.5 text-center ${l}`,children:r.jsx("span",{className:"text-base font-semibold md:text-lg",children:t})})}function ds({label:t}){return t?r.jsx("span",{className:"rounded border border-white/40 px-1 text-[0.7rem] text-white",children:t}):null}function tc({label:t,tone:a}){const l=a==="emerald"?"border-emerald-200/70 bg-emerald-600/70 text-emerald-50":a==="amber"?"border-amber-200/70 bg-amber-600/70 text-amber-50":"border-indigo-200/70 bg-indigo-600/70 text-indigo-50";return r.jsx("span",{className:`rounded-full border px-0.5 py-0.15 text-[0.7rem] font-semibold ${l}`,children:t})}function QY({instructions:t,onConfirm:a,onCancel:l,pending:s}){return r.jsx("div",{className:"fixed inset-0 z-40 flex items-center justify-center bg-black/70 p-1",children:r.jsxs("div",{className:"surface w-full max-w-md space-y-0.5 border border-indigo-700 bg-indigo-950/90 p-1 text-slate-100 shadow-2xl",children:[r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("p",{className:"text-lg font-semibold text-indigo-50",children:"Manual Docking Assist"}),r.jsx("p",{className:"text-sm text-slate-200",children:t.summary}),r.jsx(Ac,{steps:t.steps,tone:"indigo"})]}),r.jsxs("div",{className:"grid grid-cols-2 gap-0.5 text-sm",children:[r.jsx("button",{type:"button",onClick:l,className:"bg-slate-700 px-0.5 py-1 font-semibold text-slate-100 transition hover:bg-slate-600",children:"Cancel"}),r.jsx("button",{type:"button",disabled:s,onClick:a,className:"bg-indigo-600 px-0.5 py-1 font-semibold text-indigo-50 transition hover:bg-indigo-500 disabled:opacity-50",children:s?"Starting…":"Enter Assist"})]})]})})}function Bu({layout:t="desktop",expand:a=!1,fill:l=!1,driveDockState:s,compactHeightClass:u=""}){const f=t==="mobile",v=q1(x1=>x1.state.roverId),p=q1(x1=>x1.state.keymap),g=x3(),x=A0(),z=b6(v,Gc,$c),b=s??Vu(z),{driving:y,docked:H,charging:S,dockingInProgress:C}=b,[w,L]=d.useState(null),[A,V]=d.useState(!1),[N,T]=d.useState(!1),R=!!x.active,j=!v||w!==null,F=!v||w!==null,U=_2(p?.driveMacro?.[0]),O=_2(p?.dockMacro?.[0]),q={summary:"Use assist mode to manually line up with the dock.",steps:["Line up the center dot of your rover with the center of the dock","The UI will indicate when you are successfully docked","When good contact is made, the dock will stop flashing."]},$={summary:"You must enable driving mode before you can move the rover.",steps:["Press the keybind or tap this button to enable driving mode","Once ready (should be instant), this dialog will change, and you will be able to move"]},e1=H?"Docked":"Undocked",n1=H?"good":"bad",J=S?"Charging":H?"Charging soon...":"—",k=S?"good":H?"warn":"bad",I=async()=>{if(!(!v||w)){L("drive"),d1("drive_return",{roverId:v,source:"drive_dock_action"});try{x.exitAssist(),g.setMode("drive"),await g.runMacro("drive-sequence"),d1("drive_return_result",{roverId:v,status:"accepted"})}catch(x1){d1("drive_return_result",{roverId:v,status:"failed",reason:x1?.message||"unknown"}),alert(x1.message)}finally{L(null)}}},t1=async()=>{if(!(!v||w)){V(!1),T(!1),L("drive"),d1("drive_start",{roverId:v,source:"drive_dock_action"});try{x.exitAssist(),g.setMode("drive"),await g.runMacro("drive-sequence"),d1("drive_start_result",{roverId:v,status:"accepted"})}catch(x1){d1("drive_start_result",{roverId:v,status:"failed",reason:x1?.message||"unknown"}),alert(x1.message)}finally{L(null)}}},f1=async()=>{if(!(!v||w)){L("dock"),d1("dock_assist_start",{roverId:v});try{x.enterAssist(),d1("dock_assist_start_result",{roverId:v,status:"accepted"})}catch(x1){d1("dock_assist_start_result",{roverId:v,status:"failed",reason:x1?.message||"unknown"}),alert(x1.message)}finally{L(null),V(!1),T(!1)}}},m1=()=>{if(!F){if(R){x.exitAssist(),d1("dock_assist_exit",{roverId:v});return}T(!0),V(!0),d1("dock_assist_open",{roverId:v})}},E="mobile-touch-control flex w-full flex-col gap-0.5 overflow-hidden rounded-xl border-2 px-0.75 py-0.75 text-slate-100 shadow-md transition hover:-translate-y-0.5 hover:shadow-xl focus-visible:outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-60 select-none no-touch-select",_="text-center",K="items-center justify-between",r1="items-center justify-center",v1=f?"text-sm font-semibold":"",g1="border-emerald-300/70 bg-emerald-800 text-emerald-50 hover:bg-emerald-700 focus-visible:ring-emerald-300",V1="border-amber-300/70 bg-amber-900 text-amber-50 hover:bg-amber-800 focus-visible:ring-amber-300",S1="border-indigo-300/70 bg-indigo-900 text-indigo-50 hover:bg-indigo-800 focus-visible:ring-indigo-300",N1="border-cyan-300/70 bg-cyan-900 text-cyan-50 hover:bg-cyan-800 focus-visible:ring-cyan-300",P1="border-amber-300/70 bg-amber-900 text-amber-50 hover:bg-amber-800 focus-visible:ring-amber-300",R1=a||C,p2=R1?"h-full flex-1":l?"flex-1":"",s1=f&&!R1?u:"",H1=f&&!R1?r1:K,p1=f&&!R1&&y&&H;if(!y&&!C)return r.jsxs("button",{type:"button",onClick:t1,onContextMenu:x1=>x1.preventDefault(),disabled:j,className:`${E} ${p2} ${s1} ${_} ${H1} ${v1} ${g1}`,children:[r.jsxs("div",{className:"space-y-0.5 w-full",children:[r.jsxs("div",{className:"flex w-full flex-col items-center gap-0.25",children:[r.jsx("span",{className:"text-base font-semibold text-emerald-50 md:text-lg",children:"Start Driving"}),!f&&R1?r.jsxs("div",{className:"flex flex-wrap items-center justify-center gap-0.5",children:[U?r.jsx(ds,{label:U}):null,r.jsx(tc,{label:"Click to start",tone:"emerald"})]}):null]}),R1?r.jsxs(r.Fragment,{children:[r.jsx("p",{className:"text-sm text-emerald-50/90",children:$.summary}),r.jsx(Ac,{steps:$.steps,tone:"emerald"})]}):null]}),R1?r.jsxs("div",{className:"flex w-full flex-1 flex-col gap-0.5 self-stretch",children:[r.jsx(s0,{label:"Dock",value:e1,tone:n1}),r.jsx(s0,{label:"Charge",value:J,tone:k})]}):null]});if(C){const x1={summary:"The rover is currently attempting to dock itself due to being idle.",steps:["Click to return to driving mode."]};return r.jsxs("button",{type:"button",disabled:j,onClick:I,onContextMenu:L1=>L1.preventDefault(),className:`${E} ${p2} ${s1} ${_} ${H1} ${v1} ${V1}`,children:[r.jsxs("div",{className:"space-y-0.5 w-full",children:[r.jsxs("div",{className:"flex w-full flex-col items-center gap-0.25",children:[r.jsx("span",{className:"text-base font-semibold text-amber-50 md:text-lg",children:"Attempting to auto-dock..."}),R1?r.jsx("div",{className:"flex flex-wrap items-center justify-center gap-0.5",children:r.jsx(tc,{label:"Return to driving mode",tone:"emerald"})}):null]}),R1?r.jsx("p",{className:"text-sm text-amber-50/90",children:x1.summary}):null]}),R1?r.jsxs(r.Fragment,{children:[r.jsxs("div",{className:"flex w-full flex-1 flex-col gap-0.5 self-stretch",children:[r.jsx(s0,{label:"Dock",value:e1,tone:n1}),r.jsx(s0,{label:"Charge",value:J,tone:k})]}),f?null:r.jsx(Ac,{steps:x1.steps,tone:"amber"})]}):null]})}return r.jsxs(r.Fragment,{children:[r.jsxs("button",{type:"button",disabled:F,onClick:m1,onContextMenu:x1=>x1.preventDefault(),className:f?`flex w-full ${E} ${s1} ${_} ${H1} ${v1} ${R?N1:p1?P1:S1}`:`${E} ${p2} ${_} ${K} ${v1} ${R?N1:S1}`,children:[r.jsxs("div",{className:"flex w-full flex-col items-center gap-0.25",children:[r.jsx("span",{className:"text-base font-semibold text-indigo-50 md:text-lg",children:p1?"Docked!":R?"Exit Docking Assist":"Dock and charge"}),!f&&R1?r.jsxs("div",{className:"flex flex-wrap items-center justify-center gap-0.5",children:[O?r.jsx(ds,{label:O}):null,r.jsx(tc,{label:R?"Click to exit assist":"Click to enable assist",tone:"indigo"})]}):null]}),!f&&R1&&r.jsxs(r.Fragment,{children:[r.jsx("p",{className:"text-sm text-indigo-50/90",children:"Get near a dock and press this button to enter docking assist mode."}),r.jsxs("div",{className:"flex w-full flex-1 flex-col gap-0.5 self-stretch",children:[r.jsx(s0,{label:"Dock",value:e1,tone:n1}),r.jsx(s0,{label:"Charge",value:J,tone:k})]})]})]}),N||!f&&A?r.jsx(QY,{instructions:q,pending:w==="dock",onCancel:()=>{T(!1),V(!1)},onConfirm:f1}):null]})}function Ac({steps:t,tone:a="emerald"}){const l=a==="emerald"?"bg-emerald-900/60 text-emerald-50/90 border-emerald-700/60":a==="amber"?"bg-amber-900/60 text-amber-50/90 border-amber-700/60":"bg-indigo-900/60 text-indigo-50/90 border-indigo-700/60",s=a==="emerald"?"text-emerald-200":a==="amber"?"text-amber-200":"text-indigo-200";return r.jsx("div",{className:`space-y-0.5 rounded border px-0.5 py-0.35 text-left ${l}`,children:t.map((u,f)=>r.jsxs("div",{className:"text-[0.85rem] leading-snug break-words",children:[r.jsxs("div",{className:"flex items-start",children:[r.jsxs("span",{className:`mr-0 align-top text-[0.75rem] font-semibold ${s}`,children:[f+1,"."]}),r.jsx("span",{className:"align-top",children:u})]}),f(t[`${a.row}:${a.col}`]=a,t),{}),Tt=la.find(t=>t.id==="stop");function m0(t,a,l){return Number.isFinite(t)?Math.max(a,Math.min(l,t)):a}function ju(){return typeof window>"u"?{width:f0,height:f0}:{width:window.innerWidth||f0,height:window.innerHeight||f0}}function JY(t){if(!t)return f0;const a=t.getBoundingClientRect(),l=ju(),s=Math.max(96,Math.min(a.width,l.width-m6*2));return Math.round(s)}function WY(t,a,l){const s=ju(),u=l/2,f=Math.min(s.width-u,u+m6),v=Math.max(u+m6,s.width-u-m6),p=Math.min(s.height-u,u+m6),g=Math.max(u+m6,s.height-u-m6);return{x:m0(t,f,v),y:m0(a,p,g)}}function tK(t,a,l){const s=t?.size||f0,u=s/2,f=s/ec,v=m0(a-t.center.x+u,0,s-1),p=m0(l-t.center.y+u,0,s-1),g=m0(Math.floor(v/f),0,ec-1),x=m0(Math.floor(p/f),0,ec-1);return XY[`${x}:${g}`]||Tt}function eK({center:t,size:a,activeCellId:l}){if(typeof document>"u")return null;const s=a/2;return iv.createPortal(r.jsx("div",{className:"pointer-events-none fixed inset-0 z-[1000]","aria-hidden":"true",children:r.jsx("div",{className:"absolute grid grid-cols-3 grid-rows-3 overflow-hidden rounded-lg border-2 border-cyan-300/80 bg-slate-950/90 shadow-2xl shadow-cyan-950/50 backdrop-blur-sm",style:{height:a,left:t.x-s,top:t.y-s,width:a},children:la.map(u=>{const f=u.id===l,v=u.id==="stop",p="flex items-center justify-center border border-slate-700/80 px-1 text-center text-xs font-semibold leading-tight",g=f?v?"bg-rose-500 text-white":"bg-cyan-300 text-slate-950":v?"bg-slate-900 text-slate-300":"bg-slate-800/80 text-slate-200";return r.jsx("div",{className:`${p} ${g}`,children:u.label},u.id)})})}),document.body)}function cK({activeInputLabel:t="stop",disabled:a,onCellChange:l,onStop:s}){const u=d.useRef(null),f=d.useRef(null),v=d.useRef(null),p=d.useRef(null),[g,x]=d.useState(null),z=d.useCallback(()=>{f.current=null,p.current=null,x(null),s?.()},[s]),b=d.useCallback(C=>{const w=v.current;if(!w)return;const L=tK(w,C.clientX,C.clientY);p.current!==L.id&&(p.current=L.id,l?.(L)),x({...w,activeCellId:L.id})},[l]),y=d.useCallback(C=>{if(a||f.current!==null)return;C.preventDefault();const w=u.current;if(!w)return;f.current=C.pointerId;const L=JY(w),A=WY(C.clientX,C.clientY,L);v.current={center:A,size:L,activeCellId:Tt.id},w.setPointerCapture?.(C.pointerId),p.current=Tt.id,x(v.current),l?.(Tt)},[a,l]),H=d.useCallback(C=>{a||f.current!==C.pointerId||(C.preventDefault(),b(C))},[a,b]),S=d.useCallback(C=>{if(f.current!==C.pointerId)return;C.preventDefault();const w=C.pointerId;z(),u.current?.releasePointerCapture?.(w)},[z]);return d.useEffect(()=>{if(!a)return;const C=setTimeout(z,0);return()=>clearTimeout(C)},[a,z]),r.jsxs(r.Fragment,{children:[r.jsxs("div",{ref:u,role:"presentation",className:"mobile-touch-control mobile-drag-control relative flex h-full min-h-[10rem] w-full select-none items-center justify-center overflow-hidden text-slate-100",style:{touchAction:"none"},onPointerDown:y,onPointerMove:H,onPointerUp:S,onPointerCancel:S,onLostPointerCapture:C=>{f.current===C.pointerId&&z()},onContextMenu:C=>C.preventDefault(),children:[r.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-0 border-b border-slate-700 bg-slate-950 px-1.5 py-0.5 text-center",children:r.jsx("span",{className:"font-mono text-xs font-semibold text-cyan-200",children:t})}),r.jsxs("div",{className:"pointer-events-none flex flex-col items-center gap-0.5 px-2 pt-5 text-center",children:[r.jsx("span",{className:"text-sm font-semibold text-slate-100",children:"drive pad"}),r.jsx("span",{className:"text-xs leading-tight text-slate-300",children:"hold and drag"})]})]}),g?r.jsx(eK,{center:g.center,size:g.size,activeCellId:g.activeCellId}):null]})}function aK(t,a){const l=t?.[a];return!l||l.size===0?null:l.values().next().value??null}function nK(t){return Hc.find(a=>a.id===t)||Hc[1]}function lK({disabled:t=!1}){const a=q1(T=>T.state.keymap),{setDriveVector:l,registerInputState:s}=x3(),{value:u}=T1("inputs",R4),[f,v]=d.useState("normal"),[p,g]=d.useState("stop"),x=d.useRef("normal"),z=d.useRef(null),b=d.useRef(null),y=d.useMemo(()=>cu(a),[a]),H=d.useMemo(()=>vu(u),[u]),S=d.useCallback(()=>{b.current&&(clearInterval(b.current),b.current=null)},[]),C=d.useCallback((T,R=x.current)=>{const j=new Set,F=nK(R);return[...Array.isArray(T?.actions)?T.actions:[],F.modifierAction].filter(Boolean).forEach(O=>{const q=aK(y,O);q&&j.add(q)}),j},[y]),w=d.useCallback((T,R="move",j=x.current)=>{if(t)return;const F=C(T,j),U=pu(F,y),O=gu(F,y,H);l(U,{source:us,speedOptions:O}),s(us,{keys:Array.from(F),vector:U,activeCell:T?.id??"stop",speedMode:j,lastEvent:R})},[C,t,H,y,s,l]),L=d.useCallback((T="stop")=>{S(),z.current=null,g("stop"),w({id:"stop",actions:[]},T,"normal")},[S,w]),A=d.useCallback(()=>{b.current||(b.current=setInterval(()=>{z.current&&w(z.current,"repeat")},UY))},[w]),V=d.useCallback(T=>{t||(z.current=T,g(T?.label||"stop"),w(T,"move"),A())},[t,w,A]),N=d.useCallback(T=>{v(T),x.current=T,z.current&&w(z.current,"speed",T)},[w]);return d.useEffect(()=>()=>S(),[S]),d.useEffect(()=>{t&&L("disabled")},[t,L]),r.jsxs("div",{className:"mobile-touch-control flex flex-1 min-h-0 flex-col overflow-hidden rounded-xl border-2 border-slate-700 bg-slate-900 text-slate-100 shadow-md",children:[r.jsx("div",{className:"mobile-touch-control grid grid-cols-3 gap-0.5 border-b border-slate-700 bg-slate-950 p-0.5",children:Hc.map(T=>{const R=f===T.id,j=T.id==="precision"?H.precisionSpeed:T.id==="turbo"?H.turboSpeed:H.baseSpeed;return r.jsxs("button",{type:"button",className:`mobile-touch-control min-h-9 rounded-md px-1 text-xs font-semibold ${R?"bg-cyan-300 text-slate-950":"bg-slate-800 text-slate-200"}`,onClick:()=>N(T.id),disabled:t,children:[r.jsx("span",{className:"block leading-tight",children:T.label}),r.jsx("span",{className:"block font-mono text-[0.7rem] leading-tight",children:j})]},T.id)})}),r.jsx("div",{className:"mobile-touch-control min-h-0 flex-1",children:r.jsx(cK,{activeInputLabel:p,disabled:t,onCellChange:V,onStop:()=>L("stop")})})]})}function rK({layout:t}){const a=q1(g=>g.state.roverId),l=Lu(a),s=l.docked&&!l.driving,u=s||l.dockingInProgress,f=!a,p=`mobile-touch-control flex h-full flex-col gap-0.5 text-slate-100 ${s?"max-h-screen self-start":""}`;return r.jsxs("div",{className:p,"data-mobile-layout":t,children:[r.jsx(Bu,{layout:"mobile",expand:u,driveDockState:l,compactHeightClass:"min-h-[5rem]"}),u?null:r.jsx(lK,{disabled:f})]})}function Yt({layout:t,className:a=""}){return r.jsx("div",{className:`mobile-touch-control flex flex-col gap-0.5 ${a}`.trim(),"data-mobile-layout":t,children:r.jsx(rK,{layout:t==="landscape"?"landscape":"portrait"})})}function iK(t=[],a={}){const l=R2(),{enabled:s=!0,version:u=null}=a,[f,v]=d.useState({}),p=d.useRef(new Map),g=d.useMemo(()=>t.map(C=>typeof C=="string"?C:C.id),[t]),x=d.useMemo(()=>{const C=g.join("|");return u?`${C}|v:${u}`:C},[g,u]),z=d.useRef([]),[b,y]=d.useState(0),H=d.useRef(new Map),S=typeof window<"u"&&new URLSearchParams(window.location.search).has("debugSnapshots");return d.useEffect(()=>{if(!l)return;const C=()=>y(w=>w+1);return l.on("connect",C),()=>l.off("connect",C)},[l]),d.useEffect(()=>{z.current=g},[x,g]),d.useEffect(()=>{p.current.forEach(C=>URL.revokeObjectURL(C)),p.current.clear(),v({})},[x]),d.useEffect(()=>{if(!s){p.current.forEach(V=>URL.revokeObjectURL(V)),p.current.clear(),v({});return}if(!z.current.length||!l)return;let C=!1;const w=z.current,L=(V={},N)=>{if(C||!V.id||!N)return;const T=N.byteLength??N.length??0,R=Date.now(),j=H.current.get(V.id)||{count:0,totalBytes:0,lastLogAt:0},F={count:j.count+1,totalBytes:j.totalBytes+T,lastLogAt:j.lastLogAt};if(S&&(!F.lastLogAt||R-F.lastLogAt>=1e4)){const $=F.count?F.totalBytes/F.count:0;console.log("[roomCamera]",V.id,`frame=${T}B`,`avg=${Math.round($)}B`,`count=${F.count}`),F.lastLogAt=R}H.current.set(V.id,F);const U=new Blob([N],{type:"image/jpeg"}),O=URL.createObjectURL(U),q=p.current.get(V.id);q&&URL.revokeObjectURL(q),p.current.set(V.id,O),v($=>({...$,[V.id]:{status:"playing",ts:V.ts||Date.now(),error:null,objectUrl:O}}))},A=(V={})=>{C||!V.id||v(N=>({...N,[V.id]:{...N[V.id]||{},status:V.error?"error":N[V.id]?.status||"connecting",error:V.error||null,ts:V.ts||N[V.id]?.ts||null,objectUrl:N[V.id]?.objectUrl||null}}))};return l.on("roomCamera:frame",L),l.on("roomCamera:status",A),l.emit("roomCamera:subscribe",{ids:w},(V={})=>{V.error}),()=>{C=!0,l.emit("roomCamera:unsubscribe",{ids:w}),l.off("roomCamera:frame",L),l.off("roomCamera:status",A),p.current.forEach(V=>URL.revokeObjectURL(V)),p.current.clear()}},[l,x,s,b,S]),f}function sK({feed:t,label:a}){const[l,s]=d.useState(!1);d.useEffect(()=>{t&&(!t.ts&&!t.objectUrl||s(f=>!f))},[t?.ts,t?.objectUrl]);const u=d.useMemo(()=>t?t.error?`Error: ${t.error}`:t.status||"Connecting…":"Connecting…",[t]);return r.jsxs("div",{className:"relative w-full overflow-hidden rounded bg-black",style:{aspectRatio:"4 / 3"},children:[t?.objectUrl?r.jsx("img",{src:t.objectUrl,alt:a,className:"h-full w-full object-cover"}):r.jsx("div",{className:"flex h-full w-full items-center justify-center text-sm text-slate-300",children:"Waiting for frame…"}),r.jsx("div",{className:"pointer-events-none absolute left-0 top-0 bg-black/70 px-0.5 py-0.5 text-xs font-semibold text-white",children:a}),r.jsxs("div",{className:"pointer-events-none absolute bottom-0 left-0 m-0 flex items-center gap-0.5 rounded bg-black/70 px-0.5 py-0.25 text-[0.7rem] text-slate-100",children:[r.jsx("span",{className:`h-2 w-2 rounded-full ${l?"bg-emerald-400":"bg-slate-500"}`}),r.jsx("span",{children:u})]})]})}function oK(){return r.jsxs(j1,{title:"Room Cameras",bodyClassName:"space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-center text-slate-400",children:"No room cameras configured."}),r.jsx("p",{className:"text-center text-slate-500",children:"Add entries to server config to populate this list."})]})}const Nu=["horizontal","vertical"];function cc(t,a){return Nu.includes(t)?t:a}function ra({defaultOrientation:t="horizontal",orientation:a,hideLayoutToggle:l=!1,hideHeader:s=!1,panelId:u=null}){const f=u1(w=>w.session?.roomCameras||[]),v=iK(f.map(w=>({id:w.id}))),{value:p,save:g}=T1("roomCameraPanels",{}),[x,z]=d.useState(()=>cc(u?p?.[u]:t,"horizontal"));d.useEffect(()=>{if(!u)return;const w=p?.[u];w&&z(cc(w,"horizontal"))},[u,p?.[u]]);const b=a?cc(a,"horizontal"):x,y=b==="vertical"?"flex flex-col gap-0.5":"grid gap-0.5 md:grid-cols-2",H=!l&&!a&&f.length>0,S=w=>{z(w),u&&g(L=>({...L||{},[u]:w}))};if(f.length===0)return r.jsx(oK,{});const C=H?r.jsxs("div",{className:"flex items-center gap-0.5 text-[0.68rem] text-slate-400",children:[r.jsx("span",{children:"Layout"}),r.jsx("div",{className:"inline-flex overflow-hidden rounded border border-slate-700",children:Nu.map(w=>r.jsx("button",{type:"button",className:`px-1 py-0.5 ${b===w?"bg-slate-600 text-white":"bg-transparent text-slate-400 hover:text-white"}`,onClick:()=>S(w),children:w==="vertical"?"Vertical":"Grid"},w))})]}):null;return r.jsx(j1,{title:"Room cameras",actions:C,hideHeader:s,bodyClassName:"space-y-0.5 text-base",children:r.jsx("div",{className:y,children:f.map(w=>{const L=v[w.id]||null;return r.jsx("article",{className:"w-full space-y-0.5 p-0.5",children:r.jsx(sK,{feed:L,label:w.name||w.id})},w.id)})})})}const uK="modulepreload",hK=function(t){return"/"+t},fs={},ms=function(a,l,s){let u=Promise.resolve();if(l&&l.length>0){let x=function(z){return Promise.all(z.map(b=>Promise.resolve(b).then(y=>({status:"fulfilled",value:y}),y=>({status:"rejected",reason:y}))))};var v=x;document.getElementsByTagName("link");const p=document.querySelector("meta[property=csp-nonce]"),g=p?.nonce||p?.getAttribute("nonce");u=x(l.map(z=>{if(z=hK(z),z in fs)return;fs[z]=!0;const b=z.endsWith(".css"),y=b?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${z}"]${y}`))return;const H=document.createElement("link");if(H.rel=b?"stylesheet":uK,b||(H.as="script"),H.crossOrigin="",H.href=z,g&&H.setAttribute("nonce",g),document.head.appendChild(H),b)return new Promise((S,C)=>{H.addEventListener("load",S),H.addEventListener("error",()=>C(new Error(`Unable to preload CSS for ${z}`)))})}))}function f(p){const g=new Event("vite:preloadError",{cancelable:!0});if(g.payload=p,window.dispatchEvent(g),!g.defaultPrevented)throw p}return u.then(p=>{for(const g of p||[])g.status==="rejected"&&f(g.reason);return a().catch(f)})};function dK({frame:t}){const a=d.useRef(null),l=d.useRef(null),s=d.useRef(null),u=d.useRef(null),f=d.useRef(null),v=d.useRef(null),p=d.useRef(null),g=d.useRef(!1),x=d.useRef(t),z=d.useCallback(()=>{const H=l.current,S=u.current,C=s.current;!H||!S||!C||!g.current||H.render(S,C)},[]),b=d.useCallback(()=>{const H=f.current;H&&(u.current?.remove(H),H.geometry?.dispose(),H.material?.dispose(),f.current=null)},[]),y=d.useCallback(()=>{const H=u.current,S=x.current,C=p.current;if(!H||!C||!S?.buffer||!g.current)return;const w=Number(S.meta?.strideBytes)||16,L=Number(S.meta?.width)||0,A=Number(S.meta?.height)||0,V=L*A;if(!S.meta?.grid||!V||w<16){b();return}const N=new DataView(S.buffer),T=new Float32Array(V*3),R=new Float32Array(V*3),j=new Uint8Array(V),F=new Float32Array(V);for(let J=0;J0?1:0,F[J]=t1}const U=new C.BufferGeometry;U.setAttribute("position",new C.BufferAttribute(T,3)),U.setAttribute("color",new C.BufferAttribute(R,3));const O=[],q=.12,$=(J,k,I)=>{if(!j[J]||!j[k]||!j[I])return!1;const t1=Math.min(F[J],F[k],F[I]);return Math.max(F[J],F[k],F[I])-t1<=q};for(let J=0;J{x.current=t,y()},[t,y]),d.useEffect(()=>{const H=a.current;if(!H)return;let S=!1,C=null,w=null;async function L(){const[A,V]=await Promise.all([ms(()=>import("./three.module--MGUDD-H.js"),[]),ms(()=>import("./OrbitControls-BJ-UXxdt.js"),__vite__mapDeps([0,1]))]);if(S)return;const N=A,{OrbitControls:T}=V;p.current=N;const R=new N.Scene;R.background=new N.Color(657930);const j=new N.PerspectiveCamera(55,4/3,.01,20);j.position.set(0,.15,2.2);const F=new N.WebGLRenderer({antialias:!0,alpha:!1});F.setPixelRatio(Math.min(window.devicePixelRatio||1,1.5)),F.setSize(H.clientWidth||640,H.clientHeight||480,!1),H.appendChild(F.domElement);const U=new T(j,F.domElement);U.enableDamping=!1,U.target.set(0,0,-1.4),U.addEventListener("change",z),u.current=R,s.current=j,l.current=F,v.current=U,C=new ResizeObserver(([O])=>{const q=Math.max(1,O.contentRect.width),$=Math.max(1,O.contentRect.height);j.aspect=q/$,j.updateProjectionMatrix(),F.setSize(q,$,!1),z()}),C.observe(H),w=new IntersectionObserver(([O])=>{const q=!!O?.isIntersecting;g.current=q,q&&(y(),z())},{threshold:.01}),w.observe(H)}return L(),()=>{S=!0,w?.disconnect(),C?.disconnect(),v.current?.removeEventListener("change",z),v.current?.dispose(),b(),l.current?.dispose(),l.current?.domElement?.remove(),u.current=null,s.current=null,l.current=null,v.current=null,p.current=null}},[b,y,z]),r.jsx("div",{ref:a,className:"h-full w-full"})}const fK={enabled:!1,available:!1,busy:!1,captureCooldownUntil:0,lastError:null,hasPointCloud:!1,hasColorImage:!1};function mK(t){return{...fK,...t&&typeof t=="object"?t:{}}}function vs(t){return t?t instanceof ArrayBuffer?t:ArrayBuffer.isView(t)?t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength):null:null}function vK({cooldownText:t,enabled:a,busy:l,lastError:s}){return t?{label:t,className:"border-red-400 bg-red-600 text-red-50"}:!a||s?{label:"Off",className:"border-red-400 bg-red-700 text-red-50"}:l?{label:"...",className:"border-amber-200 bg-amber-500 text-amber-950"}:{label:"Ready",className:"border-emerald-300 bg-emerald-600 text-emerald-50"}}function Fu(){const t=R2(),a=u1(V=>mK(V.session?.kinect)),[l,s]=d.useState("3d"),[u,f]=d.useState(null),[v,p]=d.useState(null),[g,x]=d.useState(null),[z,b]=d.useState(()=>Date.now());d.useEffect(()=>{const V=setInterval(()=>b(Date.now()),1e3);return()=>clearInterval(V)},[]),d.useEffect(()=>{if(!t)return;const V=(T={},R)=>{const j=vs(R);!j||!T?.grid||(f({meta:T,buffer:j}),s("3d"),x(null))},N=(...T)=>{const R=T[1],j=vs(R);if(!j)return;const F=new Blob([j],{type:"image/jpeg"}),U=URL.createObjectURL(F);p(O=>(O&&URL.revokeObjectURL(O),U)),s("image"),x(null)};return t.on("kinect:pointCloudFrame",V),t.on("kinect:colorFrame",N),t.emit("kinect:requestCachedFrames",{},()=>{}),()=>{t.off("kinect:pointCloudFrame",V),t.off("kinect:colorFrame",N)}},[t]),d.useEffect(()=>()=>{v&&URL.revokeObjectURL(v)},[v]);const y=Math.max(0,Number(a.captureCooldownUntil||0)-z),H=!a.enabled||a.busy||y>0,S=y>0?`${Math.ceil(y/1e3)}s`:null,C=d.useMemo(()=>vK({cooldownText:S,enabled:a.enabled,busy:a.busy,lastError:a.lastError}),[S,a.busy,a.enabled,a.lastError]),w=g||a.lastError,L=d.useCallback(V=>{!t||H||(x(null),t.emit(V,{},(N={})=>{N.error&&x(N.error)}))},[H,t]),A=r.jsxs("div",{className:"flex flex-wrap items-center justify-end gap-0.5 text-[0.68rem] text-slate-400",children:[r.jsx("span",{className:`inline-flex min-w-[3.7rem] justify-center rounded border px-1 py-0.5 text-xs font-semibold ${C.className}`,children:C.label}),r.jsx("div",{className:"inline-flex overflow-hidden rounded border border-slate-700",children:["3d","image"].map(V=>r.jsx("button",{type:"button",className:`px-1 py-0.5 ${l===V?"bg-slate-600 text-white":"bg-transparent text-slate-400 hover:text-white"}`,onClick:()=>s(V),children:V==="3d"?"3D":"Image"},V))}),r.jsx("button",{type:"button",className:"button-dark px-1 py-0.25",disabled:H,onClick:()=>L("kinect:requestPointCloud"),children:"Request 3D"}),r.jsx("button",{type:"button",className:"button-dark px-1 py-0.25",disabled:H,onClick:()=>L("kinect:requestColorImage"),children:"Request Image"})]});return r.jsxs(j1,{title:"Kinect Viewer",actions:A,bodyClassName:"space-y-0.5 p-0.5 text-sm",children:[r.jsx("div",{className:"aspect-[4/3] w-full overflow-hidden rounded bg-black",children:l==="3d"&&u?.buffer?r.jsx(dK,{frame:u}):l==="3d"?r.jsx("div",{className:"flex h-full items-center justify-center text-center text-sm text-slate-400",children:"Request a 3D frame"}):v?r.jsx("img",{src:v,alt:"Kinect image",className:"h-full w-full object-contain"}):r.jsx("div",{className:"flex h-full items-center justify-center text-center text-sm text-slate-400",children:"Request an image"})}),w?r.jsx("p",{className:"m-0 break-words text-[0.7rem] text-red-300",children:String(w).toLowerCase()}):null]})}const pK={iceServers:[{urls:"stun:stun.l.google.com:19302"},{urls:"turn:your.turn.server:3478",username:"user",credential:"pass"}],bundlePolicy:"max-bundle",rtcpMuxPolicy:"require"};function gK(t){if(typeof btoa=="function")return btoa(t);if(typeof Buffer<"u")return Buffer.from(t).toString("base64");throw new Error("No base64 encoder available")}function xK(t){if(!t)return{};const a=`${t}:${t}`;return{Authorization:`Basic ${gK(a)}`}}class ps{constructor({url:a,token:l,video:s,onStatus:u,audioOnly:f=!1,receiveAudio:v=!0}){this.url=a,this.token=l,this.video=s,this.audioOnly=f,this.receiveAudio=v,this.pc=null,this.abortController=null,this.onStatus=u}notify(a,l){typeof this.onStatus=="function"&&this.onStatus(a,l)}configureVideoElement(){this.video&&(this.video.playsInline=!0,this.video.autoplay=!0,this.video.muted=!this.audioOnly,typeof this.video.disableRemotePlayback<"u"&&(this.video.disableRemotePlayback=!0),"latencyHint"in HTMLMediaElement.prototype&&(this.video.latencyHint="interactive"))}async start(){if(!this.url||!this.video)throw new Error("Media target missing");this.stop(),this.notify("connecting"),this.configureVideoElement(),this.abortController=new AbortController;const a=new RTCPeerConnection(pK);this.pc=a;const l=new MediaStream;a.ontrack=s=>{s.streams[0]?.getTracks().forEach(u=>l.addTrack(u)),this.video.srcObject=l,s.track?.kind==="video"&&"playoutDelayHint"in s.receiver&&(s.receiver.playoutDelayHint=0)},this.audioOnly?a.addTransceiver("audio",{direction:"recvonly"}):(a.addTransceiver("video",{direction:"recvonly"}),this.receiveAudio&&a.addTransceiver("audio",{direction:"recvonly"})),a.onconnectionstatechange=()=>{this.notify(a.connectionState)},a.oniceconnectionstatechange=()=>{const s=a.iceConnectionState;(s==="failed"||s==="disconnected")&&this.notify(s)};try{const s=await a.createOffer({offerToReceiveAudio:this.audioOnly?!0:this.receiveAudio,offerToReceiveVideo:!this.audioOnly});await a.setLocalDescription(s);const u=await fetch(this.url,{method:"POST",headers:{"Content-Type":"application/sdp",...xK(this.token)},body:s.sdp,signal:this.abortController.signal});if(!u.ok)throw new Error(`WHEP request failed: ${u.status}`);const f=await u.text();await a.setRemoteDescription({type:"answer",sdp:f}),a.getReceivers().forEach(v=>{"playoutDelayHint"in v&&(v.playoutDelayHint=0)}),await this.video.play().catch(()=>{}),this.notify("playing")}catch(s){throw this.notify("error",s.message),this.stop(),s}}stop(){this.abortController&&(this.abortController.abort(),this.abortController=null),this.pc&&(this.pc.getSenders().forEach(a=>a.track?.stop()),this.pc.getReceivers().forEach(a=>a.track?.stop()),this.pc.close(),this.pc=null),this.video&&(this.video.srcObject=null),this.notify("stopped")}}function zK(t){if(!t)return null;if(typeof t=="string"){const a=String(t).trim();return a?{type:"rover",id:a,key:a}:null}if(typeof t=="object"){if(t.type&&t.id){const a=String(t.id);let l=t.key;return l||(l=t.type==="room"?`room:${a}`:a),{type:t.type,id:a,key:l}}if(t.roverId){const a=String(t.roverId);return{type:"rover",id:a,key:t.key||a}}if(t.roomCameraId){const a=String(t.roomCameraId);return{type:"room",id:a,key:t.key||`room:${a}`}}}return null}function bK(t=[]){const a=new Set,l=[];return t.forEach(s=>{!s?.key||a.has(s.key)||(a.add(s.key),l.push(s))}),l.sort((s,u)=>s.key.localeCompare(u.key))}function Vc(t=[],a={}){const l=R2(),{enabled:s=!0,version:u=null}=a,[f,v]=d.useState({}),p=d.useMemo(()=>Array.isArray(t)?bK(t.map(zK).filter(Boolean)):[],[t]),g=d.useMemo(()=>{const H=p.map(S=>`${S.type}:${S.id}:${S.key}`).join("|");return u?`${H}|v:${u}`:H},[p,u]),x=d.useRef([]),[z,b]=d.useState(0);return d.useEffect(()=>{if(!l)return;const H=()=>b(S=>S+1);return l.on("connect",H),()=>{l.off("connect",H)}},[l]),d.useEffect(()=>{x.current=p},[p]),d.useEffect(()=>{if(!g||!s){v({});return}const H=x.current;let S=!1;function C(w){const L=w.type==="room"?{roomCameraId:w.id}:{roverId:w.id};l.emit("video:request",L,(A={})=>{S||(A?.error&&v3("video_request_failed",{type:w.type,sourceId:w.id,reason:A.error},{key:`${w.type}:${w.id}:${A.error}`,throttleMs:60*1e3}),v(V=>({...V,[w.key]:A})))})}return H.forEach(w=>{C(w)}),()=>{S=!0}},[l,g,s,z]),d.useMemo(()=>{if(!g||!s)return{};const H={};return p.forEach(S=>{f[S.key]&&(H[S.key]=f[S.key])}),H},[g,f,p])}function ku(t=[],a={}){const l=R2(),{enabled:s=!0,version:u=null}=a,[f,v]=d.useState({}),p=d.useRef(new Map),g=d.useMemo(()=>t.map(C=>typeof C=="string"?C:C.id).filter(Boolean),[t]),x=d.useMemo(()=>{const C=g.join("|");return u?`${C}|v:${u}`:C},[g,u]),z=d.useRef([]),[b,y]=d.useState(0),H=d.useRef(new Map),S=typeof window<"u"&&new URLSearchParams(window.location.search).has("debugSnapshots");return d.useEffect(()=>{if(!l)return;const C=()=>y(w=>w+1);return l.on("connect",C),()=>l.off("connect",C)},[l]),d.useEffect(()=>{z.current=g},[x,g]),d.useEffect(()=>{p.current.forEach(C=>URL.revokeObjectURL(C)),p.current.clear(),v({})},[x]),d.useEffect(()=>{if(!s){p.current.forEach(V=>URL.revokeObjectURL(V)),p.current.clear(),v({});return}if(!z.current.length||!l)return;let C=!1;const w=z.current,L=(V={},N)=>{if(C||!V.id||!N)return;const T=N.byteLength??N.length??0,R=Date.now(),j=H.current.get(V.id)||{count:0,totalBytes:0,lastLogAt:0},F={count:j.count+1,totalBytes:j.totalBytes+T,lastLogAt:j.lastLogAt};if(S&&(!F.lastLogAt||R-F.lastLogAt>=1e4)){const $=F.count?F.totalBytes/F.count:0;console.log("[roverSnapshot]",V.id,`frame=${T}B`,`avg=${Math.round($)}B`,`count=${F.count}`),F.lastLogAt=R}H.current.set(V.id,F);const U=new Blob([N],{type:"image/jpeg"}),O=URL.createObjectURL(U),q=p.current.get(V.id);q&&URL.revokeObjectURL(q),p.current.set(V.id,O),v($=>({...$,[V.id]:{status:"playing",ts:V.ts||Date.now(),error:null,objectUrl:O}}))},A=(V={})=>{C||!V.id||v(N=>({...N,[V.id]:{...N[V.id]||{},status:V.error?"error":N[V.id]?.status||"connecting",error:V.error||null,ts:V.ts||N[V.id]?.ts||null,objectUrl:N[V.id]?.objectUrl||null}}))};return l.on("roverSnapshot:frame",L),l.on("roverSnapshot:status",A),l.emit("roverSnapshot:subscribe",{ids:w},(V={})=>{V.error}),()=>{C=!0,l.emit("roverSnapshot:unsubscribe",{ids:w}),l.off("roverSnapshot:frame",L),l.off("roverSnapshot:status",A),p.current.forEach(V=>URL.revokeObjectURL(V)),p.current.clear()}},[l,x,s,b,S]),f}const gs=2e3,MK=3e3,yK=3e3,wK=40,CK=1e3,Ru={none:"",grayscale:"grayscale(1) contrast(1.08)",greenscale:"grayscale(1) sepia(1) hue-rotate(70deg) saturate(2.2) brightness(0.95) contrast(1.1)"};function SK(t){return Object.prototype.hasOwnProperty.call(Ru,t)?t:H0.colorFilter}function E8({roverId:t=null,sessionInfo:a=null,audioSessionInfo:l=null,videoMode:s=null,snapshotFeed:u=null,label:f,forceMute:v=!1,sensors:p}){const g=u1(b1=>b1.session?.assignment?.roverId??null),x=t??g,z=u1(b1=>b1.session?.mode||null),b=u1(b1=>x&&Array.isArray(b1.session?.roster)&&b1.session.roster.find(h2=>String(h2.id)===String(x))||null),y=!!b?.media?.audioPublishUrl,H=s?s==="whep":!0,S=y,C=d.useMemo(()=>x?[...H?[{type:"rover",id:x,key:x}]:[],...S?[{type:"rover",id:`${x}-audio`,key:`${x}-audio`}]:[]]:[],[x,H,S]),w=Vc(C,{enabled:!!(x&&(H||S)),version:z}),L=a??(x&&w[x]||null),A=l??(x&&y&&w[`${x}-audio`]||null),V=ku(x?[x]:[],{enabled:!!(x&&!L?.url),version:z}),N=u??(x&&V[x]||null),T=f||b?.name||(x?`Rover ${x}`:"Rover"),R=b6(x,Bp,jp),j=p?{mainBrushCurrentMa:p?.mainBrushCurrentMa??0,mainBrushOvercurrent:!!p?.wheelOvercurrents?.mainBrush}:R,F=d.useRef(null),U=d.useRef(null),O=d.useRef(null),q=d.useRef(null),$=d.useRef(null),e1=d.useRef(null),n1=d.useRef(null),J=d.useRef(null),[k,I]=d.useState("idle"),[t1,f1]=d.useState(null),[m1,E]=d.useState("idle"),[_,K]=d.useState(null),[r1,v1]=d.useState(0),[g1,V1]=d.useState(0),[S1,N1]=d.useState(!0),P1=!!A?.url,Y1=s==="snapshot"||!s&&!L?.url,{value:R1}=T1("audio",x2),{value:p2}=T1("video",H0),s1=SK(p2?.colorFilter),H1=Ru[s1],p1=H1?{filter:H1}:void 0,x1=Number.isFinite(R1?.masterVolume)?R1.masterVolume:x2.masterVolume,L1=Number.isFinite(R1?.roverVolume)?R1.roverVolume:x2.roverVolume,F1=typeof R1?.mainBrushDuckEnabled=="boolean"?R1.mainBrushDuckEnabled:typeof R1?.autoLevelEnabled=="boolean"?R1.autoLevelEnabled:x2.mainBrushDuckEnabled,h1=Number.isFinite(R1?.mainBrushDuckAmount)?Math.max(0,Math.min(1,R1.mainBrushDuckAmount)):x2.mainBrushDuckAmount,y1=Math.max(0,Math.min(1,x1*L1)),k1=!!((Number(j?.mainBrushCurrentMa)||0)>wK||j?.mainBrushOvercurrent),X1=F1&&k1?1-h1:1,C1=Math.max(0,Math.min(1,y1*X1)),g2=d.useMemo(()=>typeof window>"u"?!1:new URLSearchParams(window.location.search).has("debugAudio"),[]),t2=d.useRef({hasDedicatedAudio:!1,audioUrl:null,mainBrushDuckEnabled:!1,mainBrushDuckAmount:0,mainBrushActive:!1,baseRoverGain:0,effectiveRoverGain:0});d.useEffect(()=>{t2.current={hasDedicatedAudio:P1,audioUrl:A?.url||null,mainBrushDuckEnabled:F1,mainBrushDuckAmount:h1,mainBrushActive:k1,baseRoverGain:y1,effectiveRoverGain:C1}},[P1,A?.url,F1,h1,k1,y1,C1]);const e2=d.useCallback((b1,h2={})=>{if(!g2)return;const c2=U.current,U1=t2.current,Q1={event:b1,ts:Date.now(),roverLabel:T||null,hasDedicatedAudio:U1.hasDedicatedAudio,audioUrl:U1.audioUrl,mainBrushDuckEnabled:U1.mainBrushDuckEnabled,mainBrushDuckAmount:U1.mainBrushDuckAmount,mainBrushActive:U1.mainBrushActive,baseRoverGain:U1.baseRoverGain,effectiveRoverGain:U1.effectiveRoverGain,element:c2?{muted:c2.muted,volume:c2.volume,paused:c2.paused,ended:c2.ended,readyState:c2.readyState,networkState:c2.networkState}:null,...h2};try{console.log(`[AudioDebug] ${b1} ${JSON.stringify(Q1)}`)}catch{console.log("[AudioDebug]",b1,Q1)}},[g2,T]);d.useEffect(()=>{e2("settings/update")},[e2]);const o1=d.useCallback(()=>{clearTimeout(O.current),O.current=setTimeout(()=>v1(Date.now()),gs)},[]),P=d.useCallback(()=>{clearTimeout(q.current),q.current=setTimeout(()=>V1(Date.now()),gs)},[]),c1=d.useCallback(async()=>{const b1=F.current;if(b1)try{b1.muted=!0,await b1.play()}catch{}},[]),z1=d.useCallback((b1=0)=>{if(v||P1)return;clearTimeout(e1.current);const h2=()=>{clearTimeout(e1.current),e1.current=setTimeout(()=>{v||c2()},MK)},c2=async()=>{const U1=F.current;if(U1)try{await c1(),U1.muted=!1,await U1.play(),N1(!1)}catch{U1.muted=!0,N1(!0),h2()}};e1.current=setTimeout(c2,b1)},[c1,v,P1]);d.useEffect(()=>()=>{clearTimeout(O.current),clearTimeout(q.current),clearTimeout(e1.current),clearInterval($.current),n1.current&&(cancelAnimationFrame(n1.current),n1.current=null)},[]),d.useEffect(()=>{k==="playing"&&z1(0)},[k,z1]),d.useEffect(()=>{Y1&&(I("snapshot"),f1(null))},[Y1]),d.useEffect(()=>{if(Y1||!L?.url||!F.current)return;let b1=!0,h2;const c2=setTimeout(()=>N1(!0),0),U1=(Q1,G2)=>{b1&&(e2("video/status",{nextStatus:Q1,info:G2||null}),I(Q1),f1(G2||null),Q1==="playing"&&c1(),["error","failed","disconnected","closed"].includes(Q1)&&(v3("whep_player_error",{roverId:x,status:Q1,detail:G2||""},{key:`${x||"unknown"}:${Q1}:${G2||""}`,throttleMs:60*1e3}),o1()))};return h2=new ps({url:L.url,token:L.token,video:F.current,receiveAudio:!P1,onStatus:U1}),h2.start().catch(Q1=>{b1&&(I("error"),f1(Q1.message),v3("whep_player_error",{roverId:x,status:"start_failed",detail:Q1.message},{key:`${x||"unknown"}:start_failed:${Q1.message}`,throttleMs:60*1e3}),o1())}),()=>{b1=!1,clearTimeout(c2),h2?.stop()}},[Y1,L?.url,L?.token,r1,o1,c1,P1,e2,x]),d.useEffect(()=>{k==="stopped"&&L?.url&&o1()},[k,L?.url,o1]),d.useEffect(()=>{const b1=U.current;if(!b1||!A?.url){e2("route/no-audio-url"),J.current=null;return}const h2=Math.max(0,Math.min(1,C1)),c2=J.current==null?Math.max(0,Math.min(1,b1.volume)):J.current;if(n1.current&&(cancelAnimationFrame(n1.current),n1.current=null),h2>c2){const U1=performance.now(),Q1=c2,G2=h2-Q1,T4=f4=>{const y2=Math.min(1,(f4-U1)/CK),L4=Q1+G2*y2;b1.volume=L4,J.current=L4,y2<1?n1.current=requestAnimationFrame(T4):n1.current=null};n1.current=requestAnimationFrame(T4)}else b1.volume=h2,J.current=h2;e2("route/direct",{elementVolume:h2,duckEnabled:F1,mainBrushActive:k1,duckAmount:h1})},[A?.url,C1,F1,k1,h1,e2]),d.useEffect(()=>{if(!A?.url||!U.current)return;let b1=!0,h2;const c2=(U1,Q1)=>{b1&&(e2("audio/status",{nextStatus:U1,info:Q1||null}),E(U1),K(Q1||null),["error","failed"].includes(U1)&&P())};return h2=new ps({url:A.url,token:A.token,video:U.current,audioOnly:!0,onStatus:c2}),h2.start().catch(U1=>{b1&&(E("error"),K(U1.message),P())}),()=>{b1=!1,h2?.stop()}},[A?.url,A?.token,g1,P,e2]),d.useEffect(()=>{const b1=U.current;if(!A?.url||!b1){clearInterval($.current);return}if(!["connecting","connected","playing","paused"].includes(m1)){clearInterval($.current);return}const c2=async()=>{const U1=U.current;U1&&(U1.muted=!1,!(!U1.paused&&!U1.ended)&&(e2("retry/play-attempt"),U1.play().then(()=>{e2("retry/play-ok"),E(Q1=>["error","failed","disconnected","closed"].includes(Q1)?Q1:"playing"),K(null)}).catch(Q1=>{e2("retry/play-fail",{error:Q1?.message}),K(G2=>G2||Q1?.message||"autoplay blocked")})))};return c2(),$.current=setInterval(c2,yK),()=>clearInterval($.current)},[A?.url,m1,e2]),d.useEffect(()=>{const b1=U.current;if(!b1)return;const h2=()=>{e2("element/play"),E(y2=>y2==="error"?y2:"playing"),K(null)},c2=()=>{e2("element/pause"),E(y2=>["error","failed","disconnected","closed","stopped"].includes(y2)?y2:"paused"),K(y2=>y2||"paused")},U1=()=>{e2("element/ended"),E(y2=>y2==="error"?y2:"stopped"),K(y2=>y2||"ended")},Q1=()=>{const{error:y2}=b1,L4=y2?.message||"audio error";e2("element/error",{error:L4}),E("error"),K(L4)},G2=()=>e2("element/waiting"),T4=()=>e2("element/canplay"),f4=()=>e2("element/stalled");return b1.addEventListener("play",h2),b1.addEventListener("pause",c2),b1.addEventListener("ended",U1),b1.addEventListener("error",Q1),b1.addEventListener("waiting",G2),b1.addEventListener("canplay",T4),b1.addEventListener("stalled",f4),()=>{b1.removeEventListener("play",h2),b1.removeEventListener("pause",c2),b1.removeEventListener("ended",U1),b1.removeEventListener("error",Q1),b1.removeEventListener("waiting",G2),b1.removeEventListener("canplay",T4),b1.removeEventListener("stalled",f4)}},[A?.url,e2]);const r2=N?.error?`Error: ${N.error}`:N?.objectUrl?"snapshot":N?.status||"waiting",i2=Y1?r2:L?.url?k==="error"?`Error: ${t1||"unknown"}`:t1?`${k} (${t1})`:k:"waiting",M2=A?.error?`Error: ${A.error}`:A?.url?m1==="error"?`Error: ${_||"unknown"}`:_?`${m1} (${_})`:m1:"waiting",n4=!Y1&&!L?.error&&k!=="playing";return r.jsxs(r.Fragment,{children:[Y1?N?.objectUrl?r.jsx("img",{src:N.objectUrl,alt:T,className:"h-full w-full object-contain",style:p1,draggable:!1}):r.jsx("div",{className:"flex h-full w-full items-center justify-center text-sm text-slate-300",children:"Waiting for frame…"}):r.jsx("video",{ref:F,muted:v||S1||P1,playsInline:!0,autoPlay:!0,controls:!1,className:"h-full w-full object-contain",style:p1}),n4?r.jsx("div",{className:"pointer-events-none absolute inset-0 z-10 flex items-center justify-center bg-black/45",children:r.jsx("div",{className:"rounded border border-slate-500/70 bg-black/70 px-3 py-1 text-sm font-semibold text-slate-100",children:"Connecting to video...."})}):null,r.jsx("audio",{ref:U,autoPlay:!0,hidden:!0}),r.jsx("div",{className:"pointer-events-none absolute left-1 top-1 z-20 font-medium text-slate-100 text-[0.65rem]",children:r.jsxs("div",{className:"flex flex-col gap-0.5 leading-none",children:[r.jsxs("span",{children:["Status: ",i2]}),M2?r.jsxs("span",{children:["Audio: ",M2]}):null]})})]})}function HK(t){const a=u1(R=>R.session?.mode||null),l=u1(R=>R.session?.roster??[]),s=u1(R=>R.session?.users??[]),u=u1(R=>R.session?.turnQueues??{}),f=u1(R=>R.session?.socketId||null),v=u1(R=>R.session?.activeDrivers??{}),p=a==="turns",g=Z8(1e3,p),x=t&&u?.[t]||null,z=t&&v?.[t]||null,b=!!(f&&z===f),y=d.useMemo(()=>{const R=x?.queue||[];if(!R.length||!x?.current||R.length<=1)return null;const j=R.findIndex(F=>F===x.current);return j===-1?R[0]||null:R[(j+1)%R.length]||null},[x]),H=!!(f&&y===f),S=x?.deadline||null,C=S?S-g:null,w=l.length,L=d.useMemo(()=>{const R=new Set;return s.forEach(j=>{if(String(j?.role||"")==="spectator")return;const U=String(j?.roverId||"").trim(),O=String(j?.socketId||"").trim();!U||!O||R.add(O)}),R.size},[s]),A=p&&L>w,V=p&&H&&C!=null&&C<=5e3&&C>0;return p&&!b&&!V&&A?"snapshot":null}function AK(t){const a=t?.session?.socials;return Array.isArray(a)?a:[]}function VK(t,a){const l=String(a||"").trim().toLowerCase();return l&&AK(t).find(s=>String(s?.id||s?.label||"").trim().toLowerCase()===l)||null}function LK(t){if(typeof t!="string")return null;const a=t.trim();return a&&(/^#[0-9a-fA-F]{3,8}$/.test(a)||/^(rgb|rgba|hsl|hsla)\([^)]+\)$/.test(a))?a:null}function BK(t){if(typeof t!="string"||!t.trim())return xc;const a=SP[t.trim()];return typeof a=="function"?a:xc}function r7({id:t=null,label:a,url:l,icon:s,color:u,layout:f="stacked",className:v=""}){const p=u1(C=>t?VK(C,t):null),g=l||p?.url||null;if(!g)return null;const x=s||p?.icon||null,z=u||p?.color||null,b=BK(x),y=LK(z),H=a||p?.label||"Link",S=f==="inline";return r.jsx("a",{href:g,target:"_blank",rel:"noopener noreferrer","aria-label":H,onClick:()=>{d1("social_link_click",{id:t||"",label:H,layout:f}),t==="discord"&&d1("discord_click",{layout:f})},className:`grid h-full min-h-0 w-full place-items-center rounded-md bg-slate-700 px-0.5 ${S?"py-0.5":"pb-3"} text-center text-sm font-medium text-white transition hover:opacity-90 ${v}`,style:y?{backgroundColor:y}:void 0,children:S?r.jsxs("span",{className:"inline-flex max-w-full items-center justify-center gap-1 text-center leading-tight",children:[r.jsx(b,{className:"shrink-0",style:{fontSize:"1.1em"}}),r.jsx("span",{className:"break-words",children:H})]}):r.jsxs("span",{className:"flex h-full w-full max-w-full flex-col items-center justify-between text-center leading-tight",children:[r.jsx("span",{className:"flex min-h-0 flex-1 items-center justify-center",children:r.jsx(b,{className:"shrink-0",style:{fontSize:"clamp(1rem, 2.2vh + 1.2vw, 2rem)"}})}),r.jsx("span",{className:"w-full break-words leading-tight",children:H})]})})}function jK({roverId:t=null,mobileHud:a=!1}){const l=u1(s1=>s1.session?.assignment?.roverId??null),s=t??l,u=u1(s1=>s1.session?.mode||null),f=u1(s1=>s1.session?.roster??[]),v=u1(s1=>s1.session?.users??[]),p=u1(s1=>s1.session?.turnQueues??{}),g=u1(s1=>s1.session?.socketId||null),x=u1(s1=>s1.session?.activeDrivers??{}),z=q1(s1=>s1.state.lastControlIntentAt),[b,y]=d.useState(!1),[H,S]=d.useState(null),[C,w]=d.useState(!1),[L,A]=d.useState(0),V=d.useRef({initialized:!1,roverId:null,activeDriverId:null}),N=d.useRef(z||0),T=a?"text-[0.5rem]":"text-[0.7rem]",R=a?"px-0.5 py-0.25":"px-1 py-0.5",j=a?"text-3xl":"text-5xl",F=a?"text-xs":"text-sm",U=a?"text-[0.55rem]":"text-[0.75rem]",O=a?"px-4 py-3":"px-6 py-4",q=s?p?.[s]:null,$=s?x?.[s]:null,e1=!!(g&&$===g),n1=u==="turns",J=Z8(1e3,n1),k=d.useMemo(()=>{const s1=q?.queue||[];if(!s1.length||!q?.current||s1.length<=1)return null;const H1=s1.findIndex(p1=>p1===q.current);return H1===-1?s1[0]||null:s1[(H1+1)%s1.length]||null},[q]),I=!!(g&&k===g),t1=q?.deadline||null,f1=q?.idleDeadline||null,m1=t1?t1-J:null,E=f1?f1-J:null,_=f.length,K=d.useMemo(()=>{const s1=new Set;return v.forEach(H1=>{if(String(H1?.role||"")==="spectator")return;const x1=String(H1?.roverId||"").trim(),L1=String(H1?.socketId||"").trim();!x1||!L1||s1.add(L1)}),s1.size},[v]),r1=n1&&K>_,v1=n1&&I&&m1!=null&&m1<=5e3&&m1>0,g1=n1&&!e1,V1=g1&&!v1&&r1,S1=m1!=null&&Number.isFinite(m1)?Math.max(0,Math.ceil(m1/1e3)):null,N1=E!=null&&Number.isFinite(E)?Math.max(0,Math.ceil(E/1e3)):null,P1=d.useMemo(()=>!n1||!e1?null:S1!=null?`${S1}s left`:"Your turn",[n1,e1,S1]),Y1=d.useMemo(()=>!g1||!I||S1==null?null:`${S1} seconds until your turn.`,[g1,I,S1]),R1=e1&&typeof N1=="number",p2=C;return d.useEffect(()=>{if(u!=="turns"){y(!1),S(null),V.current={initialized:!1,roverId:null,activeDriverId:null};return}const s1=V.current,H1=$||null;if(!g||!s){y(!1),S(null),V.current={initialized:!1,roverId:null,activeDriverId:null};return}if(!s1.initialized||s1.roverId!==s){V.current={initialized:!0,roverId:s,activeDriverId:H1};return}!!s1.activeDriverId&&s1.activeDriverId!==g&&H1===g?(y(!0),S(Date.now())):H1!==g&&b&&(y(!1),S(null)),V.current={initialized:!0,roverId:s,activeDriverId:H1}},[$,u,s,g,b]),d.useEffect(()=>{!b||!H||z>H&&y(!1)},[z,b,H]),d.useEffect(()=>{const s1=Number(N.current)||0,H1=Number(z)||0;H1>s1&&g1&&A(Date.now()),N.current=H1},[z,g1]),d.useEffect(()=>{if(!g1||!L)return;w(!0);const s1=setTimeout(()=>w(!1),650);return()=>clearTimeout(s1)},[g1,L]),r.jsxs(r.Fragment,{children:[b?r.jsx("div",{className:"pointer-events-none absolute inset-0 z-30 flex items-center justify-center bg-black/55",children:r.jsxs("div",{className:`flex flex-col items-center gap-0.5 rounded border border-amber-300/80 bg-black/70 ${O}`,children:[r.jsx("div",{className:`font-semibold text-amber-200 ${j}`,children:"IT IS YOUR TURN!"}),r.jsx("div",{className:`text-amber-200/80 ${F}`,children:"Start driving!"}),R1?r.jsxs("div",{className:`text-red-100/90 ${U}`,children:["Idle skip in ",N1,"s"]}):null]})}):null,P1?r.jsx("div",{className:`pointer-events-none absolute bottom-1 left-1 rounded border ${p2?"border-red-300/90 bg-red-900/80 text-red-100":"border-amber-300/80 bg-black/75 text-amber-200"} ${R} ${T}`,children:P1}):null,g1?r.jsx("div",{className:"pointer-events-none absolute bottom-1 left-1 z-40",children:r.jsxs("div",{className:`w-fit rounded border ${C?"border-red-300/90 bg-red-900/80 text-red-100":"border-amber-300/80 bg-black/75 text-amber-200"} ${a?"px-2 py-1 text-[0.6rem]":"px-3 py-1.5 text-sm"}`,children:[r.jsx("div",{className:C?"text-[0.82rem] font-semibold text-red-50":"text-[0.82rem] font-semibold text-white",children:"Not your turn to drive!"}),Y1?r.jsx("div",{className:C?"text-red-100/95":"text-amber-100",children:Y1}):null,V1?r.jsx("div",{className:C?"text-red-100/90":"text-amber-200/85",children:"Video switched to preview mode to save bandwidth."}):null,r.jsx("div",{className:"pointer-events-auto mt-0.5",children:r.jsx(r7,{id:"discord",label:"Join our Discord while you wait!",layout:"inline"})})]})}):null]})}const NK=H2.memo(jK);function Eu(){const{value:t,save:a}=T1("page",{hudMapDesktop:!1});return[!!t?.hudMapDesktop,u=>{a({hudMapDesktop:!!u})}]}function xs({variant:t="default",label:a,roverColor:l=null,driverLabel:s=null,mobileHud:u=!1,labelScale:f=1}){const v=u?"px-0.25 py-0.25":"px-0.5 py-0.5",p=u?"text-[0.55rem]":"text-[0.8rem]",g="bottom-0.5",x={transform:`translateX(-50%) scale(${f})`,transformOrigin:"center bottom"};return t==="spectator"?r.jsx("div",{className:`absolute ${g} left-1/2`,style:x,children:r.jsxs("div",{className:`flex items-center gap-0.5 bg-black/80 text-slate-100 ${v} ${p}`,children:[r.jsx(V4,{name:a,color:l}),s?r.jsxs("span",{className:"text-slate-300",children:["• ",s]}):null]})}):r.jsx("div",{className:`absolute ${g} left-1/2`,style:x,children:r.jsx("div",{className:`flex gap-0.5 bg-black/80 text-slate-100 ${v} ${p}`,children:r.jsx(V4,{name:a,color:l})})})}function FK({sensors:t,telemetry:a=null,mobileHud:l=!1}){const s=a?.voltageMv??t?.voltageMv??null,u=a?.currentMa??t?.currentMa??null,f=a?.batteryChargeMah??t?.batteryChargeMah??null,v=a?.oiModeLabel??t?.oiMode?.label??"Unknown",p=a?.homeBase??!!t?.chargingSources?.homeBase,g=a?.chargingStateLabel??t?.chargingState?.label??"",x=l?"px-0.25 py-0.25":"px-1 py-0.5",z=l?"left-0.5 top-1/2":"left-1 top-1/2",b=l?"text-[0.45rem]":"text-[0.65rem]",y=[["Voltage",s!=null?`${(s/1e3).toFixed(2)} V`:"--"],["Current",u!=null?`${u} mA`:"--"],["Charge",f!=null?`${f}`:"--"],["OI",v||"--"]],H=!!(g&&g.toLowerCase()!=="not charging"),S=v.toLowerCase(),C=S==="full"?"bg-emerald-500/80 text-emerald-50":S==="safe"?"bg-amber-400/80 text-amber-950":S==="passive"?"bg-slate-700/80 text-slate-100":"bg-slate-700/60 text-slate-200",w=p?"bg-emerald-500/80 text-emerald-50":"bg-slate-700/70 text-slate-200",L=H?"bg-emerald-500/80 text-emerald-50":p?"bg-amber-400/80 text-amber-950":"bg-slate-700/70 text-slate-200";return r.jsx("div",{className:`absolute ${z} flex -translate-y-1/2 flex-col gap-0.5 bg-black/70 text-slate-100 ${b} ${x}`,children:r.jsxs("div",{className:"space-y-0.5 leading-tight",children:[r.jsxs("div",{className:"flex flex-col gap-0.5 text-[0.75rem] font-semibold uppercase tracking-wide",children:[r.jsx("span",{className:`rounded px-1.5 py-0.5 ${w}`,children:p?"Docked":"Undocked"}),r.jsx("span",{className:`rounded px-1.5 py-0.5 ${L}`,children:H?"Charging":"Not charging"}),r.jsxs("span",{className:`rounded px-1.5 py-0.5 ${C}`,children:["OI: ",v]})]}),y.map(([A,V])=>r.jsxs("span",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{className:"text-slate-400",children:A}),r.jsx("span",{className:"font-semibold text-white",children:V})]},A))]})})}function i7(t){return Math.max(0,Math.min(1,t))}function Tu(t){return(t-90)*Math.PI/180}function j8(t,a,l,s){const u=Tu(s);return{x:t+l*Math.cos(u),y:a+l*Math.sin(u)}}function kK(t,a,l,s,u){let f=s,v=u;v<=f&&(v+=360);const p=j8(t,a,l,f),g=j8(t,a,l,v);return["M",p.x,p.y,"A",l,l,0,0,1,g.x,g.y].join(" ")}function ia(t,a){if(a)return"#ef4444";const l=Math.abs(t);return l>900?"#f59e0b":l>300?"#22c55e":"#64748b"}function RK(t,a){if(t==null||t<=0)return"hsl(200 60% 18%)";const s=i7(t/(a||1));return`hsl(${(200+Math.pow(s,.45)*360)%360} 100% 60%)`}function EK(t,a){if(a)return"#ef4444";const l=i7(t==null?0:t/4095),s=[47,55,69],u=[245,158,11],[f,v,p]=s.map((g,x)=>Math.round(g+(u[x]-g)*l));return`rgb(${f}, ${v}, ${p})`}function TK({count:t,totalSpan:a,gap:l,startAngle:s}){const f=(a-l*(t-1))/t,v=[];let p=s;for(let g=0;gkK(a,l,z,f,v),[a,l,v,z,f]);return r.jsxs(r.Fragment,{children:[r.jsx("path",{d:y,stroke:p,strokeWidth:b,strokeLinecap:"round",fill:"none",opacity:x}),g?r.jsx("path",{d:y,stroke:"#ef4444",strokeWidth:b,strokeLinecap:"round",fill:"none",className:"animate-pulse",opacity:1}):null]})}),qK=H2.memo(function({cx:a,cy:l,rBase:s,rTip:u,startDeg:f,endDeg:v,color:p,value:g,max:x}){const z=(f+v)/2,b=i7(g!=null?g/(x||1):0),y=Math.pow(b,.35),H=s-(s-u)*y,S=Math.max(u,Math.min(H,s)),C=d.useMemo(()=>{const w=j8(a,l,u,z),L=j8(a,l,S,f),A=j8(a,l,S,v);return`M ${w.x} ${w.y} L ${L.x} ${L.y} L ${A.x} ${A.y} Z`},[S,a,l,v,z,u,f]);return r.jsx("path",{d:C,fill:p,opacity:1,stroke:"none"})}),zs=H2.memo(function({cx:a,cy:l,current:s,drop:u,overcurrent:f,label:v}){const p=Math.abs(s),g=i7(p/1200),x=ia(s,f),z=56,b=14,y=9,H=3,S=z*g,C=v==="L"?-1:1,w=C*(-y/2-H/2),L=C*(b/2+H/2),A=b+y+H+2,V=z+4;return r.jsxs("g",{transform:`translate(${a},${l})`,children:[r.jsx("rect",{x:-A/2,y:-V/2,width:A,height:V,rx:"4",fill:"none",stroke:"#64748b",strokeWidth:"1"}),r.jsx("rect",{x:w-b/2,y:-z/2,width:b,height:z,fill:"#0f172a",stroke:"#0f172a",strokeWidth:"1",rx:"2"}),r.jsx("rect",{x:w-b/2,y:z/2-S,width:b,height:S,fill:x,className:f?"animate-pulse":""}),r.jsx("rect",{x:L-y/2,y:-z/2,width:y,height:z,fill:u?"#ef4444":"#475569",className:u?"animate-pulse":"",rx:"2"}),r.jsx("text",{x:0,y:z/2+10,textAnchor:"middle",className:"fill-slate-200 text-[0.7rem]",children:v})]})}),_K=H2.memo(function({cx:a,cy:l,current:s,overcurrent:u}){let f=Math.abs(s);f<10&&(f=0);const v=ia(s*3,u),p=43,g=f>0?.65:null;return r.jsxs("g",{style:{transformOrigin:`${a}px ${l}px`,animation:g?`spin ${g}s linear infinite`:"none",animationDirection:g?"reverse":"normal"},children:[r.jsx("circle",{cx:a,cy:l,r:10,fill:"#64748b",stroke:"#64748b",strokeWidth:"1"}),[0,120,240].map(z=>{const b=Tu(z),y=a+p*Math.cos(b),H=l+p*Math.sin(b);return r.jsx("line",{x1:a,y1:l,x2:y,y2:H,stroke:v,strokeWidth:"4",strokeLinecap:"round"},z)}),u?r.jsx("circle",{cx:a,cy:l,r:p+8,stroke:"#ef4444",strokeWidth:"3",fill:"none",className:"animate-pulse"}):null]})}),DK=H2.memo(function({cx:a,cy:l,current:s,overcurrent:u,variant:f}){const v=Math.abs(s),p=ia(s,u),g=1,x=96,z=12,b=`main-brush-pattern-a-${f}`,y=`main-brush-pattern-b-${f}`,H=v>0?.6:null,S=s>=0?1:-1;return r.jsxs("g",{children:[r.jsx("defs",{children:[b,y].map((C,w)=>r.jsxs("pattern",{id:C,patternUnits:"userSpaceOnUse",width:"6",height:"6",children:[r.jsx("rect",{width:"6",height:"6",fill:p,opacity:g}),r.jsx("path",{d:"M0 6 L6 0",stroke:"#0f172a",strokeWidth:"1"}),H?r.jsx("animateTransform",{attributeName:"patternTransform",type:"translate",from:"0 0",to:`0 ${S*(w===0?6:-6)}`,dur:`${H}s`,repeatCount:"indefinite"}):null]},C))}),r.jsx("rect",{x:a-x/2,y:l-14,width:x,height:z,rx:"3",fill:`url(#${b})`,stroke:"#64748b",strokeWidth:"1"}),r.jsx("rect",{x:a-x/2,y:l+4,width:x,height:z,rx:"3",fill:`url(#${y})`,stroke:"#64748b",strokeWidth:"1"}),r.jsx("circle",{cx:a-x/4,cy:l-8,r:3.5,fill:"#fbbf24"}),r.jsx("circle",{cx:a+x/4,cy:l+8,r:3.5,fill:"#fbbf24"}),u?r.jsx("rect",{x:a-x/2-4,y:l-16,width:x+8,height:z*2+16,rx:"6",stroke:"#ef4444",strokeWidth:"3",fill:"none",className:"animate-pulse"}):null]})}),OK=["L","FL","CL","CR","FR","R"];function UK(t,a){const l=t/2,s=t*.05,u=l,f=l+s,v=l*.8,p=v-4,g=v+4,x=v-14,z=v-6,b=v*.65,y=TK({count:6,totalSpan:140,gap:6,startAngle:-70});return{size:t,variant:a,centerX:u,centerY:f,innerCircle:v,lightRingInner:p,lightRingOuter:g,cliffRingInner:x,cliffRingOuter:z,wheelLineOffset:b,lightSegments:y.map((H,S)=>({label:OK[S],start:H.start,end:H.end})),cliffSegments:[{label:"Cliff L",start:-60,end:-46,valueKey:"cliffLeftSignal",activeKey:"cliffLeft"},{label:"Cliff FL",start:-32,end:-16,valueKey:"cliffFrontLeftSignal",activeKey:"cliffFrontLeft"},{label:"Cliff FR",start:16,end:32,valueKey:"cliffFrontRightSignal",activeKey:"cliffFrontRight"},{label:"Cliff R",start:46,end:60,valueKey:"cliffRightSignal",activeKey:"cliffRight"}]}}function ZK({sensors:t={},mapTelemetry:a=null,variant:l="full",size:s,overlay:u=!1}){const f=s||(l==="mini"?190:260),v=d.useMemo(()=>UK(f,l),[f,l]),p=a??Ic({sensors:t}),g=p.wheelLeftCurrentMa??0,x=p.wheelRightCurrentMa??0,z=p.sideBrushCurrentMa??0,b=p.mainBrushCurrentMa??0,y=6,H=p.bumpLeft?y:0,S=p.bumpRight?y:0,C=[p.lightBumpLeftSignal,p.lightBumpFrontLeftSignal,p.lightBumpCenterLeftSignal,p.lightBumpCenterRightSignal,p.lightBumpFrontRightSignal,p.lightBumpRightSignal],w=C.filter(A=>A!=null),L=w.length?Math.max(...w,1200):1200;return r.jsx("div",{className:`${u?"relative":"relative p-1"}`,style:u?{width:`${f}px`,height:`${f}px`}:{height:"100%",width:"100%",aspectRatio:"1 / 1"},children:r.jsxs("svg",{width:"100%",height:"100%",viewBox:`0 0 ${f} ${f}`,preserveAspectRatio:"xMidYMid meet",className:"mx-auto block",children:[r.jsx("circle",{cx:v.centerX,cy:v.centerY,r:v.innerCircle,fill:"#0f172a",stroke:"#334155",strokeWidth:"2"}),r.jsx(zs,{cx:v.centerX-v.wheelLineOffset,cy:v.centerY,current:g,drop:p.wheelDropLeft,overcurrent:p.leftWheelOvercurrent,label:"L"}),r.jsx(zs,{cx:v.centerX+v.wheelLineOffset,cy:v.centerY,current:x,drop:p.wheelDropRight,overcurrent:p.rightWheelOvercurrent,label:"R"}),r.jsx(_K,{cx:v.centerX+v.innerCircle*.65,cy:v.centerY-v.innerCircle*.55,current:z,overcurrent:p.sideBrushOvercurrent}),r.jsx(DK,{cx:v.centerX,cy:v.centerY,current:b,overcurrent:p.mainBrushOvercurrent,variant:l}),v.lightSegments.map((A,V)=>{const N=C[V],T=RK(N,L),R=v.lightRingOuter+4,j=R+28;return r.jsx(qK,{cx:v.centerX,cy:v.centerY,rBase:j,rTip:R,startDeg:A.start,endDeg:A.end,color:T,value:N,max:L},A.label)}),v.cliffSegments.map(A=>r.jsx(ac,{cx:v.centerX,cy:v.centerY,rInner:v.cliffRingInner,rOuter:v.cliffRingOuter,startDeg:A.start,endDeg:A.end,color:EK(p[A.valueKey],p[A.activeKey]),opacity:1,pulse:!!p[A.activeKey]},A.label)),r.jsx(ac,{cx:v.centerX,cy:v.centerY,rInner:v.lightRingInner-H,rOuter:v.lightRingOuter-H,startDeg:-70,endDeg:-6,color:p.bumpLeft?"#ef4444":"#475569",opacity:1,pulse:!!p.bumpLeft}),r.jsx(ac,{cx:v.centerX,cy:v.centerY,rInner:v.lightRingInner-S,rOuter:v.lightRingOuter-S,startDeg:6,endDeg:70,color:p.bumpRight?"#ef4444":"#475569",opacity:1,pulse:!!p.bumpRight})]})})}const qu=H2.memo(ZK);function bs({sensors:t,mapTelemetry:a=null,show:l=!0,mapPosition:s="top-center",layoutFormat:u="desktop",mobileHud:f=!1}){if(!l)return null;const v=u==="mobile-portrait",p="240px",g=v?.3:f?.33:.7,z={width:p,height:p,opacity:f?.6:.7,transform:s==="top-center"?`translateX(-50%) scale(${g})`:`scale(${g})`,transformOrigin:s==="bottom-left"?"bottom left":s==="top-center"?"top center":"top right",...s==="bottom-left"?{left:"0.25rem",bottom:"0.25rem"}:s==="top-center"?{left:"50%",top:"0.25rem"}:{right:"0.25rem",top:"0.25rem"}};return r.jsx("div",{className:"pointer-events-none absolute rounded",style:z,children:r.jsx(qu,{sensors:t,mapTelemetry:a,size:240,overlay:!0})})}function $K({roverId:t=null,sensors:a,label:l,roverColor:s=null,layoutFormat:u="desktop",variant:f="default",driverLabel:v=null,showTopDown:p=void 0,mobileHud:g=!1,mapPosition:x=null,labelScale:z=1}){const b=u1(O=>O.session?.assignment?.roverId??null),y=t??b,H=Z4(y,Ic,To),S=Z4(y,Np,Fp),C=u1(O=>{if(!y)return{label:null,roverColor:null};const $=(O.session?.roster||[]).find(e1=>String(e1.id)===String(y));return{label:$?.name||null,roverColor:$?.color||null}}),w=u1(O=>{if(!y||f!=="spectator")return null;const q=O.session?.activeDrivers?.[y]||null,e1=(O.session?.users||[]).find(n1=>String(n1.socketId||"")===String(q||""));return e1?.nickname||e1?.name||null}),L=a?null:H,A=a??null,V=l??C.label??null,N=s??C.roverColor??null,T=v??w,R=g,[j]=Eu(),F=typeof p=="boolean"?p:f==="spectator"||R?!0:j,U=x||(f==="spectator"?"top-center":R?"top-right":"top-center");return f==="none"?null:f==="spectator"?r.jsxs(r.Fragment,{children:[r.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[r.jsx(FK,{sensors:A,telemetry:a?null:S,mobileHud:R}),r.jsx(xs,{variant:"spectator",label:V,roverColor:N,driverLabel:T,mobileHud:R,labelScale:z})]}),r.jsx(bs,{sensors:A,mapTelemetry:L,show:F,mapPosition:U,layoutFormat:u,mobileHud:R})]}):r.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[r.jsx(xs,{variant:"default",label:V,roverColor:N,mobileHud:R,labelScale:z}),r.jsx(bs,{sensors:A,mapTelemetry:L,show:F&&f!=="spectator",mapPosition:U,layoutFormat:u,mobileHud:R})]})}const _u=H2.memo($K);function IK({mobileHud:t=!1}){const{visible:a,statusLabel:l,statusTone:s,active:u,charging:f}=A0({manageLifecycle:!0}),[v,p]=d.useState(""),g=d.useRef(null),x=d.useRef(u);if(d.useEffect(()=>{const b=x.current;u&&!b?p("Dock assist mode enabled"):!u&&b&&f&&p("Docking successful! Thank you!"),x.current=u},[u,f]),d.useEffect(()=>{if(v)return g.current&&clearTimeout(g.current),g.current=setTimeout(()=>{p(""),g.current=null},2500),()=>{g.current&&(clearTimeout(g.current),g.current=null)}},[v]),!a)return null;const z=s==="good"?"border-emerald-200/90 bg-emerald-900/90 text-emerald-50":s==="warn"?"border-amber-200/90 bg-amber-900/90 text-amber-50":"border-cyan-200/90 bg-cyan-900/90 text-cyan-50";return r.jsx("div",{className:"pointer-events-none absolute inset-0",children:v?r.jsx("div",{className:"absolute inset-0 flex items-center justify-center",children:r.jsx("div",{className:`rounded-xl border border-indigo-200/95 bg-black/95 px-4 py-2 text-center font-semibold text-indigo-50 shadow-2xl ${t?"text-lg":"text-2xl"}`,children:v})}):r.jsx("div",{className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-lg border px-2 py-1 font-semibold shadow-lg ${z} ${t?"text-[0.65rem]":"text-xs"}`,children:l})})}const GK=H2.memo(IK),Ms=5e3,PK=700;function Du({roverId:t=null,description:a,variant:l="default",mobileHud:s=!1,displayKey:u="",controlIntentAt:f}){const v=u1(A=>A.session?.assignment?.roverId??null),p=t??v,g=u1(A=>p&&(A.session?.roster||[]).find(T=>String(T.id)===String(p))?.description||null),x=a??g,z=typeof f=="number"?f:0,b=u||`${p||""}::${x||""}`,[y,H]=d.useState(!1),[S,C]=d.useState(!1),w=d.useRef(null),L=d.useRef(null);return d.useEffect(()=>()=>{clearTimeout(w.current),clearTimeout(L.current)},[]),d.useEffect(()=>{if(l!=="default"||!x){H(!1),C(!1),clearTimeout(w.current),clearTimeout(L.current);return}clearTimeout(w.current),clearTimeout(L.current),H(!0),C(!1)},[x,b,l]),d.useEffect(()=>{l!=="default"||!x||!y||S||(Number(z)||0)<=0||w.current||L.current||(w.current=setTimeout(()=>{C(!0),w.current=null},Ms),L.current=setTimeout(()=>{H(!1),L.current=null},Ms+PK))},[z,x,S,y,l]),x?l==="spectator"?r.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-1 z-50 flex justify-center",children:r.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:x})}):l!=="default"||!y?null:r.jsx("div",{className:"pointer-events-none absolute inset-0 z-50 flex items-center justify-center",children:r.jsxs("div",{className:`surface max-w-[94%] border border-slate-400 bg-neutral-900 px-2 py-1 text-center font-semibold text-slate-100 shadow-xl transition-opacity duration-700 ${S?"opacity-0":"opacity-100"} ${s?"text-[1rem] leading-tight":"text-[1.5rem] leading-tight"}`,children:[r.jsx("p",{children:"Just so you know, this rover"}),r.jsx("p",{children:x}),r.jsx("p",{className:`${s?"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 YK={leftWheel:"Left wheel",rightWheel:"Right wheel",mainBrush:"Main brush",sideBrush:"Side brush",limiter:"Overcurrent limit"};function KK({roverId:t=null,sensors:a,overcurrentLimiter:l=null,compact:s=!1}){const u=u1(j=>j.session?.assignment?.roverId??null),f=t??u,v=Z4(f,qo,_o),p=au(f),g=a?.wheelOvercurrents??v,x=l??p??null,z=d.useMemo(()=>g==null?[]:Object.entries(g).filter(([,j])=>!!j).map(([j])=>j),[g]),b=x?.caps||null,y=d.useMemo(()=>{if(!b)return null;const j=Number.isFinite(b?.drive?.cap)?b.drive.cap:1,F=Number.isFinite(b?.aux?.cap)?b.aux.cap:1;return Math.max(0,Math.min(1,1-Math.min(j,F)))},[b]),H=!!x?.isActive,S=d.useMemo(()=>z.length?z:H?["limiter"]:[],[z,H]),C=y??(z.length?1:0);if(!S?.length)return null;const w=S.map(j=>YK[j]||j),L=s?"w-[12rem] h-[3.5rem]":"w-[20rem] h-[7rem]",A=s?"px-2 py-1":"px-4 py-2",V=s?"text-lg":"text-4xl",N=s?"text-xs":"text-xl",T=Math.max(0,Math.min(1,C)),R=`${Math.round(T*100)}%`;return r.jsx("div",{className:`pointer-events-none absolute flex items-center justify-center bg-red-900/50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 ${L}`,children:r.jsxs("div",{className:"relative h-full w-full",children:[r.jsx("div",{className:"absolute inset-0 overflow-hidden",children:r.jsx("div",{className:"h-full bg-red-700/60",style:{width:R}})}),r.jsxs("div",{className:`relative z-10 flex h-full w-full flex-col items-center justify-center text-center font-semibold text-white animate-pulse ${V} ${A}`,children:[r.jsx("div",{children:"OVERCURRENT"}),r.jsx("div",{className:`mt-0 font-medium text-white ${N}`,children:w.join(", ")})]})]})})}const Ou=H2.memo(KK),T8=10;function I8({batteryState:t=null,charge:a=null,config:l=null}){const s=t?.percentDisplay!=null&&Number.isFinite(t.percentDisplay)?Math.round(t.percentDisplay):null,u=t?.warnActive??null,f=t?.urgentActive??null,v=l?.Full??null,p=l?.Warn??null,g=l?.Urgent??null,x=a??t?.charge??null;let z=s;if(z==null&&(z=QK({charge:x,full:v,warn:p,urgent:g})),z==null)return{available:!1};const b=Math.max(0,Math.min(1,z/100)),y=u??(p!=null&&x!=null&&x<=p),H=f??(g!=null&&x!=null&&x<=g);return{available:!0,percent:b,percentDisplay:z,warnActive:y,urgentActive:H,warnDisplayPercent:T8}}function QK({charge:t,full:a,warn:l,urgent:s}){if(t!=null&&a!=null&&l!=null&&s!=null&&a>l&&l>s){const u=T8/100,f=1-u;if(t<=s)return 0;if(t<=l){const p=(t-s)/(l-s);return Math.round(Math.max(0,Math.min(1,p))*T8)}if(t>=a)return 100;const v=(t-l)/(a-l);return Math.round((u+Math.max(0,Math.min(1,v))*f)*100)}return null}function XK({roverId:t=null,sensors:a,batteryConfig:l,compact:s=!1}){const u=u1(S=>S.session?.assignment?.roverId??null),f=t??u,v=Z4(f,l7,n7),p=u1(S=>f?(S.session?.roster||[]).find(L=>String(L.id)===String(f))?.battery??null:null),g=a?{batteryChargeMah:a?.batteryChargeMah??null,batteryCapacityMah:a?.batteryCapacityMah??null}:v,x=l??p,z=I8({charge:g?.batteryChargeMah??null,config:x});if(!z?.available||!z.warnActive&&!z.urgentActive)return null;const b=z.urgentActive?"BATTERY VERY LOW, DOCK THE ROVER AND CHARGE IMMEDIATELY!!":"Battery low! please dock and charge the rover soon.",y=s?"p-2 top-6":"p-4 top-10",H=s?"text-sm":"text-2xl";return r.jsx("div",{className:`pointer-events-none absolute flex items-center justify-center bg-amber-900/60 left-1/2 -translate-x-1/2 ${y}`,children:r.jsx("div",{className:`text-center font-semibold text-white animate-pulse ${H}`,children:r.jsx("div",{children:b})})})}const Uu=H2.memo(XK);function JK({roverId:t=null,sensors:a}){const l=u1(b=>b.session?.assignment?.roverId??null),u=Z4(t??l,Vp,Lp),f=a?[a?.lightBumpLeftSignal,a?.lightBumpFrontLeftSignal,a?.lightBumpCenterLeftSignal,a?.lightBumpCenterRightSignal,a?.lightBumpFrontRightSignal,a?.lightBumpRightSignal]:u,v=f.filter(b=>b!=null).reduce((b,y)=>Math.max(b,y),1200),p=b=>Math.pow(Math.max(0,Math.min(1,(b??0)/v)),.35),g=b=>b==null||b<=0?"hsl(200 60% 18%)":`hsl(${(200+p(b)*360)%360} 100% 60%)`,x=6,z=12;return r.jsx("div",{className:"flex w-full items-center justify-center gap-0.5",children:f.map((b,y)=>{const H=p(b),S=yp.session?.assignment?.roverId??null),s=t??l,u=Z4(s,l7,n7),f=u1(p=>s?(p.session?.roster||[]).find(z=>String(z.id)===String(s))?.battery??null:null),v=I8({charge:u?.batteryChargeMah??null,config:f});return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx(WK,{roverId:s}),r.jsx("div",{className:"space-y-0.5 text-sm",children:r.jsx(s7,{visual:v,compact:a})})]})}function nQ(){if(typeof navigator>"u")return!1;const t=navigator.userAgent||"",a=navigator.vendor||"";return/safari/i.test(t)&&/apple/i.test(a)&&!/crios|fxios|edgios|opr|chrome|android/i.test(t)}function lQ({compact:t=!1}){const a=u1(O=>O.session?.role||null),l=u1(O=>O.session?.assignment?.roverId||null),s=u1(O=>O.session?.roster||[]),{sendMessage:u,onInputFocus:f,onInputBlur:v,blurChat:p,registerInputRef:g,setTypingActive:x}=ca(),{value:z}=T1("tts",{engine:"chromegtts",voice:"tpf",pitch:50,googlePitch:1,googleSpeed:1}),[b,y]=d.useState(""),[H,S]=d.useState(!1),C=a!=="spectator",w=a==="spectator",A=!!d.useMemo(()=>s.find(O=>String(O.id)===String(l))||null,[l,s])?.audio?.ttsEnabled,V=d.useMemo(()=>{if(!A)return null;const O=z?.engine==="espeak"?"espeak":z?.engine==="flite"?"flite":"chromegtts";if(O==="espeak"){let $=Number.isFinite(z?.pitch)?Math.round(z.pitch):void 0;return typeof $=="number"&&($=Math.max(0,Math.min(99,$))),{speak:!0,engine:O,pitch:$}}const q=typeof z?.voice=="string"?z.voice:void 0;if(O==="chromegtts"){const $=Number.isFinite(z?.googlePitch)?z.googlePitch:1,e1=Number.isFinite(z?.googleSpeed)?z.googleSpeed:1;return{speak:!0,engine:O,voice:q,pitch:$,speed:e1}}return{speak:!0,engine:O,voice:q}},[z?.engine,z?.googlePitch,z?.googleSpeed,z?.pitch,z?.voice,A]),N=t?"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",j=`min-w-0 flex-1 bg-transparent ${d.useMemo(()=>nQ(),[])?"mobile-text-entry":t?"text-[0.55rem]":"text-[0.7rem]"} text-slate-100 placeholder:text-slate-400 focus:outline-none`,F=t?"mobile-touch-control rounded bg-cyan-500/80 px-0.35 py-0.2 text-[0.55rem] font-semibold text-black disabled:opacity-50":"mobile-touch-control rounded bg-cyan-500/80 px-0.5 py-0.25 text-[0.7rem] font-semibold text-black disabled:opacity-50";async function U(O){if(O.preventDefault(),!C)return;const q=b.trim();if(q){S(!0);try{await u(q,V),y(""),p(),x(!1)}catch($){alert($.message)}finally{S(!1)}}}return w?null:r.jsxs("form",{onSubmit:U,className:N,children:[r.jsx("input",{className:j,value:b,onChange:O=>{const q=O.target.value;y(q),x(!!q.trim())},onFocus:O=>{f(O),x(!!b.trim())},onBlur:O=>{v(O),x(!1)},onKeyDown:O=>{O.key==="Enter"&&!b.trim()&&(O.preventDefault(),p(),x(!1))},ref:O=>g(O,{target:"hud"}),placeholder:C?"Chat (tts)":"Spectator",disabled:!C}),r.jsx("button",{type:"submit",disabled:!C||H,className:F,children:"Speak"})]})}const rQ=d.memo(lQ);function sa({layoutFormat:t="desktop"}){const a=u1(f=>f.session?.assignment?.roverId??null),l=HK(a),s=q1(f=>f.state.lastControlIntentAt);if(!a)return r.jsx(j1,{hideHeader:!0,className:"shrink-0",children:r.jsxs("div",{className:"panel-muted content-center text-center text-sm text-slate-400 aspect-[4/3]",children:[r.jsx("p",{children:"You are not assigned to a rover."}),r.jsx("p",{className:"mt-0",children:r.jsx("a",{href:"/spectate",className:"text-blue-400 underline hover:text-blue-500",children:"Click here to visit the spectator page."})})]})});const u=t!=="desktop";return r.jsx(j1,{hideHeader:!0,className:"shrink-0",children:r.jsxs("div",{className:"flex flex-col gap-0.5",children:[r.jsxs("div",{className:"relative w-full overflow-hidden bg-black aspect-[4/3]",children:[r.jsx(E8,{roverId:a,videoMode:l}),r.jsx(NK,{mobileHud:u}),r.jsx(Du,{variant:"default",mobileHud:u,controlIntentAt:s}),r.jsx(_u,{layoutFormat:t,variant:"default",mobileHud:u,labelScale:1}),r.jsx(GK,{mobileHud:u}),r.jsx(rQ,{compact:u}),r.jsx(Ou,{compact:u}),r.jsx(Uu,{compact:u})]}),r.jsx(aQ,{mobileHud:u})]})})}const iQ=Object.freeze([{id:"white",label:"White",hex:"#ffffff",action:"white"},{id:"red",label:"Red",hex:"#ff0000"},{id:"green",label:"Green",hex:"#00ff00"},{id:"cyan",label:"Cyan",hex:"#00c7be"},{id:"blue",label:"Blue",hex:"#0000ff"},{id:"purple",label:"Purple",hex:"#bf5af2"}]);function Lc({label:t,tone:a="muted"}){const l=a==="success"?"bg-emerald-900 text-emerald-100":a==="warn"?"bg-amber-900 text-amber-100":"bg-slate-800 text-slate-200";return r.jsx("span",{className:`rounded px-1 py-0.5 text-xs font-semibold leading-none ${l}`,children:t})}function Zu(...t){return t.filter(Boolean).join(" ")}function sQ(t,{unavailable:a,isOn:l,supportsColor:s}){if(a||!l)return;const u=s?t.colorHex:null;if(u)return{backgroundColor:u,borderColor:"rgba(255,255,255,0.38)"}}function oQ({entity:t,swatch:a,disabled:l,onSetColor:s,onSetWhite:u}){const f=v=>{if(v.stopPropagation(),!l){if(a.action==="white"){u(t.id).catch(()=>{});return}s(t.id,a.hex).catch(()=>{})}};return r.jsx("button",{type:"button",onClick:f,onKeyDown:v=>{v.stopPropagation()},disabled:l,title:`${a.label} ${t.name||t.id}`,"aria-label":`Set ${t.name||t.id} to ${a.label}`,className:Zu("h-5 w-6 shrink-0 rounded-sm border border-white/80 transition-transform disabled:cursor-not-allowed disabled:opacity-40",!l&&"hover:scale-110 hover:border-white"),style:{backgroundColor:a.hex}})}function uQ({entity:t,connected:a,controlsLocked:l,onToggle:s,onSetColor:u,onSetWhite:f}){const v=t.state==="unavailable"||!t.available,p=t.state==="on",g=t.type==="light"&&t.supportsColor,x=v?"warn":p?"success":"muted",z=v?"Unavailable":p?"On":"Off",b=l||!a||v,y=b||!g,H=sQ(t,{unavailable:v,isOn:p,supportsColor:g}),S=v?"border-slate-800 bg-slate-950 text-slate-500":l?"border-amber-700/60 bg-amber-950/70 text-amber-100":p?"border-emerald-700/70 bg-emerald-900 text-white":"border-neutral-700 bg-neutral-950 text-slate-300",C=()=>{b||s(t.id)},w=L=>{b||L.key!=="Enter"&&L.key!==" "||(L.preventDefault(),C())};return r.jsxs("div",{role:"button",tabIndex:b?-1:0,onClick:C,onKeyDown:w,"aria-disabled":b,className:Zu("flex min-w-[9.5rem] flex-col gap-0.5 rounded border px-0.5 py-0.5 transition-colors",b?"cursor-not-allowed opacity-70":"cursor-pointer hover:border-white/60",S),style:H,title:`${p?"Turn off":"Turn on"} ${t.name||t.id}`,children:[r.jsxs("div",{className:"-mx-0.5 -mt-0.5 grid min-h-5 grid-cols-[minmax(0,1fr)_auto] items-center gap-0.5 rounded-t bg-black/45 px-0.5 py-0.5 text-left text-white",children:[r.jsx("span",{className:"min-w-0 truncate text-[0.78rem] font-semibold leading-none",children:t.name||t.id}),r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx(Lc,{label:z,tone:x}),a?null:r.jsx("span",{className:"text-[0.65rem] font-semibold text-amber-200",children:"Offline"})]})]}),g?r.jsx("div",{className:"flex flex-wrap justify-center gap-0.5",children:iQ.map(L=>r.jsx(oQ,{entity:t,swatch:L,disabled:y,onSetColor:u,onSetWhite:f},L.id))}):null]})}function $u(){const t=q1(H=>H.state.keymap),a=u1(H=>H.session?.homeAssistant||null),{homeAssistantToggle:l,homeAssistantSetLightColor:s,homeAssistantSetLightWhite:u}=I2(),f=d.useMemo(()=>a?.entities||[],[a?.entities]),v=a?.lightPolicy||null,p=!!(v?.locked||v?.lockedOn),g=v?.lockState||(v?.lockedOn?"on":null),x=_2(t?.homeAssistantOn?.[0]),z=_2(t?.homeAssistantOff?.[0]);if(!a?.enabled)return r.jsx(j1,{title:"Room Controls",bodyClassName:"space-y-0.5 text-sm text-slate-400",children:r.jsx("p",{className:"text-slate-500",children:"Not configured on the server."})});if(f.length===0)return r.jsx(j1,{title:"Room Controls",bodyClassName:"space-y-0.5 text-sm text-slate-400",children:r.jsx("p",{className:"text-slate-500",children:"No lights or switches configured."})});const b=!!a?.connected,y=r.jsxs(r.Fragment,{children:[r.jsxs("div",{className:"flex items-center gap-0.5 text-[0.68rem] text-slate-400",children:[r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx("span",{children:"On"}),x?r.jsx(ys,{label:x}):null]}),r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx("span",{children:"Off"}),z?r.jsx(ys,{label:z}):null]})]}),p?r.jsx(Lc,{label:g==="off"?"Locked Off":"Locked On",tone:"warn"}):null,r.jsx(Lc,{label:b?"Connected":"Offline",tone:b?"success":"warn"})]});return r.jsxs(j1,{title:"Room Controls",actions:y,bodyClassName:"space-y-0.5 text-base",children:[p?r.jsx("p",{className:"rounded border border-amber-600/60 bg-amber-900/40 px-1 py-0.5 text-xs text-amber-100",children:g==="off"?"Lights are locked off. Room controls are disabled.":"Lights are locked on. Room controls are disabled."}):null,r.jsx("div",{className:"grid grid-cols-1 gap-0.5 sm:grid-cols-2 lg:grid-cols-3",children:f.map(H=>r.jsx(uQ,{entity:H,connected:b,controlsLocked:p,onToggle:l,onSetColor:s,onSetWhite:u},H.id))})]})}function ys({label:t}){return t?r.jsx("span",{className:"rounded border border-slate-600 px-1 text-[0.65rem] text-slate-300",children:t}):null}function Iu(){const{login:t}=I2(),[a,l]=d.useState(""),[s,u]=d.useState(""),[f,v]=d.useState(!1);async function p(g){g.preventDefault(),v(!0);try{await t(a,s),l(""),u("")}catch(x){alert(x.message)}finally{v(!1)}}return r.jsx(j1,{title:"Admin login",bodyClassName:"space-y-0.5 text-base",children:r.jsxs("form",{className:"flex flex-col gap-0.5",onSubmit:p,children:[r.jsx("input",{className:"field-input",placeholder:"Username",value:a,onChange:g=>l(g.target.value)}),r.jsx("input",{className:"field-input",placeholder:"Password",type:"password",value:s,onChange:g=>u(g.target.value)}),r.jsx("button",{type:"submit",disabled:f,className:"button-dark w-full disabled:opacity-50",children:f?"Logging in…":"Login"})]})})}function ws(...t){return t.filter(Boolean).join(" ")}function hQ(t){const a=t?.batteryState?.percentDisplay;return a==null?"--":`${a}%`}function dQ(t){return t?.batteryState?t.batteryState.urgentActive?"text-red-400":t.batteryState.warnActive?"text-amber-300":"text-emerald-300":"text-slate-400"}function fQ({title:t,roster:a=[],emptyText:l="No roster data.",renderActions:s=null}){return r.jsxs("div",{className:"space-y-0.5 text-sm",children:[t&&r.jsx("p",{className:"text-sm text-slate-400",children:t}),a.length===0?r.jsx("p",{className:"text-sm text-slate-500",children:l}):r.jsx("ul",{className:"space-y-0.5 text-sm",children:a.map(u=>{const f=!!(u?.private?.enabled&&u?.private?.open),v=!!u?.locked;return r.jsxs("li",{className:ws("surface flex flex-wrap items-center justify-between gap-0.5",v?"bg-red-900/40":f?"bg-amber-700/35 border border-amber-200/30":null),children:[r.jsxs("div",{children:[r.jsx("p",{children:r.jsx(V4,{rover:u,fallback:u.id})}),r.jsxs("p",{className:"text-xs text-slate-500 flex flex-wrap items-center gap-0.5",children:[r.jsx("span",{children:u.locked?"locked":"free"}),u.lockReason&&r.jsx("span",{className:"rounded bg-black/30 px-1",children:u.lockReason}),r.jsxs("span",{className:ws("font-semibold",dQ(u)),children:["Battery ",hQ(u)]})]})]}),s?s(u):null]},u.id)})})]})}function mQ(t){const a=t?.runtime||{},l=t?.output||{},s=t?.errors||{};return a.inFlight?{label:"IN FLIGHT",detail:a.reason||"Generating commentary now",className:"border-amber-400/60 bg-amber-700/20 text-amber-200"}:a.outcome==="posted"?{label:"POSTED",detail:l.posted?`Last: ${l.posted}`:"Commentary posted",className:"border-emerald-400/60 bg-emerald-700/20 text-emerald-200"}:a.outcome==="skipped"?{label:"SKIPPED",detail:a.reason||"Model chose to skip",className:"border-slate-400/60 bg-slate-700/30 text-slate-200"}:a.outcome==="failed"?{label:"FAILED",detail:s.message||a.reason||"Tick failed",className:"border-red-400/60 bg-red-700/20 text-red-200"}:{label:a.running?"IDLE":"STOPPED",detail:a.reason||"Waiting for next tick",className:"border-sky-400/50 bg-sky-700/20 text-sky-200"}}function vQ(t,a){const l=Date.now(),u=(Array.isArray(t)?t:[]).map((f,v)=>{const p=String(f?.role||"").toLowerCase(),g=typeof f?.content=="string"?f.content:JSON.stringify(f?.content??null,null,2),x=p==="system"?"LLM System":p==="assistant"?"LLM Context":p==="user"?"LLM Input":"LLM Message";return{id:`llm-msg-${v}`,message:{ts:l+v,nickname:x,text:g,role:"spectator",bot:p==="system"}}});if(a!=null){const f=String(a);u.push({id:"llm-output",message:{ts:l+u.length+1,nickname:"LLM Output",text:f.trim()?f:"",role:"spectator",bot:!0}})}return u}function pQ({state:t,onClearHistory:a,clearingHistory:l}){const[s,u]=d.useState(null);if(!t)return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),r.jsx("div",{className:"surface text-xs text-slate-300",children:"No status received yet."})]});const f=t.runtime||{},v=t.counters||{},p=t.timings||{},g=t.input||{},x=t.output||{},z=t.errors||{},b=Array.isArray(t.history)?t.history:[],y=b.find(w=>w.runId===s)||(b.length?b[b.length-1]:null),H=mQ(t),S=vQ(g.modelMessages,x.raw),C=[{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:v.skipStreak??0},{label:"clear count",value:v.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:v.promptChars??0},{label:"active drivers",value:v.snapshotSummary?.activeDrivers??0},{label:"snapshot rovers",value:v.snapshotSummary?.rovers??0},{label:"snapshot chat",value:v.snapshotSummary?.chatMessages??0}];return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),r.jsx("div",{className:"flex gap-0.5 text-xs",children:r.jsx("button",{type:"button",onClick:a,disabled:!!l,className:"button-danger disabled:cursor-not-allowed disabled:opacity-60",children:l?"Clearing...":"Clear LLM History"})}),r.jsxs("div",{className:`surface border text-center ${H.className}`,children:[r.jsx("div",{className:"text-[1.1rem] font-bold tracking-wide",children:H.label}),r.jsx("div",{className:"text-xs text-slate-200",children:H.detail})]}),r.jsx("div",{className:"surface flex flex-wrap gap-0.5 text-xs",children:C.map(w=>r.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))}),z.message?r.jsxs("div",{className:"surface text-xs text-red-300 break-words",children:["Error: ",z.message]}):null,z.details?r.jsxs("details",{className:"surface text-xs text-red-200",children:[r.jsx("summary",{className:"cursor-pointer select-none text-red-300",children:"Failure details"}),r.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-red-200",children:JSON.stringify(z.details,null,2)})]}):null,x.generated?r.jsxs("div",{className:"surface text-xs text-slate-200 break-words",children:["Generated: ",x.generated]}):null,x.posted?r.jsxs("div",{className:"surface text-xs text-emerald-200 break-words",children:["Posted: ",x.posted]}):null,r.jsxs("div",{className:"grid gap-0.5 md:grid-cols-2",children:[r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"Live Input Conversation"}),r.jsx("div",{className:"surface max-h-72 space-y-0.5 overflow-y-auto",children:S.length?S.map(w=>r.jsx(F8,{message:w.message},w.id)):r.jsx("div",{className:"text-xs text-slate-300",children:"No model conversation captured yet."})})]}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"Output + Error"}),r.jsxs("div",{className:"surface space-y-0.5 text-xs text-slate-200",children:[r.jsxs("div",{children:["Raw output: ",x.raw?.trim()?x.raw:""]}),r.jsxs("div",{children:["Posted: ",x.posted||""]}),r.jsxs("div",{children:["Output at: ",x.modelOutputAt?new Date(x.modelOutputAt).toLocaleString():"n/a"]}),r.jsxs("div",{children:["Failed at: ",z.failedAt?new Date(z.failedAt).toLocaleString():"n/a"]})]})]})]}),r.jsxs("details",{className:"surface text-xs text-slate-200",children:[r.jsx("summary",{className:"cursor-pointer select-none text-slate-300",children:"Full Monitor Payload"}),r.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-slate-200",children:JSON.stringify(t,null,2)})]}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"Recent Runs"}),r.jsx("div",{className:"surface max-h-52 space-y-0.5 overflow-y-auto text-xs",children:b.length?b.slice().reverse().map(w=>r.jsxs("button",{type:"button",onClick:()=>u(w.runId),className:`w-full text-left surface ${y?.runId===w.runId?"border border-sky-400/50":""}`,children:[r.jsxs("span",{className:"text-slate-300",children:["#",w.runId]})," ",r.jsx("span",{className:"text-slate-200",children:w.outcome||w.phase||"--"})," ",r.jsx("span",{className:"text-slate-400",children:w.durationMs!=null?`${w.durationMs}ms`:"--"})," ",r.jsx("span",{className:"text-slate-500",children:w.reason||""})]},w.runId)):r.jsx("div",{className:"text-slate-300",children:"No runs recorded yet."})})]}),y?r.jsxs("details",{className:"surface text-xs text-slate-200",open:!0,children:[r.jsxs("summary",{className:"cursor-pointer select-none text-slate-300",children:["Run #",y.runId," details"]}),r.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-slate-200",children:JSON.stringify(y,null,2)})]}):null]})}function gQ({state:t,onClearHistory:a,clearingHistory:l}){const[s,u]=d.useState(!1);if(!t)return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"Overseer Control"}),r.jsx("div",{className:"surface text-xs text-slate-300",children:"No status received yet."})]});const f=t.runtime||{},v=t.config||{},p=t.output||{},g=t.timings||{},x=t.input||{},z=t.errors||{},b=()=>{const y=Array.isArray(x.modelMessages)?x.modelMessages:[];return y.length?y.map((H,S)=>{const C=String(H?.role||"unknown").toUpperCase(),w=String(H?.content||"");return`#${S+1} ${C} + `}),r.jsxs("p",{className:"flex flex-wrap items-center gap-0.5 text-slate-100",children:[r.jsx("span",{className:"font-semibold text-slate-300 pr-1",children:"Barcode scanned:"}),r.jsx("span",{className:"font-semibold text-white",children:l}),a?r.jsx("a",{href:a,target:"_blank",rel:"noreferrer",className:"rounded-md ml-0.5 px-2 py-1 text-xl font-semibold leading-tight tracking-normal",style:{animation:"barcode-wiki-flat-flash 0.35s steps(1, end) infinite"},children:"Wiki link"}):null]})]})}function ZP({alert:t}){if(t.kind==="buttonbox-active"&&t.payload){const a=t.payload;return r.jsx("div",{className:"pointer-events-none w-[12.5rem]",children:r.jsx(Qo,{buttonId:a.buttonId,count:a.count,goal:a.goal,rewardNumber:a.rewardNumber,rewardName:a.rewardName,className:"bg-cyan-900/45"})})}return t.kind==="chat"&&t.payload?r.jsx(F8,{message:t.payload}):t.kind==="chat-typing"&&t.payload?r.jsx(F8,{message:t.payload,variant:"typing"}):t.kind==="barcode-scan"&&t.payload?r.jsx(UP,{payload:t.payload}):r.jsx("div",{className:"pointer-events-auto min-w-0 max-w-[24rem] px-1.5 py-0.5 text-left text-[0.72rem] leading-tight text-slate-100",children:r.jsxs("p",{className:"truncate text-slate-100",children:[r.jsx("span",{className:"font-semibold text-slate-300",children:t.title||"Alert"}),r.jsx("span",{className:"text-slate-500",children:" · "}),r.jsx("span",{className:"text-white",children:t.message})]})})}const r0={main:[-127,127],side:[-127,127],vacuum:[0,127]},O9={maxSpeed:500,baseSpeed:250,boostSpeed:400},$P=60,zc=100,Wc=[31,127],x0=60,bc=8,IP=250,GP=4e3,$t=2e3,Ki=.4,PP=.8,YP={start:[128],safe:[131],full:[132],passive:[128],dock:[143]},B8={driveForward:["w"],driveBackward:["s"],driveLeft:["a"],driveRight:["d"],boostModifier:["\\"],slowModifier:["shift"],auxMainForward:["i"],auxMainReverse:["k"],auxSideForward:["o"],auxSideReverse:["l"],auxVacuumFast:["p"],auxVacuumSlow:[";"],auxAllForward:[","],cameraUp:["u"],cameraDown:["j"],nightVisionToggle:["e"],videoFilterCycle:["2"],hornHonk:["h"],micPtt:["m"],driveMacro:["f"],dockMacro:["g"],chatFocus:["enter"],songNoteUp:["ArrowUp"],songNoteDown:["ArrowDown"],homeAssistantOn:["ArrowRight"],homeAssistantOff:["ArrowLeft"]},tu=[{id:"drive-sequence",label:"Drive",description:"Start, undock, and full command sequence used by the drive button.",steps:[{type:"servo",angle:0},{type:"oi",command:"start"},{type:"pause",duration:zc},{type:"oi",command:"dock"},{type:"pause",duration:zc},{type:"oi",command:"full"},{type:"pause",duration:300},{type:"drive",speeds:{left:-300,right:-300}},{type:"pause",duration:600},{type:"drive",speeds:{left:0,right:0}}]}];function Mc(){return{vector:{x:0,y:0,boost:!1},speeds:{left:0,right:0},source:null,lastUpdatedAt:0}}function yc(){return{main:0,side:0,vacuum:0}}function KP(){return{enabled:!1,angle:null,config:null}}function kt(){return{note:x0}}function V8(){return{active:!1,heat:0,overheated:!1}}function Rt(){return{pttActive:!1}}function wc(){return{active:!1}}const Qi={roverId:null,mode:"drive",drive:Mc(),aux:yc(),camera:KP(),song:kt(),horn:V8(),mic:Rt(),manualDockAssist:wc(),lastControlIntentAt:0,macros:tu,keymap:B8,inputs:{}};function QP(t,a){switch(a.type){case"control/set-rover":return{...t,roverId:a.payload??null,drive:a.payload?t.drive:Mc(),aux:a.payload?t.aux:yc(),song:a.payload?t.song:kt(),horn:a.payload?t.horn:V8(),mic:a.payload?t.mic:Rt(),manualDockAssist:a.payload?t.manualDockAssist:wc(),lastControlIntentAt:a.payload?t.lastControlIntentAt:0};case"control/set-mode":return t.mode===a.payload?t:{...t,mode:a.payload==="dock"?"dock":"drive"};case"control/update-drive":{const{vector:l,speeds:s,source:u}=a.payload;return{...t,drive:{vector:l??t.drive.vector,speeds:s??t.drive.speeds,source:u??t.drive.source,lastUpdatedAt:Date.now()}}}case"control/set-aux-motors":return{...t,aux:{...t.aux,...a.payload}};case"control/set-camera-config":return{...t,camera:{...t.camera,enabled:!!a.payload?.config,config:a.payload?.config??null,angle:typeof a.payload?.angle=="number"?a.payload.angle:a.payload?.config?a.payload.config.homeAngle??t.camera.angle:null}};case"control/set-camera-angle":return{...t,camera:{...t.camera,angle:a.payload}};case"control/register-input-state":{const l=a.payload?.source||"unknown";return{...t,inputs:{...t.inputs,[l]:{...t.inputs[l]??{},...a.payload?.state,updatedAt:Date.now()}}}}case"control/set-keymap":return{...t,keymap:{...t.keymap,...a.payload??{}}};case"control/set-macros":return{...t,macros:Array.isArray(a.payload)?a.payload:t.macros};case"control/reset":return{...t,drive:Mc(),aux:yc(),song:kt(),horn:V8(),mic:Rt(),lastControlIntentAt:0};case"control/set-horn-active":return{...t,horn:{...t.horn||V8(),active:!!a.payload}};case"control/set-horn-heat":return{...t,horn:{...t.horn||V8(),heat:typeof a.payload?.heat=="number"?a.payload.heat:0,overheated:!!a.payload?.overheated}};case"control/record-intent":return{...t,lastControlIntentAt:Date.now()};case"control/set-song-note":return{...t,song:{...t.song||kt(),note:a.payload??x0}};case"control/set-mic-ptt":return{...t,mic:{...t.mic||Rt(),pttActive:!!a.payload}};case"control/set-manual-dock-assist":return{...t,manualDockAssist:{...t.manualDockAssist||wc(),active:!!a.payload}};default:return t}}function z0(t,a,l){return typeof t!="number"||Number.isNaN(t)?a:Math.max(a,Math.min(l,t))}function Xi(t){return typeof t!="number"||Number.isNaN(t)?0:Math.max(-1,Math.min(1,t))}function C4(t,a){return!Array.isArray(a)||a.length!==2?t:z0(t,a[0],a[1])}function XP(t={}){const a=Xi(t.x??0),l=Xi(t.y??0);return{x:a,y:l,boost:!!t.boost}}function JP(t={},a={}){const l=XP(t),s=typeof a.maxSpeed=="number"?a.maxSpeed:O9.maxSpeed,u=typeof a.baseSpeed=="number"?a.baseSpeed:O9.baseSpeed,f=typeof a.boostSpeed=="number"?a.boostSpeed:O9.boostSpeed,v=l.boost?f:u,p=l.y*v,g=l.x*v;return{vector:l,speeds:{left:z0(Math.round(p+g),-s,s),right:z0(Math.round(p-g),-s,s)}}}function WP(t){const a=Array.isArray(t)?t:[],l=String.fromCharCode(...a);if(typeof btoa=="function")return btoa(l);if(typeof Buffer<"u")return Buffer.from(a).toString("base64");throw new Error("No base64 encoder available")}function Ji(t){return new Promise(a=>setTimeout(a,t))}function tY(t={}){const{driveTransform:a,auxTransform:l}=t,s=R2(),u=u1(T=>T.session?.assignment?.roverId??null),f=u1(T=>T.session?.roster??[]),v=d.useMemo(()=>!u||!Array.isArray(f)?null:f.find(T=>String(T.id)===String(u))||null,[u,f]),p=d.useMemo(()=>!v?.cameraServo||!v.cameraServo.enabled?null:v.cameraServo,[v]),g=d.useMemo(()=>!v?.nightVision||!v.nightVision.enabled?null:v.nightVision,[v]),x=d.useMemo(()=>!v?.horn||!v.horn.enabled?null:v.horn,[v]),z=d.useMemo(()=>v?.nightVision?.state??null,[v]),b=d.useCallback((T,R)=>{u&&s.emit("command",{roverId:u,...T},R)},[s,u]),y=d.useCallback(()=>{u&&b({type:"sensorStream",data:{sensorStream:{enable:!0}}})},[b,u]),H=d.useCallback(T=>{if(!u)return null;const R={left:C4(T?.left??0,[-500,500]),right:C4(T?.right??0,[-500,500])},j=a?a(R):R,F={left:C4(j?.left??0,[-500,500]),right:C4(j?.right??0,[-500,500])};return b({type:"drive",data:{driveDirect:F}}),F},[a,b,u]),S=d.useCallback(({main:T=0,side:R=0,vacuum:j=0}={})=>{if(!u)return null;const F={main:C4(T,r0.main),side:C4(R,r0.side),vacuum:C4(j,r0.vacuum)},U=l?l(F):F,O={main:C4(U?.main??0,r0.main),side:C4(U?.side??0,r0.side),vacuum:C4(U?.vacuum??0,r0.vacuum)};return b({type:"motors",data:{motorPwm:O}}),O},[l,b,u]),C=d.useCallback(T=>!u||!p?null:(b({type:"servo",data:{servo:{angle:T}}}),T),[b,u,p]),w=d.useCallback(T=>{if(!u)return!1;const R=Array.isArray(T)?T:typeof T=="string"?YP[T]:null;return R?(b({type:"raw",data:{raw:WP(R)}}),y(),!0):!1},[b,y,u]),L=d.useCallback(async T=>{if(!(!T||!Array.isArray(T.steps)||!u))for(const R of T.steps){if(!u)break;switch(R.type){case"oi":w(R.command);break;case"drive":H(R.speeds??{left:0,right:0});break;case"motors":S(R.values??{});break;case"servo":C(R.angle);break;case"pause":await Ji(R.duration??zc);break}if(R.delay||R.delayMs){const j=R.delayMs??R.delay;typeof j=="number"&&j>0&&await Ji(j)}}},[u,w,H,S,C]),A=d.useCallback((T="toggle")=>!u||!g?null:(b({type:"nightVision",data:{nightVision:{action:T}}}),T),[b,g,u]),V=d.useCallback(T=>u?(b({type:"horn",data:{horn:T}}),T):null,[b,u]),N=d.useCallback((T=[],R={})=>{if(!u)return null;const F=(Array.isArray(T)&&T.length>0?T:[{note:x0,duration:bc}]).slice(0,16).map(U=>({note:C4(Math.round(U?.note??x0),Wc),duration:C4(Math.round(U?.duration??bc),[1,255])}));return b({type:"song",data:{song:{notes:F,slot:R.slot,loop:R.loop}}}),F},[b,u]);return d.useMemo(()=>({roverId:u,rosterEntry:v,servoConfig:p,nightVision:g,nightVisionState:z,horn:x,emitCommand:b,enableSensorStream:y,sendDriveDirect:H,sendAuxMotors:S,sendServoAngle:C,sendOiCommand:w,sendNightVision:A,sendHorn:V,sendSong:N,runMacroSteps:L}),[u,v,p,g,z,x,b,y,H,S,C,w,A,V,L])}const eY={"{":"[","}":"]",":":";",'"':"'","<":",",">":".","?":"/","|":"\\",_:"-","+":"="},Wi={"[":"BracketLeft","]":"BracketRight","\\":"Backslash",";":"Semicolon","'":"Quote",",":"Comma",".":"Period","/":"Slash","-":"Minus","=":"Equal","`":"Backquote"};function $8(t){if(typeof t!="string")return"";const a=t.toLowerCase();return eY[a]??a}function cY(t){const a=$8(t);if(!a)return null;if(Wi[a])return Wi[a];if(a.length===1){if(/[a-z]/.test(a))return`Key${a.toUpperCase()}`;if(/[0-9]/.test(a))return`Digit${a}`}return null}function eu(t){const a=$8(t);return a?`key:${a}`:null}function aY(t){const a=cY(t);return a?`code:${a}`:null}function ts(t){const a=new Set,l=eu(t?.key??"");l&&a.add(l);const s=t?.code?`code:${t.code}`:null;return s&&a.add(s),Array.from(a)}function cu(t={}){return Object.fromEntries(Object.entries(t).map(([a,l])=>{const s=Array.isArray(l)?l:[l],u=new Set;return s.forEach(f=>{const v=eu(String(f));v&&u.add(v);const p=aY(String(f));p&&u.add(p)}),[a,u]}))}function _2(t){const a=$8(t);return a?a===" "?"Space":a==="\\"?"Backslash":a==="`"?"Backtick":a==="["?"[ or {":a==="]"?"] or }":a===";"?"; or :":a==="'"?`' or "`:a===","?", or <":a==="."?". or >":a==="/"?"/ or ?":a==="-"?"- or _":a==="="?"= or +":a==="arrowup"?"Arrow Up":a==="arrowdown"?"Arrow Down":a==="arrowleft"?"Arrow Left":a==="arrowright"?"Arrow Right":a.length===1?a.toUpperCase():a:"—"}const R4={keyboard:{baseSpeed:250,turboSpeed:500,precisionSpeed:125,tiltSpeed:90,tiltIntervalMs:110}},d3={label:"Default",calibration:{driveDeadzone:.18,cameraDeadzone:.08,auxDeadzone:.05,driveCurve:"linear",cameraCurve:"linear",auxCurve:"linear",cameraMode:"absolute",cameraSensitivity:60,auxSideScale:.55},bindings:{drive:{kind:"axisPair",sources:[{kind:"axisPair",x:0,y:1,invertX:!1,invertY:!0}]},cameraTilt:{kind:"axis",sources:[{kind:"axis",index:3,invert:!0},{kind:"axis",index:1,invert:!0}]},mainBrush:{kind:"axis",sources:[{kind:"buttonAxis",index:6},{kind:"axis",index:2,invert:!1}]},sideBrush:{kind:"axis",sources:[{kind:"buttonAxis",index:7},{kind:"axis",index:5,invert:!1}]},vacuum:{kind:"button",sources:[{kind:"button",index:0}]},allAux:{kind:"button",sources:[{kind:"button",index:1}]},mainReverse:{kind:"button",sources:[{kind:"button",index:4}]},sideReverse:{kind:"button",sources:[{kind:"button",index:5}]},driveMacro:{kind:"button",sources:[{kind:"button",index:2}]},dockMacro:{kind:"button",sources:[{kind:"button",index:3}]},nightVisionToggle:{kind:"button",sources:[{kind:"button",index:9}]}}},Z3={activeSignature:null,profiles:{},defaults:{profile:d3}},g6={waveform:"saw",freqs:[440,550,660,0]},x2={masterVolume:1,alertVolume:.5,roverVolume:1,mainBrushDuckEnabled:!0,mainBrushDuckAmount:.75},H0={colorFilter:"none"},v6=[{key:"drive",motors:["leftWheel","rightWheel"]},{key:"aux",motors:["mainBrush","sideBrush"]}],nY={downRatePerSec:.15,upRatePerSec:.7,releaseDelaySec:1,outputRateMs:250};function es(){return v6.reduce((t,a)=>(t[a.key]={cap:1,clearSec:0},t),{})}function cs(t){return Number.isFinite(t)?Math.max(0,Math.min(1,t)):0}function au(t,a={}){const l=u1(C=>C.session?.role||null),s=b6(t,qo,_o),u=d.useMemo(()=>({...nY,...a.config||{}}),[a.config]),[f,v]=d.useState(()=>es()),p=d.useRef(0),g=d.useRef(s);d.useEffect(()=>{g.current=s||{}},[s]),d.useEffect(()=>{v(es()),p.current=0},[t]);const x=d.useMemo(()=>v6.some(C=>C.motors.some(w=>!!s?.[w])),[s]),z=d.useMemo(()=>Object.values(f||{}).some(C=>(Number.isFinite(C?.cap)?C.cap:1)<.999),[f]),b=!!t&&(x||z);d.useEffect(()=>{if(!b)return;p.current=typeof performance<"u"?performance.now():Date.now();const C=setInterval(()=>{const w=typeof performance<"u"?performance.now():Date.now(),L=Math.max(0,w-p.current);p.current=w;const A=Math.min(.25,L/1e3);A<=0||v(V=>{let N=!1;const T={},R=Number.isFinite(u.downRatePerSec)?Math.max(0,u.downRatePerSec):0,j=Number.isFinite(u.upRatePerSec)?Math.max(0,u.upRatePerSec):0,F=Number.isFinite(u.releaseDelaySec)?Math.max(0,u.releaseDelaySec):0;return v6.forEach(U=>{const O=V[U.key]||{cap:1,clearSec:0},q=Number.isFinite(O.cap)?O.cap:1,$=Number.isFinite(O.clearSec)?O.clearSec:0,e1=U.motors.some(I=>!!g.current?.[I]),n1=e1?0:$+A,J=!e1&&n1>=F,k=cs(e1?q-R*A:J?q+j*A:q);(Math.abs(k-q)>1e-4||Math.abs(n1-$)>1e-4)&&(N=!0),T[U.key]={cap:k,clearSec:n1}}),N?T:V})},100);return()=>clearInterval(C)},[u.downRatePerSec,u.releaseDelaySec,u.upRatePerSec,t,b]);const y=d.useMemo(()=>{const C=v6.reduce((w,L)=>{const A=f?.[L.key],V=Number.isFinite(A?.cap)?A.cap:1;return w[L.key]=cs(V),w},{});return{perGroup:C,drive:{left:C.drive??1,right:C.drive??1},aux:{main:C.aux??1,side:C.aux??1,vacuum:1}}},[f]),H=d.useMemo(()=>{const C={};v6.forEach(L=>{L.motors.forEach(A=>{C[A]=!!s?.[A]})});const w=v6.reduce((L,A)=>(L[A.key]=A.motors.some(V=>!!s?.[V]),L),{});return{motors:C,groups:w}},[s]),S=l==="admin"||l==="lockdown"||l==="lockdown-admin";return d.useMemo(()=>({caps:f,overcurrent:H,scales:y,isActive:(y?.drive?.left??1)<1||(y?.drive?.right??1)<1||(y?.aux?.main??1)<1||(y?.aux?.side??1)<1,config:u,adminImmune:S}),[f,H,y,u,S])}function lY(t={},a,l=!1){if(l||!a?.drive)return t;const s=typeof a.drive.left=="number"?a.drive.left:1,u=typeof a.drive.right=="number"?a.drive.right:1;return s>=.999&&u>=.999?t:{left:Math.round((t.left??0)*s),right:Math.round((t.right??0)*u)}}function rY(t={},a,l=!1){if(l||!a?.aux)return t;const s=typeof a.aux.main=="number"?a.aux.main:1,u=typeof a.aux.side=="number"?a.aux.side:1,f=typeof a.aux.vacuum=="number"?a.aux.vacuum:1;return s>=.999&&u>=.999&&f>=.999?t:{main:Math.round((t.main??0)*s),side:Math.round((t.side??0)*u),vacuum:Math.round((t.vacuum??0)*f)}}const ta=d.createContext(null);function iY(t){return typeof t=="function"?t:a=>a}const sY=["setMode","setDriveVector","setAuxMotors","setServoAngle","nudgeServo","goServoHome","runMacro","stopAllMotion","sendOiCommand","setSensorStream","setNightVision","toggleNightVision","updateKeyBinding","resetKeyBindings","registerInputState","setManualDockAssistActive","toggleManualDockAssist","setSongNote","sendSong","startHorn","stopHorn","setMicPttActive"];function as(t){return Object.fromEntries(Object.entries(t||{}).map(([a,l])=>[a,Array.isArray(l)?[...l]:[]]))}function oY(t,a){if(!t)return a;const l=typeof t.minAngle=="number"?t.minAngle:-45,s=typeof t.maxAngle=="number"?t.maxAngle:45;return z0(a,l,s)}function uY(t=[]){if(!Array.isArray(t)||t.length<3)return t;const a=t.slice(-3),[l,s,u]=a,f=l?.type==="drive"&&Number(l?.speeds?.left)===-300&&Number(l?.speeds?.right)===-300,v=s?.type==="pause"&&Number(s?.duration)===600,p=u?.type==="drive"&&Number(u?.speeds?.left)===0&&Number(u?.speeds?.right)===0;return!f||!v||!p?t:t.slice(0,-3)}function hY({children:t}){const[a,l]=d.useReducer(QP,Qi),s=d.useRef(null),u=d.useRef(new Set),f=d.useRef({}),[v]=d.useState(()=>Object.fromEntries(sY.map(o1=>[o1,(...P)=>f.current[o1]?.(...P)])),[]),p=d.useCallback(()=>s.current,[]),g=d.useCallback((o1,P,c1=Object.is)=>{const z1=iY(o1),r2=s.current,i2={selector:z1,equalityFn:c1,listener:P,current:z1(r2)};return u.current.add(i2),()=>{u.current.delete(i2)}},[]),x=d.useCallback(o1=>{u.current.forEach(P=>{const c1=P.selector(o1);P.equalityFn(P.current,c1)||(P.current=c1,P.listener(c1))})},[]),z=d.useRef(null),b=d.useRef(!1),y=d.useRef(Qi.camera.angle),H=d.useRef(null),S=d.useRef(0),C=d.useRef(0),{value:w,save:L}=T1("controls",{keymap:B8,macros:tu}),{value:A}=T1("page",{driveMacroBackoffEnabled:!0}),{value:V}=T1("horn",g6),N=typeof A?.driveMacroBackoffEnabled=="boolean"?A.driveMacroBackoffEnabled:!0,T=u1(o1=>o1.session?.assignment?.roverId??null),R=u1(o1=>o1.session?.homeAssistant?.entities??[]),{homeAssistantSetState:j}=I2(),F=au(T),U=d.useCallback(o1=>lY(o1,F.scales,F.adminImmune),[F.adminImmune,F.scales]),O=d.useCallback(o1=>rY(o1,F.scales,F.adminImmune),[F.adminImmune,F.scales]),q=tY({driveTransform:U,auxTransform:O}),$=d.useCallback(()=>{const P=(R||[]).filter(c1=>(c1.type==="light"||c1.type==="switch")&&c1.available!==!1&&c1.state!=="on");if(P.length===0){b.current=!1;return}b.current=!0,P.forEach(c1=>{j(c1.id,"on").catch(()=>{})}),b.current=!1},[R,j]);d.useEffect(()=>{l({type:"control/set-rover",payload:q.roverId})},[q.roverId]),d.useEffect(()=>{const o1=z.current;z.current=a.mode,o1!=="drive"&&a.mode==="drive"&&R?.length?$():o1!=="drive"&&a.mode==="drive"&&(b.current=!0)},[a.mode,R,$]),d.useEffect(()=>{b.current&&R?.length&&$()},[R,$]),d.useEffect(()=>{const o1={...B8,...w?.keymap||{}};l({type:"control/set-keymap",payload:o1}),w?.macros&&l({type:"control/set-macros",payload:w.macros})},[w?.keymap,w?.macros]),d.useEffect(()=>{const o1=q.servoConfig;if(!o1){l({type:"control/set-camera-config",payload:{config:null}}),y.current=null;return}const P=typeof o1.minAngle=="number"?o1.minAngle:-45,c1=typeof o1.maxAngle=="number"?o1.maxAngle:45,z1=typeof o1.homeAngle=="number"?o1.homeAngle:(P+c1)/2,r2=typeof y.current=="number"?z0(y.current,P,c1):null,i2=r2??z0(z1,P,c1);l({type:"control/set-camera-config",payload:{config:o1,angle:i2}}),y.current=i2},[q.servoConfig]),d.useEffect(()=>{y.current=typeof a.camera.angle=="number"?a.camera.angle:y.current},[a.camera.angle]),d.useEffect(()=>{q.roverId&&q.enableSensorStream()},[q.roverId,q.enableSensorStream]);const e1=d.useCallback(o1=>{l({type:"control/set-mode",payload:o1})},[]),n1=d.useCallback(()=>{l({type:"control/record-intent"})},[]),J=d.useRef(a.drive.speeds),k=d.useRef(a.aux),I=d.useMemo(()=>JSON.stringify(F.scales),[F.scales]),t1=d.useRef(0),f1=d.useRef(0);d.useEffect(()=>{J.current=a.drive.speeds},[a.drive.speeds]),d.useEffect(()=>{k.current=a.aux},[a.aux]),d.useEffect(()=>{if(!q.roverId||F.adminImmune||!F.isActive)return;const o1=Math.max(0,Number(F?.config?.outputRateMs)||0),P=typeof performance<"u"?performance.now():Date.now(),c1=J.current||{left:0,right:0},z1=k.current||{main:0,side:0,vacuum:0},r2=!!(c1.left||c1.right),i2=!!(z1.main||z1.side||z1.vacuum);!r2&&!i2||(r2&&P-t1.current>=o1&&(t1.current=P,q.sendDriveDirect(c1)),i2&&P-f1.current>=o1&&(f1.current=P,q.sendAuxMotors(z1)))},[I,F.adminImmune,F.config,F.isActive,q]);const m1=d.useCallback((o1,P={})=>{const c1={...P.speedOptions||{}};if(a.manualDockAssist?.active){const r2=Math.max(1,Math.min($P,500));c1.maxSpeed=Math.min(typeof c1.maxSpeed=="number"?c1.maxSpeed:r2,r2),c1.baseSpeed=Math.min(typeof c1.baseSpeed=="number"?c1.baseSpeed:r2,r2),c1.boostSpeed=Math.min(typeof c1.boostSpeed=="number"?c1.boostSpeed:r2,r2)}const z1=JP(o1,c1);l({type:"control/update-drive",payload:{...z1,source:P.source??null}}),n1(),q.sendDriveDirect(z1.speeds)},[q,n1,a.manualDockAssist?.active]),E=d.useCallback((o1={})=>{const P=q.sendAuxMotors(o1)??o1;l({type:"control/set-aux-motors",payload:P}),n1()},[q,n1]),_=d.useCallback((o1,P)=>{if(!o1)return!1;const c1=$8(P);if(!c1)return!1;const z1=as(a.keymap);return z1[o1]=[c1],l({type:"control/set-keymap",payload:z1}),L(r2=>({...r2??{},keymap:z1})),!0},[a.keymap,L]),K=d.useCallback(()=>{const o1=as(B8);l({type:"control/set-keymap",payload:o1}),L(P=>({...P??{},keymap:o1}))},[L]),r1=d.useCallback((o1,P={})=>{if(!q.servoConfig)return;const c1=!!P?.force;if(a.manualDockAssist?.active&&!c1)return;const z1=oY(q.servoConfig,o1);l({type:"control/set-camera-angle",payload:z1}),q.sendServoAngle(z1),y.current=z1,n1()},[q,n1,a.manualDockAssist?.active]),v1=d.useCallback((o1=0)=>{const P=q.servoConfig;if(!P)return;const c1=typeof o1=="number"&&o1!==0?o1:P.nudgeDegrees||1,z1=typeof y.current=="number"?y.current:typeof P.homeAngle=="number"?P.homeAngle:0;r1(z1+c1)},[q.servoConfig,r1]),g1=d.useCallback(()=>{const o1=q.servoConfig;if(!o1)return;const P=typeof o1.homeAngle=="number"?o1.homeAngle:typeof o1.minAngle=="number"&&typeof o1.maxAngle=="number"?(o1.minAngle+o1.maxAngle)/2:0;r1(P)},[q.servoConfig,r1]),V1=d.useCallback(async o1=>{const P=a.macros.find(z1=>z1.id===o1)||null;if(!P)return;let c1=P;o1==="drive-sequence"&&($(),R?.length||(b.current=!0),n1(),N||(c1={...P,steps:uY(P.steps)})),await q.runMacroSteps(c1)},[N,q,n1,R,a.macros,$]),S1=d.useCallback(()=>{l({type:"control/update-drive",payload:{vector:{x:0,y:0,boost:!1},speeds:{left:0,right:0},source:"system-stop"}}),q.sendDriveDirect({left:0,right:0}),q.sendAuxMotors({main:0,side:0,vacuum:0})},[q]),N1=d.useCallback(o1=>{q.sendOiCommand(o1)},[q]),P1=d.useCallback(o1=>{q.roverId&&q.emitCommand({type:"sensorStream",data:{sensorStream:{enable:o1}}})},[q]),Y1=d.useCallback(o1=>{if(q.nightVision){if(typeof o1=="boolean"){const P=o1?"off":"on";q.sendNightVision(P)}else q.sendNightVision("toggle");n1()}},[q,n1]),R1=d.useCallback(()=>{Y1()},[Y1]),p2=d.useCallback(o1=>{const P=typeof o1=="number"?o1:x0;return l({type:"control/set-song-note",payload:P}),P},[]),s1=d.useCallback((o1,P)=>q.sendSong(o1,P),[q]),H1=d.useMemo(()=>{const o1=V??g6,P=o1.waveform==="sine"?"sine":"saw",z1=[...Array.isArray(o1.freqs)?o1.freqs:g6.freqs,0,0,0,0].slice(0,4).map(r2=>{const i2=Number(r2);return Number.isFinite(i2)?i2<=0?0:Math.min($t,Math.round(i2)):0});return{waveform:P,freqs:z1}},[V]),p1=d.useRef(null),x1=d.useCallback(()=>{if(!q.horn)return;if(a.horn?.overheated||(a.horn?.heat??0)>=1||a.horn?.active)return!1;const o1=Date.now();return q.sendHorn({action:"start",...H1}),l({type:"control/set-horn-active",payload:!0}),S.current=o1,C.current=o1,H.current&&(clearTimeout(H.current),H.current=null),H.current=setTimeout(()=>{p1.current?.()},GP),n1(),!0},[l,H1,q,n1,a.horn?.active,a.horn?.heat,a.horn?.overheated]),L1=d.useCallback(()=>{if(!q.horn)return;q.sendHorn({action:"stop"}),l({type:"control/set-horn-active",payload:!1}),H.current&&(clearTimeout(H.current),H.current=null);const o1=Date.now(),P=S.current||o1,c1=Math.max(0,o1-P);if(S.current=0,c1>0){const z1=a.horn?.heat??0,r2=c1/1e3*Ki;let i2=Math.max(0,Math.min(1,z1+r2)),M2=a.horn?.overheated??!1;i2>=1&&(i2=1,M2=!0),l({type:"control/set-horn-heat",payload:{heat:i2,overheated:M2}})}},[l,q,a.horn?.heat,a.horn?.overheated]),F1=d.useRef({active:!!a.horn?.active,heat:a.horn?.heat??0,overheated:!!a.horn?.overheated});d.useEffect(()=>{F1.current={active:!!a.horn?.active,heat:a.horn?.heat??0,overheated:!!a.horn?.overheated}},[a.horn?.active,a.horn?.heat,a.horn?.overheated]),d.useEffect(()=>{p1.current=L1},[L1]);const h1=!!a.horn?.active||(a.horn?.heat??0)>0||!!a.horn?.overheated;d.useEffect(()=>{if(!h1)return;const P=setInterval(()=>{const c1=Date.now(),z1=C.current||c1;C.current=c1;const r2=Math.min(1e3,Math.max(0,c1-z1))/1e3,i2=F1.current,M2=i2.heat??0,n4=!!i2.active,b1=!!i2.overheated,h2=r2*(n4?Ki:-.2);let c2=Math.max(0,Math.min(1,M2+h2)),U1=b1;c2>=1?(c2=1,U1=!0,n4&&p1.current()):U1&&c2<=PP&&(U1=!1),(c2!==M2||U1!==b1)&&l({type:"control/set-horn-heat",payload:{heat:c2,overheated:U1}})},100);return()=>clearInterval(P)},[l,h1]);const y1=d.useCallback(o1=>{const P=!!o1;if(!!a.manualDockAssist?.active===P)return;if(l({type:"control/set-manual-dock-assist",payload:P}),!P){q.sendSong([{note:83,duration:10},{note:76,duration:10}],{slot:0}),r1(0,{force:!0});return}const z1=typeof q.servoConfig?.minAngle=="number"?q.servoConfig.minAngle:-45;r1(z1,{force:!0}),q.sendSong([{note:76,duration:10},{note:83,duration:10}],{slot:0}),n1()},[q,n1,r1,a.manualDockAssist?.active]),k1=d.useCallback(()=>{y1(!a.manualDockAssist?.active)},[y1,a.manualDockAssist?.active]),X1=d.useCallback((o1,P)=>{l({type:"control/register-input-state",payload:{source:o1,state:P}})},[]),C1=d.useCallback(o1=>{l({type:"control/set-mic-ptt",payload:!!o1})},[]),g2=d.useMemo(()=>({setMode:e1,setDriveVector:m1,setAuxMotors:E,setServoAngle:r1,nudgeServo:v1,goServoHome:g1,runMacro:V1,stopAllMotion:S1,sendOiCommand:N1,setSensorStream:P1,setNightVision:Y1,toggleNightVision:R1,updateKeyBinding:_,resetKeyBindings:K,registerInputState:X1,setManualDockAssistActive:y1,toggleManualDockAssist:k1,setSongNote:p2,sendSong:s1,startHorn:x1,stopHorn:L1,setMicPttActive:C1}),[e1,m1,E,r1,v1,g1,V1,S1,N1,P1,Y1,R1,_,K,X1,y1,k1,p2,s1,x1,L1,C1]),t2=d.useMemo(()=>({state:a,dispatch:l,pipeline:q,overcurrentLimiter:F,actions:v}),[a,q,F,v]);s.current==null&&(s.current=t2),d.useLayoutEffect(()=>{f.current=g2},[g2]),d.useLayoutEffect(()=>{s.current!==t2&&(s.current=t2,x(t2))},[x,t2]);const e2=d.useMemo(()=>({getSnapshot:p,subscribe:g,actions:v}),[p,v,g]);return r.jsx(ta.Provider,{value:e2,children:t})}function q1(t,a=Object.is){const l=d.useContext(ta);if(!l)throw new Error("useControlSelector must be used within ControlSystemProvider");const s=d.useRef(t),u=d.useRef(a),[f,v]=d.useState(()=>t(l.getSnapshot()));return d.useEffect(()=>{s.current=t,u.current=a},[a,t]),d.useEffect(()=>(v(p=>{const g=s.current(l.getSnapshot());return u.current(p,g)?p:g}),l.subscribe(p=>s.current(p),p=>{v(g=>u.current(g,p)?g:p)},(p,g)=>u.current(p,g))),[l]),f}function x3(){const t=d.useContext(ta);if(!t)throw new Error("useControlActions must be used within ControlSystemProvider");return t.actions}const dY="data:audio/mpeg;base64,//uQxAAAAAAAAAAAAAAAAAAAAAAAWGluZwAAAA8AAAANAAAIpQBKSkpKSkpKXFxcXFxcXFxra2tra2tra3p6enp6enqJiYmJiYmJiZiYmJiYmJiYpqampqamprW1tbW1tbW1xMTExMTExMTT09PT09PT4uLi4uLi4uLx8fHx8fHx8f////////8AAABQTEFNRTMuMTAwBLkAAAAAAAAAABUgJAUYQQAB4AAACKVpqtMZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//ugxAAAwqQPR8CIwCh0BCj5jDwlIAAjW87wAACcOsAKPMk8ARj8w9OAWwNlV/gCgQMHEhAOVnFaNzWWAPI2zyjHjd8FAoKqyAa88AAAAABNjEd9CQOglIY9dtC+a51bGZrZgTewD3c+AAYx5hxIMheIcudKAyaykG1/h5EsPB0iTEFNRTMuMTAwqqqqqqrIBZqvAAAAAC9JXFIAHrCgAp0D0hUYOInIluqg1TNdKCzMeAAFQCKKsxUmVfireKILLBgSVgb4qBVtPWpMQU1FMy4xMDCqqqqqqqqqqqqqqqqpApm/AAAAAC7QYaHPHoCjkCysmc+QY9NNWRbKE+mqowNobwAAoSQQMLGChDlOrKMqVMC/6xy/CXbFaL7AZUxBTUUzLjEwMFVVVVVVVVVVVacDqZ8AAAAAMgzaYFBPNgIOnVCQfFfwmBBhLVNJQSdxdQRofwAGxF9xAAYs4AZDuE87li0YCASIBwaCiXUj+2BqTEFNRTMuMTAwqqqqqqqqlwOonwAAAAAtkABQSEZ1INNDgx8HeaaLCXiu5dqSciylQNXjv8GdmACQ5ogYKbnsmxkoChog+w9IhU6GsgzCIQBSxFpMQQAAMBiHjgAAAAv6FQQILmJmGLltnax9HszIVEAoEq1p8olpcPLlGpXFastuWosKNFlmlqADJbwAEFRI4iJJy0oDumUW//sgxOEAw5wfU8fnAGBvg6n5nDxUh7QuwcEzkK5Ztz7AZUxBTUUzLjEwMFVVVVVVVZUAhd8AAAAALZAAamQMWKtC7Avib0WLplt2IAp0SKV0pFFxCADLX6AIPFrWJIBQqPGW/x0QDTRLGaQYCRAZzKeoU6uqTEFN6AB3n/7wAAAxq//7EMT0AMPUHU/MawJgc4PpuYy8VQZjocBw2OgQQyQyECnbABEUC/ZoM0J56Jm0tqzNJaq8KospqUAQ5/QBghnCqQAhR4Mz1D1gJPstYsI1sYIg079I5cYjY6pMQU1FMy4xMDCqqqqq//sQxPUAw+AdT8zvAih6hCk5nWBFqqqWAFOf4AAAAEAIQZPkMcwUzFVE51cSBjIHpJRIEIjWgGar9VhgCUvwAFAUMk0RCpMkwXjPQDcoLBU+n5RuR4ZrPQLPckxBTUUzLjEwMKqqqqr/+xDE9oDEAB1NzG8CKIGEKPmd5EWqxgBWn9AAAAAKIiC5GcLJIczCEvNbWsF31jo4Bw0rXktvJF5YRyABlj+ABIQ2RGsHgdc0XsPntoEDUzaQOjTBqblFPUE1TEFNRckAt68AAAAALv/7EMT4AMQIHU3M7wIojwUo+Y2MZfAgKcwITAQIYN1TosJeLtDA0ubWNrFSADJoln4AC0hVaLiIIUChs+4HST4BgCpQHITPMBQkEnj73ORZfylh+sRLEGUiNIpMQU1FMy4xMDCqqqqq//sQxP6AxlgtK+13Yih3hCj5neBNqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrIkT7UNAZ7NS7yMqcihSKLMn8DlKYq8ZdPCVEoJBuWqkxBTUUzLjEwMKqqqqr/+xDE+ADEXCVHzGjDIIQEqLm9PIWqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv/7EMT+AMWoL0XNcwJoiASoeY3gVaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//sQxPgAxHAnRcxvAmiBBKj5jehEqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqr/+xDE+IDEmCVDzPMCKH6EqLmNYE2qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqv/7EMT9gEPgI0vMZwQgvYWlPY5gFaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//sQxOYDw+gpIIfgwWgAADSAAAAEqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqo=",fY=80,mY=80,vY=240,ns=new Map;function nu(){return typeof window>"u"?null:window.roverAnalytics&&typeof window.roverAnalytics=="object"?window.roverAnalytics:null}function lu(t){if(typeof t!="string")return null;const a=t.trim().toLowerCase().replace(/[^a-z0-9_:-]+/g,"_");return a?a.slice(0,fY):null}function ru(t){if(t!=null){if(typeof t=="boolean")return t;if(typeof t=="number")return Number.isFinite(t)?t:void 0;if(typeof t=="string"){const a=t.trim();return a?a.slice(0,vY):void 0}if(Array.isArray(t)){const a=t.map(l=>ru(l)).filter(l=>l!==void 0).map(l=>String(l));return a.length?a.slice(0,12).join(","):void 0}}}function ea(t={}){return!t||typeof t!="object"||Array.isArray(t)?{}:Object.entries(t).reduce((a,[l,s])=>{if(typeof l!="string")return a;const u=l.trim().replace(/[^a-zA-Z0-9_:-]+/g,"_").slice(0,mY);if(!u)return a;const f=ru(s);return f===void 0||(a[u]=f),a},{})}function d1(t,a={}){const l=lu(t);if(!l)return;const s=nu();if(!s||typeof s.track!="function")return;const u=ea(a);try{Object.keys(u).length?s.track(l,u):s.track(l)}catch(f){console.warn("Analytics event failed",f)}}function pY(t={}){const a=nu();if(!(!a||typeof a.identify!="function"))try{a.identify(ea(t))}catch(l){console.warn("Analytics identify failed",l)}}function v3(t,a={},l={}){const s=lu(t);if(!s)return;const u=Number.isFinite(l?.throttleMs)?Math.max(0,l.throttleMs):30*1e3,f=`${s}:${typeof l?.key=="string"?l.key:JSON.stringify(ea(a))}`,v=Date.now(),p=ns.get(f)||0;v-p{},focusChat:()=>{},blurChat:()=>{},registerInputRef:()=>{},onInputFocus:()=>{},onInputBlur:()=>{},setTypingActive:()=>{}},ou={isChatFocused:!1,selfSocketId:null},uu=d.createContext(iu),hu=d.createContext(su),du=d.createContext(ou),gY=d.createContext({...iu,...su,...ou});function xY({children:t}){const a=R2(),l=u1(E=>E.session),{pushAlert:s}=I2(),{value:u}=T1("audio",x2),{value:f}=T1("profile",{nickname:"",profileImageUrl:""}),[v,p]=d.useState([]),[g,x]=d.useState([]),[z,b]=d.useState(!1),y=d.useRef(null),H=d.useRef(null),S=d.useRef(null),C=d.useRef(new Map),w=d.useRef(new Map),L=d.useRef({isTyping:!1,lastSent:0}),A=Number.isFinite(u?.masterVolume)?u.masterVolume:x2.masterVolume,V=Number.isFinite(u?.alertVolume)?u.alertVolume:x2.alertVolume,N=Math.max(0,Math.min(1,A*V)),R=!!l?.isVerified?String(f?.profileImageUrl||"").trim():"",j=d.useCallback(()=>{const E=Array.from(C.current.values()).sort((_,K)=>_.lastUpdate-K.lastUpdate).map(_=>_.payload);x(E)},[]),F=d.useCallback(E=>!E||typeof E!="object"?null:E.typingId?E.typingId:E.fromDiscord?`discord:${E.discordUserId||E.discordUserName||E.nickname||"unknown"}`:`socket:${E.socketId||E.nickname||"unknown"}`,[]);d.useEffect(()=>{S.current=new Audio(dY),S.current.volume=N,S.current.load()},[N]);const U=d.useCallback(()=>{const E=S.current;E&&(E.volume=N,E.currentTime=0,E.play().catch(()=>{}))},[N]);d.useEffect(()=>{function E(_={}){p(K=>[...K.slice(-99),_]),!(_?.socketId&&l?.socketId&&_.socketId===l.socketId)&&(U(),s?.({kind:"chat",payload:_,id:`chat-${_.id||Math.random().toString(36).slice(2)}`,receivedAt:Date.now()}))}return a.on("chat:message",E),()=>{a.off("chat:message",E)}},[U,s,l?.socketId,a]),d.useEffect(()=>{function E(_={}){const K=F(_);if(!K)return;const r1=Date.now();if(_?.socketId&&l?.socketId&&_.socketId===l.socketId){_.isTyping||(C.current.delete(K),j());return}if(_.isTyping){C.current.set(K,{payload:_,expiresAt:r1+6e3,lastUpdate:r1});const v1=w.current.get(K)||0;r1-v1>=2500&&(w.current.set(K,r1),s?.({kind:"chat-typing",payload:_,id:`chat-typing-${K}-${_.id||Math.random().toString(36).slice(2)}`,receivedAt:r1}))}else C.current.delete(K);j()}return a.on("chat:typing",E),()=>{a.off("chat:typing",E)}},[s,j,F,l?.socketId,a]),d.useEffect(()=>{const E=setInterval(()=>{const _=Date.now();let K=!1;C.current.forEach((r1,v1)=>{r1.expiresAt<=_&&(C.current.delete(v1),K=!0)}),K&&j()},2e3);return()=>clearInterval(E)},[j]),d.useEffect(()=>{function E(_=[]){Array.isArray(_)&&p(K=>{if(K.length===0)return _.slice(-100);const r1=new Set(_.map(g1=>g1?.id));return[..._,...K.filter(g1=>g1?.id&&!r1.has(g1.id))].slice(-100)})}return a.on("chat:init",E),()=>{a.off("chat:init",E)}},[a]);const O=d.useCallback(E=>{const _=!!E,K=Date.now(),r1=L.current,v1=!_&&r1.isTyping;!(_&&(!r1.isTyping||K-r1.lastSent>=3500))&&!v1||(L.current={isTyping:_,lastSent:K},a.emit("chat:typing",{isTyping:_}))},[a]),q=d.useCallback((E,_=null)=>new Promise((K,r1)=>{const v1={text:E,tts:_};R&&(v1.profileImage=R),a.emit("chat:send",v1,(g1={})=>{g1.error?r1(new Error(g1.error)):(d1("chat_send",{hasTts:!!_,length:typeof E=="string"?E.trim().length:0}),K(g1))})}),[R,a]),$=d.useCallback((E,_={})=>{(_?.target==="hud"?"hud":"panel")==="hud"?H.current=E:y.current=E},[]),e1=d.useCallback(()=>{b(!0),(H.current||y.current)?.focus()},[]),n1=d.useCallback(()=>{b(!1),H.current?.blur(),y.current?.blur()},[]),J=d.useCallback(()=>b(!0),[]),k=d.useCallback(()=>b(!1),[]),I=d.useMemo(()=>({messages:v,typing:g}),[v,g]),t1=d.useMemo(()=>({sendMessage:q,focusChat:e1,blurChat:n1,registerInputRef:$,onInputFocus:J,onInputBlur:k,setTypingActive:O}),[n1,e1,k,J,$,q,O]),f1=d.useMemo(()=>({isChatFocused:z,selfSocketId:l?.socketId||null}),[z,l?.socketId]),m1=d.useMemo(()=>({...I,...t1,...f1}),[t1,f1,I]);return r.jsx(uu.Provider,{value:I,children:r.jsx(hu.Provider,{value:t1,children:r.jsx(du.Provider,{value:f1,children:r.jsx(gY.Provider,{value:m1,children:t})})})})}function zY(){const t=d.useContext(uu);if(!t)throw new Error("useChatTimeline must be used inside ChatProvider");return t}function ca(){const t=d.useContext(hu);if(!t)throw new Error("useChatActions must be used inside ChatProvider");return t}function bY(){const t=d.useContext(du);if(!t)throw new Error("useChatFocus must be used inside ChatProvider");return t}let fu=!1;function U9(t){fu=!!t}function ls(){return fu}const MY=new Set(["","text","search","email","password","url","tel","number","date","datetime-local","month","time","week"]);function mu(t){if(!t||t.nodeType!==1)return!1;const a=t.tagName;if(a==="TEXTAREA"||t.isContentEditable)return!0;if(a!=="INPUT")return!1;const l=t.type?t.type.toLowerCase():"";return MY.has(l)}function yY(){return typeof document>"u"?!1:mu(document.activeElement)}function A0(t={}){const{manageLifecycle:a=!1}=t,l=q1(w=>w.state.roverId),s=q1(w=>!!w.state.manualDockAssist?.active),u=x3(),f=b6(l,Gc,$c),v=f.chargingStateLabel||"",p=!!f.homeBase,g=p&&v.toLowerCase()!=="not charging"&&v!=="",x=d.useRef(!1),z=d.useCallback(()=>{u.setManualDockAssistActive(!0)},[u]),b=d.useCallback(()=>{u.setManualDockAssistActive(!1)},[u]),y=d.useCallback(()=>{u.toggleManualDockAssist()},[u]);d.useEffect(()=>{if(!a)return;const w=p&&!x.current,L=!p&&x.current;s&&w?u.sendSong([{note:84,duration:6}],{slot:1}):s&&L&&u.sendSong([{note:72,duration:6}],{slot:1}),x.current=p},[u,s,p,a]),d.useEffect(()=>{!a||!s||!g||b()},[s,g,b,a]);const H=g?"Docked and charging":p?"Docked":"Docking assist active",S=g?"good":p?"warn":"active",C=s||p;return d.useMemo(()=>({active:s,docked:p,charging:g,cameraLocked:s,visible:C,statusLabel:H,statusTone:S,enterAssist:z,exitAssist:b,toggleAssist:y}),[s,g,p,z,b,H,S,y,C])}function Z9(t,a){const l=Number(t);return Number.isFinite(l)?Math.max(0,Math.min(500,l)):a}function vu(t){const a=R4.keyboard,l=t?.keyboard??{};return{baseSpeed:Z9(l.baseSpeed,a.baseSpeed),turboSpeed:Z9(l.turboSpeed,a.turboSpeed),precisionSpeed:Z9(l.precisionSpeed,a.precisionSpeed)}}function L2(t,a){if(!t||t.size===0)return!1;for(const l of a)if(t.has(l))return!0;return!1}function pu(t,a){const l=L2(a.driveForward,t),s=L2(a.driveBackward,t),u=L2(a.driveLeft,t),f=L2(a.driveRight,t),v=L2(a.boostModifier,t),p=L2(a.slowModifier,t);let g=0;l&&!s?g=1:s&&!l&&(g=-1);let x=0;u&&!f?x=-1:f&&!u&&(x=1);const z=p?.4:1;return{x:x*z,y:g*z,boost:v&&!p}}function wY(t,a){if(L2(a.auxAllForward,t))return{main:127,side:127,vacuum:127};const s=L2(a.auxMainForward,t)?127:L2(a.auxMainReverse,t)?-127:0,u=L2(a.auxSideForward,t)?127:L2(a.auxSideReverse,t)?-70:0,f=L2(a.auxVacuumFast,t)?127:L2(a.auxVacuumSlow,t)?50:0;return{main:s,side:u,vacuum:f}}function gu(t,a,l){return L2(a.slowModifier,t)?{baseSpeed:l.precisionSpeed,boostSpeed:l.precisionSpeed}:{baseSpeed:l.baseSpeed,boostSpeed:l.turboSpeed}}const $9="keyboard",I9={x:0,y:0,boost:!1},G9={main:0,side:0,vacuum:0},rs=Wc[0],is=Wc[1],aa=5,k8=500,R8=1,na=100,Et=["none","grayscale","greenscale"];function xu(t){return Et.includes(t)?t:H0.colorFilter}function CY(t){const a=xu(t),l=Et.indexOf(a);return Et[(l+1)%Et.length]}function SY(t,a){const l=Number(t);return Number.isFinite(l)?Math.max(aa,Math.min(k8,l)):a}function zu(t,a){const l=Number(t);return Number.isFinite(l)?Math.max(R8,Math.min(na,l)):a}function HY(t){const l=(zu(t,t)-R8)/(na-R8),s=k8-l*(k8-aa);return Math.round(s)}function AY(t){const a=SY(t,t),l=(k8-a)/(k8-aa),s=R8+l*(na-R8);return Math.round(s)}function VY(t){return mu(t?.target)}function LY(){const{setMode:t,setDriveVector:a,setAuxMotors:l,nudgeServo:s,runMacro:u,stopAllMotion:f,registerInputState:v,toggleNightVision:p,startHorn:g,stopHorn:x,setMicPttActive:z,setSongNote:b,sendSong:y}=x3(),H=q1(p1=>p1.state.keymap),S=q1(p1=>p1.state.camera?.config?.nudgeDegrees),C=q1(p1=>p1.state.song?.note),w=q1(p1=>p1.state.roverId),L=q1(p1=>!!p1.state.horn?.active),A=u1(p1=>p1.session?.homeAssistant||null),V=A0(),{homeAssistantSetState:N,pushAlert:T}=I2(),{focusChat:R}=ca(),{isChatFocused:j}=bY(),{value:F}=T1("inputs",R4),{value:U,save:O}=T1("video",H0),q=xu(U?.colorFilter),$=d.useMemo(()=>cu(H),[H]),e1=d.useMemo(()=>{const p1=new Set;return Object.values($).forEach(x1=>{x1&&x1.forEach(L1=>p1.add(L1))}),p1},[$]),n1=d.useMemo(()=>vu(F),[F]),J=d.useMemo(()=>{const p1=R4.keyboard,x1=F?.keyboard??{},L1=zu(typeof x1.tiltSpeed=="number"?x1.tiltSpeed:typeof x1.tiltIntervalMs=="number"?AY(x1.tiltIntervalMs):p1.tiltSpeed,p1.tiltSpeed);return HY(L1)},[F?.keyboard]),k=d.useMemo(()=>Math.abs(S||1),[S]),I=d.useRef(new Set),t1=d.useRef(I9),f1=d.useRef(G9),m1=d.useRef(null),E=d.useRef(null),_=d.useRef(!1),K=d.useRef(null),r1=d.useCallback(()=>{const p1=K.current;if(!p1)return;const x1=new Set(I.current),L1=gu(x1,p1.keymap,p1.keyboardSpeeds),F1=pu(x1,p1.keymap),h1=wY(x1,p1.keymap);(F1.x!==t1.current.x||F1.y!==t1.current.y||F1.boost!==t1.current.boost)&&(t1.current=F1,p1.setDriveVector(F1,{source:$9,speedOptions:L1})),(h1.main!==f1.current.main||h1.side!==f1.current.side||h1.vacuum!==f1.current.vacuum)&&(f1.current=h1,p1.setAuxMotors(h1)),p1.registerInputState($9,{keys:Array.from(x1),vector:F1,aux:h1})},[]),v1=d.useCallback(()=>{m1.current&&(clearTimeout(m1.current),m1.current=null)},[]),g1=d.useCallback(()=>{const p1=K.current;if(!p1)return 0;const x1=new Set(I.current),L1=L2(p1.keymap.cameraUp,x1),F1=L2(p1.keymap.cameraDown,x1);return(L1?1:0)-(F1?1:0)},[]),V1=d.useCallback(()=>{if(g1()===0){v1();return}if(m1.current)return;const x1=()=>{const L1=g1();if(L1===0){v1();return}const F1=K.current;if(!F1){v1();return}F1.nudgeServo(L1*F1.servoStep),m1.current=setTimeout(x1,F1.servoRepeatMs)};m1.current=setTimeout(x1,0)},[g1,v1]),S1=d.useCallback(()=>{E.current&&(clearTimeout(E.current),E.current=null)},[]),N1=d.useCallback(()=>{const p1=K.current;if(!p1)return 0;const x1=new Set(I.current),L1=L2(p1.keymap.songNoteUp,x1),F1=L2(p1.keymap.songNoteDown,x1);return(L1?1:0)-(F1?1:0)},[]),P1=d.useCallback(p1=>{const x1=K.current;if(!x1||p1===0)return;let F1=(typeof x1.songNote=="number"?x1.songNote:x0)+p1;F1>is?F1=rs:F1{if(N1()===0){S1();return}if(E.current)return;const x1=()=>{const L1=N1();if(L1===0){S1();return}P1(L1),E.current=setTimeout(x1,IP)};E.current=setTimeout(x1,0)},[N1,S1,P1]),R1=d.useCallback(()=>{const p1=K.current;I.current.clear(),t1.current=I9,f1.current=G9,v1(),S1(),_.current&&(_.current=!1,p1?.stopHorn()),p1?.setMicPttActive(!1),p1?.stopAllMotion(),p1?.registerInputState($9,{keys:[],vector:I9,aux:G9})},[v1,S1]),p2=d.useCallback(p1=>{const x1=K.current,L1=x1?.homeAssistant;if(!L1?.enabled||!L1?.connected||L1?.lightPolicy?.locked||L1?.lightPolicy?.lockedOn)return;const h1=(L1.entities||[]).filter(y1=>(y1.type==="light"||y1.type==="switch")&&y1.available!==!1&&y1.state!=="unavailable");if(h1.length!==0){if(p1==="on"){const y1=h1.find(k1=>k1.state!=="on");y1&&x1.homeAssistantSetState(y1.id,"on").catch(()=>{});return}if(p1==="off")for(let y1=h1.length-1;y1>=0;y1-=1){const k1=h1[y1];if(k1.state==="on"){x1.homeAssistantSetState(k1.id,"off").catch(()=>{});break}}}},[]),s1=d.useCallback(()=>{const p1=K.current;if(!p1)return;const x1=CY(p1.videoColorFilter);p1.saveVideoSettings(L1=>({...L1??{},colorFilter:x1})),p1.pushAlert({id:"video-filter-active",title:"Video filter",message:`Rover video filter: ${x1}`,color:"#38bdf8",lifetimeMs:1600})},[]);d.useLayoutEffect(()=>{K.current={actionTokens:e1,dockAssist:V,focusChat:R,homeAssistant:A,homeAssistantSetState:N,isChatFocused:j,keyboardSpeeds:n1,keymap:$,nudgeServo:s,pushAlert:T,registerInputState:v,roverId:w,runMacro:u,saveVideoSettings:O,sendSong:y,servoRepeatMs:J,servoStep:k,setAuxMotors:l,setDriveVector:a,setMicPttActive:z,setMode:t,setSongNote:b,songNote:C,startHorn:g,stopAllMotion:f,stopHorn:x,toggleNightVision:p,videoColorFilter:q}}),d.useEffect(()=>{function p1(F1){const h1=K.current;if(!h1||ls()||VY(F1))return;const y1=ts(F1);if(y1.length===0)return;const k1=new Set(y1);if(L2(h1.keymap.chatFocus,k1)){F1.preventDefault(),R1(),h1.isChatFocused||h1.focusChat();return}y1.some(C1=>h1.actionTokens.has(C1))&&F1.preventDefault();const X1=y1.filter(C1=>!I.current.has(C1));if(X1.forEach(C1=>I.current.add(C1)),X1.length>0)if(X1.some(C1=>h1.keymap.driveMacro?.has(C1)))d1("drive_start",{roverId:h1.roverId||"",source:"keyboard"}),h1.dockAssist.exitAssist(),h1.setMode("drive"),h1.runMacro("drive-sequence");else if(X1.some(C1=>h1.keymap.dockMacro?.has(C1)))d1("dock_assist_toggle",{roverId:h1.roverId||"",source:"keyboard"}),h1.dockAssist.toggleAssist();else if(X1.some(C1=>h1.keymap.nightVisionToggle?.has(C1)))d1("night_vision_toggle",{roverId:h1.roverId||"",source:"keyboard"}),h1.toggleNightVision();else if(X1.some(C1=>h1.keymap.videoFilterCycle?.has(C1)))s1();else if(X1.some(C1=>h1.keymap.hornHonk?.has(C1))){if(!_.current){const C1=h1.startHorn();_.current=!!C1}}else X1.some(C1=>h1.keymap.micPtt?.has(C1))?h1.setMicPttActive(!0):X1.some(C1=>h1.keymap.homeAssistantOn?.has(C1))?p2("on"):X1.some(C1=>h1.keymap.homeAssistantOff?.has(C1))&&p2("off");V1(),Y1(),r1()}function x1(F1){const h1=K.current;if(!h1||ls())return;ts(F1).forEach(k1=>I.current.delete(k1)),_.current&&!L2(h1.keymap.hornHonk,I.current)&&(_.current=!1,h1.stopHorn()),L2(h1.keymap.micPtt,I.current)||h1.setMicPttActive(!1),V1(),Y1(),r1()}function L1(){R1()}return window.addEventListener("keydown",p1,{capture:!0}),window.addEventListener("keyup",x1,{capture:!0}),window.addEventListener("blur",L1),()=>{window.removeEventListener("keydown",p1,{capture:!0}),window.removeEventListener("keyup",x1,{capture:!0}),window.removeEventListener("blur",L1)}},[s1,r1,V1,Y1,R1,p2]);const H1=d.useRef(R1);return d.useEffect(()=>{H1.current=R1},[R1]),d.useEffect(()=>{H1.current()},[w]),d.useEffect(()=>{_.current=L},[L]),d.useEffect(()=>()=>{v1(),S1()},[v1,S1]),null}const BY=1.6;function bu(t){if(!t)return"unknown::none::0::0";const a=t.id||"unknown",l=t.mapping||"none",s=Array.isArray(t.axes)?t.axes.length:0,u=Array.isArray(t.buttons)?t.buttons.length:0;return`${a}::${l}::${s}::${u}`}function jY(t){return JSON.parse(JSON.stringify(t??{}))}function Mu(t,a){const l=jY(a);return l.meta={id:t?.id??"Unknown",mapping:t?.mapping??"none",axes:t?.axes?.length??0,buttons:t?.buttons?.length??0},l}function p6(t){return Number.isFinite(t)?Math.max(-1,Math.min(1,t)):0}function C8(t,a){if(!t)return 0;const l=Math.abs(t);return a==="expo"?Math.sign(t)*Math.pow(l,BY):t}function P9(t,a){const l=Math.abs(t);if(l<=a)return 0;const s=(l-a)/(1-a);return Math.sign(t)*s}function NY(t,a,l){const s=Math.hypot(t,a);if(s<=l)return{x:0,y:0};const f=(s-l)/(1-l)/s;return{x:t*f,y:a*f}}function It(t,a){if(!t||!Array.isArray(t.axes))return null;const l=t.axes[a];return Number.isFinite(l)?p6(l):null}function Cc(t,a){if(!t||!Array.isArray(t.buttons))return null;const l=t.buttons[a];if(!l)return null;const s=typeof l.value=="number"?l.value:l.pressed?1:0;return{pressed:!!(l.pressed||s>.5),value:Math.max(0,Math.min(1,s))}}function Y9(t,a=[]){for(const l of a)if(l){if(l.kind==="axis"){const s=It(t,l.index);if(s===null)continue;return{value:l.invert?-s:s,source:l}}if(l.kind==="buttonAxis"){const s=Cc(t,l.index);if(!s)continue;return{value:p6(s.value),source:l}}}return{value:0,source:null}}function FY(t,a=[]){for(const l of a){if(!l||l.kind!=="axisPair")continue;const s=It(t,l.x),u=It(t,l.y);if(s===null||u===null)continue;const f=l.invertX?-s:s,v=l.invertY?-u:u;return{x:f,y:v,source:l}}return{x:0,y:0,source:null}}function u6(t,a=[]){for(const l of a)if(l){if(l.kind==="button"){const s=Cc(t,l.index);if(!s)continue;return{pressed:s.pressed,source:l}}if(l.kind==="axisButton"){const s=It(t,l.index);if(s===null)continue;const u=l.direction||1,f=typeof l.threshold=="number"?l.threshold:.6;return{pressed:s*u>f,source:l}}if(l.kind==="buttonAxis"){const s=Cc(t,l.index);if(!s)continue;return{pressed:s.value>.5,source:l}}}return{pressed:!1,source:null}}function yu(t,a){const l=a?.bindings??{},s=a?.calibration??{},u=l.drive??{},f=FY(t,u.sources);let v=p6(f.x),p=p6(f.y);const g=Math.min(Math.max(s.driveDeadzone??.18,0),.8),x=NY(v,p,g);v=C8(x.x,s.driveCurve),p=C8(x.y,s.driveCurve);const z=l.cameraTilt??{},b=Y9(t,z.sources),y=Math.min(Math.max(s.cameraDeadzone??.08,0),.8);let H=P9(p6(b.value),y);H=C8(H,s.cameraCurve);const S=Math.min(Math.max(s.auxDeadzone??.05,0),.6),C=l.mainBrush??{},w=Y9(t,C.sources);let L=P9(p6(w.value),S);L=C8(L,s.auxCurve);const A=l.sideBrush??{},V=Y9(t,A.sources);let N=P9(p6(V.value),S);N=C8(N,s.auxCurve);const T=u6(t,l.vacuum?.sources),R=u6(t,l.allAux?.sources),j=u6(t,l.mainReverse?.sources),F=u6(t,l.sideReverse?.sources),U=u6(t,l.driveMacro?.sources),O=u6(t,l.dockMacro?.sources),q=u6(t,l.nightVisionToggle?.sources);return{driveVector:{x:v,y:p,boost:!1},cameraAxis:H,auxAxis:{main:L,side:N},buttons:{vacuum:T.pressed,allAux:R.pressed,mainReverse:j.pressed,sideReverse:F.pressed,driveMacro:U.pressed,dockMacro:O.pressed,nightVisionToggle:q.pressed},sources:{drive:f.source,cameraTilt:b.source,mainBrush:w.source,sideBrush:V.source,vacuum:T.source,allAux:R.source,mainReverse:j.source,sideReverse:F.source,driveMacro:U.source,dockMacro:O.source,nightVisionToggle:q.source}}}const L8=new Set;let p0=null,b0={pads:[],timestamp:0},ft=!1,mt=null;function ss(){return wu().some(t=>t?.connected!==!1)}function wu(){if(typeof navigator>"u"||!navigator.getGamepads)return[];const t=navigator.getGamepads();return t?Array.from(t).filter(Boolean):[]}function kY(t){return{index:t.index,id:t.id,mapping:t.mapping,connected:t.connected!==!1,timestamp:t.timestamp,axes:Array.from(t.axes??[]),buttons:(t.buttons??[]).map(a=>({pressed:!!a?.pressed,value:typeof a?.value=="number"?a.value:a?.pressed?1:0})),signature:bu(t)}}function Gt(){b0={pads:wu().map(kY),timestamp:typeof performance<"u"?performance.now():Date.now()},L8.forEach(a=>a(b0))}function Cu(){if(Gt(),b0.pads.length===0){Sc();return}p0=requestAnimationFrame(Cu)}function os(){p0||(Gt(),b0.pads.length!==0&&(p0=requestAnimationFrame(Cu)))}function Sc(){p0&&(cancelAnimationFrame(p0),p0=null)}function Su(t){if(L8.add(t),!ft&&typeof window<"u"){const a=()=>{Gt(),L8.size!==0&&(ss()?os():Sc())};window.addEventListener("gamepadconnected",a),window.addEventListener("gamepaddisconnected",a),mt=a,ft=!0}return ss()?os():Gt(),t(b0),()=>{L8.delete(t),L8.size===0&&(Sc(),ft&&typeof window<"u"&&(window.removeEventListener("gamepadconnected",mt),window.removeEventListener("gamepaddisconnected",mt),mt=null,ft=!1))}}function RY(){const[t,a]=d.useState(b0);return d.useEffect(()=>Su(a),[]),t}const i0="gamepad",h6={x:0,y:0,boost:!1},d6={main:0,side:0,vacuum:0},EY=100,TY=100;function K9(t,a){return t&&a&&t.x===a.x&&t.y===a.y&&t.boost===a.boost}function Q9(t,a){return t&&a&&t.main===a.main&&t.side===a.side&&t.vacuum===a.vacuum}function qY(t){return t?Math.hypot(t.x||0,t.y||0):0}function _Y(t){return t?!t.main&&!t.side&&!t.vacuum:!0}function DY(t,a){if(!t||t.length===0)return null;if(a){const l=t.find(s=>s.signature===a);if(l)return l}return t[0]}function OY(){const{setMode:t,setDriveVector:a,setAuxMotors:l,setServoAngle:s,runMacro:u,toggleNightVision:f,registerInputState:v}=x3(),p=q1(q=>q.state.camera?.angle),g=q1(q=>q.state.camera?.config),x=q1(q=>q.state.roverId),z=A0(),{value:b,save:y}=T1("gamepad",Z3),H=d.useRef(new Set),S=d.useRef(h6),C=d.useRef(d6),w=d.useRef({main:!1,side:!1}),L=d.useRef(new Map),A=d.useRef(0),V=d.useRef(0),N=d.useRef(0),T=d.useRef(null),R=d.useRef(null),j=d.useCallback(q=>{const $=R.current;if(!$)return;const e1=q.signature??bu(q);$.gamepadSettings?.profiles?.[e1]||H.current.has(e1)||(H.current.add(e1),$.saveGamepadSettings(n1=>{const J=n1??Z3;if(J.profiles?.[e1])return J;const k=J?.defaults?.profile??d3,I=Mu(q,k);return{...J,profiles:{...J.profiles??{},[e1]:I}}}))},[]),F=d.useCallback((q,$)=>{const e1=L.current.get(q)||!1;return L.current.set(q,$),$&&!e1},[]),U=d.useCallback((q,$)=>{const e1=R.current,n1=e1?.cameraConfig;if(!e1||!n1)return;const J=typeof performance<"u"?performance.now():Date.now(),k=$?.cameraMode??"absolute",I=Math.max(1,Math.min(180,$?.cameraSensitivity??60));if(k==="velocity"){const _=Math.min(50,J-N.current||16),K=q*I*(_/1e3);if(Math.abs(K)<.01)return;const v1=(typeof T.current=="number"?T.current:typeof e1.cameraAngle=="number"?e1.cameraAngle:typeof n1.homeAngle=="number"?n1.homeAngle:0)+K;e1.setServoAngle(v1),T.current=v1,N.current=J;return}const t1=typeof n1.minAngle=="number"?n1.minAngle:-45,f1=typeof n1.maxAngle=="number"?n1.maxAngle:45,m1=typeof n1.homeAngle=="number"?n1.homeAngle:(t1+f1)/2,E=q<0?m1+q*(m1-t1):m1+q*(f1-m1);typeof T.current=="number"&&Math.abs(T.current-E)<.35&&J-N.current<80||(N.current=J,T.current=E,e1.setServoAngle(E))},[]),O=d.useMemo(()=>b?.activeSignature??null,[b?.activeSignature]);return d.useLayoutEffect(()=>{R.current={activeSignature:O,cameraAngle:p,cameraConfig:g,dockAssist:z,gamepadSettings:b,registerInputState:v,roverId:x,runMacro:u,saveGamepadSettings:y,setAuxMotors:l,setDriveVector:a,setMode:t,setServoAngle:s,toggleNightVision:f}}),d.useEffect(()=>Su(q=>{const $=R.current;if(!$)return;const e1=DY(q.pads,$.activeSignature);if(!e1){K9(S.current,h6)||(S.current=h6,$.setDriveVector(h6,{source:i0})),Q9(C.current,d6)||(C.current=d6,$.setAuxMotors(d6)),L.current=new Map,w.current={main:!1,side:!1},A.current=0,V.current=0,$.registerInputState(i0,{connected:!1});return}if(yY()){K9(S.current,h6)||(S.current=h6,$.setDriveVector(h6,{source:i0})),Q9(C.current,d6)||(C.current=d6,$.setAuxMotors(d6)),L.current=new Map,w.current={main:!1,side:!1},$.registerInputState(i0,{connected:!0,blocked:!0});return}j(e1);const n1=e1.signature,J=$.gamepadSettings?.profiles?.[n1]??$.gamepadSettings?.defaults?.profile??d3,k=yu(e1,J);if(!K9(k.driveVector,S.current)){const K=typeof performance<"u"?performance.now():Date.now();(qY(k.driveVector)<.02||K-A.current>=EY)&&(S.current=k.driveVector,A.current=K,$.setDriveVector(k.driveVector,{source:i0}))}const I=J.calibration?.auxSideScale??.55,t1=Math.round(Math.min(Math.abs(k.auxAxis.main),1)*127),f1=Math.round(Math.min(Math.abs(k.auxAxis.side),1)*127),m1=w.current.main?-t1:t1,E=w.current.side?-Math.round(f1*I):Math.round(f1*I);let _={main:k.auxAxis.main!==0?m1:0,side:k.auxAxis.side!==0?E:0,vacuum:k.buttons.vacuum?127:0};if(k.buttons.allAux&&(_={main:127,side:127,vacuum:127}),!Q9(_,C.current)){const K=typeof performance<"u"?performance.now():Date.now();(_Y(_)||K-V.current>=TY)&&(C.current=_,V.current=K,$.setAuxMotors(_))}k.buttons.mainReverse&&F("mainReverse",!0)?w.current.main=!w.current.main:k.buttons.mainReverse||F("mainReverse",!1),k.buttons.sideReverse&&F("sideReverse",!0)?w.current.side=!w.current.side:k.buttons.sideReverse||F("sideReverse",!1),k.buttons.driveMacro&&F("driveMacro",!0)?(d1("drive_start",{roverId:$.roverId||"",source:"gamepad"}),$.dockAssist.exitAssist(),$.setMode("drive"),$.runMacro("drive-sequence")):k.buttons.driveMacro||F("driveMacro",!1),k.buttons.dockMacro&&F("dockMacro",!0)?(d1("dock_assist_toggle",{roverId:$.roverId||"",source:"gamepad"}),$.dockAssist.toggleAssist()):k.buttons.dockMacro||F("dockMacro",!1),k.buttons.nightVisionToggle&&F("nightVisionToggle",!0)?(d1("night_vision_toggle",{roverId:$.roverId||"",source:"gamepad"}),$.toggleNightVision()):k.buttons.nightVisionToggle||F("nightVisionToggle",!1),Math.abs(k.cameraAxis)>.001&&U(k.cameraAxis,J.calibration),$.registerInputState(i0,{connected:!0,signature:n1,id:e1.id,index:e1.index,axes:e1.axes,buttons:e1.buttons,drive:k.driveVector,aux:_,cameraAxis:k.cameraAxis,bindings:k.sources})}),[j,F,U]),null}function X9(t){const a=Number(t);return!Number.isFinite(a)||a<=0?0:Math.min($t,Math.round(a))}function Hu({disabled:t,onStart:a,onStop:l,keyLabel:s,active:u,heat:f=0,className:v="",defaultShowSettings:p=!0,showSettingsToggle:g=!1,compactSettings:x=!1}){const[z,b]=d.useState(p),{value:y,save:H}=T1("horn",g6),[S,C]=d.useState(y?.waveform||g6.waveform),w=d.useRef(null),L=d.useRef(null),[A,V]=d.useState(()=>[...Array.isArray(y?.freqs)?y.freqs:g6.freqs,0,0,0,0].slice(0,4).map(k=>X9(k)));d.useEffect(()=>{C(y?.waveform||g6.waveform),Array.isArray(y?.freqs)&&V([...y.freqs,0,0,0,0].slice(0,4).map(J=>X9(J)))},[y?.freqs,y?.waveform]);const N=!!u,T=Math.max(0,Math.min(1,Number(f)||0)),R=d.useMemo(()=>["mobile-touch-control group relative flex w-full flex-col gap-0.5 overflow-hidden rounded-xl border-2 px-1 py-1.5 text-xs font-semibold select-none no-touch-select",N?"border-fuchsia-300/70 bg-fuchsia-700 text-fuchsia-50":"border-cyan-300/70 bg-cyan-900 text-cyan-50 hover:bg-cyan-800","disabled:opacity-50",v].filter(Boolean).join(" "),[v,N]),j=S==="sine"?"sine":"saw",F=d.useCallback(J=>{const k=J.target.value==="sine"?"sine":"saw";C(k),H(I=>({...I??{},waveform:k}))},[H]),U=d.useCallback((J,k)=>{V(I=>{const t1=[...I];return t1[J]=X9(k),H(f1=>({...f1??{},freqs:t1})),t1})},[H]);d.useEffect(()=>{const J=w.current;if(!J)return;const k=I=>{const t1=I.target;if(!(t1 instanceof Element))return;const f1=t1.closest("input[data-horn-freq-index]");if(!f1)return;const m1=Number(f1.dataset.hornFreqIndex);if(!Number.isInteger(m1)||m1<0||m1>=A.length)return;I.preventDefault(),I.stopPropagation();const E=I.deltaY<0?1:-1,_=Number(A[m1])||0;U(m1,_+E*25)};return J.addEventListener("wheel",k,{passive:!1,capture:!0}),()=>{J.removeEventListener("wheel",k,{capture:!0})}},[A,U]);const O=J=>{if(t||L.current!==null)return;const k=J.target?.tagName?.toLowerCase();k==="input"||k==="select"||k==="option"||k==="label"||k==="button"||(J.preventDefault(),L.current=J.pointerId,J.currentTarget.setPointerCapture?.(J.pointerId),a?.())},q=J=>{if(L.current!==J.pointerId)return;const k=J.target?.tagName?.toLowerCase();k==="input"||k==="select"||k==="option"||k==="label"||k==="button"||(J.preventDefault(),L.current=null,J.currentTarget.releasePointerCapture?.(J.pointerId),l?.())},$=J=>{L.current===J.pointerId&&(L.current=null,l?.())},e1=()=>{L.current!==null&&(L.current=null,l?.())},n1=g?r.jsx("button",{type:"button",onClick:J=>{J.preventDefault(),b(k=>!k)},className:"mobile-touch-control rounded bg-black/40 px-1 py-0.5 text-[0.6rem] font-semibold text-white/90 hover:text-white",children:z?"Hide":"Settings"}):null;return r.jsxs("div",{role:"button",tabIndex:0,"aria-pressed":N,onPointerDown:O,onPointerUp:q,onPointerCancel:$,onLostPointerCapture:J=>{L.current===J.pointerId&&(L.current=null,l?.())},onContextMenu:J=>J.preventDefault(),onBlur:e1,className:R,children:[r.jsx("div",{className:"pointer-events-none absolute inset-0 opacity-70",style:{background:`linear-gradient(90deg, rgba(14,116,144,0.7) ${T*100}%, rgba(0,0,0,0) ${T*100}%)`}}),r.jsx("div",{className:`pointer-events-none absolute inset-0 transition-opacity ${N?"opacity-40":"opacity-0"}`,style:{background:"linear-gradient(90deg, rgba(217,70,239,0.75), rgba(244,114,182,0.35))"}}),r.jsxs("div",{className:"relative z-10 flex items-center justify-between gap-0.5",children:[r.jsxs("span",{className:"flex items-center gap-0.5 text-sm font-semibold",children:[r.jsx("span",{children:"Horn"}),s?r.jsx("span",{className:"rounded bg-black/40 px-1 py-0.5 text-[0.6rem] font-semibold text-white",children:s}):null]}),n1,r.jsx("span",{className:`rounded px-1 py-0.5 text-[0.65rem] font-semibold ${N?"bg-fuchsia-200 text-fuchsia-900":"bg-slate-800 text-slate-200"}`,children:N?"Honk":"Hold"})]}),z?x?r.jsxs("div",{ref:w,className:"relative z-10 flex flex-col gap-0.5 text-[0.65rem]",children:[r.jsxs("label",{className:"flex items-center justify-between gap-0.5 text-slate-200",children:[r.jsx("span",{className:"text-slate-300",children:"Wave"}),r.jsxs("select",{value:j,onChange:F,className:"rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-[0.65rem] text-slate-100",children:[r.jsx("option",{value:"saw",children:"Saw"}),r.jsx("option",{value:"sine",children:"Sine"})]})]}),r.jsx("div",{className:"grid grid-cols-2 gap-0.5",children:A.map((J,k)=>r.jsxs("label",{className:"flex items-center gap-0.5 text-slate-200",children:[r.jsx("span",{className:"text-[0.6rem] text-slate-400",children:k+1}),r.jsx("input",{type:"number",min:0,max:$t,step:1,value:J,"data-horn-freq-index":k,onChange:I=>U(k,I.target.value),className:"w-full rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-right text-[0.65rem] font-mono text-slate-100"})]},`horn-freq-${k}`))})]}):r.jsxs("div",{ref:w,className:"relative z-10 grid grid-cols-[minmax(0,1.2fr)_repeat(4,minmax(0,1fr))] items-center gap-0.5 text-[0.65rem]",children:[r.jsxs("label",{className:"flex items-center gap-0.5 text-slate-200",children:[r.jsx("span",{className:"text-slate-300",children:"Wave"}),r.jsxs("select",{value:j,onChange:F,className:"rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-[0.65rem] text-slate-100",children:[r.jsx("option",{value:"saw",children:"Saw"}),r.jsx("option",{value:"sine",children:"Sine"})]})]}),A.map((J,k)=>r.jsxs("label",{className:"flex items-center gap-0.5 text-slate-200",children:[r.jsx("span",{className:"text-[0.6rem] text-slate-400",children:k+1}),r.jsx("input",{type:"number",min:0,max:$t,step:1,value:J,"data-horn-freq-index":k,onChange:I=>U(k,I.target.value),className:"w-full rounded border border-slate-700 bg-slate-900 px-1 py-[2px] text-right text-[0.65rem] font-mono text-slate-100"})]},`horn-freq-${k}`))]}):null]})}function J9(t){return typeof t=="boolean"}function Au({nightVisionOn:t,disabled:a,onToggle:l,keyLabel:s,className:u="",heightClass:f=""}){const[v,p]=d.useState(J9(t)?t:null),g=d.useRef(!1),x=d.useRef(null);d.useEffect(()=>{J9(t)&&p(t)},[t]),d.useEffect(()=>()=>{x.current&&clearTimeout(x.current)},[]);const z=J9(v),b=z?v:!1,y=z?b?"On":"Off":"—",H=b?"bg-emerald-500 text-emerald-950":"bg-slate-700 text-slate-200",S=()=>{if(a)return;const A=z?!b:!0;p(A),l?.(A)},C=A=>{a||A.pointerType!=="mouse"&&(A.preventDefault(),g.current=!0,x.current&&clearTimeout(x.current),x.current=window.setTimeout(()=>{g.current=!1,x.current=null},800),S())},w=A=>{if(g.current){A.preventDefault(),g.current=!1,x.current&&(clearTimeout(x.current),x.current=null);return}S()},L=d.useMemo(()=>["mobile-touch-control group flex w-full flex-col items-center justify-center gap-0.35 rounded-xl border-2 px-1 py-0.75 text-center select-none no-touch-select",b?"border-emerald-300/70 bg-emerald-800 text-emerald-50 hover:bg-emerald-700":"border-amber-300/70 bg-amber-900 text-amber-50 hover:bg-amber-800","disabled:opacity-50",f,u].filter(Boolean).join(" "),[u,b,f]);return r.jsxs("button",{type:"button",onPointerDown:C,onClick:w,onContextMenu:A=>A.preventDefault(),disabled:a,"aria-pressed":b,className:L,children:[r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx("span",{className:"text-sm font-semibold",children:"Night Vision"}),s?r.jsx("span",{className:"rounded bg-slate-800 px-1 py-0.5 text-[0.6rem] font-semibold text-slate-200",children:s}):null]}),r.jsx("span",{className:`rounded px-1 py-0.5 text-[0.7rem] font-semibold ${H}`,children:y})]})}const us="mobile-drive-pad",UY=100,Hc=[{id:"precision",label:"precision",modifierAction:"slowModifier"},{id:"normal",label:"normal",modifierAction:null},{id:"turbo",label:"turbo",modifierAction:"boostModifier"}],ZY={main:0,side:0,vacuum:0},$Y={main:127,side:127,vacuum:127},IY={main:-127,side:-127,vacuum:-127};function hs({id:t,label:a,values:l,color:s,disabled:u,onPress:f,onRelease:v}){return r.jsx("button",{type:"button",disabled:u,onPointerDown:p=>{p.preventDefault(),f(t,l)},onPointerUp:()=>v(t),onPointerLeave:()=>v(t),onPointerCancel:()=>v(t),onContextMenu:p=>p.preventDefault(),className:`mobile-touch-control flex h-full w-full items-center justify-center rounded-xl border-2 px-1 py-0.75 text-center text-sm font-semibold text-white transition select-none no-touch-select ${s} hover:brightness-110 active:brightness-125 active:scale-[0.99] disabled:opacity-30`,children:a})}function GY({disabled:t,onPress:a,onRelease:l}){return r.jsxs("div",{className:"mobile-touch-control grid min-h-0 grid-rows-2 gap-0.5",children:[r.jsx(hs,{id:"aux-vac-forward",label:"Vacuum Forward",values:$Y,color:"bg-fuchsia-600",disabled:t,onPress:a,onRelease:l}),r.jsx(hs,{id:"aux-vac-backward",label:"Vacuum Backward",values:IY,color:"bg-fuchsia-800",disabled:t,onPress:a,onRelease:l})]})}function W9(t,a,l){return Number.isFinite(t)?Math.max(a,Math.min(l,t)):a}function PY(t){return typeof t!="number"||Number.isNaN(t)?"—":`${t>0?"+":""}${t.toFixed(1)}°`}function YY({value:t,min:a,max:l,step:s=.5,disabled:u=!1,onChange:f}){const v=d.useRef(null),p=d.useRef(null),g=d.useMemo(()=>l===a?50:(W9(t,a,l)-a)/(l-a)*100,[l,a,t]),x=u?"opacity-50":"",z=d.useCallback(C=>{const w=v.current;if(!w)return t;const L=w.getBoundingClientRect(),A=Math.max(1,L.height),V=1-(C.clientY-L.top)/A,N=a+W9(V,0,1)*(l-a),T=Math.round(N/s)*s;return W9(T,a,l)},[l,a,s,t]),b=d.useCallback(C=>{const w=z(C);f?.(w)},[f,z]),y=d.useCallback(C=>{u||p.current===null&&(C.preventDefault(),p.current=C.pointerId,v.current?.setPointerCapture?.(C.pointerId),b(C))},[u,b]),H=d.useCallback(C=>{p.current===C.pointerId&&(C.preventDefault(),b(C))},[b]),S=d.useCallback(C=>{p.current===C.pointerId&&(C.preventDefault(),p.current=null,v.current?.releasePointerCapture?.(C.pointerId))},[]);return r.jsxs("div",{className:"mobile-touch-control flex h-full items-center justify-center gap-0.5",children:[r.jsx("span",{className:"mobile-touch-control text-sm font-semibold text-emerald-50 [writing-mode:vertical-rl] rotate-180",children:"Camera tilt"}),r.jsxs("div",{ref:v,role:"slider","aria-label":"Camera tilt","aria-valuemin":a,"aria-valuemax":l,"aria-valuenow":Number.isFinite(t)?t:a,"aria-valuetext":PY(t),"aria-disabled":u,tabIndex:u?-1:0,onPointerDown:y,onPointerMove:H,onPointerUp:S,onPointerCancel:S,onLostPointerCapture:C=>{p.current===C.pointerId&&(p.current=null)},onContextMenu:C=>C.preventDefault(),style:{touchAction:"none"},className:`mobile-touch-control mobile-drag-control relative h-full w-6 rounded-full border border-emerald-100/80 bg-emerald-950 shadow-inner focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-200 ${x}`.trim(),children:[r.jsx("div",{className:"pointer-events-none absolute inset-x-1 bottom-1 rounded-full bg-emerald-400",style:{height:`${g}%`}}),r.jsx("div",{className:"pointer-events-none absolute left-1/2 h-3.5 w-3.5 -translate-x-1/2 rounded-full border border-emerald-950 bg-emerald-200 shadow",style:{bottom:`clamp(0.25rem, calc(${g}% - 0.4375rem), calc(100% - 1.125rem))`}})]})]})}function KY(){const t=q1(q=>q.state.roverId),a=q1(q=>q.state.camera),l=q1(q=>q.state.horn),s=q1(q=>q.pipeline?.nightVision),u=q1(q=>q.pipeline?.nightVisionState),f=q1(q=>q.pipeline?.horn),{setServoAngle:v,setNightVision:p,setAuxMotors:g,startHorn:x,stopHorn:z}=x3(),b=A0(),y=!t,H=d.useRef(null),S=a?.config,C=!!(t&&a?.enabled&&S),w=!!(t&&s),L=!!(t&&f),A=l?.overheated,V=typeof S?.minAngle=="number"?S.minAngle:-45,N=typeof S?.maxAngle=="number"?S.maxAngle:45,T=typeof a?.angle=="number"?a.angle:typeof S?.homeAngle=="number"?S.homeAngle:(V+N)/2,R=!!(y||b.cameraLocked),j=d.useCallback(q=>{w&&(d1("night_vision_toggle",{roverId:t,source:"mobile_control",enabled:!!q}),p(q))},[w,t,p]),F=d.useCallback(()=>(d1("horn_start",{roverId:t,source:"mobile_control"}),x()),[t,x]),U=d.useCallback((q,$)=>{y||(H.current=q,g($))},[y,g]),O=d.useCallback(q=>{y||H.current===q&&(H.current=null,g(ZY))},[y,g]);return r.jsxs("div",{className:"mobile-touch-control grid h-full min-h-0 w-full grid-rows-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)] gap-0.5 text-slate-100",children:[r.jsx(GY,{disabled:y,onPress:U,onRelease:O}),r.jsxs("div",{className:"mobile-touch-control flex min-h-0 items-stretch gap-0.5",children:[C?r.jsx("div",{className:"mobile-touch-control flex-1 min-h-0 rounded-xl border-2 border-emerald-300/70 bg-emerald-900 px-1 py-1 text-emerald-50",children:r.jsx(YY,{value:T,min:V,max:N,step:.5,disabled:R,onChange:v})}):null,w?r.jsx(Au,{nightVisionOn:u?.nightVisionOn,disabled:y,onToggle:j,heightClass:"h-full"}):null]}),r.jsx("div",{className:"mobile-touch-control min-h-0",children:L?r.jsx(Hu,{disabled:y||A,onStart:F,onStop:z,active:l?.active,heat:l?.heat,defaultShowSettings:!1,showSettingsToggle:!0,compactSettings:!0,className:"h-full"}):null})]})}function Pt({layout:t,className:a=""}){return r.jsx("div",{className:`mobile-touch-control flex flex-col gap-0.5 ${a}`.trim(),"data-mobile-layout":t,children:r.jsx(KY,{})})}function Vu(t){const a=t?.oiModeLabel||"Unknown",l=a.toLowerCase(),s=t?.chargingStateLabel||"",u=!!t?.homeBase,f=u&&s.toLowerCase()!=="not charging"&&s!=="";return{driving:l==="full",docked:u,charging:f,dockedNotCharging:u&&!f,dockingInProgress:!u&&!f&&l==="passive",oiLabel:a,chargingLabel:s}}function Lu(t){const a=b6(t,Gc,$c);return d.useMemo(()=>Vu(a),[a])}function s0({value:t,tone:a="neutral"}){const l=a==="good"?"border-emerald-200 bg-emerald-600 text-white":a==="warn"?"border-amber-200 bg-amber-600 text-white":a==="bad"?"border-red-200 bg-red-600 text-white":"border-slate-200/30 bg-slate-700 text-slate-100";return r.jsx("div",{className:`flex flex-1 flex-col items-center justify-center rounded-lg border px-0.75 py-0.5 text-center ${l}`,children:r.jsx("span",{className:"text-base font-semibold md:text-lg",children:t})})}function ds({label:t}){return t?r.jsx("span",{className:"rounded border border-white/40 px-1 text-[0.7rem] text-white",children:t}):null}function tc({label:t,tone:a}){const l=a==="emerald"?"border-emerald-200/70 bg-emerald-600/70 text-emerald-50":a==="amber"?"border-amber-200/70 bg-amber-600/70 text-amber-50":"border-indigo-200/70 bg-indigo-600/70 text-indigo-50";return r.jsx("span",{className:`rounded-full border px-0.5 py-0.15 text-[0.7rem] font-semibold ${l}`,children:t})}function QY({instructions:t,onConfirm:a,onCancel:l,pending:s}){return r.jsx("div",{className:"fixed inset-0 z-40 flex items-center justify-center bg-black/70 p-1",children:r.jsxs("div",{className:"surface w-full max-w-md space-y-0.5 border border-indigo-700 bg-indigo-950/90 p-1 text-slate-100 shadow-2xl",children:[r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("p",{className:"text-lg font-semibold text-indigo-50",children:"Manual Docking Assist"}),r.jsx("p",{className:"text-sm text-slate-200",children:t.summary}),r.jsx(Ac,{steps:t.steps,tone:"indigo"})]}),r.jsxs("div",{className:"grid grid-cols-2 gap-0.5 text-sm",children:[r.jsx("button",{type:"button",onClick:l,className:"bg-slate-700 px-0.5 py-1 font-semibold text-slate-100 transition hover:bg-slate-600",children:"Cancel"}),r.jsx("button",{type:"button",disabled:s,onClick:a,className:"bg-indigo-600 px-0.5 py-1 font-semibold text-indigo-50 transition hover:bg-indigo-500 disabled:opacity-50",children:s?"Starting…":"Enter Assist"})]})]})})}function Bu({layout:t="desktop",expand:a=!1,fill:l=!1,driveDockState:s,compactHeightClass:u=""}){const f=t==="mobile",v=q1(x1=>x1.state.roverId),p=q1(x1=>x1.state.keymap),g=x3(),x=A0(),z=b6(v,Gc,$c),b=s??Vu(z),{driving:y,docked:H,charging:S,dockingInProgress:C}=b,[w,L]=d.useState(null),[A,V]=d.useState(!1),[N,T]=d.useState(!1),R=!!x.active,j=!v||w!==null,F=!v||w!==null,U=_2(p?.driveMacro?.[0]),O=_2(p?.dockMacro?.[0]),q={summary:"Use assist mode to manually line up with the dock.",steps:["Line up the center dot of your rover with the center of the dock","The UI will indicate when you are successfully docked","When good contact is made, the dock will stop flashing."]},$={summary:"You must enable driving mode before you can move the rover.",steps:["Press the keybind or tap this button to enable driving mode","Once ready (should be instant), this dialog will change, and you will be able to move"]},e1=H?"Docked":"Undocked",n1=H?"good":"bad",J=S?"Charging":H?"Charging soon...":"—",k=S?"good":H?"warn":"bad",I=async()=>{if(!(!v||w)){L("drive"),d1("drive_return",{roverId:v,source:"drive_dock_action"});try{x.exitAssist(),g.setMode("drive"),await g.runMacro("drive-sequence"),d1("drive_return_result",{roverId:v,status:"accepted"})}catch(x1){d1("drive_return_result",{roverId:v,status:"failed",reason:x1?.message||"unknown"}),alert(x1.message)}finally{L(null)}}},t1=async()=>{if(!(!v||w)){V(!1),T(!1),L("drive"),d1("drive_start",{roverId:v,source:"drive_dock_action"});try{x.exitAssist(),g.setMode("drive"),await g.runMacro("drive-sequence"),d1("drive_start_result",{roverId:v,status:"accepted"})}catch(x1){d1("drive_start_result",{roverId:v,status:"failed",reason:x1?.message||"unknown"}),alert(x1.message)}finally{L(null)}}},f1=async()=>{if(!(!v||w)){L("dock"),d1("dock_assist_start",{roverId:v});try{x.enterAssist(),d1("dock_assist_start_result",{roverId:v,status:"accepted"})}catch(x1){d1("dock_assist_start_result",{roverId:v,status:"failed",reason:x1?.message||"unknown"}),alert(x1.message)}finally{L(null),V(!1),T(!1)}}},m1=()=>{if(!F){if(R){x.exitAssist(),d1("dock_assist_exit",{roverId:v});return}T(!0),V(!0),d1("dock_assist_open",{roverId:v})}},E="mobile-touch-control flex w-full flex-col gap-0.5 overflow-hidden rounded-xl border-2 px-0.75 py-0.75 text-slate-100 shadow-md transition hover:-translate-y-0.5 hover:shadow-xl focus-visible:outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-60 select-none no-touch-select",_="text-center",K="items-center justify-between",r1="items-center justify-center",v1=f?"text-sm font-semibold":"",g1="border-emerald-300/70 bg-emerald-800 text-emerald-50 hover:bg-emerald-700 focus-visible:ring-emerald-300",V1="border-amber-300/70 bg-amber-900 text-amber-50 hover:bg-amber-800 focus-visible:ring-amber-300",S1="border-indigo-300/70 bg-indigo-900 text-indigo-50 hover:bg-indigo-800 focus-visible:ring-indigo-300",N1="border-cyan-300/70 bg-cyan-900 text-cyan-50 hover:bg-cyan-800 focus-visible:ring-cyan-300",P1="border-amber-300/70 bg-amber-900 text-amber-50 hover:bg-amber-800 focus-visible:ring-amber-300",R1=a||C,p2=R1?"h-full flex-1":l?"flex-1":"",s1=f&&!R1?u:"",H1=f&&!R1?r1:K,p1=f&&!R1&&y&&H;if(!y&&!C)return r.jsxs("button",{type:"button",onClick:t1,onContextMenu:x1=>x1.preventDefault(),disabled:j,className:`${E} ${p2} ${s1} ${_} ${H1} ${v1} ${g1}`,children:[r.jsxs("div",{className:"space-y-0.5 w-full",children:[r.jsxs("div",{className:"flex w-full flex-col items-center gap-0.25",children:[r.jsx("span",{className:"text-base font-semibold text-emerald-50 md:text-lg",children:"Start Driving"}),!f&&R1?r.jsxs("div",{className:"flex flex-wrap items-center justify-center gap-0.5",children:[U?r.jsx(ds,{label:U}):null,r.jsx(tc,{label:"Click to start",tone:"emerald"})]}):null]}),R1?r.jsxs(r.Fragment,{children:[r.jsx("p",{className:"text-sm text-emerald-50/90",children:$.summary}),r.jsx(Ac,{steps:$.steps,tone:"emerald"})]}):null]}),R1?r.jsxs("div",{className:"flex w-full flex-1 flex-col gap-0.5 self-stretch",children:[r.jsx(s0,{label:"Dock",value:e1,tone:n1}),r.jsx(s0,{label:"Charge",value:J,tone:k})]}):null]});if(C){const x1={summary:"The rover is currently attempting to dock itself due to being idle.",steps:["Click to return to driving mode."]};return r.jsxs("button",{type:"button",disabled:j,onClick:I,onContextMenu:L1=>L1.preventDefault(),className:`${E} ${p2} ${s1} ${_} ${H1} ${v1} ${V1}`,children:[r.jsxs("div",{className:"space-y-0.5 w-full",children:[r.jsxs("div",{className:"flex w-full flex-col items-center gap-0.25",children:[r.jsx("span",{className:"text-base font-semibold text-amber-50 md:text-lg",children:"Attempting to auto-dock..."}),R1?r.jsx("div",{className:"flex flex-wrap items-center justify-center gap-0.5",children:r.jsx(tc,{label:"Return to driving mode",tone:"emerald"})}):null]}),R1?r.jsx("p",{className:"text-sm text-amber-50/90",children:x1.summary}):null]}),R1?r.jsxs(r.Fragment,{children:[r.jsxs("div",{className:"flex w-full flex-1 flex-col gap-0.5 self-stretch",children:[r.jsx(s0,{label:"Dock",value:e1,tone:n1}),r.jsx(s0,{label:"Charge",value:J,tone:k})]}),f?null:r.jsx(Ac,{steps:x1.steps,tone:"amber"})]}):null]})}return r.jsxs(r.Fragment,{children:[r.jsxs("button",{type:"button",disabled:F,onClick:m1,onContextMenu:x1=>x1.preventDefault(),className:f?`flex w-full ${E} ${s1} ${_} ${H1} ${v1} ${R?N1:p1?P1:S1}`:`${E} ${p2} ${_} ${K} ${v1} ${R?N1:S1}`,children:[r.jsxs("div",{className:"flex w-full flex-col items-center gap-0.25",children:[r.jsx("span",{className:"text-base font-semibold text-indigo-50 md:text-lg",children:p1?"Docked!":R?"Exit Docking Assist":"Dock and charge"}),!f&&R1?r.jsxs("div",{className:"flex flex-wrap items-center justify-center gap-0.5",children:[O?r.jsx(ds,{label:O}):null,r.jsx(tc,{label:R?"Click to exit assist":"Click to enable assist",tone:"indigo"})]}):null]}),!f&&R1&&r.jsxs(r.Fragment,{children:[r.jsx("p",{className:"text-sm text-indigo-50/90",children:"Get near a dock and press this button to enter docking assist mode."}),r.jsxs("div",{className:"flex w-full flex-1 flex-col gap-0.5 self-stretch",children:[r.jsx(s0,{label:"Dock",value:e1,tone:n1}),r.jsx(s0,{label:"Charge",value:J,tone:k})]})]})]}),N||!f&&A?r.jsx(QY,{instructions:q,pending:w==="dock",onCancel:()=>{T(!1),V(!1)},onConfirm:f1}):null]})}function Ac({steps:t,tone:a="emerald"}){const l=a==="emerald"?"bg-emerald-900/60 text-emerald-50/90 border-emerald-700/60":a==="amber"?"bg-amber-900/60 text-amber-50/90 border-amber-700/60":"bg-indigo-900/60 text-indigo-50/90 border-indigo-700/60",s=a==="emerald"?"text-emerald-200":a==="amber"?"text-amber-200":"text-indigo-200";return r.jsx("div",{className:`space-y-0.5 rounded border px-0.5 py-0.35 text-left ${l}`,children:t.map((u,f)=>r.jsxs("div",{className:"text-[0.85rem] leading-snug break-words",children:[r.jsxs("div",{className:"flex items-start",children:[r.jsxs("span",{className:`mr-0 align-top text-[0.75rem] font-semibold ${s}`,children:[f+1,"."]}),r.jsx("span",{className:"align-top",children:u})]}),f(t[`${a.row}:${a.col}`]=a,t),{}),Tt=la.find(t=>t.id==="stop");function m0(t,a,l){return Number.isFinite(t)?Math.max(a,Math.min(l,t)):a}function ju(){return typeof window>"u"?{width:f0,height:f0}:{width:window.innerWidth||f0,height:window.innerHeight||f0}}function JY(t){if(!t)return f0;const a=t.getBoundingClientRect(),l=ju(),s=Math.max(96,Math.min(a.width,l.width-m6*2));return Math.round(s)}function WY(t,a,l){const s=ju(),u=l/2,f=Math.min(s.width-u,u+m6),v=Math.max(u+m6,s.width-u-m6),p=Math.min(s.height-u,u+m6),g=Math.max(u+m6,s.height-u-m6);return{x:m0(t,f,v),y:m0(a,p,g)}}function tK(t,a,l){const s=t?.size||f0,u=s/2,f=s/ec,v=m0(a-t.center.x+u,0,s-1),p=m0(l-t.center.y+u,0,s-1),g=m0(Math.floor(v/f),0,ec-1),x=m0(Math.floor(p/f),0,ec-1);return XY[`${x}:${g}`]||Tt}function eK({center:t,size:a,activeCellId:l}){if(typeof document>"u")return null;const s=a/2;return iv.createPortal(r.jsx("div",{className:"pointer-events-none fixed inset-0 z-[1000]","aria-hidden":"true",children:r.jsx("div",{className:"absolute grid grid-cols-3 grid-rows-3 overflow-hidden rounded-lg border-2 border-cyan-300/80 bg-slate-950/90 shadow-2xl shadow-cyan-950/50 backdrop-blur-sm",style:{height:a,left:t.x-s,top:t.y-s,width:a},children:la.map(u=>{const f=u.id===l,v=u.id==="stop",p="flex items-center justify-center border border-slate-700/80 px-1 text-center text-xs font-semibold leading-tight",g=f?v?"bg-rose-500 text-white":"bg-cyan-300 text-slate-950":v?"bg-slate-900 text-slate-300":"bg-slate-800/80 text-slate-200";return r.jsx("div",{className:`${p} ${g}`,children:u.label},u.id)})})}),document.body)}function cK({activeInputLabel:t="stop",disabled:a,onCellChange:l,onStop:s}){const u=d.useRef(null),f=d.useRef(null),v=d.useRef(null),p=d.useRef(null),[g,x]=d.useState(null),z=d.useCallback(()=>{f.current=null,p.current=null,x(null),s?.()},[s]),b=d.useCallback(C=>{const w=v.current;if(!w)return;const L=tK(w,C.clientX,C.clientY);p.current!==L.id&&(p.current=L.id,l?.(L)),x({...w,activeCellId:L.id})},[l]),y=d.useCallback(C=>{if(a||f.current!==null)return;C.preventDefault();const w=u.current;if(!w)return;f.current=C.pointerId;const L=JY(w),A=WY(C.clientX,C.clientY,L);v.current={center:A,size:L,activeCellId:Tt.id},w.setPointerCapture?.(C.pointerId),p.current=Tt.id,x(v.current),l?.(Tt)},[a,l]),H=d.useCallback(C=>{a||f.current!==C.pointerId||(C.preventDefault(),b(C))},[a,b]),S=d.useCallback(C=>{if(f.current!==C.pointerId)return;C.preventDefault();const w=C.pointerId;z(),u.current?.releasePointerCapture?.(w)},[z]);return d.useEffect(()=>{if(!a)return;const C=setTimeout(z,0);return()=>clearTimeout(C)},[a,z]),r.jsxs(r.Fragment,{children:[r.jsxs("div",{ref:u,role:"presentation",className:"mobile-touch-control mobile-drag-control relative flex h-full min-h-[10rem] w-full select-none items-center justify-center overflow-hidden text-slate-100",style:{touchAction:"none"},onPointerDown:y,onPointerMove:H,onPointerUp:S,onPointerCancel:S,onLostPointerCapture:C=>{f.current===C.pointerId&&z()},onContextMenu:C=>C.preventDefault(),children:[r.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-0 border-b border-slate-700 bg-slate-950 px-1.5 py-0.5 text-center",children:r.jsx("span",{className:"font-mono text-xs font-semibold text-cyan-200",children:t})}),r.jsxs("div",{className:"pointer-events-none flex flex-col items-center gap-0.5 px-2 pt-5 text-center",children:[r.jsx("span",{className:"text-sm font-semibold text-slate-100",children:"drive pad"}),r.jsx("span",{className:"text-xs leading-tight text-slate-300",children:"hold and drag"})]})]}),g?r.jsx(eK,{center:g.center,size:g.size,activeCellId:g.activeCellId}):null]})}function aK(t,a){const l=t?.[a];return!l||l.size===0?null:l.values().next().value??null}function nK(t){return Hc.find(a=>a.id===t)||Hc[1]}function lK({disabled:t=!1}){const a=q1(T=>T.state.keymap),{setDriveVector:l,registerInputState:s}=x3(),{value:u}=T1("inputs",R4),[f,v]=d.useState("normal"),[p,g]=d.useState("stop"),x=d.useRef("normal"),z=d.useRef(null),b=d.useRef(null),y=d.useMemo(()=>cu(a),[a]),H=d.useMemo(()=>vu(u),[u]),S=d.useCallback(()=>{b.current&&(clearInterval(b.current),b.current=null)},[]),C=d.useCallback((T,R=x.current)=>{const j=new Set,F=nK(R);return[...Array.isArray(T?.actions)?T.actions:[],F.modifierAction].filter(Boolean).forEach(O=>{const q=aK(y,O);q&&j.add(q)}),j},[y]),w=d.useCallback((T,R="move",j=x.current)=>{if(t)return;const F=C(T,j),U=pu(F,y),O=gu(F,y,H);l(U,{source:us,speedOptions:O}),s(us,{keys:Array.from(F),vector:U,activeCell:T?.id??"stop",speedMode:j,lastEvent:R})},[C,t,H,y,s,l]),L=d.useCallback((T="stop")=>{S(),z.current=null,g("stop"),w({id:"stop",actions:[]},T,"normal")},[S,w]),A=d.useCallback(()=>{b.current||(b.current=setInterval(()=>{z.current&&w(z.current,"repeat")},UY))},[w]),V=d.useCallback(T=>{t||(z.current=T,g(T?.label||"stop"),w(T,"move"),A())},[t,w,A]),N=d.useCallback(T=>{v(T),x.current=T,z.current&&w(z.current,"speed",T)},[w]);return d.useEffect(()=>()=>S(),[S]),d.useEffect(()=>{t&&L("disabled")},[t,L]),r.jsxs("div",{className:"mobile-touch-control flex flex-1 min-h-0 flex-col overflow-hidden rounded-xl border-2 border-slate-700 bg-slate-900 text-slate-100 shadow-md",children:[r.jsx("div",{className:"mobile-touch-control grid grid-cols-3 gap-0.5 border-b border-slate-700 bg-slate-950 p-0.5",children:Hc.map(T=>{const R=f===T.id,j=T.id==="precision"?H.precisionSpeed:T.id==="turbo"?H.turboSpeed:H.baseSpeed;return r.jsxs("button",{type:"button",className:`mobile-touch-control min-h-9 rounded-md px-1 text-xs font-semibold ${R?"bg-cyan-300 text-slate-950":"bg-slate-800 text-slate-200"}`,onClick:()=>N(T.id),disabled:t,children:[r.jsx("span",{className:"block leading-tight",children:T.label}),r.jsx("span",{className:"block font-mono text-[0.7rem] leading-tight",children:j})]},T.id)})}),r.jsx("div",{className:"mobile-touch-control min-h-0 flex-1",children:r.jsx(cK,{activeInputLabel:p,disabled:t,onCellChange:V,onStop:()=>L("stop")})})]})}function rK({layout:t}){const a=q1(g=>g.state.roverId),l=Lu(a),s=l.docked&&!l.driving,u=s||l.dockingInProgress,f=!a,p=`mobile-touch-control flex h-full flex-col gap-0.5 text-slate-100 ${s?"max-h-screen self-start":""}`;return r.jsxs("div",{className:p,"data-mobile-layout":t,children:[r.jsx(Bu,{layout:"mobile",expand:u,driveDockState:l,compactHeightClass:"min-h-[5rem]"}),u?null:r.jsx(lK,{disabled:f})]})}function Yt({layout:t,className:a=""}){return r.jsx("div",{className:`mobile-touch-control flex flex-col gap-0.5 ${a}`.trim(),"data-mobile-layout":t,children:r.jsx(rK,{layout:t==="landscape"?"landscape":"portrait"})})}function iK(t=[],a={}){const l=R2(),{enabled:s=!0,version:u=null}=a,[f,v]=d.useState({}),p=d.useRef(new Map),g=d.useMemo(()=>t.map(C=>typeof C=="string"?C:C.id),[t]),x=d.useMemo(()=>{const C=g.join("|");return u?`${C}|v:${u}`:C},[g,u]),z=d.useRef([]),[b,y]=d.useState(0),H=d.useRef(new Map),S=typeof window<"u"&&new URLSearchParams(window.location.search).has("debugSnapshots");return d.useEffect(()=>{if(!l)return;const C=()=>y(w=>w+1);return l.on("connect",C),()=>l.off("connect",C)},[l]),d.useEffect(()=>{z.current=g},[x,g]),d.useEffect(()=>{p.current.forEach(C=>URL.revokeObjectURL(C)),p.current.clear(),v({})},[x]),d.useEffect(()=>{if(!s){p.current.forEach(V=>URL.revokeObjectURL(V)),p.current.clear(),v({});return}if(!z.current.length||!l)return;let C=!1;const w=z.current,L=(V={},N)=>{if(C||!V.id||!N)return;const T=N.byteLength??N.length??0,R=Date.now(),j=H.current.get(V.id)||{count:0,totalBytes:0,lastLogAt:0},F={count:j.count+1,totalBytes:j.totalBytes+T,lastLogAt:j.lastLogAt};if(S&&(!F.lastLogAt||R-F.lastLogAt>=1e4)){const $=F.count?F.totalBytes/F.count:0;console.log("[roomCamera]",V.id,`frame=${T}B`,`avg=${Math.round($)}B`,`count=${F.count}`),F.lastLogAt=R}H.current.set(V.id,F);const U=new Blob([N],{type:"image/jpeg"}),O=URL.createObjectURL(U),q=p.current.get(V.id);q&&URL.revokeObjectURL(q),p.current.set(V.id,O),v($=>({...$,[V.id]:{status:"playing",ts:V.ts||Date.now(),error:null,objectUrl:O}}))},A=(V={})=>{C||!V.id||v(N=>({...N,[V.id]:{...N[V.id]||{},status:V.error?"error":N[V.id]?.status||"connecting",error:V.error||null,ts:V.ts||N[V.id]?.ts||null,objectUrl:N[V.id]?.objectUrl||null}}))};return l.on("roomCamera:frame",L),l.on("roomCamera:status",A),l.emit("roomCamera:subscribe",{ids:w},(V={})=>{V.error}),()=>{C=!0,l.emit("roomCamera:unsubscribe",{ids:w}),l.off("roomCamera:frame",L),l.off("roomCamera:status",A),p.current.forEach(V=>URL.revokeObjectURL(V)),p.current.clear()}},[l,x,s,b,S]),f}function sK({feed:t,label:a}){const[l,s]=d.useState(!1);d.useEffect(()=>{t&&(!t.ts&&!t.objectUrl||s(f=>!f))},[t?.ts,t?.objectUrl]);const u=d.useMemo(()=>t?t.error?`Error: ${t.error}`:t.status||"Connecting…":"Connecting…",[t]);return r.jsxs("div",{className:"relative w-full overflow-hidden rounded bg-black",style:{aspectRatio:"4 / 3"},children:[t?.objectUrl?r.jsx("img",{src:t.objectUrl,alt:a,className:"h-full w-full object-cover"}):r.jsx("div",{className:"flex h-full w-full items-center justify-center text-sm text-slate-300",children:"Waiting for frame…"}),r.jsx("div",{className:"pointer-events-none absolute left-0 top-0 bg-black/70 px-0.5 py-0.5 text-xs font-semibold text-white",children:a}),r.jsxs("div",{className:"pointer-events-none absolute bottom-0 left-0 m-0 flex items-center gap-0.5 rounded bg-black/70 px-0.5 py-0.25 text-[0.7rem] text-slate-100",children:[r.jsx("span",{className:`h-2 w-2 rounded-full ${l?"bg-emerald-400":"bg-slate-500"}`}),r.jsx("span",{children:u})]})]})}function oK(){return r.jsxs(j1,{title:"Room Cameras",bodyClassName:"space-y-0.5 text-sm",children:[r.jsx("p",{className:"text-center text-slate-400",children:"No room cameras configured."}),r.jsx("p",{className:"text-center text-slate-500",children:"Add entries to server config to populate this list."})]})}const Nu=["horizontal","vertical"];function cc(t,a){return Nu.includes(t)?t:a}function ra({defaultOrientation:t="horizontal",orientation:a,hideLayoutToggle:l=!1,hideHeader:s=!1,panelId:u=null}){const f=u1(w=>w.session?.roomCameras||[]),v=iK(f.map(w=>({id:w.id}))),{value:p,save:g}=T1("roomCameraPanels",{}),[x,z]=d.useState(()=>cc(u?p?.[u]:t,"horizontal"));d.useEffect(()=>{if(!u)return;const w=p?.[u];w&&z(cc(w,"horizontal"))},[u,p?.[u]]);const b=a?cc(a,"horizontal"):x,y=b==="vertical"?"flex flex-col gap-0.5":"grid gap-0.5 md:grid-cols-2",H=!l&&!a&&f.length>0,S=w=>{z(w),u&&g(L=>({...L||{},[u]:w}))};if(f.length===0)return r.jsx(oK,{});const C=H?r.jsxs("div",{className:"flex items-center gap-0.5 text-[0.68rem] text-slate-400",children:[r.jsx("span",{children:"Layout"}),r.jsx("div",{className:"inline-flex overflow-hidden rounded border border-slate-700",children:Nu.map(w=>r.jsx("button",{type:"button",className:`px-1 py-0.5 ${b===w?"bg-slate-600 text-white":"bg-transparent text-slate-400 hover:text-white"}`,onClick:()=>S(w),children:w==="vertical"?"Vertical":"Grid"},w))})]}):null;return r.jsx(j1,{title:"Room cameras",actions:C,hideHeader:s,bodyClassName:"space-y-0.5 text-base",children:r.jsx("div",{className:y,children:f.map(w=>{const L=v[w.id]||null;return r.jsx("article",{className:"w-full space-y-0.5 p-0.5",children:r.jsx(sK,{feed:L,label:w.name||w.id})},w.id)})})})}const uK="modulepreload",hK=function(t){return"/"+t},fs={},ms=function(a,l,s){let u=Promise.resolve();if(l&&l.length>0){let x=function(z){return Promise.all(z.map(b=>Promise.resolve(b).then(y=>({status:"fulfilled",value:y}),y=>({status:"rejected",reason:y}))))};var v=x;document.getElementsByTagName("link");const p=document.querySelector("meta[property=csp-nonce]"),g=p?.nonce||p?.getAttribute("nonce");u=x(l.map(z=>{if(z=hK(z),z in fs)return;fs[z]=!0;const b=z.endsWith(".css"),y=b?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${z}"]${y}`))return;const H=document.createElement("link");if(H.rel=b?"stylesheet":uK,b||(H.as="script"),H.crossOrigin="",H.href=z,g&&H.setAttribute("nonce",g),document.head.appendChild(H),b)return new Promise((S,C)=>{H.addEventListener("load",S),H.addEventListener("error",()=>C(new Error(`Unable to preload CSS for ${z}`)))})}))}function f(p){const g=new Event("vite:preloadError",{cancelable:!0});if(g.payload=p,window.dispatchEvent(g),!g.defaultPrevented)throw p}return u.then(p=>{for(const g of p||[])g.status==="rejected"&&f(g.reason);return a().catch(f)})};function dK({frame:t}){const a=d.useRef(null),l=d.useRef(null),s=d.useRef(null),u=d.useRef(null),f=d.useRef(null),v=d.useRef(null),p=d.useRef(null),g=d.useRef(!1),x=d.useRef(t),z=d.useCallback(()=>{const H=l.current,S=u.current,C=s.current;!H||!S||!C||!g.current||H.render(S,C)},[]),b=d.useCallback(()=>{const H=f.current;H&&(u.current?.remove(H),H.geometry?.dispose(),H.material?.dispose(),f.current=null)},[]),y=d.useCallback(()=>{const H=u.current,S=x.current,C=p.current;if(!H||!C||!S?.buffer||!g.current)return;const w=Number(S.meta?.strideBytes)||16,L=Number(S.meta?.width)||0,A=Number(S.meta?.height)||0,V=L*A;if(!S.meta?.grid||!V||w<16){b();return}const N=new DataView(S.buffer),T=new Float32Array(V*3),R=new Float32Array(V*3),j=new Uint8Array(V),F=new Float32Array(V);for(let J=0;J0?1:0,F[J]=t1}const U=new C.BufferGeometry;U.setAttribute("position",new C.BufferAttribute(T,3)),U.setAttribute("color",new C.BufferAttribute(R,3));const O=[],q=.12,$=(J,k,I)=>{if(!j[J]||!j[k]||!j[I])return!1;const t1=Math.min(F[J],F[k],F[I]);return Math.max(F[J],F[k],F[I])-t1<=q};for(let J=0;J{x.current=t,y()},[t,y]),d.useEffect(()=>{const H=a.current;if(!H)return;let S=!1,C=null,w=null;async function L(){const[A,V]=await Promise.all([ms(()=>import("./three.module--MGUDD-H.js"),[]),ms(()=>import("./OrbitControls-BJ-UXxdt.js"),__vite__mapDeps([0,1]))]);if(S)return;const N=A,{OrbitControls:T}=V;p.current=N;const R=new N.Scene;R.background=new N.Color(657930);const j=new N.PerspectiveCamera(55,4/3,.01,20);j.position.set(0,.15,2.2);const F=new N.WebGLRenderer({antialias:!0,alpha:!1});F.setPixelRatio(Math.min(window.devicePixelRatio||1,1.5)),F.setSize(H.clientWidth||640,H.clientHeight||480,!1),H.appendChild(F.domElement);const U=new T(j,F.domElement);U.enableDamping=!1,U.target.set(0,0,-1.4),U.addEventListener("change",z),u.current=R,s.current=j,l.current=F,v.current=U,C=new ResizeObserver(([O])=>{const q=Math.max(1,O.contentRect.width),$=Math.max(1,O.contentRect.height);j.aspect=q/$,j.updateProjectionMatrix(),F.setSize(q,$,!1),z()}),C.observe(H),w=new IntersectionObserver(([O])=>{const q=!!O?.isIntersecting;g.current=q,q&&(y(),z())},{threshold:.01}),w.observe(H)}return L(),()=>{S=!0,w?.disconnect(),C?.disconnect(),v.current?.removeEventListener("change",z),v.current?.dispose(),b(),l.current?.dispose(),l.current?.domElement?.remove(),u.current=null,s.current=null,l.current=null,v.current=null,p.current=null}},[b,y,z]),r.jsx("div",{ref:a,className:"h-full w-full"})}const fK={enabled:!1,available:!1,busy:!1,captureCooldownUntil:0,lastError:null,hasPointCloud:!1,hasColorImage:!1};function mK(t){return{...fK,...t&&typeof t=="object"?t:{}}}function vs(t){return t?t instanceof ArrayBuffer?t:ArrayBuffer.isView(t)?t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength):null:null}function vK({cooldownText:t,enabled:a,busy:l,lastError:s}){return t?{label:t,className:"border-red-400 bg-red-600 text-red-50"}:!a||s?{label:"Off",className:"border-red-400 bg-red-700 text-red-50"}:l?{label:"...",className:"border-amber-200 bg-amber-500 text-amber-950"}:{label:"Ready",className:"border-emerald-300 bg-emerald-600 text-emerald-50"}}function Fu(){const t=R2(),a=u1(V=>mK(V.session?.kinect)),[l,s]=d.useState("3d"),[u,f]=d.useState(null),[v,p]=d.useState(null),[g,x]=d.useState(null),[z,b]=d.useState(()=>Date.now());d.useEffect(()=>{const V=setInterval(()=>b(Date.now()),1e3);return()=>clearInterval(V)},[]),d.useEffect(()=>{if(!t)return;const V=(T={},R)=>{const j=vs(R);!j||!T?.grid||(f({meta:T,buffer:j}),s("3d"),x(null))},N=(...T)=>{const R=T[1],j=vs(R);if(!j)return;const F=new Blob([j],{type:"image/jpeg"}),U=URL.createObjectURL(F);p(O=>(O&&URL.revokeObjectURL(O),U)),s("image"),x(null)};return t.on("kinect:pointCloudFrame",V),t.on("kinect:colorFrame",N),t.emit("kinect:requestCachedFrames",{},()=>{}),()=>{t.off("kinect:pointCloudFrame",V),t.off("kinect:colorFrame",N)}},[t]),d.useEffect(()=>()=>{v&&URL.revokeObjectURL(v)},[v]);const y=Math.max(0,Number(a.captureCooldownUntil||0)-z),H=!a.enabled||a.busy||y>0,S=y>0?`${Math.ceil(y/1e3)}s`:null,C=d.useMemo(()=>vK({cooldownText:S,enabled:a.enabled,busy:a.busy,lastError:a.lastError}),[S,a.busy,a.enabled,a.lastError]),w=g||a.lastError,L=d.useCallback(V=>{!t||H||(x(null),t.emit(V,{},(N={})=>{N.error&&x(N.error)}))},[H,t]),A=r.jsxs("div",{className:"flex flex-wrap items-center justify-end gap-0.5 text-[0.68rem] text-slate-400",children:[r.jsx("span",{className:`inline-flex min-w-[3.7rem] justify-center rounded border px-1 py-0.5 text-xs font-semibold ${C.className}`,children:C.label}),r.jsx("div",{className:"inline-flex overflow-hidden rounded border border-slate-700",children:["3d","image"].map(V=>r.jsx("button",{type:"button",className:`px-1 py-0.5 ${l===V?"bg-slate-600 text-white":"bg-transparent text-slate-400 hover:text-white"}`,onClick:()=>s(V),children:V==="3d"?"3D":"Image"},V))}),r.jsx("button",{type:"button",className:"button-dark px-1 py-0.25",disabled:H,onClick:()=>L("kinect:requestPointCloud"),children:"Request 3D"}),r.jsx("button",{type:"button",className:"button-dark px-1 py-0.25",disabled:H,onClick:()=>L("kinect:requestColorImage"),children:"Request Image"})]});return r.jsxs(j1,{title:"Kinect Viewer",actions:A,bodyClassName:"space-y-0.5 p-0.5 text-sm",children:[r.jsx("div",{className:"aspect-[4/3] w-full overflow-hidden rounded bg-black",children:l==="3d"&&u?.buffer?r.jsx(dK,{frame:u}):l==="3d"?r.jsx("div",{className:"flex h-full items-center justify-center text-center text-sm text-slate-400",children:"Request a 3D frame"}):v?r.jsx("img",{src:v,alt:"Kinect image",className:"h-full w-full object-contain"}):r.jsx("div",{className:"flex h-full items-center justify-center text-center text-sm text-slate-400",children:"Request an image"})}),w?r.jsx("p",{className:"m-0 break-words text-[0.7rem] text-red-300",children:String(w).toLowerCase()}):null]})}const pK={iceServers:[{urls:"stun:stun.l.google.com:19302"},{urls:"turn:your.turn.server:3478",username:"user",credential:"pass"}],bundlePolicy:"max-bundle",rtcpMuxPolicy:"require"};function gK(t){if(typeof btoa=="function")return btoa(t);if(typeof Buffer<"u")return Buffer.from(t).toString("base64");throw new Error("No base64 encoder available")}function xK(t){if(!t)return{};const a=`${t}:${t}`;return{Authorization:`Basic ${gK(a)}`}}class ps{constructor({url:a,token:l,video:s,onStatus:u,audioOnly:f=!1,receiveAudio:v=!0}){this.url=a,this.token=l,this.video=s,this.audioOnly=f,this.receiveAudio=v,this.pc=null,this.abortController=null,this.onStatus=u}notify(a,l){typeof this.onStatus=="function"&&this.onStatus(a,l)}configureVideoElement(){this.video&&(this.video.playsInline=!0,this.video.autoplay=!0,this.video.muted=!this.audioOnly,typeof this.video.disableRemotePlayback<"u"&&(this.video.disableRemotePlayback=!0),"latencyHint"in HTMLMediaElement.prototype&&(this.video.latencyHint="interactive"))}async start(){if(!this.url||!this.video)throw new Error("Media target missing");this.stop(),this.notify("connecting"),this.configureVideoElement(),this.abortController=new AbortController;const a=new RTCPeerConnection(pK);this.pc=a;const l=new MediaStream;a.ontrack=s=>{s.streams[0]?.getTracks().forEach(u=>l.addTrack(u)),this.video.srcObject=l,s.track?.kind==="video"&&"playoutDelayHint"in s.receiver&&(s.receiver.playoutDelayHint=0)},this.audioOnly?a.addTransceiver("audio",{direction:"recvonly"}):(a.addTransceiver("video",{direction:"recvonly"}),this.receiveAudio&&a.addTransceiver("audio",{direction:"recvonly"})),a.onconnectionstatechange=()=>{this.notify(a.connectionState)},a.oniceconnectionstatechange=()=>{const s=a.iceConnectionState;(s==="failed"||s==="disconnected")&&this.notify(s)};try{const s=await a.createOffer({offerToReceiveAudio:this.audioOnly?!0:this.receiveAudio,offerToReceiveVideo:!this.audioOnly});await a.setLocalDescription(s);const u=await fetch(this.url,{method:"POST",headers:{"Content-Type":"application/sdp",...xK(this.token)},body:s.sdp,signal:this.abortController.signal});if(!u.ok)throw new Error(`WHEP request failed: ${u.status}`);const f=await u.text();await a.setRemoteDescription({type:"answer",sdp:f}),a.getReceivers().forEach(v=>{"playoutDelayHint"in v&&(v.playoutDelayHint=0)}),await this.video.play().catch(()=>{}),this.notify("playing")}catch(s){throw this.notify("error",s.message),this.stop(),s}}stop(){this.abortController&&(this.abortController.abort(),this.abortController=null),this.pc&&(this.pc.getSenders().forEach(a=>a.track?.stop()),this.pc.getReceivers().forEach(a=>a.track?.stop()),this.pc.close(),this.pc=null),this.video&&(this.video.srcObject=null),this.notify("stopped")}}function zK(t){if(!t)return null;if(typeof t=="string"){const a=String(t).trim();return a?{type:"rover",id:a,key:a}:null}if(typeof t=="object"){if(t.type&&t.id){const a=String(t.id);let l=t.key;return l||(l=t.type==="room"?`room:${a}`:a),{type:t.type,id:a,key:l}}if(t.roverId){const a=String(t.roverId);return{type:"rover",id:a,key:t.key||a}}if(t.roomCameraId){const a=String(t.roomCameraId);return{type:"room",id:a,key:t.key||`room:${a}`}}}return null}function bK(t=[]){const a=new Set,l=[];return t.forEach(s=>{!s?.key||a.has(s.key)||(a.add(s.key),l.push(s))}),l.sort((s,u)=>s.key.localeCompare(u.key))}function Vc(t=[],a={}){const l=R2(),{enabled:s=!0,version:u=null}=a,[f,v]=d.useState({}),p=d.useMemo(()=>Array.isArray(t)?bK(t.map(zK).filter(Boolean)):[],[t]),g=d.useMemo(()=>{const H=p.map(S=>`${S.type}:${S.id}:${S.key}`).join("|");return u?`${H}|v:${u}`:H},[p,u]),x=d.useRef([]),[z,b]=d.useState(0);return d.useEffect(()=>{if(!l)return;const H=()=>b(S=>S+1);return l.on("connect",H),()=>{l.off("connect",H)}},[l]),d.useEffect(()=>{x.current=p},[p]),d.useEffect(()=>{if(!g||!s){v({});return}const H=x.current;let S=!1;function C(w){const L=w.type==="room"?{roomCameraId:w.id}:{roverId:w.id};l.emit("video:request",L,(A={})=>{S||(A?.error&&v3("video_request_failed",{type:w.type,sourceId:w.id,reason:A.error},{key:`${w.type}:${w.id}:${A.error}`,throttleMs:60*1e3}),v(V=>({...V,[w.key]:A})))})}return H.forEach(w=>{C(w)}),()=>{S=!0}},[l,g,s,z]),d.useMemo(()=>{if(!g||!s)return{};const H={};return p.forEach(S=>{f[S.key]&&(H[S.key]=f[S.key])}),H},[g,f,p])}function ku(t=[],a={}){const l=R2(),{enabled:s=!0,version:u=null}=a,[f,v]=d.useState({}),p=d.useRef(new Map),g=d.useMemo(()=>t.map(C=>typeof C=="string"?C:C.id).filter(Boolean),[t]),x=d.useMemo(()=>{const C=g.join("|");return u?`${C}|v:${u}`:C},[g,u]),z=d.useRef([]),[b,y]=d.useState(0),H=d.useRef(new Map),S=typeof window<"u"&&new URLSearchParams(window.location.search).has("debugSnapshots");return d.useEffect(()=>{if(!l)return;const C=()=>y(w=>w+1);return l.on("connect",C),()=>l.off("connect",C)},[l]),d.useEffect(()=>{z.current=g},[x,g]),d.useEffect(()=>{p.current.forEach(C=>URL.revokeObjectURL(C)),p.current.clear(),v({})},[x]),d.useEffect(()=>{if(!s){p.current.forEach(V=>URL.revokeObjectURL(V)),p.current.clear(),v({});return}if(!z.current.length||!l)return;let C=!1;const w=z.current,L=(V={},N)=>{if(C||!V.id||!N)return;const T=N.byteLength??N.length??0,R=Date.now(),j=H.current.get(V.id)||{count:0,totalBytes:0,lastLogAt:0},F={count:j.count+1,totalBytes:j.totalBytes+T,lastLogAt:j.lastLogAt};if(S&&(!F.lastLogAt||R-F.lastLogAt>=1e4)){const $=F.count?F.totalBytes/F.count:0;console.log("[roverSnapshot]",V.id,`frame=${T}B`,`avg=${Math.round($)}B`,`count=${F.count}`),F.lastLogAt=R}H.current.set(V.id,F);const U=new Blob([N],{type:"image/jpeg"}),O=URL.createObjectURL(U),q=p.current.get(V.id);q&&URL.revokeObjectURL(q),p.current.set(V.id,O),v($=>({...$,[V.id]:{status:"playing",ts:V.ts||Date.now(),error:null,objectUrl:O}}))},A=(V={})=>{C||!V.id||v(N=>({...N,[V.id]:{...N[V.id]||{},status:V.error?"error":N[V.id]?.status||"connecting",error:V.error||null,ts:V.ts||N[V.id]?.ts||null,objectUrl:N[V.id]?.objectUrl||null}}))};return l.on("roverSnapshot:frame",L),l.on("roverSnapshot:status",A),l.emit("roverSnapshot:subscribe",{ids:w},(V={})=>{V.error}),()=>{C=!0,l.emit("roverSnapshot:unsubscribe",{ids:w}),l.off("roverSnapshot:frame",L),l.off("roverSnapshot:status",A),p.current.forEach(V=>URL.revokeObjectURL(V)),p.current.clear()}},[l,x,s,b,S]),f}const gs=2e3,MK=3e3,yK=3e3,wK=40,CK=1e3,Ru={none:"",grayscale:"grayscale(1) contrast(1.08)",greenscale:"grayscale(1) sepia(1) hue-rotate(70deg) saturate(2.2) brightness(0.95) contrast(1.1)"};function SK(t){return Object.prototype.hasOwnProperty.call(Ru,t)?t:H0.colorFilter}function E8({roverId:t=null,sessionInfo:a=null,audioSessionInfo:l=null,videoMode:s=null,snapshotFeed:u=null,label:f,forceMute:v=!1,sensors:p}){const g=u1(b1=>b1.session?.assignment?.roverId??null),x=t??g,z=u1(b1=>b1.session?.mode||null),b=u1(b1=>x&&Array.isArray(b1.session?.roster)&&b1.session.roster.find(h2=>String(h2.id)===String(x))||null),y=!!b?.media?.audioPublishUrl,H=s?s==="whep":!0,S=y,C=d.useMemo(()=>x?[...H?[{type:"rover",id:x,key:x}]:[],...S?[{type:"rover",id:`${x}-audio`,key:`${x}-audio`}]:[]]:[],[x,H,S]),w=Vc(C,{enabled:!!(x&&(H||S)),version:z}),L=a??(x&&w[x]||null),A=l??(x&&y&&w[`${x}-audio`]||null),V=ku(x?[x]:[],{enabled:!!(x&&!L?.url),version:z}),N=u??(x&&V[x]||null),T=f||b?.name||(x?`Rover ${x}`:"Rover"),R=b6(x,Bp,jp),j=p?{mainBrushCurrentMa:p?.mainBrushCurrentMa??0,mainBrushOvercurrent:!!p?.wheelOvercurrents?.mainBrush}:R,F=d.useRef(null),U=d.useRef(null),O=d.useRef(null),q=d.useRef(null),$=d.useRef(null),e1=d.useRef(null),n1=d.useRef(null),J=d.useRef(null),[k,I]=d.useState("idle"),[t1,f1]=d.useState(null),[m1,E]=d.useState("idle"),[_,K]=d.useState(null),[r1,v1]=d.useState(0),[g1,V1]=d.useState(0),[S1,N1]=d.useState(!0),P1=!!A?.url,Y1=s==="snapshot"||!s&&!L?.url,{value:R1}=T1("audio",x2),{value:p2}=T1("video",H0),s1=SK(p2?.colorFilter),H1=Ru[s1],p1=H1?{filter:H1}:void 0,x1=Number.isFinite(R1?.masterVolume)?R1.masterVolume:x2.masterVolume,L1=Number.isFinite(R1?.roverVolume)?R1.roverVolume:x2.roverVolume,F1=typeof R1?.mainBrushDuckEnabled=="boolean"?R1.mainBrushDuckEnabled:typeof R1?.autoLevelEnabled=="boolean"?R1.autoLevelEnabled:x2.mainBrushDuckEnabled,h1=Number.isFinite(R1?.mainBrushDuckAmount)?Math.max(0,Math.min(1,R1.mainBrushDuckAmount)):x2.mainBrushDuckAmount,y1=Math.max(0,Math.min(1,x1*L1)),k1=!!((Number(j?.mainBrushCurrentMa)||0)>wK||j?.mainBrushOvercurrent),X1=F1&&k1?1-h1:1,C1=Math.max(0,Math.min(1,y1*X1)),g2=d.useMemo(()=>typeof window>"u"?!1:new URLSearchParams(window.location.search).has("debugAudio"),[]),t2=d.useRef({hasDedicatedAudio:!1,audioUrl:null,mainBrushDuckEnabled:!1,mainBrushDuckAmount:0,mainBrushActive:!1,baseRoverGain:0,effectiveRoverGain:0});d.useEffect(()=>{t2.current={hasDedicatedAudio:P1,audioUrl:A?.url||null,mainBrushDuckEnabled:F1,mainBrushDuckAmount:h1,mainBrushActive:k1,baseRoverGain:y1,effectiveRoverGain:C1}},[P1,A?.url,F1,h1,k1,y1,C1]);const e2=d.useCallback((b1,h2={})=>{if(!g2)return;const c2=U.current,U1=t2.current,Q1={event:b1,ts:Date.now(),roverLabel:T||null,hasDedicatedAudio:U1.hasDedicatedAudio,audioUrl:U1.audioUrl,mainBrushDuckEnabled:U1.mainBrushDuckEnabled,mainBrushDuckAmount:U1.mainBrushDuckAmount,mainBrushActive:U1.mainBrushActive,baseRoverGain:U1.baseRoverGain,effectiveRoverGain:U1.effectiveRoverGain,element:c2?{muted:c2.muted,volume:c2.volume,paused:c2.paused,ended:c2.ended,readyState:c2.readyState,networkState:c2.networkState}:null,...h2};try{console.log(`[AudioDebug] ${b1} ${JSON.stringify(Q1)}`)}catch{console.log("[AudioDebug]",b1,Q1)}},[g2,T]);d.useEffect(()=>{e2("settings/update")},[e2]);const o1=d.useCallback(()=>{clearTimeout(O.current),O.current=setTimeout(()=>v1(Date.now()),gs)},[]),P=d.useCallback(()=>{clearTimeout(q.current),q.current=setTimeout(()=>V1(Date.now()),gs)},[]),c1=d.useCallback(async()=>{const b1=F.current;if(b1)try{b1.muted=!0,await b1.play()}catch{}},[]),z1=d.useCallback((b1=0)=>{if(v||P1)return;clearTimeout(e1.current);const h2=()=>{clearTimeout(e1.current),e1.current=setTimeout(()=>{v||c2()},MK)},c2=async()=>{const U1=F.current;if(U1)try{await c1(),U1.muted=!1,await U1.play(),N1(!1)}catch{U1.muted=!0,N1(!0),h2()}};e1.current=setTimeout(c2,b1)},[c1,v,P1]);d.useEffect(()=>()=>{clearTimeout(O.current),clearTimeout(q.current),clearTimeout(e1.current),clearInterval($.current),n1.current&&(cancelAnimationFrame(n1.current),n1.current=null)},[]),d.useEffect(()=>{k==="playing"&&z1(0)},[k,z1]),d.useEffect(()=>{Y1&&(I("snapshot"),f1(null))},[Y1]),d.useEffect(()=>{if(Y1||!L?.url||!F.current)return;let b1=!0,h2;const c2=setTimeout(()=>N1(!0),0),U1=(Q1,G2)=>{b1&&(e2("video/status",{nextStatus:Q1,info:G2||null}),I(Q1),f1(G2||null),Q1==="playing"&&c1(),["error","failed","disconnected","closed"].includes(Q1)&&(v3("whep_player_error",{roverId:x,status:Q1,detail:G2||""},{key:`${x||"unknown"}:${Q1}:${G2||""}`,throttleMs:60*1e3}),o1()))};return h2=new ps({url:L.url,token:L.token,video:F.current,receiveAudio:!P1,onStatus:U1}),h2.start().catch(Q1=>{b1&&(I("error"),f1(Q1.message),v3("whep_player_error",{roverId:x,status:"start_failed",detail:Q1.message},{key:`${x||"unknown"}:start_failed:${Q1.message}`,throttleMs:60*1e3}),o1())}),()=>{b1=!1,clearTimeout(c2),h2?.stop()}},[Y1,L?.url,L?.token,r1,o1,c1,P1,e2,x]),d.useEffect(()=>{k==="stopped"&&L?.url&&o1()},[k,L?.url,o1]),d.useEffect(()=>{const b1=U.current;if(!b1||!A?.url){e2("route/no-audio-url"),J.current=null;return}const h2=Math.max(0,Math.min(1,C1)),c2=J.current==null?Math.max(0,Math.min(1,b1.volume)):J.current;if(n1.current&&(cancelAnimationFrame(n1.current),n1.current=null),h2>c2){const U1=performance.now(),Q1=c2,G2=h2-Q1,T4=f4=>{const y2=Math.min(1,(f4-U1)/CK),L4=Q1+G2*y2;b1.volume=L4,J.current=L4,y2<1?n1.current=requestAnimationFrame(T4):n1.current=null};n1.current=requestAnimationFrame(T4)}else b1.volume=h2,J.current=h2;e2("route/direct",{elementVolume:h2,duckEnabled:F1,mainBrushActive:k1,duckAmount:h1})},[A?.url,C1,F1,k1,h1,e2]),d.useEffect(()=>{if(!A?.url||!U.current)return;let b1=!0,h2;const c2=(U1,Q1)=>{b1&&(e2("audio/status",{nextStatus:U1,info:Q1||null}),E(U1),K(Q1||null),["error","failed"].includes(U1)&&P())};return h2=new ps({url:A.url,token:A.token,video:U.current,audioOnly:!0,onStatus:c2}),h2.start().catch(U1=>{b1&&(E("error"),K(U1.message),P())}),()=>{b1=!1,h2?.stop()}},[A?.url,A?.token,g1,P,e2]),d.useEffect(()=>{const b1=U.current;if(!A?.url||!b1){clearInterval($.current);return}if(!["connecting","connected","playing","paused"].includes(m1)){clearInterval($.current);return}const c2=async()=>{const U1=U.current;U1&&(U1.muted=!1,!(!U1.paused&&!U1.ended)&&(e2("retry/play-attempt"),U1.play().then(()=>{e2("retry/play-ok"),E(Q1=>["error","failed","disconnected","closed"].includes(Q1)?Q1:"playing"),K(null)}).catch(Q1=>{e2("retry/play-fail",{error:Q1?.message}),K(G2=>G2||Q1?.message||"autoplay blocked")})))};return c2(),$.current=setInterval(c2,yK),()=>clearInterval($.current)},[A?.url,m1,e2]),d.useEffect(()=>{const b1=U.current;if(!b1)return;const h2=()=>{e2("element/play"),E(y2=>y2==="error"?y2:"playing"),K(null)},c2=()=>{e2("element/pause"),E(y2=>["error","failed","disconnected","closed","stopped"].includes(y2)?y2:"paused"),K(y2=>y2||"paused")},U1=()=>{e2("element/ended"),E(y2=>y2==="error"?y2:"stopped"),K(y2=>y2||"ended")},Q1=()=>{const{error:y2}=b1,L4=y2?.message||"audio error";e2("element/error",{error:L4}),E("error"),K(L4)},G2=()=>e2("element/waiting"),T4=()=>e2("element/canplay"),f4=()=>e2("element/stalled");return b1.addEventListener("play",h2),b1.addEventListener("pause",c2),b1.addEventListener("ended",U1),b1.addEventListener("error",Q1),b1.addEventListener("waiting",G2),b1.addEventListener("canplay",T4),b1.addEventListener("stalled",f4),()=>{b1.removeEventListener("play",h2),b1.removeEventListener("pause",c2),b1.removeEventListener("ended",U1),b1.removeEventListener("error",Q1),b1.removeEventListener("waiting",G2),b1.removeEventListener("canplay",T4),b1.removeEventListener("stalled",f4)}},[A?.url,e2]);const r2=N?.error?`Error: ${N.error}`:N?.objectUrl?"snapshot":N?.status||"waiting",i2=Y1?r2:L?.url?k==="error"?`Error: ${t1||"unknown"}`:t1?`${k} (${t1})`:k:"waiting",M2=A?.error?`Error: ${A.error}`:A?.url?m1==="error"?`Error: ${_||"unknown"}`:_?`${m1} (${_})`:m1:"waiting",n4=!Y1&&!L?.error&&k!=="playing";return r.jsxs(r.Fragment,{children:[Y1?N?.objectUrl?r.jsx("img",{src:N.objectUrl,alt:T,className:"h-full w-full object-contain",style:p1,draggable:!1}):r.jsx("div",{className:"flex h-full w-full items-center justify-center text-sm text-slate-300",children:"Waiting for frame…"}):r.jsx("video",{ref:F,muted:v||S1||P1,playsInline:!0,autoPlay:!0,controls:!1,className:"h-full w-full object-contain",style:p1}),n4?r.jsx("div",{className:"pointer-events-none absolute inset-0 z-10 flex items-center justify-center bg-black/45",children:r.jsx("div",{className:"rounded border border-slate-500/70 bg-black/70 px-3 py-1 text-sm font-semibold text-slate-100",children:"Connecting to video...."})}):null,r.jsx("audio",{ref:U,autoPlay:!0,hidden:!0}),r.jsx("div",{className:"pointer-events-none absolute left-1 top-1 z-20 font-medium text-slate-100 text-[0.65rem]",children:r.jsxs("div",{className:"flex flex-col gap-0.5 leading-none",children:[r.jsxs("span",{children:["Status: ",i2]}),M2?r.jsxs("span",{children:["Audio: ",M2]}):null]})})]})}function HK(t){const a=u1(R=>R.session?.mode||null),l=u1(R=>R.session?.roster??[]),s=u1(R=>R.session?.users??[]),u=u1(R=>R.session?.turnQueues??{}),f=u1(R=>R.session?.socketId||null),v=u1(R=>R.session?.activeDrivers??{}),p=a==="turns",g=Z8(1e3,p),x=t&&u?.[t]||null,z=t&&v?.[t]||null,b=!!(f&&z===f),y=d.useMemo(()=>{const R=x?.queue||[];if(!R.length||!x?.current||R.length<=1)return null;const j=R.findIndex(F=>F===x.current);return j===-1?R[0]||null:R[(j+1)%R.length]||null},[x]),H=!!(f&&y===f),S=x?.deadline||null,C=S?S-g:null,w=l.length,L=d.useMemo(()=>{const R=new Set;return s.forEach(j=>{if(String(j?.role||"")==="spectator")return;const U=String(j?.roverId||"").trim(),O=String(j?.socketId||"").trim();!U||!O||R.add(O)}),R.size},[s]),A=p&&L>w,V=p&&H&&C!=null&&C<=5e3&&C>0;return p&&!b&&!V&&A?"snapshot":null}function AK(t){const a=t?.session?.socials;return Array.isArray(a)?a:[]}function VK(t,a){const l=String(a||"").trim().toLowerCase();return l&&AK(t).find(s=>String(s?.id||s?.label||"").trim().toLowerCase()===l)||null}function LK(t){if(typeof t!="string")return null;const a=t.trim();return a&&(/^#[0-9a-fA-F]{3,8}$/.test(a)||/^(rgb|rgba|hsl|hsla)\([^)]+\)$/.test(a))?a:null}function BK(t){if(typeof t!="string"||!t.trim())return xc;const a=SP[t.trim()];return typeof a=="function"?a:xc}function r7({id:t=null,label:a,url:l,icon:s,color:u,layout:f="stacked",className:v=""}){const p=u1(C=>t?VK(C,t):null),g=l||p?.url||null;if(!g)return null;const x=s||p?.icon||null,z=u||p?.color||null,b=BK(x),y=LK(z),H=a||p?.label||"Link",S=f==="inline";return r.jsx("a",{href:g,target:"_blank",rel:"noopener noreferrer","aria-label":H,onClick:()=>{d1("social_link_click",{id:t||"",label:H,layout:f}),t==="discord"&&d1("discord_click",{layout:f})},className:`grid h-full min-h-0 w-full place-items-center rounded-md bg-slate-700 px-0.5 ${S?"py-0.5":"pb-3"} text-center text-sm font-medium text-white transition hover:opacity-90 ${v}`,style:y?{backgroundColor:y}:void 0,children:S?r.jsxs("span",{className:"inline-flex max-w-full items-center justify-center gap-1 text-center leading-tight",children:[r.jsx(b,{className:"shrink-0",style:{fontSize:"1.1em"}}),r.jsx("span",{className:"break-words",children:H})]}):r.jsxs("span",{className:"flex h-full w-full max-w-full flex-col items-center justify-between text-center leading-tight",children:[r.jsx("span",{className:"flex min-h-0 flex-1 items-center justify-center",children:r.jsx(b,{className:"shrink-0",style:{fontSize:"clamp(1rem, 2.2vh + 1.2vw, 2rem)"}})}),r.jsx("span",{className:"w-full break-words leading-tight",children:H})]})})}function jK({roverId:t=null,mobileHud:a=!1}){const l=u1(s1=>s1.session?.assignment?.roverId??null),s=t??l,u=u1(s1=>s1.session?.mode||null),f=u1(s1=>s1.session?.roster??[]),v=u1(s1=>s1.session?.users??[]),p=u1(s1=>s1.session?.turnQueues??{}),g=u1(s1=>s1.session?.socketId||null),x=u1(s1=>s1.session?.activeDrivers??{}),z=q1(s1=>s1.state.lastControlIntentAt),[b,y]=d.useState(!1),[H,S]=d.useState(null),[C,w]=d.useState(!1),[L,A]=d.useState(0),V=d.useRef({initialized:!1,roverId:null,activeDriverId:null}),N=d.useRef(z||0),T=a?"text-[0.5rem]":"text-[0.7rem]",R=a?"px-0.5 py-0.25":"px-1 py-0.5",j=a?"text-3xl":"text-5xl",F=a?"text-xs":"text-sm",U=a?"text-[0.55rem]":"text-[0.75rem]",O=a?"px-4 py-3":"px-6 py-4",q=s?p?.[s]:null,$=s?x?.[s]:null,e1=!!(g&&$===g),n1=u==="turns",J=Z8(1e3,n1),k=d.useMemo(()=>{const s1=q?.queue||[];if(!s1.length||!q?.current||s1.length<=1)return null;const H1=s1.findIndex(p1=>p1===q.current);return H1===-1?s1[0]||null:s1[(H1+1)%s1.length]||null},[q]),I=!!(g&&k===g),t1=q?.deadline||null,f1=q?.idleDeadline||null,m1=t1?t1-J:null,E=f1?f1-J:null,_=f.length,K=d.useMemo(()=>{const s1=new Set;return v.forEach(H1=>{if(String(H1?.role||"")==="spectator")return;const x1=String(H1?.roverId||"").trim(),L1=String(H1?.socketId||"").trim();!x1||!L1||s1.add(L1)}),s1.size},[v]),r1=n1&&K>_,v1=n1&&I&&m1!=null&&m1<=5e3&&m1>0,g1=n1&&!e1,V1=g1&&!v1&&r1,S1=m1!=null&&Number.isFinite(m1)?Math.max(0,Math.ceil(m1/1e3)):null,N1=E!=null&&Number.isFinite(E)?Math.max(0,Math.ceil(E/1e3)):null,P1=d.useMemo(()=>!n1||!e1?null:S1!=null?`${S1}s left`:"Your turn",[n1,e1,S1]),Y1=d.useMemo(()=>!g1||!I||S1==null?null:`${S1} seconds until your turn.`,[g1,I,S1]),R1=e1&&typeof N1=="number",p2=C;return d.useEffect(()=>{if(u!=="turns"){y(!1),S(null),V.current={initialized:!1,roverId:null,activeDriverId:null};return}const s1=V.current,H1=$||null;if(!g||!s){y(!1),S(null),V.current={initialized:!1,roverId:null,activeDriverId:null};return}if(!s1.initialized||s1.roverId!==s){V.current={initialized:!0,roverId:s,activeDriverId:H1};return}!!s1.activeDriverId&&s1.activeDriverId!==g&&H1===g?(y(!0),S(Date.now())):H1!==g&&b&&(y(!1),S(null)),V.current={initialized:!0,roverId:s,activeDriverId:H1}},[$,u,s,g,b]),d.useEffect(()=>{!b||!H||z>H&&y(!1)},[z,b,H]),d.useEffect(()=>{const s1=Number(N.current)||0,H1=Number(z)||0;H1>s1&&g1&&A(Date.now()),N.current=H1},[z,g1]),d.useEffect(()=>{if(!g1||!L)return;w(!0);const s1=setTimeout(()=>w(!1),650);return()=>clearTimeout(s1)},[g1,L]),r.jsxs(r.Fragment,{children:[b?r.jsx("div",{className:"pointer-events-none absolute inset-0 z-30 flex items-center justify-center bg-black/55",children:r.jsxs("div",{className:`flex flex-col items-center gap-0.5 rounded border border-amber-300/80 bg-black/70 ${O}`,children:[r.jsx("div",{className:`font-semibold text-amber-200 ${j}`,children:"IT IS YOUR TURN!"}),r.jsx("div",{className:`text-amber-200/80 ${F}`,children:"Start driving!"}),R1?r.jsxs("div",{className:`text-red-100/90 ${U}`,children:["Idle skip in ",N1,"s"]}):null]})}):null,P1?r.jsx("div",{className:`pointer-events-none absolute bottom-1 left-1 rounded border ${p2?"border-red-300/90 bg-red-900/80 text-red-100":"border-amber-300/80 bg-black/75 text-amber-200"} ${R} ${T}`,children:P1}):null,g1?r.jsx("div",{className:"pointer-events-none absolute bottom-1 left-1 z-40",children:r.jsxs("div",{className:`w-fit rounded border ${C?"border-red-300/90 bg-red-900/80 text-red-100":"border-amber-300/80 bg-black/75 text-amber-200"} ${a?"px-2 py-1 text-[0.6rem]":"px-3 py-1.5 text-sm"}`,children:[r.jsx("div",{className:C?"text-[0.82rem] font-semibold text-red-50":"text-[0.82rem] font-semibold text-white",children:"Not your turn to drive!"}),Y1?r.jsx("div",{className:C?"text-red-100/95":"text-amber-100",children:Y1}):null,V1?r.jsx("div",{className:C?"text-red-100/90":"text-amber-200/85",children:"Video switched to preview mode to save bandwidth."}):null,r.jsx("div",{className:"pointer-events-auto mt-0.5",children:r.jsx(r7,{id:"discord",label:"Join our Discord while you wait!",layout:"inline"})})]})}):null]})}const NK=H2.memo(jK);function Eu(){const{value:t,save:a}=T1("page",{hudMapDesktop:!1});return[!!t?.hudMapDesktop,u=>{a({hudMapDesktop:!!u})}]}function xs({variant:t="default",label:a,roverColor:l=null,driverLabel:s=null,mobileHud:u=!1,labelScale:f=1}){const v=u?"px-0.25 py-0.25":"px-0.5 py-0.5",p=u?"text-[0.55rem]":"text-[0.8rem]",g="bottom-0.5",x={transform:`translateX(-50%) scale(${f})`,transformOrigin:"center bottom"};return t==="spectator"?r.jsx("div",{className:`absolute ${g} left-1/2`,style:x,children:r.jsxs("div",{className:`flex items-center gap-0.5 bg-black/80 text-slate-100 ${v} ${p}`,children:[r.jsx(V4,{name:a,color:l}),s?r.jsxs("span",{className:"text-slate-300",children:["• ",s]}):null]})}):r.jsx("div",{className:`absolute ${g} left-1/2`,style:x,children:r.jsx("div",{className:`flex gap-0.5 bg-black/80 text-slate-100 ${v} ${p}`,children:r.jsx(V4,{name:a,color:l})})})}function FK({sensors:t,telemetry:a=null,mobileHud:l=!1}){const s=a?.voltageMv??t?.voltageMv??null,u=a?.currentMa??t?.currentMa??null,f=a?.batteryChargeMah??t?.batteryChargeMah??null,v=a?.oiModeLabel??t?.oiMode?.label??"Unknown",p=a?.homeBase??!!t?.chargingSources?.homeBase,g=a?.chargingStateLabel??t?.chargingState?.label??"",x=l?"px-0.25 py-0.25":"px-1 py-0.5",z=l?"left-0.5 top-1/2":"left-1 top-1/2",b=l?"text-[0.45rem]":"text-[0.65rem]",y=[["Voltage",s!=null?`${(s/1e3).toFixed(2)} V`:"--"],["Current",u!=null?`${u} mA`:"--"],["Charge",f!=null?`${f}`:"--"],["OI",v||"--"]],H=!!(g&&g.toLowerCase()!=="not charging"),S=v.toLowerCase(),C=S==="full"?"bg-emerald-500/80 text-emerald-50":S==="safe"?"bg-amber-400/80 text-amber-950":S==="passive"?"bg-slate-700/80 text-slate-100":"bg-slate-700/60 text-slate-200",w=p?"bg-emerald-500/80 text-emerald-50":"bg-slate-700/70 text-slate-200",L=H?"bg-emerald-500/80 text-emerald-50":p?"bg-amber-400/80 text-amber-950":"bg-slate-700/70 text-slate-200";return r.jsx("div",{className:`absolute ${z} flex -translate-y-1/2 flex-col gap-0.5 bg-black/70 text-slate-100 ${b} ${x}`,children:r.jsxs("div",{className:"space-y-0.5 leading-tight",children:[r.jsxs("div",{className:"flex flex-col gap-0.5 text-[0.75rem] font-semibold uppercase tracking-wide",children:[r.jsx("span",{className:`rounded px-1.5 py-0.5 ${w}`,children:p?"Docked":"Undocked"}),r.jsx("span",{className:`rounded px-1.5 py-0.5 ${L}`,children:H?"Charging":"Not charging"}),r.jsxs("span",{className:`rounded px-1.5 py-0.5 ${C}`,children:["OI: ",v]})]}),y.map(([A,V])=>r.jsxs("span",{className:"flex items-center justify-between gap-0.5",children:[r.jsx("span",{className:"text-slate-400",children:A}),r.jsx("span",{className:"font-semibold text-white",children:V})]},A))]})})}function i7(t){return Math.max(0,Math.min(1,t))}function Tu(t){return(t-90)*Math.PI/180}function j8(t,a,l,s){const u=Tu(s);return{x:t+l*Math.cos(u),y:a+l*Math.sin(u)}}function kK(t,a,l,s,u){let f=s,v=u;v<=f&&(v+=360);const p=j8(t,a,l,f),g=j8(t,a,l,v);return["M",p.x,p.y,"A",l,l,0,0,1,g.x,g.y].join(" ")}function ia(t,a){if(a)return"#ef4444";const l=Math.abs(t);return l>900?"#f59e0b":l>300?"#22c55e":"#64748b"}function RK(t,a){if(t==null||t<=0)return"hsl(200 60% 18%)";const s=i7(t/(a||1));return`hsl(${(200+Math.pow(s,.45)*360)%360} 100% 60%)`}function EK(t,a){if(a)return"#ef4444";const l=i7(t==null?0:t/4095),s=[47,55,69],u=[245,158,11],[f,v,p]=s.map((g,x)=>Math.round(g+(u[x]-g)*l));return`rgb(${f}, ${v}, ${p})`}function TK({count:t,totalSpan:a,gap:l,startAngle:s}){const f=(a-l*(t-1))/t,v=[];let p=s;for(let g=0;gkK(a,l,z,f,v),[a,l,v,z,f]);return r.jsxs(r.Fragment,{children:[r.jsx("path",{d:y,stroke:p,strokeWidth:b,strokeLinecap:"round",fill:"none",opacity:x}),g?r.jsx("path",{d:y,stroke:"#ef4444",strokeWidth:b,strokeLinecap:"round",fill:"none",className:"animate-pulse",opacity:1}):null]})}),qK=H2.memo(function({cx:a,cy:l,rBase:s,rTip:u,startDeg:f,endDeg:v,color:p,value:g,max:x}){const z=(f+v)/2,b=i7(g!=null?g/(x||1):0),y=Math.pow(b,.35),H=s-(s-u)*y,S=Math.max(u,Math.min(H,s)),C=d.useMemo(()=>{const w=j8(a,l,u,z),L=j8(a,l,S,f),A=j8(a,l,S,v);return`M ${w.x} ${w.y} L ${L.x} ${L.y} L ${A.x} ${A.y} Z`},[S,a,l,v,z,u,f]);return r.jsx("path",{d:C,fill:p,opacity:1,stroke:"none"})}),zs=H2.memo(function({cx:a,cy:l,current:s,drop:u,overcurrent:f,label:v}){const p=Math.abs(s),g=i7(p/1200),x=ia(s,f),z=56,b=14,y=9,H=3,S=z*g,C=v==="L"?-1:1,w=C*(-y/2-H/2),L=C*(b/2+H/2),A=b+y+H+2,V=z+4;return r.jsxs("g",{transform:`translate(${a},${l})`,children:[r.jsx("rect",{x:-A/2,y:-V/2,width:A,height:V,rx:"4",fill:"none",stroke:"#64748b",strokeWidth:"1"}),r.jsx("rect",{x:w-b/2,y:-z/2,width:b,height:z,fill:"#0f172a",stroke:"#0f172a",strokeWidth:"1",rx:"2"}),r.jsx("rect",{x:w-b/2,y:z/2-S,width:b,height:S,fill:x,className:f?"animate-pulse":""}),r.jsx("rect",{x:L-y/2,y:-z/2,width:y,height:z,fill:u?"#ef4444":"#475569",className:u?"animate-pulse":"",rx:"2"}),r.jsx("text",{x:0,y:z/2+10,textAnchor:"middle",className:"fill-slate-200 text-[0.7rem]",children:v})]})}),_K=H2.memo(function({cx:a,cy:l,current:s,overcurrent:u}){let f=Math.abs(s);f<10&&(f=0);const v=ia(s*3,u),p=43,g=f>0?.65:null;return r.jsxs("g",{style:{transformOrigin:`${a}px ${l}px`,animation:g?`spin ${g}s linear infinite`:"none",animationDirection:g?"reverse":"normal"},children:[r.jsx("circle",{cx:a,cy:l,r:10,fill:"#64748b",stroke:"#64748b",strokeWidth:"1"}),[0,120,240].map(z=>{const b=Tu(z),y=a+p*Math.cos(b),H=l+p*Math.sin(b);return r.jsx("line",{x1:a,y1:l,x2:y,y2:H,stroke:v,strokeWidth:"4",strokeLinecap:"round"},z)}),u?r.jsx("circle",{cx:a,cy:l,r:p+8,stroke:"#ef4444",strokeWidth:"3",fill:"none",className:"animate-pulse"}):null]})}),DK=H2.memo(function({cx:a,cy:l,current:s,overcurrent:u,variant:f}){const v=Math.abs(s),p=ia(s,u),g=1,x=96,z=12,b=`main-brush-pattern-a-${f}`,y=`main-brush-pattern-b-${f}`,H=v>0?.6:null,S=s>=0?1:-1;return r.jsxs("g",{children:[r.jsx("defs",{children:[b,y].map((C,w)=>r.jsxs("pattern",{id:C,patternUnits:"userSpaceOnUse",width:"6",height:"6",children:[r.jsx("rect",{width:"6",height:"6",fill:p,opacity:g}),r.jsx("path",{d:"M0 6 L6 0",stroke:"#0f172a",strokeWidth:"1"}),H?r.jsx("animateTransform",{attributeName:"patternTransform",type:"translate",from:"0 0",to:`0 ${S*(w===0?6:-6)}`,dur:`${H}s`,repeatCount:"indefinite"}):null]},C))}),r.jsx("rect",{x:a-x/2,y:l-14,width:x,height:z,rx:"3",fill:`url(#${b})`,stroke:"#64748b",strokeWidth:"1"}),r.jsx("rect",{x:a-x/2,y:l+4,width:x,height:z,rx:"3",fill:`url(#${y})`,stroke:"#64748b",strokeWidth:"1"}),r.jsx("circle",{cx:a-x/4,cy:l-8,r:3.5,fill:"#fbbf24"}),r.jsx("circle",{cx:a+x/4,cy:l+8,r:3.5,fill:"#fbbf24"}),u?r.jsx("rect",{x:a-x/2-4,y:l-16,width:x+8,height:z*2+16,rx:"6",stroke:"#ef4444",strokeWidth:"3",fill:"none",className:"animate-pulse"}):null]})}),OK=["L","FL","CL","CR","FR","R"];function UK(t,a){const l=t/2,s=t*.05,u=l,f=l+s,v=l*.8,p=v-4,g=v+4,x=v-14,z=v-6,b=v*.65,y=TK({count:6,totalSpan:140,gap:6,startAngle:-70});return{size:t,variant:a,centerX:u,centerY:f,innerCircle:v,lightRingInner:p,lightRingOuter:g,cliffRingInner:x,cliffRingOuter:z,wheelLineOffset:b,lightSegments:y.map((H,S)=>({label:OK[S],start:H.start,end:H.end})),cliffSegments:[{label:"Cliff L",start:-60,end:-46,valueKey:"cliffLeftSignal",activeKey:"cliffLeft"},{label:"Cliff FL",start:-32,end:-16,valueKey:"cliffFrontLeftSignal",activeKey:"cliffFrontLeft"},{label:"Cliff FR",start:16,end:32,valueKey:"cliffFrontRightSignal",activeKey:"cliffFrontRight"},{label:"Cliff R",start:46,end:60,valueKey:"cliffRightSignal",activeKey:"cliffRight"}]}}function ZK({sensors:t={},mapTelemetry:a=null,variant:l="full",size:s,overlay:u=!1}){const f=s||(l==="mini"?190:260),v=d.useMemo(()=>UK(f,l),[f,l]),p=a??Ic({sensors:t}),g=p.wheelLeftCurrentMa??0,x=p.wheelRightCurrentMa??0,z=p.sideBrushCurrentMa??0,b=p.mainBrushCurrentMa??0,y=6,H=p.bumpLeft?y:0,S=p.bumpRight?y:0,C=[p.lightBumpLeftSignal,p.lightBumpFrontLeftSignal,p.lightBumpCenterLeftSignal,p.lightBumpCenterRightSignal,p.lightBumpFrontRightSignal,p.lightBumpRightSignal],w=C.filter(A=>A!=null),L=w.length?Math.max(...w,1200):1200;return r.jsx("div",{className:`${u?"relative":"relative p-1"}`,style:u?{width:`${f}px`,height:`${f}px`}:{height:"100%",width:"100%",aspectRatio:"1 / 1"},children:r.jsxs("svg",{width:"100%",height:"100%",viewBox:`0 0 ${f} ${f}`,preserveAspectRatio:"xMidYMid meet",className:"mx-auto block",children:[r.jsx("circle",{cx:v.centerX,cy:v.centerY,r:v.innerCircle,fill:"#0f172a",stroke:"#334155",strokeWidth:"2"}),r.jsx(zs,{cx:v.centerX-v.wheelLineOffset,cy:v.centerY,current:g,drop:p.wheelDropLeft,overcurrent:p.leftWheelOvercurrent,label:"L"}),r.jsx(zs,{cx:v.centerX+v.wheelLineOffset,cy:v.centerY,current:x,drop:p.wheelDropRight,overcurrent:p.rightWheelOvercurrent,label:"R"}),r.jsx(_K,{cx:v.centerX+v.innerCircle*.65,cy:v.centerY-v.innerCircle*.55,current:z,overcurrent:p.sideBrushOvercurrent}),r.jsx(DK,{cx:v.centerX,cy:v.centerY,current:b,overcurrent:p.mainBrushOvercurrent,variant:l}),v.lightSegments.map((A,V)=>{const N=C[V],T=RK(N,L),R=v.lightRingOuter+4,j=R+28;return r.jsx(qK,{cx:v.centerX,cy:v.centerY,rBase:j,rTip:R,startDeg:A.start,endDeg:A.end,color:T,value:N,max:L},A.label)}),v.cliffSegments.map(A=>r.jsx(ac,{cx:v.centerX,cy:v.centerY,rInner:v.cliffRingInner,rOuter:v.cliffRingOuter,startDeg:A.start,endDeg:A.end,color:EK(p[A.valueKey],p[A.activeKey]),opacity:1,pulse:!!p[A.activeKey]},A.label)),r.jsx(ac,{cx:v.centerX,cy:v.centerY,rInner:v.lightRingInner-H,rOuter:v.lightRingOuter-H,startDeg:-70,endDeg:-6,color:p.bumpLeft?"#ef4444":"#475569",opacity:1,pulse:!!p.bumpLeft}),r.jsx(ac,{cx:v.centerX,cy:v.centerY,rInner:v.lightRingInner-S,rOuter:v.lightRingOuter-S,startDeg:6,endDeg:70,color:p.bumpRight?"#ef4444":"#475569",opacity:1,pulse:!!p.bumpRight})]})})}const qu=H2.memo(ZK);function bs({sensors:t,mapTelemetry:a=null,show:l=!0,mapPosition:s="top-center",layoutFormat:u="desktop",mobileHud:f=!1}){if(!l)return null;const v=u==="mobile-portrait",p="240px",g=v?.3:f?.33:.7,z={width:p,height:p,opacity:f?.6:.7,transform:s==="top-center"?`translateX(-50%) scale(${g})`:`scale(${g})`,transformOrigin:s==="bottom-left"?"bottom left":s==="top-center"?"top center":"top right",...s==="bottom-left"?{left:"0.25rem",bottom:"0.25rem"}:s==="top-center"?{left:"50%",top:"0.25rem"}:{right:"0.25rem",top:"0.25rem"}};return r.jsx("div",{className:"pointer-events-none absolute rounded",style:z,children:r.jsx(qu,{sensors:t,mapTelemetry:a,size:240,overlay:!0})})}function $K({roverId:t=null,sensors:a,label:l,roverColor:s=null,layoutFormat:u="desktop",variant:f="default",driverLabel:v=null,showTopDown:p=void 0,mobileHud:g=!1,mapPosition:x=null,labelScale:z=1}){const b=u1(O=>O.session?.assignment?.roverId??null),y=t??b,H=Z4(y,Ic,To),S=Z4(y,Np,Fp),C=u1(O=>{if(!y)return{label:null,roverColor:null};const $=(O.session?.roster||[]).find(e1=>String(e1.id)===String(y));return{label:$?.name||null,roverColor:$?.color||null}}),w=u1(O=>{if(!y||f!=="spectator")return null;const q=O.session?.activeDrivers?.[y]||null,e1=(O.session?.users||[]).find(n1=>String(n1.socketId||"")===String(q||""));return e1?.nickname||e1?.name||null}),L=a?null:H,A=a??null,V=l??C.label??null,N=s??C.roverColor??null,T=v??w,R=g,[j]=Eu(),F=typeof p=="boolean"?p:f==="spectator"||R?!0:j,U=x||(f==="spectator"?"top-center":R?"top-right":"top-center");return f==="none"?null:f==="spectator"?r.jsxs(r.Fragment,{children:[r.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[r.jsx(FK,{sensors:A,telemetry:a?null:S,mobileHud:R}),r.jsx(xs,{variant:"spectator",label:V,roverColor:N,driverLabel:T,mobileHud:R,labelScale:z})]}),r.jsx(bs,{sensors:A,mapTelemetry:L,show:F,mapPosition:U,layoutFormat:u,mobileHud:R})]}):r.jsxs("div",{className:"pointer-events-none absolute inset-0 flex items-center justify-center",children:[r.jsx(xs,{variant:"default",label:V,roverColor:N,mobileHud:R,labelScale:z}),r.jsx(bs,{sensors:A,mapTelemetry:L,show:F&&f!=="spectator",mapPosition:U,layoutFormat:u,mobileHud:R})]})}const _u=H2.memo($K);function IK({mobileHud:t=!1}){const{visible:a,statusLabel:l,statusTone:s,active:u,charging:f}=A0({manageLifecycle:!0}),[v,p]=d.useState(""),g=d.useRef(null),x=d.useRef(u);if(d.useEffect(()=>{const b=x.current;u&&!b?p("Dock assist mode enabled"):!u&&b&&f&&p("Docking successful! Thank you!"),x.current=u},[u,f]),d.useEffect(()=>{if(v)return g.current&&clearTimeout(g.current),g.current=setTimeout(()=>{p(""),g.current=null},2500),()=>{g.current&&(clearTimeout(g.current),g.current=null)}},[v]),!a)return null;const z=s==="good"?"border-emerald-200/90 bg-emerald-900/90 text-emerald-50":s==="warn"?"border-amber-200/90 bg-amber-900/90 text-amber-50":"border-cyan-200/90 bg-cyan-900/90 text-cyan-50";return r.jsx("div",{className:"pointer-events-none absolute inset-0",children:v?r.jsx("div",{className:"absolute inset-0 flex items-center justify-center",children:r.jsx("div",{className:`rounded-xl border border-indigo-200/95 bg-black/95 px-4 py-2 text-center font-semibold text-indigo-50 shadow-2xl ${t?"text-lg":"text-2xl"}`,children:v})}):r.jsx("div",{className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-lg border px-2 py-1 font-semibold shadow-lg ${z} ${t?"text-[0.65rem]":"text-xs"}`,children:l})})}const GK=H2.memo(IK),Ms=5e3,PK=700;function Du({roverId:t=null,description:a,variant:l="default",mobileHud:s=!1,displayKey:u="",controlIntentAt:f}){const v=u1(A=>A.session?.assignment?.roverId??null),p=t??v,g=u1(A=>p&&(A.session?.roster||[]).find(T=>String(T.id)===String(p))?.description||null),x=a??g,z=typeof f=="number"?f:0,b=u||`${p||""}::${x||""}`,[y,H]=d.useState(!1),[S,C]=d.useState(!1),w=d.useRef(null),L=d.useRef(null);return d.useEffect(()=>()=>{clearTimeout(w.current),clearTimeout(L.current)},[]),d.useEffect(()=>{if(l!=="default"||!x){H(!1),C(!1),clearTimeout(w.current),clearTimeout(L.current);return}clearTimeout(w.current),clearTimeout(L.current),H(!0),C(!1)},[x,b,l]),d.useEffect(()=>{l!=="default"||!x||!y||S||(Number(z)||0)<=0||w.current||L.current||(w.current=setTimeout(()=>{C(!0),w.current=null},Ms),L.current=setTimeout(()=>{H(!1),L.current=null},Ms+PK))},[z,x,S,y,l]),x?l==="spectator"?r.jsx("div",{className:"pointer-events-none absolute inset-x-0 top-1 z-50 flex justify-center",children:r.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:x})}):l!=="default"||!y?null:r.jsx("div",{className:"pointer-events-none absolute inset-0 z-50 flex items-center justify-center",children:r.jsxs("div",{className:`surface max-w-[94%] border border-slate-400 bg-neutral-900 px-2 py-1 text-center font-semibold text-slate-100 shadow-xl transition-opacity duration-700 ${S?"opacity-0":"opacity-100"} ${s?"text-[1rem] leading-tight":"text-[1.5rem] leading-tight"}`,children:[r.jsx("p",{children:"Just so you know, this rover"}),r.jsx("p",{children:x}),r.jsx("p",{className:`${s?"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 YK={leftWheel:"Left wheel",rightWheel:"Right wheel",mainBrush:"Main brush",sideBrush:"Side brush",limiter:"Overcurrent limit"};function KK({roverId:t=null,sensors:a,overcurrentLimiter:l=null,compact:s=!1}){const u=u1(j=>j.session?.assignment?.roverId??null),f=t??u,v=Z4(f,qo,_o),p=au(f),g=a?.wheelOvercurrents??v,x=l??p??null,z=d.useMemo(()=>g==null?[]:Object.entries(g).filter(([,j])=>!!j).map(([j])=>j),[g]),b=x?.caps||null,y=d.useMemo(()=>{if(!b)return null;const j=Number.isFinite(b?.drive?.cap)?b.drive.cap:1,F=Number.isFinite(b?.aux?.cap)?b.aux.cap:1;return Math.max(0,Math.min(1,1-Math.min(j,F)))},[b]),H=!!x?.isActive,S=d.useMemo(()=>z.length?z:H?["limiter"]:[],[z,H]),C=y??(z.length?1:0);if(!S?.length)return null;const w=S.map(j=>YK[j]||j),L=s?"w-[12rem] h-[3.5rem]":"w-[20rem] h-[7rem]",A=s?"px-2 py-1":"px-4 py-2",V=s?"text-lg":"text-4xl",N=s?"text-xs":"text-xl",T=Math.max(0,Math.min(1,C)),R=`${Math.round(T*100)}%`;return r.jsx("div",{className:`pointer-events-none absolute flex items-center justify-center bg-red-900/50 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 ${L}`,children:r.jsxs("div",{className:"relative h-full w-full",children:[r.jsx("div",{className:"absolute inset-0 overflow-hidden",children:r.jsx("div",{className:"h-full bg-red-700/60",style:{width:R}})}),r.jsxs("div",{className:`relative z-10 flex h-full w-full flex-col items-center justify-center text-center font-semibold text-white animate-pulse ${V} ${A}`,children:[r.jsx("div",{children:"OVERCURRENT"}),r.jsx("div",{className:`mt-0 font-medium text-white ${N}`,children:w.join(", ")})]})]})})}const Ou=H2.memo(KK),T8=10;function I8({batteryState:t=null,charge:a=null,config:l=null}){const s=t?.percentDisplay!=null&&Number.isFinite(t.percentDisplay)?Math.round(t.percentDisplay):null,u=t?.warnActive??null,f=t?.urgentActive??null,v=l?.Full??null,p=l?.Warn??null,g=l?.Urgent??null,x=a??t?.charge??null;let z=s;if(z==null&&(z=QK({charge:x,full:v,warn:p,urgent:g})),z==null)return{available:!1};const b=Math.max(0,Math.min(1,z/100)),y=u??(p!=null&&x!=null&&x<=p),H=f??(g!=null&&x!=null&&x<=g);return{available:!0,percent:b,percentDisplay:z,warnActive:y,urgentActive:H,warnDisplayPercent:T8}}function QK({charge:t,full:a,warn:l,urgent:s}){if(t!=null&&a!=null&&l!=null&&s!=null&&a>l&&l>s){const u=T8/100,f=1-u;if(t<=s)return 0;if(t<=l){const p=(t-s)/(l-s);return Math.round(Math.max(0,Math.min(1,p))*T8)}if(t>=a)return 100;const v=(t-l)/(a-l);return Math.round((u+Math.max(0,Math.min(1,v))*f)*100)}return null}function XK({roverId:t=null,sensors:a,batteryConfig:l,compact:s=!1}){const u=u1(S=>S.session?.assignment?.roverId??null),f=t??u,v=Z4(f,l7,n7),p=u1(S=>f?(S.session?.roster||[]).find(L=>String(L.id)===String(f))?.battery??null:null),g=a?{batteryChargeMah:a?.batteryChargeMah??null,batteryCapacityMah:a?.batteryCapacityMah??null}:v,x=l??p,z=I8({charge:g?.batteryChargeMah??null,config:x});if(!z?.available||!z.warnActive&&!z.urgentActive)return null;const b=z.urgentActive?"BATTERY VERY LOW, DOCK THE ROVER AND CHARGE IMMEDIATELY!!":"Battery low! please dock and charge the rover soon.",y=s?"p-2 top-6":"p-4 top-10",H=s?"text-sm":"text-2xl";return r.jsx("div",{className:`pointer-events-none absolute flex items-center justify-center bg-amber-900/60 left-1/2 -translate-x-1/2 ${y}`,children:r.jsx("div",{className:`text-center font-semibold text-white animate-pulse ${H}`,children:r.jsx("div",{children:b})})})}const Uu=H2.memo(XK);function JK({roverId:t=null,sensors:a}){const l=u1(b=>b.session?.assignment?.roverId??null),u=Z4(t??l,Vp,Lp),f=a?[a?.lightBumpLeftSignal,a?.lightBumpFrontLeftSignal,a?.lightBumpCenterLeftSignal,a?.lightBumpCenterRightSignal,a?.lightBumpFrontRightSignal,a?.lightBumpRightSignal]:u,v=f.filter(b=>b!=null).reduce((b,y)=>Math.max(b,y),1200),p=b=>Math.pow(Math.max(0,Math.min(1,(b??0)/v)),.35),g=b=>b==null||b<=0?"hsl(200 60% 18%)":`hsl(${(200+p(b)*360)%360} 100% 60%)`,x=6,z=12;return r.jsx("div",{className:"flex w-full items-center justify-center gap-0.5",children:f.map((b,y)=>{const H=p(b),S=yp.session?.assignment?.roverId??null),s=t??l,u=Z4(s,l7,n7),f=u1(p=>s?(p.session?.roster||[]).find(z=>String(z.id)===String(s))?.battery??null:null),v=I8({charge:u?.batteryChargeMah??null,config:f});return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx(WK,{roverId:s}),r.jsx("div",{className:"space-y-0.5 text-sm",children:r.jsx(s7,{visual:v,compact:a})})]})}function nQ(){if(typeof navigator>"u")return!1;const t=navigator.userAgent||"",a=navigator.vendor||"";return/safari/i.test(t)&&/apple/i.test(a)&&!/crios|fxios|edgios|opr|chrome|android/i.test(t)}function lQ({compact:t=!1}){const a=u1(O=>O.session?.role||null),l=u1(O=>O.session?.assignment?.roverId||null),s=u1(O=>O.session?.roster||[]),{sendMessage:u,onInputFocus:f,onInputBlur:v,blurChat:p,registerInputRef:g,setTypingActive:x}=ca(),{value:z}=T1("tts",{engine:"chromegtts",voice:"tpf",pitch:50,googlePitch:1,googleSpeed:1}),[b,y]=d.useState(""),[H,S]=d.useState(!1),C=a!=="spectator",w=a==="spectator",A=!!d.useMemo(()=>s.find(O=>String(O.id)===String(l))||null,[l,s])?.audio?.ttsEnabled,V=d.useMemo(()=>{if(!A)return null;const O=z?.engine==="espeak"?"espeak":z?.engine==="flite"?"flite":"chromegtts";if(O==="espeak"){let $=Number.isFinite(z?.pitch)?Math.round(z.pitch):void 0;return typeof $=="number"&&($=Math.max(0,Math.min(99,$))),{speak:!0,engine:O,pitch:$}}const q=typeof z?.voice=="string"?z.voice:void 0;if(O==="chromegtts"){const $=Number.isFinite(z?.googlePitch)?z.googlePitch:1,e1=Number.isFinite(z?.googleSpeed)?z.googleSpeed:1;return{speak:!0,engine:O,voice:q,pitch:$,speed:e1}}return{speak:!0,engine:O,voice:q}},[z?.engine,z?.googlePitch,z?.googleSpeed,z?.pitch,z?.voice,A]),N=t?"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",j=`min-w-0 flex-1 bg-transparent ${d.useMemo(()=>nQ(),[])?"mobile-text-entry":t?"text-[0.55rem]":"text-[0.7rem]"} text-slate-100 placeholder:text-slate-400 focus:outline-none`,F=t?"mobile-touch-control rounded bg-cyan-500/80 px-0.35 py-0.2 text-[0.55rem] font-semibold text-black disabled:opacity-50":"mobile-touch-control rounded bg-cyan-500/80 px-0.5 py-0.25 text-[0.7rem] font-semibold text-black disabled:opacity-50";async function U(O){if(O.preventDefault(),!C)return;const q=b.trim();if(q){S(!0);try{await u(q,V),y(""),p(),x(!1)}catch($){alert($.message)}finally{S(!1)}}}return w?null:r.jsxs("form",{onSubmit:U,className:N,children:[r.jsx("input",{className:j,value:b,onChange:O=>{const q=O.target.value;y(q),x(!!q.trim())},onFocus:O=>{f(O),x(!!b.trim())},onBlur:O=>{v(O),x(!1)},onKeyDown:O=>{O.key==="Enter"&&!b.trim()&&(O.preventDefault(),p(),x(!1))},ref:O=>g(O,{target:"hud"}),placeholder:C?"Chat (tts)":"Spectator",disabled:!C}),r.jsx("button",{type:"submit",disabled:!C||H,className:F,children:"Speak"})]})}const rQ=d.memo(lQ);function sa({layoutFormat:t="desktop"}){const a=u1(f=>f.session?.assignment?.roverId??null),l=HK(a),s=q1(f=>f.state.lastControlIntentAt);if(!a)return r.jsx(j1,{hideHeader:!0,className:"shrink-0",children:r.jsxs("div",{className:"panel-muted content-center text-center text-sm text-slate-400 aspect-[4/3]",children:[r.jsx("p",{children:"You are not assigned to a rover."}),r.jsx("p",{className:"mt-0",children:r.jsx("a",{href:"/spectate",className:"text-blue-400 underline hover:text-blue-500",children:"Click here to visit the spectator page."})})]})});const u=t!=="desktop";return r.jsx(j1,{hideHeader:!0,className:"shrink-0",children:r.jsxs("div",{className:"flex flex-col gap-0.5",children:[r.jsxs("div",{className:"relative w-full overflow-hidden bg-black aspect-[4/3]",children:[r.jsx(E8,{roverId:a,videoMode:l}),r.jsx(NK,{mobileHud:u}),r.jsx(Du,{variant:"default",mobileHud:u,controlIntentAt:s}),r.jsx(_u,{layoutFormat:t,variant:"default",mobileHud:u,labelScale:1}),r.jsx(GK,{mobileHud:u}),r.jsx(rQ,{compact:u}),r.jsx(Ou,{compact:u}),r.jsx(Uu,{compact:u})]}),r.jsx(aQ,{mobileHud:u})]})})}const iQ=Object.freeze([{id:"white",label:"White",hex:"#ffffff",action:"white"},{id:"red",label:"Red",hex:"#ff0000"},{id:"green",label:"Green",hex:"#00ff00"},{id:"cyan",label:"Cyan",hex:"#00c7be"},{id:"blue",label:"Blue",hex:"#0000ff"},{id:"purple",label:"Purple",hex:"#bf5af2"}]);function Lc({label:t,tone:a="muted"}){const l=a==="success"?"bg-emerald-900 text-emerald-100":a==="warn"?"bg-amber-900 text-amber-100":"bg-slate-800 text-slate-200";return r.jsx("span",{className:`rounded px-1 py-0.5 text-xs font-semibold leading-none ${l}`,children:t})}function Zu(...t){return t.filter(Boolean).join(" ")}function sQ(t,{unavailable:a,isOn:l,supportsColor:s}){if(a||!l)return;const u=s?t.colorHex:null;if(u)return{backgroundColor:u,borderColor:"rgba(255,255,255,0.38)"}}function oQ({entity:t,swatch:a,disabled:l,onSetColor:s,onSetWhite:u}){const f=v=>{if(v.stopPropagation(),!l){if(a.action==="white"){u(t.id).catch(()=>{});return}s(t.id,a.hex).catch(()=>{})}};return r.jsx("button",{type:"button",onClick:f,onKeyDown:v=>{v.stopPropagation()},disabled:l,title:`${a.label} ${t.name||t.id}`,"aria-label":`Set ${t.name||t.id} to ${a.label}`,className:Zu("h-5 w-6 shrink-0 rounded-sm border border-white/80 transition-transform disabled:cursor-not-allowed disabled:opacity-40",!l&&"hover:scale-110 hover:border-white"),style:{backgroundColor:a.hex}})}function uQ({entity:t,connected:a,controlsLocked:l,onToggle:s,onSetColor:u,onSetWhite:f}){const v=t.state==="unavailable"||!t.available,p=t.state==="on",g=t.type==="light"&&t.supportsColor,x=v?"warn":p?"success":"muted",z=v?"Unavailable":p?"On":"Off",b=l||!a||v,y=b||!g,H=sQ(t,{unavailable:v,isOn:p,supportsColor:g}),S=v?"border-slate-800 bg-slate-950 text-slate-500":l?"border-amber-700/60 bg-amber-950/70 text-amber-100":p?"border-emerald-700/70 bg-emerald-900 text-white":"border-neutral-700 bg-neutral-950 text-slate-300",C=()=>{b||s(t.id)},w=L=>{b||L.key!=="Enter"&&L.key!==" "||(L.preventDefault(),C())};return r.jsxs("div",{role:"button",tabIndex:b?-1:0,onClick:C,onKeyDown:w,"aria-disabled":b,className:Zu("flex min-w-[9.5rem] flex-col gap-0.5 rounded border px-0.5 py-0.5 transition-colors",b?"cursor-not-allowed opacity-70":"cursor-pointer hover:border-white/60",S),style:H,title:`${p?"Turn off":"Turn on"} ${t.name||t.id}`,children:[r.jsxs("div",{className:"-mx-0.5 -mt-0.5 grid min-h-5 grid-cols-[minmax(0,1fr)_auto] items-center gap-0.5 rounded-t bg-black/45 px-0.5 py-0.5 text-left text-white",children:[r.jsx("span",{className:"min-w-0 truncate text-[0.78rem] font-semibold leading-none",children:t.name||t.id}),r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx(Lc,{label:z,tone:x}),a?null:r.jsx("span",{className:"text-[0.65rem] font-semibold text-amber-200",children:"Offline"})]})]}),g?r.jsx("div",{className:"flex flex-wrap justify-center gap-0.5",children:iQ.map(L=>r.jsx(oQ,{entity:t,swatch:L,disabled:y,onSetColor:u,onSetWhite:f},L.id))}):null]})}function $u(){const t=q1(H=>H.state.keymap),a=u1(H=>H.session?.homeAssistant||null),{homeAssistantToggle:l,homeAssistantSetLightColor:s,homeAssistantSetLightWhite:u}=I2(),f=d.useMemo(()=>a?.entities||[],[a?.entities]),v=a?.lightPolicy||null,p=!!(v?.locked||v?.lockedOn),g=v?.lockState||(v?.lockedOn?"on":null),x=_2(t?.homeAssistantOn?.[0]),z=_2(t?.homeAssistantOff?.[0]);if(!a?.enabled)return r.jsx(j1,{title:"Room Controls",bodyClassName:"space-y-0.5 text-sm text-slate-400",children:r.jsx("p",{className:"text-slate-500",children:"Not configured on the server."})});if(f.length===0)return r.jsx(j1,{title:"Room Controls",bodyClassName:"space-y-0.5 text-sm text-slate-400",children:r.jsx("p",{className:"text-slate-500",children:"No lights or switches configured."})});const b=!!a?.connected,y=r.jsxs(r.Fragment,{children:[r.jsxs("div",{className:"flex items-center gap-0.5 text-[0.68rem] text-slate-400",children:[r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx("span",{children:"On"}),x?r.jsx(ys,{label:x}):null]}),r.jsxs("span",{className:"flex items-center gap-0.5",children:[r.jsx("span",{children:"Off"}),z?r.jsx(ys,{label:z}):null]})]}),p?r.jsx(Lc,{label:g==="off"?"Locked Off":"Locked On",tone:"warn"}):null,r.jsx(Lc,{label:b?"Connected":"Offline",tone:b?"success":"warn"})]});return r.jsxs(j1,{title:"Room Controls",actions:y,bodyClassName:"space-y-0.5 text-base",children:[p?r.jsx("p",{className:"rounded border border-amber-600/60 bg-amber-900/40 px-1 py-0.5 text-xs text-amber-100",children:g==="off"?"Lights are locked off. Room controls are disabled.":"Lights are locked on. Room controls are disabled."}):null,r.jsx("div",{className:"grid grid-cols-1 gap-0.5 sm:grid-cols-2 lg:grid-cols-3",children:f.map(H=>r.jsx(uQ,{entity:H,connected:b,controlsLocked:p,onToggle:l,onSetColor:s,onSetWhite:u},H.id))})]})}function ys({label:t}){return t?r.jsx("span",{className:"rounded border border-slate-600 px-1 text-[0.65rem] text-slate-300",children:t}):null}function Iu(){const{login:t}=I2(),[a,l]=d.useState(""),[s,u]=d.useState(""),[f,v]=d.useState(!1);async function p(g){g.preventDefault(),v(!0);try{await t(a,s),l(""),u("")}catch(x){alert(x.message)}finally{v(!1)}}return r.jsx(j1,{title:"Admin login",bodyClassName:"space-y-0.5 text-base",children:r.jsxs("form",{className:"flex flex-col gap-0.5",onSubmit:p,children:[r.jsx("input",{className:"field-input",placeholder:"Username",value:a,onChange:g=>l(g.target.value)}),r.jsx("input",{className:"field-input",placeholder:"Password",type:"password",value:s,onChange:g=>u(g.target.value)}),r.jsx("button",{type:"submit",disabled:f,className:"button-dark w-full disabled:opacity-50",children:f?"Logging in…":"Login"})]})})}function ws(...t){return t.filter(Boolean).join(" ")}function hQ(t){const a=t?.batteryState?.percentDisplay;return a==null?"--":`${a}%`}function dQ(t){return t?.batteryState?t.batteryState.urgentActive?"text-red-400":t.batteryState.warnActive?"text-amber-300":"text-emerald-300":"text-slate-400"}function fQ({title:t,roster:a=[],emptyText:l="No roster data.",renderActions:s=null}){return r.jsxs("div",{className:"space-y-0.5 text-sm",children:[t&&r.jsx("p",{className:"text-sm text-slate-400",children:t}),a.length===0?r.jsx("p",{className:"text-sm text-slate-500",children:l}):r.jsx("ul",{className:"space-y-0.5 text-sm",children:a.map(u=>{const f=!!(u?.private?.enabled&&u?.private?.open),v=!!u?.locked;return r.jsxs("li",{className:ws("surface flex flex-wrap items-center justify-between gap-0.5",v?"bg-red-900/40":f?"bg-amber-700/35 border border-amber-200/30":null),children:[r.jsxs("div",{children:[r.jsx("p",{children:r.jsx(V4,{rover:u,fallback:u.id})}),r.jsxs("p",{className:"text-xs text-slate-500 flex flex-wrap items-center gap-0.5",children:[r.jsx("span",{children:u.locked?"locked":"free"}),u.lockReason&&r.jsx("span",{className:"rounded bg-black/30 px-1",children:u.lockReason}),r.jsxs("span",{className:ws("font-semibold",dQ(u)),children:["Battery ",hQ(u)]})]})]}),s?s(u):null]},u.id)})})]})}function mQ(t){const a=t?.runtime||{},l=t?.output||{},s=t?.errors||{};return a.inFlight?{label:"IN FLIGHT",detail:a.reason||"Generating commentary now",className:"border-amber-400/60 bg-amber-700/20 text-amber-200"}:a.outcome==="posted"?{label:"POSTED",detail:l.posted?`Last: ${l.posted}`:"Commentary posted",className:"border-emerald-400/60 bg-emerald-700/20 text-emerald-200"}:a.outcome==="skipped"?{label:"SKIPPED",detail:a.reason||"Model chose to skip",className:"border-slate-400/60 bg-slate-700/30 text-slate-200"}:a.outcome==="failed"?{label:"FAILED",detail:s.message||a.reason||"Tick failed",className:"border-red-400/60 bg-red-700/20 text-red-200"}:{label:a.running?"IDLE":"STOPPED",detail:a.reason||"Waiting for next tick",className:"border-sky-400/50 bg-sky-700/20 text-sky-200"}}function vQ(t,a){const l=Date.now(),u=(Array.isArray(t)?t:[]).map((f,v)=>{const p=String(f?.role||"").toLowerCase(),g=typeof f?.content=="string"?f.content:JSON.stringify(f?.content??null,null,2),x=p==="system"?"LLM System":p==="assistant"?"LLM Context":p==="user"?"LLM Input":"LLM Message";return{id:`llm-msg-${v}`,message:{ts:l+v,nickname:x,text:g,role:"spectator",bot:p==="system"}}});if(a!=null){const f=String(a);u.push({id:"llm-output",message:{ts:l+u.length+1,nickname:"LLM Output",text:f.trim()?f:"",role:"spectator",bot:!0}})}return u}function pQ({state:t,onClearHistory:a,clearingHistory:l}){const[s,u]=d.useState(null);if(!t)return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),r.jsx("div",{className:"surface text-xs text-slate-300",children:"No status received yet."})]});const f=t.runtime||{},v=t.counters||{},p=t.timings||{},g=t.input||{},x=t.output||{},z=t.errors||{},b=Array.isArray(t.history)?t.history:[],y=b.find(w=>w.runId===s)||(b.length?b[b.length-1]:null),H=mQ(t),S=vQ(g.modelMessages,x.raw),C=[{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:v.skipStreak??0},{label:"clear count",value:v.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:v.promptChars??0},{label:"active drivers",value:v.snapshotSummary?.activeDrivers??0},{label:"snapshot rovers",value:v.snapshotSummary?.rovers??0},{label:"snapshot chat",value:v.snapshotSummary?.chatMessages??0}];return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"LLM Commentary"}),r.jsx("div",{className:"flex gap-0.5 text-xs",children:r.jsx("button",{type:"button",onClick:a,disabled:!!l,className:"button-danger disabled:cursor-not-allowed disabled:opacity-60",children:l?"Clearing...":"Clear LLM History"})}),r.jsxs("div",{className:`surface border text-center ${H.className}`,children:[r.jsx("div",{className:"text-[1.1rem] font-bold tracking-wide",children:H.label}),r.jsx("div",{className:"text-xs text-slate-200",children:H.detail})]}),r.jsx("div",{className:"surface flex flex-wrap gap-0.5 text-xs",children:C.map(w=>r.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))}),z.message?r.jsxs("div",{className:"surface text-xs text-red-300 break-words",children:["Error: ",z.message]}):null,z.details?r.jsxs("details",{className:"surface text-xs text-red-200",children:[r.jsx("summary",{className:"cursor-pointer select-none text-red-300",children:"Failure details"}),r.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-red-200",children:JSON.stringify(z.details,null,2)})]}):null,x.generated?r.jsxs("div",{className:"surface text-xs text-slate-200 break-words",children:["Generated: ",x.generated]}):null,x.posted?r.jsxs("div",{className:"surface text-xs text-emerald-200 break-words",children:["Posted: ",x.posted]}):null,r.jsxs("div",{className:"grid gap-0.5 md:grid-cols-2",children:[r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"Live Input Conversation"}),r.jsx("div",{className:"surface max-h-72 space-y-0.5 overflow-y-auto",children:S.length?S.map(w=>r.jsx(F8,{message:w.message},w.id)):r.jsx("div",{className:"text-xs text-slate-300",children:"No model conversation captured yet."})})]}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"Output + Error"}),r.jsxs("div",{className:"surface space-y-0.5 text-xs text-slate-200",children:[r.jsxs("div",{children:["Raw output: ",x.raw?.trim()?x.raw:""]}),r.jsxs("div",{children:["Posted: ",x.posted||""]}),r.jsxs("div",{children:["Output at: ",x.modelOutputAt?new Date(x.modelOutputAt).toLocaleString():"n/a"]}),r.jsxs("div",{children:["Failed at: ",z.failedAt?new Date(z.failedAt).toLocaleString():"n/a"]})]})]})]}),r.jsxs("details",{className:"surface text-xs text-slate-200",children:[r.jsx("summary",{className:"cursor-pointer select-none text-slate-300",children:"Full Monitor Payload"}),r.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-slate-200",children:JSON.stringify(t,null,2)})]}),r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"Recent Runs"}),r.jsx("div",{className:"surface max-h-52 space-y-0.5 overflow-y-auto text-xs",children:b.length?b.slice().reverse().map(w=>r.jsxs("button",{type:"button",onClick:()=>u(w.runId),className:`w-full text-left surface ${y?.runId===w.runId?"border border-sky-400/50":""}`,children:[r.jsxs("span",{className:"text-slate-300",children:["#",w.runId]})," ",r.jsx("span",{className:"text-slate-200",children:w.outcome||w.phase||"--"})," ",r.jsx("span",{className:"text-slate-400",children:w.durationMs!=null?`${w.durationMs}ms`:"--"})," ",r.jsx("span",{className:"text-slate-500",children:w.reason||""})]},w.runId)):r.jsx("div",{className:"text-slate-300",children:"No runs recorded yet."})})]}),y?r.jsxs("details",{className:"surface text-xs text-slate-200",open:!0,children:[r.jsxs("summary",{className:"cursor-pointer select-none text-slate-300",children:["Run #",y.runId," details"]}),r.jsx("pre",{className:"mt-0.5 whitespace-pre-wrap break-words text-[0.72rem] text-slate-200",children:JSON.stringify(y,null,2)})]}):null]})}function gQ({state:t,onClearHistory:a,clearingHistory:l}){const[s,u]=d.useState(!1);if(!t)return r.jsxs("div",{className:"space-y-0.5",children:[r.jsx("div",{className:"panel-muted text-xs uppercase",children:"Overseer Control"}),r.jsx("div",{className:"surface text-xs text-slate-300",children:"No status received yet."})]});const f=t.runtime||{},v=t.config||{},p=t.output||{},g=t.timings||{},x=t.input||{},z=t.errors||{},b=()=>{const y=Array.isArray(x.modelMessages)?x.modelMessages:[];return y.length?y.map((H,S)=>{const C=String(H?.role||"unknown").toUpperCase(),w=String(H?.content||"");return`#${S+1} ${C} ${w}`}).join(` ---------------------------------------- diff --git a/server/public/index.html b/server/public/index.html index 508e40a4..cf11633e 100644 --- a/server/public/index.html +++ b/server/public/index.html @@ -78,7 +78,7 @@ Roomba Rover - + diff --git a/server/src/services/commandService/index.js b/server/src/services/commandService/index.js index ead20415..29767b81 100644 --- a/server/src/services/commandService/index.js +++ b/server/src/services/commandService/index.js @@ -76,6 +76,68 @@ function setDriveCooldown(roverId, durationMs) { driveCooldowns.set(roverId, Date.now() + durationMs); } +function getCommandMotionMagnitude(type, payload = {}) { + if (type === 'drive') { + const driveDirect = payload?.driveDirect || {}; + const left = Math.abs(Number(driveDirect.left) || 0); + const right = Math.abs(Number(driveDirect.right) || 0); + return Math.max(left, right); + } + + if (type === 'motors') { + const motorPwm = payload?.motorPwm || {}; + const main = Math.abs(Number(motorPwm.main) || 0); + const side = Math.abs(Number(motorPwm.side) || 0); + const vacuum = Math.abs(Number(motorPwm.vacuum) || 0); + return Math.max(main, side, vacuum); + } + + return 0; +} + +function shouldRecordTurnActivity(type, payload = {}) { + /* + The turn idle-skip timer is a user-intent timer, not a generic command timer. + Some commands are emitted by the browser as setup/cleanup work while the + driver is literally doing nothing. Counting those commands as activity lets + a totally idle client keep a turn forever, because recordActivity disarms + the idle skip for the rest of that turn. + */ + if (type === 'sensorStream') { + /* + Sensor streaming is enabled automatically when the UI has a rover + assignment and can also be resent after harmless React/session churn. + It is not proof that the driver touched a control. + */ + return false; + } + + if (type === 'drive' || type === 'motors') { + /* + Zero drive/motor packets are safety cleanup packets. The keyboard manager, + gamepad manager, blur handlers, and turn transitions can all send zeros + without human intent, so only non-zero motion should disarm idle skip. + */ + return getCommandMotionMagnitude(type, payload) > 0; + } + + if (type === 'horn') { + /* + Starting the horn is a deliberate action. Stopping it can be automatic + after a timeout or key release, so the stop packet should not be the event + that proves the driver is active. + */ + return payload?.horn?.action !== 'stop'; + } + + /* + Other accepted commands are left as activity because they are tied to an + explicit user control: servo moves, night vision toggles, raw OI commands, + songs, reboot/update admin actions, and similar commands. + */ + return true; +} + module.exports = { issueCommand, handleAck, @@ -154,11 +216,13 @@ io.on('connection', (socket) => { } const id = issueCommand(roverId, { type, ...payload }); logger.info('Queued command', socket.id, roverId, type); - try { - const { recordActivity } = require('../turnService'); - recordActivity(roverId, socket.id); - } catch (err) { - // best effort; ignore activity update errors + if (shouldRecordTurnActivity(type, payload)) { + try { + const { recordActivity } = require('../turnService'); + recordActivity(roverId, socket.id); + } catch (err) { + // Activity recording is best-effort because command delivery should not fail if turn bookkeeping has a transient issue. + } } reply({ id }); } catch (err) { diff --git a/webui/src/controls/ControlContext.jsx b/webui/src/controls/ControlContext.jsx index 51035fde..3a5e5eac 100644 --- a/webui/src/controls/ControlContext.jsx +++ b/webui/src/controls/ControlContext.jsx @@ -253,7 +253,7 @@ export function ControlSystemProvider({ children }) { if (pipeline.roverId) { pipeline.enableSensorStream(); } - }, [pipeline]); + }, [pipeline.roverId, pipeline.enableSensorStream]); const setMode = useCallback( (mode) => {