loop-canvas 0.1.0 → 0.1.2

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/public/app.js CHANGED
@@ -1,40 +1,85 @@
1
- const d=e=>document.querySelector(e),x=d("#viewport"),ut=d("#world"),an=d("#frames"),ge=d("#ink"),Ge=d("#cursors"),U=d("#hover-box"),$=d("#composer"),k=d("#composer-input"),W=d("#thread"),w=e=>String(e??"").replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t]),mt=()=>Math.random().toString(36).slice(2,10),ye={get(e,t){try{const n=localStorage.getItem(e);return n==null?t:JSON.parse(n)}catch{return t}},set(e,t){try{localStorage.setItem(e,JSON.stringify(t))}catch{}}},pt=["#2F5BFF","#E5484D","#1F9D55","#D9A100","#8E4EC6","#0E9AA7","#E8590C"],Ve="#E5484D";let c=null,u={x:120,y:140,z:.5},ht=!1,T="select",te=!1,M=null,_=null,h=null,ve=null;const E=new Set;let Ae=null,F=null;const gt=new Set,z=new Map,Q=new Map,ce=new Map,A=window.LOOP_ADAPTER||null,C=ye.get("loop.me",null)||{id:mt(),name:"",color:pt[Math.floor(Math.random()*pt.length)]};A?.me&&Object.assign(C,A.me),C.id=C.id||mt();async function p(e,t,n){if(A)return A.api(e,t,n);const a=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0}),i=await a.json().catch(()=>({}));if(!a.ok)throw new Error(i.error||`HTTP ${a.status}`);return i}function v(e,t=2200){const n=d("#toast");n.textContent=e,n.hidden=!1,clearTimeout(v.t),v.t=setTimeout(()=>n.hidden=!0,t)}const b=()=>c?.role==="owner";function sn(){if(A)return A.connect(yt);const e=new EventSource("/__loop/api/events");e.onmessage=t=>yt(JSON.parse(t.data)),e.onerror=()=>{d("#agent-pill").classList.add("offline")},e.onopen=()=>{d("#agent-pill").classList.remove("offline")}}function yt(e){if(e.type==="state"){const t=!c;c=e.state,t&&on(),rn()}else if(e.type==="activity")c?.live[e.frameId]&&(c.live[e.frameId].step=e.step),D(c.frames.find(t=>t.id===e.frameId)),document.querySelectorAll(`[data-step-for="${e.commentId}"]`).forEach(t=>t.textContent=e.step);else if(e.type==="frame-changed")cn(e.frameId),e.done&&dn(e.frameId,e.status==="done"?"Updated":e.status==="error"?"Failed":"",e.status!=="done"),e.done&&e.status==="done"&&Rn(e.frameId);else if(e.type==="presence"){if(e.id===C.id)return;e.leave?ce.delete(e.id):ce.set(e.id,{...e,t:Date.now()}),wt(),Pe()}}function on(){const e=ye.get(`loop.view.${c.name}`,null);e?(u=e,Y()):xe(!1),ht=!0,C.name||(b()?C.name="Host":(d("#name-modal").hidden=!1,setTimeout(()=>d("#name-input").focus(),30))),ye.set("loop.me",C),document.body.classList.toggle("guest",!b()),d("#new-frame-btn").hidden=!b(),document.querySelector("#toolbar .tb-sep").hidden=!b()}function Y(){ut.style.transform=`translate(${u.x}px, ${u.y}px) scale(${u.z})`,ut.style.setProperty("--z",u.z);let e=24*u.z;for(;e<12;)e*=4;x.style.setProperty("--gs",`${e}px`),x.style.setProperty("--gx",`${u.x}px`),x.style.setProperty("--gy",`${u.y}px`),d("#zoom-level").textContent=`${Math.round(u.z*100)}%`,V(),U.hidden=!0,ht&&c&&(clearTimeout(Y.t),Y.t=setTimeout(()=>ye.set(`loop.view.${c.name}`,u),300))}function G(e,t,n){const a=Math.min(4,Math.max(.04,u.z*n));u.x=e-(e-u.x)*(a/u.z),u.y=t-(t-u.y)*(a/u.z),u.z=a,vt()}let Ze=!1;function vt(){Ze||(Ze=!0,requestAnimationFrame(()=>{Ze=!1,Y()}))}function xt(e,t,n){e.preventDefault();const a=Math.max(-30,Math.min(30,e.deltaMode===1?e.deltaY*16:e.deltaY));G(t,n,Math.exp(-a*(e.ctrlKey&&!e.metaKey?.01:.004)))}const K=(e,t)=>({x:(e-u.x)/u.z,y:(t-u.y)/u.z});function xe(e=!0,t){const n=(c?.frames||[]).filter(S=>!t||t.includes(S.id));if(!n.length)return u={x:innerWidth/2,y:innerHeight/2,z:.5},Y();const a=Math.min(...n.map(S=>S.x)),i=Math.min(...n.map(S=>S.y)),o=Math.max(...n.map(S=>S.x+S.w)),s=Math.max(...n.map(S=>S.y+S.h)),r=80,l=110,f=110,m=Math.min(1,(innerWidth-r*2)/(o-a),(innerHeight-l-f)/(s-i)),g={z:m,x:(innerWidth-(o-a)*m)/2-a*m,y:l+(innerHeight-l-f-(s-i)*m)/2-i*m};if(!e)return u=g,Y();const y={...u},he=performance.now(),_e=S=>{const le=Math.min(1,(S-he)/280),Ue=1-Math.pow(1-le,3);u={x:y.x+(g.x-y.x)*Ue,y:y.y+(g.y-y.y)*Ue,z:y.z+(g.z-y.z)*Ue},Y(),le<1&&requestAnimationFrame(_e)};requestAnimationFrame(_e)}function rn(){if(!c)return;d("#canvas-name").querySelector("input")||(d("#canvas-name").textContent=c.name),d("#canvas-name").classList.toggle("editable",b()&&!A),document.title=`${c.name} \u2014 Loop`,d("#empty").hidden=c.frames.length>0,un(),Pe();const e=new Set(c.frames.map(t=>t.id));for(const[t,n]of z)e.has(t)||(n.el.remove(),z.delete(t));for(const t of c.frames)D(t);M&&!e.has(M)&&(M=null),$t(),Ee(),_&&Pt(),h&&h.frameId!==P&&!e.has(h.frameId)&&q();for(const t of[...E])e.has(t)||E.delete(t);oe(),Ke()}function we(e){return{...e,...Q.get(e.id)||{}}}function ln(e){const t=document.createElement("div");t.className="frame",t.dataset.id=e.id,t.innerHTML=`
1
+ const p=e=>document.querySelector(e),F=p("#viewport"),rt=p("#world"),_o=p("#frames"),Ze=p("#ink"),Ps=p("#cursors"),Q=p("#hover-box"),H=p("#composer"),Y=p("#composer-input"),I=p("#thread"),w=e=>String(e??"").replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t]),An=()=>Math.random().toString(36).slice(2,10),qs=()=>(An()+An()).slice(0,8),Ce={get(e,t){try{const n=localStorage.getItem(e);return n==null?t:JSON.parse(n)}catch{return t}},set(e,t){try{localStorage.setItem(e,JSON.stringify(t))}catch{}}},Po={select:'<path d="M9.80282 4.62973L15.8364 6.99069C19.3164 8.35243 21.0564 9.03329 20.9987 10.1133C20.941 11.1934 19.1251 11.6886 15.4933 12.6791C14.412 12.974 13.8713 13.1215 13.4964 13.4963C13.1215 13.8712 12.9741 14.4119 12.6791 15.4933C11.6887 19.125 11.1934 20.9409 10.1134 20.9986C9.03335 21.0563 8.35249 19.3163 6.99075 15.8363L4.62979 9.80276C3.20411 6.15934 2.49127 4.33764 3.41448 3.41442C4.3377 2.49121 6.15941 3.20405 9.80282 4.62973Z"/>',pen:'<path d="M3.49977 18.9853V20.5H5.01449C6.24074 20.5 6.85387 20.5 7.40518 20.2716C7.9565 20.0433 8.39004 19.6097 9.25713 18.7426L19.1211 8.87868C20.0037 7.99612 20.4449 7.55483 20.4937 7.01325C20.5018 6.92372 20.5018 6.83364 20.4937 6.74411C20.4449 6.20253 20.0037 5.76124 19.1211 4.87868C18.2385 3.99612 17.7972 3.55483 17.2557 3.50605C17.1661 3.49798 17.0761 3.49798 16.9865 3.50605C16.4449 3.55483 16.0037 3.99612 15.1211 4.87868L5.25713 14.7426C4.39004 15.6097 3.9565 16.0433 3.72813 16.5946C3.49977 17.1459 3.49977 17.759 3.49977 18.9853Z"/><path d="M13.5 6.5L17.5 10.5"/>',erase:'<path d="M8.73792 7.78021L4.84693 11.7574C3.67722 12.953 3.09236 13.5508 3.01263 14.2802C2.99579 14.4343 2.99579 14.5899 3.01263 14.744C3.09236 15.4733 3.67722 16.0711 4.84693 17.2668L4.99601 17.4191C5.62049 18.0575 5.93274 18.3766 6.30638 18.5911C6.5236 18.7157 6.75482 18.8134 6.99505 18.882C7.40827 19 7.85149 19 8.73792 19C9.62436 19 10.0676 19 10.4808 18.882C10.721 18.8134 10.9522 18.7157 11.1695 18.5911C11.5431 18.3766 11.8554 18.0575 12.4798 17.4191L15.3239 14.5121M8.73792 7.78021L12.3199 4.12313C13.7065 2.70754 14.3997 1.99974 15.2627 2C16.1256 2.00026 16.8185 2.70846 18.2042 4.12487L18.9473 4.8845C20.3159 6.28342 21.0002 6.98288 21 7.85008C20.9997 8.71728 20.315 9.41633 18.9456 10.8144L15.3239 14.5121M8.73792 7.78021L15.3239 14.5121"/><path d="M10 22L21 22"/>',comment:'<path d="M12 18.0012H15C18.2998 18.0012 19.9497 18.0012 20.9749 16.9761C22 15.951 22 14.3011 22 11.0012V9.50122C22 6.20139 22 4.55147 20.9749 3.52635C19.9497 2.50122 18.2998 2.50122 15 2.50122H9C5.70017 2.50122 4.05025 2.50122 3.02513 3.52635C2 4.55147 2 6.20139 2 9.50122V14.0012C2 14.4656 2 14.6978 2.02201 14.8931C2.20484 16.5158 3.48545 17.7964 5.10812 17.9792C5.30344 18.0012 5.53563 18.0012 6 18.0012V20.0819C6 20.9044 6 21.3157 6.26407 21.457C6.52814 21.5983 6.87033 21.3702 7.5547 20.914L12 18.0012Z"/>',frame:'<path d="M2 6H22M2 18H22"/><path d="M6 22L6 2M18 22V2"/>',comments:'<path d="M8 13.0012H16M8 8.00122H12"/><path d="M12 18.0012H15C18.2998 18.0012 19.9497 18.0012 20.9749 16.9761C22 15.951 22 14.3011 22 11.0012V9.50122C22 6.20139 22 4.55147 20.9749 3.52635C19.9497 2.50122 18.2998 2.50122 15 2.50122H9C5.70017 2.50122 4.05025 2.50122 3.02513 3.52635C2 4.55147 2 6.20139 2 9.50122V14.0012C2 14.4656 2 14.6978 2.02201 14.8931C2.20484 16.5158 3.48545 17.7964 5.10812 17.9792C5.30344 18.0012 5.53563 18.0012 6 18.0012V20.0819C6 20.9044 6 21.3157 6.26407 21.457C6.52814 21.5983 6.87033 21.3702 7.5547 20.914L12 18.0012Z"/>',undo:'<path d="M3 8H15C18.3137 8 21 10.6863 21 14C21 17.3137 18.3137 20 15 20H11"/><path d="M7 4L5.8462 4.87652C3.94873 6.31801 3 7.03875 3 8C3 8.96125 3.94873 9.68199 5.8462 11.1235L7 12"/>',redo:'<path d="M21 8H9C5.68629 8 3 10.6863 3 14C3 17.3137 5.68629 20 9 20H13"/><path d="M17 4L18.1538 4.87652C20.0513 6.31801 21 7.03875 21 8C21 8.96125 20.0513 9.68199 18.1538 11.1235L17 12"/>',before:'<path d="M3.49902 14.9656C4.72475 18.4791 8.06749 21 11.999 21C16.9696 21 20.999 16.9706 20.999 12C20.999 7.02944 16.9696 3 11.999 3C8.29827 3 4.8984 5.6756 3.68943 8.5"/><path d="M11.999 7V12L14.999 14"/><path d="M7.49751 8.74363C7.49751 8.74363 3.81388 9.3026 3.25487 8.7436C2.69585 8.1846 3.25488 4.50098 3.25488 4.50098"/>',copy:'<path d="M7.5 14.5C7.5 11.2002 7.5 9.55025 8.52513 8.52513C9.55025 7.5 11.2002 7.5 14.5 7.5C17.7998 7.5 19.4497 7.5 20.4749 8.52513C21.5 9.55025 21.5 11.2002 21.5 14.5C21.5 17.7998 21.5 19.4497 20.4749 20.4749C19.4497 21.5 17.7998 21.5 14.5 21.5C11.2002 21.5 9.55025 21.5 8.52513 20.4749C7.5 19.4497 7.5 17.7998 7.5 14.5Z"/><path d="M7.5 16.5C6.10355 16.5 5.40533 16.5 4.84402 16.3036C3.83866 15.9518 3.0482 15.1613 2.69641 14.156C2.5 13.5947 2.5 12.8964 2.5 11.5V9.5C2.5 6.20017 2.5 4.55025 3.52513 3.52513C4.55025 2.5 6.20017 2.5 9.5 2.5H11.5C12.8964 2.5 13.5947 2.5 14.156 2.69641C15.1613 3.0482 15.9518 3.83866 16.3036 4.84402C16.5 5.40533 16.5 6.10355 16.5 7.5"/>',check:'<path d="M5 14L8.5 17.5L19 6.5"/>',stop:'<path d="M4 12C4 8.72077 4 7.08116 4.81382 5.91891C5.1149 5.48891 5.48891 5.1149 5.91891 4.81382C7.08116 4 8.72077 4 12 4C15.2792 4 16.9188 4 18.0811 4.81382C18.5111 5.1149 18.8851 5.48891 19.1862 5.91891C20 7.08116 20 8.72077 20 12C20 15.2792 20 16.9188 19.1862 18.0811C18.8851 18.5111 18.5111 18.8851 18.0811 19.1862C16.9188 20 15.2792 20 12 20C8.72077 20 7.08116 20 5.91891 19.1862C5.48891 18.8851 5.1149 18.5111 4.81382 18.0811C4 16.9188 4 15.2792 4 12Z"/>',up:'<path d="M12 5.5V19"/><path d="M18 11C18 11 13.5811 5.00001 12 5C10.4188 4.99999 6 11 6 11"/>',retry:'<path d="M20.4879 15C19.2524 18.4956 15.9187 21 12 21C7.02943 21 3 16.9706 3 12C3 7.02943 7.02943 3 12 3C15.7292 3 18.9286 5.26806 20.2941 8.5"/><path d="M15 9H18C19.4142 9 20.1213 9 20.5607 8.56066C21 8.12132 21 7.41421 21 6V3"/>',steer:'<path d="M13 6H8.5C6.01472 6 4 8.01472 4 10.5C4 12.9853 6.01472 15 8.5 15H20"/><path d="M17 12C17 12 20 14.2095 20 15C20 15.7906 17 18 17 18"/>',play:'<path d="M18.8906 12.846C18.5371 14.189 16.8667 15.138 13.5257 17.0361C10.296 18.8709 8.6812 19.7884 7.37983 19.4196C6.8418 19.2671 6.35159 18.9776 5.95624 18.5787C5 17.6139 5 15.7426 5 12C5 8.2574 5 6.3861 5.95624 5.42132C6.35159 5.02245 6.8418 4.73288 7.37983 4.58042C8.6812 4.21165 10.296 5.12907 13.5257 6.96393C16.8667 8.86197 18.5371 9.811 18.8906 11.154C19.0365 11.7084 19.0365 12.2916 18.8906 12.846Z"/>',x:'<path d="M18.9991 19L5 5.00098"/><path d="M19 5L5.00092 18.999"/>',plus:'<path d="M12.001 4.00101V20.001"/><path d="M20.001 12.001L4.00098 12.001"/>',mic:'<path d="M7 6.5C7 4.01472 9.01472 2 11.5 2C13.9853 2 16 4.01472 16 6.5V11.5C16 13.9853 13.9853 16 11.5 16C9.01472 16 7 13.9853 7 11.5V6.5Z"/><path d="M11.5 19H11.0828C7.57267 19 4.57706 16.4623 4 13M11.5 19H11.9172C15.4273 19 18.4229 16.4623 19 13M11.5 19V22"/>',file:'<path d="M8 17H16"/><path d="M8 13H12"/><path d="M13 2.5V3C13 5.82843 13 7.24264 13.8787 8.12132C14.7574 9 16.1716 9 19 9H19.5M20 10.6569V14C20 17.7712 20 19.6569 18.8284 20.8284C17.6569 22 15.7712 22 12 22C8.22876 22 6.34315 22 5.17157 20.8284C4 19.6569 4 17.7712 4 14V9.45584C4 6.21082 4 4.58831 4.88607 3.48933C5.06508 3.26731 5.26731 3.06508 5.48933 2.88607C6.58831 2 8.21082 2 11.4558 2C12.1614 2 12.5141 2 12.8372 2.11401C12.9044 2.13772 12.9702 2.165 13.0345 2.19575C13.3436 2.34355 13.593 2.593 14.0919 3.09188L18.8284 7.82843C19.4065 8.40649 19.6955 8.69552 19.8478 9.06306C20 9.4306 20 9.83935 20 10.6569Z"/>',clip:'<path d="M9.5 8V14.5C9.5 15.8807 10.6193 17 12 17C13.3807 17 14.5 15.8807 14.5 14.5V6.5C14.5 4.01472 12.4853 2 10 2C7.51472 2 5.5 4.01472 5.5 6.5V15.5C5.5 19.0899 8.41015 22 12 22C15.5899 22 18.5 19.0899 18.5 15.5V6"/>',read:'<path d="M8 17H16"/><path d="M8 13H12"/><path d="M13 2.5V3C13 5.82843 13 7.24264 13.8787 8.12132C14.7574 9 16.1716 9 19 9H19.5M20 10.6569V14C20 17.7712 20 19.6569 18.8284 20.8284C17.6569 22 15.7712 22 12 22C8.22876 22 6.34315 22 5.17157 20.8284C4 19.6569 4 17.7712 4 14V9.45584C4 6.21082 4 4.58831 4.88607 3.48933C5.06508 3.26731 5.26731 3.06508 5.48933 2.88607C6.58831 2 8.21082 2 11.4558 2C12.1614 2 12.5141 2 12.8372 2.11401C12.9044 2.13772 12.9702 2.165 13.0345 2.19575C13.3436 2.34355 13.593 2.593 14.0919 3.09188L18.8284 7.82843C19.4065 8.40649 19.6955 8.69552 19.8478 9.06306C20 9.4306 20 9.83935 20 10.6569Z"/>',edit:'<path d="M16.4249 4.60509L17.4149 3.6151C18.2351 2.79497 19.5648 2.79497 20.3849 3.6151C21.205 4.43524 21.205 5.76493 20.3849 6.58507L19.3949 7.57506M16.4249 4.60509L9.76558 11.2644C9.25807 11.772 8.89804 12.4078 8.72397 13.1041L8 16L10.8959 15.276C11.5922 15.102 12.228 14.7419 12.7356 14.2344L19.3949 7.57506M16.4249 4.60509L19.3949 7.57506"/><path d="M18.9999 13.5C18.9999 16.7875 18.9999 18.4312 18.092 19.5376C17.9258 19.7401 17.7401 19.9258 17.5375 20.092C16.4312 21 14.7874 21 11.4999 21H11C7.22876 21 5.34316 21 4.17159 19.8284C3.00003 18.6569 3 16.7712 3 13V12.5C3 9.21252 3 7.56879 3.90794 6.46244C4.07417 6.2599 4.2599 6.07417 4.46244 5.90794C5.56879 5 7.21252 5 10.5 5"/>',find:'<path d="M17 17L21 21"/><path d="M19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11C3 15.4183 6.58172 19 11 19C15.4183 19 19 15.4183 19 11Z"/>',look:'<path d="M21.544 11.045C21.848 11.4713 22 11.6845 22 12C22 12.3155 21.848 12.5287 21.544 12.955C20.1779 14.8706 16.6892 19 12 19C7.31078 19 3.8221 14.8706 2.45604 12.955C2.15201 12.5287 2 12.3155 2 12C2 11.6845 2.15201 11.4713 2.45604 11.045C3.8221 9.12944 7.31078 5 12 5C16.6892 5 20.1779 9.12944 21.544 11.045Z"/><path d="M15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15C13.6569 15 15 13.6569 15 12Z"/>',run:'<path d="M14 4H10C6.22876 4 4.34315 4 3.17157 5.17157C2 6.34315 2 8.22876 2 12C2 15.7712 2 17.6569 3.17157 18.8284C4.34315 20 6.22876 20 10 20H14C17.7712 20 19.6569 20 20.8284 18.8284C22 17.6569 22 15.7712 22 12C22 8.22876 22 6.34315 20.8284 5.17157C19.6569 4 17.7712 4 14 4Z"/><path d="M7 9L8.83981 10.5858C9.61327 11.2525 10 11.5858 10 12C10 12.4142 9.61327 12.7475 8.83981 13.4142L7 15"/><path d="M13 16H17"/>',think:'<path d="M8 16.4998C6.7725 15.4011 6 13.7768 6 11.9998C6 8.68605 8.68629 5.99976 12 5.99976C15.3137 5.99976 18 8.68605 18 11.9998C18 13.7768 17.2275 15.4011 16 16.4998"/><path d="M12 11.9998V16.4998"/><path d="M9.5 18.9998H14.5"/><path d="M10.5 21.4998H13.5"/><path d="M3.5 11.9998H2.5M5.98438 5.97632L5.23438 5.23022M18.0195 5.97632L18.7695 5.23022M21.5 11.9998H20.5M12 2.49976V3.49976"/>',add:'<path d="M12 3.00005C16.2426 3.00005 18.364 3.00005 19.682 4.31807C21 5.63609 21 7.75741 21 12.0001C21 16.2427 21 18.364 19.682 19.682C18.364 21.0001 16.2426 21.0001 12 21.0001C7.75736 21.0001 5.63604 21.0001 4.31802 19.682C3 18.364 3 16.2427 3 12.0001C3 7.75741 3 5.63609 4.31802 4.31807C5.63604 3.00005 7.75736 3.00005 12 3.00005Z"/><path d="M12.0001 8.00005V12.0001M12.0001 12.0001V16.0001M12.0001 12.0001H16.0001M12.0001 12.0001H8.00006"/>',expand:'<path d="M16.4999 3.26621C17.3443 3.25421 20.1408 2.67328 20.7337 3.26621C21.3266 3.85913 20.7457 6.65559 20.7337 7.5M20.5059 3.49097L13.5021 10.4961"/><path d="M3.26636 16.5001C3.25436 17.3445 2.67343 20.141 3.26636 20.7339C3.85928 21.3268 6.65574 20.7459 7.50015 20.7339M10.502 13.4976L3.49824 20.5027"/>',collapse:'<path d="M6.5023 10.7365C7.34671 10.7485 10.1432 11.3294 10.7361 10.7365C11.329 10.1436 10.7481 7.34708 10.7361 6.50267M13.2685 17.5027C13.2565 16.6583 12.6756 13.8618 13.2685 13.2689C13.8614 12.676 16.6579 13.2569 17.5023 13.2689M20.9991 21.001L13.6102 13.6188M10.3691 10.3763L2.99998 2.99902"/>',resolve:'<path d="M22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12Z"/><path d="M8 12.5L10.5 15L16 9"/>',reopen:'<path d="M11 6H15.5C17.9853 6 20 8.01472 20 10.5C20 12.9853 17.9853 15 15.5 15H4"/><path d="M6.99998 12C6.99998 12 4.00001 14.2095 4 15C3.99999 15.7906 7 18 7 18"/>',more:'<path d="M6.00449 12.5V12M18.0045 12.5V12M12.0045 12.5V12M7.00449 12.5C7.00449 11.9477 6.55677 11.5 6.00449 11.5C5.4522 11.5 5.00449 11.9477 5.00449 12.5C5.00449 13.0523 5.4522 13.5 6.00449 13.5C6.55677 13.5 7.00449 13.0523 7.00449 12.5ZM19.0045 12.5C19.0045 11.9477 18.5568 11.5 18.0045 11.5C17.4522 11.5 17.0045 11.9477 17.0045 12.5C17.0045 13.0523 17.4522 13.5 18.0045 13.5C18.5568 13.5 19.0045 13.0523 19.0045 12.5ZM13.0045 12.5C13.0045 11.9477 12.5568 11.5 12.0045 11.5C11.4522 11.5 11.0045 11.9477 11.0045 12.5C11.0045 13.0523 11.4522 13.5 12.0045 13.5C12.5568 13.5 13.0045 13.0523 13.0045 12.5Z"/>',reply:'<path d="M3.99219 10H11.9922C13.8521 10 14.7821 10 15.5451 10.2044C17.6157 10.7592 19.2329 12.3765 19.7877 14.4471C19.9922 15.2101 19.9922 16.1401 19.9922 18"/><path d="M7.99219 6L6.83839 6.87652C4.94092 8.31801 3.99219 9.03875 3.99219 10C3.99219 10.9612 4.94092 11.682 6.83839 13.1235L7.99219 14"/>',trash:'<path d="M18.8516 16.3743L19.5 6H4.5L5.14839 16.3743C5.315 19.0401 5.39831 20.373 6.26426 21.1865C7.13021 22 8.46571 22 11.1367 22H12.8633C15.5343 22 16.8698 22 17.7357 21.1865C18.6017 20.373 18.685 19.0401 18.8516 16.3743Z"/><path d="M16 6H21M16 6L15.3778 4.34082C15.0007 3.33524 14.8122 2.83245 14.4402 2.50292C14.3213 2.39765 14.1904 2.3069 14.0501 2.2326C13.6109 2 13.074 2 12 2C10.926 2 10.3891 2 9.9499 2.2326C9.8096 2.3069 9.67865 2.39765 9.55982 2.50292C9.18783 2.83245 8.99928 3.33524 8.62219 4.34082L8 6M16 6H8M3 6H8"/><path d="M9.5 11V17M14.5 11V17"/>',phone:'<path d="M13.5 2H10.5C8.14298 2 6.96447 2 6.23223 2.73223C5.5 3.46447 5.5 4.64298 5.5 7V17C5.5 19.357 5.5 20.5355 6.23223 21.2678C6.96447 22 8.14298 22 10.5 22H13.5C15.857 22 17.0355 22 17.7678 21.2678C18.5 20.5355 18.5 19.357 18.5 17V7C18.5 4.64298 18.5 3.46447 17.7678 2.73223C17.0355 2 15.857 2 13.5 2Z"/><path d="M12.125 19H12M12.25 19C12.25 19.1381 12.1381 19.25 12 19.25C11.8619 19.25 11.75 19.1381 11.75 19C11.75 18.8619 11.8619 18.75 12 18.75C12.1381 18.75 12.25 18.8619 12.25 19Z"/>',tablet:'<path d="M14.5 2H9.5C6.67157 2 5.25736 2 4.37868 2.87868C3.5 3.75736 3.5 5.17157 3.5 8V16C3.5 18.8284 3.5 20.2426 4.37868 21.1213C5.25736 22 6.67157 22 9.5 22H14.5C17.3284 22 18.7426 22 19.6213 21.1213C20.5 20.2426 20.5 18.8284 20.5 16V8C20.5 5.17157 20.5 3.75736 19.6213 2.87868C18.7426 2 17.3284 2 14.5 2Z"/><path d="M12.125 19H12M12.25 19C12.25 19.1381 12.1381 19.25 12 19.25C11.8619 19.25 11.75 19.1381 11.75 19C11.75 18.8619 11.8619 18.75 12 18.75C12.1381 18.75 12.25 18.8619 12.25 19Z"/>',desktop:'<path d="M14 21H16M14 21C13.1716 21 12.5 20.3284 12.5 19.5V17L12 17M14 21H10M10 21H8M10 21C10.8284 21 11.5 20.3284 11.5 19.5V17L12 17M12 17V21"/><path d="M16 3H8C5.17157 3 3.75736 3 2.87868 3.87868C2 4.75736 2 6.17157 2 9V11C2 13.8284 2 15.2426 2.87868 16.1213C3.75736 17 5.17157 17 8 17H16C18.8284 17 20.2426 17 21.1213 16.1213C22 15.2426 22 13.8284 22 11V9C22 6.17157 22 4.75736 21.1213 3.87868C20.2426 3 18.8284 3 16 3Z"/>',keyboard:'<path d="M14.5 7H9.5C6.21252 7 4.56878 7 3.46243 7.90796C3.25989 8.07418 3.07418 8.25989 2.90796 8.46243C2 9.56878 2 11.2125 2 14.5C2 17.7875 2 19.4312 2.90796 20.5376C3.07418 20.7401 3.25989 20.9258 3.46243 21.092C4.56878 22 6.21252 22 9.5 22H14.5C17.7875 22 19.4312 22 20.5376 21.092C20.7401 20.9258 20.9258 20.7401 21.092 20.5376C22 19.4312 22 17.7875 22 14.5C22 11.2125 22 9.56878 21.092 8.46243C20.9258 8.25989 20.7401 8.07418 20.5376 7.90796C19.4312 7 17.7875 7 14.5 7Z"/><path d="M12 7V5C12 4.44772 12.4477 4 13 4C13.5523 4 14 3.55228 14 3V2"/><path d="M7 12L8 12"/><path d="M11.5 12L12.5 12"/><path d="M16 12L17 12"/><path d="M7 17L17 17"/>',freeze:'<path d="M14.244 3.00632C13.801 3.40963 12.6212 5.00086 11.991 5C11.3608 4.99909 10.1858 3.40451 9.744 3"/><path d="M14.244 20.9937C13.801 20.5904 12.6212 18.9991 11.991 19C11.3608 19.0009 10.1858 20.5955 9.744 21"/><path d="M20.9077 9.45191C20.337 9.26993 18.3691 9.04383 18.0547 8.4976C17.7404 7.9514 18.5338 6.13651 18.6632 5.55164"/><path d="M5.33024 18.4456C5.45802 17.8603 6.24618 16.043 5.93032 15.4976C5.61445 14.9523 3.64599 14.732 3.07477 14.5516"/><path d="M3.07602 9.45203C3.64679 9.27005 5.61472 9.04395 5.9291 8.49772C6.2434 7.95152 5.44996 6.13663 5.32055 5.55176"/><path d="M18.6529 18.4457C18.5252 17.8604 17.737 16.0431 18.0529 15.4977C18.3687 14.9524 20.3372 14.7321 20.9084 14.5518"/><path d="M15.4581 9.97911L17.994 8.49982M11.9937 8.02071L11.9937 4.99982M17.9937 15.4998L15.458 14.0206M5.99424 15.4998L8.56579 13.9997M11.9937 18.9998L11.9937 15.9789M8.56579 10.0001L5.994 8.49982"/><path d="M15.4957 11.7313C15.4955 10.8861 15.4955 10.4635 15.2945 10.1155C15.0935 9.76744 14.7275 9.55617 13.9955 9.13361L13.5316 8.86583C12.7996 8.44326 12.4336 8.23198 12.0317 8.23199C11.6298 8.23201 11.2638 8.44332 10.5318 8.86593L10.0679 9.13379C9.33581 9.55644 8.96978 9.76777 8.76882 10.1158C8.56786 10.4639 8.56786 10.8866 8.56786 11.7319L8.56786 12.2677C8.56786 13.113 8.56786 13.5356 8.76881 13.8837C8.96976 14.2318 9.33578 14.4431 10.0678 14.8658L10.5319 15.1337C11.264 15.5564 11.63 15.7678 12.032 15.7678C12.4339 15.7678 12.7999 15.5564 13.532 15.1338L13.9958 14.866C14.728 14.4433 15.0941 14.2319 15.295 13.8838C15.496 13.5356 15.4959 13.1129 15.4958 12.2674L15.4957 11.7313Z"/>',stage:'<path d="M15.5 21C16.8956 21 17.5933 21 18.1611 20.8278C19.4395 20.44 20.44 19.4395 20.8278 18.1611C21 17.5933 21 16.8956 21 15.5M21 8.5C21 7.10444 21 6.40666 20.8278 5.83886C20.44 4.56046 19.4395 3.56004 18.1611 3.17224C17.5933 3 16.8956 3 15.5 3M8.5 21C7.10444 21 6.40666 21 5.83886 20.8278C4.56046 20.44 3.56004 19.4395 3.17224 18.1611C3 17.5933 3 16.8956 3 15.5M3 8.5C3 7.10444 3 6.40666 3.17224 5.83886C3.56004 4.56046 4.56046 3.56004 5.83886 3.17224C6.40666 3 7.10444 3 8.5 3"/>',layers:'<path d="M8.64298 3.14559L6.93816 3.93362C4.31272 5.14719 3 5.75397 3 6.75C3 7.74603 4.31272 8.35281 6.93817 9.56638L8.64298 10.3544C10.2952 11.1181 11.1214 11.5 12 11.5C12.8786 11.5 13.7048 11.1181 15.357 10.3544L17.0618 9.56638C19.6873 8.35281 21 7.74603 21 6.75C21 5.75397 19.6873 5.14719 17.0618 3.93362L15.357 3.14559C13.7048 2.38186 12.8786 2 12 2C11.1214 2 10.2952 2.38186 8.64298 3.14559Z"/><path d="M20.788 11.0972C20.9293 11.2959 21 11.5031 21 11.7309C21 12.7127 19.6873 13.3109 17.0618 14.5072L15.357 15.284C13.7048 16.0368 12.8786 16.4133 12 16.4133C11.1214 16.4133 10.2952 16.0368 8.64298 15.284L6.93817 14.5072C4.31272 13.3109 3 12.7127 3 11.7309C3 11.5031 3.07067 11.2959 3.212 11.0972"/><path d="M20.3767 16.2661C20.7922 16.5971 21 16.927 21 17.3176C21 18.2995 19.6873 18.8976 17.0618 20.0939L15.357 20.8707C13.7048 21.6236 12.8786 22 12 22C11.1214 22 10.2952 21.6236 8.64298 20.8707L6.93817 20.0939C4.31272 18.8976 3 18.2995 3 17.3176C3 16.927 3.20778 16.5971 3.62334 16.2661"/>',sun:'<path d="M17 12C17 14.7614 14.7614 17 12 17C9.23858 17 7 14.7614 7 12C7 9.23858 9.23858 7 12 7C14.7614 7 17 9.23858 17 12Z"/><path d="M12 2V3.5M12 20.5V22M19.0708 19.0713L18.0101 18.0106M5.98926 5.98926L4.9286 4.9286M22 12H20.5M3.5 12H2M19.0713 4.92871L18.0106 5.98937M5.98975 18.0107L4.92909 19.0714"/>',moon:'<path d="M21.5 14.0784C20.3003 14.7189 18.9301 15.0821 17.4751 15.0821C12.7491 15.0821 8.91792 11.2509 8.91792 6.52485C8.91792 5.06986 9.28105 3.69968 9.92163 2.5C5.66765 3.49698 2.5 7.31513 2.5 11.8731C2.5 17.1899 6.8101 21.5 12.1269 21.5C16.6849 21.5 20.503 18.3324 21.5 14.0784Z"/>',left:'<path d="M15 6C15 6 9.00001 10.4189 9 12C8.99999 13.5812 15 18 15 18"/>',right:'<path d="M9.00005 6C9.00005 6 15 10.4189 15 12C15 13.5812 9 18 9 18"/>',down:'<path d="M18 9.00005C18 9.00005 13.5811 15 12 15C10.4188 15 6 9 6 9"/>',point:'<path d="M9 14.5V4.5a1.5 1.5 0 0 1 3 0v6"/><path d="M12 10a1.5 1.5 0 0 1 3 0v1.5"/><path d="M15 11a1.5 1.5 0 0 1 3 0v1"/><path d="M18 12a1.5 1.5 0 0 1 3 0v3.5a6.5 6.5 0 0 1-6.5 6.5h-1.6a6 6 0 0 1-4.7-2.3l-3.4-4.4a1.7 1.7 0 0 1 2.6-2.2L9 14.5"/>',hand:'<path d="M18 11V6a2 2 0 0 0-4 0"/><path d="M14 10V4a2 2 0 0 0-4 0v2"/><path d="M10 10.5V6a2 2 0 0 0-4 0v8"/><path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-6-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.83L7 15"/>'},E=(e,t="")=>`<svg class="hi${t?" "+t:""}" viewBox="0 0 24 24" aria-hidden="true">${Po[e]||""}</svg>`;document.querySelectorAll("i[data-i]").forEach(e=>{e.outerHTML=E(e.dataset.i)});function zs(e){e?document.documentElement.dataset.theme=e:delete document.documentElement.dataset.theme;const t=e?e==="dark":matchMedia("(prefers-color-scheme: dark)").matches,n=document.getElementById("theme-btn");n&&(n.innerHTML=E(t?"sun":"moon"),n.title=t?"Light mode (\u21E7D)":"Dark mode (\u21E7D)")}function Aa(){const t=(document.documentElement.dataset.theme?document.documentElement.dataset.theme==="dark":matchMedia("(prefers-color-scheme: dark)").matches)?"light":"dark";try{localStorage.setItem("loop.theme",t)}catch{}zs(t)}zs((()=>{try{return localStorage.getItem("loop.theme")}catch{return null}})()),matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>zs(document.documentElement.dataset.theme)),document.getElementById("theme-btn").addEventListener("click",Aa);const Hs=["#5B6AD0","#D2575C","#3B9A6C","#B98A2C","#8A63C4","#2E93A6","#CC6E3C"],qo=["#2F5BFF","#E5484D","#1F9D55","#D9A100","#8E4EC6","#0E9AA7","#E8590C"],zo=e=>{const t=qo.indexOf(String(e||"").toUpperCase());return t>=0?Hs[t]:/^#[0-9a-f]{6}$/i.test(e||"")?e:"#88888F"},_a=(e,t,n="",s="")=>`<span class="av${n?" "+n:""}" style="--c:${zo(t)}">${s?`<img src="${w(s)}" alt="" referrerpolicy="no-referrer">`:w(Xa(e).slice(0,1))}</span>`,Is="#E5484D";let d=null,h={x:120,y:140,z:.5},Ds=!1,V="select",kt=!1,P=null,W=null,R=null,We=null;const B=new Set;let _n=null,qe=null;const Pa=new Set,O=new Map,Le=new Map,It=new Map,K=window.LOOP_ADAPTER||null,j=Ce.get("loop.me",null)||{id:An(),name:"",color:Hs[Math.floor(Math.random()*Hs.length)]};K?.me&&Object.assign(j,K.me),j.id=j.id||An();async function x(e,t,n){if(K)return K.api(e,t,n);const s=await fetch(t,{method:e,headers:{"content-type":"application/json"},body:n?JSON.stringify(n):void 0}),a=await s.json().catch(()=>({}));if(!s.ok)throw new Error(a.error||`HTTP ${s.status}`);return a}function k(e,t=2200){const n=p("#toast");n.textContent=e,n.hidden=!1,clearTimeout(k.t),k.t=setTimeout(()=>n.hidden=!0,t)}const $=()=>d?.role==="owner";function Ho(){if(K)return K.connect(Pn);const e=new EventSource("/__loop/api/events");e.onmessage=t=>Pn(JSON.parse(t.data)),e.onerror=()=>{p("#agent-pill").classList.add("offline")},e.onopen=()=>{p("#agent-pill").classList.remove("offline")}}function Pn(e){if(e.type==="state"){if(d?.version&&e.state.version&&e.state.version!==d.version){location.reload();return}const t=!d;d=e.state,t&&Fo(),zn()}else if(e.type==="patch"){if(!d)return;Object.assign(d,e.set||{}),!ie&&(e.lists?.frames?.up?.length>1||e.lists?.sections?.up?.length)&&(rt.classList.add("gliding"),clearTimeout(Pn.glide),Pn.glide=setTimeout(()=>rt.classList.remove("gliding"),520));const t=$()&&(e.lists?.sections?.up||[]).find(n=>n.optionsFor&&!(d.sections||[]).some(s=>s.id===n.id));for(const[n,s]of Object.entries(e.lists||{})){const a=new Map((d[n]||[]).map(i=>[i.id,i]));for(const i of s.up||[])a.set(i.id,i);d[n]=s.order?s.order.map(i=>a.get(i)).filter(Boolean):(d[n]||[]).map(i=>a.get(i.id))}zn(),t&&wo(t.id)}else if(e.type==="activity"){if(!d)return;const t=d.live[e.frameId];t&&(t.step=e.step,t.partial=e.partial||"");const n=e.partial==null&&d.comments.find(a=>a.id===e.commentId);if(n&&e.step&&!/^(Writing…|Reading your comment…|Your chat picked this up|Working…)$/.test(e.step)){const a=n.steps||=[],i=a[a.length-1];!/^(Reading the code|Editing|Writing|Setting up an option)$/.test(e.step)&&(!i||i.s!==e.step)&&a.push({t:Date.now(),s:e.step}),bi(e.commentId)}const s=O.get(e.frameId);s&&t&&be(s.step,e.step),document.querySelectorAll(`[data-step-for="${e.commentId}"]`).forEach(a=>be(a,e.step)),oi(e.commentId,e.partial||""),rr(e.frameId)}else if(e.type==="frame-changed")Zo(e.frameId),e.done&&Jo(e.frameId,e.status==="done"?d.frames.find(t=>t.id===e.frameId)?.kind==="frozen"?"Changed in the app":"Updated":e.status==="error"?"Failed":"",e.status!=="done"),e.done&&e.status==="done"&&Kr(e.frameId),e.done&&(e.status==="done"||e.status==="error")&&Qo(e.frameId,e.commentId,e.status);else if(e.type==="presence"){if(e.id===j.id)return;e.leave?It.delete(e.id):It.set(e.id,{...e,t:Date.now()}),Ua(),On()}}function be(e,t){e&&e.textContent!==t&&(e.textContent=t)}const Ge={at:0,ids:new Set};function Io(){const e=Ce.get(`loop.seen.${d.name}`,null);e?(Ge.at=e.at,Ge.ids=new Set(e.ids)):(Ge.at=Date.now(),qa())}function qa(){Ce.set(`loop.seen.${d.name}`,{at:Ge.at,ids:[...Ge.ids].slice(-400)})}function Do(e){const t=Ct(e).filter(s=>s.kind!=="note"),n=t[t.length-1];return!!n&&n.status==="done"&&(n.finishedAt||0)>Ge.at&&!Ge.ids.has(n.id)}function za(e){let t=!1;for(const n of Ct(e))n.finishedAt&&!Ge.ids.has(n.id)&&(Ge.ids.add(n.id),t=!0);return t&&qa(),t}const Oo=[0,8,2,10,12,4,14,6,3,11,1,9,15,7,13,5],Os=[64,148,255];let qn=0,Ha=0;const Ia=matchMedia("(prefers-reduced-motion: reduce)");function Ro(){qn||(qn=requestAnimationFrame(Da))}function Da(e){qn=0;const t=[...document.querySelectorAll(".area.working")];if(!t.length||(Ia.matches||(qn=requestAnimationFrame(Da)),e-Ha<33))return;Ha=e;const n=Ia.matches?.35:e%5200/5200,s=Math.min(1,n/.8),i=-.2+s*s*(3-2*s)*1.45,o=1,r=.119;for(const l of t){const c=l.getBoundingClientRect();if(c.right<0||c.bottom<0||c.left>innerWidth||c.top>innerHeight||c.width<12||c.height<12)continue;let u=3;for(;c.width/u*(c.height/u)>6e4;)u++;const f=Math.ceil(c.width/u),m=Math.ceil(c.height/u);let y=l.querySelector(":scope > canvas.dz");y||(y=document.createElement("canvas"),y.className="dz",l.appendChild(y)),(y.width!==f||y.height!==m)&&(y.width=f,y.height=m,y.style.setProperty("--cols",f),y.style.setProperty("--rows",m));const g=y.getContext("2d"),v=g.createImageData(f,m),A=v.data,_=Math.hypot(f,m),b=Math.min(f,m),M=Math.max(2.4,b*.05+Math.max(0,b-40)*.03)*(l.classList.contains("whole")?1.5:1),L=M*4.5;for(let N=0;N<m;N++)for(let q=0;q<f;q++){const ve=Math.min(q,N,f-1-q,m-1-N);if(ve>L)continue;const Ae=Math.hypot(q,N)/_-i,Ta=o*Math.exp(-Ae*Ae/r)*Math.exp(-ve/M);if(Ta>(Oo[(N&3)*4+(q&3)]+.5)/16){const Tn=(N*f+q)*4;A[Tn]=Os[0],A[Tn+1]=Os[1],A[Tn+2]=Os[2],A[Tn+3]=255*(.3+.7*Ta)|0}}g.putImageData(v,0,0)}}const No='<svg viewBox="0 0 24 24" aria-hidden="true"><path pathLength="14" d="M5 14L8.5 17.5L19 6.5"/></svg>';function Fo(){Io();const e=Ce.get(`loop.view.${d.name}`,null);e?(h=e,te()):je(!1),Ds=!0,$()?j.name=d.hostName||j.name||"You":j.name||Di(),Ce.set("loop.me",j),document.body.classList.toggle("guest",!$()),p("#new-frame-btn").hidden=!$(),p("#section-btn").hidden=!$(),document.querySelector("#toolbar .tb-sep").hidden=!$()}function te(){h.z>=.02||(h.z=.04),Na=performance.now(),rt.style.transform=`translate(${h.x}px, ${h.y}px) scale(${h.z})`,rt.style.setProperty("--z",h.z),te.lastZ!==h.z&&(te.lastZ=h.z,rt.style.willChange!=="transform"&&(rt.style.willChange="transform"),clearTimeout(te.crisp),te.crisp=setTimeout(()=>{rt.style.willChange="auto"},160));const e=Math.min(1.5,Math.max(1,Math.pow(h.z,.42)));document.documentElement.style.setProperty("--lz",e.toFixed(3)),document.body.classList.toggle("zoom-tiny",h.z<.12);const t=`${Math.round(h.z*100)}%`,n=p("#zoom-level");if(n.textContent!==t){n.textContent=t;const s=p("#zoom");s.classList.add("awake"),clearTimeout(te.zt),te.zt=setTimeout(()=>s.classList.remove("awake"),1200)}rn(),Dt(),ye(),Mn(),ae&&xe(),Q.hidden=!0,Ds&&d&&(clearTimeout(te.t),te.t=setTimeout(()=>Ce.set(`loop.view.${d.name}`,h),300)),d&&te.z!==h.z&&(te.z=h.z,te.lq||(te.lq=requestAnimationFrame(()=>{te.lq=0,ko()})),clearTimeout(te.pt),te.pt=setTimeout(()=>{for(const s of d.frames)Ke(s.id)},120))}function Qe(e,t,n){const s=Math.min(4,Math.max(.04,h.z*n));h.x=e-(e-h.x)*(s/h.z),h.y=t-(t-h.y)*(s/h.z),h.z=s,Ns()}let Rs=!1;function Ns(){Rs||(Rs=!0,requestAnimationFrame(()=>{Rs=!1,te()}))}function Oa(e,t,n){e.preventDefault();const s=Math.max(-30,Math.min(30,e.deltaMode===1?e.deltaY*16:e.deltaY));Qe(t,n,Math.exp(-s*(e.ctrlKey&&!e.metaKey?.01:.004)))}const we=(e,t)=>({x:(e-h.x)/h.z,y:(t-h.y)/h.z});function je(e=!0,t){const n=(d?.frames||[]).filter(v=>!t||t.includes(v.id));if(!n.length)return h={x:innerWidth/2,y:innerHeight/2,z:.5},te();const s=Math.min(...n.map(v=>v.x)),a=Math.min(...n.map(v=>v.y)),i=Math.max(...n.map(v=>v.x+v.w)),o=Math.max(...n.map(v=>v.y+v.h)),r=80,l=110,c=110,u=Math.max(.04,Math.min(1,(innerWidth-r*2)/(i-s),(innerHeight-l-c)/(o-a))),f={z:u,x:(innerWidth-(i-s)*u)/2-s*u,y:l+(innerHeight-l-c-(o-a)*u)/2-a*u};if(!e)return h=f,te();const m={...h},y=performance.now(),g=v=>{const A=Math.min(1,(v-y)/280),_=1-Math.pow(1-A,3);h={x:m.x+(f.x-m.x)*_,y:m.y+(f.y-m.y)*_,z:m.z+(f.z-m.z)*_},te(),A<1&&requestAnimationFrame(g)};requestAnimationFrame(g)}function zn(){if(!d)return;p("#canvas-name").querySelector("input")||(p("#canvas-name").textContent=d.name),p("#canvas-name").classList.toggle("editable",$()&&!K),document.title=`${d.name} \u2014 Loop`,p("#empty").hidden=d.frames.length>0,$()&&!K&&d.hostName&&j.name!==d.hostName&&Ds&&(j.name=d.hostName,Ce.set("loop.me",j)),er(),On();const e=new Set(d.frames.map(t=>t.id));for(const[t,n]of O)e.has(t)||(n.el.remove(),O.delete(t));for(const t of d.frames)X(t);d.sections||=[],xt(),P&&!e.has(P)&&(P=null),lt(),fn(),W&&Xn(),ae&&si(),R&&R.frameId!==oe&&!e.has(R.frameId)&&ne();for(const t of[...B])e.has(t)||B.delete(t);Se(),Cn(),Sr(),Cr(),S&&xs(),D&&Eo(),T&&(sn(),qt()),rn(),$s()}function Hn(e){try{const t=e.iframe.contentWindow.location;return t.href==="about:blank"?null:t.pathname+t.search+t.hash}catch{return null}}let Fs=0,Bs=0,on=null;const Bo=/[?&]nosleep\b/.test(location.search);let Ra=new Set;function Wo(e){const t=bt(e),n=Math.max(0,Math.min(t.l+t.w,innerWidth)-Math.max(t.l,0)),s=Math.max(0,Math.min(t.t+t.h,innerHeight)-Math.max(t.t,0));return{shown:n*s,of:t.w*t.h,r:t}}function jo(){const e=new Set;if(!d)return e;if(S)return e.add(S.fid),e;const t=[];for(const n of d.frames){const{shown:s,of:a,r:i}=Wo(n);if(!(s<400||s<a*.1)){if(Bo||n.id===on||n.id===P||n.id===re||C?.frameId===n.id||ue?.fid===n.id||B.has(n.id)){e.add(n.id);continue}(s>=innerWidth*innerHeight*.25||s>=a*.5&&(i.h>=innerHeight*.55||i.w>=innerWidth*.55))&&t.push([n.id,s])}}return t.sort((n,s)=>s[1]-n[1]).slice(0,2).forEach(([n])=>e.add(n)),e}const Vo=e=>Ra.has(e);function Ko(e,t,n){const s=e.requestAnimationFrame.bind(e),a=new Map;let i=0;t.waking=Date.now(),e.requestAnimationFrame=r=>{if(!t.asleep)return s(r);const l=-++i;return a.set(l,r),l};const o=e.cancelAnimationFrame.bind(e);e.cancelAnimationFrame=r=>r<0?a.delete(r):o(r),t.sleepTo=r=>{if(t.asleep!==r){t.asleep=r;try{const l=e.document;let c=l.getElementById("__loop-sleep");r&&!c&&(c=l.createElement("style"),c.id="__loop-sleep",c.textContent="*, *::before, *::after { animation-play-state: paused !important; }",(l.head||l.documentElement).appendChild(c)),!r&&c&&c.remove(),l.querySelectorAll("video").forEach(u=>{try{r?(u._loopPlay=!u.paused,u.pause()):u._loopPlay&&u.play()}catch{}})}catch{}if(!r){const l=[...a.values()];a.clear(),l.forEach(c=>s(c))}}},t.asleep=!1,Dt()}function Dt(){Bs||!d||(Bs=setTimeout(()=>{Bs=0,Ra=jo();for(const[e,t]of O){if(!t.sleepTo)continue;const n=Date.now()-(t.waking||0)<700;t.sleepTo(!n&&!Vo(e))}},120))}setInterval(()=>Dt(),1500);function rn(){Fs||!d||(Fs=requestAnimationFrame(()=>{Fs=0;const e=innerWidth,t=innerHeight,n=d.frames.length>6,s=[];for(const a of d.frames){const i=O.get(a.id);if(!i?.iframe)continue;const o=ze(a),r=h.z,l=h.x+o.x*r,c=h.y+o.y*r,u=o.w*r,f=o.h*r,m=g=>Math.max(0,l-e-g,-(l+u)-g,c-t-g,-(c+f)-g),y=!n||d.live[o.id]||P===o.id||re===o.id||S?.fid===o.id||B.has(o.id);if(i.el.classList.toggle("narrow",u<200),i.el.classList.toggle("far",_t(a)),d.live[o.id]){const g=Math.max(0,Math.min(l+u,e)-Math.max(l,0)),v=Math.max(0,Math.min(c+f,t)-Math.max(c,0)),A=g*v>=e*t*.2&&g*v>=u*f*.5;i.wedge||(i.wedge=document.createElement("i"),i.wedge.className="work-edge",i.el.appendChild(i.wedge)),i.el.classList.toggle("work-far",!A)}else i.el.classList.contains("work-far")&&i.el.classList.remove("work-far");i.parked?(y||m(e*.5)===0&&Math.max(u,f)>160)&&s.push({fe:i,keep:y,on:m(0)===0,d:Math.hypot(l+u/2-e/2,c+f/2-t/2)}):!y&&(m(e)>0||Math.max(u,f)<110)&&(i.resume=Hn(i),i.parked=!0,i.el.classList.add("parked"),i.iframe.src="about:blank"),i.parked&&Ba(i)}if(s.length){const a=performance.now()-Na>140;s.sort((o,r)=>r.keep-o.keep||r.on-o.on||o.d-r.d);const i=a?s.slice(0,2):s.filter(o=>o.keep).slice(0,2);for(const{fe:o}of i)o.parked=!1,o.el.classList.remove("parked"),o.el.classList.add("waking"),clearTimeout(o.wakeT),o.wakeT=setTimeout(()=>Fa(o),8e3),o.iframe.src=o.resume||o.iframe.dataset.src||"about:blank",o.resume=null;s.length>i.length&&setTimeout(rn,a?90:160)}}))}let Na=0;function Fa(e){clearTimeout(e.wakeT),requestAnimationFrame(()=>requestAnimationFrame(()=>e.el.classList.remove("waking")))}function Ba(e){if(K)return;const t=e.hint.querySelector("img"),n=`/__loop/poster/${e.id}?v=${e.rev||0}`;if(t.dataset.src===n)return;t.dataset.src=n;const s=new Image;s.onload=()=>{t.dataset.src===n&&(t.src=n,t.hidden=!1)},s.src=n}function ze(e){return{...e,...Le.get(e.id)||{}}}function Yo(e){const t=document.createElement("div");t.className="frame",t.dataset.id=e.id,t.innerHTML=`
2
2
  <div class="frame-label">
3
- <span class="spinner"></span><span class="name"></span><span class="dims"></span><span class="kind" hidden></span><span class="count"></span>
3
+ <span class="spinner"></span><span class="ic"></span><span class="name"></span><span class="kind" hidden></span><button class="count" title="Versions: look back through this frame's changes" hidden>${E("layers")}<span></span></button>
4
4
  <span class="step"></span><span class="elapsed"></span><span class="updated"></span>
5
5
  <button class="stop" title="Stop the agent">Stop</button>
6
6
  </div>
7
- <div class="frame-body"><iframe title="${w(e.name)}"></iframe><div class="empty-hint"><b>\u2726 Describe this screen</b><span>Click to tell the agent what goes here</span></div><div class="shield"></div><div class="areas"></div><div class="progress"></div></div><div class="pins"></div>
8
- ${["n","s","e","w","ne","nw","se","sw"].map(a=>`<div class="resize rz-${a}" data-dir="${a}"></div>`).join("")}`,an.appendChild(t);const n={el:t,iframe:t.querySelector("iframe"),label:t.querySelector(".frame-label"),name:t.querySelector(".name"),dims:t.querySelector(".dims"),kind:t.querySelector(".kind"),count:t.querySelector(".count"),step:t.querySelector(".step"),elapsed:t.querySelector(".elapsed"),updated:t.querySelector(".updated"),pins:t.querySelector(".pins"),restore:null};return n.iframe.addEventListener("load",()=>{try{const a=n.iframe.contentWindow;n.restore&&(a.scrollTo(n.restore.sx,n.restore.sy),n.restore=null),n.el.classList.toggle("empty",!!a.document.querySelector('meta[name="loop-empty"]')),a.addEventListener("scroll",()=>ae(e.id),{passive:!0}),a.addEventListener("resize",()=>ae(e.id));const i=o=>{const s=n.iframe.getBoundingClientRect(),r=s.width/(n.iframe.offsetWidth||1);return[s.left+o.clientX*r,s.top+o.clientY*r]};a.addEventListener("wheel",o=>{(o.ctrlKey||o.metaKey)&&xt(o,...i(o))},{passive:!1}),a.addEventListener("gesturestart",o=>{o.preventDefault(),qe=u.z}),a.addEventListener("gesturechange",o=>{o.preventDefault();const[s,r]=i(o);G(s,r,qe*o.scale/u.z)}),a.addEventListener("keydown",o=>{o.key==="Escape"&&(B(null),window.focus());const s=o.target,r=s&&(s.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(s.tagName));(o.metaKey||o.ctrlKey)&&!r&&(o.key.toLowerCase()==="z"||o.ctrlKey&&o.key.toLowerCase()==="y")&&(o.preventDefault(),o.shiftKey||o.key.toLowerCase()==="y"?lt():Ut())})}catch{}setTimeout(()=>ae(e.id),60)}),t.querySelector(".stop").addEventListener("pointerdown",a=>a.stopPropagation()),t.querySelector(".stop").addEventListener("click",()=>{const a=c.live[e.id];a&&p("POST",`/__loop/api/comments/${a.commentId}/cancel`).catch(i=>v(i.message))}),n.label.addEventListener("dblclick",()=>b()&&fn(e.id)),z.set(e.id,n),n}function D(e){if(!e)return;const t=we(e),n=z.get(t.id)||ln(t),a=n.el.style;a.left=`${t.x}px`,a.top=`${t.y}px`,a.width=`${t.w}px`,a.height=`${t.h}px`,a.setProperty("--fw",`${t.w}px`);const i=A?.frameSrc?.(t)||(t.kind==="folder"?`/__loop/f/${t.id}/${encodeURIComponent(t.entry||"index.html")}`:t.src);n.iframe.dataset.src!==i&&(n.iframe.dataset.src=i,n.iframe.src=i),n.renaming||(n.name.textContent=t.name),n.kind.hidden=t.kind==="folder"||t.kind==="static",n.kind.textContent=t.kind==="route"?t.src:"live url";const o=c.live[t.id],s=c.comments.filter(r=>r.frameId===t.id&&!r.parentId&&r.kind!=="create"&&!r.resolved).length;if(n.count.textContent=s&&!o?`${s}`:"",n.el.classList.toggle("working",!!o),o){const r=c.comments.find(l=>l.id===o.commentId);n.step.textContent=o.step||(r?.kind==="create"?"Building the frame\u2026":"Working\u2026"),n.elapsed.textContent=Je(o.startedAt)}if(n.el.classList.toggle("selected",M===t.id||E.has(t.id)),n.el.classList.toggle("live",T==="select"&&M===t.id&&!te),n.dims.textContent=`${Math.round(t.w)} \xD7 ${Math.round(t.h)}`,ve===t.id){const r=Ae===t.id;ve=Ae=null,queueMicrotask(()=>{B(t.id),at(t.id),r&&setTimeout(()=>De(t.id),340)})}}function Je(e){const t=Math.max(0,Math.round((Date.now()-e)/1e3));return t<60?`${t}s`:`${Math.floor(t/60)}m ${String(t%60).padStart(2,"0")}s`}setInterval(()=>{if(!c)return;for(const[n,a]of Object.entries(c.live)){const i=z.get(n);i&&(i.elapsed.textContent=Je(a.startedAt))}document.querySelectorAll("[data-elapsed-from]").forEach(n=>n.textContent=Je(+n.dataset.elapsedFrom));const e=Date.now();let t=!1;for(const[n,a]of ce)e-a.t>15e3&&(ce.delete(n),t=!0);t&&(wt(),Pe())},1e3);function cn(e){const t=z.get(e);if(!t)return;try{const i=t.iframe.contentWindow;t.restore={sx:i.scrollX,sy:i.scrollY}}catch{t.restore=null}const n=t.iframe.dataset.src,a=c.frames.find(i=>i.id===e);if(a?.kind!=="static")if(a?.kind==="folder")t.iframe.src=`${n}?_m=${Date.now()}`;else if(a?.kind==="route")try{t.iframe.contentWindow.location.reload()}catch{t.iframe.src=n}else try{t.iframe.contentWindow.location.reload()}catch{t.iframe.src=n}}function dn(e,t,n){const a=z.get(e);!a||!t||(a.updated.textContent=t,a.el.classList.remove("updated","failed"),a.el.offsetWidth,a.el.classList.add(n?"failed":"updated"),clearTimeout(a.flashT),a.flashT=setTimeout(()=>a.el.classList.remove("updated","failed"),4200))}function fn(e){const t=z.get(e),n=c.frames.find(o=>o.id===e);t.renaming=!0;const a=document.createElement("input");a.className="rename",a.value=n.name,t.name.replaceChildren(a),a.focus(),a.select(),a.addEventListener("pointerdown",o=>o.stopPropagation());const i=o=>{if(!t.renaming)return;t.renaming=!1;const s=a.value.trim();if(t.name.textContent=o&&s?s:n.name,o&&s&&s!==n.name){const r=n.name;p("PATCH",`/__loop/api/frames/${e}`,{name:s}),O("Rename frame",()=>ee(e,{name:r}),()=>ee(e,{name:s}))}};a.addEventListener("keydown",o=>{o.stopPropagation(),o.key==="Enter"&&i(!0),o.key==="Escape"&&i(!1)}),a.addEventListener("blur",()=>i(!0))}function un(){const e=d("#agent-pill"),t=Object.keys(c.live).length,n=c.comments.filter(r=>r.status==="queued").length,a=c.comments.filter(r=>r.status==="waiting").length,i=c.agent.lastModel&&(c.agentBin==="codex"?!/^claude/.test(c.agent.lastModel):/^claude/.test(c.agent.lastModel));let s=c.agent.mode==="inbox"?c.chatListening?`Your chat \xB7 ${c.agentLabel||"agent"}`:"Chat away \xB7 background":(c.agentLabel||"Claude Code")+(i?` \xB7 ${Ie(c.agent.lastModel)}`:"");c.hostOnline===!1&&(s="Host offline \xB7 comments wait"),t?s+=` \xB7 ${t} working`:n&&(s+=` \xB7 ${n} queued`),a&&b()&&(s+=` \xB7 ${a} to review`),d("#agent-label").textContent=s,e.classList.toggle("busy",t>0),e.classList.toggle("inbox",c.agent.mode==="inbox"&&!t&&!c.chatListening),document.querySelectorAll("#agent-menu .menu-item").forEach(r=>{r.classList.toggle("on",r.dataset.mode===c.agent.mode&&(!r.dataset.runner||r.dataset.runner===c.agentBin)),r.dataset.runner&&(r.hidden=c.runners&&!c.runners[r.dataset.runner])}),d("#share-menu").hidden||Oe()}function Qe(e){return(e||"?").trim().split(/\s+/).map(t=>t[0]).join("").slice(0,2).toUpperCase()}function Pe(){const e=[{name:C.name||"You",color:C.color},...ce.values()];d("#presence").innerHTML=e.length>1?e.slice(0,6).map(t=>`<span class="avatar" style="background:${w(t.color)}" title="${w(t.name)}">${w(Qe(t.name))}</span>`).join(""):""}function wt(){const e=new Set;for(const t of ce.values()){e.add(t.id);let n=Ge.querySelector(`[data-id="${CSS.escape(t.id)}"]`);n||(n=document.createElement("div"),n.className="cursor",n.dataset.id=t.id,n.innerHTML=`<div class="cursor-inner"><svg viewBox="0 0 18 18"><path d="M2 1.5l13 6.2-5.6 1.5-2.4 5.6z" fill="${w(t.color)}" stroke="#fff" stroke-width="1.4" stroke-linejoin="round"/></svg><span style="background:${w(t.color)}">${w(t.name)}</span></div>`,Ge.appendChild(n)),n.style.transform=`translate(${t.x}px, ${t.y}px)`}Ge.querySelectorAll(".cursor").forEach(t=>{e.has(t.dataset.id)||t.remove()})}let bt=0;function mn(e,t){const n=Date.now();if(n-bt<70||!c)return;bt=n;const a=K(e,t);p("POST","/__loop/api/presence",{id:C.id,name:C.name||"Guest",color:C.color,avatar:C.avatar,x:a.x,y:a.y}).catch(()=>{})}addEventListener("beforeunload",()=>!A&&navigator.sendBeacon?.("/__loop/api/presence",new Blob([JSON.stringify({id:C.id,leave:!0})],{type:"application/json"})));function kt(e){if(e.length<4)return`M${e[0]} ${e[1]}l.01 0`;let t=`M${e[0]} ${e[1]}`;for(let n=2;n<e.length-2;n+=2)t+=`Q${e[n]} ${e[n+1]} ${(e[n]+e[n+2])/2} ${(e[n+1]+e[n+3])/2}`;return t+`L${e[e.length-2]} ${e[e.length-1]}`}function $t(){const e=new Set(c.strokes.map(t=>t.id));ge.querySelectorAll("path[data-id]").forEach(t=>{e.has(t.dataset.id)||t.remove()});for(const t of c.strokes){let n=ge.querySelector(`path[data-id="${t.id}"]`);n||(n=document.createElementNS("http://www.w3.org/2000/svg","path"),n.dataset.id=t.id,n.setAttribute("d",kt(t.points)),ge.appendChild(n)),n.setAttribute("stroke",t.color),n.setAttribute("stroke-width",t.width),n.classList.toggle("used",!!t.commentId)}}function pn(e,t){for(let n=c.frames.length-1;n>=0;n--){const a=c.frames[n];if(e>=a.x&&e<=a.x+a.w&&t>=a.y&&t<=a.y+a.h)return a}return null}function X(e){try{return z.get(e)?.iframe.contentDocument||null}catch{return null}}function be(e,t,n){const a=z.get(e).iframe.getBoundingClientRect();return{lx:(t-a.left)/u.z,ly:(n-a.top)/u.z}}function de(e,t,n){const a=X(e);if(!a)return null;try{return a.elementFromPoint(t,n)}catch{return null}}function ke(e){if(!e||!e.ownerDocument)return"";const t=e.ownerDocument,n=[];for(let a=e;a&&a.nodeType===1&&a!==t.documentElement;a=a.parentElement){if(a.id&&/^[A-Za-z][\w-]*$/.test(a.id)){n.unshift(`#${a.id}`);break}let i=a.tagName.toLowerCase();const o=a.parentElement?[...a.parentElement.children].filter(s=>s.tagName===a.tagName):[];if(o.length>1&&(i+=`:nth-of-type(${o.indexOf(a)+1})`),n.unshift(i),a.tagName==="BODY"||n.length>7)break}return n.join(" > ")}function $e(e){const t=typeof e.className=="string"&&e.className.trim()?"."+e.className.trim().split(/\s+/)[0]:"";return e.tagName.toLowerCase()+t}function Et(e,t,n){const a=de(e,t,n),i=X(e);let o=0,s=0;try{o=i.defaultView.scrollX,s=i.defaultView.scrollY}catch{}const r={x:t,y:n,sx:o,sy:s};if(a&&a!==i.documentElement){const l=a.getBoundingClientRect();Object.assign(r,{selector:ke(a),tag:a.tagName.toLowerCase(),label:$e(a),text:(a.innerText||a.getAttribute?.("aria-label")||a.getAttribute?.("alt")||"").replace(/\s+/g," ").trim().slice(0,140),html:a.outerHTML.length>1500?a.outerHTML.slice(0,1500)+"\u2026":a.outerHTML,fx:l.width?(t-l.left)/l.width:0,fy:l.height?(n-l.top)/l.height:0})}return r}const P="__canvas";function ze(e,t){if(e===P)return{x:t.wx,y:t.wy};if(t.scope==="frame"||t.scope==="point"||t.scope==="area"||t.scope==="elements"){let o=0,s=0;try{const r=X(e).defaultView;o=r.scrollX-(t.sx||0),s=r.scrollY-(t.sy||0)}catch{}return{x:t.x-(t.scope!=="frame"?o:0),y:t.y-(t.scope!=="frame"?s:0)}}const n=X(e);if(n&&t.selector)try{const o=n.querySelector(t.selector);if(o){const s=o.getBoundingClientRect();if(s.width||s.height)return{x:s.left+t.fx*s.width,y:s.top+t.fy*s.height}}}catch{}let a=0,i=0;try{a=n.defaultView.scrollX-(t.sx||0),i=n.defaultView.scrollY-(t.sy||0)}catch{}return{x:t.x-a,y:t.y-i}}function hn(e,t,n){const{lx:a,ly:i}=be(e,t,n),o=de(e,a,i),s=X(e);if(!o||o===s?.documentElement){U.hidden=!0;return}const r=z.get(e).iframe.getBoundingClientRect(),l=o.getBoundingClientRect(),f=u.z,m=Math.max(r.left,r.left+l.left*f),g=Math.max(r.top,r.top+l.top*f),y=Math.min(r.right,r.left+l.right*f),he=Math.min(r.bottom,r.top+l.bottom*f);Object.assign(U.style,{left:`${m}px`,top:`${g}px`,width:`${Math.max(0,y-m)}px`,height:`${Math.max(0,he-g)}px`}),U.dataset.tag=$e(o),U.hidden=!1}function Mt(e){return c.comments.filter(t=>t.id===e||t.parentId===e).sort((t,n)=>t.createdAt-n.createdAt)}function gn(e){const t=Mt(e).filter(n=>n.kind!=="note");return t.some(n=>n.status==="working")?"working":t[t.length-1]?.status||"done"}function St(e){return c.comments.filter(t=>t.frameId===e&&!t.parentId&&t.kind!=="create").sort((t,n)=>t.createdAt-n.createdAt)}function Ee(){for(const e of c.frames)Me(e.id);Me(P)}function Lt(e){return e===P?d("#canvas-pins"):z.get(e)?.pins}function ne(e){return e===P?d("#canvas-pins"):z.get(e)?.el.querySelector(".areas")}function Me(e){const t=Lt(e);if(!t)return;const n={pins:t},a=St(e),i=a.map((f,m)=>({key:f.id,n:m+1,c:f}));h?.frameId===e&&!h.prompt&&i.push({key:"__draft",n:a.length+1,draft:!0});const o=new Set(i.map(f=>f.key));n.pins.querySelectorAll(".pin").forEach(f=>{o.has(f.dataset.key)||f.remove()});for(const f of i){let m=n.pins.querySelector(`.pin[data-key="${f.key}"]`);m||(m=document.createElement("div"),m.className="pin",m.dataset.key=f.key,m.innerHTML='<div class="pin-dot"></div>',m.addEventListener("pointerdown",y=>y.stopPropagation()),f.draft||m.addEventListener("click",y=>{y.stopPropagation(),Mn(f.key)}),m.addEventListener("pointerenter",()=>ne(e)?.querySelector(`.area[data-key="${f.key}"]`)?.classList.add("hover")),m.addEventListener("pointerleave",()=>ne(e)?.querySelector(`.area[data-key="${f.key}"]`)?.classList.remove("hover")),n.pins.appendChild(m)),m.querySelector(".pin-dot").textContent=f.n;const g=f.draft?"draft":gn(f.key);m.className=`pin ${g}${f.c?.resolved?" resolved":""}${_===f.key||f.draft?" active":""}`}const s=i.filter(f=>f.draft?h?.area:f.c?.anchor?.scope==="area"||f.c?.anchor?.area),r=new Set(s.map(f=>f.key)),l=ne(e);l.querySelectorAll(".area:not(.picking)").forEach(f=>{r.has(f.dataset.key)||f.remove()});for(const f of s){let m=l.querySelector(`.area[data-key="${f.key}"]`);m||(m=document.createElement("div"),m.dataset.key=f.key,l.prepend(m)),m.className=`area${f.draft?" draft show":""}${_===f.key?" show":""}`}ae(e)}function ae(e){const t=Lt(e);!t||!c||(H?.frameId===e&&Gt(),ne(e)?.querySelectorAll(".area[data-key]").forEach(n=>{const a=n.dataset.key==="__draft"?h?.anchor:c.comments.find(l=>l.id===n.dataset.key)?.anchor;if(!a)return;const{x:i,y:o}=ze(e,a),s=a.area?a.area.w:a.w,r=a.area?a.area.h:a.h;Object.assign(n.style,{left:`${i}px`,top:`${o}px`,width:`${s}px`,height:`${r}px`})}),t.querySelectorAll(".pin").forEach(n=>{const a=n.dataset.key==="__draft"?h?.anchor:c.comments.find(r=>r.id===n.dataset.key)?.anchor;if(!a){n.hidden=!0;return}const{x:i,y:o}=ze(e,a);n.style.left=`${i}px`,n.style.top=`${o}px`;const s=c.frames.find(r=>r.id===e);n.hidden=!!s&&(i<-4||o<-4||i>s.w+4||o>s.h+4)}),(h?.frameId===e||_&&c.comments.find(n=>n.id===_)?.frameId===e)&&V())}function et(e,t,n){if(e===P)return{x:u.x+t*u.z,y:u.y+n*u.z};const a=we(c.frames.find(i=>i.id===e));return{x:u.x+(a.x+t)*u.z,y:u.y+(a.y+n)*u.z}}function tt(e,t,n){const a=e.offsetWidth||340,i=e.offsetHeight||140;let o=t+18,s=n-18;o+a>innerWidth-12&&(o=t-a-18),o=Math.max(12,Math.min(o,innerWidth-a-12)),s=Math.max(60,Math.min(s,innerHeight-i-76)),e.style.left=`${o}px`,e.style.top=`${s}px`}function V(){if(c){if(h?.prompt&&!$.hidden){const e=we(c.frames.find(t=>t.id===h.frameId));if(e){const t=$.offsetWidth||380,n=$.offsetHeight||200,a=u.x+(e.x+e.w/2)*u.z,i=u.y+(e.y+e.h/2)*u.z;e.w*u.z<t+40?tt($,u.x+(e.x+e.w)*u.z,i-n/2+18):($.style.left=`${Math.max(12,Math.min(a-t/2,innerWidth-t-12))}px`,$.style.top=`${Math.max(60,Math.min(i-n/2,innerHeight-n-76))}px`)}}else if(h&&!$.hidden){const e=ze(h.frameId,h.anchor),t=et(h.frameId,e.x,e.y);tt($,t.x,t.y)}if(_&&!W.hidden){const e=c.comments.find(t=>t.id===_);if(e?.anchor){const t=ze(e.frameId,e.anchor),n=et(e.frameId,t.x,t.y);tt(W,n.x,n.y)}}if(me(),F){const e=et(F.frameId,F.lx,F.ly),t=d("#ink-chip");t.style.left=`${e.x+10}px`,t.style.top=`${e.y+10}px`}}}function nt(e){return c.strokes.filter(t=>t.frameId===e&&!t.commentId&&gt.has(t.id))}function ie(e,t,n,a,i){N(),Se(),$.classList.remove("prompt");const o=e===P?null:i?Et(e,i.x+i.w/2,i.y+i.h/2):Et(e,t,n),s=nt(e);h={frameId:e,picked:o,lx:t,ly:n,area:i||null,inkStrokes:s.map(f=>f.id)},wn(e===P?"canvas":i?"area":"point");const r=d("#composer-area");r.hidden=!i,i&&(r.textContent=e===P?`Area \xB7 ${h.anchor.near.length||"no"} frame${h.anchor.near.length===1?"":"s"}`:`Area \xB7 ${h.anchor.elements.length} element${h.anchor.elements.length===1?"":"s"}`);const l=d("#composer-ink");l.hidden=!s.length,l.textContent=`${s.length} mark${s.length===1?"":"s"} attached`,k.placeholder=b()?c.agent.mode==="inbox"?"Comment, then \u21B5 to queue it for your agent":`Comment, then \u21B5 to send to ${c.agentLabel||"the agent"}`:"Comment, then \u21B5 \u2014 the host sends it to the agent",$.hidden=!1,k.value="",se(k),Me(e),V(),setTimeout(()=>k.focus(),0)}function Ct(e,t){return c.frames.map(n=>({f:n,d:Math.hypot(Math.max(n.x-e,0,e-n.x-n.w),Math.max(n.y-t,0,t-n.y-n.h))})).sort((n,a)=>n.d-a.d).slice(0,2).filter(n=>n.d<1200).map(n=>n.f.name)}function yn(e){const t=c.frames.filter(n=>n.x<e.x+e.w&&n.x+n.w>e.x&&n.y<e.y+e.h&&n.y+n.h>e.y).map(n=>n.name);return t.length?t:Ct(e.x+e.w/2,e.y+e.h/2)}function vn(e,t){const n=X(e);if(!n?.body)return[];const a=Math.max(12,Math.min(t.w,t.h)*.08),i=t.x-a,o=t.y-a,s=t.x+t.w+a,r=t.y+t.h+a,l=[];for(const g of n.body.querySelectorAll("*")){if(l.length>600)break;const y=g.getBoundingClientRect();!y.width||!y.height||["SCRIPT","STYLE","LINK","META"].includes(g.tagName)||y.left>=i&&y.top>=o&&y.right<=s&&y.bottom<=r&&l.push(g)}const f=new Set(l);let m=l.filter(g=>{for(let y=g.parentElement;y;y=y.parentElement)if(f.has(y))return!1;return!0});if(!m.length){const g=de(e,t.x+t.w/2,t.y+t.h/2);g&&g!==n.documentElement&&(m=[g])}return m.slice(0,14).map(g=>({selector:ke(g),tag:g.tagName.toLowerCase(),text:(g.innerText||g.getAttribute("aria-label")||g.getAttribute("alt")||"").replace(/\s+/g," ").trim().slice(0,80)}))}function xn(e,t){const n=X(e);let a=de(e,t.x+t.w/2,t.y+t.h/2);for(;a&&a!==n?.body;){const i=a.getBoundingClientRect();if(i.left<=t.x+2&&i.top<=t.y+2&&i.right>=t.x+t.w-2&&i.bottom>=t.y+t.h-2)break;a=a.parentElement}return a&&a!==n?.documentElement?{selector:ke(a),tag:a.tagName.toLowerCase(),text:(a.innerText||"").replace(/\s+/g," ").trim().slice(0,80)}:null}function wn(e){const t=h;if(!t)return;const n=c.frames.find(a=>a.id===t.frameId);t.scope=e,e==="canvas"&&t.area?t.anchor={scope:e,wx:t.area.x,wy:t.area.y,area:{w:t.area.w,h:t.area.h},near:yn(t.area)}:e==="canvas"?t.anchor={scope:e,wx:t.lx,wy:t.ly,near:Ct(t.lx,t.ly)}:e==="area"?t.anchor={scope:e,x:t.area.x,y:t.area.y,w:t.area.w,h:t.area.h,sx:t.picked?.sx||0,sy:t.picked?.sy||0,elements:vn(t.frameId,t.area),container:xn(t.frameId,t.area)}:t.anchor={...t.picked||{},scope:"point",x:t.lx,y:t.ly,fx:void 0,fy:void 0},Me(t.frameId),V()}const bn={Mobile:["Login","Onboarding","Home feed","Profile","Settings","Checkout"],Tablet:["Dashboard","Reader","Calendar","Settings","Kanban board"],Desktop:["Landing page","Dashboard","Pricing","Sign up","Settings","Blog post"]};function De(e){const t=c?.frames.find(a=>a.id===e);if(!t)return;N(),Se();const n=t.w<=480?"Mobile":t.w<=1024?"Tablet":"Desktop";h={frameId:e,picked:null,lx:24,ly:24,area:null,inkStrokes:[],prompt:!0,scope:"frame",anchor:{scope:"frame",x:24,y:24}},$.classList.add("prompt"),d("#prompt-title").textContent=`What should \u201C${t.name}\u201D be?`,d("#prompt-ideas").innerHTML=bn[n].map(a=>`<button>${w(a)}</button>`).join(""),d("#composer-area").hidden=!0,d("#composer-ink").hidden=!0,k.placeholder=n==="Mobile"?"e.g. a login screen with Google sign-in and a friendly illustration":"e.g. a landing page for a habit tracker with pricing and testimonials",$.hidden=!1,k.value="",se(k),V(),setTimeout(()=>k.focus(),0)}d("#prompt-ideas").addEventListener("click",e=>{const t=e.target.closest("button");t&&(k.value=`${t.textContent} screen \u2014 `,se(k),k.focus(),k.setSelectionRange(k.value.length,k.value.length))});function q(){$.classList.contains("soft")&&($.querySelector(".hint").innerHTML="<kbd>\u21B5</kbd> send \xB7 <kbd>\u21E7\u21B5</kbd> new line \xB7 <kbd>esc</kbd>"),$.classList.remove("prompt","soft"),Tt=null,h?.deep&&Te();const e=h?.frameId;h=null,$.hidden=!0,e&&Me(e)}function se(e){e.style.height="auto",e.style.height=`${Math.min(180,e.scrollHeight)}px`}k.addEventListener("input",()=>se(k)),k.addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Enter"&&!e.shiftKey&&!e.isComposing&&(e.preventDefault(),kn()),e.key==="Escape"&&q()});async function kn(){const e=k.value.trim();if(!e||!h)return;const t=h;q();const n=c.strokes.filter(i=>t.inkStrokes.includes(i.id)),a={frameId:t.frameId,text:e,anchor:t.anchor,author:{name:C.name,color:C.color},inkStrokes:t.inkStrokes};n.length&&t.frameId!==P&&Object.assign(a,$n(t.frameId,n));try{await p("POST","/__loop/api/comments",a),b()||v("Comment added \u2014 the host will send it to the agent")}catch(i){v(i.message)}}function $n(e,t){const n=c.frames.find(f=>f.id===e),a=X(e),i=new Map;for(const f of t){const m=f.points.length/2,g=Math.max(1,Math.floor(m/14));for(let y=0;y<m;y+=g){const he=f.points[y*2]-n.x,_e=f.points[y*2+1]-n.y,S=de(e,he,_e);if(!S||S===a?.documentElement||S===a?.body)continue;const le=ke(S);i.has(le)||i.set(le,{selector:le,tag:S.tagName.toLowerCase(),text:(S.innerText||"").replace(/\s+/g," ").trim().slice(0,60),el:S})}}const o=[...i.values()].slice(0,10),s=Math.min(1,1280/Math.max(n.w,n.h)),r=document.createElement("canvas");r.width=Math.round(n.w*s),r.height=Math.round(n.h*s);const l=r.getContext("2d");l.scale(s,s),l.fillStyle="#fff",l.fillRect(0,0,n.w,n.h),l.strokeStyle="#c9c6bd",l.lineWidth=2,l.strokeRect(1,1,n.w-2,n.h-2),l.font="14px ui-monospace, Menlo, monospace";for(const f of o)try{const m=f.el.getBoundingClientRect();l.strokeStyle="#2F5BFF",l.setLineDash([6,4]),l.lineWidth=1.5,l.strokeRect(m.left,m.top,m.width,m.height),l.setLineDash([]),l.fillStyle="#2F5BFF",l.fillText(f.tag+(f.text?` "${f.text.slice(0,30)}"`:""),m.left+4,Math.max(14,m.top-4))}catch{}l.strokeStyle=Ve,l.lineWidth=4,l.lineCap="round",l.lineJoin="round";for(const f of t){l.beginPath();for(let m=0;m<f.points.length;m+=2){const g=f.points[m]-n.x,y=f.points[m+1]-n.y;m?l.lineTo(g,y):l.moveTo(g,y)}l.stroke()}return{ink:o.map(({el:f,...m})=>m),annotationPng:r.toDataURL("image/png")}}function ta(e,t,n){F={frameId:e,lx:t,ly:n},d("#ink-chip").hidden=!1,V()}function Se(){F=null,d("#ink-chip").hidden=!0}let Tt=null;function En(e,t,n){if(!(!$.hidden&&k.value.trim())){if(e){const a=c.frames.find(f=>f.id===e),i=nt(e),o=i.flatMap(f=>f.points.filter((m,g)=>g%2===0)),s=i.flatMap(f=>f.points.filter((m,g)=>g%2===1)),r=(o.length?(Math.min(...o)+Math.max(...o))/2:t[t.length-2])-a.x,l=(s.length?(Math.min(...s)+Math.max(...s))/2:t[t.length-1])-a.y;ie(e,r,l)}else ie(P,t[t.length-2],t[t.length-1],"canvas");h&&(h.soft=!0,$.classList.add("soft"),k.placeholder="What should change here?",$.querySelector(".hint").innerHTML="<kbd>\u21B5</kbd> send \xB7 <kbd>esc</kbd> skip",Tt={x:n.clientX,y:n.clientY,t:Date.now()})}}addEventListener("pointerdown",e=>{!h?.soft||$.hidden||$.contains(e.target)||k.value.trim()||T==="pen"&&e.target.closest("#viewport")||q()},!0),k.addEventListener("input",()=>{h?.soft&&k.value.trim()&&(h.soft=!1,$.classList.remove("soft"))}),d("#ink-chip button").addEventListener("click",()=>{if(!F)return;const e=nt(F.frameId),t=c.frames.find(s=>s.id===F.frameId),n=e.flatMap(s=>s.points.filter((r,l)=>l%2===0)),a=e.flatMap(s=>s.points.filter((r,l)=>l%2===1)),i=n.length?(Math.min(...n)+Math.max(...n))/2-t.x:F.lx,o=a.length?(Math.min(...a)+Math.max(...a))/2-t.y:F.ly;ie(F.frameId,i,o)});function Mn(e){q(),Se(),_=e,W.hidden=!1,Pt(),Ee(),V()}function N(){_&&(_=null,W.hidden=!0,Ee())}const _t=e=>{const t=(Date.now()-e)/1e3;return t<60?"just now":t<3600?`${Math.floor(t/60)}m ago`:t<86400?`${Math.floor(t/3600)}h ago`:new Date(e).toLocaleDateString()};function Ie(e){if(!e)return"";const t=/claude-([a-z]+)-(\d+)(?:-(\d+))?/i.exec(e);if(t)return`${t[1][0].toUpperCase()}${t[1].slice(1)} ${t[2]}${t[3]&&t[3].length<=2?"."+t[3]:""}`;const n=/^gpt-([\d.]+)(?:-([a-z]+))?/i.exec(e);return n?`GPT-${n[1]}${n[2]?" "+n[2][0].toUpperCase()+n[2].slice(1):""}`:e}function At(e){const t=[];if(e.model&&t.push(Ie(e.model)),e.startedAt&&e.finishedAt){const n=Math.round((e.finishedAt-e.startedAt)/1e3);t.push(n<60?`${n}s`:`${Math.floor(n/60)}m ${n%60}s`)}return t.length?`<div class="a-meta">${w(t.join(" \xB7 "))}</div>`:""}const Le='<svg viewBox="0 0 12 12"><path d="M2.5 6.5l2.2 2.2L9.5 3.5"/></svg>';function Sn(e){const t=b(),n=c.live[e.frameId];switch(e.status){case"waiting":return`<div class="agent-line waiting"><span class="a-ic"></span><div><div>Waiting for the host to send this to the agent.</div>${t?`<div class="a-actions"><button data-act="send" data-id="${e.id}">Send to agent</button></div>`:""}</div></div>`;case"queued":return`<div class="agent-line working"><span class="a-ic">${Le}</span><div><div class="a-text">${c.agent.mode==="inbox"?"Queued for your agent \u2014 run loop inbox --wait":"Queued \u2014 waiting for the frame to be free"}</div>${t?`<div class="a-actions"><button class="quiet" data-act="cancel" data-id="${e.id}">Cancel</button></div>`:""}</div></div>`;case"working":return`<div class="agent-line working"><span class="a-ic">${Le}</span><div><div>${e.model?`<span class="a-model">${w(Ie(e.model))}</span> `:""}<span class="a-text" data-step-for="${e.id}">${w(n?.commentId===e.id?n.step:"Working\u2026")}</span> <span class="muted" data-elapsed-from="${n?.startedAt||e.createdAt}"></span></div>${t?`<div class="a-actions"><button class="quiet" data-act="cancel" data-id="${e.id}">Stop</button></div>`:""}</div></div>`;case"done":return`<div class="agent-line"><span class="a-ic">${Le}</span><div><div>${w(e.undone?"Reverted.":e.reply||"Done.")}</div>${At(e)}${t&&e.snapshot&&!e.undone?`<div class="a-actions"><button class="quiet" data-act="undo" data-id="${e.id}">Undo change</button></div>`:""}${t&&e.undone&&e.redoSnap?`<div class="a-actions"><button class="quiet" data-act="redo" data-id="${e.id}">Redo change</button></div>`:""}</div></div>`;case"error":return`<div class="agent-line error"><span class="a-ic">${Le}</span><div><div>${w(e.reply||"Something went wrong.")}</div>${At(e)}${t?`<div class="a-actions"><button data-act="send" data-id="${e.id}">Retry</button></div>`:""}</div></div>`;case"canceled":return`<div class="agent-line waiting"><span class="a-ic"></span><div><div>Stopped.</div>${t?`<div class="a-actions"><button data-act="send" data-id="${e.id}">Send again</button></div>`:""}</div></div>`;default:return""}}function Pt(){const e=c.comments.find(l=>l.id===_);if(!e)return N();const t=c.frames.find(l=>l.id===e.frameId),n=St(e.frameId).findIndex(l=>l.id===e.id)+1,a=W.querySelector("textarea")?.value||"",i=document.activeElement===W.querySelector("textarea"),o=Mt(e.id).map(l=>l.kind==="note"?`
9
- <div class="msg msg-agent">
10
- <div class="msg-head"><span class="av av-agent">${Le}</span><b>${w(l.author?.name||"Agent")}</b><time>${_t(l.createdAt)}</time>${l.model?`<span class="a-model">${w(Ie(l.model))}</span>`:""}</div>
11
- <div class="msg-text">${w(l.text)}</div>
12
- </div>`:`
13
- <div class="msg">
14
- <div class="msg-head"><span class="av" style="background:${w(l.author?.color||"#888")}">${w(Qe(l.author?.name))}</span><b>${w(l.author?.name||"You")}</b><time>${_t(l.createdAt)}</time></div>
15
- <div class="msg-text">${w(l.text)}</div>
16
- ${l.ink?.length?`<div class="muted" style="font-size:11.5px;margin-top:4px">\u270E ${l.ink.length} marked element${l.ink.length===1?"":"s"}</div>`:""}
17
- ${Sn(l)}
18
- </div>`).join("");W.innerHTML=`
19
- <div class="thread-head"><span class="t-title">#${n} \xB7 ${w(t?.name||(e.frameId===P?"Canvas":""))}</span>
20
- <span class="t-actions">
21
- <button class="icon-btn" data-act="resolve" title="${e.resolved?"Reopen":"Resolve"}">${e.resolved?"\u21BA":"\u2713"}</button>
22
- <button class="icon-btn" data-act="delete" title="Delete thread">\u232B</button>
23
- <button class="icon-btn" data-act="close" title="Close">\xD7</button>
24
- </span></div>
25
- <div class="thread-body">${o}</div>
26
- <div class="thread-reply"><textarea rows="1" placeholder="Reply \u2014 \u21B5 sends it to the agent"></textarea></div>`;const s=W.querySelector("textarea");s.value=a,se(s),i&&s.focus(),s.addEventListener("input",()=>se(s)),s.addEventListener("keydown",async l=>{if(l.stopPropagation(),l.key==="Escape")return N();if(l.key==="Enter"&&!l.shiftKey&&!l.isComposing){l.preventDefault();const f=s.value.trim();if(!f)return;s.value="";try{await p("POST","/__loop/api/comments",{frameId:e.frameId,parentId:e.id,text:f,author:{name:C.name,color:C.color}})}catch(m){v(m.message)}}});const r=W.querySelector(".thread-body");r.scrollTop=r.scrollHeight}W.addEventListener("pointerdown",e=>e.stopPropagation()),W.addEventListener("click",async e=>{const t=e.target.closest("[data-act]");if(!t)return;const n=t.dataset.act,a=t.dataset.id||_;try{if(n==="close")return N();if(n==="delete"){confirm("Delete this comment thread?")&&(await p("DELETE",`/__loop/api/comments/${_}`),N());return}if(n==="resolve"){await p("POST",`/__loop/api/comments/${_}/resolve`);return}if(n==="undo"){let i=await fetch(`/__loop/api/comments/${a}/undo`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"}),o=await i.json().catch(()=>({}));if(i.status===409&&o.error==="newer"){if(!confirm(`This frame has ${o.newer} newer change${o.newer===1?"":"s"} after this one. Undoing this reverts ${o.newer===1?"it":"them"} too. Continue?`))return;i=await fetch(`/__loop/api/comments/${a}/undo`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({force:!0})}),o=await i.json().catch(()=>({}))}if(!i.ok)throw new Error(o.error||"Could not undo");v(o.reverted>1?`Reverted ${o.reverted} changes`:"Change reverted");return}await p("POST",`/__loop/api/comments/${a}/${n}`),n==="redo"&&v("Change re-applied")}catch(i){v(i.message)}}),$.addEventListener("pointerdown",e=>e.stopPropagation());function R(e){if(!(e==="frame"&&!b())){if(e!=="deep"&&H&&Te(),h?.soft&&!k.value.trim()&&q(),T=e,x.dataset.tool=e,document.querySelectorAll("#toolbar [data-tool]").forEach(t=>t.classList.toggle("on",t.dataset.tool===e)),U.hidden=!0,e!=="pen"&&Se(),c)for(const t of c.frames)D(t);oe()}}document.querySelectorAll("#toolbar [data-tool]").forEach(e=>e.addEventListener("click",()=>R(e.dataset.tool)));function B(e){if(M=e,E.clear(),c)for(const t of c.frames)D(t);oe(),Ke()}let j=null;x.addEventListener("pointerdown",e=>{if(!c||e.target.closest(".pin, .stop, .rename"))return;const t=e.target.closest(".frame"),n=t?.dataset.id;if(e.button===1||T==="hand"||te)return Tn(e);if(e.button===0){if(T==="pen")return zn(e);if(T==="frame")return An(e);if(T==="erase"){j={type:"erase"},zt(e),x.setPointerCapture(e.pointerId);return}if(T==="deep"){if(n&&e.target.closest(".frame-body")){Wn(n,e);return}Te(),q(),N();return}if(T==="comment"){const a=n&&e.target.closest(".frame-body");if(!a&&(!$.hidden||_)){q(),N();return}j={type:"cpick",fid:a?n:P,sx:e.clientX,sy:e.clientY,area:!1,rect:null},x.setPointerCapture(e.pointerId);return}if(q(),e.target.closest(".resize")&&b())return Pn(n,e);if(n&&e.shiftKey&&b()){Xn(n),N();return}return e.target.closest(".frame-label")?(N(),E.has(n)?b()?Cn(n,e):void 0:(B(n),b()?_n(n,e):void 0)):(N(),!n&&!e.shiftKey&&B(null),Ln(e,n))}});function Ln(e,t){const n=K(e.clientX,e.clientY);j={type:"marquee",x0:n.x,y0:n.y,clickFid:t,base:e.shiftKey?new Set([...E,...M?[M]:[]]):new Set},x.classList.add("dragging"),x.setPointerCapture(e.pointerId)}function Cn(e,t){const n=[...E];j={type:"gmove",ids:n,sx:t.clientX,sy:t.clientY,from:Object.fromEntries(n.map(a=>{const i=c.frames.find(o=>o.id===a);return[a,{x:i.x,y:i.y}]})),moved:!1},x.classList.add("dragging"),x.setPointerCapture(t.pointerId)}function Tn(e){j={type:"pan",sx:e.clientX,sy:e.clientY,vx:u.x,vy:u.y},x.classList.add("dragging"),x.setPointerCapture(e.pointerId)}function _n(e,t){const n=c.frames.find(a=>a.id===e);j={type:"move",fid:e,sx:t.clientX,sy:t.clientY,fx:n.x,fy:n.y,moved:!1,dup:t.altKey},x.classList.add("dragging"),x.setPointerCapture(t.pointerId)}function An(e){const t=K(e.clientX,e.clientY);j={type:"draw",x0:t.x,y0:t.y,rect:null},x.classList.add("dragging"),x.setPointerCapture(e.pointerId)}function Pn(e,t){const n=c.frames.find(i=>i.id===e),a=t.target.closest(".resize")?.dataset.dir||"se";j={type:"resize",fid:e,dir:a,sx:t.clientX,sy:t.clientY,x0:n.x,y0:n.y,w:n.w,h:n.h},x.classList.add("dragging"),x.setPointerCapture(t.pointerId)}function zn(e){Se(),h?.soft&&!k.value.trim()&&q();const t=K(e.clientX,e.clientY),n=document.createElementNS("http://www.w3.org/2000/svg","path");n.setAttribute("stroke",Ve),n.setAttribute("stroke-width",3/u.z),ge.appendChild(n),j={type:"stroke",points:[t.x,t.y],path:n,width:3/u.z},x.classList.add("dragging"),x.setPointerCapture(e.pointerId)}const Dn=11;function In(e,t,n,a,i,o){const s=i-n,r=o-a,l=s*s+r*r,f=l?Math.max(0,Math.min(1,((e-n)*s+(t-a)*r)/l)):0;return Math.hypot(e-(n+f*s),t-(a+f*r))}function zt(e){const t=K(e.clientX,e.clientY);for(const n of[...c.strokes]){if(n.commentId||String(n.id).startsWith("ink-"))continue;const a=Dn/u.z+(n.width||3)/2,i=n.points;let o=!1;for(let s=0;s+1<i.length&&!o;s+=2){const r=s+3<i.length?i[s+2]:i[s],l=s+3<i.length?i[s+3]:i[s+1];o=In(t.x,t.y,i[s],i[s+1],r,l)<=a}o&&(c.strokes=c.strokes.filter(s=>s.id!==n.id),ge.querySelector(`path[data-id="${n.id}"]`)?.remove(),p("DELETE",`/__loop/api/strokes/${n.id}`).catch(()=>{}),O("Erase mark",()=>ue({strokes:[n]}),()=>p("DELETE",`/__loop/api/strokes/${n.id}`)))}}x.addEventListener("pointermove",e=>{if(mn(e.clientX,e.clientY),!j){if(T==="comment"&&(U.hidden=!0),T==="deep"){const n=e.target.closest(".frame-body")&&e.target.closest(".frame")?.dataset.id;n&&!e.target.closest(".pin")?hn(n,e.clientX,e.clientY):U.hidden=!0}return}const t=j;if(t.type==="pan")u.x=t.vx+e.clientX-t.sx,u.y=t.vy+e.clientY-t.sy,Y();else if(t.type==="move"&&t.dup){t.moved=!0;const n=c.frames.find(i=>i.id===t.fid);if(t.to={x:t.fx+(e.clientX-t.sx)/u.z,y:t.fy+(e.clientY-t.sy)/u.z},!e.metaKey&&!e.ctrlKey){const i=ft({...t.to,w:n.w,h:n.h},null);t.to.x+=i.dx,t.to.y+=i.dy,J(i.guides)}else J([]);const a=d("#dup-ghost");Object.assign(a.style,{left:`${t.to.x}px`,top:`${t.to.y}px`,width:`${n.w}px`,height:`${n.h}px`}),a.querySelector("span").textContent=`${n.name} copy`,a.hidden=!1}else if(t.type==="move"){t.moved=!0;const n=c.frames.find(i=>i.id===t.fid),a={x:t.fx+(e.clientX-t.sx)/u.z,y:t.fy+(e.clientY-t.sy)/u.z};if(!e.metaKey&&!e.ctrlKey){const i=ft({...a,w:n.w,h:n.h},t.fid);a.x+=i.dx,a.y+=i.dy,J(i.guides)}else J([]);Q.set(t.fid,a),D(n),V()}else if(t.type==="marquee"){const n=K(e.clientX,e.clientY),a={x:Math.min(t.x0,n.x),y:Math.min(t.y0,n.y),w:Math.abs(n.x-t.x0),h:Math.abs(n.y-t.y0)};if(!t.moved&&a.w*u.z<4&&a.h*u.z<4)return;!t.moved&&t.clickFid&&!e.shiftKey&&B(null),t.moved=!0;const i=d("#marquee");i.hidden=!1,Object.assign(i.style,{left:`${a.x}px`,top:`${a.y}px`,width:`${a.w}px`,height:`${a.h}px`});const o=c.frames.filter(s=>s.x<a.x+a.w&&s.x+s.w>a.x&&s.y<a.y+a.h&&s.y+s.h>a.y).map(s=>s.id);ct([...new Set([...t.base,...o])])}else if(t.type==="gmove"){t.moved=!0;let n=(e.clientX-t.sx)/u.z,a=(e.clientY-t.sy)/u.z;const i=t.ids.map(o=>{const s=c.frames.find(r=>r.id===o);return{x:t.from[o].x+n,y:t.from[o].y+a,w:s.w,h:s.h}});if(!e.metaKey&&!e.ctrlKey){const o=dt(i),s=ft(o,new Set(t.ids));n+=s.dx,a+=s.dy,J(s.guides)}else J([]);for(const o of t.ids)Q.set(o,{x:t.from[o].x+n,y:t.from[o].y+a}),D(c.frames.find(s=>s.id===o));me()}else if(t.type==="cpick"){if(!t.area&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)>6&&(t.area=!0,q(),N(),x.classList.add("dragging")),!t.area)return;let n,a;if(t.fid===P)n=K(t.sx,t.sy),a=K(e.clientX,e.clientY);else{const o=c.frames.find(r=>r.id===t.fid),s=r=>({x:Math.max(0,Math.min(o.w,r.lx)),y:Math.max(0,Math.min(o.h,r.ly))});n=s(be(t.fid,t.sx,t.sy)),a=s(be(t.fid,e.clientX,e.clientY))}t.rect={x:Math.min(n.x,a.x),y:Math.min(n.y,a.y),w:Math.abs(a.x-n.x),h:Math.abs(a.y-n.y)};let i=ne(t.fid).querySelector(".area.picking");i||(i=document.createElement("div"),i.className="area picking show",ne(t.fid).prepend(i)),Object.assign(i.style,{left:`${t.rect.x}px`,top:`${t.rect.y}px`,width:`${t.rect.w}px`,height:`${t.rect.h}px`})}else if(t.type==="draw"){const n=K(e.clientX,e.clientY),a={x:Math.min(t.x0,n.x),y:Math.min(t.y0,n.y),w:Math.abs(n.x-t.x0),h:Math.abs(n.y-t.y0)};e.shiftKey&&(a.w=a.h=Math.max(a.w,a.h)),t.rect=a;const i=d("#draw-box");Object.assign(i.style,{left:`${a.x}px`,top:`${a.y}px`,width:`${a.w}px`,height:`${a.h}px`}),i.querySelector("span").textContent=`${Math.round(a.w)} \xD7 ${Math.round(a.h)}`,i.hidden=!1}else if(t.type==="resize"){const n=(e.clientX-t.sx)/u.z,a=(e.clientY-t.sy)/u.z,i=120;let o=t.x0,s=t.y0,r=t.w,l=t.h;if(t.dir.includes("e")&&(r=t.w+n),t.dir.includes("s")&&(l=t.h+a),t.dir.includes("w")&&(r=t.w-n,o=t.x0+n),t.dir.includes("n")&&(l=t.h-a,s=t.y0+a),e.shiftKey&&t.dir.length===2){const m=Math.max(r/t.w,l/t.h),g=t.w*m,y=t.h*m;t.dir.includes("w")&&(o=t.x0+t.w-g),t.dir.includes("n")&&(s=t.y0+t.h-y),r=g,l=y}r<i&&(t.dir.includes("w")&&(o=t.x0+t.w-i),r=i),l<i&&(t.dir.includes("n")&&(s=t.y0+t.h-i),l=i);const f={x:o,y:s,w:r,h:l};if(!e.metaKey&&!e.ctrlKey&&!e.shiftKey){const m=Qn(f,t.fid,t.dir);Object.assign(f,m.rect),J(m.guides)}else J([]);Q.set(t.fid,f),D(c.frames.find(m=>m.id===t.fid)),d("#fp-sw")&&(d("#fp-sw").value=Math.round(f.w),d("#fp-sh").value=Math.round(f.h))}else if(t.type==="stroke"){const n=K(e.clientX,e.clientY),a=t.points.length;if(Math.hypot(n.x-t.points[a-2],n.y-t.points[a-1])*u.z<1.5)return;t.points.push(n.x,n.y),t.path.setAttribute("d",kt(t.points))}else t.type==="erase"&&zt(e)});const Dt=async e=>{const t=j;if(t){if(j=null,x.classList.remove("dragging"),J([]),t.type==="marquee"){d("#marquee").hidden=!0,!t.moved&&t.clickFid&&(B(t.clickFid),z.get(t.clickFid)?.el.classList.contains("empty")&&De(t.clickFid));return}if(t.type==="gmove"){if(!t.moved)return;L=null,Fe();const n=t.from,a={};for(const i of t.ids){const o=Q.get(i);Q.delete(i);const s=c.frames.find(r=>r.id===i);o&&s&&(Object.assign(s,o),a[i]={x:o.x,y:o.y})}Z(a),O(`Move ${t.ids.length} frames`,()=>Z(n),()=>Z(a));return}if(t.type==="cpick"){if(document.querySelectorAll(".area.picking").forEach(i=>i.remove()),t.area&&t.rect&&t.rect.w*u.z>8&&t.rect.h*u.z>8)return ie(t.fid,t.rect.x,t.rect.y,null,t.rect);if(t.area)return;if(t.fid===P){const i=K(t.sx,t.sy);return ie(P,i.x,i.y,"canvas")}const{lx:n,ly:a}=be(t.fid,t.sx,t.sy);return z.get(t.fid)?.el.classList.contains("empty")?De(t.fid):ie(t.fid,n,a)}if(t.type==="draw"){d("#draw-box").hidden=!0;const n=t.rect;n&&n.w*u.z>12&&n.h*u.z>12&&it("Frame",n.w,n.h,n.x,n.y);return}if(t.type==="move"&&t.dup){d("#dup-ghost").hidden=!0,t.moved&&t.to&&Xe(t.fid,t.to);return}if(t.type==="move"&&t.moved||t.type==="resize"){const n=Q.get(t.fid),a=c.frames.find(o=>o.id===t.fid),i=t.type==="move"?{x:t.fx,y:t.fy}:{x:t.x0,y:t.y0,w:t.w,h:t.h};if(n&&a&&Object.assign(a,n),Q.delete(t.fid),n){p("PATCH",`/__loop/api/frames/${t.fid}`,n).catch(r=>v(r.message));const o={...n},s=t.fid;O(t.type==="move"?"Move frame":"Resize frame",()=>ee(s,i),()=>ee(s,o))}t.type==="resize"&&setTimeout(()=>ae(t.fid),50)}else if(t.type==="stroke"){const n=t.points;n.length<4&&n.push(n[0]+.5,n[1]+.5);const a=new Map;for(let o=0;o<n.length;o+=2){const s=pn(n[o],n[o+1]);s&&a.set(s.id,(a.get(s.id)||0)+1)}const i=[...a.entries()].sort((o,s)=>s[1]-o[1])[0]?.[0]||null;try{const o=await p("POST","/__loop/api/strokes",{points:n,color:Ve,width:t.width,frameId:i});gt.add(o.id),O("Draw mark",()=>p("DELETE",`/__loop/api/strokes/${o.id}`),()=>ue({strokes:[o]})),t.path.remove(),c.strokes.find(s=>s.id===o.id)||c.strokes.push(o),$t(),En(i,n,e)}catch(o){t.path.remove(),v(o.message)}}}};x.addEventListener("pointerup",Dt),x.addEventListener("pointercancel",Dt),x.addEventListener("pointerleave",()=>{U.hidden=!0}),addEventListener("wheel",e=>{if(e.ctrlKey||e.metaKey)return xt(e,e.clientX,e.clientY);if(!e.target.closest?.("#viewport"))return;e.preventDefault();const t=e.deltaMode===1?16:1;u.x-=e.deltaX*t,u.y-=e.deltaY*t,vt()},{passive:!1,capture:!0});let qe=1;addEventListener("gesturestart",e=>{e.preventDefault(),qe=u.z}),addEventListener("gesturechange",e=>{e.preventDefault(),G(e.clientX,e.clientY,qe*e.scale/u.z)});const It=()=>{const e=document.activeElement;return e&&(e.tagName==="INPUT"||e.tagName==="TEXTAREA"||e.isContentEditable)};addEventListener("keydown",e=>{if(It())return;if(e.code==="Space"&&!te){te=!0,x.classList.add("panning"),c&&c.frames.forEach(D),e.preventDefault();return}if(e.metaKey||e.ctrlKey){if(e.key.toLowerCase()==="z"){e.preventDefault(),e.shiftKey?lt():Ut();return}if(e.key.toLowerCase()==="c"&&M&&b()){e.preventDefault(),Ye=M,v(`Copied \u201C${c.frames.find(n=>n.id===M)?.name}\u201D \u2014 \u2318V to paste`,1600);return}if(e.key.toLowerCase()==="v"&&Ye&&b()){e.preventDefault(),c.frames.find(n=>n.id===Ye)?Xe(Ye):v("The copied frame no longer exists");return}if(e.key.toLowerCase()==="d"&&E.size&&b()){e.preventDefault(),[...E].forEach(n=>Xe(n));return}if(e.key.toLowerCase()==="d"&&M&&b()){e.preventDefault(),Xe(M);return}if(e.key.toLowerCase()==="a"&&b()){e.preventDefault(),ct(c.frames.map(n=>n.id));return}if(e.key.toLowerCase()==="y"&&e.ctrlKey){e.preventDefault(),lt();return}e.key==="0"&&(e.preventDefault(),u.z=1,Y()),(e.key==="="||e.key==="+")&&(e.preventDefault(),G(innerWidth/2,innerHeight/2,1.25)),e.key==="-"&&(e.preventDefault(),G(innerWidth/2,innerHeight/2,.8));return}const t=e.key.toLowerCase();if(t==="v")R("select");else if(t==="h")R("hand");else if(t==="p")R("pen");else if(t==="e")R("erase");else if(t==="c")R("comment");else if(t==="d")R("deep");else if(t==="n"&&b())Ht();else if(t==="f"&&b())R(T==="frame"?"select":"frame");else if(e.key==="!"||e.shiftKey&&e.code==="Digit1")xe();else if(e.key==="="||e.key==="+")G(innerWidth/2,innerHeight/2,1.25);else if(e.key==="-")G(innerWidth/2,innerHeight/2,.8);else if(e.key==="Escape"&&H)Te(),q();else if(e.key==="Escape")$.hidden?_?N():!d("#agent-menu").hidden||!d("#share-menu").hidden?fe():(B(null),R("select")):q();else if((e.key==="Backspace"||e.key==="Delete")&&E.size&&b())Un([...E]);else if(e.altKey&&b()&&E.size>=2&&Vt[e.code])e.preventDefault(),Zt(Vt[e.code]);else if((e.key==="Backspace"||e.key==="Delete")&&M&&b()){const n=c.frames.find(a=>a.id===M);n&&Bn(n.id).then(()=>{M=null,oe()})}}),addEventListener("keyup",e=>{e.code==="Space"&&(te=!1,x.classList.remove("panning"),c&&c.frames.forEach(D))}),addEventListener("blur",()=>{te&&(te=!1,x.classList.remove("panning"))}),d("#zoom-in").onclick=()=>G(innerWidth/2,innerHeight/2,1.25),d("#zoom-out").onclick=()=>G(innerWidth/2,innerHeight/2,.8),d("#zoom-level").onclick=()=>xe();function fe(){d("#agent-menu").hidden=!0,d("#share-menu").hidden=!0}function qt(e,t){const n=t.getBoundingClientRect();e.hidden=!1,e.style.top=`${n.bottom+8}px`,e.style.left=`${Math.max(12,Math.min(n.right-e.offsetWidth,innerWidth-e.offsetWidth-12))}px`}d("#agent-pill").addEventListener("click",e=>{if(e.stopPropagation(),!b())return;const t=d("#agent-menu"),n=!t.hidden;fe(),n||qt(t,e.currentTarget)}),document.querySelectorAll("#agent-menu .menu-item").forEach(e=>e.addEventListener("click",async()=>{try{await p("POST","/__loop/api/settings",{mode:e.dataset.mode,runner:e.dataset.runner}),v(e.dataset.mode==="inbox"?"Comments will queue for your agent session":`Loop will run ${e.dataset.runner==="codex"?"Codex":"Claude Code"} on each comment`)}catch(t){v(t.message)}fe()}));function qn(){const e=!!c.emailSharing;d("#share-menu > .menu-title").textContent=e?"Invite people":"Share this canvas",d("#invite-signin").hidden=!e||!!I?.user,d("#invite-form").hidden=!e||!I?.user;const t=d("#share-menu .lan-share");t.open=!e,t.querySelector("summary").hidden=!e,t.classList.toggle("only",!e)}function Oe(){const e=c.share||{};d("#share-lan").value=e.lan||"No network connection",d("#share-public-row").hidden=!e.public,d("#share-public").value=e.public||"",d("#share-public-btn").hidden=!!e.public,d("#share-public-btn").textContent=e.tunnelAvailable?"Create public link":"Create public link (needs cloudflared)"}d("#share-btn").addEventListener("click",async e=>{if(e.stopPropagation(),!b()){try{await navigator.clipboard.writeText(location.href),v("Link copied")}catch{v(location.href,5e3)}return}const t=d("#share-menu"),n=!t.hidden;fe(),n||(Oe(),qn(),d("#share-public-note").textContent="",qt(t,e.currentTarget),Re())}),d("#share-public-btn").addEventListener("click",async()=>{const e=d("#share-public-note"),t=d("#share-public-btn");t.disabled=!0,e.textContent="Opening a tunnel\u2026";try{c.share=await p("POST","/__loop/api/share/public"),e.textContent="Live while this Mac is awake and Loop is running.",Oe()}catch(n){e.textContent=n.message}t.disabled=!1}),d("#share-rotate").addEventListener("click",async()=>{confirm("Reset share links? Anyone using the old links loses access.")&&(c.share=await p("POST","/__loop/api/share/rotate"),Oe(),v("Links reset"))}),document.querySelectorAll("[data-copy]").forEach(e=>e.addEventListener("click",async()=>{const t=d("#"+e.dataset.copy).value;try{await navigator.clipboard.writeText(t),v("Link copied")}catch{d("#"+e.dataset.copy).select()}})),document.querySelectorAll(".menu").forEach(e=>e.addEventListener("pointerdown",t=>t.stopPropagation())),addEventListener("pointerdown",e=>{e.target.closest(".menu, #agent-pill, #share-btn")||fe()});let Ot="1440x1024";function Ht(){fe(),d("#new-frame").hidden=!1;const e=d("#new-frame-input");e.value="",setTimeout(()=>e.focus(),0)}function He(){d("#new-frame").hidden=!0}d("#new-frame [data-close]").addEventListener("click",He),d("#new-frame").addEventListener("pointerdown",e=>{e.target.id==="new-frame"&&He()}),document.querySelectorAll("#size-pick button").forEach(e=>e.addEventListener("click",()=>{Ot=e.dataset.size,document.querySelectorAll("#size-pick button").forEach(t=>t.classList.toggle("on",t===e))})),d("#new-frame-input").addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Escape"&&He(),e.key==="Enter"&&!e.shiftKey&&!e.isComposing&&(e.preventDefault(),Nt())}),d("#new-frame-go").addEventListener("click",Nt);async function Nt(){const e=d("#new-frame-input").value.trim();if(!e)return;const[t,n]=Ot.split("x").map(Number),a=/^(https?:\/\/|\/|~\/|\.\.?\/)/.test(e)&&!/\s/.test(e);try{const i=await p("POST","/__loop/api/frames",a?{src:e,w:t,h:n}:{prompt:e,w:t,h:n});He(),setTimeout(()=>{B(null),xe(!0,[i.id])},80)}catch(i){v(i.message,4e3)}}d("#name-go").addEventListener("click",Rt),d("#name-input").addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Enter"&&Rt()});function Rt(){const e=d("#name-input").value.trim();e&&(C.name=e,ye.set("loop.me",C),d("#name-modal").hidden=!0,Pe())}let I=null,Ne=null;async function jt(e){if(Ne)return Ne;const{createClient:t}=await import("https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2.49.4/+esm");return Ne=t(e.url,e.key,{auth:{flowType:"pkce",detectSessionInUrl:!0,persistSession:!0,storageKey:"loop-host-auth"}}),Ne}async function Re(){if(!(A||!b())&&c.emailSharing){try{I=await p("GET","/__loop/api/cloud")}catch(e){d("#invite-note").textContent=e.message;return}On()}}function Ft(e,t){return t?`<img src="${w(t)}" alt="" referrerpolicy="no-referrer">`:w(Qe(e))}function On(){const e=!!I?.user;d("#invite-signin").hidden=e,d("#invite-form").hidden=!e,e&&(d("#me-avatar").innerHTML=Ft(I.user.name,I.user.avatar),d("#me-email").textContent=I.user.email,d("#cloud-link").value=I.link||"",I.error&&!d("#invite-note").textContent&&(d("#invite-note").textContent=I.error),d("#members").innerHTML=(I.members||[]).map(t=>`
27
- <div class="member"><span class="m-av">${Ft(t.name||t.email,t.avatar_url)}</span>
7
+ <div class="frame-body"><iframe title="${w(e.name)}"></iframe><div class="parked-hint"><span></span><img alt="" draggable="false" hidden></div><div class="empty-hint"><b>Describe this screen</b></div><div class="shield"></div><div class="areas"></div><div class="progress"></div></div><div class="edge-zone"></div><div class="pins"></div><button class="dims" tabindex="-1"></button>
8
+ ${["n","s","e","w","ne","nw","se","sw"].map(s=>`<div class="resize rz-${s}" data-dir="${s}"></div>`).join("")}`,_o.appendChild(t);const n={id:e.id,el:t,iframe:t.querySelector("iframe"),label:t.querySelector(".frame-label"),name:t.querySelector(".name"),dims:t.querySelector(".dims"),kind:t.querySelector(".kind"),count:t.querySelector(".count"),step:t.querySelector(".step"),elapsed:t.querySelector(".elapsed"),updated:t.querySelector(".updated"),ic:t.querySelector(".ic"),pins:t.querySelector(".pins"),restore:null,parked:!0,hint:t.querySelector(".parked-hint")};return t.classList.add("parked"),Wa(n,e,n.iframe),t.querySelector(".stop").addEventListener("pointerdown",s=>s.stopPropagation()),t.querySelector(".stop").addEventListener("click",()=>{const s=d.live[e.id];s&&x("POST",`/__loop/api/comments/${s.commentId}/cancel`).catch(a=>k(a.message))}),n.label.addEventListener("dblclick",s=>{!s.target.closest(".count")&&$()&&!n.renaming&&Ya(e.id)}),n.dims.addEventListener("pointerdown",s=>s.stopPropagation()),n.dims.innerHTML='<button class="fill-dot" data-pick="frame-fill" title="Fill"><i></i></button><span class="dz"></span>',n.dims.addEventListener("click",s=>{if(s.stopPropagation(),!$())return;const a=s.target.closest(".fill-dot");if(a){const i=d.frames.find(o=>o.id===e.id);return a.dataset.val=i?.fill&&i.fill!=="none"?i.fill:"#ffffff",us(a)}_e=_e===e.id?null:e.id,Se()}),n.count.addEventListener("pointerdown",s=>s.stopPropagation()),n.count.addEventListener("click",s=>{s.stopPropagation(),Co(e.id)}),O.set(e.id,n),n}function Wa(e,t,n){n.addEventListener("load",()=>{if(e.el.classList.contains("waking")&&n.src!=="about:blank"&&Fa(e),n._incoming){const s=e.iframe,a=document.activeElement===s;n._incoming=!1,e.iframe=n;try{e.restore&&n.contentWindow.scrollTo(e.restore.sx,e.restore.sy)}catch{}requestAnimationFrame(()=>requestAnimationFrame(()=>{if(n.classList.remove("incoming"),s.remove(),a)try{n.focus()}catch{}if(e.swapping=!1,clearTimeout(e.swapT),e.swapNext){const i=e.swapNext;e.swapNext=null,ja(e,t,i)}}))}if(n===e.iframe){try{const s=n.contentWindow;if(e.parked)return;const a=()=>{e.cur=Hn(e);const c=d?.frames.find(u=>u.id===t.id);c?.kind==="route"&&(e.kind.textContent=(e.cur||c.src).split("?")[0])};a();for(const c of["pushState","replaceState"]){const u=s.history[c];s.history[c]=function(...f){const m=u.apply(this,f);return setTimeout(a),m}}s.addEventListener("popstate",a),s.addEventListener("hashchange",a),e.restore&&(s.scrollTo(e.restore.sx,e.restore.sy),e.restore=null),e.el.classList.toggle("empty",!!s.document.querySelector('meta[name="loop-empty"]'));let i=0;s.addEventListener("scroll",()=>{i||(i=requestAnimationFrame(()=>{i=0,Ke(t.id)}))},{passive:!0,capture:!0}),s.addEventListener("resize",()=>Ke(t.id));const o=c=>{const u=n.getBoundingClientRect(),f=u.width/(n.offsetWidth||1);return[u.left+c.clientX*f,u.top+c.clientY*f]};rl(s,t.id,o),hl(t.id),Ko(s,e,t.id);let r=null,l=0;s.addEventListener("wheel",c=>{if(S){(c.ctrlKey||c.metaKey)&&c.preventDefault();return}if(c.ctrlKey||c.metaKey)return Oa(c,...o(c));const u=performance.now();if(!r||u-l>140){const m=Math.abs(c.deltaX)>Math.abs(c.deltaY);r=Ti(c.target,m?"x":"y",m?c.deltaX:c.deltaY)?"page":"canvas"}if(l=u,r==="page")return;c.preventDefault();const f=c.deltaMode===1?16:1;h.x-=c.deltaX*f,h.y-=c.deltaY*f,Ns()},{passive:!1}),Xo(s,t.id),s.addEventListener("pointerdown",()=>{Ee&&!S&&re!==t.id&&ra(t.id)},!0),e.autoKb=null,Ll(s,e,t.id),s.addEventListener("gesturestart",c=>{c.preventDefault(),Gn=h.z}),s.addEventListener("gesturechange",c=>{if(c.preventDefault(),S)return;const[u,f]=o(c);Qe(u,f,Gn*c.scale/h.z)}),s.addEventListener("keydown",c=>{if(c.key==="Escape"){re=null,Xe(),J(null);for(const g of d.frames)X(g);return}const u=c.target;!(u&&(u.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(u.tagName)))&&!c.metaKey&&!c.ctrlKey&&/^[vhpecdfnk?]$/i.test(c.key)&&setTimeout(()=>{c.defaultPrevented||(Xe(),window.dispatchEvent(new KeyboardEvent("keydown",{key:c.key,code:c.code,shiftKey:c.shiftKey,altKey:c.altKey})))},0);const m=c.target,y=m&&(m.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(m.tagName));(c.metaKey||c.ctrlKey)&&!y&&(c.key.toLowerCase()==="z"||c.ctrlKey&&c.key.toLowerCase()==="y")&&(c.preventDefault(),c.shiftKey||c.key.toLowerCase()==="y"?bn():as())})}catch{}setTimeout(()=>Ke(t.id),60)}})}function Xo(e,t){const n=e.document;let s=null,a=0;const i=()=>{const u=d?.frames.find(f=>f.id===t);return bo(u)};try{const u=n.createElement("style");u.dataset.loop="touch";const f=`url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28'%3E%3Ccircle cx='14' cy='14' r='11' fill='rgba(120,120,128,.38)' stroke='rgba(255,255,255,.75)' stroke-width='1.5'/%3E%3C/svg%3E") 14 14, default`;u.textContent=`html.loop-touch, html.loop-touch * { -webkit-user-select: none !important; user-select: none !important; -webkit-touch-callout: none; cursor: ${f} !important; }
9
+ html.loop-touch input, html.loop-touch textarea, html.loop-touch [contenteditable] { -webkit-user-select: text !important; user-select: text !important; }
10
+ html.loop-touch img, html.loop-touch a { -webkit-user-drag: none; }`,(n.head||n.documentElement).appendChild(u),n.documentElement.classList.toggle("loop-touch",i())}catch{}const o=(u,f)=>{const m=n.scrollingElement||n.documentElement;for(let y=u?.nodeType===1?u:u?.parentElement;y&&y!==m&&y!==n.body;y=y.parentElement){const g=e.getComputedStyle(y),v=f==="x"?g.overflowX:g.overflowY;if(/(auto|scroll|overlay)/.test(v)&&(f==="x"?y.scrollWidth-y.clientWidth:y.scrollHeight-y.clientHeight)>1)return y}return m},r=(u,f,m)=>{u&&(f||m)&&u.scrollTo({left:u.scrollLeft+f,top:u.scrollTop+m,behavior:"instant"})},l=u=>{try{return e.getComputedStyle(u).scrollSnapType!=="none"}catch{return!1}};e.addEventListener("pointerdown",u=>{cancelAnimationFrame(a),!(!i()||u.pointerType!=="mouse"||u.button!==0)&&(u.target.closest?.('input, textarea, select, [contenteditable=""], [contenteditable="true"], [draggable="true"]')||(s={x:u.clientX,y:u.clientY,lx:u.clientX,ly:u.clientY,lt:performance.now(),vx:0,vy:0,moved:!1,target:u.target,sx:null,sy:null}))},!0),e.addEventListener("pointermove",u=>{if(!s)return;if(!(u.buttons&1))return c();if(!s.moved){if(Math.hypot(u.clientX-s.x,u.clientY-s.y)<6)return;s.moved=!0,s.sx=o(s.target,"x"),s.sy=o(s.target,"y"),e.getSelection?.()?.removeAllRanges()}const f=u.clientX-s.lx,m=u.clientY-s.ly,y=performance.now(),g=Math.max(1,y-s.lt);s.sx===s.sy?r(s.sx,-f,-m):(r(s.sx,-f,0),r(s.sy,0,-m)),s.vx=.7*(f/g*16)+.3*s.vx,s.vy=.7*(m/g*16)+.3*s.vy,s.lx=u.clientX,s.ly=u.clientY,s.lt=y,u.preventDefault()},!0);const c=()=>{const u=s;if(s=null,!u?.moved)return;const f=v=>{v.stopPropagation(),v.preventDefault()};if(e.addEventListener("click",f,{capture:!0,once:!0}),setTimeout(()=>e.removeEventListener("click",f,!0),80),performance.now()-u.lt>90)return;let m=l(u.sx)?0:u.vx,y=l(u.sy)?0:u.vy;const g=()=>{m*=.95,y*=.95,!(Math.abs(m)<.4&&Math.abs(y)<.4)&&(u.sx===u.sy?r(u.sx,-m,-y):(r(u.sx,-m,0),r(u.sy,0,-y)),a=requestAnimationFrame(g))};a=requestAnimationFrame(g)};e.addEventListener("pointerup",c,!0),e.addEventListener("pointercancel",c,!0),e.addEventListener("blur",c),n.addEventListener("selectstart",u=>{s&&i()&&u.preventDefault()},!0),n.addEventListener("dragstart",u=>{i()&&!u.target.closest?.('[draggable="true"]')&&u.preventDefault()},!0)}function ja(e,t,n){if(e.swapping){e.swapNext=n;return}e.swapping=!0;const s=document.createElement("iframe");s.title=e.iframe.title,s.dataset.src=e.iframe.dataset.src,s.className="incoming",s._incoming=!0,Wa(e,t,s),e.iframe.after(s),s.src=n,e.swapT=setTimeout(()=>{s._incoming&&s.dispatchEvent(new Event("load"))},5e3)}function Uo(e){try{const t=e.iframe.contentWindow;return!!(t.document.querySelector('script[src*="/@vite/client"], nextjs-portal, script[src*="webpack-dev-server"], script[src*="hot-update"]')||t.__vite_plugin_react_preamble_installed__||t.$RefreshReg$||t.__webpack_hmr||t.parcelHotUpdate||Object.keys(t).some(s=>s.startsWith("webpackHotUpdate")))}catch{return!1}}function X(e){if(!e)return;const t=ze(e),n=O.get(t.id)||Yo(t),s=n.el.style,a=t.fill==="none"?"transparent":t.fill||"";(s.getPropertyValue("--fill")||"")!==a&&(a?s.setProperty("--fill",a):s.removeProperty("--fill")),n.el.classList.toggle("nofill",t.fill==="none"),s.left=`${t.x}px`,s.top=`${t.y}px`,s.width=`${t.w}px`,s.height=`${t.h}px`,s.setProperty("--fw",`${t.w}px`);{const c=Us(t),u=`Describe this ${c.what}`;s.setProperty("--pfs",`${c.fs}px`),s.setProperty("--plx",`${c.lx*100}%`),s.setProperty("--pty",`${c.ty*100}%`),n.el.dataset.on!==c.on&&(n.el.dataset.on=c.on),n.hintB||=n.el.querySelector(".empty-hint b"),n.hintB&&n.hintB.textContent!==u&&(n.hintB.textContent=u)}n.inkAt!==`${t.x},${t.y}`&&(n.inkAt=`${t.x},${t.y}`,Qa(t.id));const i=K?.frameSrc?.(t)||(t.kind==="folder"||t.kind==="frozen"?`/__loop/f/${t.id}/${encodeURIComponent(t.entry||"index.html")}`:t.src);n.iframe.dataset.src!==i&&(n.iframe.dataset.src=i,n.resume=null,n.parked||(n.iframe.src=i)),be(n.hint.firstChild,t.name),n.el.classList.toggle("narrow",t.w*h.z<200),n.renaming||(n.name.textContent=t.name),n.kind.hidden=t.kind==="folder"||t.kind==="static"||t.kind==="frozen";const o=t.kind==="frozen";n.ic.dataset.k!==(o?"frozen":"live")&&(n.ic.dataset.k=o?"frozen":"live",n.ic.innerHTML=o?ys:""),n.ic.dataset.tip=o?`Frozen ${new Date(t.frozenAt||t.createdAt).toLocaleString([],{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"})}${t.from?` \xB7 from ${t.from.split("?")[0]}`:""}`:"Live",n.el.classList.toggle("is-frozen",o),go(n,t),n.kind.textContent=t.kind==="route"?(n.cur||t.src).split("?")[0]:"live url";const r=d.live[t.id],l=t.kind==="folder"&&!K?Ts(t.id).length:0;if(be(n.count.lastChild,l&&!r?String(l+1):""),n.count.hidden=!l||!!r,n.el.classList.toggle("working",!!r),n.el.classList.toggle("building",!!t.building),n.el.classList.toggle("filling",t.building==="filling"),n.el.classList.toggle("in-section",(d.sections||[]).some(c=>Es(Ca(c),t))),r){const c=d.comments.find(u=>u.id===r.commentId);be(n.step,r.step||(c?.kind==="create"?"Building the frame\u2026":"Working\u2026")),be(n.elapsed,In(r.startedAt))}n.el.classList.toggle("selected",P===t.id||B.has(t.id)),n.el.classList.toggle("live",ue?.fid===t.id||V==="select"&&Ee&&!kt&&C?.frameId!==t.id),be(n.dims.querySelector(".dz"),`${Math.round(t.w)} \xD7 ${Math.round(t.h)}`),n.dims.dataset.tip="Fill \xB7 size & device presets";{const c=n.dims.querySelector(".fill-dot i");c&&(c.style.background=t.fill&&t.fill!=="none"?t.fill:"",c.parentElement.classList.toggle("is-none",t.fill==="none"))}if(We===t.id){const c=_n===t.id;We=_n=null,queueMicrotask(()=>{S||(J(t.id),pt(t.id),c&&setTimeout(()=>Vn(t.id),340))})}}function In(e){const t=Math.max(0,Math.round((Date.now()-e)/1e3));return t<60?`${t}s`:`${Math.floor(t/60)}m ${String(t%60).padStart(2,"0")}s`}setInterval(()=>{if(!d)return;for(const[n,s]of Object.entries(d.live)){const a=O.get(n);a&&(a.elapsed.textContent=In(s.startedAt))}document.querySelectorAll("[data-elapsed-from]").forEach(n=>be(n,In(+n.dataset.elapsedFrom)));const e=Date.now();let t=!1;for(const[n,s]of It)e-s.t>15e3&&(It.delete(n),t=!0);t&&(Ua(),On())},1e3);function Zo(e){const t=O.get(e);if(!t)return;try{const a=t.iframe.contentWindow;t.restore={sx:a.scrollX,sy:a.scrollY}}catch{t.restore=null}if(t.rev=(t.rev||0)+1,t.parked){t.resume=null,Ba(t);return}const n=t.iframe.dataset.src,s=d.frames.find(a=>a.id===e);if(!(s?.kind==="static"||s?.kind==="frozen"))if(s?.kind==="folder")ja(t,s,`${n}?_m=${Date.now()}`);else if(s?.kind==="route"){if(Uo(t))return;try{t.iframe.contentWindow.location.reload()}catch{t.iframe.src=n}}else try{t.iframe.contentWindow.location.reload()}catch{t.iframe.src=n}}const le=document.createElement("div");le.id="done",le.hidden=!0,document.body.appendChild(le);let Dn=0;const Va=document.title;function Ka(e){try{const t=Ka.ac||=new(window.AudioContext||window.webkitAudioContext),n=t.currentTime;for(const[s,a]of(e?[440,330]:[660,990]).entries()){const i=t.createOscillator(),o=t.createGain();i.type="sine",i.frequency.value=a,i.connect(o),o.connect(t.destination),o.gain.setValueAtTime(0,n+s*.11),o.gain.linearRampToValueAtTime(.06,n+s*.11+.02),o.gain.exponentialRampToValueAtTime(1e-4,n+s*.11+.5),i.start(n+s*.11),i.stop(n+s*.11+.55)}}catch{}}function Go(e){const t=d.frames.find(a=>a.id===e);if(!t)return!1;const n=bt(t);return Math.max(0,Math.min(n.l+n.w,innerWidth)-Math.max(n.l,0))*Math.max(0,Math.min(n.t+n.h,innerHeight)-Math.max(n.t,0))>n.w*n.h*.4&&n.w>120}function Qo(e,t,n){if(!$()||K||!d)return;const s=document.hidden;if(!s&&Go(e))return;const i=d.frames.find(c=>c.id===e),o=d.comments.find(c=>c.id===t),r=n==="error",l=e===oe?"the canvas":i?.name||"a frame";Ka(r),s&&(Dn++,document.title=`(${Dn}) ${Va}`),le.innerHTML=`<span class="dn-ic${r?" err":""}">${E(r?"x":"check","s")}</span><span class="dn-text"><b>${r?"Failed":"Done"}</b> \xB7 ${w(l)}</span><button class="dn-go">Go there</button><button class="dn-x" title="Dismiss">${E("x","s")}</button>`,le.dataset.fid=e,le.dataset.cid=t||"",le.hidden=!1,le.classList.remove("in"),le.offsetWidth,le.classList.add("in"),clearTimeout(le._t),le._t=setTimeout(()=>{le.hidden=!0},9e3)}le.addEventListener("click",e=>{if(e.target.closest(".dn-x")){le.hidden=!0;return}if(!e.target.closest(".dn-go"))return;le.hidden=!0;const t=d.comments.find(n=>n.id===le.dataset.cid);t?na(d.comments.find(n=>n.id===(t.parentId||t.id))||t,!0):le.dataset.fid&&le.dataset.fid!==oe&&(J(le.dataset.fid),je(!0,[le.dataset.fid]))}),document.addEventListener("visibilitychange",()=>{!document.hidden&&Dn&&(Dn=0,document.title=Va)});function Jo(e,t,n){const s=O.get(e);!s||!t||(s.updated.textContent=t,s.el.classList.remove("updated","failed"),s.el.offsetWidth,s.el.classList.add(n?"failed":"updated"),clearTimeout(s.flashT),s.flashT=setTimeout(()=>s.el.classList.remove("updated","failed"),4200))}function Ya(e){const t=O.get(e),n=d.frames.find(i=>i.id===e);t.renaming=!0;const s=document.createElement("input");s.className="rename",s.value=n.name,t.name.replaceChildren(s),s.focus(),s.select(),s.addEventListener("pointerdown",i=>i.stopPropagation());const a=i=>{if(!t.renaming)return;t.renaming=!1;const o=s.value.trim();if(t.name.textContent=i&&o?o:n.name,i&&o&&o!==n.name){const r=n.name;x("PATCH",`/__loop/api/frames/${e}`,{name:o}),Z("Rename frame",()=>ht(e,{name:r}),()=>ht(e,{name:o}))}};s.addEventListener("keydown",i=>{i.stopPropagation(),i.key==="Enter"&&a(!0),i.key==="Escape"&&a(!1)}),s.addEventListener("blur",()=>a(!0))}function er(){const e=p("#agent-pill"),t=Object.keys(d.live).length,n=d.comments.filter(f=>f.status==="queued").length,s=d.comments.filter(f=>f.status==="waiting").length,a=d.agent.lastModel&&(d.agentBin==="codex"?!/^claude/.test(d.agent.lastModel):/^claude/.test(d.agent.lastModel));let o=d.agent.mode==="inbox"?d.chatListening?`Your chat \xB7 ${d.agentLabel||"agent"}`:"Your chat is away \xB7 comments wait":(d.agentLabel||"Claude Code")+(a?` \xB7 ${mn(d.agent.lastModel)}`:"");d.hostOnline===!1&&(o=`${d.hostName||"Host"} is offline \xB7 comments wait`),t?o+=` \xB7 ${t} working`:n&&(o+=` \xB7 ${n} queued`),s&&$()&&(o+=` \xB7 ${s} to review`),p("#agent-label").textContent=o,e.classList.toggle("busy",t>0),e.classList.toggle("say",t>0||n>0||s>0&&$()||d.hostOnline===!1||d.agent.mode==="inbox"&&!d.chatListening),e.dataset.tip=e.classList.contains("say")?"Where comments go":o,e.classList.toggle("inbox",d.agent.mode==="inbox"&&!t&&!d.chatListening),document.querySelectorAll("#agent-menu .menu-item").forEach(f=>{f.classList.toggle("on",f.dataset.mode===d.agent.mode&&(!f.dataset.runner||f.dataset.runner===d.agentBin)),f.dataset.runner&&(f.hidden=d.runners&&!d.runners[f.dataset.runner])}),ia(),tr();const r=p("#agent-allowed"),l=d.agent.allow||[],c=f=>f.startsWith("dir:")?`Files in ${f.slice(4)}`:/^Bash\((.*):\*\)$/.exec(f)?.[1]??f.replace(/^mcp__/,"").replace(/__/g," \xB7 "),u=l.length?`<div class="menu-title">Allowed on this canvas</div>${l.map(f=>`<div class="al-row"><code title="${w(f)}">${w(c(f))}</code><button data-disallow="${w(f)}" title="Stop allowing this">${Wt.x}</button></div>`).join("")}`:"";r._h!==u&&(r._h=u,r.innerHTML=u,r.hidden=!l.length),p("#share-menu").hidden||Qn()}function tr(){const e=p("#update-pill"),t=d.update;if(e.hidden=!t||!$()||!!K,e.hidden)return;const n=t.state==="updating"?'<span class="up-spin"></span>Updating\u2026':t.state==="failed"?"Update failed \xB7 Retry":t.how==="next-start"?`Loop ${w(t.latest)} is ready next start`:`${E("up")}Update to ${w(t.latest)}`;e._h!==n&&(e._h=n,e.innerHTML=n),e.disabled=t.state==="updating"||t.how==="next-start",e.classList.toggle("failed",t.state==="failed"),e.title=t.state==="failed"?`Couldn\u2019t update: ${t.error||"unknown error"}`:t.how==="next-start"?"Loop runs through npx here, so the new version is used the next time it starts":`Loop ${t.latest} is out (you have ${d.version}). Installs it and restarts Loop; your canvas stays exactly as it is.`}p("#update-pill").addEventListener("click",async()=>{try{await x("POST","/__loop/api/update")}catch(e){k(e.message)}});function Xa(e){return(e||"?").trim().split(/\s+/).map(t=>t[0]).join("").slice(0,2).toUpperCase()}function On(){const e=[{name:j.name||"You",color:j.color},...It.values()];p("#presence").innerHTML=e.length>1?e.slice(0,6).map((t,n)=>`<span class="avatar${n?"":" me"}" title="${w(n?t.name:`${t.name} (you) \xB7 click to change your name`)}">${_a(t.name,t.color,"",t.avatar)}</span>`).join(""):""}function Ua(){const e=new Set;for(const t of It.values()){e.add(t.id);let n=Ps.querySelector(`[data-id="${CSS.escape(t.id)}"]`);n||(n=document.createElement("div"),n.className="cursor",n.dataset.id=t.id,n.innerHTML=`<div class="cursor-inner"><svg viewBox="0 0 18 18"><path d="M2 1.5l13 6.2-5.6 1.5-2.4 5.6z" fill="${w(t.color)}" stroke="#fff" stroke-width="1.4" stroke-linejoin="round"/></svg><span style="background:${w(t.color)}">${w(t.name)}</span></div>`,Ps.appendChild(n)),n.style.transform=`translate(${t.x}px, ${t.y}px)`}Ps.querySelectorAll(".cursor").forEach(t=>{e.has(t.dataset.id)||t.remove()})}let Za=0;function nr(e,t){const n=Date.now();if(n-Za<70||!d)return;Za=n;const s=we(e,t);x("POST","/__loop/api/presence",{id:j.id,name:j.name||"Guest",color:j.color,avatar:j.avatar,x:s.x,y:s.y}).catch(()=>{})}addEventListener("beforeunload",()=>!K&&navigator.sendBeacon?.("/__loop/api/presence",new Blob([JSON.stringify({id:j.id,leave:!0})],{type:"application/json"})));function Ws(e){if(e.length<4)return`M${e[0]} ${e[1]}l.01 0`;let t=`M${e[0]} ${e[1]}`;for(let n=2;n<e.length-2;n+=2)t+=`Q${e[n]} ${e[n+1]} ${(e[n]+e[n+2])/2} ${(e[n+1]+e[n+3])/2}`;return t+`L${e[e.length-2]} ${e[e.length-1]}`}const $t=new Set;let Ot=null;function js(e){const t=new Set(d.comments.find(n=>n.id===e)?.inkStrokes||[]);for(const n of Object.values(d.live||{})){const s=d.comments.find(a=>a.id===n.commentId);if(s&&(s.parentId||s.id)===e)for(const a of s.inkStrokes||[])t.add(a)}return[...t].filter(n=>d.strokes.some(s=>s.id===n))}function sr(){const e=new Set(R?.inkStrokes||[]);for(const t of Object.values(d.live||{}))for(const n of d.comments.find(s=>s.id===t.commentId)?.inkStrokes||[])e.add(n);for(const t of Object.values(d.live||{})){const n=d.comments.find(a=>a.id===t.commentId),s=n&&d.comments.find(a=>a.id===n.parentId);for(const a of s?.inkStrokes||[])e.add(a)}return e}function Ga(e){if(e.fx==null||!e.frameId)return{dx:0,dy:0};const t=d.frames.find(s=>s.id===e.frameId);if(!t)return{dx:0,dy:0};const n=ze(t);return{dx:n.x-e.fx,dy:n.y-e.fy}}const Rt=e=>{const{dx:t,dy:n}=Ga(e);return t||n?e.points.map((s,a)=>s+(a%2?n:t)):e.points};function Qa(e){for(const t of d.strokes){if(e&&t.frameId!==e)continue;const{dx:n,dy:s}=Ga(t),a=n||s?`translate(${n} ${s})`:"";Ze.querySelectorAll(`path[data-id="${t.id}"], path[data-for="${t.id}"]`).forEach(i=>{(i.getAttribute("transform")||"")!==a&&(a?i.setAttribute("transform",a):i.removeAttribute("transform"))})}}function lt(){Ze.querySelector("defs")||Ze.insertAdjacentHTML("afterbegin",`<defs>
11
+ <filter id="aura-blur" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="10"/></filter>
12
+ <linearGradient id="aura-grad" x1="0" y1="0" x2="1" y2="0" spreadMethod="reflect">
13
+ <stop offset="0" stop-color="#7c98ff"/><stop offset=".45" stop-color="#c58bff"/><stop offset=".55" stop-color="#ffffff"/><stop offset="1" stop-color="#7cd4ff"/>
14
+ <animateTransform attributeName="gradientTransform" type="translate" from="-1 0" to="1 0" dur="2.4s" repeatCount="indefinite"/>
15
+ </linearGradient></defs><g class="auras"></g>`);const e=new Set([...sr()].filter(a=>!(R?.inkStrokes||[]).includes(a))),t=new Set,n=Ze.querySelector("g.auras");n.querySelectorAll("path").forEach(a=>{t.has(a.dataset.for)||a.remove()});for(const a of d.strokes){if(!t.has(a.id)||n.querySelector(`path[data-for="${a.id}"]`))continue;const i=document.createElementNS("http://www.w3.org/2000/svg","path");i.dataset.for=a.id,i.setAttribute("d",Ws(a.points)),i.setAttribute("class","aura-stroke"),i.setAttribute("stroke","url(#aura-grad)"),i.setAttribute("filter","url(#aura-blur)"),n.appendChild(i)}const s=new Set(d.strokes.map(a=>a.id));Ze.querySelectorAll("path[data-id]").forEach(a=>{s.has(a.dataset.id)||a.remove()});for(const a of d.strokes){let i=Ze.querySelector(`path[data-id="${a.id}"]`);i||(i=document.createElementNS("http://www.w3.org/2000/svg","path"),i.dataset.id=a.id,i.setAttribute("d",Ws(a.points)),Ze.appendChild(i)),i.setAttribute("stroke",a.color),i.setAttribute("stroke-width",a.width),i.classList.toggle("used",!!a.commentId),i.classList.toggle("working",e.has(a.id)),i.style.display=a.commentId&&!e.has(a.id)&&!$t.has(a.commentId)&&Ot!==a.commentId?"none":""}Qa()}function Vs(e,t){for(let n=d.frames.length-1;n>=0;n--){const s=d.frames[n];if(e>=s.x&&e<=s.x+s.w&&t>=s.y&&t<=s.y+s.h)return s}return null}function ce(e){try{return O.get(e)?.iframe.contentDocument||null}catch{return null}}function Je(e,t,n){const s=O.get(e).iframe.getBoundingClientRect();return{lx:(t-s.left)/h.z,ly:(n-s.top)/h.z}}function He(e,t,n){const s=ce(e);if(!s)return null;try{return s.elementFromPoint(t,n)}catch{return null}}function Nt(e){if(!e||!e.ownerDocument)return"";const t=e.ownerDocument,n=[];for(let s=e;s&&s.nodeType===1&&s!==t.documentElement;s=s.parentElement){if(s.id&&/^[A-Za-z][\w-]*$/.test(s.id)){n.unshift(`#${s.id}`);break}let a=s.tagName.toLowerCase();const i=s.parentElement?[...s.parentElement.children].filter(o=>o.tagName===s.tagName):[];if(i.length>1&&(a+=`:nth-of-type(${i.indexOf(s)+1})`),n.unshift(a),s.tagName==="BODY"||n.length>7)break}return n.join(" > ")}function Ja(e){const t=typeof e.className=="string"&&e.className.trim()?"."+e.className.trim().split(/\s+/)[0]:"";return e.tagName.toLowerCase()+t}function Ks(e,t,n){const s=He(e,t,n),a=ce(e);let i=0,o=0;try{i=a.defaultView.scrollX,o=a.defaultView.scrollY}catch{}const r={x:t,y:n,sx:i,sy:o};if(s&&s!==a.documentElement){const l=s.getBoundingClientRect();Object.assign(r,{selector:Nt(s),tag:s.tagName.toLowerCase(),label:Ja(s),text:(s.innerText||s.getAttribute?.("aria-label")||s.getAttribute?.("alt")||"").replace(/\s+/g," ").trim().slice(0,140),html:s.outerHTML.length>1500?s.outerHTML.slice(0,1500)+"\u2026":s.outerHTML,fx:l.width?(t-l.left)/l.width:0,fy:l.height?(n-l.top)/l.height:0})}return r}const oe="__canvas";function Ys(e,t){const n=ce(e);if(!n?.defaultView)return null;const s=n.defaultView,a=n.scrollingElement||n.documentElement;let i=s.scrollX,o=s.scrollY;const r=t.selector||t.container?.selector||t.elements?.[0]?.selector;try{for(let l=r&&n.querySelector(r)?.parentElement;l&&l!==a&&l!==n.documentElement;l=l.parentElement)i+=l.scrollLeft,o+=l.scrollTop}catch{}return{x:i,y:o}}function Rn(e,t){const n=e!==oe&&t&&Ys(e,t);return n&&(t.sx=n.x,t.sy=n.y),t}function ln(e,t){if(e===oe)return{x:t.wx,y:t.wy};if(t.scope==="frame"||t.scope==="point"||t.scope==="area"||t.scope==="elements"){if(t.scope==="frame")return{x:t.x,y:t.y};const a=Ys(e,t)||{x:t.sx||0,y:t.sy||0};return{x:t.x-(a.x-(t.sx||0)),y:t.y-(a.y-(t.sy||0))}}const n=ce(e);if(n&&t.selector)try{const a=n.querySelector(t.selector);if(a){const i=a.getBoundingClientRect();if(i.width||i.height)return{x:i.left+t.fx*i.width,y:i.top+t.fy*i.height}}}catch{}const s=Ys(e,t)||{x:t.sx||0,y:t.sy||0};return{x:t.x-(s.x-(t.sx||0)),y:t.y-(s.y-(t.sy||0))}}function cn(e,t,n,s="deep"){const{lx:a,ly:i}=Je(e,t,n),o=ce(e),r=is(e,He(e,a,i),s==="drill"?"level":s);if(!r||r===o?.documentElement){Q.hidden=!0;return}const l=O.get(e).iframe.getBoundingClientRect(),c=r.getBoundingClientRect(),u=h.z,f=Math.max(l.left,l.left+c.left*u),m=Math.max(l.top,l.top+c.top*u),y=Math.min(l.right,l.left+c.right*u),g=Math.min(l.bottom,l.top+c.bottom*u);Object.assign(Q.style,{left:`${f}px`,top:`${m}px`,width:`${Math.max(0,y-f)}px`,height:`${Math.max(0,g-m)}px`}),Q.dataset.tag=xn(r),Q.classList.toggle("sel",!!C?.els.includes(r));const v=[...r.children].filter(_=>!/^(SCRIPT|STYLE|BR)$/.test(_.tagName)).slice(0,30).map(_=>_.getBoundingClientRect()).filter(_=>_.width>3&&_.height>3),A=`${c.left},${c.top},${c.width},${c.height},${u},${v.length}`;Q._k!==A&&(Q._k=A,Q.innerHTML=v.map(_=>`<i style="left:${(_.left-c.left)*u-1.5}px;top:${(_.top-c.top)*u-1.5}px;width:${_.width*u}px;height:${_.height*u}px"></i>`).join("")),Q.hidden=!1}function Ct(e){return d.comments.filter(t=>t.id===e||t.parentId===e).sort((t,n)=>t.createdAt-n.createdAt)}function Nn(e){const t=Ct(e).filter(n=>n.kind!=="note");return t.some(n=>n.status==="working")?"working":t[t.length-1]?.status||"done"}function ei(e){return d.comments.filter(t=>t.frameId===e&&!t.parentId&&t.kind!=="create").sort((t,n)=>t.createdAt-n.createdAt)}const se=document.createElement("div");se.id="peek",se.className="pop",se.hidden=!0,document.body.appendChild(se);let ae=null,Fn=null,Ft=null,Ve=null,dn=null;const Bt=(e,t)=>!!e&&Te.x>=e.left-t&&Te.x<=e.right+t&&Te.y>=e.top-t&&Te.y<=e.bottom+t,ct=e=>document.querySelector(`.pin[data-key="${e}"] .pin-dot`)?.getBoundingClientRect()||null;function ti(e,t){if(!t||matchMedia("(prefers-reduced-motion: reduce)").matches)return;const n=e.getBoundingClientRect();if(!n.width||!n.height)return;const s=(l,c)=>Math.max(0,Math.min(c,l)),a=s(t.left-n.left,n.width-24),i=s(t.top-n.top,n.height-24),o=s(n.right-t.right,n.width-a-24),r=s(n.bottom-t.bottom,n.height-i-24);e._growing?.cancel(),e._growing=e.animate([{clipPath:`inset(${i}px ${o}px ${r}px ${a}px round 14px)`,opacity:.7},{clipPath:"inset(0px 0px 0px 0px round 18px)",opacity:1}],{duration:190,easing:"cubic-bezier(.2, .8, .2, 1)"})}function ar(e){clearTimeout(Fn),!(ae===e||dn===e)&&(ae&&Bt(se.getBoundingClientRect(),0)||(Fn=setTimeout(()=>{W===e||ie||!d?.comments.some(t=>t.id===e)||!Bt(ct(e),6)||(ae&&xe(),Ft=ct(e),ae=e,se.hidden=!1,se._html=null,si(),ti(se,Ft))},ae?30:80)))}function ir(){dn&&!Bt(ct(dn),4)&&(dn=null),ae&&(Bt(se.getBoundingClientRect(),10)||Bt(Ft,8)?(clearTimeout(Ve),Ve=null):Ve||(Ve=setTimeout(()=>{Ve=null,xe()},150)))}function xe(){if(clearTimeout(Fn),clearTimeout(Ve),Ve=null,!ae)return;Bt(Ft,4)&&(dn=ae);const e=d?.comments.find(t=>t.id===ae);e&&dt(e.frameId)?.querySelector(`.area[data-key="${ae}"]`)?.classList.remove("hover"),ae=null,se.hidden=!0,jn()}function ni(e){const t=ei(e.frameId).findIndex(n=>n.id===e.id)+1;return t?`<span class="pin-n" title="Comment ${t}">${t}</span>`:""}function si(){const e=d.comments.find(o=>o.id===ae);if(!e||W===ae)return xe();const t=Ct(e.id),n=t[t.length-1],s=t.length-(n===e?1:2),a=[[e.id,Js(e,n!==e)]];s>0&&a.push(["__more",`<div class="pk-gap">${s} more ${s===1?"message":"messages"}</div>`]),n!==e&&a.push([n.id,Js(n)]),se.firstChild||(se.innerHTML='<div class="thread-body"></div><div class="pk-bar"></div>'),ai(se.querySelector(".thread-body"),a);const i=`${ni(e)}<span class="pk-who">${w(e.author?.name||"You")} \xB7 ${Lt(e.createdAt)}</span>
16
+ <button class="t-btn" data-pk="open" title="Open and reply">${De.reply}</button>${$()?`<button class="t-btn" data-pk="resolve" title="${e.resolved?"Reopen":"Resolve"}">${e.resolved?De.reopen:De.resolve}</button>`:""}`;se._bar!==i&&(se._bar=i,se.querySelector(".pk-bar").innerHTML=i),ii(se),or()}function or(){if(!ae)return;const e=d.comments.find(s=>s.id===ae);if(!e?.anchor)return;const t=ln(e.frameId,e.anchor),n=Wn(e.frameId,t.x,t.y);di(se,n.x,n.y,!1,ct(ae)),Ft=ct(ae)||Ft,jn()}document.documentElement.addEventListener("pointerleave",()=>{ae&&!Ve&&(Ve=setTimeout(()=>{Ve=null,xe()},150))}),se.addEventListener("pointerdown",e=>e.stopPropagation()),se.addEventListener("wheel",e=>e.stopPropagation()),se.addEventListener("click",async e=>{const t=ae;if(!t)return;if(e.target.closest('[data-pk="resolve"]')){xe();try{await x("POST",`/__loop/api/comments/${t}/resolve`)}catch(s){k(s.message)}return}if(e.target.closest("a"))return;const n=se.dataset.o;xe(),Kn(t,n)});function ai(e,t){const n=e._cache||=new Map,s=new Set(t.map(i=>i[0]));for(const i of[...e.children])s.has(i.dataset.mid)||(n.delete(i.dataset.mid),i.remove());let a=null;for(const[i,o]of t){let r=[...e.children].find(c=>c.dataset.mid===i);r||(r=document.createElement("div"),r.className="m",r.dataset.mid=i),n.get(i)!==o&&(n.set(i,o),r.innerHTML=o);const l=a?a.nextSibling:e.firstChild;l!==r&&e.insertBefore(r,l),a=r}}function ii(e){e.querySelectorAll("[data-step-for]").forEach(t=>{const n=d.comments.find(a=>a.id===t.dataset.stepFor),s=n&&d.live[n.frameId];be(t,s?.commentId===n?.id&&s.step||"Working\u2026"),n&&bi(n.id,e),s?.commentId===n?.id&&oi(n.id,s.partial||"",e)}),e.querySelectorAll("[data-elapsed-from]").forEach(t=>be(t,In(+t.dataset.elapsedFrom)))}function oi(e,t,n=document){n.querySelectorAll(`[data-partial-for="${e}"]`).forEach(s=>{if(s._src===t)return;s._src=t,s.hidden=!t,s.innerHTML=t?Yn(t):"";const a=s.closest(".thread-body");a&&a.scrollHeight-a.scrollTop-a.clientHeight<80&&(a.scrollTop=a.scrollHeight)})}const ri=new Map;function li(e){const t=d.live[e];return t?(t.partial||"").trim().split(`
17
+ `)[0].replace(/[*_`#>]/g,"").trim()||t.step||"Working\u2026":""}function rr(e){const t=d.live[e],n=Bn(e);if(!t||!n)return;const s=d.comments.find(o=>o.id===t.commentId)?.parentId||t.commentId,a=n.querySelector(`.pin[data-key="${s}"] .pl`);if(!a)return;const i=li(e);a.textContent!==i&&(a.textContent=i,(t.partial||"").trim()||(a.classList.remove("tick"),a.offsetWidth,a.classList.add("tick")))}async function lr(e){const t=e.dataset.act,n=e.dataset.cid;if(!t||!n)return;if(t==="see")return Kn(e.dataset.key||n);delete e.dataset.act;const s=e.querySelector(".pl");s._h=null,s.textContent=t==="send"?"Sending\u2026":t==="allow"?"Allowed":"Starting\u2026";try{await x("POST",`/__loop/api/comments/${n}/${t}`,t==="allow"?{i:d.comments.find(a=>a.id===n)?.blocked?.findIndex(a=>!a.allowed)}:void 0)}catch(a){k(a.message);const i=d.comments.find(o=>o.id===n)?.frameId;i&&et(i)}}function fn(){for(const e of d.frames)et(e.id);et(oe)}function Bn(e){return e===oe?p("#canvas-pins"):O.get(e)?.pins}function dt(e){return e===oe?p("#canvas-pins"):O.get(e)?.el.querySelector(".areas")}function et(e){const t=Bn(e);if(!t)return;const n={pins:t},s=ei(e),a=s.map((f,m)=>({key:f.id,n:m+1,c:f})).filter(f=>!f.c.resolved||W===f.key);R?.frameId===e&&!R.prompt&&a.push({key:"__draft",n:s.length+1,draft:!0});const i=new Set(a.map(f=>f.key));n.pins.querySelectorAll(".pin").forEach(f=>{i.has(f.dataset.key)||f.remove()});for(const f of a){let m=n.pins.querySelector(`.pin[data-key="${f.key}"]`);m||(m=document.createElement("div"),m.className="pin",m.dataset.key=f.key,m.innerHTML='<div class="pin-dot"><b class="pn"></b><svg class="pw" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="5.5"/></svg><span class="pl"></span></div>',m.addEventListener("pointerdown",q=>q.stopPropagation()),f.draft||m.addEventListener("click",q=>{if(q.stopPropagation(),m.dataset.act&&q.target.closest(".pin-act"))return lr(m);if(m.classList.contains("making")&&q.target.closest(".pl")){const ve=d.comments.find(Ae=>Ae.id===f.key);if(ve?.optionSection)return Cs.delete(ve.optionSection),xo(ve.optionSection)}Kn(f.key)}),m.addEventListener("pointerenter",()=>{dt(e)?.querySelector(`.area[data-key="${f.key}"]`)?.classList.add("hover"),f.draft||ar(f.key)}),m.addEventListener("pointerleave",()=>{ae!==f.key&&(dt(e)?.querySelector(`.area[data-key="${f.key}"]`)?.classList.remove("hover"),clearTimeout(Fn))}),n.pins.appendChild(m));const y=m.querySelector(".pn"),g=!!f.c&&(f.c.author?.guest||!!f.c.author?.name&&f.c.author.name!==j.name);let v=f.draft?"draft":Nn(f.key);!f.draft&&v==="done"&&W===f.key&&za(f.key);const A=!f.draft&&v==="done"&&Do(f.key);A?y._ck!==1&&(y._ck=1,y.innerHTML=No):(y._ck&&(y._ck=0,y.textContent=""),be(y,String(f.n)));const _=!f.draft&&d.frames.some(q=>q.building&&q.optionOf?.cid===f.key);_&&v!=="working"&&(v="working");const b=ri.get(f.key);ri.set(f.key,v),b==="working"&&v!=="working"&&v!=="queued"&&(m._ended=v==="done"?A?null:"Done":v==="error"?"Failed":"Stopped",clearTimeout(m._endT),m._endT=setTimeout(()=>{m._ended=null,d&&et(e)},2400));const M=m.querySelector(".pl"),L=!f.draft&&Ct(f.key).filter(q=>q.kind!=="note").pop(),N=!f.draft&&$()&&!K&&L&&(v==="queued"&&!L.local&&!L.background&&d.agent.mode==="inbox"&&!d.chatListening?{act:"background",say:"Chat paused",btn:"Run in new chat",tip:"The chat this was sent to isn\u2019t listening. Run it in a new session instead (without that chat\u2019s history). It also starts by itself in a moment."}:v==="waiting"?{act:"send",say:"Waiting for you",btn:"Send",tip:"Send this comment to the agent"}:(v==="done"||v==="error")&&gi(L).length?wr(L):null);if(N){m.dataset.act=N.act,m.dataset.cid=L.id;const q=`<span>${w(N.say)}</span><button class="pin-act" title="${w(N.tip)}">${w(N.btn)}</button>`;M._h!==q&&(M._h=q,M.innerHTML=q)}else m.dataset.act&&(delete m.dataset.act,M._h=null,M.textContent="");if(v==="working"){const q=d.live[e],ve=q&&(d.comments.find(Ae=>Ae.id===q.commentId)?.parentId||q.commentId)===f.key;be(M,_?"Making options \u2192":ve?li(e):"Working\u2026")}else A&&!N?be(M,"Done"):m._ended&&be(M,m._ended);m.className=`pin ${v}${f.c?.resolved?" resolved":""}${W===f.key||f.draft?" active":""}${v==="working"?" talking":N?" talking needs":A?" talking done-new":m._ended?" talking ended":""}${m.classList.contains("carded")?" carded":""}${m.classList.contains("ping")?" ping":""}${m.classList.contains("low")?" low":""}${g?" theirs":""}${_?" making":""}`}const o=d.live[e]?.commentId,r=o&&(d.comments.find(f=>f.id===o)?.parentId||o),l=a.filter(f=>f.draft?R?.area:f.c?.anchor?.scope==="area"||f.c?.anchor?.area||f.key===r&&(f.c?.anchor?.scope==="elements"||f.c?.anchor?.scope==="frame"||js(f.key).length)),c=new Set(l.map(f=>f.key)),u=dt(e);u.querySelectorAll(".area:not(.picking)").forEach(f=>{c.has(f.dataset.key)||f.remove()});for(const f of l){let m=u.querySelector(`.area[data-key="${f.key}"]`);m||(m=document.createElement("div"),m.dataset.key=f.key,u.prepend(m));const y=!f.draft&&f.key!==r&&Nn(f.key)==="queued";m.className=`area${f.draft?" draft show":""}${W===f.key?" show":""}${f.key===r?" show working":""}${y?" show queued":""}${f.c?.anchor?.scope==="frame"?" whole":""}${f.key===r&&js(f.key).length&&f.c?.anchor?.scope!=="area"&&!f.c?.anchor?.area?" inkbox":""}`}Ke(e),l.some(f=>f.key===r)&&Ro(),rn()}function Ke(e){const t=Bn(e);!t||!d||(C?.frameId===e&&st(),dt(e)?.querySelectorAll(".area[data-key]").forEach(n=>{const s=n.dataset.key==="__draft"?R?.anchor:d.comments.find(l=>l.id===n.dataset.key)?.anchor;if(!s)return;if(s.scope==="frame"){const l=d.frames.find(c=>c.id===e);if(!l)return;Object.assign(n.style,{left:"0px",top:"0px",width:`${l.w}px`,height:`${l.h}px`});return}if(n.classList.contains("inkbox")){const l=js(n.dataset.key),c=d.frames.find(M=>M.id===e),u=c&&ze(c),f=d.strokes.filter(M=>l.includes(M.id)).flatMap(M=>Rt(M));if(!u||f.length<2){n.style.width="0";return}const m=f.filter((M,L)=>L%2===0).map(M=>M-u.x),y=f.filter((M,L)=>L%2).map(M=>M-u.y),g=12,v=Math.max(0,Math.min(...m)-g),A=Math.max(0,Math.min(...y)-g),_=Math.min(u.w,Math.max(...m)+g),b=Math.min(u.h,Math.max(...y)+g);Object.assign(n.style,{left:`${v}px`,top:`${A}px`,width:`${Math.max(0,_-v)}px`,height:`${Math.max(0,b-A)}px`});return}if(s.scope==="elements"){const l=ce(e),c=(s.elements||[]).map(g=>{try{return l?.querySelector(g.selector)?.getBoundingClientRect()}catch{return null}}).filter(g=>g&&(g.width||g.height));if(!c.length){n.style.width="0";return}const u=Math.min(...c.map(g=>g.left)),f=Math.min(...c.map(g=>g.top)),m=Math.max(...c.map(g=>g.right)),y=Math.max(...c.map(g=>g.bottom));Object.assign(n.style,{left:`${u}px`,top:`${f}px`,width:`${m-u}px`,height:`${y-f}px`});return}const{x:a,y:i}=ln(e,s),o=s.area?s.area.w:s.w,r=s.area?s.area.h:s.h;Object.assign(n.style,{left:`${a}px`,top:`${i}px`,width:`${o}px`,height:`${r}px`})}),t.querySelectorAll(".pin").forEach(n=>{const s=n.dataset.key==="__draft"?R?.anchor:d.comments.find(r=>r.id===n.dataset.key)?.anchor;if(!s){n.hidden=!0;return}const{x:a,y:i}=ln(e,s);n.style.left=`${a}px`,n.style.top=`${i}px`;const o=d.frames.find(r=>r.id===e);n.hidden=!!o&&(a<-4||i<-4||a>o.w+4||i>o.h+4),n.classList.toggle("low",e!==oe&&i*h.z<34*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1))}),(R?.frameId===e||W&&d.comments.find(n=>n.id===W)?.frameId===e)&&ye())}function Wn(e,t,n){if(e===oe)return{x:h.x+t*h.z,y:h.y+n*h.z};const s=ze(d.frames.find(a=>a.id===e));return{x:h.x+(s.x+t)*h.z,y:h.y+(s.y+n)*h.z}}function ci(e,t,n,s){const a=e.offsetWidth||340,i=e.offsetHeight||140,o=28*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1);let r=s?t+o+10:t+18,l=s?Math.min(s.top,n)-4:n-18;r+a>innerWidth-12&&(r=t-a-10),r=Math.max(12,Math.min(r,innerWidth-a-12)),l=Math.max(60,Math.min(l,innerHeight-i-76)),e.style.left=`${r}px`,e.style.top=`${l}px`}let ft=28;function di(e,t,n,s,a){ft=28*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1),a&&a.height>4&&(t=a.left,n=a.bottom,ft=a.height),s&&(e.style.maxHeight="");const i=e.offsetWidth||340;let o=e.offsetHeight||140;const r=n-56,l=innerHeight-12-(n-ft),c=innerWidth-12-t,u=t+ft-12;let f=s&&e._side;f&&(f[0]==="b"?o>r&&l>r:o>l&&r>l)&&(f=(f[0]==="b"?"t":"b")+f[1]);const m=s?o:Math.max(o,380);if(f||(f=(m<=r||r>=l?"b":"t")+(i<=c||c>=u?"l":"r")),s){e._side=f;const _=f[0]==="b"?r:l;o>_&&(e.style.maxHeight=`${Math.max(180,Math.floor(_))}px`,o=e.offsetHeight)}const y=f[1]==="l"?t:t+ft-i,g=f[0]==="b"?n-o:n-ft,v=Math.max(12,Math.min(y,innerWidth-i-12)),A=Math.max(56,Math.min(g,innerHeight-o-12));e.style.left=`${Math.round(v)}px`,e.style.top=`${Math.round(A)}px`,e.dataset.o=f,e.style.transformOrigin=`${Math.max(0,Math.min(i,t+ft/2-v))}px ${Math.max(0,Math.min(o,n-ft/2-A))}px`,e.classList.toggle("at-pin",f==="bl"&&v===y&&A===g),e._covers=v===y&&A===g}function jn(){const e=new Set;W&&!I.hidden&&!I.classList.contains("docked")&&I._covers&&e.add(W),ae&&!se.hidden&&se._covers&&e.add(ae),document.querySelectorAll(".pin").forEach(t=>t.classList.toggle("carded",e.has(t.dataset.key)))}function ye(){if(d){if(Zt(),Xi(),R?.prompt&&!H.hidden){const e=ze(d.frames.find(t=>t.id===R.frameId));if(e){const t=Us(e),n=h.z,s=e.w*(1-2*t.lx)*n,a=Math.min(44,t.fs*n),i=s>=190&&a>=12.5;if(H.classList.toggle("onpage",i),i){H.dataset.on=t.on,H.style.width=`${s}px`,H.style.setProperty("--pfs",`${a}px`),(H._pfs!==a||H._pw!==s)&&(H._pfs=a,H._pw=s,tt(Y));const o=H.offsetHeight||160;H.style.left=`${h.x+(e.x+e.w*t.lx)*n}px`,H.style.top=`${Math.max(56,Math.min(h.y+(e.y+e.h*t.ty)*n,innerHeight-o-76))}px`}else{H.style.width="",H._pfs=H._pw=null;const o=H.offsetWidth||380,r=H.offsetHeight||200,l=h.y+(e.y+e.h/2)*n;ci(H,h.x+(e.x+e.w)*n,l-r/2+18)}}}else if(R&&!H.hidden){const e=ln(R.frameId,R.anchor),t=Wn(R.frameId,e.x,e.y);ci(H,t.x,t.y,ct("__draft"))}if(W&&!I.hidden&&!I.classList.contains("docked")){const e=d.comments.find(t=>t.id===W);if(e?.anchor){const t=ln(e.frameId,e.anchor),n=Wn(e.frameId,t.x,t.y);di(I,n.x,n.y,!0,ct(W)),I._grow&&(I._grow=!1,ti(I,ct(W)))}}if(jn(),Qt(),qe){const e=Wn(qe.frameId,qe.lx,qe.ly),t=p("#ink-chip");t.style.left=`${e.x+10}px`,t.style.top=`${e.y+10}px`}}}function Xs(e){return d.strokes.filter(t=>t.frameId===e&&!t.commentId&&Pa.has(t.id))}function ut(e,t,n,s,a){Me&&pn(!0),U(),un(),H.classList.remove("prompt"),Zs();const i=e===oe?null:a?Ks(e,a.x+a.w/2,a.y+a.h/2):Ks(e,t,n),o=Xs(e);R={frameId:e,picked:i,lx:t,ly:n,area:a||null,inkStrokes:o.map(c=>c.id)},ur(e===oe?"canvas":a?"area":"point");const r=p("#composer-area");r.classList.remove("chip-frame"),r.hidden=!a,a&&(r.textContent=e===oe?`Area \xB7 ${R.anchor.near.length||"no"} frame${R.anchor.near.length===1?"":"s"}`:`Area \xB7 ${R.anchor.elements.length} element${R.anchor.elements.length===1?"":"s"}`);const l=p("#composer-ink");l.hidden=!o.length,l.innerHTML=`${Ci}<span>${o.length} mark${o.length===1?"":"s"}</span>`,Y.placeholder=$()?"Ask for a change":"Add a comment",hn.length=0,H.hidden=!1,Y.value="",tt(Y),oa.paint(),et(e),ye(),lt(),setTimeout(()=>Y.focus(),0),Qs(e)}function fi(e,t){return d.frames.map(n=>({f:n,d:Math.hypot(Math.max(n.x-e,0,e-n.x-n.w),Math.max(n.y-t,0,t-n.y-n.h))})).sort((n,s)=>n.d-s.d).slice(0,2).filter(n=>n.d<1200).map(n=>n.f.name)}function cr(e){const t=d.frames.filter(n=>n.x<e.x+e.w&&n.x+n.w>e.x&&n.y<e.y+e.h&&n.y+n.h>e.y).map(n=>n.name);return t.length?t:fi(e.x+e.w/2,e.y+e.h/2)}function dr(e,t){const n=ce(e);if(!n?.body)return[];const s=Math.max(12,Math.min(t.w,t.h)*.08),a=t.x-s,i=t.y-s,o=t.x+t.w+s,r=t.y+t.h+s,l=[];for(const f of n.body.querySelectorAll("*")){if(l.length>600)break;const m=f.getBoundingClientRect();!m.width||!m.height||["SCRIPT","STYLE","LINK","META"].includes(f.tagName)||m.left>=a&&m.top>=i&&m.right<=o&&m.bottom<=r&&l.push(f)}const c=new Set(l);let u=l.filter(f=>{for(let m=f.parentElement;m;m=m.parentElement)if(c.has(m))return!1;return!0});if(!u.length){const f=He(e,t.x+t.w/2,t.y+t.h/2);f&&f!==n.documentElement&&(u=[f])}return u.slice(0,14).map(f=>({selector:Nt(f),tag:f.tagName.toLowerCase(),text:(f.innerText||f.getAttribute("aria-label")||f.getAttribute("alt")||"").replace(/\s+/g," ").trim().slice(0,80)}))}function fr(e,t){const n=ce(e);let s=He(e,t.x+t.w/2,t.y+t.h/2);for(;s&&s!==n?.body;){const a=s.getBoundingClientRect();if(a.left<=t.x+2&&a.top<=t.y+2&&a.right>=t.x+t.w-2&&a.bottom>=t.y+t.h-2)break;s=s.parentElement}return s&&s!==n?.documentElement?{selector:Nt(s),tag:s.tagName.toLowerCase(),text:(s.innerText||"").replace(/\s+/g," ").trim().slice(0,80)}:null}function ur(e){const t=R;if(!t)return;const n=d.frames.find(s=>s.id===t.frameId);t.scope=e,e==="canvas"&&t.area?t.anchor={scope:e,wx:t.area.x,wy:t.area.y,area:{w:t.area.w,h:t.area.h},near:cr(t.area)}:e==="canvas"?t.anchor={scope:e,wx:t.lx,wy:t.ly,near:fi(t.lx,t.ly)}:e==="area"?t.anchor={scope:e,x:t.area.x,y:t.area.y,w:t.area.w,h:t.area.h,sx:t.picked?.sx||0,sy:t.picked?.sy||0,elements:dr(t.frameId,t.area),container:fr(t.frameId,t.area)}:t.anchor={...t.picked||{},scope:"point",x:t.lx,y:t.ly,fx:void 0,fy:void 0},Rn(t.frameId,t.anchor),et(t.frameId),ye()}function Us(e){const t=e.w<=480;let n="light";if(e.fill==="none")n="canvas";else if(/^#[0-9a-f]{6}$/i.test(e.fill||"")){const s=parseInt(e.fill.slice(1),16);.299*(s>>16)+.587*(s>>8&255)+.114*(s&255)<140&&(n="dark")}return{fs:Math.max(e.w*.037,Math.min(30,e.w*.077)),lx:t?.09:.11,ty:t?.15:.27,on:n,what:e.w<=1024?"screen":"page"}}function Zs(){H.classList.remove("onpage"),H.style.width="",H._pfs=H._pw=null,document.querySelectorAll(".frame.prompting").forEach(e=>e.classList.remove("prompting"))}const mr={Mobile:["Login","Onboarding","Home feed","Profile","Settings","Checkout"],Tablet:["Dashboard","Reader","Calendar","Settings","Kanban board"],Desktop:["Landing page","Dashboard","Pricing","Sign up","Settings","Blog post"]};function Vn(e){const t=d?.frames.find(s=>s.id===e);if(!t)return;U(),un(),Zs();const n=t.w<=480?"Mobile":t.w<=1024?"Tablet":"Desktop";R={frameId:e,picked:null,lx:24,ly:24,area:null,inkStrokes:[],prompt:!0,scope:"frame",anchor:{scope:"frame",x:24,y:24}},H.classList.add("prompt"),O.get(e)?.el.classList.add("prompting"),p("#prompt-title").textContent=`What should \u201C${t.name}\u201D be?`,p("#prompt-ideas").innerHTML=mr[n].map(s=>`<button>${w(s)}</button>`).join(""),p("#composer-area").hidden=!0,p("#composer-ink").hidden=!0,Y.placeholder=`Describe this ${Us(t).what}`,hn.length=0,H.hidden=!1,Y.value="",tt(Y),oa.paint(),ye(),setTimeout(()=>Y.focus(),0),Qs(e)}p("#prompt-ideas").addEventListener("click",e=>{const t=e.target.closest("button");t&&(Y.value=`${t.textContent} `,tt(Y),oa.paint(),Y.focus(),Y.setSelectionRange(Y.value.length,Y.value.length))});function ne(){H.classList.contains("soft")&&(H.querySelector(".hint").innerHTML="<kbd>\u21B5</kbd> send \xB7 <kbd>\u21E7\u21B5</kbd> new line \xB7 <kbd>esc</kbd>"),H.classList.remove("prompt","soft"),Zs(),pi=null,Si(),R?.deep&&Ne(),document.querySelectorAll(".frame.whole").forEach(t=>t.classList.remove("whole"));const e=R?.frameId;R=null,H.hidden=!0,e&&et(e),d&&lt()}function tt(e){e.style.height="auto",e.style.height=`${Math.min(e===Y&&H.classList.contains("onpage")?innerHeight*.45:180,e.scrollHeight)}px`}Y.addEventListener("input",()=>tt(Y)),Y.addEventListener("keydown",e=>{if(e.stopPropagation(),e.key==="Enter"&&!e.shiftKey&&!e.isComposing){if(e.preventDefault(),R?.deep&&!Y.value.trim()&&!hn.length&&C?.els.length===1&&Xt(C.els[0],!0)&&$()){const{frameId:t,els:n}=C;ne(),Ut(t,n[0]);return}ui()}e.key==="Escape"&&ne()});async function ui(){const e=hn.splice(0),t=Y.value.trim()||(e.length?"See the attached reference.":"");if(!t||!R)return;const n=R;ne(),pe("select");const s=d.strokes.filter(o=>n.inkStrokes.includes(o.id)),a={id:qs(),frameId:n.frameId,text:t,anchor:n.anchor,author:{name:j.name,color:j.color},inkStrokes:n.inkStrokes,attachments:e};s.length&&n.frameId!==oe&&Object.assign(a,pr(n.frameId,s));const i=Gs(a);try{const o=await x("POST","/__loop/api/comments",a);o?.id&&o.id!==a.id&&i(),$()||k("Comment added \u2014 the host will send it to the agent")}catch(o){i(),k(o.message)}}function Gs(e){if(K)return()=>{};const t={id:e.id,frameId:e.frameId,parentId:e.parentId||null,text:e.text,anchor:e.anchor||d.comments.find(n=>n.id===e.parentId)?.anchor||null,author:{...e.author,guest:!$()},inkStrokes:e.inkStrokes||[],status:$()?"queued":"waiting",reply:null,createdAt:Date.now(),local:!0,...e.attachments?.length?{attachments:e.attachments.map(n=>({name:n.name,type:n.type,url:n.data}))}:{}};d.comments.push(t);for(const n of d.strokes)t.inkStrokes.includes(n.id)&&(n.commentId=t.id);return zn(),()=>{d.comments=d.comments.filter(n=>n!==t),zn()}}const mi=new Map;function Qs(e){!d||K||!$()||!e||Date.now()-(mi.get(e)||0)<6e4||(mi.set(e,Date.now()),x("POST",`/__loop/api/frames/${e}/warm`).catch(()=>{}))}function pr(e,t){const n=d.frames.find(c=>c.id===e),s=ce(e),a=new Map;for(const c of t){const u=c.points.length/2,f=Math.max(1,Math.floor(u/14));for(let m=0;m<u;m+=f){const y=c.points[m*2]-(c.fx??n.x),g=c.points[m*2+1]-(c.fy??n.y),v=He(e,y,g);if(!v||v===s?.documentElement||v===s?.body)continue;const A=Nt(v);a.has(A)||a.set(A,{selector:A,tag:v.tagName.toLowerCase(),text:(v.innerText||"").replace(/\s+/g," ").trim().slice(0,60),el:v})}}const i=[...a.values()].slice(0,10),o=Math.min(1,1280/Math.max(n.w,n.h)),r=document.createElement("canvas");r.width=Math.round(n.w*o),r.height=Math.round(n.h*o);const l=r.getContext("2d");l.scale(o,o),l.fillStyle="#fff",l.fillRect(0,0,n.w,n.h),l.strokeStyle="#C8C8CE",l.lineWidth=2,l.strokeRect(1,1,n.w-2,n.h-2),l.font="14px ui-monospace, Menlo, monospace";for(const c of i)try{const u=c.el.getBoundingClientRect();l.strokeStyle="#2F5BFF",l.setLineDash([6,4]),l.lineWidth=1.5,l.strokeRect(u.left,u.top,u.width,u.height),l.setLineDash([]),l.fillStyle="#2F5BFF",l.fillText(c.tag+(c.text?` "${c.text.slice(0,30)}"`:""),u.left+4,Math.max(14,u.top-4))}catch{}l.strokeStyle=Is,l.lineWidth=4,l.lineCap="round",l.lineJoin="round";for(const c of t){l.beginPath();for(let u=0;u<c.points.length;u+=2){const f=c.points[u]-(c.fx??n.x),m=c.points[u+1]-(c.fy??n.y);u?l.lineTo(f,m):l.moveTo(f,m)}l.stroke()}return{ink:i.map(({el:c,...u})=>u),annotationPng:r.toDataURL("image/png")}}function Bl(e,t,n){qe={frameId:e,lx:t,ly:n},p("#ink-chip").hidden=!1,ye()}function un(){qe=null,p("#ink-chip").hidden=!0}let pi=null;function hr(e,t,n){if(!(!H.hidden&&Y.value.trim())){if(e){const s=d.frames.find(c=>c.id===e),a=Xs(e),i=a.flatMap(c=>Rt(c).filter((u,f)=>f%2===0)),o=a.flatMap(c=>Rt(c).filter((u,f)=>f%2===1)),r=(i.length?(Math.min(...i)+Math.max(...i))/2:t[t.length-2])-s.x,l=(o.length?(Math.min(...o)+Math.max(...o))/2:t[t.length-1])-s.y;ut(e,r,l)}else ut(oe,t[t.length-2],t[t.length-1],"canvas");R&&(R.soft=!0,H.classList.add("soft"),Y.placeholder="What should change here?",H.querySelector(".hint").innerHTML="<kbd>\u21B5</kbd> send \xB7 <kbd>esc</kbd> skip",pi={x:n.clientX,y:n.clientY,t:Date.now()})}}addEventListener("pointerdown",e=>{!R?.soft||H.hidden||H.contains(e.target)||Y.value.trim()||V==="pen"&&e.target.closest("#viewport")||ne()},!0),Y.addEventListener("input",()=>{R?.soft&&Y.value.trim()&&(R.soft=!1,H.classList.remove("soft"))}),p("#ink-chip button").addEventListener("click",()=>{if(!qe)return;const e=Xs(qe.frameId),t=d.frames.find(o=>o.id===qe.frameId),n=e.flatMap(o=>Rt(o).filter((r,l)=>l%2===0)),s=e.flatMap(o=>Rt(o).filter((r,l)=>l%2===1)),a=n.length?(Math.min(...n)+Math.max(...n))/2-t.x:qe.lx,i=s.length?(Math.min(...s)+Math.max(...s))/2-t.y:qe.ly;ut(qe.frameId,a,i)});function Kn(e,t){Me&&pn(!0),ne(),un(),e!==W&&(ea.length=0),xe(),e!==W&&(I.dataset.tid="",I._side=t||null,I.classList.remove("in","grow"),I.offsetWidth,I.classList.add(t?"grow":"in"),I._grow=!t),W=e,I.hidden=!1;{const n=d.comments.find(s=>s.id===e);za(e)&&n&&et(n.frameId)}I.classList.toggle("docked",nt),nt&&(I.style.left=I.style.top=I.style.maxHeight=""),Xn(),fn(),ye()}function U(){W&&(Si(),($t.size||Ot)&&($t.clear(),Ot=null,lt()),W=null,I.hidden=!0,I.dataset.tid="",fn(),jn())}const Lt=e=>{const t=(Date.now()-e)/1e3;return t<60?"just now":t<3600?`${Math.floor(t/60)}m ago`:t<86400?`${Math.floor(t/3600)}h ago`:new Date(e).toLocaleDateString()};function mn(e){if(!e)return"";const t=/claude-([a-z]+)-(\d+)(?:-(\d+))?/i.exec(e);if(t)return`${t[1][0].toUpperCase()}${t[1].slice(1)} ${t[2]}${t[3]&&t[3].length<=2?"."+t[3]:""}`;const n=/^gpt-([\d.]+)(?:-([a-z]+))?/i.exec(e);return n?`GPT-${n[1]}${n[2]?" "+n[2][0].toUpperCase()+n[2].slice(1):""}`:e}function Wl(e){const t=[];if(e.model&&t.push(mn(e.model)),e.startedAt&&e.finishedAt){const n=Math.round((e.finishedAt-e.startedAt)/1e3);t.push(n<60?`${n}s`:`${Math.floor(n/60)}m ${n%60}s`)}return t.length?`<div class="a-meta">${w(t.join(" \xB7 "))}</div>`:""}const jl=E("check","s"),gr={claude:'<svg class="lg claude" viewBox="0 0 24 24"><path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>',codex:'<svg class="lg" viewBox="0 0 24 24"><path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>',loop:'<svg class="lg ring" viewBox="0 0 24 24"><circle cx="12" cy="12" r="6.5"/></svg>'};function yr(e){const t=String(e?.model||"").toLowerCase();return/claude|opus|sonnet|haiku|fable|mythos/.test(t)?"claude":/gpt|codex|^o\d/.test(t)||d?.agentBin==="codex"?"codex":d?.agentBin==="claude"?"claude":"loop"}const vr={claude:"Claude",codex:"Codex",loop:"Agent"},hi=e=>{const t=yr(e);return`<span class="m-mark" title="${vr[t]}">${gr[t]}</span>`};function Vl(e){if(!(e.startedAt&&e.finishedAt))return"";const t=Math.round((e.finishedAt-e.startedAt)/1e3);return`<span title="${w(e.model?mn(e.model):"")}">Worked ${t<60?`${t}s`:`${Math.floor(t/60)}m ${t%60}s`}</span>`}const Wt={undo:E("undo"),before:E("before"),redo:E("redo"),copy:E("copy"),check:E("check"),stop:E("stop"),send:E("up"),retry:E("retry"),steer:E("steer"),bg:E("play"),x:E("x")},Ie=(e,t,n,s,a="")=>`<button class="a-btn${s?" lbl":""}${a?" "+a:""}" ${t} title="${w(n)}" aria-label="${w(n)}">${Wt[e]}${s?`<span>${w(s)}</span>`:""}</button>`;function br(e){const t=$(),n=(a,i,o,r)=>`<div class="m-agent ${a}">${hi(e)}<div class="m-body">${i}${o?`<div class="m-acts${r?" show":""}">${o}</div>`:""}</div></div>`,s=`data-id="${e.id}"`;switch(e.status){case"waiting":return n("quiet",'<div class="m-text">Waiting for the host to send this to the agent.</div>',t?Ie("send",`data-act="send" ${s}`,"Send to the agent","Send","primary"):"",!0);case"queued":{if(e.local)return n("quiet",'<div class="m-work"><span class="a-text">Sending\u2026</span></div>',"");const a=e.parentId||e.id,i=t&&Ct(a).some(c=>c.status==="working"),o=d.agent.mode==="inbox"&&!e.background,r=o&&!d.chatListening;return n("quiet",`<div class="m-work"><span class="a-text">${i?"Queued \xB7 runs after the current change":r?"Your chat isn\u2019t listening, so this starts in the background in a moment.":o?"Sent to your chat":"Queued"}</span></div>`,t?`${i?Ie("steer",`data-act="steer" ${s}`,"Steer: stop the current run and include this message in it","Steer","primary"):""}${r?Ie("bg",`data-act="background" ${s}`,"Run it now in the background, without your chat\u2019s context","Run now"):""}${Ie("x",`data-act="cancel" ${s}`,"Cancel")}`:"",!0)}case"working":return n("",`<ol class="m-steps" data-steps-for="${e.id}"></ol><div class="m-work"><span class="a-text" data-step-for="${e.id}"></span><span class="m-time" data-elapsed-from="${d.live[e.frameId]?.startedAt||e.startedAt||e.createdAt}"></span>${t?Ie("stop",`data-act="cancel" ${s}`,"Stop"):""}</div><div class="m-text md m-stream" data-partial-for="${e.id}" hidden></div>`,"");case"done":return n("",`${$r(e)}<div class="m-text md">${e.undone?"Reverted.":Yn(e.reply||"Done.")}</div>${Lr(e)}${yi(e)}`,`${e.snapshot&&!K&&d.frames.find(a=>a.id===e.frameId)?.kind==="folder"?Ie("before",`data-act="before" ${s}`,"See the frame before this change"):""}${t&&e.snapshot&&!e.undone?Ie("undo",`data-act="undo" ${s}`,"Undo this change"):""}${t&&e.undone&&e.redoSnap?Ie("redo",`data-act="redo" ${s}`,"Redo this change"):""}${Ie("copy",`data-copy="${e.id}"`,"Copy the reply")}<time>${Lt(e.finishedAt||e.createdAt)}</time>`);case"error":return n("error",`<div class="m-text">${w(e.reply||"Something went wrong.")}</div>${yi(e)}`,t?Ie("retry",`data-act="send" ${s}`,"Try again","Retry","primary"):"",!0);case"interrupted":return n("quiet",'<div class="m-text">Interrupted \xB7 continued below</div>',"");case"canceled":return n("quiet",'<div class="m-text">Stopped.</div>',t?Ie("retry",`data-act="send" ${s}`,"Send again","Send again","primary"):"",!0);default:return""}}const gi=e=>(e?.blocked||[]).filter(t=>!t.allowed);function wr(e){const t=gi(e);return t.length===1?{act:"allow",say:"Blocked",btn:"Allow",tip:`The agent wasn\u2019t allowed to use ${t[0].label}. Allow it on this canvas and let the agent carry on.`}:{act:"see",say:`${t.length} blocked`,btn:"See",tip:"The agent wasn\u2019t allowed to use some things. See them in the thread."}}function yi(e){if(!e.blocked?.length)return"";const t=$()&&!K;return`<div class="m-blocked">${e.blocked.map((n,s)=>`<div class="blk${n.allowed?" ok":""}">
18
+ <span class="blk-k">${n.allowed?"Allowed":"Blocked"}</span><code title="${w(n.cmd||n.label)}">${w(n.label)}</code>
19
+ ${!n.allowed&&t?`<button class="blk-go" data-act="allow" data-id="${e.id}" data-k="${s}" title="Let the agent use this on this canvas from now on, and carry on">Allow</button>`:""}</div>`).join("")}</div>`}const xr={read:E("read"),edit:E("edit"),find:E("find"),look:E("look"),run:E("run"),think:E("think"),add:E("add")},kr=e=>xr[/^(Reading)/.test(e)?"read":/^(Editing|Writing)/.test(e)?"edit":/^Searching/.test(e)?"find":/^(Looking|Taking)/.test(e)?"look":/^(Adding|Setting|Making)/.test(e)?"add":/^(Running)/.test(e)?"run":"think"],vi=e=>e.say?`<li class="say"><div class="md">${Yn(e.s)}</div></li>`:`<li>${kr(e.s)}<span>${w(e.s)}</span></li>`;function $r(e){const t=(e.steps||[]).filter(a=>a.s!=="Thinking\u2026"),n=e.startedAt&&e.finishedAt?Math.round((e.finishedAt-e.startedAt)/1e3):0;if(!n&&!t.length)return"";const s=n?`Worked for ${n<60?`${n}s`:`${Math.floor(n/60)}m ${n%60}s`}`:"Worked";return t.length?`<details class="m-did"><summary><span>${s}</span>${E("right","s")}</summary><ol class="m-steps">${t.map(vi).join("")}</ol></details>`:`<div class="m-did flat"><span>${s}</span></div>`}function bi(e,t=document){const n=d.comments.find(r=>r.id===e);if(!n)return;const s=(n.steps||[]).filter(r=>r.s!=="Thinking\u2026"),a=d.live[n.frameId]?.commentId===e?d.live[n.frameId].step:null,o=(s.length&&!s[s.length-1].say&&s[s.length-1].s===a?s.slice(0,-1):s).slice(-8).map(vi).join("");t.querySelectorAll(`[data-steps-for="${e}"]`).forEach(r=>{r._h!==o&&(r._h=o,r.innerHTML=o,r.hidden=!o)})}function Js(e,t){return e.kind==="note"?`<div class="m-agent">${hi(e)}<div class="m-body"><div class="m-text md">${Yn(e.text)}</div><div class="m-acts">${Ie("copy",`data-copy="${e.id}"`,"Copy")}<time>${Lt(e.createdAt)}</time></div></div></div>`:`<div class="m-user">
20
+ <div class="bubble${e.attachments?.length?" has-files":""}">${Mr(e)}<div class="b-text">${w(e.text)}</div>${Er(e)}</div>
21
+ <div class="m-meta">${e.author?.guest||e.author?.name&&e.author.name!==j.name?`${w(e.author?.name||"Guest")} \xB7 `:""}${Lt(e.createdAt)}</div>
22
+ </div>${t?"":br(e)}`}function Cr(){for(const[e,t]of O){const n=[...d.comments].reverse().find(f=>f.frameId===e&&f.options?.some(m=>m.files?.length&&!m.frameId)&&!f.optionChosen&&!f.optionsCleared);let s=t.el.querySelector(":scope > .opt-strip");if(!n||!$()){s?.remove();continue}const a=d.frames.find(f=>f.id===e),i=a?a.w/a.h:1.5,o=Math.round(Math.min(150,Math.max(70,84*i))),r=Math.round(o/i),l=n.options.filter(f=>f.files?.length&&!f.frameId),c=n.id+"|"+(n.optionApplied||"")+"|"+l.map(f=>f.id+(f.thumb||"")).join(",");if(s?.dataset.key===c)continue;s||(s=document.createElement("div"),s.className="opt-strip",t.el.appendChild(s),s.addEventListener("pointerdown",f=>f.stopPropagation()),s.addEventListener("click",async f=>{const m=f.target.closest("[data-opt]"),y=f.target.closest("[data-use]"),g=s.dataset.cid;try{y?(await x("POST",`/__loop/api/comments/${g}/choose`,{option:y.dataset.use}),k(`Using option ${y.dataset.use}`)):m&&await x("POST",`/__loop/api/comments/${g}/preview`,{option:m.dataset.opt||null})}catch(v){k(v.message)}})),s.dataset.key=c,s.dataset.cid=n.id;const u=(f,m,y)=>`<button class="os-tile${(n.optionApplied||"")===f?" on":""}" data-opt="${f}" title="${f?`Preview ${w(m)}`:"Back to the original"}">
23
+ <span class="os-img" style="width:${o}px;height:${r}px">${y?`<img src="${w(y)}" alt="">`:`<b>${f||"\xB7"}</b>`}</span>
24
+ <span class="os-name">${f?`<i>${f}</i>`:""}${w(m)}</span></button>`;s.innerHTML=`<span class="os-label">Options</span>${u("","Original",n.origThumb||"")}${l.map(f=>u(f.id,f.name,f.thumb)).join("")}
25
+ ${n.optionApplied?`<button class="os-use" data-use="${n.optionApplied}">Use ${n.optionApplied}</button>`:""}`,l.some(f=>!f.thumb)&&a?.kind==="folder"&&!n._thumbsAsked&&(n._thumbsAsked=!0,x("POST",`/__loop/api/comments/${n.id}/thumbs`).catch(()=>{}))}}function Lr(e){const t=(e.options||[]).filter(s=>s.files?.length);if(!t.length)return"";if(t.some(s=>s.frameId)||e.optionsCleared){const s=t.filter(a=>a.frameId&&d.frames.some(i=>i.id===a.frameId));return s.length?`<div class="m-opts">${s.map(a=>`<button class="opt${e.optionChosen===a.id?" on":""}" data-goto="${a.frameId}" title="Go to this option's frame"><b>${w(a.id)}</b>${w(a.name)}</button>`).join("")}</div>`:e.optionChosen?`<div class="m-opts chosen"><span class="opt on"><b>${w(e.optionChosen)}</b>${w(t.find(a=>a.id===e.optionChosen)?.name||"")}</span><span class="opt-note">Chosen</span></div>`:""}if(e.optionChosen){const s=t.find(a=>a.id===e.optionChosen);return`<div class="m-opts chosen"><span class="opt on"><b>${w(s?.id||"")}</b>${w(s?.name||"")}</span><span class="opt-note">Chosen</span></div>`}const n=$();return`<div class="m-opts">${t.map(s=>`<button class="opt${e.optionApplied===s.id?" on":""}" ${n?`data-opt="${s.id}" data-for="${e.id}"`:"disabled"} title="Preview in the frame"><b>${w(s.id)}</b>${w(s.name)}</button>`).join("")}
26
+ ${n&&e.optionApplied?`<span class="opt-acts"><button class="opt-use" data-use="${e.optionApplied}" data-for="${e.id}">Use ${w(e.optionApplied)}</button><button class="opt-orig" data-opt="" data-for="${e.id}">Original</button></span>`:`<span class="opt-note">${n?"Click an option to preview it in the frame":"Options"}</span>`}</div>`}I.addEventListener("click",async e=>{const t=e.target.closest("[data-goto]");if(t){const i=t.dataset.goto;d.frames.some(o=>o.id===i)&&(U(),J(i),je(!0,[i]));return}const n=e.target.closest("[data-opt]"),s=e.target.closest("[data-use]");if(!n&&!s)return;const a=(n||s).dataset.for;try{s?(await x("POST",`/__loop/api/comments/${a}/choose`,{option:s.dataset.use}),k(`Using option ${s.dataset.use}`)):await x("POST",`/__loop/api/comments/${a}/preview`,{option:n.dataset.opt||null})}catch(i){k(i.message)}});function Yn(e){const t=a=>w(a).replace(/`([^`]+)`/g,"<code>$1</code>").replace(/\*\*([^*]+)\*\*/g,"<b>$1</b>").replace(/(^|[\s(])\*([^*\s][^*]*)\*/g,"$1<i>$2</i>"),n=[];let s=null;for(const a of String(e).split(`
27
+ `)){const i=/^\s*(?:[-*•]|\d+\.)\s+(.*)$/.exec(a);if(i){s||(s=[],n.push(s)),s.push(t(i[1]));continue}s=null,a.trim()&&n.push(`<p>${t(a)}</p>`)}return n.map(a=>Array.isArray(a)?`<ul>${a.map(i=>`<li>${i}</li>`).join("")}</ul>`:a).join("")}function Mr(e){return e.attachments?.length?`<div class="m-files">${e.attachments.map(t=>t.type.startsWith("image/")?`<a href="${w(t.url)}" target="_blank" rel="noopener"><img src="${w(t.url)}" alt="${w(t.name)}"></a>`:`<a class="f" href="${w(t.url)}" target="_blank" rel="noopener">${jt.file}<span>${w(t.name)}</span></a>`).join("")}</div>`:""}const ea=[];function Er(e){const t=(e.inkStrokes||[]).filter(s=>d.strokes.some(a=>a.id===s)).length;if(!t)return"";const n=$t.has(e.id);return`<button class="m-marks${n?" on":""}" data-marks="${e.id}" title="${n?"Hide":"Show"} the marks on the canvas">${Ci}<span>${n?"Hide":`${t} mark${t===1?"":"s"}`}</span></button>`}I.addEventListener("pointerover",e=>{const t=e.target.closest("[data-marks]");t&&Ot!==t.dataset.marks&&(Ot=t.dataset.marks,lt())}),I.addEventListener("pointerout",e=>{const t=e.target.closest("[data-marks]");t&&!t.contains(e.relatedTarget)&&(Ot=null,lt())}),I.addEventListener("click",e=>{const t=e.target.closest("[data-marks]");if(!t)return;const n=t.dataset.marks;$t.has(n)?$t.delete(n):$t.add(n),lt(),Xn()});function Xn(){const e=d.comments.find(a=>a.id===W);if(!e)return U();if(I.dataset.tid!==e.id){I.dataset.tid=e.id,I.innerHTML=`<div class="t-tools"></div><div class="thread-body"></div>
28
+ <div class="thread-reply"><div class="cbox"><div class="c-files" hidden></div><textarea rows="1" placeholder="Reply"></textarea></div></div>`,I._tools=null;const a=I.querySelector("textarea"),i=async()=>{const r=d.comments.find(y=>y.id===W);if(!r)return;const l=ea.splice(0),c=a.value.trim()||(l.length?"See the attached reference.":"");if(!c)return;a.value="",tt(a),o.paint();const u={id:qs(),frameId:r.frameId,parentId:r.id,text:c,author:{name:j.name,color:j.color},attachments:l},f=Gs(u),m=I.querySelector(".thread-body");m&&(m.scrollTop=m.scrollHeight);try{const y=await x("POST","/__loop/api/comments",u);y?.id&&y.id!==u.id&&f()}catch(y){f(),k(y.message)}},o=Ei(I.querySelector(".thread-reply .cbox"),ea,i);tt(a),a.addEventListener("input",()=>tt(a)),a.addEventListener("keydown",r=>{if(r.stopPropagation(),r.key==="Escape")return U();r.key==="Enter"&&!r.shiftKey&&!r.isComposing&&(r.preventDefault(),i())}),a.addEventListener("focus",()=>Qs(d.comments.find(r=>r.id===W)?.frameId),{once:!0})}const t=`
29
+ ${ni(e)}
30
+ <span class="t-title">${w(e.frameId===oe?"Canvas":d.frames.find(a=>a.id===e.frameId)?.name||"")}</span>
31
+ ${e.resolved?'<span class="t-state">Resolved</span>':""}
32
+ <button class="t-btn" data-act="dock" title="${nt?"Collapse":"Expand"}">${nt?De.collapse:De.expand}</button>
33
+ <button class="t-btn" data-act="resolve" title="${e.resolved?"Reopen":"Resolve"}">${e.resolved?De.reopen:De.resolve}</button>
34
+ <span class="t-more"><button class="t-btn" data-act="more" title="More">${De.more}</button>
35
+ <span class="t-menu" hidden><button data-act="delete">${De.trash}<span>Delete thread</span></button></span></span>
36
+ <button class="t-btn" data-act="close" title="Close (esc)">${De.close}</button>`;I._tools!==t&&(I._tools=t,I.querySelector(".t-tools").innerHTML=t);const n=I.querySelector(".thread-body"),s=n.scrollHeight-n.scrollTop-n.clientHeight<40;ai(n,Ct(e.id).map(a=>[a.id,Js(a)])),ii(I),s&&(n.scrollTop=n.scrollHeight),ye()}I.addEventListener("click",e=>{const t=e.target.closest("[data-copy]");if(!t)return;const n=d.comments.find(s=>s.id===t.dataset.copy);navigator.clipboard?.writeText(n?.kind==="note"?n.text:n?.reply||"").then(()=>{t.innerHTML=Wt.check,t.classList.add("ok"),setTimeout(()=>{t.innerHTML=Wt.copy,t.classList.remove("ok")},1200)}).catch(()=>{})});let nt=!!Ce.get("loop.dockThread",!1);const De={expand:E("expand"),collapse:E("collapse"),resolve:E("resolve"),reopen:E("reopen"),more:E("more"),close:E("x"),reply:E("reply"),trash:E("trash")};function wi(){p("#comments-panel").hidden=!0,mt(),_e&&(_e=null,Se()),p("#shortcuts")?.setAttribute("hidden","")}let Me=!!Ce.get("loop.hideComments",!1);function pn(e){Me=e?!1:!Me,Ce.set("loop.hideComments",Me),document.body.classList.toggle("no-comments",Me),Me&&(xe(),U(),ne()),p("#comments-btn").classList.toggle("off",Me),p("#comments-btn").dataset.tip=Me?"Comments are hidden (\u21E7C to show)":"All comments",k(Me?"Comments hidden \xB7 \u21E7C to show":"Comments shown",1600)}document.body.classList.toggle("no-comments",Me),p("#comments-btn").classList.toggle("off",Me);let Un="open";function xi(){return d.comments.filter(e=>!e.parentId&&e.kind!=="create").sort((e,t)=>t.createdAt-e.createdAt)}function Sr(){const e=d?xi().filter(t=>!t.resolved).length:0;p("#comments-count").textContent=e||"",p("#comments-btn").classList.toggle("has",e>0),p("#comments-panel").hidden||ta()}function ta(){const e=xi(),t=e.filter(o=>!o.resolved),n=e.filter(o=>o.resolved),s=p("#comments-panel .cp-tabs");s.querySelector('[data-tab="open"] span').textContent=t.length||"",s.querySelector('[data-tab="resolved"] span').textContent=n.length||"",s.querySelectorAll("button").forEach(o=>o.classList.toggle("on",o.dataset.tab===Un));const a=Un==="open"?t:n,i=o=>o.frameId===oe?"Canvas":d.frames.find(r=>r.id===o.frameId)?.name||"Deleted frame";p("#comments-panel .cp-list").innerHTML=a.length?a.map(o=>{const r=Nn(o.id);return`
37
+ <div class="cp-item${W===o.id?" on":""}" data-id="${o.id}" title="${w(`${o.author?.name||"You"} \xB7 ${i(o)} \xB7 ${Lt(o.createdAt)}`)}">
38
+ <span class="cp-av${r==="working"||r==="queued"?" busy":r==="error"?" err":""}">${_a(o.author?.name||j.name,o.author?.color||j.color)}</span>
39
+ <span class="cp-text">${w(o.text)}</span>
40
+ ${$()?`<button class="cp-res" data-res="${o.id}" title="${o.resolved?"Reopen":"Resolve"}">${o.resolved?De.reopen:De.resolve}</button>`:""}
41
+ </div>`}).join(""):`<div class="cp-empty">${Un==="open"?"No open comments. Press C and click anything to leave one.":"Nothing resolved yet."}</div>`}function na(e,t){Me&&pn(!0),U(),xe(),S&&Tt();const n=e.frameId!==oe&&d.frames.find(a=>a.id===e.frameId),s=e.anchor;if(n&&s){O.get(n.id)?.parked&&(J(n.id),rn());try{const i=s.selector||s.container?.selector||s.elements?.[0]?.selector,o=i&&ce(n.id)?.querySelector(i),r=o?.getBoundingClientRect();r&&(r.top<0||r.bottom>n.h||r.left<0||r.right>n.w)&&o.scrollIntoView({block:"center",inline:"center",behavior:"instant"})}catch{}}requestAnimationFrame(()=>{const a=p("#comments-panel").hidden?0:364;if(n){J(n.id);const i=24,o=76,r=innerWidth-a-i-24,l=innerHeight-o-96,c=Math.min(1,r/n.w,l/n.h);it({z:c,x:i+(r-n.w*c)/2-n.x*c,y:o+(l-n.h*c)/2-n.y*c},380)}else{const i=(s?.wx||0)+(s?.area?.w||0)/2,o=(s?.wy||0)+(s?.area?.h||0)/2,r=Math.max(h.z,.8);it({z:r,x:(innerWidth-a)/2-i*r,y:innerHeight/2-o*r},380)}setTimeout(()=>{if(e.resolved||t)return Kn(e.id);Ke(e.frameId);const i=Bn(e.frameId)?.querySelector(`.pin[data-key="${e.id}"]`);i&&(i.classList.remove("ping"),i.offsetWidth,i.classList.add("ping"),setTimeout(()=>i.classList.remove("ping"),2200))},420)})}p("#comments-btn").addEventListener("click",()=>{const e=p("#comments-panel");e.hidden=!e.hidden,e.hidden||(mt?.(),ta())}),p("#comments-panel").addEventListener("pointerdown",e=>e.stopPropagation()),p("#comments-panel").addEventListener("wheel",e=>e.stopPropagation()),p("#comments-panel").addEventListener("click",async e=>{if(e.target.closest(".cp-x")){p("#comments-panel").hidden=!0;return}const t=e.target.closest("[data-tab]");if(t){Un=t.dataset.tab,ta();return}const n=e.target.closest("[data-res]");if(n){try{await x("POST",`/__loop/api/comments/${n.dataset.res}/resolve`)}catch(i){k(i.message)}return}const s=e.target.closest(".cp-item");if(!s)return;const a=d.comments.find(i=>i.id===s.dataset.id);a&&na(a)}),p("#comments-panel").addEventListener("dblclick",e=>{const t=e.target.closest(".cp-item");if(!t||e.target.closest("[data-res]"))return;const n=d.comments.find(s=>s.id===t.dataset.id);n&&na(n,!0)});const jt={plus:E("plus"),mic:E("mic"),up:E("up"),file:E("file"),x:E("x","s")},ki=6,Tr=8e6,$i=window.SpeechRecognition||window.webkitSpeechRecognition,hn=[],Ci=E("pen","s"),Ar={fable:"Fable",opus:"Opus",sonnet:"Sonnet",haiku:"Haiku"},_r={minimal:"Minimal",low:"Low",medium:"Medium",high:"High",xhigh:"Extra high",max:"Max",ultra:"Ultra"},sa=e=>Ar[e]||mn(e),aa=e=>_r[e]||e,fe=document.createElement("div");fe.id="model-menu",fe.className="menu model-menu",fe.hidden=!0,document.body.appendChild(fe);let Zn=null;function Li(){const e=d?.models;if(!e)return;const t=e.runner==="codex"?"Codex default":e.chat.model||e.chat.effort?"Same as your chat":"Default",n=(s,a,i,o)=>`<button class="tm-item${(e.pick[s]||"")===a?" on":""}" data-mm="${s}" data-v="${w(a)}"><span class="tm-check"></span><span>${w(i)}</span>${o?`<kbd>${w(o)}</kbd>`:""}</button>`;fe.innerHTML=`<div class="mm-title">Model</div>${n("model","",t,e.chat.model?sa(e.chat.model):"")}${e.models.map(s=>n("model",s,sa(s))).join("")}
42
+ <div class="mm-title">Effort</div>${n("effort","",t,e.chat.effort?aa(e.chat.effort):"")}${e.efforts.map(s=>n("effort",s,aa(s))).join("")}
43
+ ${d.agent.mode==="inbox"?'<p class="mm-note">Your chat answers with its own model. This is for the runs Loop starts itself.</p>':""}`}function Mi(){if(!Zn?.isConnected){fe.hidden=!0;return}const e=Zn.getBoundingClientRect(),t=fe.offsetWidth,n=fe.offsetHeight,s=e.top-n-8>=8||e.top>innerHeight-e.bottom;fe.style.left=`${Math.max(8,Math.min(innerWidth-t-8,e.right-t))}px`,fe.style.top=`${Math.max(8,Math.min(innerHeight-n-8,s?e.top-n-8:e.bottom+8))}px`}document.addEventListener("click",e=>{const t=e.target.closest(".c-model.pick");if(t){if(!fe.hidden&&Zn===t){fe.hidden=!0;return}Zn=t,Li(),fe.hidden=!1,Mi()}}),fe.addEventListener("pointerdown",e=>e.stopPropagation()),fe.addEventListener("click",async e=>{const t=e.target.closest("[data-mm]");if(t){if(d.models){const n=d.models,s=t.dataset.mm;n.pick[s]=t.dataset.v||null,n[s]=n.pick[s]||n.chat[s],ia()}try{await x("POST","/__loop/api/settings",{pick:{[t.dataset.mm]:t.dataset.v||null}})}catch(n){k(n.message)}}}),addEventListener("pointerdown",e=>{!fe.hidden&&!e.target.closest("#model-menu, .c-model")&&(fe.hidden=!0)},!0),addEventListener("keydown",e=>{e.key==="Escape"&&!fe.hidden&&(fe.hidden=!0,e.stopPropagation())},!0);function ia(){const e=Pr(),t=!!d?.models&&$();document.querySelectorAll(".c-model").forEach(n=>{n.textContent!==e&&(n.textContent=e),n.classList.toggle("pick",t),n.title=t?"Model and effort":""}),fe.hidden||(Li(),Mi())}function Pr(){if(!d)return"";if(!$())return"Host reviews first";const e=d.models;if(e?.model){const s=d.agent.lastModel,a=e.pick.model&&s&&s.startsWith(`claude-${e.pick.model}-`)?s:e.model;return sa(a)+(e.pick.effort?` \xB7 ${aa(e.pick.effort)}`:"")}const t=d.agent.lastModel;return t&&(d.agentBin==="codex"?!/^claude/.test(t):/^claude/.test(t))?mn(t):d.agentLabel||"Agent"}const qr=e=>new Promise((t,n)=>{const s=new FileReader;s.onload=()=>t(s.result),s.onerror=n,s.readAsDataURL(e)});function Ei(e,t,n){e.insertAdjacentHTML("beforeend",`<div class="c-foot"><button type="button" class="c-btn" data-box="attach" title="Attach images or files \u2014 or drop them here">${jt.plus}</button><input type="file" multiple hidden><span class="c-model"></span>${$i?`<button type="button" class="c-btn" data-box="mic" title="Dictate">${jt.mic}</button>`:""}<button type="button" class="c-send" data-box="send" title="Send (\u21B5)">${jt.up}</button></div>`);const s=e.querySelector("textarea"),a=e.querySelector("input[type=file]"),i=e.querySelector(".c-files"),o=e.querySelector(".c-send"),r=()=>{o.disabled=!s.value.trim()&&!t.length},l=()=>{i.hidden=!t.length,i.innerHTML=t.map((u,f)=>`<span class="c-file${u.type.startsWith("image/")?" img":""}" title="${w(u.name)}">${u.type.startsWith("image/")?`<img src="${u.data}" alt="">`:`${jt.file}<span>${w(u.name)}</span>`}<button type="button" data-rm="${f}" title="Remove">${jt.x}</button></span>`).join(""),ia(),r()},c=async u=>{for(const f of u){if(t.length>=ki){k(`Up to ${ki} files per message`);break}if(f.size>Tr){k(`${f.name} is over 8 MB`);continue}t.push({name:f.name||"pasted-image.png",type:f.type||"application/octet-stream",data:await qr(f)})}l(),s.focus()};return a.addEventListener("change",()=>{c([...a.files]),a.value=""}),e.addEventListener("click",u=>{const f=u.target.closest("[data-rm]");if(f){t.splice(+f.dataset.rm,1),l();return}const m=u.target.closest("[data-box]");m&&(m.dataset.box==="attach"?a.click():m.dataset.box==="mic"?zr(s,m,r):m.dataset.box==="send"&&n())}),e.addEventListener("dragover",u=>{[...u.dataTransfer.types].includes("Files")&&(u.preventDefault(),u.stopPropagation(),e.classList.add("drop"))}),e.addEventListener("dragleave",u=>{e.contains(u.relatedTarget)||e.classList.remove("drop")}),e.addEventListener("drop",u=>{u.preventDefault(),u.stopPropagation(),e.classList.remove("drop"),c([...u.dataTransfer.files])}),s.addEventListener("paste",u=>{const f=[...u.clipboardData?.files||[]];f.length&&(u.preventDefault(),c(f))}),s.addEventListener("input",r),l(),{paint:l}}let Vt=null;function zr(e,t,n){if(Vt){Vt.stop();return}const s=new $i;s.continuous=!0,s.interimResults=!0,s.lang=navigator.language||"en-US";const a=e.value&&!/\s$/.test(e.value)?e.value+" ":e.value;s.onresult=i=>{let o="";for(const r of i.results)o+=r[0].transcript;e.value=a+o,tt(e),n()},s.onend=()=>{Vt=null,t.classList.remove("on"),e.focus()},s.onerror=i=>{i.error==="not-allowed"||i.error==="service-not-allowed"?k("Allow microphone access to dictate"):["aborted","no-speech"].includes(i.error)||k(`Dictation stopped (${i.error})`)},Vt=s,t.classList.add("on");try{s.start()}catch{Vt=null,t.classList.remove("on")}}function Si(){try{Vt?.stop()}catch{}}const oa=Ei(H.querySelector(".cbox"),hn,()=>ui());I.addEventListener("pointerdown",e=>e.stopPropagation()),I.addEventListener("click",async e=>{const t=e.target.closest("[data-act]");if(!t)return;const n=t.dataset.act,s=t.dataset.id||W;try{if(n==="close")return U();if(n==="dock"){nt=!nt,Ce.set("loop.dockThread",nt),I.classList.toggle("docked",nt),nt&&(I.style.left=I.style.top=I.style.maxHeight=""),Xn(),ye();return}if(n==="more"){const a=I.querySelector(".t-menu");a.hidden=!a.hidden;return}if(n==="allow"){t.disabled=!0,t.textContent="Allowing\u2026",await x("POST",`/__loop/api/comments/${s}/allow`,{i:+t.dataset.k});return}if(n==="before"){const a=d.comments.find(i=>i.id===s);a&&(Co(a.frameId,a.id),pt(a.frameId));return}if(n==="delete"){confirm("Delete this comment thread? This can\u2019t be undone.")&&(await x("DELETE",`/__loop/api/comments/${W}`),U());return}if(n==="resolve"){const a=d.comments.find(i=>i.id===W)?.resolved;await x("POST",`/__loop/api/comments/${W}/resolve`),a||(U(),k("Resolved. Find it in Comments \u2192 Resolved"));return}if(n==="undo"){let a=await fetch(`/__loop/api/comments/${s}/undo`,{method:"POST",headers:{"content-type":"application/json"},body:"{}"}),i=await a.json().catch(()=>({}));if(a.status===409&&i.error==="newer"){if(!confirm(`This frame has ${i.newer} newer change${i.newer===1?"":"s"} after this one. Undoing this reverts ${i.newer===1?"it":"them"} too. Continue?`))return;a=await fetch(`/__loop/api/comments/${s}/undo`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({force:!0})}),i=await a.json().catch(()=>({}))}if(!a.ok)throw new Error(i.error||"Could not undo");k(i.reverted>1?`Reverted ${i.reverted} changes`:"Change reverted");return}await x("POST",`/__loop/api/comments/${s}/${n}`),n==="redo"&&k("Change re-applied")}catch(a){k(a.message)}}),H.addEventListener("pointerdown",e=>e.stopPropagation());let Ee=!1;function pe(e){if(!((e==="frame"||e==="section")&&!$())){if(Ee=e==="use",Ee&&(e="select"),!Ee&&re&&!S&&(re=null,Xe()),e!=="deep"&&C&&Ne(),R?.soft&&!Y.value.trim()&&ne(),V=e,F.dataset.tool=e,e!=="select"&&re&&(re=null,Xe()),e==="select"||e==="hand"){const t=p("#move-btn");t.dataset.tool!==e&&(t.dataset.tool=e,t.innerHTML=E(e==="hand"?"hand":"select"),t.title=e==="hand"?"Hand (H)":"Select (V)")}if(document.querySelectorAll("#tool-menu [data-pick-tool]").forEach(t=>t.classList.toggle("on",t.dataset.pickTool===e&&!Ee)),document.querySelectorAll("#toolbar [data-tool]").forEach(t=>t.classList.toggle("on",t.dataset.tool===(Ee?"use":e))),F.dataset.use=Ee?"1":"",xa(),Vi(),Ee&&C&&(ne(),Ne()),Q.hidden=!0,e!=="pen"&&un(),d)for(const t of d.frames)X(t);Se()}}document.querySelectorAll("#toolbar [data-tool]").forEach(e=>e.addEventListener("click",()=>pe(e.dataset.tool)));const Ye=p("#tool-menu");p("#move-caret").addEventListener("click",e=>{if(e.stopPropagation(),!Ye.hidden){Ye.hidden=!0;return}Ye.hidden=!1;const t=p("#move-caret").closest(".tb-group").getBoundingClientRect();Ye.style.left=`${Math.round(t.left)}px`,Ye.style.bottom=`${Math.round(innerHeight-t.top+8)}px`,Ye.style.top="auto"}),Ye.addEventListener("click",e=>{const t=e.target.closest("[data-pick-tool]");t&&(pe(t.dataset.pickTool),Ye.hidden=!0)}),addEventListener("pointerdown",e=>{!Ye.hidden&&!e.target.closest("#tool-menu, #move-caret")&&(Ye.hidden=!0)},!0);let _e=null,re=null;function ra(e){if(re!==e&&(re=e,d))for(const t of d.frames)X(t)}function Ti(e,t,n){if(!n)return!1;const s=e?.ownerDocument;if(!s)return!1;const a=s.defaultView,i=s.scrollingElement||s.documentElement;for(let o=e.nodeType===1?e:e.parentElement;o;o=o.parentElement){const r=o===i||o===s.body,l=a.getComputedStyle(o),c=t==="x"?l.overflowX:l.overflowY;if(!r&&!/(auto|scroll|overlay)/.test(c))continue;const u=r?i:o,f=t==="x"?u.scrollLeft:u.scrollTop,m=t==="x"?u.scrollWidth-u.clientWidth:u.scrollHeight-u.clientHeight;if(m>1&&(n>0?f<m-1:f>0))return!0;if(r)break}return!1}function Xe(){document.activeElement?.tagName==="IFRAME"&&document.activeElement.blur(),window.focus()}function J(e){if($e&&($e=null,xt()),e!==_e&&(_e=null),(e||re)&&(re=null,Xe()),P=e,B.clear(),d)for(const t of d.frames)X(t);Se(),Cn(),$s()}let ie=null,Kt={fid:null,t:0,x:0,y:0};F.addEventListener("pointermove",e=>{const t=e.target.closest?.(".frame")?.dataset.id||null;t!==on&&(on=t,Dt())}),F.addEventListener("pointerleave",()=>{on&&(on=null,Dt())}),F.addEventListener("pointerdown",e=>{if(Dt(),!d||e.target.closest(".pin, .stop, .rename, .count, .dims"))return;T&&e.target.closest(".frame")?.dataset.id!==T.fid&&Be();const t=S&&e.button===0&&e.target.closest(".frame-body")&&e.target.closest(".frame")?.dataset.id;if(t&&t!==S.fid&&H.hidden&&!W)return e.preventDefault(),en(t);if(S&&e.button===0&&e.target.closest(".frame:not(.edge-zone)")?.dataset.id!==S.fid){!H.hidden||W?(ne(),U()):Tt();return}const n=e.target.closest(".edge-zone")?null:e.target.closest(".frame"),s=n?.dataset.id;if(S&&e.button===0&&s&&s!==S.fid)return e.preventDefault(),en(s);if(e.button===1||V==="hand"||kt)return Ir(e);if(e.button!==0)return;if(V==="pen")return Rr(e);if(V==="frame"||V==="section")return Dr(e);if(V==="erase"){ie={type:"erase"},Pi(e),F.setPointerCapture(e.pointerId);return}if(V==="deep"){if(s&&e.target.closest(".frame-body")){os(s,e);return}Ne(),ne(),U();return}if(V==="comment"&&s&&e.target.closest(".frame-label")){e.preventDefault(),U(),ut(s,0,0),R.scope="frame",R.anchor=Rn(s,{scope:"frame",x:0,y:0});const r=p("#composer-area");r.hidden=!1,r.innerHTML=`${E("frame")}<b>${w(d.frames.find(l=>l.id===s)?.name||"Frame")}</b><span>Whole frame</span>`,r.classList.add("chip-frame"),Y.placeholder="What should change about this screen?",O.get(s)?.el.classList.add("whole"),et(s),ye();return}if(V==="comment"){const r=s&&e.target.closest(".frame-body");if(!r&&(!H.hidden||W)){ne(),U();return}if(r&&e[Mt]&&!e.target.closest(".pin")){const{lx:l,ly:c}=Je(s,e.clientX,e.clientY),u=is(s,He(s,l,c),"block");if(u)return ne(),U(),Q.hidden=!0,C={frameId:s,els:[u],scope:u.parentElement},eo()}ie={type:"cpick",fid:r?s:oe,sx:e.clientX,sy:e.clientY,area:!1,rect:null},F.setPointerCapture(e.pointerId);return}if(e.altKey&&$()&&!Ee&&!S&&s&&e.target.closest(".frame-body")&&!e.target.closest(".pin")&&!_t(d.frames.find(r=>r.id===s)||{})){const{lx:r,ly:l}=Je(s,e.clientX,e.clientY),c=He(s,r,l),u=ce(s),f=C?.frameId===s?C.els[C.els.length-1]:null,m=f&&f.contains(c)?f:is(s,c,"deep");if(m&&m!==u?.documentElement&&m!==u?.body){m!==f&&os(s,e),ie={type:"edrag",fid:s,el:m,sx:e.clientX,sy:e.clientY,moved:!1},F.classList.add("dragging"),F.setPointerCapture(e.pointerId);return}}if(!Ee&&(!S||s===S.fid)&&s&&e.target.closest(".frame-body")&&!e.target.closest(".pin")&&!_t(d.frames.find(r=>r.id===s)||{})&&!O.get(s)?.el.classList.contains("empty")){const r=performance.now(),l=wn.fid===s&&r-wn.t<420&&Math.hypot(e.clientX-wn.x,e.clientY-wn.y)<6;wn={fid:s,t:l?0:r,x:e.clientX,y:e.clientY};const c=C?.frameId===s?C.els[C.els.length-1]:null;if(l&&c&&$()&&Xt(c,!0)){Ut(s,c);return}if(l)return;U(),os(s,e,e[Mt]?"outer":"deep");return}C&&!e.target.closest(".pin")&&Ne(),ne();const a=s?null:e.target.closest(".section"),i=a?a.dataset.id:null;if(i&&e.target.closest(".srz")&&$())return Al(i,e);if(i&&!e.target.closest(".sec-label")&&!e.shiftKey){U(),re&&(re=null,Xe()),Ss(i),$()&&$o(i,e);return}if(i&&e.target.closest(".sec-label")){U();const r=performance.now(),l=Ms.id===i&&r-Ms.t<420;return Ms={id:i,t:r},Ss(i),$()?l&&e.target.closest(".sec-name")?(e.preventDefault(),Ms.t=0,ql(i)):$o(i,e):void 0}if(e.target.closest(".resize")&&$())return Or(s,e);if(s&&e.shiftKey&&$()){gl(s),U();return}if(e.target.closest(".frame-label")){U();const r=performance.now(),l=Kt.fid===s&&r-Kt.t<420&&Math.hypot(e.clientX-Kt.x,e.clientY-Kt.y)<6;if(Kt={fid:s,t:r,x:e.clientX,y:e.clientY},l&&$()&&e.target.closest(".name")&&!O.get(s)?.renaming)return e.preventDefault(),J(s),Kt.t=0,Ya(s);if(B.has(s))return $()?Ai(s,e):void 0;if(J(s),!$())return;_i(s,e),ie.onDims=!!e.target.closest(".dims");return}if(s&&e.target.closest(".frame-body")&&_t(d.frames.find(r=>r.id===s)||{})){U();const r=performance.now(),l=Ls.fid===s&&r-Ls.t<420;if(Ls={fid:s,t:r},l)return Ls.t=0,J(s),je(!0,[s]);if(B.has(s))return $()?Ai(s,e):void 0;J(s),$()&&_i(s,e);return}if(U(),!s&&!e.shiftKey&&(J(null),re)){re=null,Xe();for(const r of d.frames)X(r)}Hr(e,s),ie.clickSid=i||null});function Hr(e,t){const n=we(e.clientX,e.clientY);ie={type:"marquee",x0:n.x,y0:n.y,clickFid:t,base:e.shiftKey?new Set([...B,...P?[P]:[]]):new Set},F.classList.add("dragging"),F.setPointerCapture(e.pointerId)}function Ai(e,t){const n=[...B];ie={type:"gmove",ids:n,sx:t.clientX,sy:t.clientY,from:Object.fromEntries(n.map(s=>{const a=d.frames.find(i=>i.id===s);return[s,{x:a.x,y:a.y}]})),moved:!1},F.classList.add("dragging"),F.setPointerCapture(t.pointerId)}function Ir(e){ie={type:"pan",sx:e.clientX,sy:e.clientY,vx:h.x,vy:h.y},F.classList.add("dragging"),F.setPointerCapture(e.pointerId)}function _i(e,t){const n=d.frames.find(s=>s.id===e);ie={type:"move",fid:e,sx:t.clientX,sy:t.clientY,fx:n.x,fy:n.y,moved:!1,dup:t.altKey,kids:t.altKey?[]:Yr(e).map(s=>({id:s.id,x:s.x,y:s.y}))},F.classList.add("dragging"),F.setPointerCapture(t.pointerId)}function Dr(e){const t=we(e.clientX,e.clientY);ie={type:"draw",x0:t.x,y0:t.y,rect:null},F.classList.add("dragging"),F.setPointerCapture(e.pointerId)}function Or(e,t){const n=d.frames.find(a=>a.id===e),s=t.target.closest(".resize")?.dataset.dir||"se";ie={type:"resize",fid:e,dir:s,sx:t.clientX,sy:t.clientY,x0:n.x,y0:n.y,w:n.w,h:n.h},F.classList.add("dragging"),F.setPointerCapture(t.pointerId)}function Rr(e){un(),R?.soft&&!Y.value.trim()&&ne();const t=we(e.clientX,e.clientY),n=document.createElementNS("http://www.w3.org/2000/svg","path");n.setAttribute("stroke",Is),n.setAttribute("stroke-width",3/h.z),Ze.appendChild(n),ie={type:"stroke",points:[t.x,t.y],path:n,width:3/h.z},F.classList.add("dragging"),F.setPointerCapture(e.pointerId)}const Nr=11;function Fr(e,t,n,s,a,i){const o=a-n,r=i-s,l=o*o+r*r,c=l?Math.max(0,Math.min(1,((e-n)*o+(t-s)*r)/l)):0;return Math.hypot(e-(n+c*o),t-(s+c*r))}function Pi(e){const t=we(e.clientX,e.clientY);for(const n of[...d.strokes]){if(n.commentId||String(n.id).startsWith("ink-"))continue;const s=Nr/h.z+(n.width||3)/2,a=Rt(n);let i=!1;for(let o=0;o+1<a.length&&!i;o+=2){const r=o+3<a.length?a[o+2]:a[o],l=o+3<a.length?a[o+3]:a[o+1];i=Fr(t.x,t.y,a[o],a[o+1],r,l)<=s}i&&(d.strokes=d.strokes.filter(o=>o.id!==n.id),Ze.querySelector(`path[data-id="${n.id}"]`)?.remove(),x("DELETE",`/__loop/api/strokes/${n.id}`).catch(()=>{}),Z("Erase mark",()=>Ue({strokes:[n]}),()=>x("DELETE",`/__loop/api/strokes/${n.id}`)))}}F.addEventListener("pointermove",e=>{if(nr(e.clientX,e.clientY),!ie){if(V==="comment"){const n=e[Mt]&&e.target.closest?.(".frame-body")&&!e.target.closest(".pin")&&e.target.closest(".frame")?.dataset.id,s=n&&d.frames.find(a=>a.id===n);s&&!_t(s)&&(!S||n===S.fid)?cn(n,e.clientX,e.clientY,"block"):Q.hidden=!0}if(V==="deep"){const n=e.target.closest(".frame-body")&&e.target.closest(".frame")?.dataset.id;n&&!e.target.closest(".pin")?cn(n,e.clientX,e.clientY):Q.hidden=!0}else if(V==="select"&&!Ee&&!ue){const n=e.target.closest?.(".frame-body")&&e.target.closest(".frame")?.dataset.id,s=n&&d.frames.find(a=>a.id===n);s&&(!S||n===S.fid)&&(S||!_t(s))&&!e.target.closest(".pin")&&!O.get(n)?.el.classList.contains("empty")?cn(n,e.clientX,e.clientY,e[Mt]?"outer":"deep"):Q.hidden=!0}return}const t=ie;if(t.type==="pan")h.x=t.vx+e.clientX-t.sx,h.y=t.vy+e.clientY-t.sy,te();else if(t.type==="smove"){const n=(e.clientX-t.sx)/h.z,s=(e.clientY-t.sy)/h.z;if(!t.moved&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)<3)return;t.moved=!0,En.set(t.sid,{x:t.x0+n,y:t.y0+s});for(const[a,i]of Object.entries(t.from))Le.set(a,{x:i.x+n,y:i.y+s}),X(d.frames.find(o=>o.id===a));xt(),ye()}else if(t.type==="sresize"){const n=(e.clientX-t.sx)/h.z,s=(e.clientY-t.sy)/h.z,a=120;let i=t.x0,o=t.y0,r=t.w,l=t.h;t.dir.includes("e")&&(r=t.w+n),t.dir.includes("s")&&(l=t.h+s),t.dir.includes("w")&&(r=t.w-n,i=t.x0+n),t.dir.includes("n")&&(l=t.h-s,o=t.y0+s),r<a&&(t.dir.includes("w")&&(i=t.x0+t.w-a),r=a),l<a&&(t.dir.includes("n")&&(o=t.y0+t.h-a),l=a),En.set(t.sid,{x:i,y:o,w:r,h:l}),xt()}else if(t.type==="move"&&t.dup){t.moved=!0;const n=d.frames.find(a=>a.id===t.fid);if(t.to={x:t.fx+(e.clientX-t.sx)/h.z,y:t.fy+(e.clientY-t.sy)/h.z},!e.metaKey&&!e.ctrlKey){const a=ba({...t.to,w:n.w,h:n.h},null);t.to.x+=a.dx,t.to.y+=a.dy,at(a.guides)}else at([]);const s=p("#dup-ghost");Object.assign(s.style,{left:`${t.to.x}px`,top:`${t.to.y}px`,width:`${n.w}px`,height:`${n.h}px`}),s.querySelector("span").textContent=`${n.name} copy`,s.hidden=!1}else if(t.type==="move"){t.moved=!0;const n=d.frames.find(i=>i.id===t.fid),s={x:t.fx+(e.clientX-t.sx)/h.z,y:t.fy+(e.clientY-t.sy)/h.z};if(e.shiftKey&&(Math.abs(s.x-t.fx)>=Math.abs(s.y-t.fy)?s.y=t.fy:s.x=t.fx),!e.metaKey&&!e.ctrlKey){const i=ba({...s,w:n.w,h:n.h},t.fid);(!e.shiftKey||s.y===t.fy)&&(s.x+=i.dx),(!e.shiftKey||s.x===t.fx)&&(s.y+=i.dy),at(i.guides)}else at([]);Le.set(t.fid,s);for(const i of t.kids||[]){Le.set(i.id,{x:i.x+s.x-t.fx,y:i.y+s.y-t.fy});const o=d.frames.find(r=>r.id===i.id);o&&X(o)}const a=(d.sections||[]).find(i=>Es(i,{...n,...s}));wt.querySelectorAll(".section").forEach(i=>i.classList.toggle("target",i.dataset.id===a?.id)),X(n),ye()}else if(t.type==="marquee"){const n=we(e.clientX,e.clientY),s={x:Math.min(t.x0,n.x),y:Math.min(t.y0,n.y),w:Math.abs(n.x-t.x0),h:Math.abs(n.y-t.y0)};if(!t.moved&&s.w*h.z<4&&s.h*h.z<4)return;!t.moved&&t.clickFid&&!e.shiftKey&&J(null),t.moved=!0;const a=p("#marquee");a.hidden=!1,Object.assign(a.style,{left:`${s.x}px`,top:`${s.y}px`,width:`${s.w}px`,height:`${s.h}px`});const i=d.frames.filter(o=>o.x<s.x+s.w&&o.x+o.w>s.x&&o.y<s.y+s.h&&o.y+o.h>s.y).map(o=>o.id);ya([...new Set([...t.base,...i])])}else if(t.type==="gmove"){t.moved=!0;let n=(e.clientX-t.sx)/h.z,s=(e.clientY-t.sy)/h.z;const a=t.ids.map(i=>{const o=d.frames.find(r=>r.id===i);return{x:t.from[i].x+n,y:t.from[i].y+s,w:o.w,h:o.h}});if(!e.metaKey&&!e.ctrlKey){const i=va(a),o=ba(i,new Set(t.ids));n+=o.dx,s+=o.dy,at(o.guides)}else at([]);for(const i of t.ids)Le.set(i,{x:t.from[i].x+n,y:t.from[i].y+s}),X(d.frames.find(o=>o.id===i));Qt()}else if(t.type==="cpick"){if(!t.area&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)>6&&(t.area=!0,ne(),U(),F.classList.add("dragging")),!t.area)return;let n,s;if(t.fid===oe)n=we(t.sx,t.sy),s=we(e.clientX,e.clientY);else{const i=d.frames.find(r=>r.id===t.fid),o=r=>({x:Math.max(0,Math.min(i.w,r.lx)),y:Math.max(0,Math.min(i.h,r.ly))});n=o(Je(t.fid,t.sx,t.sy)),s=o(Je(t.fid,e.clientX,e.clientY))}t.rect={x:Math.min(n.x,s.x),y:Math.min(n.y,s.y),w:Math.abs(s.x-n.x),h:Math.abs(s.y-n.y)};let a=dt(t.fid).querySelector(".area.picking");a||(a=document.createElement("div"),a.className="area picking show",dt(t.fid).prepend(a)),Object.assign(a.style,{left:`${t.rect.x}px`,top:`${t.rect.y}px`,width:`${t.rect.w}px`,height:`${t.rect.h}px`})}else if(t.type==="edrag"){if(!t.moved&&Math.hypot(e.clientX-t.sx,e.clientY-t.sy)<4)return;if(!t.moved){t.moved=!0,t.copy=to(t.fid,t.el);const o=ze(d.frames.find(r=>r.id===t.fid));t.x0=o.x+t.copy.x,t.y0=o.y+t.copy.y,t.ghost=document.createElement("div"),t.ghost.id="el-ghost",t.ghost.innerHTML=t.copy.html,Object.assign(t.ghost.style,{width:`${t.copy.w}px`,height:`${t.copy.h}px`}),rt.appendChild(t.ghost),Q.hidden=!0}const n=(e.clientX-t.sx)/h.z,s=(e.clientY-t.sy)/h.z;t.ghost.style.transform=`translate(${t.x0+n}px, ${t.y0+s}px)`;const a=we(e.clientX,e.clientY),i=Vs(a.x,a.y);document.querySelectorAll(".frame.drop-into").forEach(o=>o.classList.remove("drop-into")),i&&O.get(i.id)?.el.classList.add("drop-into")}else if(t.type==="draw"){const n=we(e.clientX,e.clientY),s={x:Math.min(t.x0,n.x),y:Math.min(t.y0,n.y),w:Math.abs(n.x-t.x0),h:Math.abs(n.y-t.y0)};if(e.shiftKey&&(s.w=s.h=Math.max(s.w,s.h)),t.rect=s,V==="section"){t.sec||(t.sec=document.createElement("div"),t.sec.className="section drawing",t.sec.innerHTML='<div class="sec-label"><span class="sec-name">Section</span></div>',wt.appendChild(t.sec)),Object.assign(t.sec.style,{left:`${s.x}px`,top:`${s.y}px`,width:`${s.w}px`,height:`${s.h}px`});return}const a=p("#draw-box");Object.assign(a.style,{left:`${s.x}px`,top:`${s.y}px`,width:`${s.w}px`,height:`${s.h}px`}),a.querySelector("span").textContent=`${Math.round(s.w)} \xD7 ${Math.round(s.h)}`,a.hidden=!1}else if(t.type==="resize"){const n=(e.clientX-t.sx)/h.z,s=(e.clientY-t.sy)/h.z,a=120;let i=t.x0,o=t.y0,r=t.w,l=t.h;if(t.dir.includes("e")&&(r=t.w+n),t.dir.includes("s")&&(l=t.h+s),t.dir.includes("w")&&(r=t.w-n,i=t.x0+n),t.dir.includes("n")&&(l=t.h-s,o=t.y0+s),e.shiftKey&&t.dir.length===2){const u=Math.max(r/t.w,l/t.h),f=t.w*u,m=t.h*u;t.dir.includes("w")&&(i=t.x0+t.w-f),t.dir.includes("n")&&(o=t.y0+t.h-m),r=f,l=m}r<a&&(t.dir.includes("w")&&(i=t.x0+t.w-a),r=a),l<a&&(t.dir.includes("n")&&(o=t.y0+t.h-a),l=a);const c={x:i,y:o,w:r,h:l};if(!e.metaKey&&!e.ctrlKey&&!e.shiftKey){const u=kl(c,t.fid,t.dir);Object.assign(c,u.rect),at(u.guides)}else at([]);Le.set(t.fid,c),X(d.frames.find(u=>u.id===t.fid)),p("#fp-sw")&&(p("#fp-sw").value=Math.round(c.w),p("#fp-sh").value=Math.round(c.h))}else if(t.type==="stroke"){const n=we(e.clientX,e.clientY),s=t.points.length;if(Math.hypot(n.x-t.points[s-2],n.y-t.points[s-1])*h.z<1.5)return;t.points.push(n.x,n.y),t.path.setAttribute("d",Ws(t.points))}else t.type==="erase"&&Pi(e)});const qi=async e=>{const t=ie;if(t){if(ie=null,F.classList.remove("dragging"),at([]),wt.querySelectorAll(".section.target").forEach(n=>n.classList.remove("target")),t.type==="smove"||t.type==="sresize"){const n=En.get(t.sid),s=d.sections.find(r=>r.id===t.sid);if(En.delete(t.sid),!n||!s)return;const a=t.type==="smove"?{x:t.x0,y:t.y0}:{x:t.x0,y:t.y0,w:t.w,h:t.h},i={...n},o=t.sid;if(Object.assign(s,n),x("PATCH",`/__loop/api/sections/${o}`,n).catch(r=>k(r.message)),t.type==="smove"){const r=t.from,l={};for(const c of Object.keys(r)){const u=Le.get(c);Le.delete(c);const f=d.frames.find(m=>m.id===c);u&&f&&(Object.assign(f,u),l[c]={x:u.x,y:u.y})}he(l),Z("Move section",()=>Promise.all([ot(o,a),he(r)]),()=>Promise.all([ot(o,i),he(l)]))}else Z("Resize section",()=>ot(o,a),()=>ot(o,i));xt();return}if(t.type==="marquee"){if(p("#marquee").hidden=!0,!t.moved&&!t.clickFid&&t.clickSid){Ss(t.clickSid);return}if(!t.moved&&t.clickFid){const n=t.clickFid,s=d.frames.find(o=>o.id===n);if(O.get(n)?.el.classList.contains("empty")){J(n),Vn(n);return}J(n),ra(n);const a=we(e.clientX,e.clientY),i=s&&He(n,a.x-s.x,a.y-s.y);try{O.get(n)?.iframe.focus()}catch{}if(i&&i!==ce(n)?.documentElement)try{i.focus?.({preventScroll:!0,focusVisible:!1}),i.click?.()}catch{}}return}if(t.type==="gmove"){if(!t.moved)return;de=null,ps();const n=t.from,s={};for(const a of t.ids){const i=Le.get(a);Le.delete(a);const o=d.frames.find(r=>r.id===a);i&&o&&(Object.assign(o,i),s[a]={x:i.x,y:i.y})}he(s),Z(`Move ${t.ids.length} frames`,()=>he(n),()=>he(s));return}if(t.type==="cpick"){if(document.querySelectorAll(".area.picking").forEach(a=>a.remove()),t.area&&t.rect&&t.rect.w*h.z>8&&t.rect.h*h.z>8)return ut(t.fid,t.rect.x,t.rect.y,null,t.rect);if(t.area)return;if(t.fid===oe){const a=we(t.sx,t.sy);return ut(oe,a.x,a.y,"canvas")}const{lx:n,ly:s}=Je(t.fid,t.sx,t.sy);return O.get(t.fid)?.el.classList.contains("empty")?Vn(t.fid):ut(t.fid,n,s)}if(t.type==="edrag"){if(t.ghost?.remove(),document.querySelectorAll(".frame.drop-into").forEach(o=>o.classList.remove("drop-into")),!t.moved)return;const n=we(e.clientX,e.clientY),s=Vs(n.x,n.y);if(s){const o=ze(s),r=He(s.id,n.x-o.x,n.y-o.y);return so(t.copy,s.id,r)}const a=(e.clientX-t.sx)/h.z,i=(e.clientY-t.sy)/h.z;return no(t.copy,t.x0+a,t.y0+i)}if(t.type==="draw"){p("#draw-box").hidden=!0,t.sec?.remove();const n=t.rect;if(V==="section"){pe("select"),n&&n.w*h.z>24&&n.h*h.z>24&&_l({x:n.x,y:n.y,w:n.w,h:n.h});return}n&&n.w*h.z>12&&n.h*h.z>12?ss("Frame",n.w,n.h,n.x,n.y):V==="frame"&&ss(Pe.name,Pe.w,Pe.h,t.x0,t.y0);return}if(t.type==="move"&&t.dup){p("#dup-ghost").hidden=!0,t.moved&&t.to&&_s(t.fid,t.to);return}if(t.type==="move"&&!t.moved&&t.onDims){_e=_e===t.fid?null:t.fid,Se();return}if(t.type==="move"&&t.moved||t.type==="resize"){const n=Le.get(t.fid),s=d.frames.find(i=>i.id===t.fid),a=t.type==="move"?{x:t.fx,y:t.fy}:{x:t.x0,y:t.y0,w:t.w,h:t.h};if(n&&s&&Object.assign(s,n),Le.delete(t.fid),n){const i=t.fid,o=t.type==="move"?t.kids||[]:[];let r;if(t.type==="move"&&s){const f=new Set([i,...o.map(y=>y.id)]),m=Gi({...s,...n},f)?.id;(m||void 0)!==s.parent&&(r=m||null)}x("PATCH",`/__loop/api/frames/${i}`,r===void 0?n:{...n,parent:r}).catch(f=>k(f.message)),r!==void 0&&s&&(s.parent=r||void 0);const l={...n},c={},u={};for(const f of o){const m=Le.get(f.id);Le.delete(f.id),m&&(c[f.id]={x:f.x,y:f.y},u[f.id]={x:Math.round(m.x),y:Math.round(m.y)})}o.length&&he(u),Z(t.type==="move"?"Move frame":"Resize frame",()=>Promise.all([ht(i,a),o.length&&he(c)]),()=>Promise.all([ht(i,l),o.length&&he(u)]))}t.type==="resize"&&setTimeout(()=>Ke(t.fid),50)}else if(t.type==="stroke"){const n=t.points;n.length<4&&n.push(n[0]+.5,n[1]+.5);const s=new Map;for(let i=0;i<n.length;i+=2){const o=Vs(n[i],n[i+1]);o&&s.set(o.id,(s.get(o.id)||0)+1)}const a=[...s.entries()].sort((i,o)=>o[1]-i[1])[0]?.[0]||null;try{const i=await x("POST","/__loop/api/strokes",{points:n,color:Is,width:t.width,frameId:a});Pa.add(i.id),Z("Draw mark",()=>x("DELETE",`/__loop/api/strokes/${i.id}`),()=>Ue({strokes:[i]})),t.path.remove(),d.strokes.find(o=>o.id===i.id)||d.strokes.push(i),lt(),hr(a,n,e)}catch(i){t.path.remove(),k(i.message)}}}};F.addEventListener("pointerup",qi),F.addEventListener("pointercancel",qi),F.addEventListener("pointerleave",()=>{Q.hidden=!0}),addEventListener("wheel",e=>{if(S&&e.target.closest?.("#viewport")){e.preventDefault();try{const s=e.deltaMode===1?16:1,{lx:a,ly:i}=Je(S.fid,e.clientX,e.clientY),o=He(S.fid,a,i),r=ce(S.fid)?.defaultView;if(o&&r){let l=o;const c=r.document.scrollingElement||r.document.documentElement;for(;l&&l!==c&&l!==r.document.body;l=l.parentElement){const u=r.getComputedStyle(l).overflowY;if(/(auto|scroll|overlay)/.test(u)&&l.scrollHeight>l.clientHeight+1)break}(l&&l!==r.document.body?l:c).scrollTop+=e.deltaY*s,Q.hidden=!0,requestAnimationFrame(()=>{st(),ye()})}}catch{}return}if(e.ctrlKey||e.metaKey)return Oa(e,e.clientX,e.clientY);if(!e.target.closest?.("#viewport"))return;e.preventDefault();const t=e.deltaMode===1?16:1,n=e.target.closest?.(".frame-body")&&e.target.closest(".frame")?.dataset.id;if(n&&(C?.frameId===n||P===n)&&Math.abs(e.deltaY)>=Math.abs(e.deltaX))try{const{lx:s,ly:a}=Je(n,e.clientX,e.clientY),i=He(n,s,a),o=ce(n)?.defaultView;if(i&&o&&Ti(i,"y",e.deltaY)){let r=i;const l=o.document.scrollingElement||o.document.documentElement;for(;r&&r!==l&&r!==o.document.body;r=r.parentElement){const c=o.getComputedStyle(r).overflowY;if(/(auto|scroll|overlay)/.test(c)&&r.scrollHeight>r.clientHeight+1&&(e.deltaY>0?r.scrollTop<r.scrollHeight-r.clientHeight-1:r.scrollTop>0))break}(r&&r!==o.document.body?r:l).scrollTop+=e.deltaY*t,Q.hidden=!0,requestAnimationFrame(()=>{st(),ye()});return}}catch{}h.x-=e.deltaX*t,h.y-=e.deltaY*t,Ns()},{passive:!1,capture:!0});let Gn=1;addEventListener("gesturestart",e=>{e.preventDefault(),Gn=h.z}),addEventListener("gesturechange",e=>{e.preventDefault(),!S&&Qe(e.clientX,e.clientY,Gn*e.scale/h.z)});const gn=()=>{const e=document.activeElement;return e&&(e.tagName==="INPUT"||e.tagName==="TEXTAREA"||e.isContentEditable)};addEventListener("keydown",e=>{if(gn())return;if(e.code==="Space"&&!kt){kt=!0,F.classList.add("panning"),d&&d.frames.forEach(X),e.preventDefault();return}if(e.metaKey||e.ctrlKey){if(e.key.toLowerCase()==="z"){e.preventDefault(),e.shiftKey?bn():as();return}if(e.key.toLowerCase()==="c"&&C&&!ue&&$()){e.preventDefault();const n=C.els[C.els.length-1];Fe=to(C.frameId,n),an=null;try{navigator.clipboard?.write?.([new ClipboardItem({"text/html":new Blob([Fe.html],{type:"text/html"}),"text/plain":new Blob([Fe.html],{type:"text/plain"})})]).catch(()=>{})}catch{}k(`Copied \u201C${Fe.name}\u201D \u2014 \u2318V to paste`,1600);return}if(e.key.toLowerCase()==="v"&&Fe&&!an&&$()){if(e.preventDefault(),C){so(Fe,C.frameId,C.els[C.els.length-1]);return}const n=d.frames.find(r=>r.id===Fe.fid),s=Fe.w,a=Fe.h,i=r=>d.frames.some(l=>r.x<l.x+l.w+40&&r.x+s+40>l.x&&r.y<l.y+l.h+40&&r.y+a+40>l.y);let o=n?{x:n.x+n.w+80,y:n.y}:we(innerWidth/2-s*h.z/2,innerHeight/2-a*h.z/2);i(o)&&(o=Zi(s,a)),no(Fe,o.x,o.y);return}if(e.key.toLowerCase()==="c"&&P&&$()){e.preventDefault(),an=P,Fe=null,k(`Copied \u201C${d.frames.find(n=>n.id===P)?.name}\u201D \u2014 \u2318V to paste`,1600);return}if(e.key.toLowerCase()==="v"&&an&&$()){e.preventDefault(),d.frames.find(n=>n.id===an)?_s(an):k("The copied frame no longer exists");return}if(e.key.toLowerCase()==="d"&&B.size&&$()){e.preventDefault(),[...B].forEach(n=>_s(n));return}if(e.key.toLowerCase()==="d"&&P&&$()){e.preventDefault(),_s(P);return}if(e.key.toLowerCase()==="a"&&$()){e.preventDefault(),ya(d.frames.map(n=>n.id));return}if(e.key.toLowerCase()==="y"&&e.ctrlKey){e.preventDefault(),bn();return}e.key==="0"&&(e.preventDefault(),h.z=1,te()),(e.key==="="||e.key==="+")&&(e.preventDefault(),Qe(innerWidth/2,innerHeight/2,1.25)),e.key==="-"&&(e.preventDefault(),Qe(innerWidth/2,innerHeight/2,.8));return}const t=e.key.toLowerCase();if(t==="v")pe("select");else if(t==="h")pe("hand");else if(t==="p")pe("pen");else if(t==="e")pe("erase");else if(t==="s"&&e.shiftKey&&$())pe(V==="section"?"select":"section");else if((e.key==="Backspace"||e.key==="Delete")&&C&&$())e.preventDefault(),lo();else if((e.key==="Backspace"||e.key==="Delete")&&$e&&$())Pl($e);else if(t==="c"&&e.shiftKey)pn();else if(t==="c")Me&&pn(!0),pe("comment");else if(t==="i"||t==="u")pe("use");else if(t==="d"&&e.shiftKey)Aa();else if(t==="n"&&$())la();else if(t==="f"&&e.shiftKey&&$())P?vs(P):k("Select a frame to freeze it");else if(t==="k"&&$()&&P)bs(P);else if(t==="f"&&$())pe(V==="frame"?"select":"frame");else if(e.key==="!"||e.shiftKey&&e.code==="Digit1")je();else if(e.key==="@"||e.shiftKey&&e.code==="Digit2"){const n=B.size?[...B]:P?[P]:$e?La(d.sections.find(s=>s.id===$e)).map(s=>s.id):[];n.length?je(!0,n):k("Select something to zoom to it")}else if(/^Arrow(Left|Right|Up|Down)$/.test(e.key)&&$()&&!S&&!T&&(P||B.size||$e)){const n=e.shiftKey?10:1;Tl(e.key==="ArrowLeft"?-n:e.key==="ArrowRight"?n:0,e.key==="ArrowUp"?-n:e.key==="ArrowDown"?n:0)&&e.preventDefault()}else if(e.key==="="||e.key==="+")Qe(innerWidth/2,innerHeight/2,1.25);else if(e.key==="-")Qe(innerWidth/2,innerHeight/2,.8);else if(e.key==="Escape"&&C)Ne(),ne();else if(e.key==="Escape")H.hidden?W?U():!p("#agent-menu").hidden||!p("#share-menu").hidden?mt():S?Tt():(J(null),pe("select")):ne();else if((e.key==="Backspace"||e.key==="Delete")&&B.size&&$())yl([...B]);else if(e.altKey&&$()&&B.size>=2&&co[e.code])e.preventDefault(),fo(co[e.code]);else if((e.key==="Backspace"||e.key==="Delete")&&P&&$()){const n=d.frames.find(s=>s.id===P);n&&Xr(n.id).then(()=>{P=null,Se()})}}),addEventListener("keyup",e=>{e.code==="Space"&&(kt=!1,F.classList.remove("panning"),d&&d.frames.forEach(X))}),addEventListener("blur",()=>{kt&&(kt=!1,F.classList.remove("panning"))}),p("#zoom-in").onclick=()=>Qe(innerWidth/2,innerHeight/2,1.25),p("#zoom-out").onclick=()=>Qe(innerWidth/2,innerHeight/2,.8),p("#zoom-level").onclick=()=>je();function mt(){p("#agent-menu").hidden=!0,p("#share-menu").hidden=!0}function zi(e,t){const n=t.getBoundingClientRect();e.hidden=!1,e.style.top=`${n.bottom+8}px`,e.style.left=`${Math.max(12,Math.min(n.right-e.offsetWidth,innerWidth-e.offsetWidth-12))}px`}p("#agent-pill").addEventListener("click",e=>{if(e.stopPropagation(),!$())return;const t=p("#agent-menu"),n=!t.hidden;mt(),n||zi(t,e.currentTarget)}),document.querySelectorAll("#agent-menu .menu-item").forEach(e=>e.addEventListener("click",async()=>{try{await x("POST","/__loop/api/settings",{mode:e.dataset.mode,runner:e.dataset.runner}),k(e.dataset.mode==="inbox"?"Comments will queue for your agent session":`Loop will run ${e.dataset.runner==="codex"?"Codex":"Claude Code"} on each comment`)}catch(t){k(t.message)}mt()})),p("#agent-allowed").addEventListener("click",async e=>{const t=e.target.closest("[data-disallow]");if(t)try{await x("POST","/__loop/api/settings",{disallow:t.dataset.disallow})}catch(n){k(n.message)}});function Br(){const e=!!d.emailSharing;p("#share-menu > .menu-title").textContent=e?"Invite people":"Share this canvas",p("#invite-signin").hidden=!e||!!ke?.user,p("#invite-form").hidden=!e||!ke?.user;const t=p("#share-menu .lan-share");t.open=!e,t.querySelector("summary").hidden=!e,t.classList.toggle("only",!e)}function Qn(){const e=d.share||{};p("#share-lan").value=e.lan||"No network connection",p("#share-public-row").hidden=!e.public,p("#share-public").value=e.public||"",p("#share-public-btn").hidden=!!e.public,p("#share-public-btn").textContent=e.tunnelAvailable?"Create public link":"Create public link (needs cloudflared)"}p("#share-btn").addEventListener("click",async e=>{if(e.stopPropagation(),!$()){try{await navigator.clipboard.writeText(location.href),k("Link copied")}catch{k(location.href,5e3)}return}const t=p("#share-menu"),n=!t.hidden;mt(),n||(Qn(),Br(),p("#share-public-note").textContent="",zi(t,e.currentTarget),ts())}),p("#share-public-btn").addEventListener("click",async()=>{const e=p("#share-public-note"),t=p("#share-public-btn");t.disabled=!0,e.textContent="Opening a tunnel\u2026";try{d.share=await x("POST","/__loop/api/share/public"),e.textContent="Live while this Mac is awake and Loop is running.",Qn()}catch(n){e.textContent=n.message}t.disabled=!1}),p("#share-rotate").addEventListener("click",async()=>{confirm("Reset share links? Anyone using the old links loses access.")&&(d.share=await x("POST","/__loop/api/share/rotate"),Qn(),k("Links reset"))}),document.querySelectorAll("[data-copy]").forEach(e=>e.addEventListener("click",async()=>{const t=p("#"+e.dataset.copy).value;try{await navigator.clipboard.writeText(t),k("Link copied")}catch{p("#"+e.dataset.copy).select()}})),document.querySelectorAll(".menu").forEach(e=>e.addEventListener("pointerdown",t=>t.stopPropagation())),addEventListener("pointerdown",e=>{e.target.closest(".menu, #agent-pill, #share-btn")||mt()});let Hi="1440x1024";function la(){mt(),p("#new-frame").hidden=!1;const e=p("#new-frame-input");e.value="",setTimeout(()=>e.focus(),0)}function Jn(){p("#new-frame").hidden=!0}p("#new-frame [data-close]").addEventListener("click",Jn),p("#new-frame").addEventListener("pointerdown",e=>{e.target.id==="new-frame"&&Jn()}),document.querySelectorAll("#size-pick button").forEach(e=>e.addEventListener("click",()=>{Hi=e.dataset.size,document.querySelectorAll("#size-pick button").forEach(t=>t.classList.toggle("on",t===e))})),p("#new-frame-input").addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Escape"&&Jn(),e.key==="Enter"&&!e.shiftKey&&!e.isComposing&&(e.preventDefault(),Ii())}),p("#new-frame-go").addEventListener("click",Ii);async function Ii(){const e=p("#new-frame-input").value.trim();if(!e)return;const[t,n]=Hi.split("x").map(Number),s=/^(https?:\/\/|\/|~\/|\.\.?\/)/.test(e)&&!/\s/.test(e);try{const a=await x("POST","/__loop/api/frames",s?{src:e,w:t,h:n}:{prompt:e,w:t,h:n});Jn(),setTimeout(()=>{J(null),je(!0,[a.id])},80)}catch(a){k(a.message,4e3)}}function Di(){p("#name-input").value=j.name||"",p("#name-go").textContent=j.name?"Save":"Join",p("#name-modal").hidden=!1,setTimeout(()=>p("#name-input").select(),30)}p("#presence").addEventListener("click",e=>{e.target.closest(".avatar.me")&&Di()}),p("#name-modal").addEventListener("keydown",e=>{e.key==="Escape"&&j.name&&(p("#name-modal").hidden=!0)}),p("#name-go").addEventListener("click",Oi),p("#name-input").addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Enter"&&Oi()});function Oi(){const e=p("#name-input").value.trim();e&&(j.name=e,Ce.set("loop.me",j),p("#name-modal").hidden=!0,On(),$()&&!K&&x("POST","/__loop/api/settings",{hostName:e}).catch(t=>k(t.message)))}let ke=null,es=null;async function Ri(e){if(es)return es;const{createClient:t}=await import("https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2.49.4/+esm");return es=t(e.url,e.key,{auth:{flowType:"pkce",detectSessionInUrl:!0,persistSession:!0,storageKey:"loop-host-auth"}}),es}async function ts(){if(!(K||!$())&&d.emailSharing){try{ke=await x("GET","/__loop/api/cloud")}catch(e){p("#invite-note").textContent=e.message;return}Wr()}}function Ni(e,t){return t?`<img src="${w(t)}" alt="" referrerpolicy="no-referrer">`:w(Xa(e))}function Wr(){const e=!!ke?.user;p("#invite-signin").hidden=e,p("#invite-form").hidden=!e,e&&(p("#me-avatar").innerHTML=Ni(ke.user.name,ke.user.avatar),p("#me-email").textContent=ke.user.email,p("#cloud-link").value=ke.link||"",ke.error&&!p("#invite-note").textContent&&(p("#invite-note").textContent=ke.error),p("#members").innerHTML=(ke.members||[]).map(t=>`
44
+ <div class="member"><span class="m-av">${Ni(t.name||t.email,t.avatar_url)}</span>
28
45
  <span class="m-text"><div class="m-name">${w(t.name||t.email)}</div><div class="m-sub">${t.name?w(t.email)+" \xB7 ":""}${t.joined_at?"Joined":"Invited"}${t.role==="viewer"?" \xB7 can view":""}</div></span>
29
- <button class="m-x" title="Remove" data-email="${w(t.email)}">\xD7</button></div>`).join(""))}d("#members").addEventListener("click",async e=>{const t=e.target.closest("[data-email]");if(t&&confirm(`Remove ${t.dataset.email} from this canvas?`))try{await p("DELETE",`/__loop/api/cloud/members/${encodeURIComponent(t.dataset.email)}`),Re()}catch(n){v(n.message)}}),d("#cloud-google").addEventListener("click",async()=>{try{const e=I||await p("GET","/__loop/api/cloud");if(!(await fetch(`${e.config.url}/auth/v1/settings`,{headers:{apikey:e.config.key}}).then(i=>i.json()).catch(()=>({external:{google:!0}}))).external?.google){d("#invite-note").textContent="",v("Google sign-in isn\u2019t switched on yet. Enable the Google provider in Supabase (Authentication \u2192 Sign In / Providers).",7e3);return}const n=await jt(e.config),{error:a}=await n.auth.signInWithOAuth({provider:"google",options:{redirectTo:`${location.origin}/__loop/?loop_auth=1`}});if(a)throw a}catch(e){v(e.message||"Google sign-in is not available",5e3)}}),d("#cloud-signout").addEventListener("click",async()=>{await p("POST","/__loop/api/cloud/signout"),I=null,Re()});async function Hn(){if(!(A||!new URLSearchParams(location.search).has("loop_auth"))){try{const e=await p("GET","/__loop/api/cloud"),t=await jt(e.config);let{data:n}=await t.auth.getSession();for(let i=0;!n.session&&i<20;i++)await new Promise(o=>setTimeout(o,150)),{data:n}=await t.auth.getSession();if(!n.session)throw new Error("Google sign-in did not complete");t.auth.stopAutoRefresh();const{user:a}=await p("POST","/__loop/api/cloud/session",{access_token:n.session.access_token,refresh_token:n.session.refresh_token,expires_at:n.session.expires_at});try{localStorage.removeItem("loop-host-auth")}catch{}v(`Signed in as ${a.email}`),setTimeout(()=>d("#share-btn").click(),300)}catch(e){v(e.message,5e3)}history.replaceState(null,"","/__loop/")}}async function Kt(e){const t=X(e);if(!t?.documentElement)throw new Error("screen not loaded yet");const n=`<!doctype html>
30
- `+t.documentElement.outerHTML;return p("POST","/__loop/api/cloud/snapshot",{frameId:e,html:n})}async function Nn(e){await p("POST","/__loop/api/cloud/publish");const t=c.frames.filter(a=>a.kind==="route");let n=0;for(const a of t){e.textContent=`Uploading screens\u2026 ${++n}/${t.length}`;try{await Kt(a.id)}catch(i){console.warn("snapshot",a.name,i)}}}function Rn(e){const t=c?.frames.find(n=>n.id===e);A||!t||t.kind!=="route"||!I?.canvasId||!I?.user||setTimeout(()=>Kt(e).catch(()=>{}),2500)}d("#invite-go").addEventListener("click",Bt),d("#invite-emails").addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Enter"&&Bt()});async function Bt(){const e=d("#invite-emails").value.split(/[\s,;]+/).map(a=>a.trim()).filter(Boolean),t=d("#invite-note"),n=d("#invite-go");if(!e.length){t.textContent="Add one or more email addresses.";return}n.disabled=!0;try{await Nn(t),t.textContent="Sending invites\u2026";const a=await p("POST","/__loop/api/cloud/invite",{emails:e});d("#invite-emails").value="",t.textContent=a.warning?a.warning:a.failed?.length?`Invited, but email failed for ${a.failed.map(i=>i.email).join(", ")} \u2014 share the link with them.`:`Invite${a.emailed.length===1?"":"s"} sent to ${a.emailed.join(", ")}.`,await Re()}catch(a){t.textContent=a.message}n.disabled=!1}const Wt=[["Mobile",393,852],["Tablet",834,1194],["Desktop",1440,1024]],Yt=[["Phone",[["iPhone 16",393,852],["iPhone 16 Pro Max",440,956],["iPhone SE",375,667],["Android (compact)",412,917],["Android (large)",448,998]]],["Tablet",[["iPad mini",744,1133],['iPad Pro 11"',834,1194],['iPad Pro 13"',1032,1376],["Android tablet",800,1280]]],["Desktop",[["Desktop",1440,1024],["MacBook Air",1280,832],['MacBook Pro 14"',1512,982],["Desktop HD",1920,1080],["Wide",1728,1117]]]],jn={Mobile:'<svg viewBox="0 0 24 24"><rect x="7" y="2.5" width="10" height="19" rx="2.2"/><path d="M11 18.5h2"/></svg>',Tablet:'<svg viewBox="0 0 24 24"><rect x="4.5" y="2.5" width="15" height="19" rx="2.2"/><path d="M11 18.5h2"/></svg>',Desktop:'<svg viewBox="0 0 24 24"><rect x="2.5" y="4" width="19" height="12.5" rx="1.8"/><path d="M9 20h6M12 16.5V20"/></svg>'};function Fn(e){const t=new Set(c.frames.map(n=>n.name));if(!t.has(e))return e;for(let n=2;;n++)if(!t.has(`${e} ${n}`))return`${e} ${n}`}function Kn(e,t){const n=K(innerWidth/2,innerHeight/2),a=(s,r)=>c.frames.some(l=>s<l.x+l.w+80&&s+e+80>l.x&&r<l.y+l.h+80&&r+t+80>l.y),i=Math.round(n.x-e/2),o=Math.round(n.y-t/2);for(let s=0;s<30;s++)for(const[r,l]of[[1,0],[0,1],[-1,0],[0,-1]]){const f=i+r*s*(e*.5+80),m=o+l*s*(t*.5+80);if(!a(f,m))return{x:f,y:m}}return{x:i,y:o}}function at(e){const t=c.frames.find(i=>i.id===e);if(!t)return;const n={x:u.x+t.x*u.z,y:u.y+t.y*u.z},a={x:n.x+t.w*u.z,y:n.y+t.h*u.z};(n.x<0||n.y<60||a.x>innerWidth||a.y>innerHeight-80)&&xe(!0,[e])}async function it(e,t,n,a,i){const o=a!=null?{x:Math.round(a),y:Math.round(i)}:Kn(t,n);try{const s=await p("POST","/__loop/api/frames",{new:!0,blank:!0,name:Fn(e),w:Math.round(t),h:Math.round(n),...o});ve=s.id,Ae=s.id;let r=null;O("Add frame",async()=>{r=je(s.id)||r,await p("DELETE",`/__loop/api/frames/${s.id}`)},()=>ue(r||{frames:[s]})),R("select"),c.frames.find(l=>l.id===s.id)&&(ve=Ae=null,B(s.id),at(s.id),setTimeout(()=>De(s.id),340))}catch(s){v(s.message)}}function oe(){const e=d("#frame-panel");if(!c||!b()||A){e.hidden=!0;return}if(e.contains(document.activeElement)&&document.activeElement.tagName==="INPUT")return;const t=T==="select"&&M&&c.frames.find(a=>a.id===M);if(T!=="frame"&&!t){e.hidden=!0;return}e.hidden=!1;const n=d("#fp-body");if(T==="frame")d("#fp-title").textContent="New frame",n.innerHTML=`
31
- <div class="fp-quick">${Wt.map(([a,i,o])=>`<button class="fp-q" data-w="${i}" data-h="${o}" data-name="${a}">${jn[a]}<b>${a}</b><small>${i} \xD7 ${o}</small></button>`).join("")}</div>
32
- <p class="fp-hint">Or drag on the canvas to draw any size. Hold \u21E7 for a square.</p>
33
- ${Yt.map(([a,i])=>`<details class="fp-group"><summary>${a}</summary>${i.map(([o,s,r])=>`<button class="fp-row" data-w="${s}" data-h="${r}" data-name="${o}"><span>${w(o)}</span><small>${s} \xD7 ${r}</small></button>`).join("")}</details>`).join("")}
34
- <div class="fp-custom"><label>W<input id="fp-w" inputmode="numeric" value="1200"></label><label>H<input id="fp-h" inputmode="numeric" value="800"></label><button id="fp-make" class="btn-dark">Add</button></div>
35
- <button id="fp-describe" class="link-btn">Describe a frame and let the agent build it (N)</button>`;else{d("#fp-title").innerHTML=`<input id="fp-name" value="${w(t.name)}" title="Rename frame" spellcheck="false">`;const a=t.kind==="route"?`App route ${t.src}`:t.kind==="url"?"Live URL":"Static frame";n.innerHTML=`
36
- <div class="fp-size"><label>W<input id="fp-sw" inputmode="numeric" value="${Math.round(t.w)}"></label><label>H<input id="fp-sh" inputmode="numeric" value="${Math.round(t.h)}"></label></div>
37
- <div class="fp-chips">${Wt.map(([i,o,s])=>`<button class="fp-chip${Math.round(t.w)===o&&Math.round(t.h)===s?" on":""}" data-w="${o}" data-h="${s}">${i}</button>`).join("")}</div>
38
- <details class="fp-group"><summary>All sizes</summary>${Yt.flatMap(([,i])=>i).map(([i,o,s])=>`<button class="fp-row resize" data-w="${o}" data-h="${s}"><span>${w(i)}</span><small>${o} \xD7 ${s}</small></button>`).join("")}</details>
39
- <p class="fp-hint">${w(a)} \xB7 drag the corner handle to resize freely.</p>`}}async function st(e,t){const n=c.frames.find(s=>s.id===M);if(!n||!(e>0&&t>0))return;const a={w:n.w,h:n.h},i={w:Math.round(e),h:Math.round(t)},o=n.id;(a.w!==i.w||a.h!==i.h)&&O("Resize frame",()=>ee(o,a),()=>ee(o,i)),Object.assign(n,i),D(n);try{await p("PATCH",`/__loop/api/frames/${n.id}`,{w:n.w,h:n.h})}catch(s){v(s.message)}oe(),setTimeout(()=>ae(n.id),60)}d("#frame-panel").addEventListener("pointerdown",e=>e.stopPropagation()),d("#frame-panel").addEventListener("wheel",e=>e.stopPropagation()),d("#frame-panel").addEventListener("click",e=>{if(e.target.closest("#fp-close")){T==="frame"?R("select"):B(null);return}if(e.target.closest("#fp-describe")){R("select"),Ht();return}if(e.target.closest("#fp-make")){const n=+d("#fp-w").value,a=+d("#fp-h").value;n>0&&a>0&&it("Frame",n,a);return}const t=e.target.closest("[data-w]");t&&(T==="frame"?it(t.dataset.name,+t.dataset.w,+t.dataset.h):st(+t.dataset.w,+t.dataset.h))}),d("#frame-panel").addEventListener("keydown",e=>{if(e.stopPropagation(),e.key==="Escape"){e.target.blur();return}if(e.key==="Enter"){if(e.target.id==="fp-sw"||e.target.id==="fp-sh"){const t=+d("#fp-sw").value,n=+d("#fp-sh").value;e.target.blur(),st(t,n)}(e.target.id==="fp-w"||e.target.id==="fp-h")&&d("#fp-make").click()}}),d("#frame-panel").addEventListener("focusout",e=>{if((e.target.id==="fp-sw"||e.target.id==="fp-sh")&&!d("#frame-panel").contains(e.relatedTarget)){const t=c.frames.find(i=>i.id===M),n=+d("#fp-sw")?.value,a=+d("#fp-sh")?.value;t&&(n!==Math.round(t.w)||a!==Math.round(t.h))&&st(n,a)}});const Ce=[],ot=[];let rt=!1;function O(e,t,n){rt||A||!b()||(Ce.push({label:e,undo:t,redo:n}),Ce.length>200&&Ce.shift(),ot.length=0)}async function Xt(e,t,n){const a=e.pop();if(!a){v(n==="undo"?"Nothing to undo":"Nothing to redo",1200);return}rt=!0;try{await a[n](),t.push(a),v(`${n==="undo"?"Undo":"Redo"}: ${a.label}`,1400)}catch(i){v(`Couldn't ${n}: ${i.message}`)}finally{rt=!1}}const Ut=()=>Xt(Ce,ot,"undo"),lt=()=>Xt(ot,Ce,"redo");function ee(e,t){const n=c.frames.find(a=>a.id===e);return n&&(Object.assign(n,t),D(n),oe(),setTimeout(()=>ae(e),50)),p("PATCH",`/__loop/api/frames/${e}`,t)}const ue=e=>p("POST","/__loop/api/restore",e);function je(e){const t=c.frames.find(n=>n.id===e);return t?{frames:[{...t}],comments:c.comments.filter(n=>n.frameId===e).map(n=>({...n}))}:null}async function Bn(e){const t=je(e);t&&(await p("DELETE",`/__loop/api/frames/${e}`),O("Delete frame",()=>ue(t),()=>p("DELETE",`/__loop/api/frames/${e}`)),v(`Deleted \u201C${t.frames[0].name}\u201D \u2014 \u2318Z to undo`,2600))}let H=null;function Wn(e,t){const{lx:n,ly:a}=be(e,t.clientX,t.clientY),i=de(e,n,a),o=X(e);if(!i||i===o?.documentElement)return;if(t.shiftKey&&H?.frameId===e){const f=H.els.indexOf(i);if(f>=0?H.els.splice(f,1):H.els.push(i),!H.els.length){Te(),q();return}}else H={frameId:e,els:[i]};const s=!$.hidden&&h?.deep?k.value:"";ie(e,n,a);const r=H.els;h.deep=!0,h.anchor={...h.anchor,scope:"elements",elements:r.map(Yn)},k.value=s,se(k),k.placeholder=r.length>1?"What should change about these?":"What should change about this?";const l=d("#composer-area");l.hidden=!1,l.textContent=`${r.length} element${r.length===1?"":"s"}${r.length===1?` \xB7 ${$e(r[0])}`:""}`,Gt()}function Yn(e){const t=e.outerHTML;return{selector:ke(e),tag:e.tagName.toLowerCase(),label:$e(e),text:(e.innerText||e.getAttribute("aria-label")||e.getAttribute("alt")||"").replace(/\s+/g," ").trim().slice(0,120),html:t.length>900?t.slice(0,900)+"\u2026":t}}function Gt(){if(document.querySelectorAll(".deep-box").forEach(t=>t.remove()),!H)return;const e=ne(H.frameId);if(e)for(const t of H.els){const n=t.getBoundingClientRect(),a=document.createElement("div");a.className="deep-box",Object.assign(a.style,{left:`${n.left}px`,top:`${n.top}px`,width:`${n.width}px`,height:`${n.height}px`}),a.dataset.tag=$e(t),e.appendChild(a)}}function Te(){H=null,document.querySelectorAll(".deep-box").forEach(e=>e.remove())}function ct(e){if(e=e.filter(t=>c.frames.find(n=>n.id===t)),e.length===1)return B(e[0]);M=null,E.clear(),e.forEach(t=>E.add(t));for(const t of c.frames)D(t);oe(),Ke()}function Xn(e){const t=new Set(E.size?E:M?[M]:[]);t.has(e)?t.delete(e):t.add(e),ct([...t])}const dt=e=>{const t=Math.min(...e.map(a=>a.x)),n=Math.min(...e.map(a=>a.y));return{x:t,y:n,w:Math.max(...e.map(a=>a.x+a.w))-t,h:Math.max(...e.map(a=>a.y+a.h))-n}};async function Z(e){for(const[t,n]of Object.entries(e)){const a=c.frames.find(i=>i.id===t);a&&(Object.assign(a,n),D(a))}me(),Ee(),await Promise.all(Object.entries(e).map(([t,n])=>p("PATCH",`/__loop/api/frames/${t}`,n)))}const Vt={KeyA:"left",KeyD:"right",KeyW:"top",KeyS:"bottom",KeyH:"hcenter",KeyV:"vcenter"};function Zt(e){const t=[...E].map(s=>c.frames.find(r=>r.id===s)).filter(Boolean);if(t.length<2)return;const n=dt(t),a={},i={};for(const s of t)a[s.id]={x:s.x,y:s.y};if(e==="hdist"||e==="vdist")return Gn(e,t,n,a);L=null,Fe();for(const s of t){const r={...a[s.id]};e==="left"?r.x=n.x:e==="right"?r.x=n.x+n.w-s.w:e==="hcenter"?r.x=Math.round(n.x+n.w/2-s.w/2):e==="top"?r.y=n.y:e==="bottom"?r.y=n.y+n.h-s.h:e==="vcenter"&&(r.y=Math.round(n.y+n.h/2-s.h/2)),i[s.id]=r}Z(i);const o={left:"Align left",right:"Align right",hcenter:"Align centres",top:"Align top",bottom:"Align bottom",vcenter:"Align middles",hdist:"Distribute horizontally",vdist:"Distribute vertically"}[e];O(o,()=>Z(a),()=>Z(i))}async function Un(e){const t=e.map(je).filter(Boolean);await Promise.all(e.map(a=>p("DELETE",`/__loop/api/frames/${a}`)));const n={frames:t.flatMap(a=>a.frames),comments:t.flatMap(a=>a.comments)};O(`Delete ${e.length} frames`,()=>ue(n),()=>Promise.all(e.map(a=>p("DELETE",`/__loop/api/frames/${a}`)))),E.clear(),Ke(),v(`Deleted ${e.length} frames \u2014 \u2318Z to undo`,2600)}let L=null;function Gn(e,t,n,a){const i=e==="hdist"?"x":"y",o=e==="hdist"?"w":"h",s=[...t].sort((f,m)=>f[i]-m[i]);let r=((i==="x"?n.w:n.h)-s.reduce((f,m)=>f+m[o],0))/Math.max(1,s.length-1);r<40&&(r=80),L={k:i,size:o,ids:s.map(f=>f.id),start:s[0][i],before:a,after:null,gap:Math.round(r)};const l=L;re(l.gap,!0),O(e==="hdist"?"Distribute horizontally":"Distribute vertically",()=>Z(l.before),()=>Z(l.after)),Fe()}function Vn(e){const t=L,n={};let a=t.start;for(const i of t.ids){const o=c.frames.find(s=>s.id===i);o&&(n[i]={...t.before[i],[t.k]:Math.round(a)},a+=o[t.size]+e)}return n}function re(e,t){if(!L)return;e=Math.max(0,Math.round(e)),L.gap=e;const n=Vn(e);if(t)L.after=n,Z(n);else{for(const[s,r]of Object.entries(n)){const l=c.frames.find(f=>f.id===s);l&&(Object.assign(l,r),D(l))}me(),Ee()}const a=d("#align-bar"),i=a.querySelector(".ab-range"),o=a.querySelector(".ab-val");i&&(i.max=Math.max(800,e*2),i.value=e),o&&document.activeElement!==o&&(o.value=e)}function Fe(){const e=d("#align-bar").querySelector(".ab-spacing");if(!e||(e.hidden=!L,!L))return;e.querySelector(".ab-scrub").innerHTML=L.k==="x"?'<svg viewBox="0 0 24 24"><path d="M3 12h18M7 8l-4 4 4 4M17 8l4 4-4 4"/></svg>':'<svg viewBox="0 0 24 24"><path d="M12 3v18M8 7l4-4 4 4M8 17l4 4 4-4"/></svg>';const t=e.querySelector(".ab-range"),n=e.querySelector(".ab-val");t.max=Math.max(800,L.gap*2),t.value=L.gap,document.activeElement!==n&&(n.value=L.gap),me()}const Zn={left:'<path d="M4 3v18"/><rect x="7" y="6" width="11" height="4" rx="1"/><rect x="7" y="14" width="7" height="4" rx="1"/>',hcenter:'<path d="M12 3v18"/><rect x="5" y="6" width="14" height="4" rx="1"/><rect x="8" y="14" width="8" height="4" rx="1"/>',right:'<path d="M20 3v18"/><rect x="6" y="6" width="11" height="4" rx="1"/><rect x="10" y="14" width="7" height="4" rx="1"/>',top:'<path d="M3 4h18"/><rect x="6" y="7" width="4" height="11" rx="1"/><rect x="14" y="7" width="4" height="7" rx="1"/>',vcenter:'<path d="M3 12h18"/><rect x="6" y="5" width="4" height="14" rx="1"/><rect x="14" y="8" width="4" height="8" rx="1"/>',bottom:'<path d="M3 20h18"/><rect x="6" y="6" width="4" height="11" rx="1"/><rect x="14" y="10" width="4" height="7" rx="1"/>',hdist:'<path d="M4 4v16M20 4v16"/><rect x="9" y="7" width="6" height="10" rx="1"/>',vdist:'<path d="M4 4h16M4 20h16"/><rect x="7" y="9" width="10" height="6" rx="1"/>'},Jn={left:"Align left (\u2325A)",hcenter:"Align horizontal centres (\u2325H)",right:"Align right (\u2325D)",top:"Align top (\u2325W)",vcenter:"Align vertical centres (\u2325V)",bottom:"Align bottom (\u2325S)",hdist:"Distribute horizontally",vdist:"Distribute vertically"};function Ke(){const e=d("#align-bar");if(!c||E.size<2||!b()||A){e.hidden=!0;return}if(!e.dataset.ready){e.innerHTML='<span class="ab-count"></span><span class="ab-sep"></span>'+["left","hcenter","right","|","top","vcenter","bottom","|","hdist","vdist"].map(i=>i==="|"?'<span class="ab-sep"></span>':`<button data-align="${i}" title="${Jn[i]}"><svg viewBox="0 0 24 24">${Zn[i]}</svg></button>`).join("")+'<span class="ab-spacing" hidden><span class="ab-sep"></span><span class="ab-scrub" title="Drag left or right to change the spacing"></span><input class="ab-range" type="range" min="0" max="800" step="1" title="Drag to spread them out or pull them closer"><label class="ab-num" title="Space between frames"><input class="ab-val" inputmode="numeric"><small>px</small></label></span>';const t=e.querySelector(".ab-range"),n=e.querySelector(".ab-val"),a=e.querySelector(".ab-scrub");t.addEventListener("input",()=>re(+t.value,!1)),t.addEventListener("change",()=>re(+t.value,!0)),n.addEventListener("keydown",i=>{i.stopPropagation(),i.key==="Enter"&&(re(+n.value||0,!0),n.blur()),i.key==="Escape"&&n.blur()}),n.addEventListener("change",()=>re(+n.value||0,!0)),a.addEventListener("pointerdown",i=>{if(!L)return;i.preventDefault(),a.setPointerCapture(i.pointerId);const o=i.clientX,s=L.gap,r=f=>re(s+(f.clientX-o)*2,!1),l=()=>{a.removeEventListener("pointermove",r),a.removeEventListener("pointerup",l),re(L.gap,!0)};a.addEventListener("pointermove",r),a.addEventListener("pointerup",l)}),e.addEventListener("pointerdown",i=>i.stopPropagation()),e.addEventListener("click",i=>{const o=i.target.closest("[data-align]");o&&Zt(o.dataset.align)}),e.dataset.ready="1"}e.querySelector(".ab-count").textContent=`${E.size} frames`,e.querySelectorAll('[data-align$="dist"]').forEach(t=>t.disabled=E.size<2),L&&(L.ids.length!==E.size||L.ids.some(t=>!E.has(t)))&&(L=null),Fe(),e.hidden=!1,me()}function me(){const e=d("#align-bar");if(e.hidden||E.size<2||!c)return;const t=[...E].map(s=>c.frames.find(r=>r.id===s)).filter(Boolean).map(we);if(!t.length)return;const n=dt(t),a=u.x+(n.x+n.w/2)*u.z,i=u.y+n.y*u.z-34,o=e.offsetWidth||360;e.style.left=`${Math.max(12,Math.min(a-o/2,innerWidth-o-12))}px`,e.style.top=`${Math.max(60,i-46)}px`}const Jt=6,Be=e=>[e.x,e.x+e.w/2,e.x+e.w],We=e=>[e.y,e.y+e.h/2,e.y+e.h];function Qt(e){const t=e instanceof Set?e:new Set([e]);return c.frames.filter(n=>!t.has(n.id)).map(n=>we(n))}function pe(e,t,n){let a=null;for(const i of e)for(const o of t){const s=o-i;Math.abs(s)<=n&&(!a||Math.abs(s)<Math.abs(a.d))&&(a={d:s,at:o})}return a}function en(e,t,n,a){const i=[],o=[e,...t],s=.5/u.z;if(n){const r=o.filter(l=>Be(l).some(f=>Math.abs(f-n.at)<s));i.push({x1:n.at,y1:Math.min(...r.map(l=>l.y)),x2:n.at,y2:Math.max(...r.map(l=>l.y+l.h))})}if(a){const r=o.filter(l=>We(l).some(f=>Math.abs(f-a.at)<s));i.push({x1:Math.min(...r.map(l=>l.x)),y1:a.at,x2:Math.max(...r.map(l=>l.x+l.w)),y2:a.at})}return i}function ft(e,t){const n=Qt(t),a=Jt/u.z,i=pe(Be(e),n.flatMap(Be),a),o=pe(We(e),n.flatMap(We),a),s={...e,x:e.x+(i?.d||0),y:e.y+(o?.d||0)};return{dx:i?.d||0,dy:o?.d||0,guides:en(s,n,i,o)}}function Qn(e,t,n="se"){const a=Qt(t),i=Jt/u.z,o=a.flatMap(Be),s=a.flatMap(We),r={...e};let l=null,f=null;return n.includes("e")?(l=pe([e.x+e.w],o,i),l&&(r.w=e.w+l.d)):n.includes("w")&&(l=pe([e.x],o,i),l&&(r.x=e.x+l.d,r.w=e.w-l.d)),n.includes("s")?(f=pe([e.y+e.h],s,i),f&&(r.h=e.h+f.d)):n.includes("n")&&(f=pe([e.y],s,i),f&&(r.y=e.y+f.d,r.h=e.h-f.d)),{rect:r,guides:en(r,a,l,f)}}function J(e){const t=d("#guides");t.innerHTML=e.map(n=>`<line x1="${n.x1}" y1="${n.y1}" x2="${n.x2}" y2="${n.y2}"/>`).join("")}let Ye=null;async function Xe(e,t){try{const n=await p("POST",`/__loop/api/frames/${e}/duplicate`,t?{x:Math.round(t.x),y:Math.round(t.y)}:{});let a=null;O("Duplicate frame",async()=>{a=je(n.id)||a,await p("DELETE",`/__loop/api/frames/${n.id}`)},()=>ue(a||{frames:[n]})),c.frames.find(i=>i.id===n.id)?(B(n.id),at(n.id)):ve=n.id}catch(n){v(n.message)}}addEventListener("keydown",e=>{e.key==="Alt"&&x.classList.add("alt")}),addEventListener("keyup",e=>{e.key==="Alt"&&x.classList.remove("alt")}),addEventListener("blur",()=>x.classList.remove("alt"));const ea=[["Tools",[["V","Select & interact"],["H / hold Space","Pan"],["F","Frame (presets, or drag to draw)"],["C","Comment (click = pin, drag = area)"],["D","Deep select: pick exact elements (\u21E7 for more)"],["P","Draw"],["E","Erase marks"],["N","Describe a frame for the agent"]]],["Edit",[["\u2318Z","Undo"],["\u21E7\u2318Z / Ctrl Y","Redo"],["\u2325 drag title","Duplicate frame"],["\u2318C / \u2318V","Copy / paste frame"],["\u2318D","Duplicate in place"],["\u21E7 click / drag box","Select several frames"],["\u2318A","Select all frames"],["\u2325A \u2325H \u2325D","Align left / centre / right"],["\u2325W \u2325V \u2325S","Align top / middle / bottom"],["Delete","Delete selected frame"],["Double-click title","Rename frame"],["Esc","Close / deselect"]]],["View",[["Pinch / \u2318 scroll","Zoom"],["Scroll","Pan"],["\u21E71","Fit everything"],["\u23180","Zoom to 100%"],["+ / \u2212","Zoom in / out"]]],["Comments",[["\u21B5","Send to the agent"],["\u21E7\u21B5","New line"],["?","This list"]]]];function tn(e){let t=d("#shortcuts");t||(t=document.createElement("div"),t.id="shortcuts",t.className="modal",t.hidden=!0,t.innerHTML=`<div class="modal-card sc-card"><div class="modal-head"><span>Keyboard shortcuts</span><button class="icon-btn" data-close>\xD7</button></div>
40
- <div class="sc-grid">${ea.map(([n,a])=>`<div><div class="sc-group">${n}</div>${a.map(([i,o])=>`<div class="sc-row"><span>${w(o)}</span><span class="sc-keys">${i.split(" / ").map(s=>`<kbd>${w(s)}</kbd>`).join(" ")}</span></div>`).join("")}</div>`).join("")}</div></div>`,document.body.appendChild(t),t.addEventListener("pointerdown",n=>{(n.target===t||n.target.closest("[data-close]"))&&(t.hidden=!0)})),t.hidden=e===void 0?!t.hidden:!e}addEventListener("keydown",e=>{It()||(e.key==="?"?(e.preventDefault(),tn()):e.key==="Escape"&&d("#shortcuts")&&!d("#shortcuts").hidden&&tn(!1))});function nn(e){const t=c.frames.find(a=>a.id===M),n=e.value.trim();if(t&&n&&n!==t.name){const a=t.name,i=t.id;t.name=n,D(t),p("PATCH",`/__loop/api/frames/${i}`,{name:n}).catch(o=>v(o.message)),O("Rename frame",()=>ee(i,{name:a}),()=>ee(i,{name:n}))}}d("#frame-panel").addEventListener("change",e=>{e.target.id==="fp-name"&&nn(e.target)}),d("#frame-panel").addEventListener("keydown",e=>{e.target.id==="fp-name"&&e.key==="Enter"&&(nn(e.target),e.target.blur())},!0),d("#canvas-name").addEventListener("click",()=>{const e=d("#canvas-name");if(!b()||A||e.querySelector("input"))return;const t=document.createElement("input");t.className="canvas-rename",t.value=c.name,t.spellcheck=!1,e.replaceChildren(t),t.focus(),t.select();const n=a=>{const i=t.value.trim();if(e.textContent=a&&i?i:c.name,a&&i&&i!==c.name){const o=c.name;c.name=i,p("POST","/__loop/api/settings",{name:i}).catch(s=>v(s.message)),O("Rename canvas",()=>p("POST","/__loop/api/settings",{name:o}),()=>p("POST","/__loop/api/settings",{name:i}))}};t.addEventListener("keydown",a=>{a.stopPropagation(),a.key==="Enter"&&t.blur(),a.key==="Escape"&&(t.value=c.name,t.blur())}),t.addEventListener("blur",()=>n(!0))}),addEventListener("resize",()=>V()),Hn(),R("select"),Y(),sn();
46
+ <button class="m-x" title="Remove" data-email="${w(t.email)}">\xD7</button></div>`).join(""))}p("#members").addEventListener("click",async e=>{const t=e.target.closest("[data-email]");if(t&&confirm(`Remove ${t.dataset.email} from this canvas?`))try{await x("DELETE",`/__loop/api/cloud/members/${encodeURIComponent(t.dataset.email)}`),ts()}catch(n){k(n.message)}}),p("#cloud-google").addEventListener("click",async()=>{try{const e=ke||await x("GET","/__loop/api/cloud");if(!(await fetch(`${e.config.url}/auth/v1/settings`,{headers:{apikey:e.config.key}}).then(a=>a.json()).catch(()=>({external:{google:!0}}))).external?.google){p("#invite-note").textContent="",k("Google sign-in isn\u2019t switched on yet. Enable the Google provider in Supabase (Authentication \u2192 Sign In / Providers).",7e3);return}const n=await Ri(e.config),{error:s}=await n.auth.signInWithOAuth({provider:"google",options:{redirectTo:`${location.origin}/__loop/?loop_auth=1`}});if(s)throw s}catch(e){k(e.message||"Google sign-in is not available",5e3)}}),p("#cloud-signout").addEventListener("click",async()=>{await x("POST","/__loop/api/cloud/signout"),ke=null,ts()});async function jr(){if(!(K||!new URLSearchParams(location.search).has("loop_auth"))){try{const e=await x("GET","/__loop/api/cloud"),t=await Ri(e.config);let{data:n}=await t.auth.getSession();for(let a=0;!n.session&&a<20;a++)await new Promise(i=>setTimeout(i,150)),{data:n}=await t.auth.getSession();if(!n.session)throw new Error("Google sign-in did not complete");t.auth.stopAutoRefresh();const{user:s}=await x("POST","/__loop/api/cloud/session",{access_token:n.session.access_token,refresh_token:n.session.refresh_token,expires_at:n.session.expires_at});try{localStorage.removeItem("loop-host-auth")}catch{}k(`Signed in as ${s.email}`),setTimeout(()=>p("#share-btn").click(),300)}catch(e){k(e.message,5e3)}history.replaceState(null,"","/__loop/")}}async function Fi(e){const t=ce(e);if(!t?.documentElement)throw new Error("screen not loaded yet");const n=`<!doctype html>
47
+ `+t.documentElement.outerHTML;return x("POST","/__loop/api/cloud/snapshot",{frameId:e,html:n})}async function Vr(e){await x("POST","/__loop/api/cloud/publish");const t=d.frames.filter(s=>s.kind==="route");let n=0;for(const s of t){e.textContent=`Uploading screens\u2026 ${++n}/${t.length}`;try{await Fi(s.id)}catch(a){console.warn("snapshot",s.name,a)}}}function Kr(e){const t=d?.frames.find(n=>n.id===e);K||!t||t.kind!=="route"||!ke?.canvasId||!ke?.user||setTimeout(()=>Fi(e).catch(()=>{}),2500)}p("#invite-go").addEventListener("click",Bi),p("#invite-emails").addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Enter"&&Bi()});async function Bi(){const e=p("#invite-emails").value.split(/[\s,;]+/).map(s=>s.trim()).filter(Boolean),t=p("#invite-note"),n=p("#invite-go");if(!e.length){t.textContent="Add one or more email addresses.";return}n.disabled=!0;try{await Vr(t),t.textContent="Sending invites\u2026";const s=await x("POST","/__loop/api/cloud/invite",{emails:e});p("#invite-emails").value="",t.textContent=s.warning?s.warning:s.failed?.length?`Invited, but email failed for ${s.failed.map(a=>a.email).join(", ")} \u2014 share the link with them.`:`Invite${s.emailed.length===1?"":"s"} sent to ${s.emailed.join(", ")}.`,await ts()}catch(s){t.textContent=s.message}n.disabled=!1}const ca=[["Mobile",393,852],["Tablet",834,1194],["Desktop",1440,1024]],ns=[["Phone",[["iPhone 16",393,852],["iPhone 16 Pro Max",440,956],["iPhone SE",375,667],["Android (compact)",412,917],["Android (large)",448,998]]],["Tablet",[["iPad mini",744,1133],['iPad Pro 11"',834,1194],['iPad Pro 13"',1032,1376],["Android tablet",800,1280]]],["Desktop",[["Desktop",1440,1024],["MacBook Air",1280,832],['MacBook Pro 14"',1512,982],["Desktop HD",1920,1080],["Wide",1728,1117]]]],Wi={Mobile:E("phone"),Tablet:E("tablet"),Desktop:E("desktop")};let Pe=Ce.get("loop.framePreset",null)||{name:"Desktop",w:1440,h:1024};const ji={Phone:E("phone"),Tablet:E("tablet"),Desktop:E("desktop")};function da(e,t,n){Pe={name:e,w:Math.round(t),h:Math.round(n)},Ce.set("loop.framePreset",Pe),Vi()}function Vi(){const e=p("#toolbar"),t=p("#frame-tray"),n=V==="frame"&&!!d&&$();if(e.classList.toggle("tray-open",n),!n){p("#preset-menu").hidden=!0;return}const s=(r,l)=>Pe.w===r&&Pe.h===l,a=[...ca].reverse(),i=a.some(([,r,l])=>s(r,l)),o=a.map(([r,l,c])=>`<button class="tr-dev${s(l,c)?" on":""}" data-w="${l}" data-h="${c}" data-name="${r}" title="${r} \xB7 ${l} \xD7 ${c}">${Wi[r]}</button>`).join("")+`<button class="tr-more${i?"":" on"}" title="All sizes">${i?"<span>More</span>":`<span>${w(Pe.name)}</span>`}<small>${Pe.w} \xD7 ${Pe.h}</small>${E("down")}</button>`;t._h!==o&&(t._h=o,t.innerHTML=o)}function Ki(e){const t=p("#preset-menu"),n=e||Pe,s=(a,i)=>Math.round(n.w)===a&&Math.round(n.h)===i;if(t.dataset.mode=e?"resize":"new",t.classList.toggle("for-frame",!!e),e||(t.style.left=t.style.top=""),e){const a=[e.kind==="frozen"?e.from?'<button class="pm-act" data-act="live">Open live</button>':"":`<button class="pm-act" data-act="freeze">${ys}<span>Freeze a copy</span><kbd>\u21E7F</kbd></button>`,yt(e)?`<button class="pm-act${e.keyboard?" on":""}" data-act="keyboard"><span>Keyboard</span><kbd>K</kbd></button>`:""].join("");t.innerHTML=`<div class="pm-custom pm-top"><span>Size</span><label>W<input id="pm-w" inputmode="numeric" value="${Math.round(e.w)}"></label><label>H<input id="pm-h" inputmode="numeric" value="${Math.round(e.h)}"></label><button id="pm-use">Apply</button></div>`+ns.map(([i,o])=>`<div class="pm-group"><div class="pm-title">${ji[i]||""}<span>${i}</span></div>${o.map(([r,l,c])=>`<button class="pm-row${s(l,c)?" on":""}" data-w="${l}" data-h="${c}" data-name="${w(r)}"><span>${w(r)}</span><small>${l} \xD7 ${c}</small></button>`).join("")}</div>`).join("")+(a?`<div class="pm-acts">${a}</div>`:"");return}t.innerHTML=ns.map(([a,i])=>`<div class="pm-group"><div class="pm-title">${ji[a]||""}<span>${a}</span></div>${i.map(([o,r,l])=>`<button class="pm-row${s(r,l)?" on":""}" data-w="${r}" data-h="${l}" data-name="${w(o)}"><span>${w(o)}</span><small>${r} \xD7 ${l}</small></button>`).join("")}</div>`).join("")+`<div class="pm-custom"><span>Custom</span><label>W<input id="pm-w" inputmode="numeric" value="${Pe.w}"></label><label>H<input id="pm-h" inputmode="numeric" value="${Pe.h}"></label><button id="pm-use">Use</button></div><button class="pm-describe" id="pm-describe">${E("frame")}<span>Describe a frame for the agent</span><kbd>N</kbd></button>`}p("#frame-tray").addEventListener("pointerdown",e=>e.stopPropagation()),p("#frame-tray").addEventListener("click",e=>{const t=e.target.closest(".tr-dev");if(t){da(t.dataset.name,+t.dataset.w,+t.dataset.h),p("#preset-menu").hidden=!0;return}if(e.target.closest(".tr-more")){const n=p("#preset-menu");if(!n.hidden){n.hidden=!0;return}Ki(),n.hidden=!1}}),p("#preset-menu").addEventListener("pointerdown",e=>e.stopPropagation()),p("#preset-menu").addEventListener("click",e=>{const t=p("#preset-menu");if(t.dataset.mode==="resize"){const s=e.target.closest("[data-act]")?.dataset.act;if(s&&P){s==="freeze"?vs(P):s==="live"?ho(P):s==="keyboard"&&bs(P),Yi(!0);return}const a=e.target.closest(".pm-row");if(a){yn(+a.dataset.w,+a.dataset.h);return}if(e.target.closest("#pm-use")){const i=+p("#pm-w").value,o=+p("#pm-h").value;i>=40&&o>=40&&yn(i,o)}return}const n=e.target.closest(".pm-row");if(n){da(n.dataset.name,+n.dataset.w,+n.dataset.h),t.hidden=!0;return}if(e.target.closest("#pm-use")){const s=+p("#pm-w").value,a=+p("#pm-h").value;s>=40&&a>=40&&(da("Frame",s,a),t.hidden=!0);return}e.target.closest("#pm-describe")&&(p("#preset-menu").hidden=!0,pe("select"),la())}),p("#preset-menu").addEventListener("keydown",e=>{e.key==="Enter"&&(e.target.id==="pm-w"||e.target.id==="pm-h")&&p("#pm-use").click(),e.key==="Escape"&&(p("#preset-menu").hidden=!0,e.stopPropagation())}),addEventListener("pointerdown",e=>{const t=p("#preset-menu");t.hidden||e.target.closest("#preset-menu, #frame-tray, .frame > .dims")||(t.hidden=!0,t.dataset.mode==="resize"&&_e&&(_e=null))},!0);function Yi(e){const t=p("#preset-menu"),n=d&&$()&&!K&&V==="select"&&P&&_e===P&&d.frames.find(a=>a.id===P);if(!n){t.dataset.mode==="resize"&&(t.hidden=!0);return}const s=`${n.id}|${Math.round(n.w)}|${Math.round(n.h)}|${n.kind}|${!!n.keyboard}`;(e||t.dataset.mode!=="resize"||t._key!==s&&!t.contains(document.activeElement))&&(Ki(n),t._for=n.id,t._key=s),t.hidden=!1,Xi()}function Xi(){const e=p("#preset-menu");if(e.hidden||e.dataset.mode!=="resize")return;const t=O.get(e._for)?.el.querySelector(":scope > .dims");if(!t)return;const n=t.getBoundingClientRect(),s=t.parentElement.querySelector(".frame-body").getBoundingClientRect(),a=e.offsetWidth,i=e.offsetHeight;let o=s.right+14,r=Math.max(60,Math.min(s.bottom-i,innerHeight-i-76));o+a>innerWidth-12&&(o=s.left-14-a),o<12&&(o=Math.max(12,Math.min(n.left+n.width/2-a/2,innerWidth-a-12)),r=n.bottom+8,r+i>innerHeight-70&&(r=Math.max(12,n.top-i-8))),e.style.left=`${Math.round(o)}px`,e.style.top=`${Math.round(r)}px`}function Ui(e){const t=new Set(d.frames.map(n=>n.name));if(!t.has(e))return e;for(let n=2;;n++)if(!t.has(`${e} ${n}`))return`${e} ${n}`}function Zi(e,t){const n=we(innerWidth/2,innerHeight/2),s=(o,r)=>d.frames.some(l=>o<l.x+l.w+80&&o+e+80>l.x&&r<l.y+l.h+80&&r+t+80>l.y),a=Math.round(n.x-e/2),i=Math.round(n.y-t/2);for(let o=0;o<30;o++)for(const[r,l]of[[1,0],[0,1],[-1,0],[0,-1]]){const c=a+r*o*(e*.5+80),u=i+l*o*(t*.5+80);if(!s(c,u))return{x:c,y:u}}return{x:a,y:i}}function pt(e){if(S)return;const t=d.frames.find(a=>a.id===e);if(!t)return;const n={x:h.x+t.x*h.z,y:h.y+t.y*h.z},s={x:n.x+t.w*h.z,y:n.y+t.h*h.z};(n.x<0||n.y<60||s.x>innerWidth||s.y>innerHeight-80)&&je(!0,[e])}function Yr(e){const t=[],n=s=>{for(const a of d.frames)a.parent===s&&!t.includes(a)&&(t.push(a),n(a.id))};return n(e),t}function Gi(e,t=new Set){return d.frames.filter(n=>!t.has(n.id)&&e.x>=n.x&&e.y>=n.y&&e.x+e.w<=n.x+n.w&&e.y+e.h<=n.y+n.h).sort((n,s)=>n.w*n.h-s.w*s.h)[0]||null}async function ss(e,t,n,s,a){const i=s!=null?{x:Math.round(s),y:Math.round(a)}:Zi(t,n),o=s!=null?Gi({...i,w:t,h:n})?.id:null;try{const r=await x("POST","/__loop/api/frames",{new:!0,blank:!0,name:Ui(e),w:Math.round(t),h:Math.round(n),...i,...o?{parent:o}:{}});We=r.id,_n=r.id;let l=null;Z("Add frame",async()=>{l=Yt(r.id)||l,await x("DELETE",`/__loop/api/frames/${r.id}`)},()=>Ue(l||{frames:[r]})),pe("select"),d.frames.find(c=>c.id===r.id)&&(We=_n=null,J(r.id),pt(r.id),setTimeout(()=>Vn(r.id),340))}catch(r){k(r.message)}}function Se(){const e=p("#frame-panel");e.hidden=!0,Yi()}async function yn(e,t){const n=d.frames.find(o=>o.id===P);if(!n||!(e>0&&t>0))return;const s={w:n.w,h:n.h},a={w:Math.round(e),h:Math.round(t)},i=n.id;(s.w!==a.w||s.h!==a.h)&&Z("Resize frame",()=>ht(i,s),()=>ht(i,a)),Object.assign(n,a),X(n);try{await x("PATCH",`/__loop/api/frames/${n.id}`,{w:n.w,h:n.h})}catch(o){k(o.message)}Se(),setTimeout(()=>Ke(n.id),60)}p("#frame-panel").addEventListener("pointerdown",e=>e.stopPropagation()),p("#frame-panel").addEventListener("click",e=>{const t=e.target.closest('[data-pick="frame-fill"]');if(t)return us(t);if(e.target.closest(".fp-fill-none")){const n=d.frames.find(a=>a.id===P);if(!n)return;const s=n.fill==="none"?null:"none";gt={id:n.id,before:n.fill||null},n.fill=s||void 0,X(n),x("PATCH",`/__loop/api/frames/${n.id}`,{fill:s}).catch(a=>k(a.message)),ro(),Se()}}),p("#frame-panel").addEventListener("wheel",e=>e.stopPropagation()),p("#frame-panel").addEventListener("click",e=>{const t=e.target.closest("[data-act]")?.dataset.act;if(t&&P){t==="freeze"?vs(P):t==="live"?ho(P):t==="keyboard"&&bs(P);return}if(e.target.closest("#fp-close")){V==="frame"?pe("select"):(_e=null,Se());return}if(e.target.closest("#fp-describe")){pe("select"),la();return}if(e.target.closest("#fp-make")){const s=+p("#fp-w").value,a=+p("#fp-h").value;s>0&&a>0&&ss("Frame",s,a);return}const n=e.target.closest("[data-w]");n&&(V==="frame"?ss(n.dataset.name,+n.dataset.w,+n.dataset.h):yn(+n.dataset.w,+n.dataset.h))}),p("#frame-panel").addEventListener("keydown",e=>{if(e.stopPropagation(),e.key==="Escape"){e.target.blur();return}if(e.key==="Enter"){if(e.target.id==="fp-sw"||e.target.id==="fp-sh"){const t=+p("#fp-sw").value,n=+p("#fp-sh").value;e.target.blur(),yn(t,n)}(e.target.id==="fp-w"||e.target.id==="fp-h")&&p("#fp-make").click()}}),p("#frame-panel").addEventListener("focusout",e=>{if((e.target.id==="fp-sw"||e.target.id==="fp-sh")&&!p("#frame-panel").contains(e.relatedTarget)){const t=d.frames.find(a=>a.id===P),n=+p("#fp-sw")?.value,s=+p("#fp-sh")?.value;t&&(n!==Math.round(t.w)||s!==Math.round(t.h))&&yn(n,s)}});const vn=[],fa=[];let ua=!1;function Z(e,t,n){ua||K||!$()||(vn.push({label:e,undo:t,redo:n}),vn.length>200&&vn.shift(),fa.length=0)}async function Qi(e,t,n){const s=e.pop();if(!s){k(n==="undo"?"Nothing to undo":"Nothing to redo",1200);return}ua=!0;try{await s[n](),t.push(s),k(`${n==="undo"?"Undo":"Redo"}: ${s.label}`,1400)}catch(a){k(`Couldn't ${n}: ${a.message}`)}finally{ua=!1}}const as=()=>Qi(vn,fa,"undo"),bn=()=>Qi(fa,vn,"redo");function ht(e,t){const n=d.frames.find(s=>s.id===e);return n&&(Object.assign(n,t),X(n),Se(),setTimeout(()=>Ke(e),50)),x("PATCH",`/__loop/api/frames/${e}`,t)}const Ue=e=>x("POST","/__loop/api/restore",e);function Yt(e){const t=d.frames.find(n=>n.id===e);return t?{frames:[{...t}],comments:d.comments.filter(n=>n.frameId===e).map(n=>({...n}))}:null}async function Xr(e){const t=Yt(e);t&&(await x("DELETE",`/__loop/api/frames/${e}`),Z("Delete frame",()=>Ue(t),()=>x("DELETE",`/__loop/api/frames/${e}`)),k(`Deleted \u201C${t.frames[0].name}\u201D \u2014 \u2318Z to undo`,2600))}let C=null,wn={fid:null,t:0,x:0,y:0};function Ji(e){let t=e;for(let n=0;n<6;n++){const s=[...t.children].filter(o=>!/^(SCRIPT|STYLE|LINK|META|NOSCRIPT|TEMPLATE)$/.test(o.tagName));if(s.length!==1||!s[0].children.length)break;const a=t.getBoundingClientRect();if(s[0].getBoundingClientRect().width<a.width*.9)break;t=s[0]}return t}function is(e,t,n){const s=ce(e),a=s?.body;if(!t||!a||t===s.documentElement)return null;if(n==="block")return a.contains(t)?Ur(t,a):null;if(n==="deep"||!a.contains(t))return t===a?null:t;if(n==="outer"){const c=C?.frameId===e?C.els[C.els.length-1]:null,u=c?.isConnected&&c.contains(t)?c:t,f=u.parentElement;return!f||f===a?u:f}const i=C?.frameId===e,o=i?C.els[C.els.length-1]:null;let r=n==="drill"&&o?.isConnected&&o.contains(t)?o:i&&C.scope?.isConnected?C.scope:Ji(a);for(;r!==a&&!r.contains(t);)r=r.parentElement;if(t===r)return r===a?null:r;let l=t;for(;l.parentElement&&l.parentElement!==r;)l=l.parentElement;return l}function Ur(e,t){let n=e.closest?.("svg")||e;for(;n&&n!==t;n=n.parentElement){if(n.tagName.toLowerCase()==="svg")continue;const s=[...n.children].filter(i=>!/^(SCRIPT|STYLE|BR|TEMPLATE)$/.test(i.tagName)).length,a=n.getBoundingClientRect();if(s&&n.ownerDocument.defaultView.getComputedStyle(n).display!=="inline"&&a.width>24&&a.height>16)return n}return null}function xn(e){const t=[...e.childNodes].filter(o=>o.nodeType===3).map(o=>o.data).join(" ").replace(/\s+/g," ").trim();if(t&&!e.children.length)return t.length>28?t.slice(0,27)+"\u2026":t;const n=e.tagName.toLowerCase(),s={img:"Image",svg:"Icon",picture:"Image",video:"Video",canvas:"Canvas",button:"Button",a:"Link",input:"Field",textarea:"Field",select:"Menu",ul:"List",ol:"List",li:"Item",nav:"Navigation",header:"Header",footer:"Footer",form:"Form",table:"Table",label:"Label",section:"Section",main:"Main",aside:"Aside",article:"Article"},a=(e.getAttribute("aria-label")||"").trim();if(s[n]&&(n==="button"||n==="a")&&(t||a))return`${s[n]} \xB7 ${(t||a).slice(0,22)}`;if(s[n])return s[n];if(/^h[1-6]$/.test(n))return"Heading";const i=typeof e.className=="string"&&e.className.trim().split(/\s+/).find(o=>/^[a-zA-Z][a-zA-Z0-9_-]{2,}$/.test(o)&&!/[:\[]/.test(o)&&!/\d/.test(o))||(/^[a-zA-Z][\w-]*$/.test(e.id)?e.id:"");if(i){const o=i.replace(/[-_]+/g," ").replace(/([a-z])([A-Z])/g,"$1 $2").trim();return o[0].toUpperCase()+o.slice(1).toLowerCase()}return t?"Text":"Frame"}function os(e,t,n="deep"){const{lx:s,ly:a}=Je(e,t.clientX,t.clientY),i=He(e,s,a),o=ce(e),r=C?.frameId===e?C.els[C.els.length-1]:null;if(n==="drill"&&r&&r.contains(i)&&(i===r||!r.children.length)&&Xt(r,!0)){Ut(e,r);return}const l=is(e,i,n);if(!l||l===o?.documentElement)return;if(n==="drill"&&l===r&&Xt(r,!0)){Ut(e,r);return}if(t.shiftKey&&C?.frameId===e){const u=C.els.indexOf(l);if(u>=0?C.els.splice(u,1):C.els.push(l),!C.els.length){Ne(),ne();return}}else H.hidden||ne(),C={frameId:e,els:[l],scope:l.parentElement};Q.hidden=!0,re===e&&(re=null,Xe());const c=d.frames.find(u=>u.id===e);c&&X(c),ma(e)}function ma(e){{const t=d.frames.find(n=>n.id===e);t&&X(t)}U(),xe(),st(),ha()}function eo(){if(!C)return;const{frameId:e,els:t}=C,n=t[t.length-1].getBoundingClientRect(),s=O.get(e).iframe.getBoundingClientRect(),a=C;C=null,ut(e,n.left+Math.min(n.width/2,60),n.top+Math.min(n.height/2,20)),C=a,R.deep=!0,R.anchor=Rn(e,{...R.anchor,scope:"elements",elements:t.map(rs)}),Y.placeholder=t.length>1?"What should change about these?":"What should change about this?";const i=p("#composer-area");i.hidden=!1,i.classList.remove("chip-frame"),i.textContent=t.length===1?xn(t[0]):`${t.length} layers`,ee.hidden=!0,st(),ye()}function Kl(){if(!C||C.els.length!==1)return!1;const e=C.frameId,t=C.els[0],n=ce(e)?.body,s=t.parentElement;if(!n||!s||s===n||s===Ji(n)||!n.contains(s))return!1;const a=s.getBoundingClientRect(),i=O.get(e).iframe.getBoundingClientRect();return C={frameId:e,els:[s],scope:s.parentElement},ma(e),!0}function rs(e){const t=e.outerHTML;return{selector:Nt(e),tag:e.tagName.toLowerCase(),label:Ja(e),text:(e.innerText||e.getAttribute("aria-label")||e.getAttribute("alt")||"").replace(/\s+/g," ").trim().slice(0,120),html:t.length>900?t.slice(0,900)+"\u2026":t}}function st(){if(document.querySelectorAll(".deep-box").forEach(t=>t.remove()),!C)return;const e=dt(C.frameId);if(e)for(const t of C.els){const n=t.getBoundingClientRect(),s=document.createElement("div");s.className="deep-box",Object.assign(s.style,{left:`${n.left}px`,top:`${n.top}px`,width:`${n.width}px`,height:`${n.height}px`}),s.dataset.tag=xn(t),e.appendChild(s);const a=C.els.length===1&&t.parentElement,i=t.ownerDocument.body;if(a&&a!==i&&a!==t.ownerDocument.documentElement){const o=a.getBoundingClientRect(),r=document.createElement("div");r.className="deep-box par",Object.assign(r.style,{left:`${o.left}px`,top:`${o.top}px`,width:`${o.width}px`,height:`${o.height}px`}),e.appendChild(r)}}}function Ne(){if(Et(),C=null,document.querySelectorAll(".deep-box").forEach(e=>e.remove()),z&&(clearTimeout(z.t),Object.keys(z.pending).length&&d.frames.find(e=>e.id===z.fid)?.kind==="folder"&&io()),ee.hidden=!0,z=null,Q.hidden=!0,d)for(const e of d.frames)X(e)}const Mt=/Mac|iPhone|iPad/.test(navigator.platform)?"metaKey":"ctrlKey",Zr=new Set(["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"]),Gr=new Set(["script","style","textarea","title"]),Qr=new Set(["address","article","aside","blockquote","div","dl","fieldset","footer","form","h1","h2","h3","h4","h5","h6","header","hr","main","nav","ol","p","pre","section","table","ul"]),Jr={li:["li"],dt:["dt","dd"],dd:["dt","dd"],option:["option"],tr:["tr"],td:["td","th"],th:["td","th"]};function el(e){const t={tag:"#root",kids:[],parent:null},n=e.length;let s=t,a=0,i=0,o=0;const r=c=>{c>i&&s.kids.push({text:!0,a:i,b:c})},l=(c,u,f)=>{c.innerB=u,c.b=f,(c.tag==="svg"||c.tag==="math")&&(o=Math.max(0,o-1))};for(;a<n;){const c=e.indexOf("<",a);if(c<0)break;if(e.startsWith("<!--",c)){r(c);const L=e.indexOf("-->",c+4),N=L<0?n:L+3;s.kids.push({comment:!0,a:c,b:N}),a=i=N;continue}const u=e[c+1];if(u==="!"||u==="?"){r(c);const L=e.indexOf(">",c);a=i=L<0?n:L+1;continue}const f=/^<(\/?)([a-zA-Z][^\s/>]*)/.exec(e.slice(c,c+96));if(!f){a=c+1;continue}let m=c+f[0].length,y=null;for(;m<n;m++){const L=e[m];if(y)L===y&&(y=null);else if(L==='"'||L==="'")y=L;else if(L===">")break}if(m>=n)break;r(c);const g=f[2].toLowerCase(),v=m+1;if(f[1]){let L=s;for(;L!==t&&L.tag!==g;)L=L.parent;if(L!==t){for(let N=s;N!==L;N=N.parent)l(N,c,c);l(L,c,v),s=L.parent}a=i=v;continue}if(!o){Qr.has(g)&&s.tag==="p"&&(l(s,c,c),s=s.parent);const L=Jr[g];L&&L.includes(s.tag)&&(l(s,c,c),s=s.parent)}const A={tag:g,a:c,openEnd:v,kids:[],parent:s,attrs:[],innerA:v,innerB:n,b:n},_=/([^\s"'<>\/=]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g,b=e.slice(c+f[0].length,m);for(let L;L=_.exec(b);){const N=c+f[0].length+L.index,q=L[2]??L[3]??L[4],ve=L[2]!=null?'"':L[3]!=null?"'":"",Ae=q==null?-1:N+L[0].length-q.length-(ve?1:0);A.attrs.push({name:L[1].toLowerCase(),a:N,b:N+L[0].length,va:Ae,vb:Ae<0?-1:Ae+q.length,q:ve,value:q})}s.kids.push(A);const M=e[m-1]==="/";if(Zr.has(g)||M&&o){A.innerB=v,A.b=v,a=i=v;continue}if(Gr.has(g)&&!o){const L=new RegExp(`</${g}\\s*>`,"i"),N=e.slice(v),q=L.exec(N),ve=q?v+q.index:n,Ae=q?ve+q[0].length:n;ve>v&&A.kids.push({text:!0,a:v,b:ve}),A.innerB=ve,A.b=Ae,a=i=Ae;continue}(g==="svg"||g==="math")&&o++,s=A,a=i=v}return r(n),t}const tl=e=>e.kids.filter(t=>t.tag),ls=e=>[...e.childNodes].map(t=>t.nodeType===3?"t":t.nodeType===1?t.tagName.toLowerCase():"c").join(","),nl=e=>e.kids.map(t=>t.text?"t":t.tag?t.tag:"c").join(","),sl=e=>e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");async function kn(e,t){const n=d.frames.find(s=>s.id===e);if(!n||n.kind!=="folder"||K||!$())return null;try{const s=t.ownerDocument,a=[];for(let m=t;m&&m!==s.body;m=m.parentElement){if(!m.parentElement)return null;a.unshift(m)}const{text:i}=await x("GET",`/__loop/api/frames/${e}/source`),o=new DOMParser().parseFromString(i,"text/html"),r=m=>{if(m.tag==="body")return m;for(const y of m.kids)if(y.tag){const g=r(y);if(g)return g}return null};let l=o.body,c=r(el(i)),u=s.body;if(!l||!c)return null;const f=m=>`${m.tagName}#${m.id||""}.${typeof m.className=="string"?m.className.trim().split(/\s+/).filter(y=>!/^(on|active|is-|selected|open)/.test(y)).sort().join("."):""}`;for(const m of a){const y=tl(c);if(y.length!==l.children.length)return null;const g=[...u.children],v=[...l.children];let A=0,_=-1;for(const b of g){let M=A;for(;M<v.length&&f(v[M])!==f(b)&&v[M].tagName!==b.tagName;)M++;if(M<v.length&&(f(v[M])===f(b)||v[M].tagName===b.tagName&&!g.slice(g.indexOf(b)+1).some(L=>f(L)===f(v[M]))))b===m&&(_=M),A=M+1;else if(b===m)return null}if(_<0||(l=v[_],c=y[_],u=m,!l||!c||l.tagName.toLowerCase()!==c.tag))return null}return l.tagName!==t.tagName?null:{src:i,P:l,N:c}}catch{return null}}/[?&]debug\b/.test(location.search)&&(window.__loop={locate:(...e)=>kn(...e),stage:e=>en(e),fit:e=>je(!0,[e])});let Oe=null;const pa=new Map;function al(e){const t=e instanceof(e.ownerDocument.defaultView.SVGElement||SVGElement),n=(t?"svg:":"")+e.tagName.toLowerCase();if(pa.has(n))return pa.get(n);if(!Oe){const o=document.createElement("iframe");o.style.cssText="position:fixed;left:-9999px;width:10px;height:10px;visibility:hidden",document.body.appendChild(o),Oe=o.contentDocument,Oe.open(),Oe.write("<!doctype html><html><body></body></html>"),Oe.close()}const s=t?Oe.createElementNS("http://www.w3.org/2000/svg",e.tagName):Oe.createElement(e.tagName);(t?Oe.body.querySelector("svg")||Oe.body.appendChild(Oe.createElementNS("http://www.w3.org/2000/svg","svg")):Oe.body).appendChild(s);const a=Oe.defaultView.getComputedStyle(s),i={};for(const o of a)i[o]=a.getPropertyValue(o);return s.remove(),pa.set(n,i),i}function il(e){let t="",n="";for(const s of e.querySelectorAll('link[rel~="stylesheet"]'))/fonts\.(googleapis|gstatic)\.com|typekit|fonts\.bunny/.test(s.href)&&(t+=`<link rel="stylesheet" href="${s.href}">`);for(const s of e.styleSheets){let a;try{a=s.cssRules}catch{continue}const i=s.href||e.baseURI;for(const o of a)o.constructor.name==="CSSFontFaceRule"?n+=o.cssText.replace(/url\((['"]?)([^'")]+)\1\)/g,(r,l,c)=>/^(data:|https?:)/.test(c)?r:`url("${new URL(c,i).href}")`):o.constructor.name==="CSSImportRule"&&/fonts/.test(o.href)&&(t+=`<link rel="stylesheet" href="${new URL(o.href,i).href}">`)}return t+(n?`<style>${n}</style>`:"")}function to(e,t){const n=t.ownerDocument,s=n.defaultView,a=t.cloneNode(!0),i=[t,...t.querySelectorAll("*")],o=[a,...a.querySelectorAll("*")];i.forEach((l,c)=>{const u=o[c];if(!u||u.nodeType!==1)return;if(/^(SCRIPT|NOSCRIPT|TEMPLATE)$/.test(l.tagName)){u.remove();return}const f=s.getComputedStyle(l),m=al(l);let y="";for(const g of f){const v=f.getPropertyValue(g);v!==m[g]&&!/^(transition|animation)/.test(g)&&(y+=`${g}:${v};`)}u.setAttribute("style",y),u.removeAttribute("contenteditable");for(const g of["src","href","poster"])u.hasAttribute(g)&&l[g]&&typeof l[g]=="string"&&u.setAttribute(g,l[g]);u.hasAttribute("srcset")&&u.removeAttribute("srcset")}),a.style.setProperty("margin","0"),a.style.setProperty("position","relative"),a.style.setProperty("inset","auto"),a.style.setProperty("transform","none");const r=t.getBoundingClientRect();return{html:a.outerHTML,fonts:il(n),w:Math.max(8,Math.ceil(r.width)),h:Math.max(8,Math.ceil(r.height)),name:xn(t),fid:e,x:r.left,y:r.top}}const ol=e=>`<!doctype html>
48
+ <html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${w(e.name)}</title>${e.fonts}<style>html,body{margin:0;background:transparent}</style></head>
49
+ <body>
50
+ ${e.html}
51
+ </body></html>
52
+ `;async function no(e,t,n){try{const s=await x("POST","/__loop/api/frames",{new:!0,name:Ui(e.name||"Element"),w:e.w,h:e.h,x:Math.round(t),y:Math.round(n),html:ol(e),fill:"none"});let a=null;Z("Copy element",async()=>{a=Yt(s.id)||a,await x("DELETE",`/__loop/api/frames/${s.id}`)},()=>Ue(a||{frames:[s]})),We=s.id,k(`Copied \u201C${e.name}\u201D to its own frame`,1600)}catch(s){k(s.message)}}async function so(e,t,n){const s=d.frames.find(l=>l.id===t);if(!s||s.kind!=="folder")return k("Elements can be pasted into static frames. For an app screen, ask the agent.");const a=ce(t),i=n&&n!==a?.documentElement?n:a?.body,o=i&&await kn(t,i);if(!o)return k("Couldn\u2019t find that spot in the page\u2019s file. Try selecting another element first.");const r=i===a.body?o.N.innerB??o.N.b:o.N.b;try{await cs(t,[{a:r,b:r,before:"",text:`
53
+ ${e.html}`}],`Paste \u201C${e.name}\u201D`),k(`Pasted \u201C${e.name}\u201D into ${s.name}`,1600)}catch(l){k(l.message)}}let Fe=null;async function cs(e,t,n){await x("POST",`/__loop/api/frames/${e}/edit`,{edits:t,what:n});let s=0;const a=[...t].sort((i,o)=>i.a-o.a).map(i=>{const o={a:i.a+s,b:i.a+s+i.text.length,before:i.text,text:i.before};return s+=i.text.length-(i.b-i.a),o});Z(n,()=>x("POST",`/__loop/api/frames/${e}/edit`,{edits:a,what:`Undo: ${n}`}),()=>x("POST",`/__loop/api/frames/${e}/edit`,{edits:t,what:n}))}async function ao(e,t,n,s){const a=t.getBoundingClientRect(),i=Rn(e,{...Ks(e,a.left+Math.min(a.width/2,40),a.top+Math.min(a.height/2,20)),scope:"elements",elements:[n]}),o={id:qs(),frameId:e,text:s,anchor:i,author:{name:j.name,color:j.color}},r=Gs(o);try{const l=await x("POST","/__loop/api/comments",o);l?.id&&l.id!==o.id&&r()}catch(l){r(),k(l.message)}}let ue=null;function Xt(e,t){let n=e?.nodeType===3?e.parentElement:e;return!n||n.nodeType!==1||n.namespaceURI!=="http://www.w3.org/1999/xhtml"||/^(INPUT|TEXTAREA|SELECT|SCRIPT|STYLE|HTML|BODY)$/.test(n.tagName)||n.isContentEditable||![...n.childNodes].some(s=>s.nodeType===3&&s.data.trim())||!t&&n.closest('a, button, label, summary, select, [role="button"], [role="tab"], [role="link"]')?null:n}function Ut(e,t){if(!$()||ue||K)return!1;ne(),U(),xe(),Q.hidden=!0,ee.hidden=!0,ue={fid:e,el:t,html:t.innerHTML,texts:[...t.childNodes].map(i=>i.nodeType===3?i.data:null),shape:ls(t),desc:rs(t),attr:t.getAttribute("contenteditable"),outline:[t.style.outline,t.style.outlineOffset,t.style.cursor]},t.setAttribute("contenteditable","plaintext-only"),t.contentEditable!=="plaintext-only"&&t.setAttribute("contenteditable","true"),Object.assign(t.style,{outline:"1.5px solid #2F5BFF",outlineOffset:"3px",cursor:"text"});const n=ue,s=d.frames.find(i=>i.id===e);s&&X(s);const a=()=>{if(ue===n){try{O.get(e)?.iframe.focus()}catch{}t.focus({preventScroll:!0});try{const i=t.ownerDocument.getSelection(),o=t.ownerDocument.createRange();o.selectNodeContents(t),i.removeAllRanges(),i.addRange(o)}catch{}}};return n.t0=performance.now(),a(),setTimeout(a,40),t.addEventListener("blur",n.onBlur=()=>{performance.now()-n.t0<300?setTimeout(a,0):ds(!0)}),!0}async function ds(e){const t=ue;if(!t)return;ue=null;const{fid:n,el:s}=t;s.removeEventListener("blur",t.onBlur),t.attr==null?s.removeAttribute("contenteditable"):s.setAttribute("contenteditable",t.attr),[s.style.outline,s.style.outlineOffset,s.style.cursor]=t.outline,s.getAttribute("style")||s.removeAttribute("style");try{s.ownerDocument.getSelection().removeAllRanges(),s.blur()}catch{}{const m=d.frames.find(y=>y.id===n);m&&X(m),Xe()}const a=[...s.childNodes].map(m=>m.nodeType===3?m.data:null),i=m=>(m||"").replace(/\s+/g," ").trim(),o=i(t.texts.filter(m=>m!=null).join(" ")),r=i(s.textContent);if(C?.frameId===n&&z&&(ee.hidden=!1,Zt()),!e||!r||ls(s)===t.shape&&a.every((m,y)=>i(m)===i(t.texts[y]))){s.innerHTML=t.html;return}const l=await kn(n,s);let c=null;if(l){const{src:m,P:y,N:g}=l,v=(_,b)=>/^\s*/.exec(_)[0]+sl(b.trim())+/\s*$/.exec(_)[0],A=[...y.childNodes].map(_=>_.nodeType===3?_.data:null);ls(y)===t.shape&&nl(g)===t.shape&&A.every((_,b)=>i(_)===i(t.texts[b]))&&(ls(s)===t.shape?c=a.map((_,b)=>_!=null&&i(_)!==i(t.texts[b])?{a:g.kids[b].a,b:g.kids[b].b,before:m.slice(g.kids[b].a,g.kids[b].b),text:v(m.slice(g.kids[b].a,g.kids[b].b),_)}:null).filter(Boolean):!s.children.length&&!y.children.length&&(c=[{a:g.innerA,b:g.innerB,before:m.slice(g.innerA,g.innerB),text:v(m.slice(g.innerA,g.innerB),s.textContent)}]))}if(c?.length)try{await cs(n,c,"Edited text"),k("Saved",1100);return}catch(m){k(m.message),s.innerHTML=t.html;return}(C?.frameId!==n||C.els[0]!==s)&&(C={frameId:n,els:[s],scope:s.parentElement},ma(n)),z?.el===s&&(z.text={from:z.text?.from||o,to:r},z.held=!0,Gt());const u=z,f=t.html;Z("Edited text",()=>{s.innerHTML=f,u&&(u.text=null),st(),z===u&&Gt()},()=>{})}function rl(e,t,n){const s=r=>r[Mt]&&V==="select"&&r.button===0,a=r=>{r.preventDefault(),r.stopImmediatePropagation()};for(const r of["pointerdown","mousedown","pointerup","mouseup","dblclick"])e.addEventListener(r,l=>{(s(l)&&!ue||performance.now()<0)&&a(l)},!0);e.addEventListener("click",r=>{if(performance.now()<0)return a(r);if(ue?.fid===t)return ue.el.contains(r.target)?a(r):void 0;if(!s(r))return;a(r);const[l,c]=n(r);Q.hidden=!0,os(t,{clientX:l,clientY:c,shiftKey:r.shiftKey})},!0);let o=!1;e.addEventListener("mousemove",r=>{if(r[Mt]&&V==="select"&&!ue){const[l,c]=n(r);cn(t,l,c),o=!0}else o&&(o=!1,Q.hidden=!0)},!0),e.addEventListener("keyup",r=>{o&&(r.key==="Meta"||r.key==="Control")&&(o=!1,Q.hidden=!0)},!0),e.addEventListener("mouseleave",()=>{o&&(o=!1,Q.hidden=!0)}),e.addEventListener("dblclick",r=>{if(V!=="select"||!$()||ue||!r[Mt])return;const l=Xt(r.target,!0);l&&(a(r),Ut(t,l))},!0),e.addEventListener("keydown",r=>{ue?.fid===t&&(r.stopImmediatePropagation(),r.key==="Enter"&&!r.shiftKey&&!r.isComposing?(r.preventDefault(),ds(!0)):r.key==="Escape"&&(r.preventDefault(),ds(!1)))},!0);for(const r of["keyup","keypress"])e.addEventListener(r,l=>{ue?.fid===t&&(l.stopImmediatePropagation(),l.key===" "&&r==="keyup"&&l.preventDefault())},!0)}const ll='<svg class="qi" viewBox="0 0 16 16"><path d="M2 4.5V3h7v1.5M5.5 3v10M4 13h3"/><path d="M10 8.5V8h4.5v.5M12.25 8v5M11.25 13h2"/></svg>',cl='<svg class="qi" viewBox="0 0 16 16"><path d="M3 13V8a5 5 0 0 1 5-5h5"/><path d="M3 13h.01M13 3h.01" stroke-width="2.2"/></svg>',ee=document.createElement("div");ee.id="quick",ee.hidden=!0,document.body.appendChild(ee);let z=null;const fs=e=>{const t=/rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:[,\s/]+([\d.]+))?/.exec(e||"");return!t||t[4]!=null&&+t[4]==0?"":"#"+[t[1],t[2],t[3]].map(n=>Math.round(+n).toString(16).padStart(2,"0")).join("")};function ha(){const e=C?.els.length===1?C.els[0]:null;if(!C||K){ee.hidden=!0,z=null;return}if(!e){ee.innerHTML=`<span class="q-count">${C.els.length} selected</span><span class="q-sep"></span><button class="q-btn" data-q="comment" title="Comment on these">${E("comment")}</button>`,ee.hidden=!1,z=null,Zt();return}const t=C.frameId,n=e.ownerDocument.defaultView.getComputedStyle(e);if(z?.el!==e&&(z={fid:t,el:e,sel:Nt(e),pending:{},text:null,held:!1,t:null,desc:rs(e)}),!$()){ee.innerHTML=`<button class="q-btn" data-q="comment" title="Comment on this">${E("comment")}</button>`,ee.hidden=!1,Zt();return}const s=(i,o,r)=>`<button class="q-sw${r?"":" none"}" data-pick="${i}" data-val="${r}" title="${o} colour"><i style="${r?`background:${r}`:""}"></i><span>${o}</span></button>`,a=(i,o,r,l)=>`<div class="q-num" title="${r}"><span class="q-scrub" data-scrub="${i}" title="Drag to change ${r.toLowerCase()}">${o}</span><input type="text" inputmode="numeric" data-q="${i}" value="${Math.round(parseFloat(l)||0)}"></div>`;ee.innerHTML=`${Xt(e,!0)?`<button class="q-btn" data-q="text" title="Edit the text (or double-click it)">${E("edit")}</button><span class="q-sep"></span>`:""}
54
+ ${s("color","Text",fs(n.color))}${s("background-color","Fill",fs(n.backgroundColor))}${s("border-color","Border",parseFloat(n.borderTopWidth)?fs(n.borderTopColor):"")}
55
+ <span class="q-sep"></span>${a("font-size",ll,"Text size",n.fontSize)}${a("border-radius",cl,"Corner radius",n.borderTopLeftRadius)}
56
+ <span class="q-sep"></span><button class="q-btn" data-q="comment" title="Comment on this (for the agent)">${E("comment")}</button><button class="q-btn" data-q="delete" title="Delete (\u232B)">${E("trash")}</button><span class="q-note"></span>`,ee.hidden=!1,Gt(),Zt()}function Zt(){if(ee.hidden||!C)return;const e=C.frameId,t=C.els[C.els.length-1],n=O.get(e);if(!n||!t?.isConnected)return;const s=n.iframe.getBoundingClientRect(),a=t.getBoundingClientRect(),i=h.z,o=s.left+a.left*i,r=s.top+a.top*i,l=s.top+a.bottom*i,c=ee.offsetWidth,u=ee.offsetHeight;let f=r-u-8;f<60&&(f=l+8),f+u>innerHeight-76&&(f=Math.max(60,r+8)),ee.style.left=`${Math.round(Math.max(12,Math.min(o,innerWidth-c-12)))}px`,ee.style.top=`${Math.round(f)}px`}function Gt(e){const t=ee.querySelector(".q-note");if(!t||!z)return;const n=d.frames.find(a=>a.id===z.fid)?.kind==="folder",s=Object.keys(z.pending).length+(z.text?1:0);t.innerHTML=e?`<span>${w(e)}</span>`:(z.held||!n)&&s?`<span>Only on screen</span><button class="q-send" data-q="send" title="Loop can't change this in the code by itself. Ask the agent to make it real">Send to agent</button>`:"",Zt()}function $n(e,t){if(!z)return;const{el:n}=z,s=(i,o)=>{n.style.setProperty(i,o),z.pending[i]=o};if(!z.base){const i=z,o=n.getAttribute("style");z.base=!0,setTimeout(()=>{i.base=!1},1500),(i.held||d.frames.find(r=>r.id===i.fid)?.kind!=="folder")&&Z("Edited style",()=>{o==null?i.el.removeAttribute("style"):i.el.setAttribute("style",o),i.pending={},st(),z===i&&ha()},()=>{})}e==="border-color"&&!parseFloat(n.ownerDocument.defaultView.getComputedStyle(n).borderTopWidth)&&(s("border-width","1px"),s("border-style","solid")),s(e,t),st();const a=d.frames.find(i=>i.id===z.fid)?.kind==="folder";clearTimeout(z.t),a?z.t=setTimeout(io,380):Gt()}async function io(){const e=z;if(!e||!Object.keys(e.pending).length)return;const t=e.pending;e.pending={};const n=e.el.isConnected?await kn(e.fid,e.el):null;if(!n){e.pending={...t,...e.pending},e.held=!0,z===e&&Gt();return}const{src:s,N:a}=n,i=a.attrs.find(c=>c.name==="style"),o=new Map;for(const c of(i?.value||"").split(";")){const u=c.indexOf(":");u>0&&o.set(c.slice(0,u).trim().toLowerCase(),c.slice(u+1).trim())}for(const[c,u]of Object.entries(t))o.set(c,u);const r=[...o].map(([c,u])=>`${c}: ${u}`).join("; ").replace(/"/g,"'");let l;if(i&&i.va>=0&&i.q)l={a:i.va,b:i.vb,before:s.slice(i.va,i.vb),text:i.q==='"'?r:r.replace(/'/g,'"')};else if(i)l={a:i.a,b:i.b,before:s.slice(i.a,i.b),text:`style="${r}"`};else{const c=s[a.openEnd-2]==="/"?a.openEnd-2:a.openEnd-1;l={a:c,b:c,before:"",text:` style="${r}"`}}try{await cs(e.fid,[l],"Edited style"),z===e&&Gt("Saved")}catch(c){k(c.message)}}async function dl(e){const t=Object.entries(e.pending).map(([s,a])=>`${s}: ${a}`).join("; "),n=[e.text&&`Change this text from "${e.text.from.slice(0,300)}" to "${e.text.to.slice(0,600)}".`,t&&`Set these on this element: ${t}.`].filter(Boolean);n.length&&(e.pending={},e.text=null,e.held=!1,Ne(),await ao(e.fid,e.el,e.desc,`${n.join(" ")} Make it in the source and change nothing else.`))}ee.addEventListener("pointerdown",e=>e.stopPropagation()),ee.addEventListener("input",e=>{const t=e.target.closest("[data-q]");if(!(!t||!z)&&t.type==="color"){const n=t.closest(".q-sw");n.classList.remove("none"),n.querySelector("i").style.background=t.value,$n(t.dataset.q,t.value)}}),ee.addEventListener("change",e=>{const t=e.target.closest("input[data-q]");t&&t.value.trim()!==""&&!isNaN(+t.value)&&$n(t.dataset.q,`${Math.max(0,Math.min(400,Math.round(+t.value)))}px`)}),ee.addEventListener("keydown",e=>{if(e.stopPropagation(),(e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==="z"){e.preventDefault(),e.target.blur?.(),e.shiftKey?bn():as();return}if(e.key==="Escape")return e.target.blur?.(),Ne();if(e.key==="Enter")return e.target.blur?.();const t=e.target.closest("input[data-q]");t&&(e.key==="ArrowUp"||e.key==="ArrowDown")&&(e.preventDefault(),t.value=Math.max(0,Math.min(400,(parseInt(t.value)||0)+(e.key==="ArrowUp"?1:-1)*(e.shiftKey?10:1))),$n(t.dataset.q,`${t.value}px`))}),ee.addEventListener("pointerdown",e=>{const t=e.target.closest("[data-scrub]");if(!t||!z)return;e.preventDefault();const n=t.parentElement.querySelector("input"),s=parseInt(n.value)||0,a=e.clientX;t.setPointerCapture(e.pointerId),document.body.classList.add("scrubbing");const i=r=>{const l=Math.max(0,Math.min(400,Math.round(s+(r.clientX-a)/2*(r.shiftKey?10:1))));String(l)!==n.value&&(n.value=l,$n(t.dataset.scrub,`${l}px`))},o=()=>{t.removeEventListener("pointermove",i),document.body.classList.remove("scrubbing")};t.addEventListener("pointermove",i),t.addEventListener("pointerup",o,{once:!0}),t.addEventListener("pointercancel",o,{once:!0})}),ee.addEventListener("click",e=>{const t=e.target.closest("[data-pick]");if(t&&z)return us(t);const n=e.target.closest("button[data-q]");if(!n)return;if(n.dataset.q==="comment")return eo();if(n.dataset.q==="delete")return lo();const s=e.target.closest("[data-pick]");if(s&&z)return us(s);if(z)if(n.dataset.q==="text"){const{fid:a,el:i}=z;Ut(a,i)}else n.dataset.q==="send"&&dl(z)});const me=document.createElement("div");me.id="cpick",me.hidden=!0,document.body.appendChild(me);let G=null;const fl=(e,t,n)=>{const s=a=>{const i=(a+e/60)%6;return n-n*t*Math.max(0,Math.min(i,4-i,1))};return[s(5),s(3),s(1)].map(a=>Math.round(a*255))},ul=e=>"#"+e.map(t=>t.toString(16).padStart(2,"0")).join("");function ga(e){const t=/^#?([0-9a-f]{6})$/i.exec(e||"");if(!t)return{h:0,s:0,v:1};const n=parseInt(t[1],16),s=(n>>16&255)/255,a=(n>>8&255)/255,i=(n&255)/255,o=Math.max(s,a,i),r=o-Math.min(s,a,i);return{h:r?o===s?((a-i)/r+6)%6*60:o===a?((i-s)/r+2)*60:((s-a)/r+4)*60:0,s:o?r/o:0,v:o}}function ml(e){const t=new Map;for(const n of[...e.body.querySelectorAll("*")].slice(0,1500)){const s=e.defaultView.getComputedStyle(n);for(const a of[s.color,s.backgroundColor,s.borderTopWidth!=="0px"?s.borderTopColor:""]){const i=fs(a);i&&t.set(i,(t.get(i)||0)+1)}}return[...t].sort((n,s)=>s[1]-n[1]).slice(0,14).map(n=>n[0])}function us(e){if(G?.btn===e)return Et();Et();const t=e.dataset.val||"#ffffff";G={prop:e.dataset.pick,btn:e,...ga(t)};const n=(()=>{try{return ml(z.el.ownerDocument)}catch{return[]}})();me.innerHTML=`<div class="cp-sv"><i></i></div><div class="cp-hue"><i></i></div>
57
+ <div class="cp-row"><span class="cp-now"></span><input class="cp-hex" spellcheck="false" maxlength="7">${e.dataset.pick==="frame-fill"?'<button class="cp-none" title="No fill: the frame shows the canvas behind it">No fill</button>':""}</div>
58
+ ${n.length?`<div class="cp-label">On this page</div><div class="cp-used">${n.map(r=>`<button data-c="${r}" style="background:${r}" title="${r}"></button>`).join("")}</div>`:""}`,me.hidden=!1,ms(!0);const s=e.getBoundingClientRect(),a=me.offsetWidth,i=me.offsetHeight;let o=s.bottom+8;o+i>innerHeight-12&&(o=s.top-i-8),me.style.left=`${Math.round(Math.max(12,Math.min(s.left-8,innerWidth-a-12)))}px`,me.style.top=`${Math.round(Math.max(12,o))}px`,e.classList.add("on")}function Et(){G&&(G.prop==="frame-fill"&&ro(),G.btn?.classList.remove("on"),G=null,me.hidden=!0)}let gt=null;function oo(e){const t=d.frames.find(n=>n.id===P);t&&((!gt||gt.id!==t.id)&&(gt={id:t.id,before:t.fill||null}),t.fill=e,X(t),clearTimeout(gt.t),gt.t=setTimeout(()=>x("PATCH",`/__loop/api/frames/${t.id}`,{fill:e}).catch(n=>k(n.message)),250))}function ro(){const e=gt;if(gt=null,!e)return;const t=d.frames.find(a=>a.id===e.id),n=t?.fill||null;if(n===e.before)return;const s=a=>{const i=d.frames.find(o=>o.id===e.id);return i&&(i.fill=a||void 0,X(i),Se()),x("PATCH",`/__loop/api/frames/${e.id}`,{fill:a})};Z("Frame fill",()=>s(e.before),()=>s(n))}function ms(e){if(!G)return;const t=ul(fl(G.h,G.s,G.v));me.querySelector(".cp-sv").style.background=`linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, hsl(${G.h}, 100%, 50%))`,Object.assign(me.querySelector(".cp-sv i").style,{left:`${G.s*100}%`,top:`${(1-G.v)*100}%`,background:t}),Object.assign(me.querySelector(".cp-hue i").style,{left:`${G.h/360*100}%`,background:`hsl(${G.h}, 100%, 50%)`}),me.querySelector(".cp-now").style.background=t;const n=me.querySelector(".cp-hex");if(document.activeElement!==n&&(n.value=t.toUpperCase()),e)return;const s=G.btn;if(s.classList.remove("none"),s.querySelector("i").style.background=t,s.dataset.val=t,G.prop==="frame-fill"){const a=s.querySelector("span");return a&&(a.textContent=t.toUpperCase()),oo(t)}$n(G.prop,t)}me.addEventListener("pointerdown",e=>{e.stopPropagation();const t=e.target.closest(".cp-sv, .cp-hue");if(!t||!G)return;e.preventDefault(),t.setPointerCapture(e.pointerId);const n=a=>{const i=t.getBoundingClientRect(),o=Math.max(0,Math.min(1,(a.clientX-i.left)/i.width)),r=Math.max(0,Math.min(1,(a.clientY-i.top)/i.height));t.classList.contains("cp-hue")?G.h=o*360:(G.s=o,G.v=1-r),ms()};n(e);const s=()=>t.removeEventListener("pointermove",n);t.addEventListener("pointermove",n),t.addEventListener("pointerup",s,{once:!0})}),me.addEventListener("click",e=>{if(e.target.closest(".cp-none")&&G?.prop==="frame-fill"){oo("none"),Et(),Se();return}const t=e.target.closest("[data-c]");t&&G&&(Object.assign(G,ga(t.dataset.c)),ms())}),me.addEventListener("keydown",e=>{e.stopPropagation(),e.key==="Escape"&&Et(),(e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==="z"&&(e.preventDefault(),e.target.blur?.(),e.shiftKey?bn():as())}),me.addEventListener("input",e=>{if(!e.target.classList.contains("cp-hex")||!G)return;const t=e.target.value.trim(),n=/^#?([0-9a-f]{6})$/i.exec(t);n&&(Object.assign(G,ga("#"+n[1])),ms())}),addEventListener("pointerdown",e=>{G&&!e.target.closest("#cpick, [data-pick]")&&Et()},!0);async function lo(){if(!C||!$())return;const{frameId:e,els:t}=C,n=[],s=[];for(const r of t){const l=r.isConnected?await kn(e,r):null;if(l){const{src:c,N:u}=l;let f=u.a,m=u.b;const y=c.lastIndexOf(`
59
+ `,f-1)+1,g=c.indexOf(`
60
+ `,m);/^[ \t]*$/.test(c.slice(y,f))&&/^[ \t]*$/.test(c.slice(m,g<0?c.length:g))&&(f=y,m=g<0?c.length:g+1),n.push({a:f,b:m,before:c.slice(f,m),text:""})}else s.push(r)}n.sort((r,l)=>r.a-l.a||l.b-r.b);const a=n.filter((r,l)=>!n.slice(0,l).some(c=>c.a<=r.a&&c.b>=r.b)),i=t.map(rs),o=t.length===1?xn(t[0]):`${t.length} layers`;if(Ne(),s.length){const r=s.map(l=>[l,l.parentNode,l.nextSibling]);s.forEach(l=>l.remove()),Z(`Delete ${o}`,()=>r.forEach(([l,c,u])=>c?.insertBefore(l,u)),()=>{}),pl(e,s[0],i)}if(a.length)try{await cs(e,a,`Delete ${o}`)}catch(r){k(r.message)}}function pl(e,t,n){const s=document.createElement("div");s.id="del-ask",s.innerHTML="<span>This is drawn by the page's own script, so it's only hidden for now</span><button>Have the agent remove it</button>",document.querySelector("#del-ask")?.remove(),document.body.appendChild(s),s.querySelector("button").onclick=async()=>{s.remove(),await ao(e,t,n[0],`Remove ${n.length===1?"this element":`these ${n.length} elements`} from the page, in the source. Change nothing else.`)},setTimeout(()=>s.remove(),8e3)}function hl(e){if(C?.frameId!==e||!z||z.fid!==e)return;const t=ce(e);if(!t||t.location.href==="about:blank"||!t.body?.children.length)return;const n=t.querySelector(z.sel);if(!n)return ne();const s=z.pending;C.els=[n],z.el=n;for(const[a,i]of Object.entries(s))n.style.setProperty(a,i);st(),ha()}function ya(e){if(e=e.filter(t=>d.frames.find(n=>n.id===t)),e.length===1)return J(e[0]);P=null,B.clear(),e.forEach(t=>B.add(t));for(const t of d.frames)X(t);Se(),Cn()}function gl(e){const t=new Set(B.size?B:P?[P]:[]);t.has(e)?t.delete(e):t.add(e),ya([...t])}const va=e=>{const t=Math.min(...e.map(s=>s.x)),n=Math.min(...e.map(s=>s.y));return{x:t,y:n,w:Math.max(...e.map(s=>s.x+s.w))-t,h:Math.max(...e.map(s=>s.y+s.h))-n}};async function he(e){for(const[t,n]of Object.entries(e)){const s=d.frames.find(a=>a.id===t);s&&(Object.assign(s,n),X(s))}Qt(),fn(),await Promise.all(Object.entries(e).map(([t,n])=>x("PATCH",`/__loop/api/frames/${t}`,n)))}const co={KeyA:"left",KeyD:"right",KeyW:"top",KeyS:"bottom",KeyH:"hcenter",KeyV:"vcenter"};function fo(e){const t=[...B].map(o=>d.frames.find(r=>r.id===o)).filter(Boolean);if(t.length<2)return;const n=va(t),s={},a={};for(const o of t)s[o.id]={x:o.x,y:o.y};if(e==="hdist"||e==="vdist")return vl(e,t,n,s);de=null,ps();for(const o of t){const r={...s[o.id]};e==="left"?r.x=n.x:e==="right"?r.x=n.x+n.w-o.w:e==="hcenter"?r.x=Math.round(n.x+n.w/2-o.w/2):e==="top"?r.y=n.y:e==="bottom"?r.y=n.y+n.h-o.h:e==="vcenter"&&(r.y=Math.round(n.y+n.h/2-o.h/2)),a[o.id]=r}he(a);const i={left:"Align left",right:"Align right",hcenter:"Align centres",top:"Align top",bottom:"Align bottom",vcenter:"Align middles",hdist:"Distribute horizontally",vdist:"Distribute vertically"}[e];Z(i,()=>he(s),()=>he(a))}async function yl(e){const t=e.map(Yt).filter(Boolean);await Promise.all(e.map(s=>x("DELETE",`/__loop/api/frames/${s}`)));const n={frames:t.flatMap(s=>s.frames),comments:t.flatMap(s=>s.comments)};Z(`Delete ${e.length} frames`,()=>Ue(n),()=>Promise.all(e.map(s=>x("DELETE",`/__loop/api/frames/${s}`)))),B.clear(),Cn(),k(`Deleted ${e.length} frames \u2014 \u2318Z to undo`,2600)}let de=null;function vl(e,t,n,s){const a=e==="hdist"?"x":"y",i=e==="hdist"?"w":"h",o=[...t].sort((c,u)=>c[a]-u[a]);let r=((a==="x"?n.w:n.h)-o.reduce((c,u)=>c+u[i],0))/Math.max(1,o.length-1);r<40&&(r=80),de={k:a,size:i,ids:o.map(c=>c.id),start:o[0][a],before:s,after:null,gap:Math.round(r)};const l=de;St(l.gap,!0),Z(e==="hdist"?"Distribute horizontally":"Distribute vertically",()=>he(l.before),()=>he(l.after)),ps()}function bl(e){const t=de,n={};let s=t.start;for(const a of t.ids){const i=d.frames.find(o=>o.id===a);i&&(n[a]={...t.before[a],[t.k]:Math.round(s)},s+=i[t.size]+e)}return n}function St(e,t){if(!de)return;e=Math.max(0,Math.round(e)),de.gap=e;const n=bl(e);if(t)de.after=n,he(n);else{for(const[o,r]of Object.entries(n)){const l=d.frames.find(c=>c.id===o);l&&(Object.assign(l,r),X(l))}Qt(),fn()}const s=p("#align-bar"),a=s.querySelector(".ab-range"),i=s.querySelector(".ab-val");a&&(a.max=Math.max(800,e*2),a.value=e),i&&document.activeElement!==i&&(i.value=e)}function ps(){const e=p("#align-bar").querySelector(".ab-spacing");if(!e||(e.hidden=!de,!de))return;e.querySelector(".ab-scrub").innerHTML=de.k==="x"?'<svg viewBox="0 0 24 24"><path d="M3 12h18M7 8l-4 4 4 4M17 8l4 4-4 4"/></svg>':'<svg viewBox="0 0 24 24"><path d="M12 3v18M8 7l4-4 4 4M8 17l4 4 4-4"/></svg>';const t=e.querySelector(".ab-range"),n=e.querySelector(".ab-val");t.max=Math.max(800,de.gap*2),t.value=de.gap,document.activeElement!==n&&(n.value=de.gap),Qt()}const wl={left:'<path d="M4 3v18"/><rect x="7" y="6" width="11" height="4" rx="1"/><rect x="7" y="14" width="7" height="4" rx="1"/>',hcenter:'<path d="M12 3v18"/><rect x="5" y="6" width="14" height="4" rx="1"/><rect x="8" y="14" width="8" height="4" rx="1"/>',right:'<path d="M20 3v18"/><rect x="6" y="6" width="11" height="4" rx="1"/><rect x="10" y="14" width="7" height="4" rx="1"/>',top:'<path d="M3 4h18"/><rect x="6" y="7" width="4" height="11" rx="1"/><rect x="14" y="7" width="4" height="7" rx="1"/>',vcenter:'<path d="M3 12h18"/><rect x="6" y="5" width="4" height="14" rx="1"/><rect x="14" y="8" width="4" height="8" rx="1"/>',bottom:'<path d="M3 20h18"/><rect x="6" y="6" width="4" height="11" rx="1"/><rect x="14" y="10" width="4" height="7" rx="1"/>',hdist:'<path d="M4 4v16M20 4v16"/><rect x="9" y="7" width="6" height="10" rx="1"/>',vdist:'<path d="M4 4h16M4 20h16"/><rect x="7" y="9" width="10" height="6" rx="1"/>'},xl={left:"Align left (\u2325A)",hcenter:"Align horizontal centres (\u2325H)",right:"Align right (\u2325D)",top:"Align top (\u2325W)",vcenter:"Align vertical centres (\u2325V)",bottom:"Align bottom (\u2325S)",hdist:"Distribute horizontally",vdist:"Distribute vertically"};function Cn(){const e=p("#align-bar");if(!d||B.size<2||!$()||K){e.hidden=!0;return}if(!e.dataset.ready){e.innerHTML='<span class="ab-count"></span><span class="ab-sep"></span>'+["left","hcenter","right","|","top","vcenter","bottom","|","hdist","vdist"].map(a=>a==="|"?'<span class="ab-sep"></span>':`<button data-align="${a}" title="${xl[a]}"><svg viewBox="0 0 24 24">${wl[a]}</svg></button>`).join("")+'<span class="ab-spacing" hidden><span class="ab-sep"></span><span class="ab-scrub" title="Drag left or right to change the spacing"></span><input class="ab-range" type="range" min="0" max="800" step="1" title="Drag to spread them out or pull them closer"><label class="ab-num" title="Space between frames"><input class="ab-val" inputmode="numeric"><small>px</small></label></span>';const t=e.querySelector(".ab-range"),n=e.querySelector(".ab-val"),s=e.querySelector(".ab-scrub");t.addEventListener("input",()=>St(+t.value,!1)),t.addEventListener("change",()=>St(+t.value,!0)),n.addEventListener("keydown",a=>{a.stopPropagation(),a.key==="Enter"&&(St(+n.value||0,!0),n.blur()),a.key==="Escape"&&n.blur()}),n.addEventListener("change",()=>St(+n.value||0,!0)),s.addEventListener("pointerdown",a=>{if(!de)return;a.preventDefault(),s.setPointerCapture(a.pointerId);const i=a.clientX,o=de.gap,r=c=>St(o+(c.clientX-i)*2,!1),l=()=>{s.removeEventListener("pointermove",r),s.removeEventListener("pointerup",l),St(de.gap,!0)};s.addEventListener("pointermove",r),s.addEventListener("pointerup",l)}),e.addEventListener("pointerdown",a=>a.stopPropagation()),e.addEventListener("click",a=>{const i=a.target.closest("[data-align]");i&&fo(i.dataset.align)}),e.dataset.ready="1"}e.querySelector(".ab-count").textContent=`${B.size} frames`,e.querySelectorAll('[data-align$="dist"]').forEach(t=>t.disabled=B.size<2),de&&(de.ids.length!==B.size||de.ids.some(t=>!B.has(t)))&&(de=null),ps(),e.hidden=!1,Qt()}function Qt(){const e=p("#align-bar");if(e.hidden||B.size<2||!d)return;const t=[...B].map(o=>d.frames.find(r=>r.id===o)).filter(Boolean).map(ze);if(!t.length)return;const n=va(t),s=h.x+(n.x+n.w/2)*h.z,a=h.y+n.y*h.z-34,i=e.offsetWidth||360;e.style.left=`${Math.max(12,Math.min(s-i/2,innerWidth-i-12))}px`,e.style.top=`${Math.max(60,a-46)}px`}const uo=6,hs=e=>[e.x,e.x+e.w/2,e.x+e.w],gs=e=>[e.y,e.y+e.h/2,e.y+e.h];function mo(e){const t=e instanceof Set?e:new Set([e]);return d.frames.filter(n=>!t.has(n.id)).map(n=>ze(n))}function Jt(e,t,n){let s=null;for(const a of e)for(const i of t){const o=i-a;Math.abs(o)<=n&&(!s||Math.abs(o)<Math.abs(s.d))&&(s={d:o,at:i})}return s}function po(e,t,n,s){const a=[],i=[e,...t],o=.5/h.z;if(n){const r=i.filter(l=>hs(l).some(c=>Math.abs(c-n.at)<o));a.push({x1:n.at,y1:Math.min(...r.map(l=>l.y)),x2:n.at,y2:Math.max(...r.map(l=>l.y+l.h))})}if(s){const r=i.filter(l=>gs(l).some(c=>Math.abs(c-s.at)<o));a.push({x1:Math.min(...r.map(l=>l.x)),y1:s.at,x2:Math.max(...r.map(l=>l.x+l.w)),y2:s.at})}return a}function ba(e,t){const n=mo(t),s=uo/h.z,a=Jt(hs(e),n.flatMap(hs),s),i=Jt(gs(e),n.flatMap(gs),s),o={...e,x:e.x+(a?.d||0),y:e.y+(i?.d||0)};return{dx:a?.d||0,dy:i?.d||0,guides:po(o,n,a,i)}}function kl(e,t,n="se"){const s=mo(t),a=uo/h.z,i=s.flatMap(hs),o=s.flatMap(gs),r={...e};let l=null,c=null;return n.includes("e")?(l=Jt([e.x+e.w],i,a),l&&(r.w=e.w+l.d)):n.includes("w")&&(l=Jt([e.x],i,a),l&&(r.x=e.x+l.d,r.w=e.w-l.d)),n.includes("s")?(c=Jt([e.y+e.h],o,a),c&&(r.h=e.h+c.d)):n.includes("n")&&(c=Jt([e.y],o,a),c&&(r.y=e.y+c.d,r.h=e.h-c.d)),{rect:r,guides:po(r,s,l,c)}}function at(e){const t=p("#guides");t.innerHTML=e.map(n=>`<line x1="${n.x1}" y1="${n.y1}" x2="${n.x2}" y2="${n.y2}"/>`).join("")}const ys=E("freeze");function $l(e){const t=O.get(e),n=ce(e);if(!t||t.parked||!n?.documentElement||n.location.href==="about:blank")throw new Error("Bring the frame into view first, so it is loaded");const s=t.iframe.contentWindow,a=b=>{try{const M=new URL(b,n.baseURI);return M.origin===location.origin?M.pathname+M.search+M.hash:M.href}catch{return b}},i=(b,M)=>b.replace(/url\(\s*(['"]?)([^'")]+)\1\s*\)/g,(L,N,q)=>/^(data:|blob:|#)/.test(q)?L:`url("${a(new URL(q,M).href)}")`);let o="";const r=(b,M=0)=>{let L;try{L=b.cssRules}catch{b.href&&(o+=`@import url("${a(b.href)}");
61
+ `);return}if(b.disabled||!L)return;const N=b.media?.mediaText;N&&M===0&&b.ownerNode?.tagName==="LINK"&&(o+=`@media ${N} {
62
+ `);for(const q of L)q.type===CSSRule.IMPORT_RULE&&q.styleSheet&&M<4?r(q.styleSheet,M+1):o+=i(q.cssText,b.href||n.baseURI)+`
63
+ `;N&&M===0&&b.ownerNode?.tagName==="LINK"&&(o+=`}
64
+ `)};for(const b of[...n.styleSheets,...n.adoptedStyleSheets||[]])r(b);const l=n.documentElement.cloneNode(!0),c=n.querySelectorAll("input, textarea, select"),u=l.querySelectorAll("input, textarea, select");c.forEach((b,M)=>{const L=u[M];L&&(b.tagName==="TEXTAREA"?L.textContent=b.value:b.tagName==="SELECT"?[...b.options].forEach((N,q)=>L.options[q]?.toggleAttribute("selected",N.selected)):/^(checkbox|radio)$/.test(b.type)?L.toggleAttribute("checked",b.checked):/^(password|file)$/.test(b.type)||L.setAttribute("value",b.value))});const f=n.querySelectorAll("canvas"),m=l.querySelectorAll("canvas");f.forEach((b,M)=>{const L=n.createElement("img");for(const q of m[M].attributes)L.setAttribute(q.name,q.value);try{L.src=b.toDataURL("image/png")}catch{}const N=b.getBoundingClientRect();b.getAttribute("style")||L.setAttribute("style",`width:${N.width}px;height:${N.height}px`),m[M].replaceWith(L)});const y=n.documentElement.querySelectorAll("*"),g=l.querySelectorAll("*");y.length===g.length&&y.forEach((b,M)=>{(b.scrollTop||b.scrollLeft)&&g[M].setAttribute("data-loop-scroll",`${b.scrollLeft},${b.scrollTop}`)}),l.querySelectorAll('script, noscript, base, link[rel="stylesheet"], link[rel="preload"], link[rel="modulepreload"], link[rel="prefetch"], style').forEach(b=>b.remove()),l.querySelectorAll("*").forEach(b=>{for(const M of[...b.attributes])(/^on/i.test(M.name)||/^(href|src|action)$/i.test(M.name)&&/^\s*javascript:/i.test(M.value))&&b.removeAttribute(M.name)});let v=l.querySelector("head");v||(v=n.createElement("head"),l.prepend(v));const A=s.location.pathname+s.location.search,_=`scrollTo(${Math.round(s.scrollX)},${Math.round(s.scrollY)});document.querySelectorAll('[data-loop-scroll]').forEach(e=>{const[x,y]=e.dataset.loopScroll.split(',');e.scrollLeft=+x;e.scrollTop=+y});addEventListener('click',e=>{if(e.target.closest('a[href]'))e.preventDefault()},true);addEventListener('submit',e=>e.preventDefault(),true)`;return v.insertAdjacentHTML("afterbegin",`<meta charset="utf-8"><base href="${w(A)}"><meta name="loop-frozen" content="${Date.now()}"><style>${o.replace(/<\/style/gi,"<\\/style")}</style>`),l.querySelector("body")?.insertAdjacentHTML("beforeend",`<script>addEventListener('load',()=>{${_}})<\/script>`),`<!doctype html>
65
+ `+l.outerHTML}async function vs(e){const t=d.frames.find(s=>s.id===e);if(!t)return;if(t.kind==="frozen")return k("This frame is already frozen");let n;try{n=$l(e)}catch(s){return k(s.message)}try{const s=await x("POST",`/__loop/api/frames/${e}/freeze`,{html:n,from:Hn(O.get(e))});let a=null;if(Z("Freeze frame",async()=>{a=Yt(s.id)||a,await x("DELETE",`/__loop/api/frames/${s.id}`)},()=>Ue(a||{frames:[s]})),S)return k("Frozen copy added next to this frame");d.frames.find(i=>i.id===s.id)?(J(s.id),pt(s.id)):We=s.id,k("Frozen: this copy keeps the screen as it is now")}catch(s){k(s.message)}}async function ho(e){const t=d.frames.find(n=>n.id===e);if(t?.from)try{const n=await x("POST","/__loop/api/frames",{route:t.from,name:t.name.replace(/ · frozen( \d+)?$/,""),w:t.w,h:t.h,near:t.id,dup:!0});d.frames.find(s=>s.id===n.id)?(J(n.id),pt(n.id)):We=n.id}catch(n){k(n.message)}}const yt=e=>Math.min(e.w,e.h)<=500&&Math.max(e.w,e.h)<=1e3,wa=["qwertyuiop","asdfghjkl","zxcvbnm"];function go(e,t){const n=e.autoKb,s=yt(t)&&(!!t.keyboard||!!n);if(e.el.classList.toggle("kb-on",s),!s)return;const a=t.w>t.h,i=n==="num"?"num":"abc";let o=e.el.querySelector(".kb");if(o||(o=document.createElement("div"),o.className="kb",e.el.querySelector(".frame-body").appendChild(o)),o.dataset.kind!==i){o.dataset.kind=i;const r=l=>[...l].map(c=>`<span class="k">${c}</span>`).join("");o.innerHTML=i==="num"?[["1",""],["2","ABC"],["3","DEF"],["4","GHI"],["5","JKL"],["6","MNO"],["7","PQRS"],["8","TUV"],["9","WXYZ"],[".",null],["0",""],["\u232B",null]].reduce((l,c,u)=>((l[Math.floor(u/3)]||=[]).push(c),l),[]).map(l=>`<div class="kb-row">${l.map(([c,u])=>`<span class="k${u==null?" fn plain":""}"><b>${c}</b>${u?`<i>${u}</i>`:""}</span>`).join("")}</div>`).join(""):`<div class="kb-bar"><span>I</span><span>The</span><span>I\u2019m</span></div>
66
+ <div class="kb-row">${r(wa[0])}</div><div class="kb-row r2">${r(wa[1])}</div>
67
+ <div class="kb-row"><span class="k fn">\u21E7</span>${r(wa[2])}<span class="k fn">\u232B</span></div>
68
+ <div class="kb-row"><span class="k fn">123</span><span class="k fn">\u263A</span><span class="k sp">space</span><span class="k fn ret">return</span></div>`}o.classList.toggle("num",i==="num"),o.classList.toggle("land",a)}function Cl(e){if(!e||e.disabled||e.readOnly)return null;const t=e.tagName,n=(e.getAttribute?.("type")||"text").toLowerCase(),s=(e.getAttribute?.("inputmode")||"").toLowerCase();return s==="none"?null:t==="TEXTAREA"||e.isContentEditable?"abc":t!=="INPUT"||/^(checkbox|radio|range|button|submit|reset|file|color|date|time|datetime-local|month|week|image|hidden)$/.test(n)?null:/^(numeric|decimal|tel)$/.test(s)||/^(number|tel)$/.test(n)?"num":"abc"}function Ll(e,t,n){const s=()=>{const a=d?.frames.find(o=>o.id===n);if(!a||!yt(a))return;const i=ue?.fid===n?null:Cl(e.document.activeElement);t.autoKb!==i&&(t.autoKb=i,go(t,a),i&&setTimeout(()=>{try{e.document.activeElement?.scrollIntoView({block:"center",behavior:"smooth"})}catch{}},60),S?.fid===n&&setTimeout(()=>Ke(n),80))};e.addEventListener("focusin",s),e.addEventListener("focusout",()=>setTimeout(s,0))}async function bs(e){const t=d.frames.find(s=>s.id===e);if(!t)return;if(!yt(t))return k("The keyboard is for phone-sized frames");const n=!t.keyboard;try{await x("PATCH",`/__loop/api/frames/${e}`,{keyboard:n}),Z(n?"Show keyboard":"Hide keyboard",()=>x("PATCH",`/__loop/api/frames/${e}`,{keyboard:!n}),()=>x("PATCH",`/__loop/api/frames/${e}`,{keyboard:n}))}catch(s){k(s.message)}}let S=null;const Ln=(()=>{try{return new Set(JSON.parse(localStorage.getItem("loop.stageNoDevice")||"[]"))}catch{return new Set}})(),yo=e=>yt(e)&&!Ln.has(e.id);let vo=0;function it(e,t=420){const n={...h},s=performance.now(),a=++vo,i=o=>{if(a!==vo)return;const r=Math.min(1,(o-s)/t),l=r<.5?4*r*r*r:1-Math.pow(-2*r+2,3)/2;h={x:n.x+(e.x-n.x)*l,y:n.y+(e.y-n.y)*l,z:n.z+(e.z-n.z)*l},te(),r<1&&requestAnimationFrame(i)};requestAnimationFrame(i)}function ws(e){const t=yo(e),n=t?22:0,s=O.get(e.id)?.el.querySelector(":scope > .opt-strip"),a=84+(s?s.offsetHeight+44:0),i=96,r=Math.max(.04,Math.min((innerWidth-40*2)/(e.w+n*2),(innerHeight-a-i)/(e.h+n*2),2)),l=S.zoom==="100"?1:r;return{z:l,x:innerWidth/2-(e.x+e.w/2)*l,y:a+(innerHeight-a-i)/2-(e.y+e.h/2)*l}}function en(e){const t=d.frames.find(n=>n.id===e);t&&(S||(S={prev:{...h},zoom:"fit"}),document.querySelectorAll(".frame.staged").forEach(n=>n.classList.remove("staged","device")),S.fid=e,J(null),U(),ne(),wi(),Be(),xe(),Ne(),Et(),Q.hidden=!0,ue&&ds(!1),Sn?.(),document.body.classList.add("staging"),xs(),it(ws(t)),Ee&&ra(e))}function Tt(){if(!S)return;const e=S.prev;if(document.querySelectorAll(".frame.staged").forEach(t=>t.classList.remove("staged","device","landscape")),document.body.classList.remove("staging"),p("#stage-bar")?.remove(),S=null,xa(),re){re=null,Xe();for(const t of d.frames)X(t)}it(e,380)}function bo(e){return!!e&&yt(e)&&(S?S.fid===e.id:Ee)}function xa(){for(const[e,t]of O)try{t.iframe.contentDocument?.documentElement.classList.toggle("loop-touch",bo(d.frames.find(n=>n.id===e)))}catch{}}function ka(){return[...d.frames].sort((e,t)=>Math.abs(e.y-t.y)<200?e.x-t.x:e.y-t.y)}function xs(){const e=d.frames.find(r=>r.id===S.fid);if(!e)return Tt();const t=O.get(e.id),n=yt(e),s=yo(e);t?.el.classList.add("staged"),t?.el.classList.toggle("device",s),t?.el.classList.toggle("landscape",e.w>e.h),xa();let a=p("#stage-bar");a||(a=document.createElement("div"),a.id="stage-bar",document.body.appendChild(a),a.addEventListener("pointerdown",r=>r.stopPropagation()),a.addEventListener("click",El));const i=ka(),o=i.findIndex(r=>r.id===e.id);a.innerHTML=`
69
+ ${n?`<button class="sb-btn${s?" on":""}" data-sb="device" title="Show it inside an iPhone">${E("phone")}</button>`:""}
70
+ ${e.kind!=="frozen"&&$()?`<button class="sb-btn" data-sb="freeze" title="Freeze a copy of it as it is now (\u21E7F)">${ys}</button>`:""}
71
+ <button class="sb-exit" data-sb="exit" title="Exit stage (Esc)">${E("x")}<span>Exit</span></button>`}function Ml(e){if(!S)return;const t=ka(),n=t.findIndex(s=>s.id===S.fid);t.length>1&&en(t[(n+e+t.length)%t.length].id)}function El(e){const t=e.target.closest("[data-sb]");if(!t||!S)return;const n=d.frames.find(o=>o.id===S.fid);if(!n)return;const s=t.dataset.sb,a=ka(),i=a.findIndex(o=>o.id===n.id);if(s==="exit")return Tt();if(s==="prev"||s==="next"){const o=a[(i+(s==="next"?1:-1)+a.length)%a.length];return en(o.id)}if(s==="device"){Ln.has(n.id)?Ln.delete(n.id):Ln.add(n.id);try{localStorage.setItem("loop.stageNoDevice",JSON.stringify([...Ln]))}catch{}return xs(),it(ws(n),300)}if(s==="keyboard")return bs(n.id);if(s==="freeze")return vs(n.id);if(s==="zoom")return S.zoom=S.zoom==="fit"?"100":"fit",xs(),it(ws(n),320)}addEventListener("keydown",e=>{!S||gn()||e.metaKey||e.ctrlKey||(e.key==="ArrowRight"||e.key==="ArrowLeft")&&(e.preventDefault(),Ml(e.key==="ArrowRight"?1:-1))}),addEventListener("resize",()=>{if(S){const e=d.frames.find(t=>t.id===S.fid);e&&(h=ws(e),te())}});const ge=document.createElement("div");ge.id="edge",ge.hidden=!0,document.body.appendChild(ge),ge.innerHTML=`<button class="eg-btn" data-eg="stage">${E("stage")}<span></span></button>`;let vt=null,At=null,ks=!1,$a=0;const Te={x:-1,y:-1},tn=52;function bt(e){const t=ze(e),n=h.z;return{l:h.x+t.x*n,t:h.y+t.y*n,w:t.w*n,h:t.h*n}}function Sl(){if(!d)return null;if(S)return S.fid;if(ie||document.body.classList.contains("versions-on"))return null;for(let e=d.frames.length-1;e>=0;e--){const t=bt(d.frames[e]),n=Math.max(t.t,tn);if(Te.x>=t.l-6&&Te.x<=t.l+t.w+6&&Te.y>=Math.max(t.t-44,0)&&Te.y<=Math.min(n+110,t.t+t.h))return d.frames[e].id}return!B.size&&P||re||null}function $s(){const e=Sl();e?(clearTimeout(At),At=null,vt=e):vt&&!At&&!ks&&(At=setTimeout(()=>{At=null,ks||(vt=null,Mn())},380)),Mn()}function Mn(){const e=vt&&d?.frames.find(u=>u.id===vt),t=!1,n=e&&bt(e);if(!e||S||n.w<72||n.t+n.h<tn+30||n.t>innerHeight-40||n.l>innerWidth-40||n.l+n.w<40){ge.hidden=!0;return}ge.hidden=!1,ge.classList.toggle("exit",t),ge.classList.toggle("compact",!t&&n.w<200);const s=ge.querySelector('[data-eg="stage"]');be(s.lastChild,t?"Exit stage":"Stage"),s.dataset.tip="Stage: focus on this frame";const a=ge.offsetWidth,i=ge.offsetHeight;let o=n.t-12*(parseFloat(getComputedStyle(document.documentElement).getPropertyValue("--lz"))||1)-i/2;const r=o<tn;r&&(o=Math.max(n.t+8,tn+4));const l=r?-8:parseFloat(getComputedStyle(s).paddingRight)||0;let c=Math.min(n.l+n.w-a+l,innerWidth-a-12);c=Math.max(c,n.l),ge.classList.toggle("inside",r),ge.style.left=`${Math.round(c)}px`,ge.style.top=`${Math.round(o)}px`;for(const[u,f]of O){const m=f.el.querySelector(":scope > .opt-strip, :scope > .ver-strip");if(!m)continue;const y=d.frames.find(b=>b.id===u);if(!y)continue;const g=bt(y),v=m.offsetHeight,A=g.t-34-v,_=A<tn+4?Math.min(tn+4-A,Math.max(0,g.h-20)):0;m.style.translate=_?`0 ${_/h.z}px`:""}}addEventListener("pointermove",e=>{Te.x=e.clientX,Te.y=e.clientY,ir(),$a||($a=requestAnimationFrame(()=>{$a=0,$s()}))},{capture:!0,passive:!0}),ge.addEventListener("pointerenter",()=>{ks=!0,clearTimeout(At),At=null}),ge.addEventListener("pointerleave",()=>{ks=!1,$s()}),ge.addEventListener("pointerdown",e=>e.stopPropagation()),ge.addEventListener("click",async e=>{!e.target.closest('[data-eg="stage"]')||!vt||(S?.fid===vt?Tt():en(vt))});const Cs=new Set;function wo(e,t=0){if(!Cs.has(e)){if((ie||S||D||ue)&&t<40)return setTimeout(()=>wo(e,t+1),250);setTimeout(()=>{!Cs.has(e)&&d.sections.some(n=>n.id===e)&&(Cs.add(e),xo(e))},t?0:500)}}function xo(e){const t=d.sections.find(f=>f.id===e),n=t&&d.comments.find(f=>f.id===t.optionsFor),s=n&&d.frames.find(f=>f.id===n.frameId);if(!t||!s||S||D)return;const a=Math.min(s.x,t.x),i=Math.min(s.y,t.y)-40,o=Math.max(s.x+s.w,t.x+t.w),r=Math.max(s.y+s.h,t.y+t.h),l={x:h.x+a*h.z,y:h.y+i*h.z},c={x:h.x+o*h.z,y:h.y+r*h.z};if(l.x>=0&&l.y>=50&&c.x<=innerWidth&&c.y<=innerHeight-70&&(o-a)*h.z>innerWidth*.45)return;const u=Math.min(1,(innerWidth-160)/(o-a),(innerHeight-240)/(r-i));it({z:u,x:(innerWidth-(o-a)*u)/2-a*u,y:120+(innerHeight-240-(r-i)*u)/2-i*u},520)}function _t(e){const t=h.z;return t<.33||e.w*t<300&&e.h*t<300}let Ls={fid:null,t:0},Pt=null;function Tl(e,t){const n=$e&&d.sections.find(a=>a.id===$e),s=n?La(n).map(a=>a.id):B.size?[...B]:P?[P]:[];if(!s.length&&!n)return!1;Pt||={from:Object.fromEntries(s.map(a=>{const i=d.frames.find(o=>o.id===a);return[a,{x:i.x,y:i.y}]})),sec:n&&{id:n.id,x:n.x,y:n.y}};for(const a of Object.keys(Pt.from)){const i=d.frames.find(o=>o.id===a);i&&(i.x+=e,i.y+=t,X(i))}return n&&Pt.sec&&(n.x+=e,n.y+=t,xt()),ye(),Mn(),Cn(),clearTimeout(Pt.t),Pt.t=setTimeout(()=>{const a=Pt;Pt=null;const i=Object.fromEntries(Object.keys(a.from).map(u=>{const f=d.frames.find(m=>m.id===u);return[u,{x:f.x,y:f.y}]})),o=a.from,r=a.sec&&d.sections.find(u=>u.id===a.sec.id),l=r&&{x:r.x,y:r.y},c=a.sec&&{x:a.sec.x,y:a.sec.y};he(i),r&&x("PATCH",`/__loop/api/sections/${r.id}`,l).catch(()=>{}),Z("Nudge",()=>Promise.all([he(o),r&&ot(r.id,c)]),()=>Promise.all([he(i),r&&ot(r.id,l)]))},400),!0}const wt=p("#sections"),En=new Map;let $e=null,Ms={id:null,t:0};const Ca=e=>({...e,...En.get(e.id)||{}}),Es=(e,t)=>{const n=t.x+t.w/2,s=t.y+t.h/2;return n>=e.x&&n<=e.x+e.w&&s>=e.y&&s<=e.y+e.h},La=e=>d.frames.filter(t=>Es(e,t));function ko(){if(!d)return;const e=h.z,t=(d.sections||[]).map(Ca);for(const n of d.frames){const s=O.get(n.id);if(!s)continue;const a=n.w*e,i=ze(n),o=t.some(r=>Es(r,i)&&(i.y-r.y)*e<24);s.el.classList.toggle("narrow",a<200),s.el.classList.toggle("noname",a<34||o)}for(const n of t){const s=wt.querySelector(`.section[data-id="${n.id}"]`);s&&(s.classList.toggle("noname",n.w*e<48),s.classList.remove("lift"))}}function xt(){const e=d.sections||[],t=new Set(e.map(n=>n.id));wt.querySelectorAll(".section").forEach(n=>{t.has(n.dataset.id)||n.remove()}),$e&&!t.has($e)&&($e=null);for(const n of e){const s=Ca(n);let a=wt.querySelector(`.section[data-id="${s.id}"]`);a||(a=document.createElement("div"),a.className="section",a.dataset.id=s.id,a.innerHTML=`<div class="sec-label"><span class="sec-name"></span></div>${["n","s","e","w","ne","nw","se","sw"].map(r=>`<div class="srz rz-${r}" data-dir="${r}"></div>`).join("")}`,wt.appendChild(a)),Object.assign(a.style,{left:`${s.x}px`,top:`${s.y}px`,width:`${s.w}px`,height:`${s.h}px`}),a.style.setProperty("--sw",`${s.w}px`);const i=a.querySelector(".sec-name");i.querySelector("input")||be(i,s.name),a.classList.toggle("selected",$e===s.id);const o=s.optionsFor&&d.comments.find(r=>r.id===s.optionsFor);a.classList.toggle("making",!!o&&(Nn(o.id)==="working"||d.frames.some(r=>r.building&&r.optionOf?.cid===o.id)))}ko()}function Ss(e){(P||B.size||re)&&J(null),$e=e,xt()}function $o(e,t){const n=d.sections.find(s=>s.id===e);ie={type:"smove",sid:e,sx:t.clientX,sy:t.clientY,x0:n.x,y0:n.y,moved:!1,from:Object.fromEntries(La(n).map(s=>[s.id,{x:s.x,y:s.y}]))},F.classList.add("dragging"),F.setPointerCapture(t.pointerId)}function Al(e,t){const n=d.sections.find(s=>s.id===e);ie={type:"sresize",sid:e,dir:t.target.dataset.dir||"se",sx:t.clientX,sy:t.clientY,x0:n.x,y0:n.y,w:n.w,h:n.h},F.classList.add("dragging"),F.setPointerCapture(t.pointerId)}function ot(e,t){const n=d.sections.find(s=>s.id===e);return n&&(Object.assign(n,t),xt()),x("PATCH",`/__loop/api/sections/${e}`,t)}async function _l(e){try{const t=await x("POST","/__loop/api/sections",e);d.sections.find(n=>n.id===t.id)||d.sections.push(t),Z("Add section",()=>x("DELETE",`/__loop/api/sections/${t.id}`),()=>Ue({sections:[t]})),Ss(t.id)}catch(t){k(t.message)}}async function Pl(e){const t=d.sections.find(s=>s.id===e);if(!t)return;const n={...t};$e=null,await x("DELETE",`/__loop/api/sections/${e}`),Z("Delete section",()=>Ue({sections:[n]}),()=>x("DELETE",`/__loop/api/sections/${e}`)),k(`Removed \u201C${n.name}\u201D (its frames stay) \xB7 \u2318Z to undo`,2600)}function ql(e){const t=wt.querySelector(`.section[data-id="${e}"] .sec-name`),n=d.sections.find(o=>o.id===e);if(!t||!n)return;const s=document.createElement("input");s.className="rename",s.value=n.name,t.replaceChildren(s),s.focus(),s.select(),s.addEventListener("pointerdown",o=>o.stopPropagation());let a=!1;const i=o=>{if(a)return;a=!0;const r=s.value.trim(),l=n.name;t.textContent=o&&r?r:l,o&&r&&r!==l&&(ot(e,{name:r}),Z("Rename section",()=>ot(e,{name:l}),()=>ot(e,{name:r})))};s.addEventListener("keydown",o=>{o.stopPropagation(),o.key==="Enter"&&i(!0),o.key==="Escape"&&i(!1)}),s.addEventListener("blur",()=>i(!0))}let T=null;const nn=e=>{const t=Ts(e);return t.length?[...t,{id:"",now:!0,label:t[t.length-1].last,at:Date.now(),thumb:null}]:[]};function Co(e,t){if(T?.fid===e&&t==null)return Be();Be();const n=O.get(e),s=d.frames.find(r=>r.id===e);if(!n||!s||!nn(e).length)return;D&&zt(),Hl(e),ne(),xe();const a=document.createElement("div");a.className="ver-strip",a.innerHTML='<div class="vt-row"></div><div class="vt-foot"><div class="vt-cap"></div><div class="vt-acts"></div></div>',n.el.appendChild(a),T={fid:e,pin:t??null,hover:null,now:null,el:a,key:"",akey:"",back:null};const i=a.querySelector(".vt-row");let o=null;a.addEventListener("pointerdown",r=>r.stopPropagation()),i.addEventListener("wheel",r=>{(Math.abs(r.deltaX)>Math.abs(r.deltaY)||r.shiftKey)&&r.stopPropagation()},{passive:!0}),a.addEventListener("pointermove",r=>{const l=r.target.closest("[data-v]"),c=l?l.dataset.v:null;if(!T||c===T.hover){clearTimeout(o),o=null;return}clearTimeout(o),o=setTimeout(()=>{o=null,T&&(T.hover=c,qt())},c==null?140:90)}),a.addEventListener("pointerleave",()=>{clearTimeout(o),o=setTimeout(()=>{T&&(T.hover=null,qt())},140)}),a.addEventListener("click",r=>{const l=r.target.closest("[data-vs]"),c=r.target.closest("[data-v]");if(l)return Dl(l.dataset.vs);c&&(T.pin=c.dataset.v===""||T.pin===c.dataset.v?null:c.dataset.v,T.hover=null,sn(),qt())}),sn(),qt(),i.scrollLeft=i.scrollWidth,zl(),x("POST",`/__loop/api/frames/${e}/versions`).then(r=>{T?.el===a&&(T.now=r.now,sn())}).catch(()=>{})}function zl(){const e=d.frames.find(o=>o.id===T.fid);if(!e)return;const t=bt(e),n=64+T.el.offsetHeight+44,s=t.l<12||t.l+Math.min(t.w,T.el.offsetWidth)>innerWidth-12;if(t.t>=n&&t.t<innerHeight-160&&!s)return;const a=h.z,i={z:a,x:s?Math.max(24,(innerWidth-e.w*a)/2)-e.x*a:h.x,y:n-e.y*a};T.back={from:{...h},to:i},it(i,320)}function Hl(e){const t=W&&d.comments.find(n=>n.id===W);t&&t.frameId!==e&&U()}function sn(){if(!T)return;const{fid:e,el:t}=T,n=d.frames.find(u=>u.id===e),s=nn(e);if(!n||!s.length)return Be();T.pin&&!s.some(u=>u.id===T.pin)&&(T.pin=null);const a=n.w/n.h,i=56,o=Math.round(Math.min(112,Math.max(34,i*a))),r=s.map((u,f)=>{const m=u.now?T.now:u.thumb;return`<button class="vt${(u.now?!T.pin:T.pin===u.id)?" on":""}" data-v="${u.id}"><span class="vt-img" style="width:${o}px;height:${i}px">${m?`<img src="${w(m)}" alt="" draggable="false">`:""}</span><span class="vt-name">${u.now?"Now":`v${f+1}`}</span></button>`}).join(""),l=t.querySelector(".vt-row");if(T.key!==r){const u=l.scrollLeft;T.key=r,l.innerHTML=r,l.scrollLeft=u}const c=`${T.pin&&$()?`<button class="vt-go" data-vs="back" title="Go back to this version (the one you are on is kept)">${E("undo")}<span>Go back</span></button><button class="vt-btn" data-vs="dup" title="Make this version its own frame">${Wt.copy}</button>`:""}<button class="vt-btn" data-vs="stack" title="See them as a stack">${Il}</button><button class="vt-btn" data-vs="close" title="Close (esc)">${Wt.x}</button>`;T.akey!==c&&(T.akey=c,t.querySelector(".vt-acts").innerHTML=c),Lo(),Mn()}const Il=E("layers");function Lo(){if(!T)return;const e=nn(T.fid),t=T.hover!=null?T.hover:T.pin,n=t?e.findIndex(o=>o.id===t):e.length-1,s=e[n];if(!s)return;const a=`<b>${s.now?"Now":`v${n+1}`}</b><span>${w(s.label||"")}</span>${s.now?"":`<time>${Lt(s.at)}</time>`}`,i=T.el.querySelector(".vt-cap");i._h!==a&&(i._h=a,i.innerHTML=a,i.title=s.label||"")}function qt(){if(!T)return;Lo();const{fid:e}=T,t=O.get(e),n=d.frames.find(m=>m.id===e);if(!t||!n)return;const s=T.hover!=null?T.hover:T.pin,a=t.el.querySelector(".frame-body");let i=a.querySelector(":scope > .ver-prev");const o=s?nn(e).find(m=>m.id===s):null;if(t.el.classList.toggle("previewing",!!o),!o){i&&(i.classList.remove("on"),setTimeout(()=>{i.classList.contains("on")||i.remove()},180));return}i||(i=document.createElement("div"),i.className="ver-prev",i.innerHTML='<img alt="" draggable="false"><iframe title=""></iframe>',a.appendChild(i),i.offsetWidth),i.classList.add("on");const r=i.querySelector("img"),l=i.querySelector("iframe"),c=`/__loop/hist/${o.id}/${encodeURIComponent(n.entry||"index.html")}`;o.thumb?(r.getAttribute("src")!==o.thumb&&(r.src=o.thumb),r.hidden=!1):r.hidden=!0;const u=T.pin===o.id,f=u||!o.thumb;i.classList.toggle("live",u),f?l.dataset.src!==c&&(l.dataset.src=c,l.classList.remove("ready"),l.onload=()=>l.classList.add("ready"),l.src=c):l.dataset.src&&(l.dataset.src="",l.classList.remove("ready"),l.src="about:blank")}function Be(e){if(!T)return;const{fid:t,el:n,back:s}=T;T=null,n.remove();const a=O.get(t);a?.el.classList.remove("previewing"),a?.el.querySelector(".frame-body > .ver-prev")?.remove(),s&&!e&&Math.abs(h.x-s.to.x)<2&&Math.abs(h.y-s.to.y)<2&&Math.abs(h.z-s.to.z)<.004&&it(s.from,300)}async function Dl(e){if(!T)return;const{fid:t,pin:n}=T,s=nn(t),a=s.findIndex(o=>o.id===n),i=d.frames.find(o=>o.id===t);if(e==="close")return Be();if(e==="stack")return Be(!0),Ol(t,n);if(!(a<0))try{if(e==="back")await x("POST",`/__loop/api/frames/${t}/versions/restore`,{id:n}),Be(),k("Back to that version. The one you were on is kept.",3200);else if(e==="dup"){const o=await x("POST",`/__loop/api/frames/${t}/versions/duplicate`,{id:n,name:`${i?.name||"Frame"} \xB7 v${a+1}`});Be(!0),d.frames.find(r=>r.id===o.id)?(J(o.id),pt(o.id)):We=o.id,k("That version is now its own frame")}}catch(o){k(o.message)}}addEventListener("keydown",e=>{if(!T||D||gn()||e.metaKey||e.ctrlKey)return;if(e.key==="Escape"){e.stopPropagation(),e.preventDefault(),T.pin?(T.pin=null,sn(),qt()):Be();return}if(e.key!=="ArrowLeft"&&e.key!=="ArrowRight")return;e.stopPropagation(),e.preventDefault();const t=nn(T.fid),n=T.pin?t.findIndex(o=>o.id===T.pin):t.length-1,s=t[Math.max(0,Math.min(t.length-1,n+(e.key==="ArrowRight"?1:-1)))];T.pin=s.now?null:s.id,T.hover=null,sn(),qt();const a=T.el.querySelector(".vt-row"),i=a.querySelector(".vt.on");i&&(a.scrollLeft=Math.max(0,Math.min(i.offsetLeft-(a.clientWidth-i.offsetWidth)/2,a.scrollWidth)))},!0);let D=null;function Ts(e){const t=d.frames.find(s=>s.id===e),n=[...d.comments.filter(s=>s.frameId===e&&s.snapshot&&!s.local&&s.status!=="working"&&s.status!=="queued").map(s=>({id:s.id,at:s.startedAt||s.createdAt,thumb:s.snapThumb,what:s.kind==="create"?"Created":s.text})),...(t?.restores||[]).map(s=>({id:s.id,at:s.at,thumb:s.thumb,what:s.what||"Went back to an earlier version"}))].sort((s,a)=>s.at-a.at);return n.map((s,a)=>({id:s.id,thumb:s.thumb,at:a?n[a-1].at:s.at,label:a?n[a-1].what:"Original",last:n[n.length-1].what}))}function Ol(e,t){const n=d.frames.find(b=>b.id===e),s=n&&Ts(e).slice(-11);if(!n||!s.length||D)return;S&&Tt(),U(),ne(),xe(),J(null),wi(),Be(!0);const a=bt(n),i=132,o=96,r=Math.min((innerWidth-200)/n.w,(innerHeight-i-o)/n.h,1.2),l=n.w*r,c=n.h*r,u=(innerWidth-l)/2,f=i+(innerHeight-i-o-c)/2,m=[...s,{id:"",now:!0,label:s[s.length-1].last,at:Date.now(),thumb:null}].reverse(),y=t?Math.max(0,m.findIndex(b=>b.id===t)):0,g=document.createElement("div");g.id="versions",g.innerHTML=`<div class="vs-rig" style="left:${u}px;top:${f}px;width:${l}px;height:${c}px">
72
+ ${m.map((b,M)=>`<div class="vs-layer${M===y?" front":""}" data-i="${M}">${b.thumb?`<img src="${w(b.thumb)}" alt="" draggable="false">`:""}</div>`).join("")}
73
+ <div class="vs-live"><iframe title="" style="width:${n.w}px;height:${n.h}px;transform:scale(${r})"></iframe></div></div>
74
+ <div class="vs-bar"></div>`,document.body.appendChild(g),document.body.classList.add("versions-on"),D={fid:e,layers:m,el:g,at:y,liveT:null};const v=g.querySelector(".vs-rig");v.style.transform=`translate(${a.l-u}px, ${a.t-f}px) scale(${a.w/l})`,requestAnimationFrame(()=>requestAnimationFrame(()=>{D?.el===g&&(v.style.transform="",g.classList.add("open"),Ma())})),x("POST",`/__loop/api/frames/${e}/versions`).then(b=>{!D||D.el!==g||(b.now&&So(0,b.now),Eo())}).catch(b=>{D?.el===g&&(D.failed=b.message,g.classList.add("failed"),Mo())}),g.addEventListener("pointerdown",b=>b.stopPropagation());let A=0,_=0;g.addEventListener("wheel",b=>{b.preventDefault(),b.stopPropagation(),A+=Math.abs(b.deltaY)>=Math.abs(b.deltaX)?b.deltaY:b.deltaX;const M=performance.now();Math.abs(A)>40&&M-_>170&&(As(A>0?1:-1),A=0,_=M)},{passive:!1}),g.addEventListener("click",b=>{const M=b.target.closest("[data-vc]");if(M)return Rl(M.dataset.vc);if(b.target.closest(".vs-bar, .vs-live"))return;const L=b.target.closest(".vs-layer");if(L){+L.dataset.i!==D.at&&(D.at=+L.dataset.i,Ma());return}zt()})}function As(e){if(!D)return;const t=Math.max(0,Math.min(D.layers.length-1,D.at+e));t!==D.at&&(D.at=t,Ma())}function Ma(){if(!D)return;const{el:e,layers:t,at:n,fid:s}=D,a=d.frames.find(c=>c.id===s);e.querySelectorAll(".vs-layer").forEach(c=>{const u=+c.dataset.i-n,f=u<0||u>3;c.classList.toggle("front",u===0),c.classList.toggle("gone",f),c.style.transform=u<0?"translate3d(0, 48px, 260px)":`translate3d(0, ${-u*22}px, ${-u*150}px)`,c.style.opacity=f?"0":"1",c.style.filter=u>0&&!f?`brightness(${(1-u*.09).toFixed(2)})`:"",c.style.zIndex=String(100-Math.abs(u))}),Mo();const i=e.querySelector(".vs-live"),o=i.querySelector("iframe"),r=t[n];if(i.classList.remove("ready"),clearTimeout(D.liveT),!a||!r)return;const l=r.now?`/__loop/f/${a.id}/${encodeURIComponent(a.entry||"index.html")}?_v=${Date.now()}`:`/__loop/hist/${r.id}/${encodeURIComponent(a.entry||"index.html")}`;D.liveT=setTimeout(()=>{D?.el!==e||D.at!==n||(o.onload=()=>{D?.el===e&&D.at===n&&i.classList.add("ready")},o.src=l)},460)}function Mo(){if(!D)return;const{el:e,layers:t,at:n}=D,s=t.length,a=t[n],i=a.now?"Now":`v${s-n}`;e.querySelector(".vs-bar").innerHTML=`
75
+ <button class="sb-btn" data-vc="older" title="Older version (\u2190)" ${n>=s-1?"disabled":""}>${E("left")}</button>
76
+ <div class="vs-pos"><b>${i}</b><span>${s-n} of ${s}</span></div>
77
+ <button class="sb-btn" data-vc="newer" title="Newer version (\u2192)" ${n<=0?"disabled":""}>${E("right")}</button>
78
+ <span class="sb-sep"></span>
79
+ <div class="vs-what" title="${w(a.label||"")}"><span>${D.failed?`The pictures could not be made (${w(D.failed)})`:w(a.label||"")}</span>${a.now?"":`<time>${Lt(a.at)}</time>`}</div>
80
+ ${$()&&!a.now?`<span class="sb-sep"></span>
81
+ <button class="sb-tog" data-vc="restore" title="Go back to this version (the one you are on is kept)">${E("undo")}<span>Go back to it</span></button>
82
+ <button class="sb-btn" data-vc="duplicate" title="Make this version its own frame on the canvas">${E("copy")}</button>`:""}
83
+ <span class="sb-sep"></span>
84
+ <button class="sb-btn" data-vc="exit" title="Close (esc)">${E("x")}</button>`}async function Rl(e){if(!D)return;const t=D.at,n=D.layers[t],s=D.layers.length,a=D.fid,i=d.frames.find(o=>o.id===a);if(e==="exit")return zt();if(e==="older")return As(1);if(e==="newer")return As(-1);if(!(!n||n.now))try{if(e==="duplicate"){const o=await x("POST",`/__loop/api/frames/${a}/versions/duplicate`,{id:n.id,name:`${i?.name||"Frame"} \xB7 v${s-t}`});zt(!0),d.frames.find(r=>r.id===o.id)?(J(o.id),pt(o.id)):We=o.id,k(`v${s-t} is now its own frame`)}else e==="restore"&&(await x("POST",`/__loop/api/frames/${a}/versions/restore`,{id:n.id}),zt(),k(`Back to v${s-t}. The version you were on is kept.`,3200))}catch(o){k(o.message)}}function Eo(){if(!D)return;const e=Ts(D.fid);D.layers.forEach((t,n)=>{const s=!t.now&&e.find(a=>a.id===t.id)?.thumb;s&&So(n,s)})}function So(e,t){const n=D?.el.querySelector(`.vs-layer[data-i="${e}"]`);if(!n)return;let s=n.querySelector("img");s||(s=document.createElement("img"),s.alt="",s.draggable=!1,n.appendChild(s)),s.getAttribute("src")!==t&&(s.src=t)}function zt(e){if(!D)return;const{el:t,fid:n}=D;clearTimeout(D.liveT),D=null;const s=d.frames.find(i=>i.id===n),a=t.querySelector(".vs-rig");if(t.classList.remove("open"),t.classList.add("closing"),s&&a&&!e){const i=bt(s),o=parseFloat(a.style.left),r=parseFloat(a.style.top),l=parseFloat(a.style.width);a.style.transform=`translate(${i.l-o}px, ${i.t-r}px) scale(${i.w/l})`}document.body.classList.remove("versions-on"),setTimeout(()=>t.remove(),380)}addEventListener("keydown",e=>{D&&(e.key==="Escape"?(e.stopPropagation(),e.preventDefault(),zt()):/^Arrow(Left|Right|Up|Down)$/.test(e.key)&&!gn()&&(e.stopPropagation(),e.preventDefault(),As(e.key==="ArrowLeft"||e.key==="ArrowUp"?1:-1)))},!0),addEventListener("resize",()=>zt());let an=null;async function _s(e,t){try{const n=O.get(e),s=n&&!n.parked?Hn(n):n?.resume,a=await x("POST",`/__loop/api/frames/${e}/duplicate`,{...t?{x:Math.round(t.x),y:Math.round(t.y)}:{},...s?{route:s}:{}});let i=null;Z("Duplicate frame",async()=>{i=Yt(a.id)||i,await x("DELETE",`/__loop/api/frames/${a.id}`)},()=>Ue(i||{frames:[a]})),d.frames.find(o=>o.id===a.id)?(J(a.id),pt(a.id)):We=a.id}catch(n){k(n.message)}}addEventListener("keydown",e=>{e.key==="Alt"&&F.classList.add("alt")}),addEventListener("keyup",e=>{e.key==="Alt"&&F.classList.remove("alt")}),addEventListener("keydown",e=>{if(V!=="comment"||!(e.key==="Meta"||e.key==="Control")||ie)return;const t=document.elementFromPoint(Te.x,Te.y),n=t?.closest(".frame-body")&&!t.closest(".pin")&&t.closest(".frame")?.dataset.id,s=n&&d.frames.find(a=>a.id===n);s&&!_t(s)&&(!S||n===S.fid)&&cn(n,Te.x,Te.y,"block")}),addEventListener("keyup",e=>{V==="comment"&&(e.key==="Meta"||e.key==="Control")&&(Q.hidden=!0)}),addEventListener("blur",()=>F.classList.remove("alt"));const Nl=[["Tools",[["V","Select: frames, and the elements inside them"],["I","Interact: click, type and scroll in the pages"],["Scroll in a frame you\u2019re using","Up/down scrolls its page; sideways moves the canvas"],["H / hold Space","Pan"],["F","Frame (presets, or drag to draw)"],["\u21E7S","Section: drag a region that holds frames"],["C","Comment (click = pin, drag = area)"],["C, then hold \u2318","Comment on a block: hover to outline it, click to comment"],["\u21E7C","Hide / show comments"],["D","Deep select: pick exact elements (\u21E7 for more)"],["P","Draw"],["E","Erase marks"],["N","Describe a frame for the agent"]]],["Edit",[["\u2318Z","Undo"],["\u21E7\u2318Z / Ctrl Y","Redo"],["\u2325 drag title","Duplicate frame"],["\u2318C / \u2318V","Copy / paste frame"],["\u2318D","Duplicate in place"],["\u21E7F","Freeze a copy (keeps this moment)"],["K","Phone keyboard on / off"],["\u21E7 click / drag box","Select several frames"],["\u2318A","Select all frames"],["\u2325A \u2325H \u2325D","Align left / centre / right"],["\u2325W \u2325V \u2325S","Align top / middle / bottom"],["Delete","Delete selected frame"],["Double-click title","Rename frame"],["Click the size by a title","Size & device presets"],["Esc","Close / deselect"]]],["View",[["Pinch / \u2318 scroll","Zoom"],["Scroll","Pan"],["\u21E71","Fit everything"],["\u21E72","Zoom to the selection"],["Arrows / \u21E7 arrows","Nudge the selection 1px / 10px"],["\u21E7 drag","Move straight across or up/down"],["\u23180","Zoom to 100%"],["+ / \u2212","Zoom in / out"]]],["Comments",[["\u21B5","Send to the agent"],["\u21E7\u21B5","New line"],["?","This list"]]]];function To(e){let t=p("#shortcuts");t||(t=document.createElement("div"),t.id="shortcuts",t.className="modal",t.hidden=!0,t.innerHTML=`<div class="modal-card sc-card"><div class="modal-head"><span>Keyboard shortcuts</span><button class="icon-btn" data-close>\xD7</button></div>
85
+ <div class="sc-grid">${Nl.map(([n,s])=>`<div><div class="sc-group">${n}</div>${s.map(([a,i])=>`<div class="sc-row"><span>${w(i)}</span><span class="sc-keys">${a.split(" / ").map(o=>`<kbd>${w(o)}</kbd>`).join(" ")}</span></div>`).join("")}</div>`).join("")}</div></div>`,document.body.appendChild(t),t.addEventListener("pointerdown",n=>{(n.target===t||n.target.closest("[data-close]"))&&(t.hidden=!0)})),t.hidden=e===void 0?!t.hidden:!e}addEventListener("keydown",e=>{gn()||(e.key==="?"?(e.preventDefault(),To()):e.key==="Escape"&&p("#shortcuts")&&!p("#shortcuts").hidden&&To(!1))});function Ao(e){const t=d.frames.find(s=>s.id===P),n=e.value.trim();if(t&&n&&n!==t.name){const s=t.name,a=t.id;t.name=n,X(t),x("PATCH",`/__loop/api/frames/${a}`,{name:n}).catch(i=>k(i.message)),Z("Rename frame",()=>ht(a,{name:s}),()=>ht(a,{name:n}))}}p("#frame-panel").addEventListener("change",e=>{e.target.id==="fp-name"&&Ao(e.target)}),p("#frame-panel").addEventListener("keydown",e=>{e.target.id==="fp-name"&&e.key==="Enter"&&(Ao(e.target),e.target.blur())},!0),p("#canvas-name").addEventListener("click",()=>{const e=p("#canvas-name");if(!$()||K||e.querySelector("input"))return;const t=document.createElement("input");t.className="canvas-rename",t.value=d.name,t.spellcheck=!1,e.replaceChildren(t),t.focus(),t.select();const n=s=>{const a=t.value.trim();if(e.textContent=s&&a?a:d.name,s&&a&&a!==d.name){const i=d.name;d.name=a,x("POST","/__loop/api/settings",{name:a}).catch(o=>k(o.message)),Z("Rename canvas",()=>x("POST","/__loop/api/settings",{name:i}),()=>x("POST","/__loop/api/settings",{name:a}))}};t.addEventListener("keydown",s=>{s.stopPropagation(),s.key==="Enter"&&t.blur(),s.key==="Escape"&&(t.value=d.name,t.blur())}),t.addEventListener("blur",()=>n(!0))}),addEventListener("resize",()=>ye()),jr(),pe("select"),te(),Ho();const Re=document.createElement("div");Re.id="tip",Re.hidden=!0,document.body.appendChild(Re);let Ht=null,Ea=null,Sa=0;function Sn(){clearTimeout(Ea),Ea=null,Ht&&!Re.hidden&&(Sa=Date.now()),Ht=null,Re.hidden=!0}function Fl(e,t){if(!e.isConnected)return Sn();const n=/^(.*\S)\s+\(([^()]{1,14})\)$/.exec(t);Re.innerHTML=n?`${w(n[1])}<kbd>${w(n[2])}</kbd>`:w(t),Re.hidden=!1;const s=e.getBoundingClientRect(),a=Re.offsetWidth,i=Re.offsetHeight,o=s.bottom+8+i<innerHeight-6&&s.top<innerHeight*.6;Re.style.left=`${Math.round(Math.max(8,Math.min(s.left+s.width/2-a/2,innerWidth-a-8)))}px`,Re.style.top=`${Math.round(o?s.bottom+8:s.top-i-8)}px`,Re.classList.toggle("up",!o)}document.addEventListener("pointerover",e=>{const t=e.target.closest?.("[title]:not(iframe), [data-tip]");if(t===Ht||(Sn(),!t||e.pointerType==="touch"))return;t.title&&(t.dataset.tip=t.title,!t.getAttribute("aria-label")&&!t.textContent.trim()&&t.setAttribute("aria-label",t.title),t.removeAttribute("title"));const n=t.dataset.tip;n&&(Ht=t,Ea=setTimeout(()=>Fl(t,n),Date.now()-Sa<700?0:260))},!0),document.addEventListener("pointerout",e=>{Ht&&!Ht.contains(e.relatedTarget)&&Sn()},!0);for(const e of["pointerdown","wheel","keydown"])addEventListener(e,()=>{Ht&&(Sn(),Sa=0)},{capture:!0,passive:!0});