@xenon-device-management/xenon 1.22.2 → 1.22.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/package.json +1 -1
- package/lib/public/assets/{ApiKeyGate-Snh2iZH5.js → ApiKeyGate-mUVQGEc0.js} +1 -1
- package/lib/public/assets/{BugReportButton-DFLx1uf_.css → BugReportButton-CPBjfiv4.css} +1 -1
- package/lib/public/assets/{BugReportButton-Sk0KGufH.js → BugReportButton-DTEs8tGN.js} +1 -1
- package/lib/public/assets/DeviceMosaicView-BRoAd1Sj.js +7 -0
- package/lib/public/assets/{EmptyState-CQun3BJE.js → EmptyState-ErJtYI1I.js} +1 -1
- package/lib/public/assets/{FieldGroup-DmYZP2j7.js → FieldGroup-65VOAW_s.js} +1 -1
- package/lib/public/assets/{Modal-C5W8lMJ6.js → Modal-CumsTFc7.js} +1 -1
- package/lib/public/assets/{SegmentedControl-BIzlKyUd.js → SegmentedControl-Dq0r4nxn.js} +1 -1
- package/lib/public/assets/{SettingCard-DAFqQw7S.js → SettingCard-BlYmGnxD.js} +1 -1
- package/lib/public/assets/{Table-DRkkM4OR.js → Table-Dw77VPjI.js} +1 -1
- package/lib/public/assets/{activity-B6x69oOy.js → activity-W-IYNYOw.js} +1 -1
- package/lib/public/assets/{ai-settings-CSZQis7F.js → ai-settings-DBYtabv0.js} +1 -1
- package/lib/public/assets/{api-keys-4ddjSngL.js → api-keys-DTCC8uWq.js} +1 -1
- package/lib/public/assets/{apps-CePIfnu9.js → apps-BanJSL1m.js} +1 -1
- package/lib/public/assets/{arrow-left-CaOe18yC.js → arrow-left-DG02ll-2.js} +1 -1
- package/lib/public/assets/{arrow-right-FEQsqDvH.js → arrow-right-DjAmMmYl.js} +1 -1
- package/lib/public/assets/{arrow-up-right-Dnszb73S.js → arrow-up-right-Dk4zYVvC.js} +1 -1
- package/lib/public/assets/{auth-shell-Vq1rYIVD.js → auth-shell-DX60Cnp3.js} +2 -2
- package/lib/public/assets/{builds-page-FfsUegKZ.js → builds-page-DlEfR2IF.js} +1 -1
- package/lib/public/assets/{button-DrqhMLZ0.js → button-CLqhTbpf.js} +1 -1
- package/lib/public/assets/{calendar-BuRuUa7q.js → calendar-DbUhR1ky.js} +1 -1
- package/lib/public/assets/{check-DYccNk73.js → check-DBN5pEHK.js} +1 -1
- package/lib/public/assets/chevron-left-C_NNcuSy.js +6 -0
- package/lib/public/assets/{chevron-right-C6ny35i3.js → chevron-right-DSEJHO6A.js} +1 -1
- package/lib/public/assets/{circle-check-Cokzy9a2.js → circle-check-DCvFQDU8.js} +1 -1
- package/lib/public/assets/{circle-x-BhUzyxKR.js → circle-x-DozngDyk.js} +1 -1
- package/lib/public/assets/{clock-BCG0drfS.js → clock-rmbxO4wJ.js} +1 -1
- package/lib/public/assets/{copy-BKOm9hko.js → copy-BaeAL15w.js} +1 -1
- package/lib/public/assets/device-explorer-C4d2_w5A.css +1 -0
- package/lib/public/assets/device-explorer-D7Jz-zbV.js +245 -0
- package/lib/public/assets/{download-R2k7Nd4P.js → download-CA52fegs.js} +1 -1
- package/lib/public/assets/{forgot-password-CiZcr-gB.js → forgot-password-B9IbsWvo.js} +1 -1
- package/lib/public/assets/{funnel-SD4F5IdR.js → funnel-Ba_b7Wqz.js} +1 -1
- package/lib/public/assets/{index-C7S8Y7Fj.css → index-BYvkQIjW.css} +1 -1
- package/lib/public/assets/{index-BHDlQcd6.js → index-c8lodEdC.js} +2 -2
- package/lib/public/assets/{input-Ilib6feD.js → input-chJvT8xE.js} +1 -1
- package/lib/public/assets/keycodes-D_POkMkt.js +21 -0
- package/lib/public/assets/layers-DmlmDics.js +6 -0
- package/lib/public/assets/{lock-s9ZhGDFF.js → lock-DYppIRUo.js} +1 -1
- package/lib/public/assets/{login-EkaxK7K5.js → login-BU4PznoN.js} +1 -1
- package/lib/public/assets/{maintenance-settings-yYhZaU7n.js → maintenance-settings-BuAlGIXr.js} +1 -1
- package/lib/public/assets/{mouse-pointer-2-C6yy1DTx.js → mouse-pointer-2-Bf4XBYxV.js} +1 -1
- package/lib/public/assets/{network-B8fPwmW9.js → network-vHrQFUoR.js} +1 -1
- package/lib/public/assets/{overview-DrTe5eJi.js → overview-Bg07_C5h.js} +1 -1
- package/lib/public/assets/{page-header-DhD-Kua9.js → page-header-odsXTF6s.js} +1 -1
- package/lib/public/assets/{plus-B75ovH3O.js → plus-BxPFTMza.js} +1 -1
- package/lib/public/assets/{profile-page-C2p5rB3x.js → profile-page-B8xPVAnw.js} +1 -1
- package/lib/public/assets/{reset-password-tCemYrqV.js → reset-password-WDhJisGT.js} +1 -1
- package/lib/public/assets/{runbook-page-Dq3wdSII.js → runbook-page-CCc8c4KT.js} +1 -1
- package/lib/public/assets/{select-Cfv-njLE.js → select-2OHlz_YH.js} +1 -1
- package/lib/public/assets/selector-detail-page-Dmmuh77c.js +1 -0
- package/lib/public/assets/{selector-health-BP45B44s.js → selector-health-BpX8aLag.js} +1 -1
- package/lib/public/assets/{selector-health-page-D-8SdN_l.js → selector-health-page-CSkHlwY0.js} +1 -1
- package/lib/public/assets/{session-detail-page-Dm4tnoTT.js → session-detail-page-C8YHyGHB.js} +3 -8
- package/lib/public/assets/{settings-ChfaAd8F.js → settings-DabtQQ3v.js} +1 -1
- package/lib/public/assets/{status-pill-outline-CLa0C1Sg.js → status-pill-outline-Ch5V_U-d.js} +1 -1
- package/lib/public/assets/{tablet-0sIFwy2Z.js → tablet-RsMViU1S.js} +1 -1
- package/lib/public/assets/{teams-BFhWbK5i.js → teams-Dr0FkHHP.js} +1 -1
- package/lib/public/assets/{trash-2-BcQxmJP-.js → trash-2-CYQosy3T.js} +1 -1
- package/lib/public/assets/{upload-BucqEWub.js → upload-DRltjrDF.js} +1 -1
- package/lib/public/assets/{use-password-reset-mode-XoxXVCzm.js → use-password-reset-mode-DtUlGfEB.js} +1 -1
- package/lib/public/assets/{users-DyB6E3FF.js → users-Dm7GOgLZ.js} +1 -1
- package/lib/public/assets/{users-B7uveXL_.js → users-GL3VzMF-.js} +1 -1
- package/lib/public/assets/video-off-DvHtrcFg.js +6 -0
- package/lib/public/assets/{webhook-settings-qoHAETzC.js → webhook-settings-BKJqCNNZ.js} +1 -1
- package/lib/public/assets/{zap-CqGOjAjn.js → zap-Dg_oVDEp.js} +1 -1
- package/lib/public/index.html +2 -2
- package/package.json +1 -1
- package/lib/public/assets/DeviceMosaicView-O292tZkA.js +0 -2
- package/lib/public/assets/device-explorer-CCbOXiB6.css +0 -1
- package/lib/public/assets/device-explorer-CIjs3BXP.js +0 -265
- package/lib/public/assets/keycodes-bIEJfQzr.js +0 -1
- package/lib/public/assets/layers-CLuKN5Oy.js +0 -11
- package/lib/public/assets/selector-detail-page-8xf4CxH5.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{x as P,r,X as c,j as e,H as u,D as b,C as U,J as D}from"./index-
|
|
1
|
+
import{x as P,r,X as c,j as e,H as u,D as b,C as U,J as D}from"./index-c8lodEdC.js";/* empty css */import{F as S}from"./FieldGroup-65VOAW_s.js";import{P as H}from"./page-header-odsXTF6s.js";import{T as O}from"./trash-2-CYQosy3T.js";import{P as x}from"./plus-BxPFTMza.js";import{C as V}from"./circle-x-DozngDyk.js";import{C as B}from"./circle-check-DCvFQDU8.js";import{Z as I}from"./zap-Dg_oVDEp.js";import{A as J}from"./activity-W-IYNYOw.js";const C=[{id:"device_offline",label:"Device offline",icon:U,tone:"red"},{id:"device_new",label:"New device",icon:x,tone:"green"},{id:"session_failed",label:"Session failed",icon:V,tone:"amber"},{id:"selector_health_digest",label:"Selector health digest",icon:D,tone:"green"}],X=["udid","host","name","sessionId","failureReason","eventType","platform"],ae=()=>{const{toast:o}=P(),[g,T]=r.useState([]),[A,w]=r.useState(!0),[l,j]=r.useState(""),[d,k]=r.useState(["device_offline","session_failed"]),[h,f]=r.useState(!1),[v,N]=r.useState(!1),[n,_]=r.useState(!1),[y,m]=r.useState("");r.useEffect(()=>{p()},[]);const p=async()=>{w(!0);try{const s=await c.getWebhookConfigs();T(s||[])}catch(s){console.error("Failed to load webhook configs",s),o("Failed to load webhooks.","error")}finally{w(!1)}},z=async()=>{if(!l.trim()){o("Webhook URL is required.","error");return}if(d.length===0){o("Select at least one trigger event.","error");return}f(!0);try{await c.addWebhookConfig(l.trim(),d,"slack",y||void 0),j(""),m(""),_(!1),k(["device_offline","session_failed"]),await p(),o("Webhook saved.","success")}catch(s){console.error("Failed to add webhook",s),o(`Failed to add webhook: ${s.message||"unknown error"}`,"error")}finally{f(!1)}},E=async(s,t)=>{if(window.confirm(`Remove webhook for "${t}"?`))try{await c.deleteWebhookConfig(s),await p(),o("Webhook removed.","success")}catch(a){console.error("Failed to delete webhook",a),o(`Failed to delete: ${a.message||"unknown error"}`,"error")}},L=async()=>{if(l.trim()){N(!0);try{await c.testWebhook(l.trim(),"slack"),o("Test payload delivered.","success")}catch(s){o(`Test failed: ${s.message||"check the URL"}`,"error")}finally{N(!1)}}},$=s=>{k(t=>t.includes(s)?t.filter(a=>a!==s):[...t,s])},R=s=>{m(t=>t+`{{${s}}} `)};return e.jsxs("div",{className:"settings-container",children:[e.jsx(H,{icon:u,title:"Notifications",subtitle:"Configure Slack or generic webhooks to receive alerts for critical infrastructure events."}),e.jsxs("div",{className:"settings-content",children:[A?e.jsxs("div",{className:"settings-loading",style:{height:200},children:[e.jsx(b,{className:"animate-spin",size:28}),e.jsx("span",{children:"Loading webhooks…"})]}):g.length===0?e.jsxs("div",{className:"empty-state",children:[e.jsx("div",{className:"empty-state__icon",children:e.jsx(u,{size:28})}),e.jsx("h3",{className:"empty-state__title",children:"No webhooks configured"}),e.jsx("p",{className:"empty-state__copy",children:"Wire up a Slack incoming webhook or any HTTPS endpoint to receive alerts when devices go offline, new devices register, or sessions fail. Configure your first webhook below."})]}):e.jsx("div",{className:"webhook-list-grid",children:g.map(s=>{const t=(()=>{try{return JSON.parse(s.events)}catch{return[]}})();return e.jsxs("div",{className:"webhook-row-card",children:[e.jsxs("div",{className:"webhook-row-card__header",children:[e.jsx("span",{className:`pill-chip ${s.payloadTemplate?"pill-chip--admin":"pill-chip--scope"}`,children:s.payloadTemplate?"CUSTOM":"SLACK"}),e.jsx("span",{className:"webhook-row-card__url",title:s.url,children:s.url}),e.jsxs("button",{type:"button",className:"row-action row-action--danger",onClick:()=>E(s.id,s.url),"aria-label":`Remove webhook for ${s.url}`,children:[e.jsx(O,{size:13}),e.jsx("span",{children:"Remove"})]})]}),e.jsx("div",{className:"webhook-row-card__events",children:t.length===0?e.jsx("span",{className:"webhook-row-card__no-events",children:"No triggers"}):t.map(a=>{const i=C.find(F=>F.id===a),W=(i==null?void 0:i.icon)??u;return e.jsxs("span",{className:`event-pill event-pill--${(i==null?void 0:i.tone)||"gray"}`,children:[e.jsx(W,{size:11}),(i==null?void 0:i.label)||a]},a)})})]},s.id)})}),e.jsxs("div",{className:"add-webhook-card",children:[e.jsxs("div",{className:"add-webhook-card__header",children:[e.jsx(x,{size:14}),e.jsx("span",{children:"Add a new webhook"})]}),e.jsxs("div",{className:"add-webhook-card__body",children:[e.jsx(S,{label:"Webhook URL",description:"The endpoint we POST webhook events to.",htmlFor:"webhook-url",children:e.jsx("div",{className:"setting-input-wrapper",children:e.jsx("input",{id:"webhook-url",type:"url",placeholder:"https://hooks.slack.com/services/...",value:l,onChange:s=>j(s.target.value)})})}),e.jsx(S,{label:"Trigger events",children:e.jsx("div",{className:"event-toggle-grid",children:C.map(s=>{const t=d.includes(s.id),a=s.icon;return e.jsxs("button",{type:"button",role:"checkbox","aria-checked":t,className:`event-toggle event-toggle--${s.tone} ${t?"is-selected":""}`,onClick:()=>$(s.id),children:[e.jsx(a,{size:14,className:"event-toggle__lead"}),e.jsx("span",{children:s.label}),t&&e.jsx(B,{size:14,className:"event-toggle__check"})]},s.id)})})}),e.jsxs("div",{className:"template-section",children:[e.jsxs("button",{type:"button",className:"template-section__toggle",onClick:()=>_(!n),"aria-expanded":n,children:[e.jsx(I,{size:14,className:n?"tone-amber":"tone-dim"}),e.jsx("span",{children:"Use custom payload (optional)"}),e.jsx("span",{className:"template-section__indicator",children:n?"−":"+"})]}),n&&e.jsxs("div",{className:"template-editor",children:[e.jsx("p",{className:"template-editor__hint",children:"Define a JSON or text template. Click a variable below to insert it."}),e.jsx("div",{className:"template-editor__chips",children:X.map(s=>e.jsx("button",{type:"button",className:"template-editor__chip",onClick:()=>R(s),children:`{{${s}}}`},s))}),e.jsx("textarea",{className:"template-editor__textarea",placeholder:'Example: { "text": "Alert: Device {{udid}} is offline!" }',value:y,onChange:s=>m(s.target.value),rows:4})]})]})]}),e.jsxs("div",{className:"add-webhook-card__footer",children:[e.jsxs("button",{type:"button",className:"page-header-action page-header-action--ghost",onClick:L,disabled:!l.trim()||v,children:[v?e.jsx(b,{size:14,className:"animate-spin"}):e.jsx(J,{size:14}),e.jsx("span",{children:"Test payload"})]}),e.jsxs("button",{type:"button",className:"page-header-action",onClick:z,disabled:h||!l.trim(),children:[h?e.jsx(b,{size:14,className:"animate-spin"}):e.jsx(x,{size:14}),e.jsx("span",{children:h?"Saving…":"Save webhook"})]})]})]})]})]})};export{ae as WebhookSettings};
|
package/lib/public/index.html
CHANGED
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
Learn how to configure a non-root public URL by running `npm run build`.
|
|
37
37
|
-->
|
|
38
38
|
<title>Xenon</title>
|
|
39
|
-
<script type="module" crossorigin src="/xenon/assets/index-
|
|
40
|
-
<link rel="stylesheet" crossorigin href="/xenon/assets/index-
|
|
39
|
+
<script type="module" crossorigin src="/xenon/assets/index-c8lodEdC.js"></script>
|
|
40
|
+
<link rel="stylesheet" crossorigin href="/xenon/assets/index-BYvkQIjW.css">
|
|
41
41
|
</head>
|
|
42
42
|
|
|
43
43
|
<body>
|
package/package.json
CHANGED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as d,j as n,X as $,T as Ie,Y as De}from"./index-BHDlQcd6.js";import{p as ke}from"./labels-C21SA4JG.js";import{A as q,I as Me}from"./keycodes-bIEJfQzr.js";import{a as _e}from"./page-header-DhD-Kua9.js";function $e(e,t){return e!=="auto"?e:t<=1?"1":t===2?"2x1":t<=4?"2x2":"3x2"}const Oe={selected:new Set,layout:"2x2",tiles:[],groupId:null,compositeEnabled:!1,downloadableVideoCount:0,recordingPhase:"idle",recording:!1,startedAt:null,annotateMode:!1,shape:"RECT",color:"#ff3333",overlayAnnotations:{},errorBanner:null,banner:null};function Pe(e,t){var r;switch(t.type){case"SET_LAYOUT":return{...e,layout:t.layout};case"TOGGLE_SELECTED":{const o=new Set(e.selected);return o.has(t.udid)?o.delete(t.udid):o.add(t.udid),{...e,selected:o}}case"CLEAR_SELECTED":return{...e,selected:new Set};case"SET_TILES":return{...e,tiles:t.tiles};case"ADD_TILE":return e.tiles.some(o=>o.udid===t.tile.udid)?e:{...e,tiles:[...e.tiles,t.tile]};case"PATCH_TILE_DIMS":{let o=!1;const s=e.tiles.map(f=>f.udid!==t.udid||f.screenWidth&&f.screenHeight?f:(o=!0,{...f,screenWidth:t.screenWidth,screenHeight:t.screenHeight,aspect:t.aspect??f.aspect}));return o?{...e,tiles:s}:e}case"REMOVE_TILE":return e.recordingPhase!=="idle"?e:{...e,tiles:e.tiles.filter(o=>o.udid!==t.udid)};case"BIND_RECORDING_IDS":{const o=e.tiles.map(s=>({...s,recordingId:t.map[s.udid]??s.recordingId}));return{...e,tiles:o}}case"SET_RECORDING_PHASE":{const o=t.phase;return{...e,recordingPhase:o,recording:o==="recording"||o==="stopping"}}case"START_RECORDING":{const o=e.tiles.map(s=>({...s,recordingId:t.tileIds[s.udid]??s.recordingId}));return{...e,groupId:t.groupId,compositeEnabled:t.compositeEnabled===!0,downloadableVideoCount:0,recordingPhase:"recording",recording:!0,annotateMode:!0,startedAt:t.startedAt,overlayAnnotations:{},tiles:o}}case"REHYDRATE_RECORDING":{const o=e.tiles.map(s=>({...s,recordingId:t.tileIds[s.udid]??s.recordingId}));return{...e,groupId:t.groupId,compositeEnabled:t.compositeEnabled,downloadableVideoCount:0,recordingPhase:"recording",recording:!0,annotateMode:!1,startedAt:t.startedAt,overlayAnnotations:t.overlayAnnotations,tiles:o}}case"STOP_RECORDING":{const o=e.tiles.map(s=>({...s,recordingId:void 0}));return{...e,recording:!1,recordingPhase:"idle",annotateMode:!1,overlayAnnotations:{},downloadableVideoCount:t.downloadableVideoCount??e.downloadableVideoCount,compositeEnabled:t.compositeEnabled!==void 0?t.compositeEnabled:e.compositeEnabled,tiles:o}}case"SET_ANNOTATE_MODE":return{...e,annotateMode:t.enabled};case"SET_SHAPE":return{...e,shape:t.shape};case"SET_COLOR":return{...e,color:t.color};case"SET_OVERLAY_ANNOTATIONS":return{...e,overlayAnnotations:{...e.overlayAnnotations,[t.recordingId]:t.annotations}};case"CLEAR_OVERLAY_ANNOTATIONS":return{...e,overlayAnnotations:{}};case"SET_ERROR_BANNER":return{...e,errorBanner:t.message,banner:t.message?{tone:"error",message:t.message}:null};case"SET_BANNER":return{...e,banner:t.banner,errorBanner:((r=t.banner)==null?void 0:r.tone)==="error"?t.banner.message:null};default:return e}}const pe=d.createContext(null);function Le(){const e=d.useContext(pe);if(!e)throw new Error("useMosaic must be used inside <MosaicContext.Provider>");return e}function Be(){return d.useReducer(Pe,Oe)}function Ye(e){const t=Math.max(0,Math.floor(e/1e3)),r=Math.floor(t/3600),o=Math.floor(t%3600/60),s=t%60;return r>0?`${r}:${String(o).padStart(2,"0")}:${String(s).padStart(2,"0")}`:`${o}:${String(s).padStart(2,"0")}`}function Ue(e){switch(e){case"automation":return"In automation";case"manual_other":return"Manual control by another user";case"manual_self":return"In your mosaic";case"recording_other_group":return"Recording in another group";default:return e?"Busy":null}}const ie=[{id:"ios",label:"iOS",match:e=>e==="ios"},{id:"android",label:"Android",match:e=>e==="android"},{id:"tvos",label:"tvOS",match:e=>e==="tvos"},{id:"androidtv",label:"Android TV",match:e=>e==="androidtv"||e==="android-tv"},{id:"other",label:"Other",match:()=>!0}];function Fe(e){return ke(e)}function Xe({devices:e,inMosaic:t,onToggle:r}){const[o,s]=d.useState(""),[f,l]=d.useState({}),x=d.useMemo(()=>{const a=o.trim().toLowerCase();return a?e.filter(g=>g.udid.toLowerCase().includes(a)||(g.name??"").toLowerCase().includes(a)||(g.platform??"").toLowerCase().includes(a)):e},[e,o]),w=d.useMemo(()=>{const a=ie.map(u=>({id:u.id,label:u.label,rows:[]})),g=u=>a.find((y,E)=>ie[E].match(u))??a[a.length-1];for(const u of x)g((u.platform??"").toLowerCase()).rows.push(u);return a.filter(u=>u.rows.length>0)},[x]);return e.length===0?n.jsx("div",{className:"text-xs text-[var(--text-dim)] p-3",children:"No devices online."}):n.jsxs("div",{className:"flex flex-col gap-2",children:[n.jsxs("div",{className:"relative",children:[n.jsx("span",{"aria-hidden":!0,className:"absolute left-2 top-1/2 -translate-y-1/2 text-[var(--text-dim)] text-xs",children:"⌕"}),n.jsx("input",{type:"text",value:o,placeholder:"Filter devices...",onChange:a=>s(a.target.value),className:"w-full pl-7 pr-2 py-1.5 text-xs rounded border border-[var(--border)] bg-transparent placeholder:text-[var(--text-dim)] focus:outline-none focus:border-[var(--color-info)]"})]}),w.map(a=>{const g=f[a.id];return n.jsxs("section",{className:"flex flex-col gap-1",children:[n.jsxs("button",{type:"button",onClick:()=>l(u=>({...u,[a.id]:!u[a.id]})),className:"flex items-center justify-between w-full text-[11px] text-[var(--text-dim)] hover:text-[rgb(var(--rgb-fg))] px-1 py-0.5",children:[n.jsxs("span",{className:"flex items-center gap-1.5",children:[n.jsx("span",{"aria-hidden":!0,className:`inline-block transition-transform ${g?"-rotate-90":"rotate-0"}`,children:"▾"}),a.label]}),n.jsx("span",{children:a.rows.length})]}),!g&&n.jsx("ul",{className:"flex flex-col gap-1 text-sm",children:a.rows.map(u=>{const y=u.busyReason==="manual_self",E=t.has(u.udid),p=!!u.busy&&!y&&!E||!!u.offline,b=u.offline?"Offline":Ue(u.busyReason),I=!p;return n.jsx("li",{children:n.jsxs("button",{type:"button",disabled:p,draggable:!p,onDragStart:D=>{D.dataTransfer.effectAllowed="copy",D.dataTransfer.setData("application/x-xenon-udid",u.udid),D.dataTransfer.setData("text/plain",u.udid)},onClick:()=>r(u.udid),className:`w-full flex items-center gap-2 px-2 py-1.5 rounded text-left border transition-colors ${p?"opacity-60 cursor-not-allowed border-transparent":E?"border-[rgb(var(--rgb-accent)/0.4)] bg-[rgb(var(--rgb-accent)/0.05)] hover:bg-[rgb(var(--rgb-accent)/0.1)]":"border-transparent hover:border-[var(--border)] hover:bg-[var(--surface-2)]"}`,title:p?`${b} — release first`:E?"Click to remove from mosaic (or drag to a cell)":"Click to add to mosaic (or drag to a cell)",children:[n.jsx("span",{"aria-hidden":!0,className:`inline-flex items-center justify-center w-4 h-4 text-xs ${E?"text-[var(--color-accent-soft)]":"text-[var(--text-dim)]"}`,children:E?"●":"○"}),n.jsx("span",{"aria-hidden":!0,className:`inline-block w-1.5 h-1.5 rounded-full ${u.offline?"bg-zinc-600":I?"bg-[var(--color-success)]":"bg-yellow-500"}`}),n.jsx("span",{className:"font-medium flex-1 truncate text-[13px]",children:u.name??u.udid}),u.platform&&n.jsx("span",{className:"text-[11px] px-1.5 py-0.5 rounded bg-[var(--surface-2)] text-[var(--text-dim)]",children:Fe(u.platform)})]})},u.udid)})})]},a.id)}),o&&w.length===0&&n.jsxs("div",{className:"text-xs text-[var(--text-dim)] px-1 py-2",children:['No devices match "',o,'".']}),n.jsxs("div",{className:"text-[10px] text-[var(--text-dim)] px-1 pt-2 flex items-center gap-3",children:[n.jsxs("span",{className:"inline-flex items-center gap-1",children:[n.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-[var(--color-success)] inline-block"})," available"]}),n.jsxs("span",{className:"inline-flex items-center gap-1",children:[n.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-yellow-500 inline-block"})," in use"]}),n.jsxs("span",{className:"inline-flex items-center gap-1",children:[n.jsx("span",{className:"w-1.5 h-1.5 rounded-full bg-zinc-600 inline-block"})," offline"]})]})]})}const Ve=[{id:"1",label:"1",icon:n.jsx(We,{})},{id:"2x1",label:"2×1",icon:n.jsx(ze,{})},{id:"2x2",label:"2×2",icon:n.jsx(He,{})},{id:"3x2",label:"3×2",icon:n.jsx(Ke,{})},{id:"auto",label:"Auto",icon:n.jsx(Je,{})}];function Ge({value:e,onChange:t}){return n.jsx("div",{role:"tablist",className:"inline-flex border border-[var(--border)] rounded-md overflow-hidden text-xs bg-[rgb(var(--rgb-white)/0.02)]",children:Ve.map(r=>{const o=e===r.id;return n.jsxs("button",{role:"tab","aria-selected":o,onClick:()=>t(r.id),className:`flex items-center gap-1.5 px-2.5 py-1.5 border-r border-[var(--border)] last:border-r-0 transition-colors ${o?"bg-[var(--surface-2)] text-[rgb(var(--rgb-fg))]":"text-[var(--text-dim)] hover:bg-[var(--surface-2)] hover:text-[rgb(var(--rgb-fg))]"}`,title:`Layout: ${r.label}`,children:[n.jsx("span",{className:"w-3.5 h-3.5 inline-flex items-center justify-center",children:r.icon}),n.jsx("span",{children:r.label})]},r.id)})})}function U(e){return n.jsx("rect",{rx:1.2,ry:1.2,fill:"currentColor",...e})}function We(){return n.jsx("svg",{viewBox:"0 0 14 14",className:"w-3.5 h-3.5",children:U({x:2,y:2,width:10,height:10})})}function ze(){return n.jsxs("svg",{viewBox:"0 0 14 14",className:"w-3.5 h-3.5",children:[U({x:1.5,y:3,width:5,height:8}),U({x:7.5,y:3,width:5,height:8})]})}function He(){return n.jsxs("svg",{viewBox:"0 0 14 14",className:"w-3.5 h-3.5",children:[U({x:1.5,y:1.5,width:5,height:5}),U({x:7.5,y:1.5,width:5,height:5}),U({x:1.5,y:7.5,width:5,height:5}),U({x:7.5,y:7.5,width:5,height:5})]})}function Ke(){return n.jsxs("svg",{viewBox:"0 0 14 14",className:"w-3.5 h-3.5",children:[U({x:1,y:1.5,width:3.3,height:5}),U({x:5.35,y:1.5,width:3.3,height:5}),U({x:9.7,y:1.5,width:3.3,height:5}),U({x:1,y:7.5,width:3.3,height:5}),U({x:5.35,y:7.5,width:3.3,height:5}),U({x:9.7,y:7.5,width:3.3,height:5})]})}function Je(){return n.jsxs("svg",{viewBox:"0 0 14 14",className:"w-3.5 h-3.5",fill:"none",stroke:"currentColor",strokeWidth:"1.4",children:[n.jsx("rect",{x:"2",y:"2",width:"10",height:"10",rx:"1.5"}),n.jsx("circle",{cx:"7",cy:"7",r:"1.5",fill:"currentColor",stroke:"none"})]})}const qe=1600;function Ze(e,t){const r=qe/Math.max(e,t);return{w:Math.round(e*r),h:Math.round(t*r)}}function Qe(e,t,r,o=document){if(t<=0||r<=0)return null;const{w:s,h:f}=Ze(t,r),l=o.createElement("canvas");l.width=s,l.height=f;const x=l.getContext("2d");if(!x)return null;x.scale(s/t,f/r),ne(x,t,r,e);try{return l.toDataURL("image/png")}catch{return null}}function me(e,t,r){const o={left:0,top:0,width:e,height:t};if(!r||!(r>0)||e<=0||t<=0)return o;const s=e/t;if(Math.abs(s-r)<1e-6)return o;if(r>s){const l=e/r;return{left:0,top:(t-l)/2,width:e,height:l}}const f=t*r;return{left:(e-f)/2,top:0,width:f,height:t}}const et=(e,t)=>e===t||!!e&&!!t&&e.left===t.left&&e.top===t.top&&e.width===t.width&&e.height===t.height,tt=2,rt=2e3;function ae(e,t,r){if(e.length>=rt)return e;const o=e[e.length-1];return o&&Math.hypot(t-o[0],r-o[1])<tt?e:[...e,[t,r]]}function ce(e,t){const r=(e||"#ff3333").trim();if(/^#[0-9a-fA-F]{6}$/.test(r)){const o=parseInt(r.slice(1,3),16),s=parseInt(r.slice(3,5),16),f=parseInt(r.slice(5,7),16);return`rgba(${o},${s},${f},${t})`}return r}function ne(e,t,r,o){var u;const s=o.geometry,f=o.color||"#ff3333",l=Math.max(4,Math.round(Math.min(t,r)*.008));if(e.lineCap="round",e.lineJoin="round",o.shape==="CIRCLE"){const y=(s.x??0)*t,E=(s.y??0)*r,p=Math.max(2,(s.w??0)*t),b=Math.max(2,(s.h??0)*r);e.beginPath(),e.ellipse(y,E,p,b,0,0,Math.PI*2),e.fillStyle=ce(f,.22),e.fill(),e.lineWidth=l+2,e.strokeStyle="rgba(0,0,0,0.55)",e.stroke(),e.beginPath(),e.ellipse(y,E,p,b,0,0,Math.PI*2),e.lineWidth=l,e.strokeStyle=f,e.stroke();return}if(o.shape==="ARROW"){const y=(s.x??0)*t,E=(s.y??0)*r,p=y+(s.w??0)*t,b=E+(s.h??0)*r;e.lineWidth=l+2,e.strokeStyle="rgba(0,0,0,0.55)",e.beginPath(),e.moveTo(y,E),e.lineTo(p,b),e.stroke(),e.lineWidth=l,e.strokeStyle=f,e.beginPath(),e.moveTo(y,E),e.lineTo(p,b),e.stroke();const I=Math.atan2(b-E,p-y),D=Math.max(14,l*3);e.fillStyle=f,e.beginPath(),e.moveTo(p,b),e.lineTo(p-D*Math.cos(I-.4),b-D*Math.sin(I-.4)),e.lineTo(p-D*Math.cos(I+.4),b-D*Math.sin(I+.4)),e.closePath(),e.fill();return}if(o.shape==="TEXT"&&o.text){const y=Math.max(16,Math.round(Math.min(t,r)*.035));e.font=`bold ${y}px sans-serif`,e.lineWidth=3,e.strokeStyle="rgba(0,0,0,0.65)",e.strokeText(o.text,(s.x??0)*t,(s.y??0)*r),e.fillStyle=f,e.fillText(o.text,(s.x??0)*t,(s.y??0)*r);return}if(o.shape==="FREEHAND"&&(((u=s.points)==null?void 0:u.length)??0)>=2){const y=s.points,E=()=>{e.beginPath(),e.moveTo(y[0][0]*t,y[0][1]*r);for(let p=1;p<y.length;p++)e.lineTo(y[p][0]*t,y[p][1]*r)};e.lineWidth=l+2,e.strokeStyle="rgba(0,0,0,0.55)",E(),e.stroke(),e.lineWidth=l,e.strokeStyle=f,E(),e.stroke();return}const x=(s.x??0)*t,w=(s.y??0)*r,a=Math.max(2,(s.w??0)*t),g=Math.max(2,(s.h??0)*r);e.fillStyle=ce(f,.22),e.fillRect(x,w,a,g),e.lineWidth=l+2,e.strokeStyle="rgba(0,0,0,0.55)",e.strokeRect(x,w,a,g),e.lineWidth=l,e.strokeStyle=f,e.strokeRect(x,w,a,g)}function le(e,t,r,o,s){if(o<=0||s<=0)return null;if(e==="CIRCLE"){const a=Math.hypot(r.curX-r.startX,r.curY-r.startY);return a<=4?null:{shape:e,color:t,geometry:{x:r.startX/o,y:r.startY/s,w:a/o,h:a/s}}}if(e==="ARROW"){const a=r.curX-r.startX,g=r.curY-r.startY;return Math.hypot(a,g)<=6?null:{shape:e,color:t,geometry:{x:r.startX/o,y:r.startY/s,w:a/o,h:g/s}}}if(e==="FREEHAND"){if(r.points.length<2)return null;const a=r.points.map(E=>E[0]),g=r.points.map(E=>E[1]),u=Math.min(...a),y=Math.min(...g);return{shape:e,color:t,geometry:{x:u/o,y:y/s,w:Math.max(.005,(Math.max(...a)-u)/o),h:Math.max(.005,(Math.max(...g)-y)/s),points:r.points.map(([E,p])=>[E/o,p/s])}}}const f=Math.min(r.startX,r.curX)/o,l=Math.min(r.startY,r.curY)/s,x=Math.abs(r.curX-r.startX)/o,w=Math.abs(r.curY-r.startY)/s;return x<=.005||w<=.005?null:{shape:e,color:t,geometry:{x:f,y:l,w:x,h:w}}}function nt({enabled:e,shape:t,color:r,onCommit:o,committed:s,onCommittedChange:f,mediaAspect:l}){const x=d.useRef(null),[w,a]=d.useState(null),[g,u]=d.useState([]),[y,E]=d.useState(null),p=s??g,b=d.useRef(p),I=d.useRef(w),D=d.useRef(t),M=d.useRef(r),i=d.useRef(e);b.current=p,I.current=w,D.current=t,M.current=r,i.current=e;const m=d.useCallback(h=>{const R=h(b.current);b.current=R,f?f(R):u(R)},[f]),N=d.useCallback(()=>{const h=x.current;if(!h)return;const R=h.getContext("2d");if(!R)return;R.clearRect(0,0,h.width,h.height);for(const j of b.current)ne(R,h.width,h.height,j);const C=I.current;if(C){const j=le(D.current,M.current,C,h.width,h.height);j&&ne(R,h.width,h.height,j)}},[]);d.useEffect(()=>{const h=x.current;if(!h)return;const R=()=>{const j=Math.max(1,Math.round(h.clientWidth)),O=Math.max(1,Math.round(h.clientHeight));(h.width!==j||h.height!==O)&&(h.width=j,h.height=O),N()};R();const C=new ResizeObserver(R);return C.observe(h),()=>C.disconnect()},[N]),d.useEffect(()=>{N()},[w,p,N]),d.useEffect(()=>{var j;const h=(j=x.current)==null?void 0:j.parentElement;if(!h)return;const R=()=>{const O=l?me(h.clientWidth,h.clientHeight,l):null;E(F=>et(F,O)?F:O)};R();const C=new ResizeObserver(R);return C.observe(h),()=>C.disconnect()},[l]),d.useEffect(()=>{var R;if(e)return;a(null);const h=x.current;if(h&&h.hasPointerCapture)try{for(let C=0;C<8;C++)(R=h.hasPointerCapture)!=null&&R.call(h,C)&&h.releasePointerCapture(C)}catch{}},[e]);const A=h=>{const C=x.current.getBoundingClientRect();return{px:h.clientX-C.left,py:h.clientY-C.top,w:C.width,h:C.height}},v=h=>{const R=I.current;if(!R||!i.current){a(null);return}const C=x.current;if(!C||C.width<=0){a(null);return}const j=A(h),O=le(D.current,M.current,{...R,curX:j.px,curY:j.py,points:ae(R.points,j.px,j.py)},j.w,j.h);O&&(m(F=>[...F,O]),o(O,Qe(O,j.w,j.h))),a(null)},T=h=>{if(!e||h.button!==0)return;h.preventDefault(),h.currentTarget.setPointerCapture(h.pointerId);const R=A(h);a({startX:R.px,startY:R.py,curX:R.px,curY:R.py,points:[[R.px,R.py]]})},_=h=>{if(!I.current)return;const R=A(h);a(C=>C&&{...C,curX:R.px,curY:R.py,points:ae(C.points,R.px,R.py)})},k=h=>{try{h.currentTarget.releasePointerCapture(h.pointerId)}catch{}v(h)};return n.jsx("canvas",{ref:x,style:{position:"absolute",...y?{left:`${y.left}px`,top:`${y.top}px`,width:`${y.width}px`,height:`${y.height}px`}:{inset:0,width:"100%",height:"100%"},pointerEvents:e?"auto":"none",cursor:e?"crosshair":"default",zIndex:e?40:25},onPointerDown:T,onPointerMove:_,onPointerUp:k,onPointerCancel:k})}function ot(e,t,r,o,s,f,l=!1){const x=me(r.width,r.height,f);let w=(e-r.left-x.left)/x.width,a=(t-r.top-x.top)/x.height;return!(w>=0&&w<=1&&a>=0&&a<=1)&&!l?null:(w=Math.min(1,Math.max(0,w)),a=Math.min(1,Math.max(0,a)),{x:Math.round(w*o),y:Math.round(a*s)})}const st=5e3;function it(e,t){if(e.httpStatus===404)return{ended:!0,startedAt:t};if(e.httpStatus!==200)return{ended:!1,startedAt:t};const r=e.body??{};return r.status!=="running"?{ended:!0,startedAt:t}:t&&r.startedAt&&r.startedAt!==t?{ended:!0,startedAt:t}:{ended:!1,startedAt:t??r.startedAt}}function at(e,t,r,o=st){const s=d.useRef(r);s.current=r,d.useEffect(()=>{if(!t)return;let f=!1,l=!1,x;const w=async()=>{if(!(l||f)){l=!0;try{const g=await fetch(`/xenon/api/control/${encodeURIComponent(e)}/stream/status`),u=g.ok?await g.json().catch(()=>{}):void 0;if(f)return;const y=it({httpStatus:g.status,body:u},x);x=y.startedAt,y.ended&&(f=!0,s.current())}catch{}finally{l=!1}}};w();const a=setInterval(w,o);return()=>{f=!0,clearInterval(a)}},[e,t,o])}const ct=3,lt=45e3,de=[2e3,5e3,1e4];function dt(e){const t=Math.max(0,Math.min(e,de.length-1));return de[t]}function ut(e){return e<ct}function ue(e){const t=(e.lastError||"").toLowerCase();return/did not find test app|not installed|webdriveragentrunner|applicationverification/.test(t)?"WebDriverAgent is not installed on this device. Install and trust WDA, then retry.":/unsupported ios version|manualpairingtunnelstart/.test(t)?"This device’s iOS version is not supported for live streaming on this host.":/econnrefused|econnreset|connection reset|tunnel/.test(t)?"Lost the connection to the device tunnel. Reconnect the device, then retry.":e.lastError&&e.lastError.trim()?e.lastError.trim():"We couldn’t start the live stream for this device."}function ht(e){for(let t=0;t+4<e.length;t++){const r=e[t]===0&&e[t+1]===0&&e[t+2]===0&&e[t+3]===1,o=e[t]===0&&e[t+1]===0&&e[t+2]===1;if(!r&&!o)continue;const s=t+(r?4:3);if((e[s]&31)===7){const f=l=>l.toString(16).padStart(2,"0");return`avc1.${f(e[s+1])}${f(e[s+2])}${f(e[s+3])}`}}return"avc1.42e01e"}const ft=({wsUrl:e,onFatal:t,onReady:r,onFrameSize:o,className:s})=>{const f=d.useRef(null),l=d.useRef(t);l.current=t;const x=d.useRef(r);x.current=r;const w=d.useRef(o);return w.current=o,d.useEffect(()=>{var M;const a=window,g=f.current;if(typeof a.VideoDecoder>"u"||!g){(M=l.current)==null||M.call(l);return}const u=g.getContext("2d");let y=!1,E=!1,p=!0,b=0;const I=new a.VideoDecoder({output:i=>{var m,N;if(y){i.close();return}(g.width!==i.displayWidth||g.height!==i.displayHeight)&&(g.width=i.displayWidth,g.height=i.displayHeight,(m=w.current)==null||m.call(w,i.displayWidth,i.displayHeight)),u==null||u.drawImage(i,0,0),i.close(),p&&(p=!1,(N=x.current)==null||N.call(x))},error:()=>{var i;return(i=l.current)==null?void 0:i.call(l)}}),D=new WebSocket(e);return D.binaryType="arraybuffer",D.onerror=()=>{var i;return(i=l.current)==null?void 0:i.call(l)},D.onclose=()=>{var i;y||(i=l.current)==null||i.call(l)},D.onmessage=i=>{var v;const m=i.data,N=new DataView(m).getUint8(0),A=new Uint8Array(m,1);if(N===0){if(E)return;try{I.configure({codec:ht(A),optimizeForLatency:!0}),E=!0}catch{(v=l.current)==null||v.call(l)}return}if(!(!E||I.state!=="configured"))try{I.decode(new a.EncodedVideoChunk({type:N===1?"key":"delta",timestamp:b,data:A})),b+=11111}catch{}},()=>{y=!0;try{D.close()}catch{}try{I.state!=="closed"&&I.close()}catch{}}},[e]),n.jsx("canvas",{ref:f,className:s,style:{width:"100%",height:"100%",objectFit:"contain",display:"block"}})};function pt(e,t,r){return(e==="android"||e==="androidtv"||e==="android-tv")&&t==="h264"&&r?"h264":"mjpeg"}const mt=10,gt=500;function xt({udid:e,name:t,recordingId:r,annotateMode:o,shape:s,color:f,aspect:l="9 / 16",screenWidth:x,screenHeight:w,platform:a,onAnnotation:g,overlayAnnotations:u,onOverlayAnnotationsChange:y,onRemove:E}){const[p,b]=d.useState("connecting"),[I,D]=d.useState(),M=d.useCallback((c,S)=>{if(!(c>0)||!(S>0))return;const L=c/S;D(B=>B!==void 0&&Math.abs(B-L)<.001?B:L)},[]),[i,m]=d.useState(0),[N,A]=d.useState(null),v=d.useRef(0),T=d.useRef(null),[_,k]=d.useState(""),[h,R]=d.useState([]),[C,j]=d.useState(!1),O=d.useRef(null),F=d.useRef(null),G=a==="android"||a==="androidtv"||a==="android-tv",be=a==="ios"||a==="tvos";d.useEffect(()=>{let c=!1;if(r){A(null),b("connecting"),m(Date.now()),$.startStream(e).catch(()=>{});return}const S=typeof window.VideoDecoder<"u";return(async()=>{try{const L=encodeURIComponent(e),B=await fetch(`/xenon/api/control/${L}/stream/status`);if(!B.ok)return;const P=await B.json();if(pt(a||"",P==null?void 0:P.type,S)!=="h264"||!(P!=null&&P.h264Path))return;const X=await fetch(`/xenon/api/control/${L}/stream/ticket`,{method:"POST"});if(!X.ok)return;const{ticket:Y}=await X.json();if(c||!Y)return;const K=`${window.location.protocol==="https:"?"wss":"ws"}://${window.location.host}${P.h264Path}?ticket=${encodeURIComponent(Y)}`;A(K)}catch{}})(),()=>{c=!0}},[e,a,r]);const H=!o&&!!x&&!!w,Q=(c,S,L,B=!1)=>ot(c,S,L,x,w,I,B),ye=(c,S,L)=>{const B=Date.now()+Math.random(),P=c-L.left,X=S-L.top;R(Y=>[...Y,{id:B,x:P,y:X}]),window.setTimeout(()=>{R(Y=>Y.filter(z=>z.id!==B))},500)},ve=c=>{if(!H||p==="unavailable"||c.button!==0)return;const S=c.currentTarget;S.focus(),Q(c.clientX,c.clientY,S.getBoundingClientRect())&&(S.setPointerCapture(c.pointerId),F.current={startX:c.clientX,startY:c.clientY,startTime:Date.now(),rect:S.getBoundingClientRect()},ye(c.clientX,c.clientY,F.current.rect))},we=async c=>{var K,se;const S=F.current;if(F.current=null,!S||!H)return;try{c.currentTarget.releasePointerCapture(c.pointerId)}catch{}const L=c.clientX-S.startX,B=c.clientY-S.startY,P=Math.hypot(L,B),X=Date.now()-S.startTime,Y=Q(S.startX,S.startY,S.rect,!0),z=P<mt;try{if(z&&X<gt)await $.tap(e,Y.x,Y.y);else if(z)await((se=(K=$).touchAndHold)==null?void 0:se.call(K,e,Y.x,Y.y,X));else{const J=Q(c.clientX,c.clientY,S.rect,!0);await $.swipe(e,Y.x,Y.y,J.x,J.y)}}catch(J){console.error(`[DeviceTile] gesture failed for ${e}`,J)}},Ee=()=>{F.current=null},Ne=async c=>{if(!H||p==="unavailable"||c.metaKey||c.ctrlKey||c.altKey)return;const S=c.key;try{if(S.length===1){c.preventDefault(),await $.typeText(e,S);return}if(S==="Backspace"){c.preventDefault(),G?await $.pressKey(e,67):await $.typeText(e,"\b");return}if(S==="Enter"){c.preventDefault(),G?await $.pressKey(e,66):await $.typeText(e,`
|
|
2
|
-
`);return}if(S==="Tab"){c.preventDefault(),await $.typeText(e," ");return}S==="Escape"&&G&&(c.preventDefault(),await $.pressKey(e,q.BACK))}catch(L){console.error(`[DeviceTile] keystroke "${S}" failed for ${e}`,L)}},Re=()=>$.pressKey(e,G?q.HOME:Me.HOME).catch(c=>console.error(`[DeviceTile] home failed for ${e}`,c)),Se=()=>$.pressKey(e,q.BACK).catch(c=>console.error(`[DeviceTile] back failed for ${e}`,c)),Te=()=>$.pressKey(e,q.APP_SWITCH).catch(c=>console.error(`[DeviceTile] app-switch failed for ${e}`,c)),je=async()=>{try{const c=await $.getScreenshot(e),S=(c==null?void 0:c.screenshot)??(c==null?void 0:c.value)??c;if(!S)return;const L=await fetch(`data:image/png;base64,${S}`).then(X=>X.blob()),B=URL.createObjectURL(L),P=document.createElement("a");P.href=B,P.download=`${t||e}-${Date.now()}.png`,document.body.appendChild(P),P.click(),P.remove(),setTimeout(()=>URL.revokeObjectURL(B),1e3)}catch(c){console.error(`[DeviceTile] screenshot failed for ${e}`,c)}};d.useEffect(()=>{console.log(`[DeviceTile] Rendering ${e} in state: ${p}`)},[e,p]);const Ce=`/xenon/api/control/${encodeURIComponent(e)}/stream?t=${i}`,oe=d.useCallback(async()=>{try{const c=await fetch(`/xenon/api/control/${encodeURIComponent(e)}/stream/status`);if(!c.ok)throw new Error(String(c.status));const S=await c.json();k(ue({lastError:S==null?void 0:S.lastError,status:S==null?void 0:S.status}))}catch{k(ue({}))}},[e]),ee=d.useCallback(()=>{const c=v.current;ut(c)?(v.current=c+1,T.current&&clearTimeout(T.current),T.current=setTimeout(()=>{b("connecting"),m(Date.now())},dt(c))):(b("unavailable"),oe())},[oe]);d.useEffect(()=>{if(p!=="connecting")return;const c=setTimeout(ee,lt);return()=>clearTimeout(c)},[p,i,ee]),at(e,p==="live"&&!N,()=>{console.warn(`[DeviceTile] MJPEG stream ended for ${e}; reconnecting`),b("connecting"),m(Date.now())}),d.useEffect(()=>()=>{T.current&&clearTimeout(T.current)},[]);const Ae=()=>{T.current&&clearTimeout(T.current),v.current=0,k(""),b("connecting"),m(Date.now())},W=!!r,te=t||e.slice(0,16)+"…";return n.jsxs("div",{className:"flex items-stretch justify-center w-full h-full min-h-0 min-w-0 gap-2",children:[n.jsxs("div",{className:"relative bg-[var(--black)] rounded-lg overflow-hidden border border-[var(--border)] group max-h-full max-w-full self-center",style:{aspectRatio:l,height:"100%"},children:[p==="connecting"&&n.jsxs("div",{className:"flex flex-col items-center justify-center bg-neutral-900/80 text-neutral-400 absolute inset-0 z-20 pointer-events-none",children:[n.jsx("div",{className:"relative flex items-center justify-center",children:n.jsx("div",{className:"w-12 h-12 border-4 border-neutral-800 border-t-neutral-400 rounded-full animate-spin"})}),n.jsx("div",{className:"mt-4 font-bold text-neutral-200",children:"Starting Stream…"}),n.jsx("div",{className:"text-[10px] mt-1 text-neutral-500 opacity-60 font-mono",children:e}),n.jsx("div",{className:"text-[10px] mt-4 text-neutral-400 bg-white/5 px-2 py-1 rounded",children:"Waiting for device connection..."})]}),p==="unavailable"&&n.jsx("div",{className:"flex items-center justify-center bg-black text-neutral-400 absolute inset-0 z-20",children:n.jsxs("div",{className:"text-center p-6",children:[n.jsx("div",{className:"text-5xl mb-4 opacity-20",children:"📵"}),n.jsx("div",{className:"font-bold text-white text-lg",children:"Connection Failed"}),n.jsx("p",{className:"text-xs mt-2 text-neutral-500 leading-relaxed max-w-[240px] mx-auto",children:_||"We couldn’t start the live stream for this device."}),n.jsx("button",{className:"mt-6 text-sm font-semibold px-6 py-2.5 rounded-full bg-red-600 hover:bg-red-500 text-white transition-all active:scale-95",onClick:Ae,children:"Retry connection"})]})}),N?n.jsx(ft,{wsUrl:N,className:"absolute inset-0 w-full h-full object-contain bg-black select-none pointer-events-none",onReady:()=>b("live"),onFrameSize:M,onFatal:()=>{console.warn(`[DeviceTile] H.264 fatal for ${e}; falling back to MJPEG`),A(null),b("connecting"),m(Date.now())}}):n.jsx("img",{src:Ce,alt:te,className:"absolute inset-0 w-full h-full object-contain bg-black select-none pointer-events-none",draggable:!1,style:{opacity:p==="live"?1:0,transition:"opacity 0.3s ease-in-out"},onLoad:c=>{console.log(`[DeviceTile] Image LOADED for ${e}`),M(c.currentTarget.naturalWidth,c.currentTarget.naturalHeight),v.current=0,T.current&&clearTimeout(T.current),b("live")},onError:c=>{console.error(`[DeviceTile] Image ERROR for ${e}`,c),ee()}},i),H&&p!=="unavailable"&&n.jsx("div",{ref:O,className:`absolute inset-0 z-[35] touch-none outline-none ${C?"ring-2 ring-[rgb(var(--rgb-accent)/0.6)] ring-inset rounded-lg":""}`,tabIndex:0,onPointerDown:ve,onPointerUp:we,onPointerCancel:Ee,onKeyDown:Ne,onFocus:()=>j(!0),onBlur:()=>j(!1)}),n.jsx("div",{className:"absolute inset-0 z-20 pointer-events-none overflow-hidden",children:h.map(c=>n.jsx("span",{className:"absolute block w-10 h-10 rounded-full border-2 border-[var(--color-accent-soft)] animate-ping",style:{left:c.x-20,top:c.y-20}},c.id))}),W&&n.jsx(nt,{enabled:o,shape:s,color:f,committed:u,mediaAspect:I,onCommittedChange:y,onCommit:(c,S)=>g(r,c,S)}),W&&o&&p==="live"&&n.jsx("div",{className:"absolute top-3 left-14 right-3 z-30 flex justify-end pointer-events-none",children:n.jsx("span",{className:"px-2 py-0.5 rounded-sm bg-[var(--color-info)] text-white text-[10px] font-semibold shadow-lg whitespace-nowrap overflow-hidden text-ellipsis",children:"Annotating · drag to mark"})}),W&&n.jsx("div",{className:"absolute top-3 left-3 z-30 pointer-events-none",children:n.jsx("span",{className:"px-2 py-0.5 rounded-sm bg-red-600 text-white text-[9px] font-black shadow-lg",children:"REC"})}),n.jsxs("div",{className:"absolute top-3 left-3 z-30 flex flex-col gap-1.5 pointer-events-none opacity-0 group-hover:opacity-100 transition-opacity duration-150",children:[p==="live"&&n.jsx("span",{className:"px-2 py-0.5 rounded-sm bg-[var(--color-success)] text-[var(--color-on-success)] text-[11px] font-semibold shadow-lg w-fit",children:"Live"}),n.jsx("span",{className:"px-2 py-1 rounded bg-black/80 text-white text-[11px] font-medium backdrop-blur-md border border-white/10 shadow-xl truncate max-w-[180px]",children:te})]})]}),n.jsx(bt,{streamState:p,recording:W,isIOS:be,isAndroid:G,platform:a,onClose:!W&&E?()=>E(e):void 0,sendHome:Re,sendBack:Se,sendAppSwitch:Te,captureScreenshot:je,displayName:te})]})}function bt({streamState:e,recording:t,isIOS:r,isAndroid:o,platform:s,onClose:f,sendHome:l,sendBack:x,sendAppSwitch:w,captureScreenshot:a,displayName:g}){const u=e==="live";return!f&&!u?null:n.jsxs("div",{className:"self-stretch w-9 flex flex-col items-center justify-between gap-1 py-2 rounded-lg bg-black/40 border border-white/10 backdrop-blur-md text-white",children:[n.jsx("div",{className:"flex flex-col items-center gap-1",children:f&&n.jsx("button",{type:"button","aria-label":`Remove ${g} from mosaic`,title:"Remove from mosaic",onClick:f,className:"w-7 h-7 flex items-center justify-center rounded-md hover:bg-red-600/70 transition-colors text-base leading-none",children:"×"})}),u&&n.jsxs("div",{className:"flex flex-col items-center gap-1.5 my-auto",children:[(o||r)&&n.jsx("button",{type:"button",title:`Home${s?` (${s})`:""}`,onClick:l,className:"w-7 h-7 flex items-center justify-center rounded-md hover:bg-white/15 transition-colors text-sm",children:"⌂"}),o&&n.jsx("button",{type:"button",title:"Back",onClick:x,className:"w-7 h-7 flex items-center justify-center rounded-md hover:bg-white/15 transition-colors text-sm",children:"‹"}),o&&n.jsx("button",{type:"button",title:"Recent apps",onClick:w,className:"w-7 h-7 flex items-center justify-center rounded-md hover:bg-white/15 transition-colors text-sm",children:"▢"})]}),u&&n.jsx("div",{className:"flex flex-col items-center gap-1",children:n.jsx("button",{type:"button",title:"Screenshot",onClick:a,className:"w-7 h-7 flex items-center justify-center rounded-md hover:bg-white/15 transition-colors text-sm",children:"⎙"})})]})}const yt={1:"1fr","2x1":"1fr 1fr","2x2":"1fr 1fr","3x2":"1fr 1fr 1fr"},vt={1:"1fr","2x1":"1fr","2x2":"1fr 1fr","3x2":"1fr 1fr"},wt={1:1,"2x1":2,"2x2":4,"3x2":6};function Et({layout:e,tiles:t,annotateMode:r,shape:o,color:s,onAnnotation:f,overlayAnnotationsByRecording:l,onOverlayAnnotationsChange:x,onRemove:w,onDropDevice:a}){const g=$e(e,t.length),u=wt[g];t.length;const y=t.length,E=e==="auto"?Math.max(y,1):u,p=Math.max(0,E-y);return n.jsxs("div",{style:{display:"grid",gap:8,gridTemplateColumns:yt[g],gridTemplateRows:vt[g]},className:"h-full",children:[t.map(b=>n.jsx(xt,{udid:b.udid,name:b.name,mjpegPort:b.mjpegPort,recordingId:b.recordingId,aspect:b.aspect,screenWidth:b.screenWidth,screenHeight:b.screenHeight,platform:b.platform,annotateMode:r,shape:o,color:s,overlayAnnotations:b.recordingId?l==null?void 0:l[b.recordingId]:void 0,onOverlayAnnotationsChange:b.recordingId&&x?I=>x(b.recordingId,I):void 0,onAnnotation:f,onRemove:w},b.udid)),Array.from({length:p},(b,I)=>n.jsx(Nt,{onDropDevice:a},`empty-${I}`))]})}function Nt({onDropDevice:e}){const[t,r]=d.useState(!1);return n.jsxs("div",{onDragOver:o=>{e&&(o.preventDefault(),o.dataTransfer.dropEffect="copy",t||r(!0))},onDragLeave:()=>r(!1),onDrop:o=>{if(r(!1),!e)return;o.preventDefault();const s=o.dataTransfer.getData("application/x-xenon-udid")||o.dataTransfer.getData("text/plain");s&&e(s)},className:`flex flex-col items-center justify-center gap-2 rounded-lg border border-dashed transition-colors ${t?"border-[rgb(var(--rgb-accent)/0.6)] bg-[rgb(var(--rgb-accent)/0.05)]":"border-[var(--border)] bg-[rgb(var(--rgb-white)/0.02)]"} text-[var(--text-dim)] min-h-[120px]`,children:[n.jsx("div",{"aria-hidden":"true",className:`w-8 h-8 rounded-full flex items-center justify-center text-xl ${t?"bg-[rgb(var(--rgb-accent)/0.15)] text-[var(--color-accent-soft)]":"bg-[rgb(var(--rgb-fg)/0.05)] text-[rgb(var(--rgb-fg)/0.6)]"}`,children:"+"}),n.jsx("div",{className:"text-xs font-medium",children:"Drag device here"}),n.jsx("div",{className:"text-[10px] opacity-70",children:"or click one in the panel"})]})}const V="/xenon/api/recordings";class ge extends Error{constructor(t){super(t.message??t.error),this.body=t}}async function Z(e,t){const r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0});if(r.status===409)throw new ge(await r.json());if(!r.ok)throw new Error(`HTTP ${r.status}`);return r.json()}function Rt(e,t){return Z(V,{udids:e,...t})}function St(e){return Z(`${V}/${encodeURIComponent(e)}/stop`)}function he(e,t){return Z(`${V}/${encodeURIComponent(e)}/annotation`,t)}function Tt(e,t){return Z(`${V}/${encodeURIComponent(e)}/annotations/clear`,{timecodeMs:t})}async function jt(){const e=await fetch(`${V}/active`);if(!e.ok)throw new Error(`HTTP ${e.status}`);return e.json()}function Ct(e){return`${V}/${encodeURIComponent(e)}/videos.zip`}function At(e,t){return`${V}/${encodeURIComponent(e)}/video.mp4`}function It(e){return`${V}/${encodeURIComponent(e)}/composite.mp4`}function Dt(e,t){return t==="starting"?"Starting…":e<=0?"Record":e===1?"● Record":`● Record ${e} devices`}function kt({selectedUdids:e,onClearMarks:t}){const{state:r,dispatch:o}=Le(),[s,f]=d.useState(()=>Date.now());d.useEffect(()=>{if(r.recordingPhase!=="recording"&&r.recordingPhase!=="stopping")return;f(Date.now());const v=window.setInterval(()=>f(Date.now()),250);return()=>window.clearInterval(v)},[r.recordingPhase]);const l=r.startedAt&&(r.recordingPhase==="recording"||r.recordingPhase==="stopping")?s-r.startedAt:0,x=r.recordingPhase==="starting"||r.recordingPhase==="stopping",w=r.recordingPhase==="idle"&&e.length>0&&!x,a=r.recordingPhase==="recording"||r.recording&&r.tiles.some(v=>!!v.recordingId),g=a&&!x,u=g,y=u&&r.annotateMode,E=!!r.groupId&&r.recordingPhase==="idle",p=e.length>1||r.downloadableVideoCount>1,b=E&&r.compositeEnabled,I=E&&!r.compositeEnabled&&(r.downloadableVideoCount===1||r.downloadableVideoCount===0&&e.length<=1),D=async()=>{var v;if(w){o({type:"SET_RECORDING_PHASE",phase:"starting"}),o({type:"SET_BANNER",banner:null});try{const T=await Rt(e);if(!((v=T.recordings)!=null&&v.length)){o({type:"SET_RECORDING_PHASE",phase:"idle"}),o({type:"SET_BANNER",banner:{tone:"error",message:"Recording did not start. Check that live preview is working, then try again."}});return}const _={};for(const h of T.recordings)_[h.udid]=h.id;const k=e.length-T.recordings.length;o({type:"START_RECORDING",groupId:T.groupId,startedAt:Date.now(),tileIds:_,compositeEnabled:T.compositeEnabled===!0}),k>0?o({type:"SET_BANNER",banner:{tone:"error",message:`Recording started on ${T.recordings.length} of ${e.length} devices (${k} failed).`}}):o({type:"SET_BANNER",banner:null})}catch(T){if(o({type:"SET_RECORDING_PHASE",phase:"idle"}),T instanceof ge)if(T.body.error==="device_busy"){const _=(T.body.busyDevices??[]).map(k=>`${k.udid} (${k.reason})`).join(", ");o({type:"SET_BANNER",banner:{tone:"error",message:`Cannot start — these devices are busy: ${_}`}})}else o({type:"SET_BANNER",banner:{tone:"error",message:`Server-wide recording cap reached (${T.body.active}/${T.body.limit}).`}});else o({type:"SET_BANNER",banner:{tone:"error",message:`Recording failed: ${T.message}`}})}}},M=async()=>{if(!(!r.groupId||r.recordingPhase!=="recording")){o({type:"SET_RECORDING_PHASE",phase:"stopping"});try{const v=await St(r.groupId),T=(v.recordings??[]).filter(k=>k.status==="STOPPED"&&(k.sizeBytes??0)>=1024),_=(v.recordings??[]).filter(k=>k.status!=="STOPPED");o({type:"STOP_RECORDING",downloadableVideoCount:T.length,compositeEnabled:r.compositeEnabled}),T.length===0?o({type:"SET_BANNER",banner:{tone:"error",message:_.length>0?`Recording failed on ${_.length} device(s). Nothing to download.`:"Recording stopped but no playable video was produced."}}):_.length>0?o({type:"SET_BANNER",banner:{tone:"info",message:`${T.length} video(s) ready · ${_.length} failed. Use Download below.`}}):o({type:"SET_BANNER",banner:{tone:"info",message:T.length===1?"Video ready — download below.":`${T.length} videos ready — download below.`}})}catch(v){o({type:"STOP_RECORDING"}),o({type:"SET_BANNER",banner:{tone:"error",message:`Stop failed: ${v.message}`}})}}},i=()=>{u&&o({type:"SET_ANNOTATE_MODE",enabled:!r.annotateMode})},m=()=>{u&&t()},N=Object.values(r.overlayAnnotations).some(v=>((v==null?void 0:v.length)??0)>0),A=[{id:"RECT",label:"Rect"},{id:"CIRCLE",label:"Circle"},{id:"ARROW",label:"Arrow"},{id:"FREEHAND",label:"Draw"}];return n.jsxs("div",{className:"flex items-center gap-2 flex-wrap justify-end",children:[(r.recordingPhase==="recording"||r.recordingPhase==="stopping")&&n.jsxs("span",{className:"inline-flex items-center gap-1.5 px-2 py-1 rounded text-xs font-mono tabular-nums bg-[rgb(var(--rgb-red-600)/0.2)] text-[var(--red-200)] border border-[rgb(var(--rgb-red)/0.4)]",title:"Recording elapsed time",children:[n.jsx("span",{className:"inline-block w-1.5 h-1.5 rounded-full bg-[var(--red)] animate-pulse"}),"REC ",Ye(l),r.recordingPhase==="stopping"?" · Stopping…":""]}),n.jsx("button",{type:"button",onClick:D,disabled:!w,title:e.length===0?"Add a device to the mosaic first":"Record every device currently in the mosaic",className:"px-3 py-1.5 text-sm rounded bg-[var(--red-600)] text-white disabled:opacity-40 disabled:cursor-not-allowed light:disabled:bg-transparent light:disabled:text-[var(--text)] light:disabled:ring-1 light:disabled:ring-inset light:disabled:ring-[color:var(--border)]",children:Dt(e.length,r.recordingPhase)}),n.jsx("button",{type:"button",onClick:M,disabled:!g,className:"px-3 py-1.5 text-sm rounded border border-[var(--border)] disabled:opacity-40 disabled:cursor-not-allowed",children:r.recordingPhase==="stopping"?"Stopping…":"⏹ Stop"}),n.jsx("button",{type:"button",onClick:i,disabled:!u,title:u?r.annotateMode?"Exit annotate mode (tap/swipe resumes)":"Draw on the live screen — saved with the recording":"Start recording to annotate",className:`px-3 py-1.5 text-sm rounded border ${r.annotateMode?"bg-[var(--color-info)] text-white border-transparent":"border-[var(--border)]"} disabled:opacity-40 disabled:cursor-not-allowed`,children:"✎ Annotate"}),a&&n.jsxs("div",{className:"flex items-center gap-1 ml-1 pl-2 border-l border-[var(--border)]",children:[A.map(v=>n.jsx("button",{type:"button",disabled:!y,"aria-pressed":r.shape===v.id,onClick:()=>o({type:"SET_SHAPE",shape:v.id}),className:`px-2 py-1 text-xs rounded border disabled:opacity-40 disabled:cursor-not-allowed ${r.shape===v.id?"bg-[var(--surface-2)] border-[var(--color-info)] text-[rgb(var(--rgb-fg))]":"border-[var(--border)] opacity-80 hover:opacity-100"}`,children:v.label},v.id)),n.jsx("input",{type:"color",value:r.color,disabled:!y,onChange:v=>o({type:"SET_COLOR",color:v.target.value}),title:"Annotation color","aria-label":"Annotation color",className:"w-7 h-7 rounded border border-[var(--border)] bg-transparent cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed"}),n.jsx("button",{type:"button",onClick:m,disabled:!u||!N,title:"Clear marks from the preview and the recording",className:"px-2 py-1 text-xs rounded border border-[var(--border)] hover:bg-[var(--surface-2)] disabled:opacity-40 disabled:cursor-not-allowed",children:"Clear marks"})]}),E&&I&&n.jsx("a",{href:At(r.groupId),className:"ml-1 px-3 py-1.5 text-sm rounded border border-[var(--border)] hover:bg-[var(--surface-2)]",download:!0,children:"⤓ Download video"}),E&&!I&&n.jsxs("a",{href:Ct(r.groupId),className:"ml-1 px-3 py-1.5 text-sm rounded border border-[var(--border)] hover:bg-[var(--surface-2)]",download:`videos-${r.groupId}.zip`,title:"ZIP of mp4 files only (no JSON extras)",children:["⤓ Download ",p?"videos":"video"]}),b&&n.jsx("a",{href:It(r.groupId),className:"px-3 py-1.5 text-sm rounded border border-[var(--border)] hover:bg-[var(--surface-2)]",download:`side-by-side-${r.groupId}.mp4`,title:"All devices in one side-by-side video",children:"⤓ Side-by-side"})]})}function Mt({remainingSec:e,onContinue:t,onReleaseNow:r}){return n.jsx("div",{role:"dialog","aria-modal":"true","aria-labelledby":"idle-warning-title",className:"fixed inset-0 z-40 bg-black/60 flex items-center justify-center",children:n.jsxs("div",{className:"bg-[var(--bg)] border border-[var(--border)] rounded-lg w-full max-w-md p-6",children:[n.jsx("h3",{id:"idle-warning-title",className:"text-base font-semibold mb-2",children:"Are you still there?"}),n.jsxs("p",{className:"text-sm text-[var(--text-dim)] mb-4",children:["Your devices will be released in"," ",n.jsxs("span",{className:"text-[var(--text)] font-mono font-semibold",children:[e,"s"]})," due to inactivity. Click ",n.jsx("strong",{children:"Continue Session"})," to keep them locked."]}),n.jsxs("div",{className:"flex justify-end gap-2",children:[n.jsx("button",{type:"button",onClick:r,className:"h-9 px-3 rounded-md border border-[var(--border)] text-sm text-[var(--text-dim)] hover:text-[var(--text)]",children:"Release now"}),n.jsx("button",{type:"button",autoFocus:!0,onClick:t,className:"h-9 px-4 rounded-md bg-[var(--color-accent)] text-[var(--color-on-accent)] text-sm font-medium",children:"Continue session"})]})]})})}function xe(e,t,r){return!r||!e?!1:e===`manual_${r}_${t}`}function _t(e,t){return e.busy?xe(e.session_id,e.udid,t):!1}function $t(){let e=Promise.resolve();return{enqueue(t){const r=e.then(t,t);return e=r.then(()=>{},()=>{}),r}}}const fe=["mousemove","mousedown","keydown","touchstart","wheel"];function Ot({idleAfterMs:e,warningSec:t,onWarning:r,onTimeout:o,enabled:s}){const[f,l]=d.useState(!1),[x,w]=d.useState(null),a=d.useRef(null),g=d.useRef(null),u=d.useRef(!1),y=d.useRef(r),E=d.useRef(o);y.current=r,E.current=o;function p(){a.current&&(clearTimeout(a.current),a.current=null),g.current&&(clearInterval(g.current),g.current=null)}function b(){u.current=!0,l(!0),w(t),y.current(t);let M=t;g.current=setInterval(()=>{M-=1,M<=0?(p(),u.current=!1,l(!1),w(null),E.current()):w(M)},1e3)}function I(){p(),u.current=!1,l(!1),w(null);const M=e-t*1e3;a.current=setTimeout(b,Math.max(0,M))}function D(){s&&I()}return d.useEffect(()=>{if(!s){p(),u.current=!1,l(!1),w(null);return}function M(){u.current||I()}return fe.forEach(i=>window.addEventListener(i,M,{passive:!0})),I(),()=>{fe.forEach(i=>window.removeEventListener(i,M)),p()}},[s,e,t]),{warning:f,remainingSec:x,reset:D}}const Pt=5*60*1e3,Lt=30;function re(e){if(!e)return"9 / 16";const t=Number(e.screenWidth),r=Number(e.screenHeight);if(Number.isFinite(t)&&Number.isFinite(r)&&t>0&&r>0)return`${t} / ${r}`;const o=(e.platform||"").toLowerCase();return o==="tvos"||o==="androidtv"||o==="android-tv"?"16 / 9":"9 / 16"}function Bt(e,t){if(e.busy)return e.session_id?e.session_id.startsWith("manual_")?xe(e.session_id,e.udid,t)?"manual_self":"manual_other":"automation":"unknown"}function Yt(e,t){return{udid:e.udid,name:e.name,platform:e.platform,busy:e.busy,busyReason:Bt(e,t),mjpegServerPort:e.mjpegServerPort,offline:!!e.offline}}function Gt(){const[e,t]=Be(),[r,o]=d.useState([]),[s,f]=d.useState(0),[l,x]=d.useState(null),w=d.useRef(!1),a=d.useRef($t());d.useEffect(()=>{let i=!1;return fetch("/xenon/api/auth/me",{credentials:"include"}).then(m=>m.ok?m.json():null).then(m=>{!i&&(m!=null&&m.userId)&&x(m.userId)}).catch(()=>{}),()=>{i=!0}},[]),d.useEffect(()=>{let i=!1;const m=async()=>{try{const A=await $.getDevices();i||o(Array.isArray(A)?A:[])}catch{}};m();const N=window.setInterval(m,5e3);return()=>{i=!0,window.clearInterval(N)}},[s]),d.useEffect(()=>{let i=!1;if(!l||w.current)return;w.current=!0;const m=N=>{const A=Number(N.screenWidth),v=Number(N.screenHeight);return{udid:N.udid,name:N.name,mjpegPort:0,aspect:re(N),screenWidth:Number.isFinite(A)&&A>0?A:void 0,screenHeight:Number.isFinite(v)&&v>0?v:void 0,platform:N.platform}};return(async()=>{var v;let N=[],A=[];try{const T=await $.getDevices();N=Array.isArray(T)?T:[];const _=N.filter(h=>_t(h,l));if(A=(await Promise.all(_.map(async h=>{try{const R=await fetch(`/xenon/api/control/${encodeURIComponent(h.udid)}/stream/status`);if(!R.ok)return null;const C=await R.json();return(C==null?void 0:C.status)==="running"?h:null}catch{return null}}))).filter(h=>h!==null).map(m),i)return;A.length>0&&t({type:"SET_TILES",tiles:A})}catch{}try{const{serverNow:T,groups:_}=await jt(),k=_[0];if(i||!k)return;const h=new Set(A.map(j=>j.udid)),R=k.recordings.filter(j=>!h.has(j.udid)).map(j=>N.find(O=>O.udid===j.udid)).filter(j=>!!j).map(m);R.length>0&&t({type:"SET_TILES",tiles:[...A,...R]});const C={};for(const j of k.annotations){let O;try{O=JSON.parse(j.geometry)}catch{continue}(C[v=j.recordingId]??(C[v]=[])).push({shape:j.shape,color:j.color,geometry:O,text:j.text??void 0})}t({type:"REHYDRATE_RECORDING",groupId:k.groupId,startedAt:Date.now()-(T-Date.parse(k.startedAt)),tileIds:Object.fromEntries(k.recordings.map(j=>[j.udid,j.id])),compositeEnabled:k.compositeEnabled,overlayAnnotations:C})}catch{}})(),()=>{i=!0}},[l,t]),d.useEffect(()=>{for(const i of e.tiles){if(i.screenWidth&&i.screenHeight)continue;const m=r.find(v=>v.udid===i.udid);if(!m)continue;const N=Number(m.screenWidth),A=Number(m.screenHeight);Number.isFinite(N)&&N>0&&Number.isFinite(A)&&A>0&&t({type:"PATCH_TILE_DIMS",udid:i.udid,screenWidth:N,screenHeight:A,aspect:re(m)})}},[r,e.tiles,t]);const g=d.useMemo(()=>new Set(e.tiles.map(i=>i.udid)),[e.tiles]),u=d.useMemo(()=>r.map(i=>Yt(i,l)),[r,l]),y=i=>{const m=Number(i.screenWidth),N=Number(i.screenHeight);return{udid:i.udid,name:i.name,mjpegPort:0,aspect:re(i),screenWidth:Number.isFinite(m)&&m>0?m:void 0,screenHeight:Number.isFinite(N)&&N>0?N:void 0,platform:i.platform}},E=async i=>{if(e.tiles.some(v=>v.udid===i)){await p(i);return}if(e.recording){t({type:"SET_ERROR_BANNER",message:"Stop recording before changing the mosaic layout."});return}const N=r.find(v=>v.udid===i);if(!N)return;t({type:"ADD_TILE",tile:y(N)});const A=await $.startStream(i).catch(()=>null);De(A)&&t({type:"REMOVE_TILE",udid:i})},p=async i=>{t({type:"REMOVE_TILE",udid:i});try{await fetch(`/xenon/api/control/${encodeURIComponent(i)}/stream/stop`,{method:"POST"})}catch{}f(m=>m+1)},b=(i,m,N)=>{if(!e.groupId)return;const A=e.groupId,v=e.startedAt?Date.now()-e.startedAt:0,T={recordingId:i,timecodeMs:v,shape:m.shape,geometry:JSON.stringify(m.geometry),color:m.color,text:m.text};a.current.enqueue(async()=>{try{return await he(A,N?{...T,image:N}:T)}catch(_){if(!N)throw _;return he(A,T)}}).catch(_=>t({type:"SET_ERROR_BANNER",message:`Annotation failed: ${_.message}`}))},I=()=>{if(!e.groupId)return;const i=e.groupId,m=e.startedAt?Date.now()-e.startedAt:0;t({type:"CLEAR_OVERLAY_ANNOTATIONS"}),a.current.enqueue(()=>Tt(i,m)).catch(()=>t({type:"SET_ERROR_BANNER",message:"Couldn't clear marks from the recording. They will still appear in the video."}))},D=()=>{for(const i of e.tiles){const m=`/xenon/api/control/${encodeURIComponent(i.udid)}/stream/stop`;try{navigator.sendBeacon?navigator.sendBeacon(m):fetch(m,{method:"POST",keepalive:!0}).catch(()=>{})}catch{}}e.tiles.forEach(i=>t({type:"REMOVE_TILE",udid:i.udid}))},M=Ot({idleAfterMs:Pt,warningSec:Lt,enabled:e.tiles.length>0,onWarning:()=>{},onTimeout:()=>{D()}});return n.jsxs(pe.Provider,{value:{state:e,dispatch:t},children:[n.jsxs("div",{className:"flex flex-col h-full p-4 gap-3",children:[n.jsxs("header",{className:"flex items-center justify-between gap-3",children:[n.jsxs("div",{className:"flex items-center gap-3",children:[n.jsx(_e,{icon:Ie,children:"Live devices"}),n.jsx(Ge,{value:e.layout,onChange:i=>t({type:"SET_LAYOUT",layout:i})})]}),n.jsx(kt,{selectedUdids:e.tiles.map(i=>i.udid),onClearMarks:I})]}),e.banner&&n.jsxs("div",{role:"alert",className:`text-sm rounded border px-3 py-2 flex items-center gap-2 ${e.banner.tone==="error"?"border-[rgb(var(--rgb-red)/0.4)] bg-[rgb(var(--rgb-red)/0.1)] text-[var(--red-100)]":"border-[rgb(var(--rgb-success)/0.4)] bg-[rgb(var(--rgb-success)/0.1)] text-[var(--text)]"}`,children:[n.jsx("span",{className:"flex-1",children:e.banner.message}),n.jsx("button",{type:"button",className:"text-xs opacity-80 hover:opacity-100",onClick:()=>t({type:"SET_BANNER",banner:null}),children:"Dismiss"})]}),n.jsxs("div",{className:"grid grid-cols-[260px_1fr] gap-3 flex-1 min-h-0",children:[n.jsxs("aside",{className:"flex flex-col gap-2 border border-[var(--border)] rounded p-3 overflow-y-auto min-h-0",children:[n.jsxs("div",{className:"flex items-center justify-between",children:[n.jsx("span",{className:"text-xs text-[var(--text-dim)]",children:"Devices"}),n.jsx("button",{className:"text-xs underline opacity-70 hover:opacity-100",onClick:()=>f(i=>i+1),children:"Refresh"})]}),n.jsx(Xe,{devices:u,inMosaic:g,onToggle:E}),n.jsx("p",{className:"mt-2 text-[11px] text-[var(--text-dim)] leading-relaxed",children:"Click a device to add it to the mosaic. Record captures every device in the mosaic. After Stop, download the video (mp4) — not a proof bundle."})]}),n.jsx("main",{className:"border border-[var(--border)] rounded p-2 overflow-y-auto h-full min-h-0",children:n.jsx(Et,{layout:e.layout,tiles:e.tiles,annotateMode:e.annotateMode,shape:e.shape,color:e.color,overlayAnnotationsByRecording:e.overlayAnnotations,onOverlayAnnotationsChange:(i,m)=>t({type:"SET_OVERLAY_ANNOTATIONS",recordingId:i,annotations:m}),onAnnotation:b,onRemove:p,onDropDevice:E})})]})]}),M.warning&&M.remainingSec!==null&&n.jsx(Mt,{remainingSec:M.remainingSec,onContinue:M.reset,onReleaseNow:D})]})}export{Gt as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.status-dot{display:inline-block;border-radius:50%;vertical-align:middle}.status-dot-ready{background:var(--status-ready-fg)}.status-dot-busy{background:var(--status-busy-fg)}.status-dot-reserved{background:var(--status-reserved-fg)}.status-dot-error{background:var(--status-error-fg)}.status-dot-offline{background:var(--status-offline-fg)}.status-code{display:inline-flex;align-items:center;gap:6px;font-family:JetBrains Mono,monospace;font-size:10px;letter-spacing:.1em;font-weight:600}.status-code-label{line-height:1}.status-code-ready{color:var(--status-ready-fg)}.status-code-busy{color:var(--status-busy-fg)}.status-code-reserved{color:var(--status-reserved-fg)}.status-code-error{color:var(--status-error-fg)}.status-code-offline{color:var(--status-offline-fg)}.kv-row{display:flex;justify-content:space-between;align-items:center;font-size:12px;min-height:18px}.kv-label{color:var(--text-muted)}.kv-value{color:var(--text);font-weight:500;min-width:0;max-width:70%;text-align:right}.kv-value-mono{font-family:JetBrains Mono,monospace;font-size:11px}.popover{z-index:9000;background:var(--surface-2);border:1px solid var(--border-strong);border-radius:var(--radius-md);box-shadow:var(--shadow-md);min-width:180px;padding:4px}.menu{display:flex;flex-direction:column;gap:0}.menu-item{display:flex;align-items:center;gap:8px;padding:6px 10px;background:transparent;border:none;border-radius:var(--radius-sm);color:var(--text);font-family:Inter,sans-serif;font-size:12px;cursor:pointer;text-align:left;width:100%}.menu-item:hover:not(:disabled){background:var(--bg);color:var(--text)}.menu-item:disabled{opacity:.4;cursor:not-allowed}.menu-item-danger{color:var(--status-error-fg)}.menu-item-icon{display:inline-flex;align-items:center;color:var(--text-muted)}.menu-divider{height:1px;background:var(--border);margin:4px 0}.reservation-modal-body{display:flex;flex-direction:column;gap:20px}.reservation-modal-body p{color:var(--text-dim);font-size:13px;line-height:1.6;margin:0}.device-id-badge{display:inline-flex;align-items:center;gap:8px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));padding:8px 16px;border-radius:6px;border:1px solid var(--border);font-family:JetBrains Mono,monospace;font-size:11px;width:fit-content;margin-bottom:12px}.reservation-input{width:100%;background-color:rgb(var(--rgb-well) / calc(.3 * var(--well-k)));border:1px solid var(--border);border-radius:6px;padding:12px 16px;color:var(--text);font-size:13px;box-sizing:border-box;transition:all .2s;font-family:JetBrains Mono,monospace}.reservation-input:focus{outline:none;border-color:var(--color-accent);box-shadow:none}.duration-selector{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:8px}.duration-option{background-color:rgb(var(--rgb-well) / calc(.3 * var(--well-k)));border:1px solid var(--border);color:var(--text-dim);padding:10px;border-radius:6px;font-size:11px;cursor:pointer;text-align:center;transition:all .2s;font-weight:800;font-family:JetBrains Mono,monospace}.duration-option:hover{border-color:var(--text-muted);background-color:rgb(var(--rgb-fg) / .02)}.duration-option.active{background-color:rgb(var(--rgb-accent) / .05);border-color:var(--color-accent);color:var(--color-accent);box-shadow:none}.btn-cancel{background:transparent;border:1px solid var(--border);color:var(--text-dim);padding:10px 24px;border-radius:6px;font-size:12px;font-weight:700;cursor:pointer;transition:all .2s}.btn-reserve{background:var(--color-accent);color:var(--bg);border:none;padding:10px 24px;border-radius:6px;font-size:12px;font-weight:800;cursor:pointer;transition:all .2s;box-shadow:none}.btn-reserve:hover:not(:disabled){background:var(--color-accent);box-shadow:none}.btn-reserve:disabled{background-color:var(--border);color:var(--text-dim);cursor:not-allowed;box-shadow:none;filter:grayscale(1);opacity:.5}.title-icon{color:var(--color-accent)}.tag-modal-body{display:flex;flex-direction:column;gap:20px}.device-id-badge{display:inline-flex;align-items:center;gap:8px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));padding:8px 16px;border-radius:6px;border:1px solid var(--border);font-family:JetBrains Mono,monospace;font-size:11px}.device-id-badge .label{color:var(--text-dim);font-weight:800;font-size:11px}.device-id-badge .value{color:var(--color-accent);font-weight:800}.tags-display-section label{display:block;font-size:11px;font-weight:800;color:var(--text-dim);margin-bottom:8px}.input-with-button{display:flex;gap:8px}.input-with-button input{flex:1;background:rgb(var(--rgb-well) / calc(.3 * var(--well-k)));border:1px solid var(--border);border-radius:6px;padding:10px 14px;color:var(--text);font-size:13px;transition:all .2s;font-family:JetBrains Mono,monospace}.input-with-button input:focus{outline:none;border-color:var(--color-accent);box-shadow:none}.add-inline-btn{background:var(--color-accent);color:var(--bg);border:none;border-radius:6px;width:40px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s}.add-inline-btn:hover:not(:disabled){background:var(--color-accent);box-shadow:none}.add-inline-btn:disabled{background:var(--border);color:var(--text-dim);cursor:not-allowed;filter:grayscale(1);opacity:.5}.tags-list{display:flex;flex-wrap:wrap;gap:8px;min-height:48px;padding:12px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border-radius:6px;border:1px dashed var(--border)}.tag-pill-editable{display:flex;align-items:center;gap:6px;background:rgb(var(--rgb-accent) / .05);color:var(--color-accent);padding:6px 12px;border-radius:6px;font-size:11px;font-weight:800;border:1px solid rgb(var(--rgb-accent) / .3);box-shadow:none}.remove-tag{background:transparent;border:none;color:var(--color-accent);cursor:pointer;padding:2px;border-radius:4px;display:flex;align-items:center;justify-content:center;transition:all .2s;opacity:.7}.remove-tag:hover{background:rgb(var(--rgb-accent) / .2);opacity:1}.btn-cancel{padding:10px 24px;border-radius:6px;background:transparent;border:1px solid var(--border);color:var(--text-dim);font-weight:700;cursor:pointer;transition:all .2s;font-size:12px}.btn-cancel:hover{color:var(--text);border-color:var(--text-muted)}.btn-save{padding:10px 24px;border-radius:6px;background:var(--color-accent);border:none;color:var(--bg);font-weight:800;cursor:pointer;transition:all .2s;box-shadow:none;font-size:12px}.btn-save:hover:not(:disabled){background:var(--color-accent);box-shadow:none}.btn-save:disabled{background-color:var(--border);color:var(--text-dim);cursor:not-allowed;box-shadow:none;filter:grayscale(1);opacity:.5}.dc2{position:relative;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:12px 14px 14px 16px;font-family:Inter,sans-serif;display:flex;flex-direction:column;gap:8px;min-height:200px;transition:border-color var(--motion-fast),box-shadow var(--motion-fast)}.dc2:hover{border-color:var(--border-strong);box-shadow:var(--shadow-md)}.dc2-stripe{position:absolute;left:0;top:12px;bottom:12px;width:2px;border-radius:0 2px 2px 0}.dc2-ready .dc2-stripe{background:var(--status-ready-fg)}.dc2-busy .dc2-stripe{background:var(--status-busy-fg)}.dc2-reserved .dc2-stripe{background:var(--status-reserved-fg)}.dc2-error .dc2-stripe{background:var(--status-error-fg)}.dc2-offline .dc2-stripe{background:var(--status-offline-fg)}.dc2-header{display:flex;justify-content:space-between;align-items:center}.dc2-platform{color:var(--text-muted);font-size:11px;font-weight:500}.dc2-name{color:var(--text);font-size:15px;font-weight:600;letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dc2-udid-row{display:flex;align-items:center;gap:6px;min-width:0}.dc2-udid{color:var(--text-dim);font-family:JetBrains Mono,monospace;font-size:11px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dc2-udid-copy{flex-shrink:0;background:transparent;border:none;color:var(--text-muted);padding:2px;border-radius:var(--radius-sm);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;transition:color var(--motion-fast),background var(--motion-fast)}.dc2-udid-copy:hover{color:var(--text);background:var(--surface-2)}.dc2-udid-copy:focus-visible{outline:2px solid var(--border-strong);outline-offset:1px}.dc2-copyable{display:inline-flex;align-items:center;gap:4px;min-width:0;max-width:100%}.dc2-copyable-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.dc2-tags{display:flex;gap:4px;flex-wrap:wrap;align-items:center}.dc2-team-pill{background:transparent;border:1px solid var(--border);font-size:11px;padding:2px 8px;border-radius:999px;color:var(--text);cursor:pointer;font-family:Inter,sans-serif;line-height:1.4;transition:border-color var(--motion-fast)}.dc2-team-pill:hover{border-color:var(--border-strong)}.dc2-team-pill:focus-visible{outline:2px solid var(--border-strong);outline-offset:1px}.dc2-metrics{background:var(--bg);border-radius:var(--radius-sm);padding:10px 12px;display:flex;flex-direction:column;gap:6px;margin-top:auto}.dc2-banner{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:600;padding:3px 8px;border-radius:var(--radius-sm);font-family:Inter,sans-serif;width:fit-content}.dc2-banner-reserved{color:var(--status-reserved-fg);background:var(--status-reserved-bg)}.dc2-banner-session{color:var(--status-busy-fg);background:var(--status-busy-bg)}.dc2-actions{display:flex;gap:6px;align-items:center}.dc2-primary{flex:1;justify-content:center}.dc2-more{background:transparent;border:1px solid var(--border);color:var(--text-muted);border-radius:var(--radius-md);width:32px;height:26px;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:background var(--motion-fast),color var(--motion-fast)}.dc2-more:hover{background:var(--surface-2);color:var(--text)}.dc2-health{display:flex;gap:6px;margin-top:4px;flex-wrap:wrap}.device-explorer-card-container{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px;padding:16px;flex:1}.device-explorer-card-container::-webkit-scrollbar{width:6px}.device-explorer-card-container::-webkit-scrollbar-thumb{background:var(--border);border-radius:8px}.device-explorer-container{display:flex;flex-direction:column;width:100%;gap:var(--space-4)}.device-explorer-header-container{display:flex;align-items:center;justify-content:space-between;padding:4px 24px;background:#0f0f1ae6;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border-bottom:2px solid var(--border);position:sticky;top:0;z-index:15;gap:var(--space-8);flex-wrap:nowrap;box-shadow:0 10px 30px rgb(var(--rgb-black) / calc(.4 * var(--shadow-k)))}.device-explorer-header-left-container{display:flex;align-items:center;gap:24px;flex:1;min-width:0}.device-explorer-header-entry{display:flex;flex-direction:column;gap:4px;min-width:0}.device-explorer-header-entry-header{font-size:11px;font-weight:700;color:var(--text-dim)}.device-explorer-header-value{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.device-explorer-header-value>.device-explorer-header__platform-btn+.device-explorer-header__platform-btn{margin-left:4px}.device-explorer-header__platform-btn,.device-explorer-header__device-state{display:flex;align-items:center;gap:6px;padding:6px 12px;border-radius:6px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border:1px solid var(--border);color:var(--text-muted);font-size:12px;font-weight:600;cursor:pointer;transition:all .2s ease}.device-explorer-header__platform-btn:hover,.device-explorer-header__device-state:hover{background:rgb(var(--rgb-fg) / .03);color:var(--text);border-color:var(--border)}.device-explorer-header__platform-btn.selected,.device-explorer-header__device-state.selected{background:rgb(var(--rgb-accent) / .05);color:var(--color-accent);border-color:rgb(var(--rgb-accent) / .3);box-shadow:none}.device-explorer-header__device-state.ready.selected{border-color:var(--color-success);box-shadow:none}.device-explorer-header__device-state.busy.selected{background:rgb(var(--rgb-amber-alt) / .05);color:var(--status-busy-fg);border-color:rgb(var(--rgb-amber-alt) / .3);box-shadow:none}.device-explorer-header__device-state.offline.selected{background:#4a4a6a1a;color:var(--text-dim);border-color:var(--text-dim)}.device-explorer-search-wrapper{position:relative;width:320px}.device-explorer-search-icon{position:absolute;left:12px;top:50%;transform:translateY(-50%);pointer-events:none;opacity:.5}.device-explorer-header-text-filter{width:100%;height:32px;padding:0 12px 0 36px;border-radius:6px;border:1px solid var(--border);background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));font-family:JetBrains Mono,monospace;font-size:12px;color:var(--text);transition:all .2s ease}.device-explorer-header-text-filter:focus{outline:none;border-color:var(--color-accent);background:rgb(var(--rgb-well) / calc(.6 * var(--well-k)));box-shadow:none}.device-explorer-header-text-filter::placeholder{color:var(--text-dim);font-size:11px}.device-explorer-header-right-container{display:flex;align-items:center;gap:12px}.device-explorer-header-filter-count{display:flex;align-items:center;gap:8px;padding-right:16px;border-right:1px solid var(--border)}@media (max-width: 1024px){.device-explorer-header-container{flex-direction:column;align-items:stretch;gap:var(--space-4);padding:var(--space-4)}.device-explorer-header-left-container{flex-wrap:wrap;gap:var(--space-4)}.device-explorer-header-entry{flex:1;min-width:120px}.device-explorer-search-wrapper{width:100%}.device-explorer-header-right-container{justify-content:space-between;width:100%}}@media (max-width: 640px){.device-explorer-header-left-container{display:flex;flex-direction:column;align-items:stretch;gap:var(--space-3)}.device-explorer-header-entry,.device-explorer-header-value,.device-explorer-header-filter-count{width:100%;min-width:0}.device-explorer-header-filter-count{padding-right:0;border-right:none;justify-content:flex-start}.device-explorer-header-right-container{flex-direction:row;flex-wrap:wrap;align-items:center;gap:var(--space-2);width:100%}}.device-explorer-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:80px 40px;background:#0f0f1a66;border:1px dashed var(--border);border-radius:var(--radius-md);text-align:center;margin:60px auto 40px;max-width:600px;gap:var(--space-4)}.device-explorer-empty-icon{width:64px;height:64px;background:rgb(var(--rgb-accent) / .05);border-radius:50%;display:flex;align-items:center;justify-content:center;color:var(--color-accent);margin-bottom:8px;border:1px solid rgb(var(--rgb-accent) / .1)}.device-explorer-empty h3{font-size:1.5rem;font-weight:700;color:var(--text);margin:0;font-family:Outfit,sans-serif}.device-explorer-empty p{color:var(--text-muted);font-size:14px;max-width:400px;line-height:1.6;margin:0}.device-explorer-empty .Button{margin-top:8px}.device-control-modal-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:var(--bg);z-index:6000;display:flex;flex-direction:column;padding:0;margin:0;animation:modal-fade-in .25s ease-out}.device-control-modal{flex:1;width:100%;height:100%;overflow:hidden;display:flex;flex-direction:column;background:var(--bg)}@keyframes modal-fade-in{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.de2-sticky-group{position:sticky;top:0;z-index:15;background:var(--bg);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);box-shadow:0 6px 16px -8px rgb(var(--rgb-black) / calc(.5 * var(--shadow-k)))}.de2-toolbar{display:flex;gap:10px;align-items:center;padding:12px 20px;border-bottom:1px solid var(--border);background:transparent;box-shadow:none;flex-wrap:wrap}.de2-search{flex:1;min-width:200px;height:28px;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:0 10px;color:var(--text);font-family:Inter,sans-serif;font-size:12px;outline:none}.de2-search::placeholder{color:var(--text-dim)}.de2-search:focus{border-color:var(--border-strong)}.device-explorer-empty h3{color:var(--text);font-family:Inter,sans-serif;font-weight:700;letter-spacing:-.01em}:root[data-theme=light] .device-explorer-header-container{background:rgb(var(--rgb-white) / .9)}:root[data-theme=light] .device-explorer-empty{background:var(--surface-2)}.device-control-view{display:flex;flex-direction:column;height:100%;width:100%;background:var(--bg);color:var(--text);overflow:hidden;font-family:Inter,sans-serif}*{scrollbar-width:thin;scrollbar-color:var(--border) transparent}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:8px;-webkit-transition:background .2s;transition:background .2s}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}.control-view-top-bar{display:flex;align-items:center;padding:0 24px;height:64px;background:var(--surface);border-bottom:2px solid var(--border);gap:24px;z-index:100;position:relative}.device-info-mini{display:flex;align-items:center;gap:16px}.device-pill{font-size:11px;font-weight:800;padding:2px 10px;border-radius:6px}.platform-pill{background:rgb(var(--rgb-accent) / .05);color:var(--color-accent);border:1px solid rgb(var(--rgb-accent) / .2)}.version-pill{background:rgb(var(--rgb-amber-alt) / .05);color:var(--status-busy-fg);border:1px solid rgb(var(--rgb-amber-alt) / .2)}.reserved-pill{background:rgb(var(--rgb-sky-400) / .1);color:var(--sky-400);border:1px solid rgb(var(--rgb-sky-400) / .3);animation:pulse-reserved-pill 2s infinite ease-in-out}.device-name-text{font-family:Outfit,sans-serif;font-weight:800;font-size:14px;color:var(--text)}.code-font{font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-dim);background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));padding:4px 10px;border-radius:6px;border:1px solid var(--border)}.udid-chip{display:inline-flex;align-items:center;gap:6px;padding:3px 4px 3px 10px;font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-dim);background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border-radius:6px;border:1px solid var(--border);max-width:280px}.udid-chip__value{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.udid-chip__copy{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border:none;background:transparent;border-radius:4px;color:var(--text-muted);cursor:pointer;transition:background .15s,color .15s;flex-shrink:0}.udid-chip__copy:hover{background:rgb(var(--rgb-fg) / .05);color:var(--color-accent)}.back-to-devices-btn{background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));color:var(--text-dim);border:1px solid var(--border);padding:8px 16px;border-radius:6px;font-size:11px;font-weight:800;display:flex;align-items:center;gap:8px;transition:all .2s;cursor:pointer}.back-to-devices-btn:hover{background:rgb(var(--rgb-fg) / .03);border-color:var(--color-accent);color:var(--color-accent)}.control-view-main{display:flex;flex-direction:row;flex:1;overflow:hidden;padding:24px;gap:32px;background:var(--bg);justify-content:center;align-items:stretch;min-height:0}.control-view-main.is-landscape{align-items:flex-start}.control-view-main.omni-mode{gap:20px}.control-view-main.omni-mode .device-preview-column{min-width:0;flex-shrink:1}.control-view-main.omni-mode .device-stream-canvas{max-width:100%;max-height:100%}.device-preview-column{display:flex;flex-direction:row-reverse;align-items:center;justify-content:center;gap:24px;flex-shrink:1;min-width:0;max-width:42%}.control-view-main.is-landscape .device-preview-column{max-width:none;flex-direction:column}.device-screen-wrapper{position:relative;padding:12px;background:var(--black);border-radius:48px;box-shadow:0 0 0 2px #334155,0 20px 50px rgb(var(--rgb-black) / calc(.6 * var(--shadow-k)));border:1px solid rgb(var(--rgb-white) / .1);transition:all .5s cubic-bezier(.16,1,.3,1)}.device-screen-wrapper:hover{transform:translateY(-4px) scale(1.005);box-shadow:0 0 0 2px var(--color-accent),0 30px 60px rgb(var(--rgb-black) / calc(.8 * var(--shadow-k)))}.device-stream-canvas{position:relative;background:var(--black);border-radius:28px;overflow:hidden;cursor:crosshair;transition:box-shadow .3s ease,border-color .3s ease;outline:none;border:2px solid transparent;user-select:none;-webkit-user-select:none}.device-stream-canvas.focused{border-color:var(--color-accent);box-shadow:none}.device-stream-image{pointer-events:none;-webkit-user-select:none;user-select:none;-webkit-user-drag:none}.device-stream-placeholder{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;width:100%;color:var(--text-muted);gap:16px;background:radial-gradient(circle at center,var(--surface) 0%,var(--bg) 100%)}.device-screen-off{position:absolute;top:0;right:0;bottom:0;left:0;z-index:10;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;padding:16px;text-align:center;color:var(--text-muted);background:rgb(var(--rgb-black) / .55);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.device-screen-off p{margin:6px 0 0;font-size:13px;font-weight:600;color:var(--text)}.device-screen-off span{font-size:11px;line-height:1.5;opacity:.75;max-width:220px}.device-screen-off button{margin-top:10px}.device-footer-actions{display:flex;flex-direction:column;flex-wrap:wrap;align-content:center;justify-content:center;width:auto;flex-shrink:0;background:color-mix(in srgb,var(--surface-2) 80%,transparent);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-radius:16px;border:1px solid rgb(var(--rgb-fg) / .08);padding:6px;gap:6px;box-shadow:0 10px 25px -5px rgb(var(--rgb-black) / calc(.4 * var(--shadow-k)))}.footer-action-btn{flex:0 0 auto;display:flex;align-items:center;justify-content:center;gap:8px;width:36px;height:36px;padding:0;color:var(--text-muted);font-size:11px;font-weight:700;border:none;background:transparent;border-radius:var(--radius-sm);transition:all .2s ease}.footer-action-btn:hover{background:rgb(var(--rgb-fg) / .05);color:var(--text)}.footer-action-btn.active{background:rgb(var(--rgb-fg) / .04);color:var(--color-accent);box-shadow:inset 0 -2px 0 0 var(--color-accent)}.footer-divider{width:24px;height:1px;background:var(--border);margin:4px auto;flex-shrink:0}.control-view-main.is-landscape .device-footer-actions{flex-direction:row;width:100%}.control-view-main.is-landscape .footer-divider{width:1px;height:24px;margin:auto 4px}.hint-text{font-size:11px;color:var(--text-muted);font-style:italic;margin-top:4px}.device-interactions-column{flex:1;display:flex;flex-direction:column;gap:0;min-width:450px;max-width:1200px;height:100%;overflow:hidden;min-height:0}.interaction-tabs{display:flex;gap:4px;background:var(--surface);padding:4px;border-radius:6px;border:1px solid var(--border);margin-bottom:16px;flex-shrink:0}.tab-btn{flex:1 1 0;min-width:0;display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:8px 6px;background:transparent;border:none;font-size:11px;font-weight:800;color:var(--text-dim);border-radius:4px;cursor:pointer;transition:all .2s;white-space:nowrap}.tab-btn>svg{flex-shrink:0;opacity:.7;transition:opacity .15s}.tab-btn>span{min-width:0;overflow:hidden;text-overflow:ellipsis}.tab-btn:hover>svg,.tab-btn.active>svg{opacity:1}.tab-btn:hover{color:var(--text);background:rgb(var(--rgb-fg) / .02)}.tab-btn.active{color:var(--bg);background:var(--color-accent);box-shadow:none}.interactions-scroll-area{flex:1;overflow-y:auto;overflow-x:hidden;padding-right:8px;display:flex;flex-direction:column}.action-card{background:rgb(var(--rgb-well) / calc(.2 * var(--well-k)));border-radius:6px;padding:20px;border:1px solid var(--border);transition:all .2s;display:flex;flex-direction:column;gap:16px}.action-card:hover{background:rgb(var(--rgb-fg) / .01);border-color:var(--color-accent);box-shadow:0 4px 20px rgb(var(--rgb-black) / calc(.4 * var(--shadow-k)))}.action-card-title{font-family:Outfit,sans-serif;font-size:13px;font-weight:800;color:var(--text);display:flex;align-items:center;gap:12px;opacity:.9}.compact-label{font-size:11px;color:var(--text-muted);font-weight:600}.action-card-hint{margin:0 0 4px;font-size:12px;color:var(--text-muted);line-height:1.5}.actions-grid{display:flex;flex-direction:column;gap:16px}.btn-sm{padding:8px 16px;font-size:11px}.type-input-field.compact{padding:10px;font-size:13px}.file-select-box.compact{padding:var(--space-4);margin-bottom:8px}.clipboard-display.compact{min-height:48px;max-height:80px;overflow-y:auto;padding:8px;font-size:11px;background:rgb(var(--rgb-well) / calc(.3 * var(--well-k)))}.clipboard-row{display:flex;gap:12px;align-items:stretch}.clipboard-row>button{width:140px;flex-shrink:0}.clipboard-row>.clipboard-display.compact{flex:1;margin-top:0}.dpad-caption{opacity:.5}.actions-row{display:flex;gap:var(--space-8)}.install-app-section,.uninstall-app-section{flex:1;display:flex;flex-direction:column;gap:12px;min-width:0}.file-select-box{background:rgb(var(--rgb-fg) / .03);border:2px dashed var(--border);border-radius:var(--radius-md);padding:var(--space-8);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-4);transition:all .3s ease}.file-select-box:hover{background:rgb(var(--rgb-accent) / .05);border-color:var(--color-accent)}.btn-premium,.btn-secondary{padding:10px 20px;border-radius:var(--radius-sm);font-weight:700;font-size:11px;cursor:pointer;transition:all .2s cubic-bezier(.16,1,.3,1);display:flex;align-items:center;justify-content:center;gap:8px;border:none}.btn-premium{background:var(--color-accent);color:var(--color-on-accent)}.btn-premium:hover:not(:disabled){background:var(--color-accent-strong);transform:translateY(-1px);box-shadow:none}.btn-secondary{background:rgb(var(--rgb-fg) / .05);color:var(--text);border:1px solid var(--border)}.btn-secondary:hover:not(:disabled){background:rgb(var(--rgb-fg) / .1);color:var(--text);border-color:var(--text-muted)}.btn-secondary.active{background:var(--primary-soft);color:var(--color-accent);border-color:var(--color-accent)}.btn-sm{padding:6px 12px!important;font-size:11px!important}.type-input-field{width:100%;padding:10px 14px;border-radius:var(--radius-sm);border:1px solid var(--border);background:rgb(var(--rgb-well) / calc(.3 * var(--well-k)));font-size:13px;color:var(--text);transition:all .2s ease}.type-input-field:focus{outline:none;border-color:var(--color-accent);background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));box-shadow:0 0 0 3px var(--primary-soft)}.clipboard-display{background:#161b22b3;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border-radius:var(--radius-md);border:1px solid var(--border);padding:var(--space-4);margin-top:var(--space-4);font-family:Fira Code,monospace;font-size:12px;color:var(--sky-400);min-height:80px;box-shadow:inset 0 2px 10px rgb(var(--rgb-black) / calc(.5 * var(--shadow-k)))}.animate-pulse{animation:pulse-op 1.5s infinite}@keyframes pulse-op{0%,to{opacity:1}50%{opacity:.4}}.tab-content{animation:slideUpFade .4s cubic-bezier(.16,1,.3,1);display:flex;flex-direction:column;flex:1;min-height:0}@keyframes slideUpFade{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}.gestures-grid-container{display:flex;flex-direction:column;align-items:center;gap:12px}.gestures-dpad{display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);gap:8px;width:140px;height:140px;padding:12px;background:rgb(var(--rgb-well) / calc(.2 * var(--well-k)));border-radius:50%;border:1px solid rgb(var(--rgb-fg) / .05)}.dpad-btn{display:flex;align-items:center;justify-content:center;background:rgb(var(--rgb-fg) / .03);border:1px solid rgb(var(--rgb-fg) / .05);border-radius:8px;color:var(--text-muted);cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.dpad-btn:hover{background:var(--color-accent);border-color:var(--color-accent);color:var(--color-on-accent);transform:scale(1.1);box-shadow:none;z-index:2}.dpad-btn:active{transform:scale(.95)}.dpad-center{background:radial-gradient(circle,var(--accent-subtle) 0%,transparent 70%);border-radius:50%;opacity:.2}.app-mgmt-content{display:flex;flex-direction:row;gap:var(--space-6);align-items:stretch;--app-mgmt-control-h: 34px}.install-section,.uninstall-section{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:8px}.upload-box-row,.uninstall-controls-row{display:flex;gap:12px;align-items:center}.upload-box-row>*,.uninstall-controls-row>*{height:var(--app-mgmt-control-h)}.upload-box-row,.uninstall-controls-row{flex-wrap:wrap;row-gap:8px}.uninstall-controls-row .select-wrapper,.upload-box-row .file-upload-launcher{flex:1 1 150px;min-width:0}.uninstall-controls-row .select-wrapper>select{height:100%}.upload-box-row>button,.uninstall-controls-row>button{flex:0 0 auto}.app-mgmt-content .hint-text{margin-top:auto}.file-upload-launcher{flex:1;min-width:0;display:flex;align-items:center;gap:12px;white-space:nowrap;overflow:hidden;padding:0 16px;background:rgb(var(--rgb-fg) / .03);border:1px dashed var(--border);border-radius:var(--radius-md);cursor:pointer;font-size:13px;color:var(--text-muted);transition:all .2s ease}.file-upload-launcher>svg{flex:none}.file-upload-launcher>span{min-width:0;overflow:hidden;text-overflow:ellipsis}.file-upload-launcher:hover{background:rgb(var(--rgb-accent) / .05);border-color:var(--color-accent);color:var(--text)}.divider-v{width:1px;align-self:stretch;background:linear-gradient(180deg,transparent,var(--border),transparent)}.select-wrapper{flex:1;position:relative;display:flex;align-items:center}.select-loader{position:absolute;right:32px;color:var(--color-accent)}.btn-destructive{background:var(--status-error-fg);color:var(--white);border:1px solid transparent;padding:10px 20px;border-radius:var(--radius-sm);font-weight:700;font-size:11px;display:flex;align-items:center;gap:8px;cursor:pointer;transition:background .2s ease,transform .2s ease,box-shadow .2s ease}.btn-destructive:hover:not(:disabled){background:var(--red-600);transform:translateY(-1px);box-shadow:none}.btn-destructive:disabled{opacity:.5;cursor:not-allowed}.manual-input-box{margin-top:8px;padding-top:8px;border-top:1px solid rgb(var(--rgb-fg) / .05)}.type-input-field.tiny{padding:8px 12px;font-size:12px;opacity:.6}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.action-card-header{display:flex;justify-content:flex-end;align-items:flex-start;margin-bottom:12px}.screenshot-workspace{display:flex;gap:20px;flex:1;min-height:0;overflow:hidden}.screenshot-gallery-sidebar{width:180px;display:flex;flex-direction:column;gap:16px;flex-shrink:0;min-height:0}.screenshot-workspace.is-empty .screenshot-main-preview{display:none}.screenshot-workspace.is-empty .screenshot-gallery-sidebar{width:100%;align-items:center;justify-content:center;gap:24px}.screenshot-workspace.is-empty .screenshot-thumbnails-list{order:1;flex:none;overflow:visible}.screenshot-workspace.is-empty .take-screenshot-btn{order:2;width:auto;min-width:200px;flex:none}.take-screenshot-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%}.screenshot-thumbnails-list{flex:1;overflow-y:auto;display:flex;flex-direction:column;gap:10px;padding-right:4px;min-height:0}.screenshot-thumb-item{position:relative;border-radius:8px;overflow:hidden;aspect-ratio:9/16;background:rgb(var(--rgb-black) / .4);border:2px solid transparent;cursor:pointer;transition:all .2s ease;flex-shrink:0}.screenshot-thumb-item:hover{border-color:rgb(var(--rgb-accent) / .4)}.screenshot-thumb-item.active{border-color:var(--color-accent);box-shadow:none}.screenshot-thumb-item img{width:100%;height:100%;object-fit:cover;opacity:.7;transition:opacity .2s ease}.screenshot-thumb-item:hover img,.screenshot-thumb-item.active img{opacity:1}.thumb-time{position:absolute;bottom:0;left:0;right:0;background:rgb(var(--rgb-black) / .7);color:#fff;font-size:11px;padding:2px 4px;text-align:center;font-family:JetBrains Mono,monospace}.thumb-delete-btn{position:absolute;top:4px;right:4px;width:20px;height:20px;border-radius:4px;background:rgb(var(--rgb-red) / .8);color:#fff;border:none;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease}.screenshot-thumb-item:hover .thumb-delete-btn{opacity:1}.thumb-delete-btn:hover{background:var(--status-error-fg)}.screenshot-main-preview{flex:1;background:rgb(var(--rgb-black) / .3);border-radius:8px;display:flex;align-items:center;justify-content:center;overflow:hidden;position:relative;border:1px solid rgb(var(--rgb-white) / .05);min-height:0}.preview-container{display:flex;flex-direction:column;width:100%;height:100%;position:relative}.preview-image-wrapper{flex:1;position:relative;min-height:0}.preview-image-wrapper img{position:absolute;top:20px;bottom:20px;left:20px;right:20px;max-width:calc(100% - 40px);max-height:calc(100% - 40px);object-fit:contain;margin:auto;border-radius:4px;box-shadow:0 10px 40px rgb(var(--rgb-black) / calc(.5 * var(--shadow-k)))}.preview-footer{padding:16px 24px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border-top:1px solid rgb(var(--rgb-fg) / .05);display:flex;justify-content:space-between;align-items:center}.preview-meta{display:flex;align-items:center;gap:8px;font-size:11px;color:var(--text-muted)}.meta-label{font-weight:700;opacity:.5}.meta-divider{opacity:.2}.preview-actions{display:flex;gap:12px}.btn-text-only{background:transparent;border:none;color:var(--text-muted);font-size:11px;font-weight:700;letter-spacing:.05em;cursor:pointer;padding:4px 8px;border-radius:4px}.btn-text-only:hover{color:var(--red);background:rgb(var(--rgb-red) / .05)}.empty-gallery-state{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:24px 12px;color:var(--text-muted);font-size:11px;text-align:center}.empty-gallery-icon{opacity:.4}.empty-gallery-title{font-weight:700;font-size:12px;color:var(--text);margin:0}.empty-gallery-hint{margin:0;font-size:11px;color:var(--text-muted);line-height:1.4;max-width:160px}.empty-gallery-hint strong{color:var(--color-accent);font-weight:700}.interactions-scroll-area.terminal-mode{overflow:hidden;padding:0;display:flex;flex-direction:column;height:100%;min-height:0}.omni-inspector-tab-wrapper{flex:1;min-height:0;display:flex;flex-direction:column}.interactions-scroll-area.terminal-mode .action-card.full-height{height:100%;min-height:0;border-radius:0;border:none}.interactions-scroll-area.screenshot-mode{overflow:hidden;height:100%;min-height:0;display:flex;flex-direction:column;padding:0}.interactions-scroll-area.screenshot-mode .tab-content{display:flex;flex-direction:column;flex:1 1 0%;min-height:0;padding:0}.interactions-scroll-area.screenshot-mode .action-card.screenshot-card{display:flex;flex-direction:column;flex:1;min-height:0;margin-bottom:0;border-radius:0;border:none;padding:0;overflow:hidden}@media (max-width: 900px){.control-view-main{flex-direction:column;padding:16px;gap:16px;overflow-y:auto}.device-preview-column{min-width:0;width:100%;max-width:420px;margin:0 auto}.device-interactions-column{width:100%;max-width:100%;min-width:0}}.device-stream-canvas.is-inspecting{cursor:crosshair}:root[data-theme=light] .clipboard-display{background:var(--surface-2)}.terminal-container{display:flex;flex-direction:column;background-color:var(--bg);color:var(--text);font-family:JetBrains Mono,monospace;border-radius:6px;overflow:hidden;height:100%;max-height:100%;width:100%;min-height:0;border:1px solid var(--border);box-shadow:0 20px 50px rgb(var(--rgb-black) / calc(.5 * var(--shadow-k)));position:relative}.terminal-header{display:flex;align-items:center;justify-content:space-between;padding:12px 20px;background-color:rgb(var(--rgb-black) / .4);border-bottom:2px solid var(--border)}.terminal-controls{display:flex;gap:8px;width:60px}.dot{width:8px;height:8px;border-radius:4px;border:1px solid rgb(var(--rgb-fg) / .1)}.dot.red{background-color:var(--red-alt)}.dot.yellow{background-color:#fc0}.dot.green{background-color:var(--color-accent)}.terminal-title{font-size:11px;font-weight:800;color:var(--text-dim)}.terminal-actions{display:flex;justify-content:flex-end;width:60px}.terminal-action-btn{background:transparent;border:1px solid var(--border);color:var(--text-dim);font-size:11px;font-weight:800;padding:4px 10px;border-radius:6px;cursor:pointer;transition:all .2s}.terminal-action-btn:hover{color:var(--text);background:rgb(var(--rgb-white) / .05);border-color:var(--text-muted)}.terminal-history{flex:1;overflow-y:auto;overflow-x:hidden;padding:20px;font-size:12px;line-height:1.6;scrollbar-width:thin;scrollbar-color:var(--color-accent) var(--bg);min-height:0}.terminal-history::-webkit-scrollbar{width:6px}.terminal-history::-webkit-scrollbar-track{background:transparent}.terminal-history::-webkit-scrollbar-thumb{background-color:var(--border);border-radius:4px}.terminal-history::-webkit-scrollbar-thumb:hover{background-color:var(--color-accent)}.terminal-line{margin-bottom:6px;white-space:pre-wrap;word-break:normal;overflow-wrap:anywhere}.terminal-line.command{color:var(--color-accent);font-weight:600}.terminal-line.output{color:var(--text)}.terminal-line.error{color:var(--red-alt)}.terminal-line.system{color:var(--text-dim);font-style:italic;border-bottom:1px dashed var(--border);padding-bottom:6px;margin-bottom:12px}.terminal-input-area{display:flex;align-items:center;padding:16px 20px;background-color:rgb(var(--rgb-black) / .4);border-top:2px solid var(--border)}.terminal-prompt{color:var(--color-accent);margin-right:12px;font-weight:800;-webkit-user-select:none;user-select:none}.terminal-input{flex:1;background:transparent;border:none;color:var(--text);font-family:inherit;font-size:13px;outline:none;font-weight:500}.terminal-input::placeholder{color:rgb(var(--rgb-white) / .1)}.terminal-loading-indicator{display:inline-block;width:8px;height:16px;background-color:var(--color-accent);animation:blink 1s step-end infinite;vertical-align:middle;margin-left:8px;border-radius:4px}@keyframes blink{0%,to{opacity:1}50%{opacity:0}}.omni-inspector-container{display:flex;flex-direction:column;height:100%;background:var(--bg);color:var(--text);font-family:Inter,sans-serif;overflow:hidden;position:relative}.omni-main-content{flex:1;display:flex;gap:16px;padding:16px;overflow:hidden;height:100%}.omni-screenshot-panel{width:380px;min-width:320px;flex-shrink:0;display:flex;flex-direction:column;background:var(--surface);border-radius:6px;border:1px solid var(--border);overflow:hidden}.omni-screenshot-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:rgb(var(--rgb-black) / .4);border-bottom:2px solid var(--border)}.omni-screenshot-title{font-size:11px;font-weight:800;color:var(--text);opacity:.9}.omni-mode-toggle{display:flex;background:rgb(var(--rgb-well) / calc(.3 * var(--well-k)));padding:2px;border-radius:6px;border:1px solid var(--border)}.omni-mode-btn{display:flex;align-items:center;gap:6px;padding:4px 10px;background:transparent;border:none;border-radius:4px;color:var(--text-dim);font-size:11px;font-weight:800;cursor:pointer;transition:all .2s}.omni-mode-btn.active{background:var(--color-accent);color:var(--bg);box-shadow:none}.omni-refresh-btn{display:flex;align-items:center;gap:6px;padding:6px 12px;background:var(--color-accent);color:var(--bg);border:none;border-radius:6px;font-size:11px;font-weight:800;cursor:pointer;transition:all .2s}.omni-refresh-btn:hover:not(:disabled){background:var(--color-accent);box-shadow:none}.omni-refresh-btn:disabled{opacity:.5;cursor:not-allowed}.omni-screenshot-container{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;padding:12px;background:#161b22b3;position:relative;overflow:hidden}.omni-screenshot-wrapper{position:relative;max-width:100%;max-height:100%;height:100%;display:flex;align-items:center;justify-content:center;-webkit-user-select:none;user-select:none}.omni-screenshot-wrapper.interactable{cursor:crosshair}.omni-screenshot-img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;border-radius:4px;display:block}.omni-overlay{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}.omni-overlay>*{pointer-events:auto}.omni-hit-area{position:absolute;cursor:pointer;background:transparent;transition:background .15s ease}.omni-hit-area:hover{background:rgb(var(--rgb-accent) / .2)}.omni-frame-hover{position:absolute;border:2px solid var(--color-accent);background:rgb(var(--rgb-accent) / .1);pointer-events:none;border-radius:6px}.omni-frame-select{position:absolute;border:2px solid var(--color-accent);background:rgb(var(--rgb-accent) / .2);pointer-events:none;box-shadow:none;border-radius:6px}.omni-frame-match{position:absolute;pointer-events:none;border-radius:6px;border-style:dashed;border-width:2px;animation:omni-match-pulse 1.6s ease-out 1}.omni-frame-match.unique{border-color:var(--color-success);background:rgb(var(--rgb-success) / .12);box-shadow:none}.omni-frame-match.multi{border-color:var(--amber, var(--amber));background:rgb(var(--rgb-amber) / .1);box-shadow:none}@keyframes omni-match-pulse{0%{opacity:0;transform:scale(.96)}35%{opacity:1;transform:scale(1)}to{opacity:1;transform:scale(1)}}.omni-loading-overlay{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:rgb(var(--rgb-black) / .8);color:var(--text-muted);font-size:11px}.omni-spinner{width:24px;height:24px;border:2px solid var(--border);border-top-color:var(--color-accent);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.omni-empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;color:var(--text-muted);text-align:center;padding:32px;font-size:12px}.omni-empty-state svg{opacity:.3}.omni-empty-state.small{padding:24px;font-size:11px}.omni-tree-panel{flex:1;min-width:0;display:flex;flex-direction:column;background:rgb(var(--rgb-well) / calc(.2 * var(--well-k)));border-radius:6px;border:1px solid var(--border);overflow:hidden;min-height:0}.omni-tree-content{flex:1;min-height:0;overflow-y:auto;padding:8px;scrollbar-width:thin;scrollbar-color:var(--border) transparent}.omni-tree-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;row-gap:8px;column-gap:8px;padding:12px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border-bottom:2px solid var(--border)}.omni-tree-title{display:flex;align-items:center;gap:8px;font-size:11px;font-weight:800;color:var(--text);opacity:.9}.omni-count-badge{white-space:nowrap;font-size:11px;background:rgb(var(--rgb-accent) / .05);color:var(--color-accent);padding:2px 8px;border-radius:6px;font-weight:800}.omni-action-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;background:rgb(var(--rgb-fg) / .02);border:1px solid var(--border);border-radius:6px;color:var(--text-dim);cursor:pointer;transition:all .2s}.omni-action-btn:hover{background:rgb(var(--rgb-fg) / .05);color:var(--color-accent);border-color:var(--color-accent)}.omni-tree-search{display:flex;align-items:center;gap:8px;margin:12px;padding:8px 12px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border:1px solid var(--border);border-radius:6px;transition:all .2s}.omni-tree-search:focus-within{border-color:var(--color-accent);box-shadow:none}.omni-tree-search input{flex:1;background:transparent;border:none;color:var(--text);font-size:11px;outline:none;font-family:JetBrains Mono,monospace}.tree-item{display:flex;align-items:center;gap:8px;padding:8px 12px;margin-bottom:2px;border-radius:4px;cursor:pointer;font-size:12px;color:var(--text-dim);transition:all .15s;border:1px solid transparent;min-height:36px;background:rgb(var(--rgb-well) / calc(.1 * var(--well-k)))}.tree-item:hover{background:rgb(var(--rgb-fg) / .02);color:var(--text)}.tree-item.selected{background:rgb(var(--rgb-accent) / .08);color:var(--color-accent);border-color:rgb(var(--rgb-accent) / .4);box-shadow:inset 0 0 0 1px rgb(var(--rgb-accent) / .2)}.tree-item.hovered:not(.selected){background:rgb(var(--rgb-fg) / .04);border-color:rgb(var(--rgb-fg) / .1);color:var(--text)}.tree-node{display:flex;flex-direction:column}.tree-children{margin-left:0}.tree-toggle{display:flex;align-items:center;justify-content:center;width:18px;height:18px;border:none;background:transparent;color:var(--text-muted);cursor:pointer;border-radius:3px;flex-shrink:0;padding:0;transition:color .15s,background .15s}.tree-toggle:hover{color:var(--color-accent);background:rgb(var(--rgb-accent) / .1)}.tree-toggle-spacer{display:inline-block;width:18px;flex-shrink:0}.tree-item-indent{flex-shrink:0}.tree-icon{color:var(--text-muted);flex-shrink:0;opacity:.6}.tree-label{flex:1;font-size:12px;font-family:JetBrains Mono,Fira Code,monospace;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tree-badge{font-size:10px;font-weight:700;background:rgb(var(--rgb-fg) / .06);color:var(--text-muted);padding:1px 5px;border-radius:4px;flex-shrink:0;font-family:JetBrains Mono,monospace}.omni-details-panel{flex:1;min-width:280px;max-width:360px;display:flex;flex-direction:column;background:var(--surface);border-radius:6px;border:1px solid var(--border);overflow:hidden;min-height:0}.omni-details-content{flex:1;min-height:0;overflow-y:auto;padding:16px;scrollbar-width:thin;scrollbar-color:var(--border) transparent}.omni-header-left{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.omni-tree-actions{display:flex;gap:6px;align-items:center;flex-shrink:0;margin-left:auto}.omni-clear-btn{background:transparent;border:none;color:var(--text-muted);cursor:pointer;font-size:16px;padding:0 4px;line-height:1;border-radius:3px}.omni-clear-btn:hover{color:var(--text);background:rgb(var(--rgb-fg) / .08)}.omni-info-table,.omni-locators-list{display:flex;flex-direction:column;gap:6px}.omni-details-header{display:flex;align-items:center;gap:8px;padding:12px 16px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border-bottom:2px solid var(--border);font-size:11px;font-weight:800;color:var(--text);opacity:.9}.omni-section{margin-bottom:24px}.omni-section-header{font-size:11px;font-weight:800;color:var(--text-dim);margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid var(--border)}.omni-info-row{display:flex;gap:16px;padding:12px 16px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border-radius:6px;border:1px solid var(--border);min-height:44px;align-items:center}.omni-info-key{width:60px;flex-shrink:0;font-size:11px;font-weight:800;color:var(--text-dim)}.omni-info-value{flex:1;font-size:11px;color:var(--text);word-break:break-all}.omni-layout-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.omni-layout-item{display:flex;flex-direction:column;gap:6px;padding:12px 8px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border-radius:6px;border:1px solid var(--border);text-align:center;min-height:60px;justify-content:center}.omni-layout-label{font-size:11px;font-weight:800;color:var(--text-dim)}.omni-layout-value{font-size:12px;font-weight:800;color:var(--color-accent);font-family:JetBrains Mono,monospace}.omni-locator-row{display:flex;align-items:center;gap:12px;padding:12px 16px;background:rgb(var(--rgb-well) / calc(.6 * var(--well-k)));border-radius:6px;border:1px solid var(--border);border-left:3px solid var(--color-accent);transition:all .2s;min-height:48px}.omni-locator-strategy{flex-shrink:0;font-size:11px;font-weight:800;background:rgb(var(--rgb-accent) / .05);color:var(--color-accent);padding:2px 6px;border-radius:6px}.omni-locator-value{flex:1;font-family:JetBrains Mono,monospace;font-size:11px;color:var(--text-muted);word-break:break-all;line-height:1.5}.omni-copy-btn{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:24px;height:24px;background:rgb(var(--rgb-fg) / .03);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text-muted);cursor:pointer;transition:all .2s ease}.omni-copy-btn:hover{background:var(--color-accent);border-color:var(--color-accent);color:var(--color-on-accent)}.omni-locator-actions{display:flex;flex-direction:column;gap:4px;flex-shrink:0}.omni-test-btn{display:flex;align-items:center;justify-content:center;width:24px;height:24px;background:rgb(var(--rgb-fg) / .03);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text-muted);cursor:pointer;transition:all .2s ease}.omni-test-btn:hover{background:rgb(var(--rgb-accent) / .12);border-color:var(--color-accent);color:var(--color-accent)}.omni-test-btn.active{background:var(--color-accent);border-color:var(--color-accent);color:var(--color-on-accent)}.omni-match-badge{display:inline-flex;align-items:center;gap:3px;padding:1px 6px;border-radius:4px;font-size:11px;font-weight:600;border:1px solid transparent;line-height:1.4;white-space:nowrap}.omni-match-badge.unique{background:rgb(var(--rgb-success) / .12);border-color:rgb(var(--rgb-success) / .4);color:var(--color-success)}.omni-match-badge.multi{background:rgb(var(--rgb-amber) / .12);border-color:rgb(var(--rgb-amber) / .4);color:var(--amber, var(--amber))}.omni-match-badge.zero{background:rgb(var(--rgb-red) / .12);border-color:rgb(var(--rgb-red) / .4);color:var(--red, var(--red))}.omni-match-badge.unsupported{background:rgb(var(--rgb-fg) / .04);border-color:var(--border);color:var(--text-dim)}.omni-copy-btn.copied{background:var(--color-accent);border-color:var(--color-accent);color:var(--color-on-accent)}.omni-attributes-table{display:flex;flex-direction:column;gap:4px;background:#161b22b3;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border-radius:var(--radius-sm);border:1px solid var(--border);padding:8px;max-height:200px;overflow-y:auto}.omni-attr-row{display:flex;gap:8px;padding:6px 8px;border-radius:4px;transition:background .2s ease}.omni-attr-row:hover{background:rgb(var(--rgb-fg) / .03)}.omni-attr-key{width:120px;flex-shrink:0;font-size:11px;font-weight:600;color:var(--text-muted);font-family:Fira Code,monospace}.omni-attr-value{flex:1;font-size:11px;color:#e2e8f0;font-family:Fira Code,monospace;word-break:break-all}.omni-tree-content::-webkit-scrollbar,.omni-details-content::-webkit-scrollbar,.omni-attributes-table::-webkit-scrollbar{width:6px}.omni-tree-content::-webkit-scrollbar-track,.omni-details-content::-webkit-scrollbar-track,.omni-attributes-table::-webkit-scrollbar-track{background:transparent}.omni-tree-content::-webkit-scrollbar-thumb,.omni-details-content::-webkit-scrollbar-thumb,.omni-attributes-table::-webkit-scrollbar-thumb{background:var(--border);border-radius:8px}.omni-tree-content::-webkit-scrollbar-thumb:hover,.omni-details-content::-webkit-scrollbar-thumb:hover,.omni-attributes-table::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}.omni-quick-actions{display:flex;flex-direction:column;gap:16px}.omni-input-group{display:flex;flex-direction:column;gap:8px}.omni-input-field{width:100%;background:rgb(var(--rgb-well) / calc(.3 * var(--well-k)));border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 12px;color:var(--text);font-size:12px;outline:none;transition:all .2s ease}.omni-input-field:focus{border-color:var(--color-accent);background:rgb(var(--rgb-well) / calc(.5 * var(--well-k)))}.omni-gestures-container{display:flex;flex-direction:column;align-items:center;gap:12px;padding:16px;background:rgb(var(--rgb-well) / calc(.2 * var(--well-k)));border-radius:var(--radius-md);border:1px solid var(--border)}.omni-dpad{display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);gap:8px;width:120px;height:120px}.omni-dpad-btn{display:flex;align-items:center;justify-content:center;background:rgb(var(--rgb-fg) / .03);border:1px solid rgb(var(--rgb-fg) / .05);border-radius:8px;color:var(--text-muted);cursor:pointer;transition:all .2s ease}.omni-dpad-btn:hover{background:var(--color-accent);color:var(--color-on-accent);transform:scale(1.1)}.omni-clipboard-box{display:flex;gap:8px;align-items:center}.omni-clipboard-val{flex:1;background:#161b22b3;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid var(--border);border-radius:4px;padding:8px;font-family:Fira Code,monospace;font-size:11px;color:var(--sky-400);min-height:32px;overflow-x:auto;white-space:nowrap}.omni-details-tabs{display:flex;background:rgb(var(--rgb-well) / calc(.5 * var(--well-k)));border-bottom:1px solid var(--border);flex-shrink:0}.omni-details-tab{display:flex;align-items:center;gap:5px;flex:1;padding:10px 8px;border:none;background:transparent;color:var(--text-muted);font-size:11px;font-weight:700;cursor:pointer;border-bottom:2px solid transparent;transition:all .15s ease;justify-content:center;min-width:0;white-space:nowrap}.omni-details-tab>svg{flex-shrink:0}.omni-details-tab>span{min-width:0;overflow:hidden;text-overflow:ellipsis}.omni-details-tab:hover:not(:disabled){color:var(--text);background:rgb(var(--rgb-fg) / .03)}.omni-details-tab.active{color:var(--color-accent);border-bottom-color:var(--color-accent);background:rgb(var(--rgb-accent) / .04)}.omni-details-tab:disabled{opacity:.3;cursor:not-allowed}.omni-locator-row{display:flex;align-items:flex-start;gap:10px;padding:10px 14px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border-radius:6px;border:1px solid var(--border);border-left:3px solid var(--color-accent);transition:all .15s;cursor:pointer}.omni-locator-row:hover{background:rgb(var(--rgb-fg) / .02);border-color:var(--color-accent)}.omni-locator-row.selected-for-code{border-color:var(--color-accent);background:rgb(var(--rgb-accent) / .06);box-shadow:none}.omni-locator-left{flex:1;display:flex;flex-direction:column;gap:4px;min-width:0}.omni-locator-top{display:flex;align-items:center;gap:6px;flex-wrap:wrap}.omni-stability-badge{display:inline-flex;align-items:center;gap:3px;font-size:11px;font-weight:800;padding:2px 6px;border-radius:4px}.omni-stability-badge.stable{background:rgb(var(--rgb-accent) / .12);color:var(--color-accent);border:1px solid rgb(var(--rgb-accent) / .25)}.omni-stability-badge.moderate{background:rgb(var(--rgb-amber-400) / .1);color:var(--amber-400);border:1px solid rgb(var(--rgb-amber-400) / .25)}.omni-stability-badge.fragile{background:#f43f5e1a;color:#f43f5e;border:1px solid rgba(244,63,94,.25)}.omni-stability-reason{font-size:10px;color:var(--text-muted);font-style:italic;line-height:1.3}.omni-section-badge{font-size:11px;font-weight:600;background:rgb(var(--rgb-accent) / .08);color:var(--color-accent);padding:2px 6px;border-radius:4px;margin-left:6px;vertical-align:middle}.tree-text-preview{font-size:10px;color:var(--text-muted);font-style:italic;max-width:80px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.tree-type-tag{font-size:9px;font-weight:700;color:var(--text-dim);background:rgb(var(--rgb-fg) / .04);padding:1px 5px;border-radius:3px;flex-shrink:0;font-family:JetBrains Mono,monospace;text-transform:none;letter-spacing:.02em;max-width:110px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.omni-inspector-container.omni-embedded{height:100%}.omni-inspector-container.omni-embedded .omni-main-content{padding:0;gap:12px}.omni-inspector-container.omni-embedded .omni-tree-panel{flex:1 1 50%;min-width:180px}.omni-inspector-container.omni-embedded .omni-details-panel{flex:1 1 50%;min-width:230px;max-width:none}.omni-summary-panel{display:flex;flex-direction:column;gap:18px}.omni-summary-hero{display:flex;align-items:flex-start;gap:12px;padding:14px;background:rgb(var(--rgb-accent) / .04);border:1px solid rgb(var(--rgb-accent) / .15);border-radius:8px;color:var(--color-accent)}.omni-summary-hero>svg{flex-shrink:0;margin-top:2px}.omni-summary-title{font-size:13px;font-weight:700;color:var(--text);margin-bottom:2px}.omni-summary-subtitle{font-size:11px;color:var(--text-muted);line-height:1.5}.omni-summary-stats{display:grid;grid-template-columns:repeat(2,1fr);gap:8px}.omni-summary-stat{display:flex;flex-direction:column;gap:4px;padding:10px 12px;background:rgb(var(--rgb-well) / calc(.4 * var(--well-k)));border:1px solid var(--border);border-radius:6px}.omni-summary-stat__label{font-size:11px;font-weight:700;color:var(--text-dim)}.omni-summary-stat__value{font-size:14px;font-weight:700;color:var(--color-accent);font-family:JetBrains Mono,monospace;word-break:break-all}.omni-summary-roles{display:flex;flex-direction:column;gap:4px}.omni-summary-role{display:flex;align-items:center;gap:10px;padding:8px 10px;background:rgb(var(--rgb-well) / calc(.25 * var(--well-k)));border:1px solid var(--border);border-radius:6px}.omni-summary-role__emoji{font-size:16px;line-height:1}.omni-summary-role__name{flex:1;font-size:12px;color:var(--text)}.omni-summary-role__count{font-size:11px;font-weight:700;color:var(--color-accent);background:rgb(var(--rgb-accent) / .06);padding:2px 8px;border-radius:4px;font-family:JetBrains Mono,monospace}.omni-search-hint{display:flex;align-items:center;gap:5px;padding:4px 14px;font-size:10px;color:var(--color-accent);opacity:.7;font-style:italic;background:rgb(var(--rgb-accent) / .03);border-bottom:1px solid rgb(var(--rgb-accent) / .08)}.omni-insight-panel{display:flex;flex-direction:column;gap:16px}.omni-insight-role{display:flex;align-items:center;gap:14px;padding:16px;background:rgb(var(--rgb-accent) / .04);border-radius:8px;border:1px solid rgb(var(--rgb-accent) / .12)}.omni-insight-emoji{font-size:28px;line-height:1}.omni-insight-role-name{font-size:14px;font-weight:700;color:var(--text);font-family:JetBrains Mono,monospace}.omni-insight-interactable{margin-top:4px;display:flex;gap:6px}.omni-badge-green{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:700;color:var(--color-success);background:rgb(var(--rgb-success) / .1);padding:2px 8px;border-radius:4px;border:1px solid rgb(var(--rgb-success) / .2)}.omni-badge-gray{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:700;color:var(--text-muted);background:rgb(var(--rgb-fg) / .04);padding:2px 8px;border-radius:4px;border:1px solid var(--border)}.omni-insight-warning{padding:10px 12px;background:rgb(var(--rgb-amber-400) / .06);border:1px solid rgb(var(--rgb-amber-400) / .2);border-radius:6px;font-size:11px;color:var(--amber-400)}.omni-insight-description{display:flex;gap:10px;align-items:flex-start;padding:12px;background:rgb(var(--rgb-well) / calc(.3 * var(--well-k)));border-radius:6px;border:1px solid var(--border)}.omni-insight-icon{color:var(--color-accent);flex-shrink:0;margin-top:2px}.omni-insight-description p{font-size:12px;color:var(--text);line-height:1.6;margin:0}.omni-insight-best-locator,.omni-insight-attributes{display:flex;flex-direction:column;gap:8px}.omni-quick-facts{display:flex;flex-direction:column;gap:4px}.omni-quick-fact-row{display:flex;justify-content:space-between;align-items:center;padding:6px 10px;border-radius:4px;background:rgb(var(--rgb-well) / calc(.2 * var(--well-k)))}.omni-quick-fact-label{font-size:11px;color:var(--text-muted);font-weight:600}.omni-quick-fact-value{font-size:11px;color:var(--text);font-family:JetBrains Mono,monospace}.omni-quick-fact-value.true{color:var(--color-accent);font-weight:700}.omni-codegen-panel{display:flex;flex-direction:column;gap:12px}.omni-codegen-frameworks{display:flex;gap:4px;flex-wrap:wrap}.omni-fw-btn{flex:1;padding:6px 4px;background:rgb(var(--rgb-fg) / .03);border:1px solid var(--border);border-radius:6px;color:var(--text-muted);font-size:10px;font-weight:700;cursor:pointer;transition:all .15s;white-space:nowrap}.omni-fw-btn:hover{background:rgb(var(--rgb-fg) / .06);color:var(--text)}.omni-fw-btn.active{background:rgb(var(--rgb-accent) / .08);border-color:rgb(var(--rgb-accent) / .4);color:var(--color-accent)}.omni-codegen-locator-selector{display:flex;align-items:center;gap:8px}.omni-codegen-label{font-size:11px;font-weight:700;color:var(--text-muted);white-space:nowrap}.omni-codegen-output{display:flex;flex-direction:column;border-radius:8px;border:1px solid var(--border);overflow:hidden}.omni-codegen-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;background:rgb(var(--rgb-well) / calc(.5 * var(--well-k)));border-bottom:1px solid var(--border)}.omni-codegen-lang{font-size:11px;font-weight:700;color:var(--color-accent)}.omni-codegen-pre{margin:0;padding:14px;background:#161b22b3;color:#e2e8f0;font-family:Fira Code,JetBrains Mono,monospace;font-size:11px;line-height:1.6;overflow-x:auto;white-space:pre}.omni-codegen-pre code{font-family:inherit;font-size:inherit;color:inherit}.omni-verify-line{display:flex;align-items:center;gap:4px;margin-top:3px;font-size:10px;line-height:1.4}.omni-verify-line.is-ok{color:var(--color-success)}.omni-verify-line.is-warn{color:var(--amber-400)}.omni-verify-line.is-error{color:var(--red-400)}.omni-source-badge{font-size:11px;padding:2px 8px;border-radius:6px;font-weight:800;white-space:nowrap}.omni-source-badge.is-session{background:rgb(var(--rgb-blue-400) / .08);color:var(--blue-400)}.omni-source-badge.is-device{background:#94a3b81a;color:#94a3b8}.omni-locators-empty{padding:10px 12px;font-size:11px;line-height:1.6;color:var(--text);opacity:.6}.omni-tree-error{display:flex;align-items:center;gap:6px;margin:8px;padding:8px 10px;border:1px solid rgb(var(--rgb-red-400) / .35);border-radius:8px;background:rgb(var(--rgb-red-400) / .08);color:var(--red-400);font-size:11px;line-height:1.5}.omni-tree-error>span{flex:1;min-width:0}.omni-tree-error-retry{flex-shrink:0;padding:3px 8px;border:1px solid rgb(var(--rgb-red-400) / .4);border-radius:6px;background:transparent;color:inherit;font-size:11px;font-weight:700;cursor:pointer}.omni-tree-error-retry:hover{background:rgb(var(--rgb-red-400) / .15)}:root[data-theme=light] .omni-screenshot-container,:root[data-theme=light] .omni-attributes-table,:root[data-theme=light] .omni-clipboard-val{background:var(--surface-2)}:root[data-theme=light] .omni-attr-value{color:var(--text)}:root[data-theme=light] .omni-stability-badge.fragile{background:rgb(var(--rgb-red) / .08);color:var(--red);border-color:rgb(var(--rgb-red) / .25)}:root[data-theme=light] .omni-source-badge.is-device{background:rgb(var(--rgb-fg) / .05);color:var(--text-dim)}:root[data-theme=light] .omni-codegen-pre{background:var(--surface)}.logcat-root{display:flex;flex-direction:column;flex:1;min-height:0}.log-toolbar{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;row-gap:6px;background:color-mix(in srgb,var(--surface-2) 60%,transparent);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);padding:8px 16px;border-radius:var(--radius-md) var(--radius-md) 0 0;border:1px solid var(--border);border-bottom:none}.log-filter-group,.log-actions-group{display:flex;gap:8px;align-items:center;min-width:0;flex-wrap:wrap}.log-stat-pill{font-size:11px;background:rgb(var(--rgb-accent) / .1);color:var(--color-accent);padding:3px 8px;border-radius:4px;font-weight:700;display:flex;align-items:center;gap:6px}.log-live-dot{width:8px;height:8px;border-radius:50%;background:var(--text-muted);flex-shrink:0;transition:background .3s ease}.log-live-dot.active{background:var(--color-success);box-shadow:none;animation:logcat-live-pulse 2s infinite}@keyframes logcat-live-pulse{0%,to{opacity:1;box-shadow:none}50%{opacity:.6;box-shadow:none}}.log-empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 20px;text-align:center;min-height:200px}.log-empty-title{font-family:Outfit,sans-serif;font-size:14px;font-weight:700;color:var(--text);margin:0 0 6px;letter-spacing:.02em}.log-empty-subtitle{font-size:12px;color:var(--text-muted);max-width:300px;margin:0;line-height:1.5}.logcat-query{flex:1;min-width:160px}.logcat-count{opacity:.6}.logcat-rows{flex:1;overflow-y:auto;font-family:JetBrains Mono,monospace;font-size:11.5px;line-height:1.6;padding:8px 12px}.logcat-row{display:grid;grid-template-columns:56px 70px minmax(0,150px) minmax(0,160px) 12px;gap:4px 8px;align-items:baseline;padding:1px 0}.logcat-row:hover{background:rgb(var(--rgb-fg) / .03)}.logcat-time,.logcat-pid,.logcat-pkg,.logcat-tag{color:var(--text-muted);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.logcat-tag{color:#7dd3fc}.logcat-msg{grid-column:1 / -1;padding-left:8px;color:var(--text);min-width:0;white-space:pre-wrap;overflow-wrap:anywhere}.logcat-level{font-weight:700;text-align:center;border-radius:3px}.lvl-V,.lvl-D{color:var(--text-muted)}.lvl-I{color:var(--color-accent)}.lvl-W{color:var(--amber-400)}.lvl-E,.lvl-F{color:var(--red-400)}.logcat-row.is-hit{background:color-mix(in srgb,var(--color-accent) 12%,transparent)}.logcat-row.is-active-hit{background:color-mix(in srgb,var(--color-accent) 22%,transparent);box-shadow:inset 2px 0 0 var(--color-accent)}.logcat-rows.no-wrap{overflow-x:auto}.logcat-rows.no-wrap .logcat-row{grid-template-columns:56px 70px minmax(0,150px) minmax(0,160px) 12px minmax(0,1fr);width:max-content;min-width:100%}.logcat-rows.no-wrap .logcat-msg{grid-column:auto;padding-left:0;white-space:pre;overflow:hidden;text-overflow:ellipsis}.logcat-input-wrap{position:relative;display:flex;align-items:center}.logcat-find{width:120px}.logcat-query{padding-right:22px}.logcat-input-btn{position:absolute;right:4px;display:flex;align-items:center;justify-content:center;padding:2px;border:0;border-radius:3px;background:transparent;color:var(--text-muted);cursor:pointer}.logcat-input-btn:hover{color:var(--text);background:rgb(var(--rgb-fg) / .08)}.logcat-hit-count{position:absolute;right:8px;font-size:10px;font-variant-numeric:tabular-nums;color:var(--text-muted);pointer-events:none}.btn-secondary.is-recording{color:var(--red-400);border-color:color-mix(in srgb,var(--red-400) 45%,transparent);background:color-mix(in srgb,var(--red-400) 12%,transparent)}.btn-secondary.is-recording svg{fill:currentColor}.logcat-icon-btn{padding:4px 6px}.logcat-icon-btn:disabled{opacity:.4;cursor:default}.logcat-row.is-synthetic .logcat-msg{color:var(--amber-400);font-style:italic}.log-live-dot.is-error{background:var(--red-400);box-shadow:none}.logcat-status-banner{display:flex;align-items:center;gap:8px;padding:8px 10px;margin-bottom:8px;border-radius:var(--radius-sm);font-family:Outfit,sans-serif;font-size:12px;line-height:1.4}.logcat-status-banner.is-denied{background:rgb(var(--rgb-red-400) / .1);border:1px solid rgb(var(--rgb-red-400) / .3);color:#fecdd3}.logcat-status-banner.is-exhausted{background:rgb(var(--rgb-amber-400) / .1);border:1px solid rgb(var(--rgb-amber-400) / .3);color:#fde68a}:root[data-theme=light] .logcat-rows{background:var(--bg);border-radius:0 0 var(--radius-md) var(--radius-md)}
|