1import{k as qs,b as Xs,r as l,e as q,a as j,z as ve,j as e,B as f,L as X,S as is,G as S,X as Zs,D as et,f as be,M as st,H as ds}from"./index-wEf7CNwx.js";import{u as cs}from"./useQuery-7eNXufmd.js";import{u as Te,A as tt,f as at,T as ms}from"./AppLayout-CY6tk7gY.js";import{P as us,s as nt,l as rt,p as xs,a as lt,n as Ue,b as ot,F as it,f as F,e as dt,c as ct,d as mt,g as ut,h as xt,i as ht}from"./store-DxZ96GY6.js";import{C as y}from"./card-BpVMxKnC.js";import{C as hs}from"./checkbox-B98mK1Pr.js";import{C as ps,a as fs,b as gs}from"./collapsible-DjIxcU0o.js";import{I as ye}from"./input-Bk6apN8e.js";import{S as Z,a as ee,b as se,c as te,d as ae}from"./select-VkaEwFNP.js";import{T as pt,a as ft,b as js,c as gt}from"./tabs-D1OBvDs_.js";import{u as jt}from"./useTranslatedConstants-D7GDlYJw.js";import{L as vt}from"./layout-grid-Cg_DD9GP.js";import{U as vs}from"./upload-DKTAqwHE.js";import{P as bt}from"./plus-BBxs9khZ.js";import{T as Ae}from"./trash-2-BXc8_gzD.js";import{U as yt}from"./undo-2-CeuObWEj.js";import{W as wt}from"./wand-sparkles-uSb7ehxV.js";import{C as Nt}from"./copy-Cc8kjLmO.js";import{F as kt}from"./folder-open-CrL512z5.js";import"./separator-C45GX3TU.js";import"./sun-CRo_k_Vt.js";import"./three.module-Qk6yGQWx.js";import"./OrbitControls-3XXtKPyd.js";import"./mountain-DRcmxYRP.js";import"./layers-BJ8YWjgS.js";import"./eye-BzNpErAa.js";import"./index-DLEWjOzy.js";import"./index-BdQq_4o_.js";import"./staging-B1eZd9a4.js";import"./videoPresets-OEMPU9TT.js";/** 2 * @license lucide-react v0.462.0 - ISC 3 * 4 * This source code is licensed under the ISC license. 5 * See the LICENSE file in the root directory of this source tree. 6 */const Ct=qs("FileUp",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M12 12v6",key:"3ahymv"}],["path",{d:"m15 15-3-3-3 3",key:"15xj92"}]]),ws=[{key:"walls",label:"Walls",color:"#e11d48"},{key:"doors",label:"Doors",color:"#16a34a"},{key:"windows",label:"Windows",color:"#2563eb"},{key:"rooms",label:"Rooms",color:"#0ea5e9"},{key:"fixtures",label:"Fixtures",color:"#d946ef"},{key:"dimensions",label:"Printed dims",color:"#f97316"},{key:"measure",label:"Measurements",color:"#334155"}],bs={"gemini-3.8-flash":"newest flash, best on doors, ~15 s","gemini-3.5-flash":"what the drawing pack uses today, ~30 s","gemini-3.1-pro-preview":"pro preview, slower, not better on doors"},St=[{id:"normal",label:"Normal (nano-banana-2)"},{id:"pro",label:"Pro 2K (nano-banana-pro)"},{id:"pro4k",label:"4K (nano-banana-pro)"}],Pt={dimensions:"printed dimensions",doors:"door width guess",model:"model estimate",unknown:"unknown",calibrated:"calibrated by you"},Rt=[],Mt={},U=d=>ws.find(c=>c.key===d).color;function $t(d,c){switch(c){case"walls":case"doors":case"windows":case"rooms":case"fixtures":case"dimensions":return d[c].length;default:return null}}function Lt(d,c){return d.ppmOverrides[c.id]??c.scale.pixelsPerMeter}function ys(d){return d.runs.find(c=>c.id===d.activeRunId)??d.runs[0]??null}function Et({plan:d,layers:c}){const w=(i,u,x,o,h,C)=>e.jsx("line",{x1:u.x,y1:u.y,x2:x.x,y2:x.y,stroke:o,strokeWidth:h,strokeLinecap:"round",strokeDasharray:C,vectorEffect:"non-scaling-stroke"},i);return e.jsxs("svg",{className:"pointer-events-none absolute inset-0 h-full w-full",viewBox:"0 0 1000 1000",preserveAspectRatio:"none",children:[c.rooms&&d.rooms.map((i,u)=>e.jsx("polygon",{points:i.polygon.map(x=>`${x.x},${x.y}`).join(" "),fill:U("rooms"),fillOpacity:.12,stroke:U("rooms"),strokeWidth:1.5,strokeDasharray:"6 4",vectorEffect:"non-scaling-stroke"},`room-${u}`)),c.walls&&d.walls.map((i,u)=>w(`wall-${u}`,i.a,i.b,U("walls"),i.exterior?4:3)),c.doors&&d.doors.map((i,u)=>w(`door-${u}`,i.a,i.b,U("doors"),6)),c.windows&&d.windows.map((i,u)=>w(`win-${u}`,i.a,i.b,U("windows"),6)),c.dimensions&&d.dimensions.map((i,u)=>w(`dim-${u}`,i.a,i.b,U("dimensions"),2,"4 3")),c.fixtures&&d.fixtures.map((i,u)=>e.jsx("rect",{x:Math.min(i.box.x0,i.box.x1),y:Math.min(i.box.y0,i.box.y1),width:Math.abs(i.box.x1-i.box.x0),height:Math.abs(i.box.y1-i.box.y0),fill:"none",stroke:U("fixtures"),strokeWidth:1.5,vectorEffect:"non-scaling-stroke"},`fix-${u}`))]})}function Ft({plan:d,metric:c,layers:w}){const i=o=>({left:`${o.x/10}%`,top:`${o.y/10}%`}),u=(o,h)=>({x:(o.x+h.x)/2,y:(o.y+h.y)/2}),x="absolute -translate-x-1/2 -translate-y-1/2 whitespace-nowrap rounded px-1 text-[9px] leading-tight shadow-sm";return e.jsxs("div",{className:"pointer-events-none absolute inset-0",children:[w.rooms&&d.rooms.map((o,h)=>
6{if(o.polygon.length===0)return null;const C=o.polygon.reduce((v,P)=>v+P.x,0)/o.polygon.length,B=o.polygon.reduce((v,P)=>v+P.y,0)/o.polygon.length,A=c?c.areaM2(o.polygon):null;return e.jsxs("div",{className:"absolute -translate-x-1/2 -translate-y-1/2 rounded bg-white/85 px-1.5 py-0.5 text-center text-[11px] font-semibold leading-tight text-sky-700 shadow-sm",style:i({x:C,y:B}),children:[o.name,A!=null&&e.jsxs("span",{className:"block text-[10px] font-normal text-sky-600",children:[A.toFixed(1)," m²"]})]},`rl-${h}`)}),w.measure&&c&&d.walls.map((o,h)=>{const C=c.lengthM(o.a,o.b);return C<.3?null:e.jsx("div",{className:S(x,"bg-slate-800/85 text-white"),style:i(u(o.a,o.b)),children:F(C)},`wm-${h}`)}),w.measure&&c&&d.doors.map((o,h)=>e.jsx("div",{className:S(x,"bg-green-700/90 text-white"),style:i(u(o.a,o.b)),children:F(c.lengthM(o.a,o.b))},`dm-${h}`)),w.measure&&c&&d.windows.map((o,h)=>e.jsx("div",{className:S(x,"bg-blue-700/90 text-white"),style:i(u(o.a,o.b)),children:F(c.lengthM(o.a,o.b))},`wnm-${h}`)),w.dimensions&&d.dimensions.map((o,h)=>e.jsxs("div",{className:S(x,"bg-orange-500/90 text-white"),style:i(u(o.a,o.b)),children:[o.meters," m"]},`dl-${h}`)),w.fixtures&&d.fixtures.map((o,h)=>e.jsx("div",{className:"absolute rounded-sm bg-fuchsia-500/85 px-1 text-[9px] leading-tight text-white",style:{left:`${Math.min(o.box.x0,o.box.x1)/10}%`,top:`${Math.min(o.box.y0,o.box.y1)/10}%`},children:o.label},`fl-${h}`))]})}const ca=()=>{const{user:d}=Xs(),c=l.useRef(null),w=l.useRef(null),i=l.useRef(null),u=l.useRef("plan"),[x,o]=l.useState(null),[h,C]=l.useState(""),[B,A]=l.useState(0),[v,P]=l.useState([]),[p,D]=l.useState(null),[z,W]=l.useState([]),ne=l.useRef({variants:[],cameras:[],walks:[],videos:[],references:[]}),[De,Ns]=l.useState([]),[we,re]=l.useState("idle"),[ze,ks]=l.useState(!1),g=l.useMemo(()=>v.find(s=>s.id===p)??null,[v,p]),Q=(g==null?void 0:g.imageUrl)??null,le=(g==null?void 0:g.runs)??Rt,oe=(g==null?void 0:g.activeRunId)??null,Ne=(g==null?void 0:g.ppmOverrides)??Mt,$=l.useCallback((s,t)=>{P(a=>a.map(n=>n.id===s?{...n,...typeof t=="function"?t(n):t}:n))},[]),[ke,We]=l.useState(!1),[J,Cs]=l.useState("gemini-3.8-flash"),[K,Ce]=l.useState("plan"),[Se,Ss]=l.useState({walls:!0,doors:!0,windows:!0,rooms:!0,fixtures:!0,dimensions:!0,measure:!0}),[Ve,Ps]=l.useState(!1),[ie,de]=l.useState(null),[ce,Y]=l.useState(!1),[k,V]=l.useState([]),[_e,Rs]=l.useState("1.00"),Be=l.useRef(null),Ms=l.useCallback(s=>{Be.current=s},[]),[I,$s]=l.useState("interior"),[Pe,Ls]=l.useState("scandi"),[Re,Es]=l.useState("living-room"),[Me,Fs]=l.useState("hdr-enhance"),[$e,Is]=l.useState(""),[Le,Os]=l.useState("normal"),[G,me]=l.useState("idle"),[Ee,Ts]=l.useState(!1),{stylePresets:Qe,roomTypes:Je,editPresets:Ke}=jt(),[ue,Ye]=l.useState(""),[Ge,Fe]=l.useState([]),[L,xe]=l.useState(null),{data:Us}=cs(q.floorplanLab.models.queryOptions()),r=l.useMemo(()=>le.find(s=>s.id===oe)??null,[le,oe]),_=r?Ne[r.id]??r.scale.pixelsPerMeter:null,he=r?Ne[r.id]?"calibrated":r.scale.source:null,R=l.useMemo(()=>r&&_?new us(r.width,r.height,_):null,[r,_]),N=l.useMemo(()=>r&&R?nt(r.plan,R):null,[r,R]),He=l.useMemo(()=>{const s=[];for(const t of v){const a=ys(t),n=a?Lt(t,a):null;!a||!n||s.push({id:t.id,label:t.label,level:t.level,plan:a.plan,metric:new us(a.width,a.height,n)})}return s},[v]),Ie=He.some(s=>s.id===p),Oe=l.useMemo(()=>({mode:I,outputQuality:Le,aspectRatio:"auto",style:I==="interior"?Pe:void 0,roomType:I==="interior"?Re:void 0,editPreset:I==="edit"?Me:void 0,customPrompt:$e.trim()||void 0}),[I,Le,Pe,Re,Me,$e]),pe=cs({...q.floorplanLab.renderPrompt.queryOptions(Oe),enabled:Ee}),As=Te(q.floorplanLab.render.mutationOptions()),fe=Te(q.floorplanLab.vectorize.mutationOptions()),ge=Te(q.floorplanLab.editFixtures.mutationOptions()),O=l.useCallback(async()=>{try{Ns(await rt())}catch(s){console.warn("Floorplan Lab: could not list saved plans",s)}},[]);l.useEffect(()=>{O()},[O]),l.useEffect(()=>{if(!x||v.length===0)return;re("saving");const s=window.setTimeout(async()=>{try{await xs({id:x,name:h||"Untitled plan",createdAt:B||Date.now(),updatedAt:Date.now(),floors:v,activeFloorId:p,renders:z,...ne.current}),re("saved"),O()}catch(t){re("error"),j.error(t instanceof Error?t.message:"Could not save plan")}},400);return()=>window.clearTimeout(s)},[x,h,B,v,p,z,O]);const M=l.useCallback(()=>{de(null),Y(!1),V([]),Fe([]),xe(null),Ce("plan")},[]),qe=l.useCallback(s=>{var t;o(s.id),C(s.name),A(s.createdAt),P(s.floors),D(s.activeFloorId??((t=s.floors[0])==null?void 0:t.id)??null),W(s.renders),ne.current={variants:s.variants,cameras:s.cameras,walks:s.walks,videos:s.videos,references:s.references},M()},[M]),Xe=(s,t)=>({id:Ue(),label:lt(t),level:t,labelAuto:!0,imageUrl:s,runs:[],activeRunId:null,ppmOverrides:{}}),Ze=l.useCallback((s,t)=>{const a=Xe(s,0);o(Ue()),C(t),A(Date.now()),P([a]),D(a.id),W([]),ne.current={variants:[],cameras:[],walks:[],videos:[],references:[]},M()},[M]),es=l.useCallback(s=>{P(t=>{const a=t.length?Math.max(...t.map(m=>m.level))+1:0,n=Xe(s,a);return D(n.id),[...t,n]}),M()},[M]),Ds=s=>{P(t=>{var n;const a=t.filter(m=>m.id!==s);return s===p&&D(((n=a[0])==null?void 0:n.id)??null),a}),W(t=>t.filter(a=>a.floorId!==s)),M()},ss=l.useCallback(()=>{o(null),C(""),A(0),P([]),D(null),W([]),re("idle"),M()},[M]),ts=async s=>{try{const t=await xt(s);if(!t){j.error("That plan is no longer in this browser"),O();return}qe(t)}catch(t){j.error(t instanceof Error?t.message:"Could not open plan")}},zs=async s=>{try{await ht(s),s===x&&ss(),O()}catch(t){j.error(t instanceof Error?t.message:"Could not delete plan")}},Ws=()=>
6{if(!x)return;const s=dt({id:x,name:h||"Untitled plan",createdAt:B||Date.now(),updatedAt:Date.now(),floors:v,activeFloorId:p,renders:z,...ne.current}),t=new Blob([s],{type:"application/json"}),a=URL.createObjectURL(t),n=document.createElement("a");n.href=a,n.download=`${(h||"floorplan").replace(/[^\w.-]+/g,"_")}.floorplan.json`,n.click(),URL.revokeObjectURL(a)},Vs=async s=>{try{const t=ut(await s.text());await xs(t),qe(t),O(),j.success(`Imported "${t.name}" with ${t.floors.length} floor${t.floors.length===1?"":"s"}`)}catch(t){j.error(t instanceof Error?t.message:"Import failed")}},_s=l.useCallback(async s=>{if(d){if(!s.type.startsWith("image/")){j.error("Please choose an image file");return}We(!0);try{const t=s.name.replace(/[^\w.-]+/g,"_"),a=`${d.id}/floorplan-lab/${Date.now()}-${t}`,{error:n}=await ve.storage.from("room-images").upload(a,s,{cacheControl:"3600",upsert:!1});if(n)throw n;const{publicUrl:m}=ve.storage.from("room-images").getPublicUrl(a).data;u.current==="floor"&&x?es(m):Ze(m,ot(s.name))}catch(t){j.error(t instanceof Error?t.message:"Upload failed")}finally{We(!1),u.current="plan"}}},[d,x,es,Ze]),as=s=>{var t;u.current=s,(t=c.current)==null||t.click()},Bs=async()=>{if(!Q||!p)return;const s=p;try{const t=await fe.mutateAsync({imageUrl:Q,model:J}),a={id:`${Date.now()}`,...t};$(s,n=>{var je;const m=(je=a.plan.floorLabel)==null?void 0:je.trim(),b=a.plan.floorLevel,E=n.labelAuto!==!1&&!!m;return{runs:[a,...n.runs],activeRunId:a.id,label:E?m:n.label,level:E&&typeof b=="number"&&Number.isFinite(b)?Math.round(b):n.level}}),de(null),j.success(`${t.model}: ${t.plan.walls.length} walls, ${t.plan.doors.length} doors, ${t.plan.windows.length} windows in ${(t.ms/1e3).toFixed(1)} s${t.plan.floorLabel?` · reads as "${t.plan.floorLabel}"`:""}`)}catch(t){j.error(`Vectorise failed: ${t instanceof Error?t.message:String(t)}`)}},Qs=s=>{if(!ce||!i.current)return;const t=i.current.getBoundingClientRect(),a={x:(s.clientX-t.left)/t.width*1e3,y:(s.clientY-t.top)/t.height*1e3};V(n=>n.length>=2?[a]:[...n,a])},Js=()=>{if(!r||!p||k.length!==2)return;const s=Number.parseFloat(_e.replace(",","."));if(!Number.isFinite(s)||s<=0){j.error("Enter the real distance in metres");return}const[t,a]=k,n=Math.hypot((t.x-a.x)*r.width/1e3,(t.y-a.y)*r.height/1e3);if(n<2){j.error("Points are too close together");return}const m=r.id;$(p,b=>({ppmOverrides:{...b.ppmOverrides,[m]:n/s}})),Y(!1),V([]),j.success(`Scale set to ${(n/s).toFixed(1)} px/m`)},Ks=()=>{if(!r||!p)return;const s=r.id;$(p,t=>{const a={...t.ppmOverrides};return delete a[s],{ppmOverrides:a}}),V([]),Y(!1)},ns=async()=>{const s=Be.current;if(!s||!d||!r){j.error("Open the 3D model first");return}try{me("capturing");const t=await s();if(!t)throw new Error("Could not capture the 3D view");me("uploading");const a=`${d.id}/floorplan-lab/snapshots/${Date.now()}.png`,{error:n}=await ve.storage.from("room-images").upload(a,t,{cacheControl:"3600",upsert:!1,contentType:"image/png"});if(n)throw n;const m=ve.storage.from("room-images").getPublicUrl(a).data.publicUrl;me("rendering");const b=await As.mutateAsync({snapshotUrl:m,...Oe}),E={id:Ue(),runId:r.id,floorId:p??void 0,createdAt:Date.now(),snapshotUrl:m,imageUrl:b.imageUrl,prompt:b.prompt,model:b.model,ms:b.ms,settings:Oe};W(je=>[E,...je]),j.success(`Rendered in ${(b.ms/1e3).toFixed(0)} s`)}catch(t){j.error(t instanceof Error?t.message:"Render failed")}finally{me("idle")}},rs=s=>{var t,a,n;return s.settings.mode==="edit"?((t=Ke.find(m=>m.id===s.settings.editPreset))==null?void 0:t.name)??s.settings.editPreset:`${((a=Qe.find(m=>m.id===s.settings.style))==null?void 0:a.name)??s.settings.style} · ${((n=Je.find(m=>m.value===s.settings.roomType))==null?void 0:n.label)??s.settings.roomType}`},ls=async()=>{if(!r||!R||!p||ue.trim().length<2)return;const s=p,t=r.id,a=r.plan;try{const n=await ge.mutateAsync({instruction:ue.trim(),context:ct(a,R)});if(n.operations.length===0){xe({summary:n.summary,applied:0,warnings:[],rejected:n.rejected.length,ms:n.ms});return}const m=mt(a,R,n.operations);Fe(b=>[...b,{floorId:s,runId:t,plan:a}]),$(s,b=>({runs:b.runs.map(E=>E.id===t?{...E,plan:m.plan}:E)})),xe({summary:n.summary,applied:m.changed,warnings:m.warnings,rejected:n.rejected.length,ms:n.ms}),Ye("")}catch(n){j.error(n instanceof Error?n.message:"Edit failed")}},T=Ge[Ge.length-1],os=!!T&&T.floorId===p&&T.runId===oe,Ys=()=>{!os||!T||($(T.floorId,s=>({runs:s.runs.map(t=>
6t.id===T.runId?{...t,plan:T.plan}:t)})),Fe(s=>s.slice(0,-1)),xe(null))},Gs=l.useCallback(s=>de(s),[]),Hs=l.useMemo(()=>[...v].sort((s,t)=>t.level-s.level),[v]),H=G!=="idle";return e.jsx(tt,{children:e.jsx("main",{className:"flex-1 overflow-auto",children:e.jsxs("div",{className:"space-y-6 p-4 md:p-6",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(vt,{className:"h-6 w-6 text-primary"}),e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-semibold",children:"Floorplan Lab"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Floor plans â measured vectors â stacked 3D model â styled renders, with plain-language furniture edits. QA-only â no credits, nothing lands in a library."})]})]}),e.jsxs("div",{className:"grid items-start gap-6 xl:grid-cols-[1fr_360px]",children:[e.jsxs("div",{className:"space-y-3",children:[r&&e.jsxs(pt,{value:K,onValueChange:s=>Ce(s),children:[e.jsxs(ft,{children:[e.jsx(js,{value:"plan",children:"2D overlay"}),e.jsxs(js,{value:"model",disabled:!Ie,children:["3D model",Ie?"":" (needs scale)"]})]}),e.jsx(gt,{value:"model",className:"mt-3",children:Ie&&p&&e.jsx(y,{className:"relative h-[72vh] overflow-hidden p-0",children:e.jsx(it,{floors:He,activeFloorId:p,showAllFloors:ze,onSelect:Gs,registerCapture:Ms,className:"h-full w-full",toolbar:e.jsxs(f,{size:"sm",onClick:()=>void ns(),disabled:H,children:[H?e.jsx(X,{className:"mr-1.5 h-4 w-4 animate-spin"}):e.jsx(is,{className:"mr-1.5 h-4 w-4"}),G==="idle"&&"Render this view",G==="capturing"&&"Capturingâ¦",G==="uploading"&&"Uploadingâ¦",G==="rendering"&&"Renderingâ¦"]})})})})]}),(K==="plan"||!r)&&e.jsxs(y,{className:S("relative flex min-h-80 items-center justify-center overflow-hidden bg-muted/40 p-0",ce&&"cursor-crosshair ring-2 ring-orange-400"),children:[Q?e.jsxs(e.Fragment,{children:[e.jsxs("div",{ref:i,className:"relative inline-block max-w-full",onClick:Qs,children:[e.jsx("img",{src:Q,alt:"Floor plan",className:"block max-h-[78vh] w-auto max-w-full select-none",draggable:!1}),r&&e.jsxs(e.Fragment,{children:[e.jsx(Et,{plan:r.plan,layers:Se}),e.jsx(Ft,{plan:r.plan,metric:R,layers:Se})]}),k.length>0&&e.jsxs("svg",{className:"pointer-events-none absolute inset-0 h-full w-full",viewBox:"0 0 1000 1000",preserveAspectRatio:"none",children:[k.length===2&&e.jsx("line",{x1:k[0].x,y1:k[0].y,x2:k[1].x,y2:k[1].y,stroke:"#f97316",strokeWidth:2.5,vectorEffect:"non-scaling-stroke"}),k.map((s,t)=>e.jsx("circle",{cx:s.x,cy:s.y,r:5,fill:"#f97316",vectorEffect:"non-scaling-stroke"},t))]})]}),e.jsx("div",{className:"absolute left-3 top-3 rounded bg-black/55 px-2 py-1 text-[11px] text-white",children:g==null?void 0:g.label}),e.jsx("div",{className:"absolute right-3 top-3 flex gap-2",children:e.jsx(f,{size:"sm",variant:"secondary",onClick:ss,children:e.jsx(Zs,{className:"h-4 w-4"})})}),ce&&e.jsx("div",{className:"pointer-events-none absolute bottom-2 left-2 rounded bg-orange-500/90 px-2 py-1 text-[11px] text-white",children:k.length<2?`Click ${k.length===0?"the first":"the second"} end of a known distance (a door, a printed dimension, an outer wall)`:"Now enter the real distance on the right and apply"})]}):e.jsxs("div",{className:"flex flex-col items-center gap-3 p-10 text-center",children:[e.jsx(vs,{className:"h-8 w-8 text-muted-foreground"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Upload a floor plan (PNG, JPG or WebP). Clean digital plans vectorise best; scans still get rooms and outer walls. Add more floors afterwards."}),e.jsxs(f,{onClick:()=>as("plan"),disabled:ke,children:[ke?e.jsx(X,{className:"mr-2 h-4 w-4 animate-spin"}):e.jsx(vs,{className:"mr-2 h-4 w-4"}),"Choose plan"]})]}),e.jsx("input",{ref:c,type:"file",accept:"image/*",className:"hidden",onChange:s=>{var a;const t=(a=s.target.files)==null?void 0:a[0];t&&_s(t),s.target.value=""}})]})]}),e.jsxs("div",{className:"space-y-4",children:[x&&e.jsxs(y,{className:"space-y-2 p-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("div",{className:"text-sm font-medium",children:"Plan"}),e.jsxs("span",{className:"text-[11px] text-muted-foreground",children:[we==="saving"&&"Savingâ¦",we==="saved"&&"Saved in this browser",we==="error"&&"Not saved"]})]}),e.jsx(ye,{value:h,onChange:s=>C(s.target.value),placeholder:"Plan name",className:"h-8"}),e.jsxs(f,{size:"sm",variant:"secondary",className:"w-full",onClick:Ws,children:[e.jsx(et,{className:"mr-1.5 h-4 w-4"}),"Export JSON"]})]}),x&&e.jsxs(y,{className:"space-y-2 p-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("div",{className:"text-sm font-medium",children:"Floors"}),e.jsxs(f,{size:"sm",variant:"ghost",className:"h-7 px-2",onClick:()=>as("floor"),disabled:ke,children:[e.jsx(bt,{className:"mr-1 h-4 w-4"}),"Add floor"]})]}),e.jsx("ul",{className:"space-y-1",children:Hs.map(s=>{const t=ys(s),a=s.id===p;return e.jsxs("li",{className:S("flex items-center gap-2 rounded-md border px-2 py-1.5 text-xs",a?"border-primary bg-primary/5":"border-transparent hover:bg-muted"),children:[e.jsx("button",{type:"button",className:"shrink-0",onClick:()=>{D(s.id),M()},title:"Open this floor",children:e.jsx("img",{src:s.imageUrl,alt:"",className:"h-8 w-10 rounded object-cover"})}),e.jsx(ye,{value:s.label,onChange:n=>$(s.id,{label:n.target.value,labelAuto:!1}),className:"h-7 min-w-0 flex-1 px-2 text-xs"}),e.jsx(ye,{type:"number",value:s.level,onChange:n=>$(s.id,{level:Number.parseInt(n.target.value||"0",10)||0,labelAuto:!1}),className:"h-7 w-14 px-2 text-xs",title:"Storey: 0 = ground, 1 = first, -1 = basement"}),e.jsx("span",{className:"w-10 shrink-0 text-right text-muted-foreground",children:t?`${t.plan.rooms.length} rm`:"â"}),v.length>1&&e.jsx(f,{size:"icon",variant:"ghost",className:"h-7 w-7 shrink-0 text-muted-foreground hover:text-destructive",onClick:()=>Ds(s.id),title:"Remove floor",children:e.jsx(Ae,{className:"h-3.5 w-3.5"})})]},s.id)})}),v.length>1&&e.jsxs("label",{className:"flex cursor-pointer items-center gap-2 text-xs",children:[e.jsx(hs,{checked:ze,onCheckedChange:s=>ks(s===!0)}),"Stack all floors in 3D"]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"The vectoriser reads the storey off the plan when it is printed; edit the label or level to override."})]}),e.jsxs(y,{className:"space-y-3 p-4",children:[e.jsx("div",{className:"text-sm font-medium",children:"Model"}),e.jsxs(Z,{value:J,onValueChange:s=>Cs(s),children:[e.jsx(ee,{children:e.jsx(se,{})}),e.jsx(te,{children:(Us??[J]).map(s=>e.jsx(ae,{value:s,children:s},s))})]}),bs[J]&&e.jsx("p",{className:"text-xs text-muted-foreground",children:bs[J]}),e.jsxs(f,{className:"w-full",disabled:!Q||fe.isPending,onClick:()=>void Bs(),children:[fe.isPending?e.jsx(X,{className:"mr-2 h-4 w-4 animate-spin"}):e.jsx(at,{className:"mr-2 h-4 w-4"}),fe.isPending?"Vectorisingâ¦":`Vectorise${g?` ${g.label.toLowerCase()}`:""}`]})]}),r&&e.jsxs(y,{className:"space-y-3 p-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("div",{className:"text-sm font-medium",children:"Scale"}),he&&e.jsx(be,{variant:he==="calibrated"||he==="dimensions"?"default":"secondary",children:Pt[he]})]}),e.jsx("div",{className:"text-xs text-muted-foreground",children:_?`${_.toFixed(1)} px per metre · ${r.scale.basis}`:"No scale found. Calibrate with a known distance."}),ce?e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(ye,{value:_e,onChange:s=>Rs(s.target.value),inputMode:"decimal",className:"h-8"}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"m"})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(f,{size:"sm",className:"flex-1",disabled:k.length!==2,onClick:Js,children:"Apply"}),e.jsx(f,{size:"sm",variant:"secondary",onClick:()=>{Y(!1),V([])},children:"Cancel"})]})]}):e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(f,{size:"sm",variant:"secondary",className:"flex-1",onClick:()=>{Ce("plan"),Y(!0),V([])},children:[e.jsx(st,{className:"mr-1.5 h-4 w-4"}),"Calibrate"]}),Ne[r.id]&&e.jsx(f,{size:"sm",variant:"ghost",onClick:Ks,children:"Reset"})]})]}),N&&r&&e.jsxs(y,{className:"space-y-2 p-4",children:[e.jsx("div",{className:"text-sm font-medium",children:"Measurements"}),e.jsxs("dl",{className:"grid grid-cols-2 gap-x-3 gap-y-1 text-xs",children:[e.jsx("dt",{className:"text-muted-foreground",children:"Floor area"}),e.jsxs("dd",{children:[N.floorAreaM2.toFixed(1)," m²"]}),e.jsx("dt",{className:"text-muted-foreground",children:"Footprint"}),e.jsxs("dd",{children:[N.boundsM.w.toFixed(2)," Ã"," ",N.boundsM.h.toFixed(2)," m"]}),e.jsx("dt",{className:"text-muted-foreground",children:"Walls total"}),e.jsx("dd",{children:F(N.wallTotalM,1)}),e.jsx("dt",{className:"text-muted-foreground",children:"Exterior / interior"}),e.jsxs("dd",{children:[F(N.exteriorWallM,1)," /"," ",F(N.interiorWallM,1)]}),e.jsx("dt",{className:"text-muted-foreground",children:"Doors"}),e.jsxs("dd",{children:[N.doorCount,N.medianDoorWidthM!=null&&` · median ${F(N.medianDoorWidthM)}`]}),e.jsx("dt",{className:"text-muted-foreground",children:"Windows"}),e.jsxs("dd",{children:[N.windowCount,N.medianWindowWidthM!=null&&` · median ${F(N.medianWindowWidthM)}`]})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Sanity check: interior doors are usually 0.8â0.9 m. If the median is far off, calibrate."})]}),K==="model"&&r&&R&&e.jsxs(y,{className:"space-y-3 p-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("div",{className:"text-sm font-medium",children:"Edit with words"}),e.jsxs(f,{size:"sm",variant:"ghost",className:"h-7 px-2",disabled:!os,onClick:Ys,title:"Undo the last edit",children:[e.jsx(yt,{className:"mr-1 h-4 w-4"}),"Undo"]})]}),e.jsx(ms,{value:ue,onChange:s=>Ye(s.target.value),placeholder:"Put a corner sofa under the living room window and move the dining table next to the kitchen counterâ¦",rows:3,className:"text-xs",onKeyDown:s=>
6{s.key==="Enter"&&(s.metaKey||s.ctrlKey)&&(s.preventDefault(),ls())}}),e.jsxs(f,{className:"w-full",disabled:ge.isPending||ue.trim().length<2,onClick:()=>void ls(),children:[ge.isPending?e.jsx(X,{className:"mr-2 h-4 w-4 animate-spin"}):e.jsx(wt,{className:"mr-2 h-4 w-4"}),ge.isPending?"Laying outâ¦":"Apply"]}),L&&e.jsxs("div",{className:"space-y-1 rounded bg-muted p-2 text-[11px]",children:[e.jsx("div",{children:L.summary}),e.jsxs("div",{className:"text-muted-foreground",children:[L.applied," change",L.applied===1?"":"s",L.rejected>0&&` · ${L.rejected} rejected`," ","· ",(L.ms/1e3).toFixed(0)," s"]}),L.warnings.map((s,t)=>e.jsx("div",{className:"text-orange-600",children:s},t))]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Moves, resizes, adds and removes the labelled boxes on this floor. The camera stays where it is. Around 30â100 s per instruction."})]}),K==="model"&&r&&e.jsxs(y,{className:"space-y-3 p-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("div",{className:"text-sm font-medium",children:"Render this view"}),e.jsx(be,{variant:"secondary",children:"clay â photo"})]}),e.jsx("div",{className:"grid grid-cols-2 gap-1 rounded-md bg-muted p-1 text-xs",children:["interior","edit"].map(s=>e.jsx("button",{type:"button",onClick:()=>$s(s),className:S("rounded px-2 py-1 font-medium",I===s?"bg-background shadow-sm":"text-muted-foreground"),children:s==="interior"?"Restyle":"Photo Enhance"},s))}),I==="interior"?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Style"}),e.jsxs(Z,{value:Pe,onValueChange:Ls,children:[e.jsx(ee,{className:"h-8",children:e.jsx(se,{})}),e.jsx(te,{children:Qe.map(s=>e.jsx(ae,{value:s.id,children:s.name},s.id))})]})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Room"}),e.jsxs(Z,{value:Re,onValueChange:Es,children:[e.jsx(ee,{className:"h-8",children:e.jsx(se,{})}),e.jsx(te,{children:Je.map(s=>e.jsx(ae,{value:s.value,children:s.label},s.value))})]})]})]}):e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Preset"}),e.jsxs(Z,{value:Me,onValueChange:Fs,children:[e.jsx(ee,{className:"h-8",children:e.jsx(se,{})}),e.jsx(te,{children:Ke.map(s=>e.jsx(ae,{value:s.id,children:s.name},s.id))})]})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Custom prompt"}),e.jsx(ms,{value:$e,onChange:s=>Is(s.target.value),placeholder:"Walnut floor, black window frames, a large linen sofa where the box isâ¦",rows:3,className:"text-xs"})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Quality"}),e.jsxs(Z,{value:Le,onValueChange:s=>Os(s),children:[e.jsx(ee,{className:"h-8",children:e.jsx(se,{})}),e.jsx(te,{children:St.map(s=>e.jsx(ae,{value:s.id,children:s.label},s.id))})]})]}),e.jsxs(f,{className:"w-full",onClick:()=>void ns(),disabled:H,children:[H?e.jsx(X,{className:"mr-2 h-4 w-4 animate-spin"}):e.jsx(is,{className:"mr-2 h-4 w-4"}),H?"Workingâ¦":"Render this view"]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Captures the current camera with fixture name tags on and room labels off, then sends the clay image through the production prompt builder. No credits, no library entry. Pro and 4K take up to a minute."}),e.jsxs(ps,{open:Ee,onOpenChange:Ts,children:[e.jsx(fs,{asChild:!0,children:e.jsxs(f,{variant:"ghost",size:"sm",className:"px-2",children:[e.jsx(ds,{className:S("mr-1 h-4 w-4 transition-transform",Ee&&"rotate-180")}),"Prompt preview"]})}),e.jsx(gs,{children:e.jsx("pre",{className:"max-h-56 overflow-auto whitespace-pre-wrap rounded bg-muted p-2 text-[10px] leading-snug",children:pe.isLoading?"Buildingâ¦":pe.error?pe.error.message:pe.data})})]})]}),K==="model"&&ie&&e.jsxs(y,{className:"space-y-1 p-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("div",{className:"text-sm font-medium",children:ie.label}),e.jsx(be,{variant:"secondary",children:ie.kind})]}),e.jsx("ul",{className:"text-xs text-muted-foreground",children:ie.details.map((s,t)=>e.jsx("li",{children:s},t))})]}),z.length>0&&e.jsxs(y,{className:"space-y-2 p-4",children:[e.jsxs("div",{className:"text-sm font-medium",children:["Renders (",z.length,")"]}),e.jsx("div",{className:"grid grid-cols-2 gap-2",children:z.map(s=>e.jsxs("div",{className:"group relative overflow-hidden rounded-md border",children:[e.jsx("a",{href:s.imageUrl,target:"_blank",rel:"noreferrer",children:e.jsx("img",{src:s.imageUrl,alt:rs(s),className:"aspect-[4/3] w-full object-cover"})}),e.jsx("a",{href:s.snapshotUrl,target:"_blank",rel:"noreferrer",title:"Clay input",className:"absolute left-1 top-1 h-8 w-10 overflow-hidden rounded border bg-white/80",children:e.jsx("img",{src:s.snapshotUrl,alt:"",className:"h-full w-full object-cover"})}),e.jsx(f,{size:"icon",variant:"secondary",className:"absolute right-1 top-1 h-6 w-6 opacity-0 group-hover:opacity-100",onClick:()=>W(t=>t.filter(a=>
6a.id!==s.id)),title:"Remove",children:e.jsx(Ae,{className:"h-3 w-3"})}),e.jsxs("div",{className:"truncate px-1.5 py-1 text-[10px] text-muted-foreground",title:s.prompt,children:[rs(s)," · ",s.settings.outputQuality," ·"," ",(s.ms/1e3).toFixed(0)," s"]})]},s.id))})]}),e.jsxs(y,{className:"space-y-2 p-4",children:[e.jsx("div",{className:"text-sm font-medium",children:"Layers (2D)"}),e.jsx("div",{className:"grid grid-cols-2 gap-2",children:ws.map(s=>{const t=r?$t(r.plan,s.key):null;return e.jsxs("label",{className:"flex cursor-pointer items-center gap-2 text-sm",children:[e.jsx(hs,{checked:Se[s.key],onCheckedChange:a=>Ss(n=>({...n,[s.key]:a===!0}))}),e.jsx("span",{className:"inline-block h-2.5 w-2.5 rounded-full",style:{background:s.color}}),s.label,t!=null&&e.jsx("span",{className:"ml-auto text-xs text-muted-foreground",children:t})]},s.key)})})]}),le.length>0&&p&&e.jsxs(y,{className:"space-y-2 p-4",children:[e.jsxs("div",{className:"text-sm font-medium",children:["Runs · ",g==null?void 0:g.label]}),e.jsx("div",{className:"space-y-1",children:le.map(s=>e.jsxs("button",{type:"button",onClick:()=>{$(p,{activeRunId:s.id}),de(null)},className:S("flex w-full items-center justify-between rounded-md border px-2.5 py-1.5 text-left text-xs",s.id===oe?"border-primary bg-primary/5":"border-transparent hover:bg-muted"),children:[e.jsx("span",{className:"font-medium",children:s.model}),e.jsxs("span",{className:"text-muted-foreground",children:[(s.ms/1e3).toFixed(1)," s ·"," ",s.plan.walls.length,"w / ",s.plan.doors.length,"d /"," ",s.plan.windows.length,"win"]})]},s.id))})]}),r&&e.jsxs(y,{className:"space-y-3 p-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("div",{className:"text-sm font-medium",children:"Run"}),e.jsx(be,{variant:"secondary",children:r.model})]}),e.jsxs("dl",{className:"grid grid-cols-2 gap-x-3 gap-y-1 text-xs",children:[e.jsx("dt",{className:"text-muted-foreground",children:"Time"}),e.jsxs("dd",{children:[(r.ms/1e3).toFixed(1)," s"]}),e.jsx("dt",{className:"text-muted-foreground",children:"Tokens in / out"}),e.jsxs("dd",{children:[r.usage.inputTokens," /"," ",r.usage.outputTokens,r.usage.reasoningTokens>0&&` (${r.usage.reasoningTokens} thinking)`]}),e.jsx("dt",{className:"text-muted-foreground",children:"Image"}),e.jsxs("dd",{children:[r.width," à ",r.height," px"]}),r.plan.floorLabel&&e.jsxs(e.Fragment,{children:[e.jsx("dt",{className:"text-muted-foreground",children:"Storey read"}),e.jsxs("dd",{children:[r.plan.floorLabel,typeof r.plan.floorLevel=="number"&&` (level ${r.plan.floorLevel})`]})]})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-xs font-medium",children:"Rooms"}),e.jsx("ul",{className:"max-h-48 space-y-0.5 overflow-auto text-xs",children:r.plan.rooms.map((s,t)=>e.jsxs("li",{className:"flex justify-between gap-2",children:[e.jsx("span",{className:"truncate",children:s.name}),e.jsx("span",{className:"shrink-0 text-muted-foreground",children:R?`${R.areaM2(s.polygon).toFixed(1)} m²`:""})]},t))})]}),e.jsxs(ps,{open:Ve,onOpenChange:Ps,children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(fs,{asChild:!0,children:e.jsxs(f,{variant:"ghost",size:"sm",className:"px-2",children:[e.jsx(ds,{className:S("mr-1 h-4 w-4 transition-transform",Ve&&"rotate-180")}),"Raw JSON"]})}),e.jsxs(f,{variant:"ghost",size:"sm",onClick:()=>{navigator.clipboard.writeText(JSON.stringify({scale:{...r.scale,pixelsPerMeter:_},...r.plan},null,2)).then(()=>j.success("Plan JSON copied")).catch(()=>j.error("Copy failed"))},children:[e.jsx(Nt,{className:"mr-1 h-4 w-4"}),"Copy"]})]}),e.jsx(gs,{children:e.jsx("pre",{className:"max-h-72 overflow-auto rounded bg-muted p-2 text-[10px] leading-tight",children:JSON.stringify(r.plan,null,2)})})]})]}),e.jsxs(y,{className:"space-y-2 p-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("div",{className:"text-sm font-medium",children:"Saved plans"}),e.jsxs(f,{size:"sm",variant:"ghost",className:"h-7 px-2",onClick:()=>{var s;return(s=w.current)==null?void 0:s.click()},children:[e.jsx(Ct,{className:"mr-1 h-4 w-4"}),"Import"]}),e.jsx("input",{ref:w,type:"file",accept:"application/json,.json",className:"hidden",onChange:s=>{var a;const t=(a=s.target.files)==null?void 0:a[0];t&&Vs(t),s.target.value=""}})]}),De.length===0?e.jsx("p",{className:"text-xs text-muted-foreground",children:"Nothing saved yet. Plans save automatically in this browser once uploaded."}):e.jsx("ul",{className:"max-h-64 space-y-1 overflow-auto",children:De.map(s=>e.jsxs("li",{className:S("flex items-center gap-2 rounded-md border px-2 py-1.5 text-xs",s.id===x?"border-primary bg-primary/5":"border-transparent hover:bg-muted"),children:[e.jsx("img",{src:s.imageUrl,alt:"",className:"h-8 w-10 shrink-0 rounded object-cover"}),e.jsxs("button",{type:"button",className:"min-w-0 flex-1 text-left",onClick:()=>
6void ts(s.id),children:[e.jsx("span",{className:"block truncate font-medium",children:s.name}),e.jsxs("span",{className:"block text-muted-foreground",children:[s.floorCount," floor",s.floorCount===1?"":"s"," ","· ",s.runCount," run",s.runCount===1?"":"s",s.renderCount>0&&` · ${s.renderCount} render${s.renderCount===1?"":"s"}`," ","· ",new Date(s.updatedAt).toLocaleDateString()]})]}),s.id!==x&&e.jsx(f,{size:"icon",variant:"ghost",className:"h-7 w-7 shrink-0",onClick:()=>void ts(s.id),title:"Open",children:e.jsx(kt,{className:"h-3.5 w-3.5"})}),e.jsx(f,{size:"icon",variant:"ghost",className:"h-7 w-7 shrink-0 text-muted-foreground hover:text-destructive",onClick:()=>void zs(s.id),title:"Delete from this browser",children:e.jsx(Ae,{className:"h-3.5 w-3.5"})})]},s.id))})]})]})]})]})})})};export{ca as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.