1const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/vendor-sweetalert-CRdFYMG-.js","assets/vendor-sweetalert-CNWhCx-c.css","assets/AssistantPanel-CpypnVsz.js","assets/vendor-react-DVrBU6_x.js","assets/wrench-OWDPItrK.js","assets/square-eZWa-Jut.js","assets/vendor-d3-CGnuPtl4.js","assets/vendor-duckdb-DncbAeEm.js","assets/Timeline-FzdYx3uT.js","assets/deploymentYears-CPD6el1W.js","assets/MapPanel-BCnzR17w.js","assets/vendor-maplibre-Bs2b5MJ0.js","assets/vendor-maplibre-DjAR36at.css","assets/ChartsPanel-B6VoBFMO.js","assets/DecisionTrailPanel-BeHSF_3E.js","assets/ScenarioExplanationPanel-BxDRobpi.js","assets/BuildingTable-CBMD9IlM.js","assets/BuildingTable-B7wBF6i4.css","assets/api-CVce_W2q.js","assets/supabase-Bv9-lbLI.js","assets/vendor-supabase-CZFTDb9k.js","assets/index-CDGEgwxr.js"])))=>i.map(i=>d[i]); 2import{r as N,j as s,R as ze,a as Fi}from"./vendor-react-DVrBU6_x.js";import{p as yn,s as Bi,l as Ui,a as zn,b as We,c as ei,m as Hi,d as ti,e as Pn,f as ni,g as wt,h as Vi,i as Yi,j as ri}from"./vendor-d3-CGnuPtl4.js";import"./vendor-sweetalert-CRdFYMG-.js";import{X as Wi,f as qi,A as zi,w as Gi,e as Ki,d as Zi,m as Ji,b as Xi}from"./vendor-duckdb-DncbAeEm.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))r(i);new MutationObserver(i=>{for(const a of i)if(a.type==="childList")for(const o of a.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(i){const a={};return i.integrity&&(a.integrity=i.integrity),i.referrerPolicy&&(a.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?a.credentials="include":i.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function r(i){if(i.ep)return;i.ep=!0;const a=n(i);fetch(i.href,a)}})();const ii="laep-dashboard:assistant-settings:v1",Qi="laep-dashboard:assistant-mock",ea=[{id:"anthropic",label:"Anthropic (Claude)"},{id:"openai",label:"OpenAI"}],ta=[{id:"claude-opus-4-8",label:"Claude Opus 4.8",hint:"Most capable â $5/$25 per MTok"},{id:"claude-haiku-4-5",label:"Claude Haiku 4.5",hint:"Fast & cheap â $1/$5 per MTok"}],na="gpt-5.1",at=Object.freeze({provider:"anthropic",apiKey:"",model:ta[0].id,baseUrl:""});function ai(e){const t=String(e||"").trim();return t?t.replace(/\/+$/,""):""}function Gn(){try{return typeof window<"u"?window.localStorage:null}catch{return null}}function ra(){const e=Gn();if(!e)return{...at};try{const t=e.getItem(ii);if(!t)return{...at};const n=JSON.parse(t);if(!n||typeof n!="object")return{...at};const r=ea.some(i=>i.id===n.provider)?n.provider:at.provider;return{provider:r,apiKey:typeof n.apiKey=="string"?n.apiKey:"",model:typeof n.model=="string"&&n.model.trim()?n.model.trim():r==="openai"?na:at.model,baseUrl:ai(n.baseUrl)}}catch{return{...at}}}function jc(e){const t=Gn();if(!t)return null;const n={provider:e.provider,apiKey:e.apiKey||"",model:e.model||"",baseUrl:ai(e.baseUrl),updatedAt:new Date().toISOString()};try{return t.setItem(ii,JSON.stringify(n)),n}catch{return null}}const ia="assistant",aa="demo";function oi(){if(typeof window>"u")return!1;try{return new URLSearchParams(window.location.search).get(ia)===aa}catch{return!1}}function oa(){return oi(),!1}function sa(){const e=Gn();if(!e)return!1;try{return e.getItem(Qi)==="1"}catch{return!1}}const It="weights",Oe="columns",ir=Object.freeze({type:It,columns:[]});function ar(e,t){if(!e||typeof t!="string"||t==="")return null;let n=e;for(const r of t.split(".")){if(n==null||typeof n!="object")return null;n=n[r]}return n===void 0?null:n}function la(e,t){if(typeof e=="number"&&typeof t=="number")return e-t;const n=Number(e),r=Number(t),i=Number.isFinite(n)&&String(e).trim()!=="",a=Number.isFinite(r)&&String(t).trim()!=="";return i&&a?n-r:String(e).localeCompare(String(t))}function ca(e){const t=(Array.isArray(e)?e:[]).filter(n=>n&&typeof n.field=="string"&&n.field!=="").map(n=>({field:n.field,desc:n.dir==="desc"}));return t.length?(n,r)=>{for(const{field:i,desc:a}
2of t){const o=ar(n,i),l=ar(r,i),c=o==null||o==="",d=l==null||l==="";if(c&&d)continue;if(c)return 1;if(d)return-1;const p=la(o,l);if(p!==0)return a?-p:p}return 0}:null}function Kn(e){if(!e||typeof e!="object")return{...ir};if(e.type!==Oe)return{...ir};const t=(Array.isArray(e.columns)?e.columns:[]).filter(n=>n&&typeof n.field=="string"&&n.field!=="").map(n=>({field:n.field,dir:n.dir==="asc"?"asc":"desc"}));return{type:Oe,columns:t}}function da(e){const t=Kn(e);return t.type!==Oe||!t.columns.length?"weighted score":t.columns.map(n=>`${n.field} ${n.dir}`).join(", ")}const si=1,or={type:"user",id:"local-user",label:"Dashboard user"},ua=Object.freeze({budget:!0,history:!0,carbon:!0,demand:!0}),pa=Object.freeze({carbonSavingPotential:.5,fuelPovertyScore:.3,gridCapacityEfficiency:.2}),Gt=Object.freeze({label:"Name",name:"Name",tech:"Technology",profile:"Building profile",budget:"Budget",startYear:"Start year",duration:"Duration",timing:"Timing",strategy:"Priority method",weights:"Priority weights",prioritisation:"Prioritisation",targetEPC:"Target EPC",pluginConfig:"Result layers",budgetAllocations:"Budget allocation",index:"Plan order",direction:"Direction"}),ma=new Set(["strategy","weights","targetEPC","prioritisation"]),sn=new Set(["scenario.saved","scenario.loaded","scenario.imported","scenario.exported"]);function ln(e="id"){return`${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`}function nt(e="prov"){return ln(e)}function fa(e){return Array.isArray(e)?{count:e.length}:e&&typeof e=="object"?e:e??null}function Zt(e){const t=Number(e);return Number.isFinite(t)?Math.abs(t)>=1e6?`£${(t/1e6).toFixed(1)}M`:Math.abs(t)>=1e3?`£${(t/1e3).toFixed(0)}k`:`£${t.toLocaleString()}`:null}function sr(e){if(e==null)return"none";if(Array.isArray(e))return`${e.length} item${e.length===1?"":"s"}`;if(typeof e!="object")return String(e);if(e.count!=null)return`${e.count} item${Number(e.count)===1?"":"s"}`;if(e.name)return String(e.name);if(e.label)return String(e.label);if(e.type)return e.type==="selection"?`selection (${Array.isArray(e.uprns)?e.uprns.length:e.count||"custom"} buildings)`:String(e.type);const t=Object.entries(e).filter(([,n])=>n!==!1&&n!=null);return t.length?t.slice(0,3).map(([n,r])=>`${n}: ${typeof r=="number"?Math.round(r*100)/100:String(r)}`).join(", "):"none"}function ha(e){return!e||typeof e!="object"?"none":Object.entries(e).filter(([,t])=>Number.isFinite(Number(t))&&Number(t)>0).sort((t,n)=>Number(n[1])-Number(t[1])).slice(0,3).map(([t,n])=>`${Gt[t]||t}: ${Math.round(Number(n)*100)}%`).join(", ")||"none"}function ga(e){if(!Array.isArray(e)||!e.length)return"even annual split";const t=e.reduce((a,o)=>a+(Number(o?.budget)||0),0),n=e.reduce((a,o)=>{const l=Number(o?.budget)||0;return!a||l>a.budget?{year:o.year,budget:l}:a},null),r=Zt(t)||"custom",i=n?`${Zt(n.budget)} peak in ${n.year}`:"custom curve";return`${r} custom curve, ${i}`}function Rt(e,t){if(e==="budget")return Zt(t)||"not set";if(e==="weights")return ha(t);if(e==="prioritisation")return da(t);if(e==="pluginConfig"){if(!t||typeof t!="object")return"none";const n=Object.entries(t).filter(([,r])=>r).map(([r])=>r);return n.length?n.join(", "):"none"}return e==="budgetAllocations"?ga(t):e==="profile"?sr(t):e==="index"?Number.isFinite(Number(t))?`position ${Number(t)+1}`:"unknown":t==null||t===""?"not set":typeof t=="object"?sr(t):String(t)}function ya(e={},t={}){const n=Number(e.startYear),r=Number(e.duration),i=Number(t.startYear),a=Number(t.duration),o=n+r-1,l=i+a-1;return!Number.isFinite(o)||!Number.isFinite(l)?null:`Timing ${n}-${o} to ${i}-${l}`}function bn(e,t){return JSON.stringify(e??null)!==JSON.stringify(t??null)}function ba(e={},t={}){const n=new Set([...Object.keys(e||{}),...Object.keys(t||{})]),r=[];if((n.has("startYear")||n.has("duration"))&&(bn(e.startYear,t.startYear)||bn(e.duration,t.duration))){const a=ya(e,t);r.push({key:"timing",label:Gt.timing,before:{startYear:e.startYear,duration:e.duration},after:{startYear:t.startYear,duration:t.duration},beforeLabel:a?`${e.startYear}-${Number(e.startYear)+Number(e.duration)-1}`:Rt("startYear",e.startYear),afterLabel:a?`${t.startYear}-${Number(t.startYear)+Number(t.duration)-1}`:Rt("startYear",t.startYear),summary:a||"Timing changed"})}n.delete("startYear"),n.delete("duration");for(const a of n){if(!bn(e?.[a],t?.[a]))continue;const o=Rt(a,e?.[a]),l=Rt(a,t?.[a]);r.push({key:a,label:Gt[a]||a,before:e?.[a]??null,after:t?.[a]??null,beforeLabel:o,afterLabel:l,summary:`${Gt[a]||a} ${o} to ${l}`})}return r}function li(e=""){return sn.has(e)?"storage":e==="simulation.ran"?"simulation":e.startsWith("scenario.")||e.startsWith("session.")?"lineage":e.startsWith("intervention.")||e.startsWith("profile.")||e.startsWith("computed-field.")?"edit":"activity"}function va(e="",t={}){if(t.workflowStage)return t.workflowStage;if(e==="simulation.ran")return"run-simulation";if(sn.has(e))return"inspect-save";if(e.startsWith("profile.")||e.startsWith("computed-field."))return"refine-buildings";if(e.startsWith("intervention.")){const n=(t.changedFields||[]).map(r=>r.key);return n.length&&n.every(r=>ma.has(r))?"set-priority":"define-intervention"}return"set-area"}
2function xa(e="",t={}){if(e==="simulation.ran"){const n=t.results||{},r=Number(n.finalBuildingsCount??n.rawResultsCount);return Number.isFinite(r)?`${r.toLocaleString()} building result${r===1?"":"s"} captured`:"Simulation output captured"}return e==="intervention.updated"&&t.changedFields?.length?`${t.changedFields.length} field${t.changedFields.length===1?"":"s"} changed; simulation marked stale`:e==="intervention.added"||e==="intervention.deleted"?"Scenario simulation marked stale":e==="intervention.reordered"?"Intervention order changed; simulation marked stale":e==="profile.created"?"Reusable building cohort captured":e==="profile.updated"?"Building cohort definition changed":e==="scenario.versioned"?"New scenario version created from the parent pathway":e==="scenario.branched"?"Alternative pathway created from the parent scenario":sn.has(e)?"Persistence checkpoint recorded":null}function Sa(e="",t={}){const n=t.label||t.after?.label||t.before?.label||t.name||t.scenarioName,r=t.changedFields||[];if(e==="intervention.added"){const i=t.after||{},a=[i.tech?`${i.tech}`:null,Zt(i.budget),i.startYear&&i.duration?`${i.startYear}-${Number(i.startYear)+Number(i.duration)-1}`:null].filter(Boolean);return[`Added ${n||"intervention"}${a.length?` (${a.join(", ")})`:""}`]}if(e==="intervention.updated")return r.length?r.slice(0,4).map(i=>i.summary):[`Updated ${n||"intervention"}`];if(e==="intervention.deleted")return[`Removed ${n||"intervention"}`];if(e==="intervention.reordered"){const i=t.before?.index,a=t.after?.index;return Number.isFinite(Number(i))&&Number.isFinite(Number(a))?[`Moved ${n||"intervention"} from position ${Number(i)+1} to ${Number(a)+1}`]:[`Reordered ${n||"intervention"}`]}if(e==="profile.created"){const i=t.after?.uprns?.count??t.after?.count;return[`Created ${n||t.name||"building profile"}${i?` with ${i} building${Number(i)===1?"":"s"}`:""}`]}if(e==="profile.updated")return r.length?r.slice(0,4).map(i=>i.summary):[`Updated ${n||t.name||"building profile"}`];if(e==="scenario.renamed")return r.length?r.map(i=>i.summary):["Scenario renamed"];if(e==="scenario.versioned"||e==="scenario.branched")return[t.changeSummary||t.versionLabel||"Lineage checkpoint recorded"];if(e==="simulation.ran"){const i=Number(t.interventionCount);return[Number.isFinite(i)?`Ran model with ${i} intervention${i===1?"":"s"}`:"Simulation executed"]}return sn.has(e)?[t.storageMode?`Storage mode: ${t.storageMode}`:t.source?`Source: ${t.source}`:"Scenario bundle checkpoint"]:[]}function wa(e,t={},n=ln("decision")){const r=t.before||null,i=t.after||null,a=t.changedFields||(r&&i?ba(r,i):[]),o={...t,decisionId:t.decisionId||n,episodeType:t.episodeType||li(e),source:t.source||"dashboard",changedFields:a};return o.workflowStage=va(e,o),o.diffSummary=t.diffSummary||Sa(e,o),o.impactSummary=t.impactSummary??xa(e,o),o}function kt(e){if(!e||typeof e!="object")return e??null;const{finalBuildings:t,rawResults:n,...r}=e;return{...r,finalBuildingsCount:Array.isArray(t)?t.length:r.finalBuildingsCount??0,rawResultsCount:Array.isArray(n)?n.length:r.rawResultsCount??0}}function _a(e,t=0){if(!e||typeof e!="object")return e;const n=e.tech||"ASHP",r=Number.isFinite(Number(e.startYear))?Number(e.startYear):2026,i=Number.isFinite(Number(e.duration))?Math.min(10,Math.max(1,Number(e.duration))):3,a=Number.isFinite(Number(e.budget))?Math.max(0,Number(e.budget)):4e6;return{...e,id:e.id||ln("intv"),label:e.label||`${n} Intervention ${t+1}`,tech:n,profile:e.profile?.type?e.profile:{type:"all"},strategy:e.strategy||"multi-objective",startYear:r,duration:i,budget:a,weights:{...pa,...e.weights||{}},targetEPC:e.targetEPC||"Any",status:e.status||"planned",prioritisation:Kn(e.prioritisation),pluginConfig:{...ua,...e.pluginConfig||{}}}}function tt(e){if(!e||typeof e!="object")return e;const t=e.provenanceId||nt("scenario-prov");return{...e,provenanceId:t,lineageRootProvenanceId:e.lineageRootProvenanceId||e.parentScenarioProvenanceId||t,parentScenarioProvenanceId:e.parentScenarioProvenanceId||null,branchName:e.branchName||e.name||"Untitled scenario",ver
2sionNumber:Number.isFinite(Number(e.versionNumber))?Number(e.versionNumber):1,versionLabel:e.versionLabel||`v${Number.isFinite(Number(e.versionNumber))?Number(e.versionNumber):1}`,changeSummary:e.changeSummary||null,forkedFromEventId:e.forkedFromEventId||null,interventions:Array.isArray(e.interventions)?e.interventions.map((n,r)=>_a(n,r)):[],profiles:Array.isArray(e.profiles)?e.profiles:[],results:kt(e.results)}}function Rn(e){return!e||typeof e!="object"?e:{...e,provenanceId:e.provenanceId||nt("session-prov"),computedFields:Array.isArray(e.computedFields)?e.computedFields:[]}}function Na(e,t={}){const n=t.name||t.after?.name||t.before?.name||t.scenarioName,r=t.label||t.after?.label||t.before?.label||t.interventionLabel,i=Array.isArray(t.diffSummary)?t.diffSummary[0]:null;switch(e){case"session.created":return`Created session "${n||"Untitled session"}"`;case"scenario.created":return`Created scenario "${n||"Untitled scenario"}"`;case"scenario.versioned":return`Saved new version "${n||"Untitled scenario"}"${t.changeSummary?`: ${t.changeSummary}`:""}`;case"scenario.branched":return`Branched scenario "${n||"Untitled scenario"}"${t.changeSummary?`: ${t.changeSummary}`:""}`;case"scenario.renamed":return`Renamed scenario from "${t.before?.name||"Untitled"}" to "${t.after?.name||n||"Untitled"}"`;case"scenario.deleted":return`Deleted scenario "${n||"Untitled scenario"}"`;case"scenario.saved":return`Saved scenario "${n||"Untitled scenario"}"`;case"scenario.loaded":return"Loaded scenario data";case"scenario.imported":return"Imported scenario bundle";case"scenario.exported":return"Exported scenario bundle";case"intervention.added":return i||`Added intervention "${r||"Untitled intervention"}"`;case"intervention.updated":return i?`${r||"Intervention"} updated: ${i}`:`Updated intervention "${r||"Untitled intervention"}"`;case"intervention.deleted":return i||`Deleted intervention "${r||"Untitled intervention"}"`;case"intervention.reordered":return i||`Reordered intervention "${r||"Untitled intervention"}"`;case"profile.created":return i||`Created building profile "${n||"Untitled profile"}"`;case"profile.updated":return i||`Updated building profile "${n||"Untitled profile"}"`;case"computed-field.created":return`Created computed field "${n||"Untitled field"}"`;case"computed-field.updated":return i||`Updated computed field "${n||"Untitled field"}"`;case"computed-field.deleted":return`Deleted computed field "${n||"Untitled field"}"`;case"simulation.ran":return`Ran simulation${t.currentYear?` for ${t.currentYear}`:""}`;default:return e.replace(/\./g," ")}}function D({id:e,timestamp:t,activity:n,agent:r=or,session:i=null,scenario:a=null,sessionId:o,scenarioId:l,scenarioProvenanceId:c,entityType:d="scenario",entityId:p,used:f=[],generated:u=[],payload:m={},summary:h,appVersion:b="0.1.0"}={}){if(!n)throw new Error("createProvenanceEvent requires an activity");const S=e||ln("prov-event"),w=o??i?.id??null,k=l??a?.id??null,E=c??a?.provenanceId??k??null,x=p??k??w??null,_=wa(n,fa(m)||{},S);return{schemaVersion:si,id:S,timestamp:t||new Date().toISOString(),activity:n,agent:r||or,sessionId:w,scenarioId:k,scenarioProvenanceId:E,entityType:d,entityId:x,used:Array.isArray(f)?f:[],generated:Array.isArray(u)?u:[],payload:_,summary:h||Na(n,_),appVersion:b}}const Zn="2026-08-25-annual-energy-cost",_e="session-default",Ca="session-prov-default",$n="scenario-demo-heat-v1",ci="2026-06-01T09:00:00.000Z",ce={budget:!0,history:!0,carbon:!0,demand:!0},vn={type:"all"},Ce=e=>({type:"predefined",predefinedId:e}),$t=({prioritisation:e,...t})=>t,Mt=(e,t)=>t.map((n,r)=>({year:e+r,budget:n})),Ie=[{id:"demo-cfield-cost-effectiveness",name:"costEffectivenessRatio",label:null,expression:"estimatedCost.ASHP / annualEnergyCost",createdAt:"2026-06-02T09:05:00.000Z"},{id:"demo-cfield-fuel-poor-target",name:"fuelPoorTarget",label:null,expression:"fuelPoorPct > 20 and epc >= 'D' and epc <= 'G'",createdAt:"2026-06-01T09:10:00.000Z"}],O={id:_e,provenanceId:Ca,name:"Winchester City Council",description:"Local demo workspace with preloaded LAEP pathways.",createdAt:ci,computedFields:Ie,source:"local"},lr={type:"columns",columns:[{field:"costEffectivenessRatio",dir:"asc"},{field:"fuelPoorPct",dir:"desc"}]},g=[{id:"scenario-demo-cost-v1",provenanceId:"scenario-prov-demo-cost-v1",lineageRootProvenanceId:"scenario-prov-demo-cost-v1",parentScenarioProvenanceId:null,branchName:"Cost-Effective Renewables",versionNumber:1,versionLabel:"v1",changeSummary:null,forkedFromEventId:null,sessionId:_e,name:"Cost-Effective Renewables",description:"Prioritises high-yield rooftop PV, then fills the best mixed-retrofit opportunities.",interventions:[{id:"demo-cost-pv",label:"High-yield rooftop PV",tech:"PV",profile:Ce("pv-potential-top-10"),strategy:"cost-effective",startYear:2026,duration:6,budget:12e6,weights:{carbonSavingPotential:.78,fuelPovertyScore:.04,gridCapacityEfficiency:.18},targetEPC:"Any",color:"amber",status:"planned",pluginConfig:ce},{id:"demo-cost-mixed",label:"Mixed retrofit follow-on",tech:"Mixed",profile:Ce("carbon-top-10"),strategy:"cost-effective",startYear:2029,duration:4,budget:85e5,weights:{carbonSavingPotential:.64,fuelPovertyScore:.12,gridCapacityEfficiency:.2},targetEPC:"D",color:"slate",status:"planned",pluginConfig:ce}],profiles:[{id:"demo-profile-cost-fuel-poor",name:"Fuel-poor EPC D-G cohort",uprns:["10003001","10003002","10003003","10003004","10003005","10003006","10003007","10003008"]}],createdAt:ci,source:"local"},{id:"scenario-demo-cost-v2",provenanceId:"scenario-prov-demo-cost-v2",lineageRootProvenanceId:"scenario-prov-demo-cost-v1",parentScenarioProvenanceId:"scenario-prov-demo-cost-v1",branchName:"Cost-Effective Renewables",versionNumber:2,versionLabel:"v2",changeSummary:"Pulled ASHP work earlier after reviewing the first PV-only pass.",forkedFromEventId:"prov-event-demo-cost-versioned",sessionId:_e,name:"Cost-Effective Renewables v2",description:"A saved version of the renewables pathway with earlier heat-pump delivery.",interventions:[{id:"demo-cost-v2-pv",label:"High-yield rooftop PV",tech:"PV",profile:Ce("pv-potential-top-10"),strategy:"cost-effective",startYear:2026,duration:5,budget:145e5,weights:{carbonSavingPotential:.72,fuelPovertyScore:.04,gridCapacityEfficiency:.24},targetEPC:"Any",color:"amber",status:"planned",pluginConfig:ce},{id:"demo-cost-v2-ashp",label:"ASHP infill for high-carbon homes",tech:"ASHP",profile:Ce("carbon-top-10"),strategy:"multi-objective",startYear:2028,duration:6,budget:16e6,budgetAllocations:[{year:2028,budget:18e5},{year:2029,budget:22e5},{year:2030,budget:28e5},{year:2031,budget:32e5},{year:2032,budget:3e6},{year:2033,budget:3e6}],weights:{carbonSavingPotential:.52,fuelPovertyScore:.28,gridCapacityEfficiency:.12},prioritisation:lr,targetEPC:"E",color:"emerald",status:"planned",pluginConfig:ce}],profiles:[],createdAt:"2026-06-02T09:15:00.000Z",source:"local"},{id:"scenario-demo-equity-v1",provenanceId:"scenario-prov-demo-equity-v1",lineageRootProvenanceId:"scenario-prov-demo-cost-v1",parentScenarioProvenanceId:"scenario-prov-demo-cost-v1",branchName:"Fuel Poverty Alternative",versionNumber:1,versionLabel:"v1",changeSummary:"Alternative branch that gives fuel poverty the highest priority.",forkedFromEventId:"prov-event-demo-equity-branched",sessionId:_e,name:"Fuel Poverty Alternative",description:"Directs heat and solar spend toward the most fuel-deprived cohorts first.",interventions:[{id:"demo-equity-ashp",label:"Fuel-poor ASHP rollout",tech:"ASHP",profile:Ce("fuel-poor-top-25"),strategy:"equity-first",startYear:2026,duration:8,budget:18e6,weights:{carbonSavingPotential:.2,fuelPovertyScore:.66,gridCapacityEfficiency:.04},targetEPC:"D",color:"emerald",status:"planned",pluginConfig:ce},{id:"demo-equity-pv",label:"Community solar top-up",tech:"PV",profile:Ce("imd-most-deprived-10"),strategy:"equity-first",startYear:2027,duration:5,budget:65e5,weights:{carbonSavingPotential:.22,fuelPovertyScore:.48,gridCapacityEfficiency:.06},targetEPC:"Any",color:"amber",status:"planned",pluginConfig:ce}],profiles:[],createdAt:"2026-06-03T10:10:00.000Z",source:"local"},{id:"scenario-demo-heat-v1",provenanceId:"scenario-prov-demo-heat-v1",lineageRootProvenanceId:"scenario-prov-demo-cost-v1",parentScenarioProvenanceId:"scenario-prov-demo-cost-v2",branchName:"Heat Electrification Focus",versionNumber:1,versionLabel:"v1",changeSummary:"Branched from v2 to explore a heat-led policy extreme.",forkedFromEventId:"prov-event-demo-heat-branched",sessionId:_e,name:"Heat Electrification Focus",description:"Tests an aggressive switch to air and ground-source heat pumps.",interventions:[{id:"demo-heat-ashp",label:"ASHP mass deployment",tech:"ASHP",profile:vn,strategy:"multi-objective",startYear:2026,duration:7,budget:26e6,weights:{carbonSavingPotential:.48,fuelPovertyScore:.24,gridCapacityEfficiency:.2},targetEPC:"Any",color:"emerald",status:"planned",pluginConfig:ce},{id:"demo-heat-gshp",label:"GSHP community clusters",tech:"GSHP",profile:Ce("carbon-top-10"),strategy:"multi-objective",startYear:2029,duration:5,budget:14e6,weights:{carbonSavingPotential:.58,fuelPovertyScore:.1,gridCapacityEfficiency:.12},targetEPC:"Any",color:"indigo",status:"planned",pluginConfig:ce}],profiles:[],createdAt:"2026-06-04T09:05:00.000Z",source:"local"},{id:"scenario-demo-grid-v1",provenanceId:"scenario-prov-demo-grid-v1",lineageRootProvenanceId:"scenario-prov-demo-grid-v1",parentScenarioProvenanceId:null,branchName:"Grid-Constrained Solar",versionNumber:1,versionLabel:"v1",changeSummary:null,forkedFromEventId:null,sessionId:_e,name:"Grid-Constrained Solar",description:"A slower PV pathway with later hydrogen and district heat options for c
2omparison.",interventions:[{id:"demo-grid-pv",label:"Network-friendly PV tranche",tech:"PV",profile:Ce("pv-potential-top-10"),strategy:"grid-aware",startYear:2027,duration:9,budget:95e5,weights:{carbonSavingPotential:.38,fuelPovertyScore:.06,gridCapacityEfficiency:.54},targetEPC:"Any",color:"amber",status:"planned",pluginConfig:ce},{id:"demo-grid-district",label:"District heat ready zones",tech:"District Heating",profile:Ce("carbon-top-10"),strategy:"grid-aware",startYear:2030,duration:6,budget:175e5,weights:{carbonSavingPotential:.44,fuelPovertyScore:.16,gridCapacityEfficiency:.28},targetEPC:"Any",color:"sky",status:"planned",pluginConfig:ce},{id:"demo-grid-hydrogen",label:"Hydrogen boiler trial",tech:"Hydrogen",profile:vn,strategy:"pilot",startYear:2032,duration:3,budget:45e5,weights:{carbonSavingPotential:.34,fuelPovertyScore:.08,gridCapacityEfficiency:.44},targetEPC:"Any",color:"rose",status:"planned",pluginConfig:ce}],profiles:[],createdAt:"2026-06-05T09:10:00.000Z",source:"local"},{id:"scenario-demo-iterative-v1",provenanceId:"scenario-prov-demo-iterative-v1",lineageRootProvenanceId:"scenario-prov-demo-iterative-v1",parentScenarioProvenanceId:null,branchName:"Iterative Retrofit Workshop",versionNumber:1,versionLabel:"v1",changeSummary:null,forkedFromEventId:null,sessionId:_e,name:"Iterative Retrofit Workshop",description:"A deliberately exploratory workshop scenario used to demonstrate the full decision trail.",interventions:[{id:"demo-iterative-v1-ashp",label:"Baseline ASHP feasibility pass",tech:"ASHP",profile:vn,strategy:"multi-objective",startYear:2026,duration:4,budget:9e6,budgetAllocations:Mt(2026,[12e5,21e5,27e5,3e6]),weights:{carbonSavingPotential:.46,fuelPovertyScore:.24,gridCapacityEfficiency:.2},targetEPC:"Any",color:"emerald",status:"planned",pluginConfig:ce},{id:"demo-iterative-v1-pv",label:"Solar quick wins",tech:"PV",profile:Ce("pv-potential-top-10"),strategy:"cost-effective",startYear:2028,duration:3,budget:52e5,budgetAllocations:Mt(2028,[24e5,17e5,11e5]),weights:{carbonSavingPotential:.7,fuelPovertyScore:.06,gridCapacityEfficiency:.22},targetEPC:"Any",color:"amber",status:"planned",pluginConfig:ce}],profiles:[],results:{ranAt:"2026-06-05T09:55:00.000Z",yearly:{2026:{deployedBuildings:42,budgetSpent:17e5,carbonSaved:118},2027:{deployedBuildings:88,budgetSpent:23e5,carbonSaved:261},2028:{deployedBuildings:146,budgetSpent:315e4,carbonSaved:434}},finalBuildingsCount:146,rawResultsCount:146},createdAt:"2026-06-05T09:40:00.000Z",source:"local"},{id:"scenario-demo-iterative-v2",provenanceId:"scenario-prov-demo-iterative-v2",lineageRootProvenanceId:"scenario-prov-demo-iterative-v1",parentScenarioProvenanceId:"scenario-prov-demo-iterative-v1",branchName:"Iterative Retrofit Workshop",versionNumber:2,versionLabel:"v2",changeSummary:"Refined after the first model pass: fuel-poor heat first ordered by best cost-effectiveness ratio (computed field), PV pulled earlier, and GSHP clusters added.",forkedFromEventId:"prov-event-demo-iterative-versioned",sessionId:_e,name:"Iterative Retrofit Workshop v2",description:"A complete exploratory session with computed fields, column-sorted deployment, saved cohorts, priority edits, timing changes, simulation output, and persistence checkpoints.",interventions:[{id:"demo-iterative-v2-pv",label:"Grid-aware solar tranche",tech:"PV",profile:Ce("pv-potential-top-10"),strategy:"grid-aware",startYear:2026,duration:5,budget:115e5,budgetAllocations:Mt(2026,[34e5,28e5,21e5,17e5,15e5]),weights:{carbonSavingPotential:.46,fuelPovertyScore:.08,gridCapacityEfficiency:.36},targetEPC:"Any",color:"amber",status:"planned",pluginConfig:ce},{id:"demo-iterative-v2-ashp",label:"Fuel-poor heat pump core",tech:"ASHP",profile:{type:"saved",profileId:"demo-profile-fuel-poor-terraces"},strategy:"equity-first",startYear:2027,duration:6,budget:185e5,budgetAllocations:[{year:2027,budget:18e5},{year:2028,budget:25e5},{year:2029,budget:33e5},{year:2030,budget:37e5},{year:2031,budget:36e5},{year:2032,budget:36e5}],weights:{carbonSavingPotential:.28,fuelPovertyScore:.55,gridCapacityEfficiency:.06},prioritisation:lr,targetEPC:"E",color:"emerald",status:"planned",pluginConfig:ce},{id:"demo-iterative-v2-gshp",label:"GSHP conservation-area clusters",tech:"GSHP",profile:{type:"saved",profileId:"demo-profile-cluster-homes"},strategy:"multi-objective",startYear:2030,duration:4,budget:7e6,budgetAllocations:Mt(2030,[9e5,14e5,21e5,26e5]),weights:{carbonSavingPotential:.42,fuelPovertyScore:.18,gridCapacityEfficiency:.14},targetEPC:"D",color:"indigo",status:"planned",pluginConfig:ce}],profiles:[{id:"demo-profile-fuel-poor-terraces",name:"Fuel-poor terraces near central Winchester",uprns:["10001001","10001002","10001003","10001004","10001005","10001006","10001007","10001008"]},{id:"demo-profile-cluster-homes",name:"Conservation-area cluster candidates",uprns:["10002001","10002002","10002003","10002004","10002005"]}],results:{ranAt:"2026-06-05T10:30:00.000Z",yearly:{2026:{deployedBuildings:74,budgetSpent:21e5,carbonSaved:142},2027:{deployedBuildings:151,budgetSpent:405e4,carbonSaved:382},2028:{deployedBuildings:244,budgetSpent:62e5,carbonSaved:733},2029:{deployedBuildings:352,budgetSpent:75e5,carbonSaved:1156},2030:{deployedBuildings:438,budgetSpent:82e5,carbonSaved:1520}},finalBuildingsCount:438,rawResultsCount:438},createdAt:"2026-06-05T10:05:00.000Z",source:"local"}
2],di=[D({id:"prov-event-demo-session-created",timestamp:"2026-06-01T09:00:00.000Z",activity:"session.created",session:O,entityType:"session",entityId:O.id,payload:{name:O.name,description:O.description}}),D({id:"prov-event-demo-cost-created",timestamp:"2026-06-01T09:05:00.000Z",activity:"scenario.created",session:O,scenario:g[0],entityType:"scenario",entityId:g[0].id,generated:[{type:"scenario",id:g[0].id,provenanceId:g[0].provenanceId}],payload:{name:g[0].name,description:g[0].description,interventionCount:g[0].interventions.length}}),D({id:"prov-event-demo-cost-profile-created",timestamp:"2026-06-01T09:12:00.000Z",activity:"profile.created",session:O,scenario:g[0],entityType:"profile",entityId:"demo-profile-cost-fuel-poor",payload:{name:g[0].profiles[0].name,after:{...g[0].profiles[0],uprns:{count:g[0].profiles[0].uprns.length}},source:"building-table",uiContext:{surface:"building-table",selectionCount:g[0].profiles[0].uprns.length}}}),D({id:"prov-event-demo-cost-pv-added",timestamp:"2026-06-01T09:15:00.000Z",activity:"intervention.added",session:O,scenario:g[0],entityType:"intervention",entityId:"demo-cost-pv",payload:{label:g[0].interventions[0].label,after:g[0].interventions[0],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-cost-mixed-added",timestamp:"2026-06-01T09:24:00.000Z",activity:"intervention.added",session:O,scenario:g[0],entityType:"intervention",entityId:"demo-cost-mixed",payload:{label:g[0].interventions[1].label,after:g[0].interventions[1],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-cost-v1-simulated",timestamp:"2026-06-01T09:32:00.000Z",activity:"simulation.ran",session:O,scenario:g[0],entityType:"simulation",entityId:"2026-06-01T09:32:00.000Z",generated:[{type:"simulation-result",id:"2026-06-01T09:32:00.000Z"}],payload:{currentYear:2030,interventionCount:g[0].interventions.length,results:{finalBuildingsCount:56567,rawResultsCount:56567},source:"simulation-runner",uiContext:{surface:"scenario-rail"}}}),D({id:"prov-event-demo-cost-mixed-budget-trimmed",timestamp:"2026-06-01T10:05:00.000Z",activity:"intervention.updated",session:O,scenario:g[0],entityType:"intervention",entityId:"demo-cost-mixed",payload:{label:g[0].interventions[1].label,before:{...g[0].interventions[1],budget:95e5,duration:5},after:g[0].interventions[1],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-cost-reordered",timestamp:"2026-06-01T10:12:00.000Z",activity:"intervention.reordered",session:O,scenario:g[0],entityType:"intervention",entityId:"demo-cost-pv",payload:{label:g[0].interventions[0].label,direction:"up",before:{index:1},after:{index:0},source:"timeline",uiContext:{surface:"timeline"}}}),D({id:"prov-event-demo-cost-v1-resimulated",timestamp:"2026-06-01T10:18:00.000Z",activity:"simulation.ran",session:O,scenario:g[0],entityType:"simulation",entityId:"2026-06-01T10:18:00.000Z",generated:[{type:"simulation-result",id:"2026-06-01T10:18:00.000Z"}],payload:{currentYear:2030,interventionCount:g[0].interventions.length,results:{finalBuildingsCount:56567,rawResultsCount:56567},source:"simulation-runner",uiContext:{surface:"scenario-rail"}}}),D({id:"prov-event-demo-cost-versioned",timestamp:"2026-06-02T09:15:00.000Z",activity:"scenario.versioned",session:O,scenario:g[1],entityType:"scenario",entityId:g[1].id,used:[{type:"scenario",id:g[0].id,provenanceId:g[0].provenanceId}],generated:[{type:"scenario",id:g[1].id,provenanceId:g[1].provenanceId}],payload:{name:g[1].name,changeSummary:g[1].changeSummary,parentScenarioId:g[0].id,parentScenarioProvenanceId:g[0].provenanceId,versionLabel:g[1].versionLabel}}),D({id:"prov-event-demo-cost-v2-ashp-added",timestamp:"2026-06-02T09:22:00.000Z",activity:"intervention.added",session:O,scenario:g[1],entityType:"intervention",entityId:"demo-cost-v2-ashp",payload:{label:g[1].interventions[1].label,after:$t(g[1].interventions[1]),source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-cost-v2-pv-updated",timestamp:"2026-06-02T09:36:00.000Z",activity:"intervention.updated",session:O,scenario:g[1],entityType:"intervention",entityId:"demo-cost-v2-pv",payload:{label:g[1].interventions[0].label,before:{...g[1].interventions[0],budget:g[0].interventions[0].budget,duration:g[0].interventions[0].duration,weights:g[0].interventions[0].weights},after:g[1].interventions[0],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-cost-v2-ashp-prioritised",timestamp:"2026-06-02T09:44:00.000Z",activity:"intervention.updated",session:O,scenario:g[1],entityType:"intervention",entityId:"demo-cost-v2-ashp",payload:{label:g[1].interventions[1].label,before:$t(g[1].interventions[1]),after:g[1].interventions[1],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-cost-v2-simulated",timestamp:"2026-06-02T09:52:00.000Z",activity:"simulation.ran",session:O,scenario:g[1],entityType:"simulation",entityId:"2026-06-02T09:52:00.000Z",generated:[{type:"simulation-result",id:"2026-06-02T09:52:00.000Z"}],payload:{currentYear:2032,interventionCount:g[1].interventions.length,results:{finalBuildingsCount:56567,rawResultsCount:56567},source:"simulation-runner",uiContext:{surface:"scenario-rail"}}}),D({id:"prov-event-demo-cost-v2-saved",timestamp:"2026-06-02T09:58:00.000Z",activity:"scenario.saved",session:O,scenario:g[1],entityType:"scenario",entityId:g[1].id,payload:{scenarioName:g[1].name,storageMode:"browser-local",source:"scenario-rail",uiContext:{surface:"scenario-rail"}}}),D({id:"prov-event-demo-equity-branched",timestamp:"2026-06-03T10:10:00.000Z",activity:"scenario.branched",session:O,scenario:g[2],entityType:"scenario",entityId:g[2].id,used:[{type:"scenario",id:g[0].id,provenanceId:g[0].provenanceId}],generated:[{type:"scenario",id:g[2].id,provenanceId:g[2].provenanceId}],payload:{name:g[2].name,changeSummary:g[2].changeSummary,parentScenarioId:g[0].id,parentScenarioProvenanceId:g[0].provenanceId,versionLabel:g[2].versionLabel}}),D({id:"prov-event-demo-equity-ashp-added",timestamp:"2026-06-03T10:16:00.000Z",activity:"intervention.added",session:O,scenario:g[2],entityType:"intervention",entityId:"demo-equity-ashp",payload:{label:g[2].interventions[0].label,after:g[2].interventions[0],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-equity-pv-added",timestamp:"2026-06-03T10:22:00.000Z",activity:"intervention.added",session:O,scenario:g[2],entityType:"intervention",entityId:"demo-equity-pv",payload:{label:g[2].interventions[1].label,after:g[2].interventions[1],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-equity-simulated",timestamp:"2026-06-03T10:31:00.000Z",activity:"simulation.ran",session:O,scenario:g[2],entityType:"simulation",entityId:"2026-06-03T10:31:00.000Z",generated:[{type:"simulation-result",id:"2026-06-03T10:31:00.000Z"}],payload:{currentYear:2033,interventionCount:g[2].interventions.length,results:{finalBuildingsCount:56567,rawResultsCount:56567},source:"simulation-runner",uiContext:{surface:"scenario-rail"}}}),D({id:"prov-event-demo-heat-branched",timestamp:"2026-06-04T09:05:00.000Z",activity:"scenario.branched",session:O,scenario:g[3],entityType:"scenario",entityId:g[3].id,used:[{type:"scenario",id:g[1].id,provenanceId:g[1].provenanceId}],generated:[{type:"scenario",id:g[3].id,provenanceId:g[3].provenanceId}],payload:{name:g[3].name,changeSummary:g[3].changeSummary,parentScenarioId:g[1].id,parentScenarioProvenanceId:g[1].provenanceId,versionLabel:g[3].versionLabel}}),D({id:"prov-event-demo-heat-ashp-added",timestamp:"2026-06-04T09:14:00.000Z",activity:"intervention.added",session:O,scenario:g[3],entityType:"intervention",entityId:"demo-heat-ashp",payload:{label:g[3].interventions[0].label,after:g[3].interventions[0],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-heat-gshp-added",timestamp:"2026-06-04T09:26:00.000Z",activity:"intervention.added",session:O,scenario:g[3],entityType:"intervention",entityId:"demo-heat-gshp",payload:{label:g[3].interventions[1].label,after:g[3].interventions[1],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-heat-simulated",timestamp:"2026-06-04T09:40:00.000Z",activity:"simulation.ran",session:O,scenario:g[3],entityType:"simulation",entityId:"2026-06-04T09:40:00.000Z",generated:[{type:"simulation-result",id:"2026-06-04T09:40:00.000Z"}],payload:{currentYear:2033,interventionCount:g[3].interventions.length,results:{finalBuildingsCount:56567,rawResultsCount:56567},source:"simulation-runner",uiContext:{surface:"scenario-rail"}}}),D({id:"prov-event-demo-heat-gshp-retimed",timestamp:"2026-06-04T09:55:00.000Z",activity:"intervention.updated",session:O,scenario:g[3],entityType:"intervention",entityId:"demo-heat-gshp",payload:{label:g[3].interventions[1].label,before:{...g[3].interventions[1],startYear:2028,budget:12e6},after:g[3].interventions[1],source:"timeline",uiContext:{surface:"timeline"}}}),D({id:"prov-event-demo-heat-resimulated",timestamp:"2026-06-04T10:04:00.000Z",activity:"simulation.ran",session:O,scenario:g[3],entityType:"simulation",entityId:"2026-06-04T10:04:00.000Z",generated:[{type:"simulation-result",id:"2026-06-04T10:04:00.000Z"}],payload:{currentYear:2033,interventionCount:g[3].interventions.length,results:{finalBuildingsCount:56567,rawResultsCount:56567},source:"simulation-runner",uiContext:{surface:"scenario-rail"}}}),D({id:"prov-event-demo-heat-saved",timestamp:"2026-06-04T10:15:00.000Z",activity:"scenario.saved",session:O,scenario:g[3],entityType:"scenario",entityId:g[3].id,payload:{scenarioName:g[3].name,storageMode:"browser-local",source:"scenario-rail",uiContext:{surface:"scenario-rail"}}}),D({id:"prov-event-demo-grid-created",timestamp:"2026-06-05T09:10:00.000Z",activity:"scenario.created",session:O,scenario:g[4],entityType:"scenario",entityId:g[4].id,generated:[{type:"scenario",id:g[4].id,provenanceId:g[4].provenanceId}],payload:{name:g[4].name,description:g[4].description,interventionCount:g[4].interventions.length}}),D({id:"prov-event-demo-iterative-created",timestamp:"2026-06-05T09:40:00.000Z",activity:"scenario.created",session:O,scenario:g[5],entityType:"scenario",entityId:g[5].id,generated:[{type:"scenario",id:g[5].id,provenanceId:g[5].provenanceId}],payload:{name:g[5].name,description:g[5].description,interventionCount:g[5].interventions.length,source:"scenario-rail"}}),D({id:"prov-event-demo-iterative-ashp-added",timestamp:"2026-06-05T09:44:00.000Z",activity:"intervention.added",session:O,scenario:g[5],entityType:"intervention",entityId:"demo-iterative-v1-ashp",payload:{label:g[5].interventions[0].label,after:g[5].interventions[0],source:"configuration",uiContext:{surface:"configuration-panel"}}}
2),D({id:"prov-event-demo-iterative-pv-added",timestamp:"2026-06-05T09:47:00.000Z",activity:"intervention.added",session:O,scenario:g[5],entityType:"intervention",entityId:"demo-iterative-v1-pv",payload:{label:g[5].interventions[1].label,after:g[5].interventions[1],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-iterative-v1-simulated",timestamp:"2026-06-05T09:55:00.000Z",activity:"simulation.ran",session:O,scenario:g[5],entityType:"simulation",entityId:"2026-06-05T09:55:00.000Z",generated:[{type:"simulation-result",id:"2026-06-05T09:55:00.000Z"}],payload:{currentYear:2030,interventionCount:g[5].interventions.length,results:g[5].results,source:"simulation-runner",uiContext:{surface:"scenario-rail"}}}),D({id:"prov-event-demo-iterative-versioned",timestamp:"2026-06-05T10:05:00.000Z",activity:"scenario.versioned",session:O,scenario:g[6],entityType:"scenario",entityId:g[6].id,used:[{type:"scenario",id:g[5].id,provenanceId:g[5].provenanceId}],generated:[{type:"scenario",id:g[6].id,provenanceId:g[6].provenanceId}],payload:{name:g[6].name,changeSummary:g[6].changeSummary,parentScenarioId:g[5].id,parentScenarioProvenanceId:g[5].provenanceId,versionLabel:g[6].versionLabel,source:"scenario-rail"}}),D({id:"prov-event-demo-cfield-cost-created",timestamp:"2026-06-02T09:05:00.000Z",activity:"computed-field.created",session:O,scenarioId:null,entityType:"computed-field",entityId:Ie[0].id,payload:{name:Ie[0].name,after:{name:Ie[0].name,label:Ie[0].label,expression:Ie[0].expression},source:"field-calculator",uiContext:{surface:"field-calculator"}}}),D({id:"prov-event-demo-cfield-fuelpoor-created",timestamp:"2026-06-01T09:10:00.000Z",activity:"computed-field.created",session:O,scenarioId:null,entityType:"computed-field",entityId:Ie[1].id,payload:{name:Ie[1].name,after:{name:Ie[1].name,label:Ie[1].label,expression:Ie[1].expression},source:"field-calculator",uiContext:{surface:"field-calculator"}}}),D({id:"prov-event-demo-iterative-profile-created",timestamp:"2026-06-05T10:08:00.000Z",activity:"profile.created",session:O,scenario:g[6],entityType:"profile",entityId:"demo-profile-fuel-poor-terraces",payload:{name:g[6].profiles[0].name,after:{...g[6].profiles[0],uprns:{count:g[6].profiles[0].uprns.length}},source:"building-table",uiContext:{surface:"building-table",selectionCount:g[6].profiles[0].uprns.length}}}),D({id:"prov-event-demo-iterative-ashp-updated",timestamp:"2026-06-05T10:12:00.000Z",activity:"intervention.updated",session:O,scenario:g[6],entityType:"intervention",entityId:"demo-iterative-v2-ashp",payload:{label:"Fuel-poor heat pump core",before:g[5].interventions[0],after:$t(g[6].interventions[1]),source:"building-table",uiContext:{surface:"building-table",selectionCount:g[6].profiles[0].uprns.length}}}),D({id:"prov-event-demo-iterative-ashp-prioritised",timestamp:"2026-06-05T10:14:00.000Z",activity:"intervention.updated",session:O,scenario:g[6],entityType:"intervention",entityId:"demo-iterative-v2-ashp",payload:{label:"Fuel-poor heat pump core",before:$t(g[6].interventions[1]),after:g[6].interventions[1],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-iterative-pv-updated",timestamp:"2026-06-05T10:16:00.000Z",activity:"intervention.updated",session:O,scenario:g[6],entityType:"intervention",entityId:"demo-iterative-v2-pv",payload:{label:"Grid-aware solar tranche",before:g[5].interventions[1],after:g[6].interventions[0],source:"timeline",uiContext:{surface:"timeline"}}}),D({id:"prov-event-demo-iterative-cluster-profile-created",timestamp:"2026-06-05T10:19:00.000Z",activity:"profile.created",session:O,scenario:g[6],entityType:"profile",entityId:"demo-profile-cluster-homes",payload:{name:g[6].profiles[1].name,after:{...g[6].profiles[1],uprns:{count:g[6].profiles[1].uprns.length}},source:"building-table",uiContext:{surface:"building-table",selectionCount:g[6].profiles[1].uprns.length}}}),D({id:"prov-event-demo-iterative-gshp-added",timestamp:"2026-06-05T10:21:00.000Z",activity:"intervention.added",session:O,scenario:g[6],entityType:"intervention",entityId:"demo-iterative-v2-gshp",payload:{label:g[6].interventions[2].label,after:g[6].interventions[2],source:"configuration",uiContext:{surface:"configuration-panel"}}}),D({id:"prov-event-demo-iterative-reordered",timestamp:"2026-06-05T10:24:00.000Z",activity:"intervention.reordered",session:O,scenario:g[6],entityType:"intervention",entityId:"demo-iterative-v2-pv",payload:{label:g[6].interventions[0].label,direction:"up",before:{index:1},after:{index:0},source:"timeline",uiContext:{surface:"timeline"}}}),D({id:"prov-event-demo-iterative-v2-simulated",timestamp:"2026-06-05T10:30:00.000Z",activity:"simulation.ran",session:O,scenario:g[6],entityType:"simulation",entityId:"2026-06-05T10:30:00.000Z",generated:[{type:"simulation-result",id:"2026-06-05T10:30:00.000Z"}],payload:{currentYear:2032,interventionCount:g[6].interventions.length,results:g[6].results,source:"simulation-runner",uiContext:{surface:"scenario-rail"}}}),D({id:"prov-event-demo-iterative-saved",timestamp:"2026-06-05T10:34:00.000Z",activity:"scenario.saved",session:O,scenario:g[6],entityType:"scenario",entityId:g[6].id,payload:{scenarioName:g[6].name,storageMode:"browser-local",source:"scenario-rail",uiContext:{surface:"scenario-rail"}}}),D({id:"prov-event-demo-iterative-exported",timestamp:"2026-06-05T10:38:00.000Z",activity:"scenario.exported",session:O,scenario:g[6],entityType:"scenario",entityId:g[6].id,payload:{scenarioName:g[6].name,scenarioCount:g.length,source:"scenario-rail",uiContext:{surface:"scenario-rail"}}})];function Jn(e={}){return{schemaVersion:1,app:"laep-dashboard",exportedAt:"2026-06-05T11:00:00.000Z",activeSessionId:_e,activeScenarioId:$n,sessions:[O],scenarios:g,provenanceEvents:di,ui:{workflow:null},metadata:{dataset:"winchester_building_stock.parquet",source:"local-demo-fixture",demoVersion:Zn,...e}}}const ui=1,pi="laep-dashboard";function mi(e,t={}){return{schemaVersion:ui,app:pi,exportedAt:new Date().toISOString(),activeSessionId:e.activeSessionId??null,activeScenarioId:e.activeScenarioId??null,sessions:(e.sessions||[]).map(Rn),scenarios:(e.scenarios||[]).map(tt),provenanceEvents:(e.provenanceEvents||[]).map(n=>({schemaVersion:si,...n})),ui:{workflow:e.ui?.workflow||null},metadata:{dataset:"winchester_building_stock.parquet",demoVersion:Zn,...t}}}function fi(e){if(!e||typeof e!="object")throw new Error("Scenario bundle must be a JSON object.");if(e.schemaVersion!==ui)throw new Error(`Unsupported scenario bundle schema version: ${e.schemaVersion??"missing"}.`);if(e.app&&e.app!==pi)throw new Error(`Unsupported scenario bundle app: ${e.app}.`);if(!Array.isArray(e.sessions))throw new Error("Scenario bundle is missing sessions.");if(!Array.isArray(e.scenarios))throw new Error("Scenario bundle is missing scenarios.");
2if(e.provenanceEvents&&!Array.isArray(e.provenanceEvents))throw new Error("Scenario bundle provenanceEvents must be an array.");return e}function ut(e){return fi(e),{...e,sessions:e.sessions.map(t=>({...t,provenanceId:t.provenanceId||nt("session-prov"),source:t.source||"local"})),scenarios:e.scenarios.map(t=>({...tt(t),source:t.source||"local"})),provenanceEvents:e.provenanceEvents||[]}}function hi(e,t,n={}){const r=ut(t),i=r.sessions.some(l=>l.id===r.activeSessionId)?r.activeSessionId:r.sessions[0]?.id??null,a=r.scenarios.some(l=>l.id===r.activeScenarioId)?r.activeScenarioId:r.scenarios.find(l=>l.sessionId===i)?.id??r.scenarios[0]?.id??null,o=r.scenarios.find(l=>l.id===a)??null;return{...e,sessions:r.sessions,scenarios:r.scenarios,activeSessionId:i,activeScenarioId:a,provenanceEvents:r.provenanceEvents,ui:{...e.ui,selectedInterventionId:o?.interventions?.[0]?.id??null,editingInterventionId:null,buildingTableTab:"raw",simulationOutput:null,simulationStatus:"idle",mapConfig:{...e.ui?.mapConfig,layer:"raw"},workflow:r.ui?.workflow||e.ui?.workflow},persistence:{...e.persistence,storageMode:n.storageMode||e.persistence?.storageMode||"browser-local",lastSavedAt:r.exportedAt||null,dirty:!1,error:null}}}const Je=e=>`${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,Qe={mode:"guided",activeStageId:"set-area",completedStageIds:[],dismissedHints:[],tableFilterSummary:{visibleRows:null,totalRows:null,operations:[],activeTab:"raw"}};function Ia(e){if(!Array.isArray(e)||e.length===0)return null;const t=new Set,n=[];for(const r of e){if(r==null)continue;const i=String(r);t.has(i)||(t.add(i),n.push(i))}return n.length?n:null}function Ea(e,t){const n=!Array.isArray(e)||e.length===0,r=!Array.isArray(t)||t.length===0;if(n&&r)return!0;if(n||r||e.length!==t.length)return!1;const i=new Set(e);if(i.size!==e.length)return!1;for(const a of t)if(!i.has(a))return!1;return!0}const cr={sessions:[O],activeSessionId:_e,scenarios:g,activeScenarioId:$n,provenanceEvents:di,persistence:{storageMode:"browser-local",lastSavedAt:null,dirty:!1,error:null},ui:{currentYear:2026,selectedInterventionId:g.find(e=>e.id===$n)?.interventions?.[0]?.id??null,editingInterventionId:null,activeWorkspaceTab:"table",panelVisibility:{timeline:!0,configuration:!0,workspace:!0},mapConfig:{splitView:!1,layer:"raw",compareYear:2032,basemap:"light",showGlyphLayer:!0,showBuildingLayer:!1,glyphFields:["pvKW","ashpKW","gshpKW"],glyphMetric:"sum",mapEncodings:[{field:"pvKW",type:"numeric",mode:"magnitude",aggregation:"sum"},{field:"ashpKW",type:"numeric",mode:"magnitude",aggregation:"sum"},{field:"gshpKW",type:"numeric",mode:"magnitude",aggregation:"sum"}],mapEncoding:{field:"pvKW",type:"numeric",mode:"magnitude",aggregation:"sum"},timelineMetric:"carbon"},buildingTableTab:"raw",workflow:Qe,selectionState:{selectedUprns:null},tableConfig:{query:"",sortBy:"budget",sortDir:"desc"},simulationOutput:null,simulationStatus:"idle",error:null}};function st(e){return{...e,persistence:{...e.persistence||{},storageMode:e.persistence?.storageMode||"browser-local",dirty:!0,error:null}}}function dr(e,t=null){return{...e,persistence:{...e.persistence||{},storageMode:e.persistence?.storageMode||"browser-local",lastSavedAt:t||e.persistence?.lastSavedAt||new Date().toISOString(),dirty:!1,error:null}}}function ka(e,t=e.activeSessionId){return e.sessions.find(n=>n.id===t)||null}function _t(e,t=e.activeScenarioId){return e.scenarios.find(n=>n.id===t)||null}function ie(e,t,n={}){if(n.log===!1)return n.dirty===!1?e:st(e);const r=t.session||ka(e,t.sessionId),i=t.scenario||_t(e,t.scenarioId),a=D({session:r,scenario:i,...t}),o={...e,provenanceEvents:[...e.provenanceEvents||[],a]};return n.dirty===!1?o:st(o)}function Ot(e,t,n){return e.scenarios.map(r=>r.id!==t?r:{...r,interventions:n(r.interventions)})}function ur(e){if(!e||typeof e!="object")return e??null;const t=kt(e);return{...e,finalBuildingsCount:t?.finalBuildingsCount??0,rawResultsCount:t?.rawResultsCount??0}}function Aa(e,t){switch(t.type){case"CREATE_SESSION":{const n={id:Je("session"),provenanceId:nt("session-prov"),name:t.payload.name,description:t.payload.description||"",createdAt:new Date().toISOString(),source:"local"},r={...e,sessions:[n,...e.sessions],activeSessionId:n.id};return ie(r,{activity:"session.created",session:n,entityType:"session",entityId:n.id,payload:{name:n.name,description:n.description}})}case"SET_ACTIVE_SESSION":return{...e,activeSessionId:t.payload.sessionId};case"CREATE_SCENARIO":{const n={id:Je("scenario"),provenanceId:nt("scenario-prov"),lineageRootProvenanceId:null,parentScenarioProvenanceId:null,branchName:t.payload.name,versionNumber:1,versionLabel:"v1",changeSummary:null,forkedFromEventId:null,sessionId:e.activeSessionId,name:t.payload.name,description:t.payload.description||"",interventions:t.payload.interventions||[],profiles:[],createdAt:new Date().toISOString(),source:"local"};n.lineageRootProvenanceId=n.provenanceId;
2const r={...e,scenarios:[n,...e.scenarios],activeScenarioId:n.id,ui:{...e.ui,selectedInterventionId:n.interventions[0]?.id??null,editingInterventionId:null,mapConfig:{...e.ui.mapConfig,layer:"raw"},buildingTableTab:"raw",selectionState:{selectedUprns:null},simulationOutput:null,simulationStatus:"idle",tableConfig:{query:"",sortBy:"budget",sortDir:"desc"}}};return ie(r,{activity:"scenario.created",sessionId:n.sessionId,scenario:n,entityType:"scenario",entityId:n.id,payload:{name:n.name,description:n.description,interventionCount:n.interventions.length,source:"scenario-rail",uiContext:{surface:"scenario-rail"}}})}case"CREATE_SCENARIO_VERSION":{const{scenarioId:n,name:r,changeSummary:i}=t.payload,a=_t(e,n);if(!a)return e;const o=Number(a.versionNumber||1),l=tt({...a,id:Je("scenario"),provenanceId:nt("scenario-prov"),parentScenarioProvenanceId:a.provenanceId,lineageRootProvenanceId:a.lineageRootProvenanceId||a.provenanceId,branchName:a.branchName||a.name,versionNumber:o+1,versionLabel:`v${o+1}`,changeSummary:i||"Saved as a new version",forkedFromEventId:null,name:r||`${a.branchName||a.name} v${o+1}`,createdAt:new Date().toISOString(),source:"local",results:null}),c={...e,scenarios:[l,...e.scenarios],activeScenarioId:l.id,ui:{...e.ui,selectedInterventionId:l.interventions[0]?.id??null,editingInterventionId:null,simulationOutput:null,simulationStatus:"idle",buildingTableTab:"raw",mapConfig:{...e.ui.mapConfig,layer:"raw"}}};return ie(c,{activity:"scenario.versioned",sessionId:l.sessionId,scenario:l,entityType:"scenario",entityId:l.id,used:[{type:"scenario",id:a.id,provenanceId:a.provenanceId}],generated:[{type:"scenario",id:l.id,provenanceId:l.provenanceId}],payload:{name:l.name,changeSummary:l.changeSummary,parentScenarioId:a.id,parentScenarioProvenanceId:a.provenanceId,versionLabel:l.versionLabel,source:"scenario-rail",uiContext:{surface:"scenario-rail"}}})}case"BRANCH_SCENARIO":{const{scenarioId:n,name:r,changeSummary:i}=t.payload,a=_t(e,n);if(!a)return e;const o=tt({...a,id:Je("scenario"),provenanceId:nt("scenario-prov"),parentScenarioProvenanceId:a.provenanceId,lineageRootProvenanceId:a.lineageRootProvenanceId||a.provenanceId,branchName:r||`${a.name} alternative`,versionNumber:1,versionLabel:"v1",changeSummary:i||"Branched as an alternative scenario",forkedFromEventId:null,name:r||`${a.name} alternative`,createdAt:new Date().toISOString(),source:"local",results:null}),l={...e,scenarios:[o,...e.scenarios],activeScenarioId:o.id,ui:{...e.ui,selectedInterventionId:o.interventions[0]?.id??null,editingInterventionId:null,simulationOutput:null,simulationStatus:"idle",buildingTableTab:"raw",mapConfig:{...e.ui.mapConfig,layer:"raw"}}};return ie(l,{activity:"scenario.branched",sessionId:o.sessionId,scenario:o,entityType:"scenario",entityId:o.id,used:[{type:"scenario",id:a.id,provenanceId:a.provenanceId}],generated:[{type:"scenario",id:o.id,provenanceId:o.provenanceId}],payload:{name:o.name,changeSummary:o.changeSummary,parentScenarioId:a.id,parentScenarioProvenanceId:a.provenanceId,versionLabel:o.versionLabel,source:"scenario-rail",uiContext:{surface:"scenario-rail"}}})}case"SET_ACTIVE_SCENARIO":{const n=e.scenarios.find(i=>i.id===t.payload.scenarioId),r=!n?.interventions?.length;return{...e,activeScenarioId:t.payload.scenarioId,ui:{...e.ui,selectedInterventionId:n?.interventions[0]?.id??null,editingInterventionId:null,simulationOutput:null,simulationStatus:"idle",buildingTableTab:"raw",mapConfig:{...e.ui.mapConfig,layer:"raw"},...r&&{tableConfig:{query:"",sortBy:"budget",sortDir:"desc"}}}}}case"DELETE_SCENARIO":{const{scenarioId:n}=t.payload,r=e.scenarios.find(d=>d.id===n),i=e.scenarios.filter(d=>d.id!==n),a=e.activeScenarioId===n,o=a?i.find(d=>d.sessionId===e.activeSessionId)??i[0]:null,l=o?.id??null,c={...e,scenarios:i,activeScenarioId:l,ui:{...e.ui,selectedInterventionId:o?.interventions?.[0]?.id??null,editingInterventionId:null,simulationOutput:a?null:e.ui.simulationOutput,simulationStatus:a?"idle":e.ui.simulationStatus}};return r?ie(c,{activity:"scenario.deleted",sessionId:r.sessionId,scenarioId:r.id,scenarioProvenanceId:r.provenanceId,entityType:"scenario",entityId:r.id,payload:{name:r.name,snapshot:tt(r),source:"scenario-rail",uiContext:{surface:"scenario-rail"}}}):st(c)}case"SET_SESSIONS":{const n=new Map((e.sessions||[]).map(a=>[a.id,a])),r=(t.payload.sessions||[]).map(a=>{const o=a?.id!=null?n.get(a.id):null;return Rn(o?{...o,...a}:a)});let i=e.activeSessionId;return r.some(a=>a.id===i)||(i=r[0]?.id||null),{...e,sessions:r,activeSessionId:t.payload.activeSessionId??i}}case"SET_SCENARIOS":{const n=(t.payload.scenarios||[]).map(tt);let r=e.activeScenarioId;return n.some(i=>i.id===r)||(r=n[0]?.id||null),{...e,scenarios:n,activeScenarioId:t.payload.activeScenarioId??r}}case"UPSERT_SESSION":{const n=Rn(t.payload.session),i=e.sessions.find(o=>o.id===n.id)?e.sessions.map(o=>o.id===n.id?{...o,...n}:o):[n,...e.sessions],a={...e,sessions:i,activeSessionId:t.payload.setActive?n.id:e.activeSessionId};return t.payload.markClean?dr(a):a}case"UPSERT_SCENARIO":{const n=t.payload.scenario,r=e.scenarios.find(l=>l.id===n.id),i=tt(r?{...r,...n}:n),a=r?e.scenarios.map(l=>
2l.id===i.id?i:l):[i,...e.scenarios],o={...e,scenarios:a,activeScenarioId:t.payload.setActive?i.id:e.activeScenarioId};return t.payload.logEvent===!1?t.payload.markClean?dr(o):o:r&&r.name!==i.name?ie(o,{activity:"scenario.renamed",sessionId:i.sessionId||r.sessionId,scenario:{...r,...i},entityType:"scenario",entityId:i.id,payload:{before:{name:r.name},after:{name:i.name},source:t.payload.source||"scenario-rail",uiContext:t.payload.uiContext||{surface:"scenario-rail"}}}):r?st(o):o}case"ADD_INTERVENTION":{const{scenarioId:n,intervention:r}=t.payload,i={...r,id:r.id||Je("intv")},a={...e,scenarios:Ot(e,n,o=>[...o,i]),ui:{...e.ui,selectedInterventionId:i.id,editingInterventionId:null,simulationStatus:"stale",error:null}};return ie(a,{activity:"intervention.added",scenarioId:n,entityType:"intervention",entityId:i.id,payload:{label:i.label,after:i,source:t.payload.source||"configuration",uiContext:t.payload.uiContext||{surface:"configuration-panel"}}})}case"UPDATE_INTERVENTION":{const{scenarioId:n,interventionId:r,updates:i}=t.payload,o=e.scenarios.find(f=>f.id===n)?.interventions?.find(f=>f.id===r)||null,l=o?{...o,...i}:i,c=t.payload.source||"configuration",d=t.payload.uiContext||{surface:c==="timeline"?"timeline":"configuration-panel"},p={...e,scenarios:Ot(e,n,f=>f.map(u=>u.id===r?{...u,...i}:u)),ui:{...e.ui,simulationStatus:"stale",error:null}};return ie(p,{activity:"intervention.updated",scenarioId:n,entityType:"intervention",entityId:r,payload:{label:l?.label||o?.label,before:o,after:l,source:c,uiContext:d}})}case"REORDER_INTERVENTION":{const{scenarioId:n,interventionId:r,direction:i}=t.payload,a=e.scenarios.find(f=>f.id===n),o=a?.interventions?.findIndex(f=>f.id===r)??-1,l=o>=0?a.interventions[o]:null,c={...e,scenarios:Ot(e,n,f=>{const u=f.findIndex(S=>S.id===r);if(u<0)return f;const m=i==="up"?u-1:u+1;if(m<0||m>=f.length)return f;const h=[...f],[b]=h.splice(u,1);return h.splice(m,0,b),h}),ui:{...e.ui,simulationStatus:"stale",error:null}},p=c.scenarios.find(f=>f.id===n)?.interventions?.findIndex(f=>f.id===r)??-1;return o===p?e:ie(c,{activity:"intervention.reordered",scenarioId:n,entityType:"intervention",entityId:r,payload:{label:l?.label,direction:i,before:{index:o},after:{index:p},source:t.payload.source||"timeline",uiContext:t.payload.uiContext||{surface:"timeline"}}})}case"DELETE_INTERVENTION":{const{scenarioId:n,interventionId:r}=t.payload,i=e.scenarios.find(c=>c.id===n),a=i?.interventions?.find(c=>c.id===r)||null,o=i?i.interventions.filter(c=>c.id!==r):[],l={...e,scenarios:Ot(e,n,c=>c.filter(d=>d.id!==r)),ui:{...e.ui,selectedInterventionId:e.ui.selectedInterventionId===r?o[0]?.id??null:e.ui.selectedInterventionId,editingInterventionId:e.ui.editingInterventionId===r?null:e.ui.editingInterventionId,simulationStatus:"stale",error:null}};return ie(l,{activity:"intervention.deleted",scenarioId:n,entityType:"intervention",entityId:r,payload:{label:a?.label,before:a,source:t.payload.source||"configuration",uiContext:t.payload.uiContext||{surface:"configuration-panel"}}})}case"SET_SELECTED_INTERVENTION":return{...e,ui:{...e.ui,selectedInterventionId:t.payload.interventionId}};case"SET_EDITING_INTERVENTION":return{...e,ui:{...e.ui,editingInterventionId:t.payload.interventionId}};case"SET_CURRENT_YEAR":return{...e,ui:{...e.ui,currentYear:t.payload.year}};case"SET_WORKSPACE_TAB":return{...e,ui:{...e.ui,activeWorkspaceTab:t.payload.tab}};case"SET_PANEL_VISIBILITY":return{...e,ui:{...e.ui,panelVisibility:{...e.ui.panelVisibility,[t.payload.panel]:t.payload.visible}}};case"SET_MAP_CONFIG":return{...e,ui:{...e.ui,mapConfig:{...e.ui.mapConfig,...t.payload}}};case"SET_TABLE_CONFIG":return{...e,ui:{...e.ui,tableConfig:{...e.ui.tableConfig,...t.payload}}};case"SET_SIMULATION_STATUS":return{...e,ui:{...e.ui,simulationStatus:t.payload.status,error:t.payload.error??null}};case"SET_SIMULATION_OUTPUT":{const n=ur(t.payload.output),r=kt(n),i={...e,scenarios:e.scenarios.map(o=>o.id===e.activeScenarioId?{...o,results:n}:o),ui:{...e.ui,simulationOutput:t.payload.output,mapConfig:{...e.ui.mapConfig,layer:"deployment"},buildingTableTab:"results"}}
2,a=t.payload.provenanceEvent||{activity:"simulation.ran",scenarioId:e.activeScenarioId,entityType:"simulation",entityId:t.payload.output?.ranAt||e.activeScenarioId,generated:[{type:"simulation-result",id:t.payload.output?.ranAt||e.activeScenarioId}],payload:{currentYear:e.ui.currentYear,interventionCount:_t(e)?.interventions?.length??0,results:r,source:t.payload.source||"simulation-runner",uiContext:t.payload.uiContext||{surface:"scenario-rail"}}};return ie(i,a)}case"SET_SCENARIO_RESULTS":{const n=ur(t.payload.output),r=kt(n),i={...e,scenarios:e.scenarios.map(a=>a.id===t.payload.scenarioId?{...a,results:n}:a)};return ie(i,{activity:"simulation.ran",scenarioId:t.payload.scenarioId,entityType:"simulation",entityId:t.payload.output?.ranAt||t.payload.scenarioId,generated:[{type:"simulation-result",id:t.payload.output?.ranAt||t.payload.scenarioId}],payload:{currentYear:e.ui.currentYear,interventionCount:_t(e,t.payload.scenarioId)?.interventions?.length??0,results:r,source:t.payload.source||"simulation-runner",uiContext:t.payload.uiContext||{surface:"comparison-simulation"}}})}case"SET_BUILDING_TABLE_TAB":{const n=t.payload.tab,r=e.ui.buildingTableTab,i=n!==r&&!t.payload.preserveSelection;return{...e,ui:{...e.ui,buildingTableTab:n,...i&&{selectionState:{selectedUprns:null}},...n==="raw"&&{mapConfig:{...e.ui.mapConfig,glyphFields:["pvKW","ashpKW","gshpKW"],glyphMetric:"sum"}}}}}case"SET_WORKFLOW_MODE":{const n={...e,ui:{...e.ui,workflow:{...Qe,...e.ui.workflow||{},mode:t.payload.mode==="expert"?"expert":"guided"}}};return st(n)}case"SET_WORKFLOW_STAGE":return{...e,ui:{...e.ui,workflow:{...Qe,...e.ui.workflow||{},activeStageId:t.payload.stageId||Qe.activeStageId}}};case"SET_WORKFLOW_TABLE_FILTER_SUMMARY":{const n=t.payload.summary||{},r=e.ui.workflow?.tableFilterSummary||Qe.tableFilterSummary,i={visibleRows:Number.isFinite(Number(n.visibleRows))?Number(n.visibleRows):null,totalRows:Number.isFinite(Number(n.totalRows))?
2Number(n.totalRows):null,operations:Array.isArray(n.operations)?n.operations.slice(-5):[],activeTab:n.activeTab||r.activeTab||"raw"};return r.visibleRows===i.visibleRows&&r.totalRows===i.totalRows&&r.activeTab===i.activeTab&&JSON.stringify(r.operations||[])===JSON.stringify(i.operations||[])?e:{...e,ui:{...e.ui,workflow:{...Qe,...e.ui.workflow||{},tableFilterSummary:i}}}}case"DISMISS_WORKFLOW_HINT":{const n=t.payload.hintId;if(!n)return e;const r=new Set(e.ui.workflow?.dismissedHints||[]);r.add(n);const i={...e,ui:{...e.ui,workflow:{...Qe,...e.ui.workflow||{},dismissedHints:Array.from(r)}}};return st(i)}case"SET_SELECTION":{const n=e.ui.selectionState?.selectedUprns??null,r=Ia(t.payload.uprns);return Ea(n,r)?e:{...e,ui:{...e.ui,selectionState:{selectedUprns:r}}}}case"ADD_PROFILE":{const{scenarioId:n,profile:r}=t.payload;let i=null;const a={...e,scenarios:e.scenarios.map(o=>{if(o.id!==n)return o;const l={...r,id:r.id||Je("profile")};return i=l,{...o,profiles:[...o.profiles||[],l]}})};return ie(a,{activity:"profile.created",scenarioId:n,entityType:"profile",entityId:i?.id,payload:{name:i?.name,after:{...i,uprns:Array.isArray(i?.uprns)?{count:i.uprns.length}:void 0},source:t.payload.source||"building-table",uiContext:t.payload.uiContext||{surface:"building-table"}}})}case"UPDATE_PROFILE":{const{scenarioId:n,profileId:r,updates:i}=t.payload,o=e.scenarios.find(d=>d.id===n)?.profiles?.find(d=>d.id===r)||null,l=o?{...o,...i}:i,c={...e,scenarios:e.scenarios.map(d=>d.id!==n?d:{...d,profiles:(d.profiles||[]).map(p=>p.id===r?{...p,...i}:p)})};return ie(c,{activity:"profile.updated",scenarioId:n,entityType:"profile",entityId:r,payload:{name:l?.name||o?.name,before:o,after:l,source:t.payload.source||"building-table",uiContext:t.payload.uiContext||{surface:"building-table"}}})}case"ADD_COMPUTED_FIELD":{const n=t.payload.sessionId||e.activeSessionId,{field:r}=t.payload;let i=null;const a={...e,sessions:e.sessions.map(o=>{if(o.id!==n)return o;const l={id:r.id||Je("cfield"),name:r.name,label:r.label||null,expression:r.expression,createdAt:r.createdAt||new Date().toISOString()};return i=l,{...o,computedFields:[...o.computedFields||[],l]}})};return ie(a,{activity:"computed-field.created",sessionId:n,scenarioId:null,entityType:"computed-field",entityId:i?.id,payload:{name:i?.name,after:i?{name:i.name,label:i.label,expression:i.expression}:void 0,source:t.payload.source||"field-calculator",uiContext:t.payload.uiContext||{surface:"field-calculator"}}})}case"UPDATE_COMPUTED_FIELD":{const n=t.payload.sessionId||e.activeSessionId,{fieldId:r,updates:i}=t.payload,o=e.sessions.find(f=>f.id===n)?.computedFields?.find(f=>f.id===r)||null,l=o?{name:o.name,label:o.label,expression:o.expression}:null,c=o?{...o,...i}:null,d=c?{name:c.name,label:c.label,expression:c.expression}:i,p={...e,sessions:e.sessions.map(f=>f.id!==n?f:{...f,computedFields:(f.computedFields||[]).map(u=>u.id===r?{...u,...i}:u)})};return ie(p,{activity:"computed-field.updated",sessionId:n,scenarioId:null,entityType:"computed-field",entityId:r,payload:{name:d?.name||l?.name,before:l,after:d,source:t.payload.source||"field-calculator",uiContext:t.payload.uiContext||{surface:"field-calculator"}}})}case"DELETE_COMPUTED_FIELD":{const n=t.payload.sessionId||e.activeSessionId,{fieldId:r}=t.payload,a=e.sessions.find(l=>l.id===n)?.computedFields?.find(l=>l.id===r)||null,o={...e,sessions:e.sessions.map(l=>l.id!==n?l:{...l,computedFields:(l.computedFields||[]).filter(c=>c.id!==r)})};return ie(o,{activity:"computed-field.deleted",sessionId:n,scenarioId:null,entityType:"computed-field",entityId:r,payload:{name:a?.name,before:a?{name:a.name,label:a.label,expression:a.expression}:null,source:t.payload.source||"field-calculator",uiContext:t.payload.uiContext||{surface:"field-calculator"}}})}case"RECORD_PROVENANCE_EVENT":return ie(e,t.payload||{},{dirty:t.payload?.dirty!==!1});case"MERGE_PROVENANCE_EVENTS":{const n=t.payload.events||[],r=new Map((e.provenanceEvents||[]).map(i=>[i.id,i]));for(const i of n)i?.id&&r.set(i.id,i);return{...e,provenanceEvents:Array.from(r.values()).sort((i,a)=>String(i.timestamp||"").localeCompare(String(a.timestamp||"")))}}case"SET_STORAGE_MODE":return{...e,persistence:{...e.persistence||{},storageMode:t.payload.storageMode||"browser-local",error:null}};case"SET_PERSISTENCE_STATUS":return{...e,persistence:{...e.persistence||{},...t.payload}};case"HYDRATE_FROM_BUNDLE":{const n=hi(e,t.payload.bundle,{storageMode:t.payload.storageMode||e.persistence?.storageMode||"browser-local"});return t.payload.activity?ie(n,{activity:t.payload.activity,entityType:"scenario",payload:t.payload.payload||{}},{dirty:t.payload.dirty!==!1}):n}default:return e}}const Kt="laep-dashboard:scenario-bundle:v1";function gi(){try{return typeof window<"u"?window.localStorage:null}catch{return null}}function Ta(e){const t=gi();if(!t)return null;const n=ut(e),r=new Date().toISOString();return t.setItem(Kt,JSON.stringify({...n,exportedAt:r})),r}function ja(){const e=gi();if(!e)return null;const t=e.getItem(Kt);if(!t)return null;const n=JSON.parse(t);if($a(n)){const i=Jn({migratedFrom:"legacy-blank-local-save"});return e.setItem(Kt,JSON.stringify(i)),ut(i)}const r=Ra(n);return r?(e.setItem(Kt,JSON.stringify(r)),ut(r)):ut(n)}const Pa=e=>typeof e?.id=="string"&&e.id.startsWith("scenario-demo-");function Ra(e){if(!e||typeof e!="object")return null;const t=e.metadata?.demoVersion??null;if(t===Zn)return null;const n=Jn({migratedFrom:t??"unversioned-local-save"}),r=(e.scenarios||[]).filter(l=>!Pa(l)),i=(e.sessions||[]).filter(l=>l?.id!==_e),a=(e.provenanceEvents||[]).filter(l=>l?.sessionId!==_e),o=r.some(l=>l?.id===e.activeScenarioId);return{...n,sessions:[...n.sessions,...i],scenarios:[...n.scenarios,...r],provenanceEvents:[...n.provenanceEvents,...a],activeSessionId:o?e.activeSessionId:n.activeSessionId,activeScenarioId:o?e.activeScenarioId:n.activeScenarioId}}function $a(e){if(!e||typeof e!="object")return!1;const t=Array.isArray(e.scenarios)?e.scenarios:[];if(t.length!==1)return!1;const n=t[0]||{},r=Array.isArray(n.interventions)?n.interventions:[],i=Array.isArray(n.config?.interventions)?n.config.interventions:[];return n.id==="scenario-default"&&n.name==="New Scenario"&&r.length===0&&i.length===0}function yi(e){return Ta(mi(e))}function Ma(e,t="laep-scenario-bundle.json"){if(fi(e),typeof document>"u")return;const n=new Blob([JSON.stringify(e,null,2)],{type:"application/json;charset=utf-8;"}),r=URL.createObjectURL(n),i=document.createElement("a");i.href=r,i.download=t,i.click(),URL.revokeObjectURL(r)}function Oa(e){return new Promise((t,n)=>{const r=new FileReader;r.onload=()=>{try{const i=JSON.parse(String(r.result||""));t(ut(i))}catch(i){n(i)}},r.onerror=()=>n(r.error||new Error("Failed to read scenario bundle.")),r.readAsText(e)})}const Xn=N.createContext(null);function La(e){try{const t=ja();return t?hi(e,t,{storageMode:"browser-local"}):e}catch(t){return console.warn("Failed to load local scenario bundle:",t),{...e,persistence:{...e.persistence,error:t.message}}}}function Da(e){const t=e?.ui?.buildingTableTab??"raw",n=!!e?.ui?.simulationOutput?.finalBuildings?.length;return t==="raw"?"raw":(t==="results"||t==="comparison")&&n?"simulated":"awaiting-simulation"}const Fa=({children:e})=>{const[t,n]=N.useReducer(Aa,cr,La),r=t?.scenarios?.find(d=>d.id===t.activeScenarioId)??null,i=t?.sessions?.find(d=>d.id===t.activeSessionId)??null,a=r?.interventions?.find(d=>d.id===t?.ui?.selectedInterventionId)??null,o=r?.interventions?.find(d=>d.id===t?.ui?.editingInterventionId)??null,l=N.useMemo(()=>Da(t),[t?.ui?.buildingTableTab,t?.ui?.simulationOutput]);N.useEffect(()=>{if(t?.persistence?.storageMode!=="browser-local"||!t?.persistence?.dirty)return;const d=window.setTimeout(()=>{try{const p=yi(t);n({type:"SET_PERSISTENCE_STATUS",payload:{lastSavedAt:p||new Date().toISOString(),dirty:!1,error:null}})}catch(p){n({type:"SET_PERSISTENCE_STATUS",payload:{error:p.message,dirty:!0}})}},450);return()=>window.clearTimeout(d)},[t]);const c=N.useMemo(()=>({state:t??cr,dispatch:n,activeScenario:r,activeSession:i,selectedIntervention:a,editingIntervention:o,dataMode:l}),[t,r,i,a,o,l]);return s.jsx(Xn.Provider,{value:c,children:e})},Ba="modulepreload",Ua=function(e){return"/"+e},pr={},ge=function(t,n,r){let i=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const o=document.querySelector("meta[property=csp-nonce]"),l=o?.nonce||o?.getAttribute("nonce");i=Promise.allSettled(n.map(c=>{if(c=Ua(c),c in pr)return;pr[c]=!0;const d=c.endsWith(".css"),p=d?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${p}`))return;const f=document.createElement("link");if(f.rel=d?"stylesheet":Ba,d||(f.as="script"),f.crossOrigin="",f.href=c,l&&f.setAttribute("nonce",l),document.head.appendChild(f),d)return new Promise((u,m)=>{f.addEventListener("load",u),f.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${c}`)))})}))}function a(o){const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=o,window.dispatchEvent(l),!l.defaultPrevented)throw o}return i.then(o=>{for(const l of o||[])l.status==="rejected"&&a(l.reason);return t().catch(a)})};/** 3 * @license lucide-react v0.344.0 - ISC 4 * 5 * This source code is licensed under the ISC license. 6 * See the LICENSE file in the root directory of this source tree. 7 */var Ha={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};/** 8 * @license lucide-react v0.344.0 - ISC 9 * 10 * This source code is licensed under the ISC license. 11 * See the LICENSE file in the root directory of this source tree. 12 */const Va=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase().trim(),Y=(e,t)=>
vendor: 12,855 bytes, lines 12-182
12{const n=N.forwardRef(({color:r="currentColor",size:i=24,strokeWidth:a=2,absoluteStrokeWidth:o,className:l="",children:c,...d},p)=>N.createElement("svg",{ref:p,...Ha,width:i,height:i,stroke:r,strokeWidth:o?Number(a)*24/Number(i):a,className:["lucide",`lucide-${Va(e)}`,l].join(" "),...d},[...t.map(([f,u])=>N.createElement(f,u)),...Array.isArray(c)?c:[c]]));return n.displayName=`${e}`,n};/** 13 * @license lucide-react v0.344.0 - ISC 14 * 15 * This source code is licensed under the ISC license. 16 * See the LICENSE file in the root directory of this source tree. 17 */const Ya=Y("Activity",[["path",{d:"M22 12h-4l-3 9L9 3l-3 9H2",key:"d5dnw9"}]]);/** 18 * @license lucide-react v0.344.0 - ISC 19 * 20 * This source code is licensed under the ISC license. 21 * See the LICENSE file in the root directory of this source tree. 22 */const bi=Y("ArrowDownUp",[["path",{d:"m3 16 4 4 4-4",key:"1co6wj"}],["path",{d:"M7 20V4",key:"1yoxec"}],["path",{d:"m21 8-4-4-4 4",key:"1c9v7m"}],["path",{d:"M17 4v16",key:"7dpous"}]]);/** 23 * @license lucide-react v0.344.0 - ISC 24 * 25 * This source code is licensed under the ISC license. 26 * See the LICENSE file in the root directory of this source tree. 27 */const Wa=Y("BarChart3",[["path",{d:"M3 3v18h18",key:"1s2lah"}],["path",{d:"M18 17V9",key:"2bz60n"}],["path",{d:"M13 17V5",key:"1frdt8"}],["path",{d:"M8 17v-3",key:"17ska0"}]]);/** 28 * @license lucide-react v0.344.0 - ISC 29 * 30 * This source code is licensed under the ISC license. 31 * See the LICENSE file in the root directory of this source tree. 32 */const qa=Y("Calendar",[["path",{d:"M8 2v4",key:"1cmpym"}],["path",{d:"M16 2v4",key:"4m81vk"}],["rect",{width:"18",height:"18",x:"3",y:"4",rx:"2",key:"1hopcy"}],["path",{d:"M3 10h18",key:"8toen8"}]]);/** 33 * @license lucide-react v0.344.0 - ISC 34 * 35 * This source code is licensed under the ISC license. 36 * See the LICENSE file in the root directory of this source tree. 37 */const vi=Y("CheckCircle2",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]]);/** 38 * @license lucide-react v0.344.0 - ISC 39 * 40 * This source code is licensed under the ISC license. 41 * See the LICENSE file in the root directory of this source tree. 42 */const za=Y("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);/** 43 * @license lucide-react v0.344.0 - ISC 44 * 45 * This source code is licensed under the ISC license. 46 * See the LICENSE file in the root directory of this source tree. 47 */const Jt=Y("ChevronDown",[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]);/** 48 * @license lucide-react v0.344.0 - ISC 49 * 50 * This source code is licensed under the ISC license. 51 * See the LICENSE file in the root directory of this source tree. 52 */const Ga=Y("CircleDashed",[["path",{d:"M10.1 2.182a10 10 0 0 1 3.8 0",key:"5ilxe3"}],["path",{d:"M13.9 21.818a10 10 0 0 1-3.8 0",key:"11zvb9"}],["path",{d:"M17.609 3.721a10 10 0 0 1 2.69 2.7",key:"1iw5b2"}],["path",{d:"M2.182 13.9a10 10 0 0 1 0-3.8",key:"c0bmvh"}],["path",{d:"M20.279 17.609a10 10 0 0 1-2.7 2.69",key:"1ruxm7"}],["path",{d:"M21.818 10.1a10 10 0 0 1 0 3.8",key:"qkgqxc"}],["path",{d:"M3.721 6.391a10 10 0 0 1 2.7-2.69",key:"1mcia2"}],["path",{d:"M6.391 20.279a10 10 0 0 1-2.69-2.7",key:"1fvljs"}]]);/** 53 * @license lucide-react v0.344.0 - ISC 54 * 55 * This source code is licensed under the ISC license. 56 * See the LICENSE file in the root directory of this source tree. 57 */const Ka=Y("ClipboardList",[["rect",{width:"8",height:"4",x:"8",y:"2",rx:"1",ry:"1",key:"tgr4d6"}],["path",{d:"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2",key:"116196"}],["path",{d:"M12 11h4",key:"1jrz19"}],["path",{d:"M12 16h4",key:"n85exb"}],["path",{d:"M8 11h.01",key:"1dfujw"}],["path",{d:"M8 16h.01",key:"18s6g9"}]]);/** 58 * @license lucide-react v0.344.0 - ISC 59 * 60 * This source code is licensed under the ISC license. 61 * See the LICENSE file in the root directory of this source tree. 62 */const Za=Y("Clock",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["polyline",{points:"12 6 12 12 16 14",key:"68esgv"}]]);/** 63 * @license lucide-react v0.344.0 - ISC 64 * 65 * This source code is licensed under the ISC license. 66 * See the LICENSE file in the root directory of this source tree. 67 */const Ja=Y("Coins",[["circle",{cx:"8",cy:"8",r:"6",key:"3yglwk"}],["path",{d:"M18.09 10.37A6 6 0 1 1 10.34 18",key:"t5s6rm"}],["path",{d:"M7 6h1v4",key:"1obek4"}],["path",{d:"m16.71 13.88.7.71-2.82 2.82",key:"1rbuyh"}]]);/** 68 * @license lucide-react v0.344.0 - ISC 69 * 70 * This source code is licensed under the ISC license. 71 * See the LICENSE file in the root directory of this source tree. 72 */const Xa=Y("FileDown",[["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 18v-6",key:"17g6i2"}],["path",{d:"m9 15 3 3 3-3",key:"1npd3o"}]]);/** 73 * @license lucide-react v0.344.0 - ISC 74 * 75 * This source code is licensed under the ISC license. 76 * See the LICENSE file in the root directory of this source tree. 77 */const Qa=Y("FileText",[["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:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]]);/** 78 * @license lucide-react v0.344.0 - ISC 79 * 80 * This source code is licensed under the ISC license. 81 * See the LICENSE file in the root directory of this source tree. 82 */const eo=Y("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"}]]);/** 83 * @license lucide-react v0.344.0 - ISC 84 * 85 * This source code is licensed under the ISC license. 86 * See the LICENSE file in the root directory of this source tree. 87 */const to=Y("Flag",[["path",{d:"M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z",key:"i9b6wo"}],["line",{x1:"4",x2:"4",y1:"22",y2:"15",key:"1cm3nv"}]]);/** 88 * @license lucide-react v0.344.0 - ISC 89 * 90 * This source code is licensed under the ISC license. 91 * See the LICENSE file in the root directory of this source tree. 92 */const no=Y("FunctionSquare",[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",ry:"2",key:"1m3agn"}],["path",{d:"M9 17c2 0 2.8-1 2.8-2.8V10c0-2 1-3.3 3.2-3",key:"m1af9g"}],["path",{d:"M9 11.2h5.7",key:"3zgcl2"}]]);/** 93 * @license lucide-react v0.344.0 - ISC 94 * 95 * This source code is licensed under the ISC license. 96 * See the LICENSE file in the root directory of this source tree. 97 */const xi=Y("GitBranch",[["line",{x1:"6",x2:"6",y1:"3",y2:"15",key:"17qcm7"}],["circle",{cx:"18",cy:"6",r:"3",key:"1h7g24"}],["circle",{cx:"6",cy:"18",r:"3",key:"fqmcym"}],["path",{d:"M18 9a9 9 0 0 1-9 9",key:"n2h4wq"}]]);/** 98 * @license lucide-react v0.344.0 - ISC 99 * 100 * This source code is licensed under the ISC license. 101 * See the LICENSE file in the root directory of this source tree. 102 */const ro=Y("GitFork",[["circle",{cx:"12",cy:"18",r:"3",key:"1mpf1b"}],["circle",{cx:"6",cy:"6",r:"3",key:"1lh9wr"}],["circle",{cx:"18",cy:"6",r:"3",key:"1h7g24"}],["path",{d:"M18 9v2c0 .6-.4 1-1 1H7c-.6 0-1-.4-1-1V9",key:"1uq4wg"}],["path",{d:"M12 12v3",key:"158kv8"}]]);/** 103 * @license lucide-react v0.344.0 - ISC 104 * 105 * This source code is licensed under the ISC license. 106 * See the LICENSE file in the root directory of this source tree. 107 */const io=Y("History",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]]);/** 108 * @license lucide-react v0.344.0 - ISC 109 * 110 * This source code is licensed under the ISC license. 111 * See the LICENSE file in the root directory of this source tree. 112 */const ao=Y("LineChart",[["path",{d:"M3 3v18h18",key:"1s2lah"}],["path",{d:"m19 9-5 5-4-4-3 3",key:"2osh9i"}]]);/** 113 * @license lucide-react v0.344.0 - ISC 114 * 115 * This source code is licensed under the ISC license. 116 * See the LICENSE file in the root directory of this source tree. 117 */const oo=Y("MoreHorizontal",[["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}],["circle",{cx:"19",cy:"12",r:"1",key:"1wjl8i"}],["circle",{cx:"5",cy:"12",r:"1",key:"1pcz8c"}]]);/** 118 * @license lucide-react v0.344.0 - ISC 119 * 120 * This source code is licensed under the ISC license. 121 * See the LICENSE file in the root directory of this source tree. 122 */const so=Y("Pen",[["path",{d:"M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z",key:"5qss01"}]]);/** 123 * @license lucide-react v0.344.0 - ISC 124 * 125 * This source code is licensed under the ISC license. 126 * See the LICENSE file in the root directory of this source tree. 127 */const Qn=Y("Pencil",[["path",{d:"M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z",key:"5qss01"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]]);/** 128 * @license lucide-react v0.344.0 - ISC 129 * 130 * This source code is licensed under the ISC license. 131 * See the LICENSE file in the root directory of this source tree. 132 */const lo=Y("PlayCircle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["polygon",{points:"10 8 16 12 10 16 10 8",key:"1cimsy"}]]);/** 133 * @license lucide-react v0.344.0 - ISC 134 * 135 * This source code is licensed under the ISC license. 136 * See the LICENSE file in the root directory of this source tree. 137 */const co=Y("Play",[["polygon",{points:"5 3 19 12 5 21 5 3",key:"191637"}]]);/** 138 * @license lucide-react v0.344.0 - ISC 139 * 140 * This source code is licensed under the ISC license. 141 * See the LICENSE file in the root directory of this source tree. 142 */const lt=Y("Plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);/** 143 * @license lucide-react v0.344.0 - ISC 144 * 145 * This source code is licensed under the ISC license. 146 * See the LICENSE file in the root directory of this source tree. 147 */const uo=Y("RotateCcw",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]]);/** 148 * @license lucide-react v0.344.0 - ISC 149 * 150 * This source code is licensed under the ISC license. 151 * See the LICENSE file in the root directory of this source tree. 152 */const po=Y("Save",[["path",{d:"M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z",key:"1owoqh"}],["polyline",{points:"17 21 17 13 7 13 7 21",key:"1md35c"}],["polyline",{points:"7 3 7 8 15 8",key:"8nz8an"}]]);/** 153 * @license lucide-react v0.344.0 - ISC 154 * 155 * This source code is licensed under the ISC license. 156 * See the LICENSE file in the root directory of this source tree. 157 */const mo=Y("Search",[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["path",{d:"m21 21-4.3-4.3",key:"1qie3q"}]]);/** 158 * @license lucide-react v0.344.0 - ISC 159 * 160 * This source code is licensed under the ISC license. 161 * See the LICENSE file in the root directory of this source tree. 162 */const fo=Y("Settings2",[["path",{d:"M20 7h-9",key:"3s1dr2"}],["path",{d:"M14 17H5",key:"gfn3mx"}],["circle",{cx:"17",cy:"17",r:"3",key:"18b49y"}],["circle",{cx:"7",cy:"7",r:"3",key:"dfmy0x"}]]);/** 163 * @license lucide-react v0.344.0 - ISC 164 * 165 * This source code is licensed under the ISC license. 166 * See the LICENSE file in the root directory of this source tree. 167 */const ho=Y("SlidersHorizontal",[["line",{x1:"21",x2:"14",y1:"4",y2:"4",key:"obuewd"}],["line",{x1:"10",x2:"3",y1:"4",y2:"4",key:"1q6298"}],["line",{x1:"21",x2:"12",y1:"12",y2:"12",key:"1iu8h1"}],["line",{x1:"8",x2:"3",y1:"12",y2:"12",key:"ntss68"}],["line",{x1:"21",x2:"16",y1:"20",y2:"20",key:"14d8ph"}],["line",{x1:"12",x2:"3",y1:"20",y2:"20",key:"m0wm8r"}],["line",{x1:"14",x2:"14",y1:"2",y2:"6",key:"14e1ph"}],["line",{x1:"8",x2:"8",y1:"10",y2:"14",key:"1i6ji0"}],["line",{x1:"16",x2:"16",y1:"18",y2:"22",key:"1lctlv"}]]);/** 168 * @license lucide-react v0.344.0 - ISC 169 * 170 * This source code is licensed under the ISC license. 171 * See the LICENSE file in the root directory of this source tree. 172 */const go=Y("Sparkles",[["path",{d:"m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z",key:"17u4zn"}],["path",{d:"M5 3v4",key:"bklmnn"}],["path",{d:"M19 17v4",key:"iiml17"}],["path",{d:"M3 5h4",key:"nem4j1"}],["path",{d:"M17 19h4",key:"lbex7p"}]]);/** 173 * @license lucide-react v0.344.0 - ISC 174 * 175 * This source code is licensed under the ISC license. 176 * See the LICENSE file in the root directory of this source tree. 177 */const yo=Y("Table",[["path",{d:"M12 3v18",key:"108xh3"}],["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M3 9h18",key:"1pudct"}],["path",{d:"M3 15h18",key:"5xshup"}]]);/** 178 * @license lucide-react v0.344.0 - ISC 179 * 180 * This source code is licensed under the ISC license. 181 * See the LICENSE file in the root directory of this source tree. 182 */const er=Y("Trash2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}
182],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);/** 183 * @license lucide-react v0.344.0 - ISC 184 * 185 * This source code is licensed under the ISC license. 186 * See the LICENSE file in the root directory of this source tree. 187 */const bo=Y("TrendingUp",[["polyline",{points:"22 7 13.5 15.5 8.5 10.5 2 17",key:"126l90"}],["polyline",{points:"16 7 22 7 22 13",key:"kwv8wd"}]]);/** 188 * @license lucide-react v0.344.0 - ISC 189 * 190 * This source code is licensed under the ISC license. 191 * See the LICENSE file in the root directory of this source tree. 192 */const mr=Y("Users",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["path",{d:"M16 3.13a4 4 0 0 1 0 7.75",key:"1da9ce"}]]);/** 193 * @license lucide-react v0.344.0 - ISC 194 * 195 * This source code is licensed under the ISC license. 196 * See the LICENSE file in the root directory of this source tree. 197 */const Mn=Y("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);function On(e,t,n,r="linear",i={},a=!1){const o=Array.from({length:n},(u,m)=>t+m);if(r==="linear"){const u=e/n;return o.map(m=>({year:m,budget:u}))}const{exponent:l=2}=i;let c;switch(r){case"log":c=Ui().domain([1,n]).range([1,10]).clamp(!0);break;case"sqrt":c=Bi().domain([0,1]).range([1,10]);break;case"exp":c=yn().exponent(l).domain([0,1]).range([1,10]);break;case"quad":c=yn().exponent(2).domain([0,1]).range([1,10]);break;case"cubic":c=yn().exponent(3).domain([0,1]).range([1,10]);break;default:return o.map(u=>({year:u,budget:e/n}))}const d=o.map((u,m)=>{const h=a?n-1-m:m;return c(r==="log"?h+1:h/Math.max(1,n-1))}),p=zn(d);let f=0;return o.map((u,m)=>{if(f>=e)return{year:u,budget:0};let h=d[m]/p*e;return f+h>e&&(h=e-f),f+=h,{year:u,budget:h}})}function vo(e,t){const n=zn(t,i=>i.budget),r=Math.abs(n-e)<1;return{totalBudget:e,totalAllocated:n,budgetMatches:r}}const fr=[{id:"linear",label:"Equal / Linear"},{id:"sqrt",label:"Front-loaded (â)"},{id:"quad",label:"Front-loaded (x²)"},{id:"cubic",label:"Front-loaded (x³)"},{id:"exp",label:"Custom power"},{id:"log",label:"Logarithmic"}],$e=e=>e>=1e9?wt(".1f")(e/1e9)+"B":e>=1e6?wt(".1f")(e/1e6)+"M":e>=1e3?wt(".1f")(e/1e3)+"k":wt(".0f")(e),Ve=(e,t)=>typeof window>"u"?t:window.getComputedStyle(document.documentElement).getPropertyValue(e).trim()||t,xo=({totalBudget:e,startYear:t,duration:n,allocations:r,onAllocationsChange:i,color:a="#3b82f6",readOnly:o=!1})=>{const l=N.useRef(null),c=N.useRef(null),[d,p]=N.useState("linear"),[f,u]=N.useState(!1),[m,h]=N.useState(!1),b=N.useMemo(()=>Array.from({length:n},(_,v)=>t+v),[t,n]),[S,w]=N.useState(()=>Array.isArray(r)&&r.length===n?r.map(_=>({..._})):On(e,t,n,d,{},f)),k=N.useCallback((_,v)=>{const A=On(e,t,n,_,{},v);w(A),i?.(A)},[e,t,n,i]);N.useEffect(()=>{Array.isArray(r)&&r.length===n?w(r.map(_=>({..._}))):k(d,f)},[e,t,n]),N.useEffect(()=>{if(!l.current)return;const _=We(l.current);_.selectAll("*").remove();const v=c.current?.clientWidth||440,A=180,P={top:18,right:16,bottom:32,left:54},U=Ve("--laep-text-muted","#64748b"),$=Ve("--laep-border-subtle","#e2e8f0"),B=Ve("--laep-border-strong","#cbd5e1"),X=Ve("--laep-action","#1e293b"),pe=Ve("--laep-action-contrast","#ffffff"),R=Ve("--laep-success","#16a34a"),C=Ve("--laep-danger","#dc2626");_.attr("width",v).attr("height",A).attr("viewBox",[0,0,v,A]);const T=ei().domain(b).range([P.left,v-P.right]).padding(.15),H=Array.isArray(S)?S:[],W=H.filter(V=>T(V.year)!==void 0),z=Math.max(Hi(H,V=>V.budget)||0,1)*1.25,K=ti().domain([0,z]).nice().range([A-P.bottom,P.top]);_.append("g").attr("class","grid").attr("transform",`translate(${P.left},0)`).call(Pn(K).ticks(4).tickSize(-(v-P.left-P.right)).tickFormat("")).selectAll("line").attr("stroke",$).attr("stroke-dasharray","2,3"),_.selectAll(".grid .domain").remove(),_.append("g").attr("transform",`translate(0,${A-P.bottom})`).call(ni(T).tickFormat(wt("d"))).selectAll("text").attr("font-size","10px").attr("fill",U),_.append("g").attr("transform",`translate(${P.left},0)`).call(Pn(K).ticks(4).tickFormat(V=>"£"+$e(V))).selectAll("text").attr("font-size","10px").attr("fill",U),_.selectAll(".domain").attr("stroke",B);const Pe=_.append("g");
197Pe.selectAll("rect").data(W).join("rect").attr("x",V=>T(V.year)).attr("y",V=>K(V.budget)).attr("width",T.bandwidth()).attr("height",V=>K(0)-K(V.budget)).attr("rx",3).attr("fill","url(#barGrad)").attr("opacity",.85);const Q=_.append("defs").append("linearGradient").attr("id","barGrad").attr("x1","0").attr("x2","0").attr("y1","0").attr("y2","1");Q.append("stop").attr("offset","0%").attr("stop-color",a),Q.append("stop").attr("offset","100%").attr("stop-color",a).attr("opacity",.8);const Ae=Vi().defined(V=>T(V.year)!==void 0&&!isNaN(K(V.budget))).x(V=>T(V.year)+T.bandwidth()/2).y(V=>K(V.budget)).curve(Yi);_.append("path").datum(S).attr("fill","none").attr("stroke",a).attr("stroke-width",2.5).attr("d",Ae);const de=_.selectAll(".drag-circle").data(W).join("circle").attr("class","drag-circle").attr("cx",V=>T(V.year)+T.bandwidth()/2).attr("cy",V=>K(V.budget)).attr("r",6).attr("fill",a).attr("stroke",Ve("--laep-surface-panel","#fff")).attr("stroke-width",2).attr("cursor",o?"default":"ns-resize").attr("filter","drop-shadow(0 1px 2px rgba(0,0,0,.2))"),G=_.append("g").attr("opacity",0).attr("pointer-events","none"),Z=G.append("rect").attr("fill",X).attr("rx",4).attr("height",22).attr("opacity",.9),ue=G.append("text").attr("fill",pe).attr("font-size","10px").attr("text-anchor","middle").attr("dy",14),De=_.append("text").attr("x",v-P.right).attr("y",P.top-4).attr("text-anchor","end").attr("font-size","10px").attr("fill",U),Ne=()=>{const V=zn(S,ae=>ae.budget),ee=e-V,oe=Math.abs(ee),ne=oe<1;De.text(ne?`£${$e(V)} allocated â`:`£${$e(V)} / £${$e(e)}`).attr("fill",ne?R:oe>e*.05?C:U)};Ne();const xe=ri().on("start",function(){We(this).attr("r",8)}).on("drag",function(V,ee){const oe=Math.max(P.top,Math.min(A-P.bottom,V.y));let ne=K.invert(oe);ne=Math.max(0,Math.round(ne/1e4)*1e4),ee.budget=ne,de.attr("cy",L=>K(L.budget)),Pe.selectAll("rect").data(W).attr("y",L=>K(L.budget)).attr("height",L=>K(0)-K(L.budget)),_.select("path").datum(S).attr("d",Ae);const ae=T(ee.year)+T.bandwidth()/2,re=K(ee.budget),be=`${ee.year}: £${$e(ee.budget)}`;ue.text(be);const F=ue.node().getComputedTextLength()+12;Z.attr("width",F).attr("x",ae-F/2),G.attr("transform",`translate(0,${re-28})`).attr("opacity",1),ue.attr("x",ae),Ne()}).on("end",function(V,ee){We(this).attr("r",6),G.attr("opacity",0);const oe=S.map(ne=>({...ne}));w(oe),i?.(oe)});o||de.call(xe),de.on("mouseenter",function(V,ee){We(this).attr("r",7);const oe=T(ee.year)+T.bandwidth()/2,ne=K(ee.budget),ae=`${ee.year}: £${$e(ee.budget)}`;ue.text(ae);const re=ue.node().getComputedTextLength()+12;Z.attr("width",re).attr("x",oe-re/2),G.attr("transform",`translate(0,${ne-28})`).attr("opacity",1),ue.attr("x",oe)}).on("mouseleave",function(){We(this).attr("r",6),G.attr("opacity",0)})},[S,b,e,o]);const{budgetMatches:E,totalAllocated:x}=vo(e,S);return s.jsxs("div",{className:"space-y-2",children:[s.jsxs("div",{className:"flex items-center justify-between",children:[s.jsxs("label",{className:"text-xs laep-label uppercase tracking-wider font-semibold flex items-center gap-1",children:[s.jsx(Wa,{className:"w-3 h-3"})," Budget Distribution"]}),!o&&s.jsxs("div",{className:"relative",children:[s.jsxs("button",{type:"button",onClick:()=>h(_=>!_),"aria-label":"Choose budget distribution curve","aria-expanded":m,className:"flex min-h-10 xl:min-h-7 items-center gap-1 text-[10px] laep-control border rounded px-2 py-0.5 transition-colors",children:[s.jsx(bo,{className:"w-3 h-3"}),fr.find(_=>_.id===d)?.label||"Linear",s.jsx(Jt,{className:"w-3 h-3"})]}),m&&s.jsxs("div",{className:"absolute right-0 top-full mt-1 z-30 laep-panel border rounded-md shadow-lg py-1 min-w-[160px]",children:[fr.map(_=>s.jsx("button",{type:"button","aria-label":`Use ${_.label} budget curve`,"aria-pressed":d===_.id,className:`w-full min-h-10 xl:min-h-7 text-left px-3 py-1.5 text-xs hover:bg-[var(--laep-surface-muted)] transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)] ${d===_.id?"text-[var(--laep-provenance-simulation)] font-semibold bg-[var(--laep-surface-selected)]":"text-[var(--laep-text-muted)]"}`,onClick:()=>{p(_.id),k(_.id,f),h(!1)},children:_.label},_.id)),s.jsx("hr",{className:"my-1 border-[var(--laep-border-subtle)]"}),s.jsxs("button",{type:"button","aria-label":f?"Use front-loaded budget curve":"Use back-loaded budget curve","aria-pressed":f,className:`w-full min-h-10 xl:min-h-7 text-left px-3 py-1.5 text-xs hover:bg-[var(--laep-surface-muted)] transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)] ${f?"text-[var(--laep-provenance-simulation)] font-semibold":"text-[var(--laep-text-muted)]"}`,onClick:()=>{const _=!f;u(_),k(d,_),h(!1)},children:[f?"â ":"","Invert curve (back-loaded)"]})]})]})]}),s.jsx("div",{ref:c,className:"laep-panel-muted border rounded-lg p-1 overflow-hidden",children:s.jsx("svg",{ref:l,className:"w-full",style:{minHeight:180}})}),s.jsxs("div",{className:"flex items-center justify-between text-[10px]",children:[s.jsx("span",{className:"laep-soft",children:o?"Yearly spend distribution":"Drag points to adjust yearly spend"}),s.jsx("span",{className:E?"text-[var(--laep-success)] font-medium":"text-[var(--laep-warning)] font-medium",children:E?`£${$e(x)} allocated â`:`£${$e(x)} / £${$e(e)}`})]})]})},So=({weights:e,onChange:t,disabled:n=!1})=>{const r=N.useRef(),i=[{key:"carbonSavingPotential",label:"Carbon",color:"var(--laep-action)"},{key:"fuelPovertyScore",label:"Equity",color:"var(--laep-success)"},{key:"gridCapacityEfficiency",label:"Grid",color:"var(--laep-provenance-simulation)"}].map(a=>({...a,value:e[a.key]||0}));return N.useEffect(()=>{if(!r.current)return;
197const a={top:10,right:30,bottom:20,left:60},o=280-a.left-a.right,l=120-a.top-a.bottom;We(r.current).selectAll("*").remove();const c=We(r.current).attr("width",o+a.left+a.right).attr("height",l+a.top+a.bottom).append("g").attr("transform",`translate(${a.left},${a.top})`),d=ti().domain([0,1]).range([0,o]),p=ei().range([0,l]).domain(i.map(u=>u.label)).padding(.2);c.append("g").attr("class","grid").attr("transform",`translate(0,${l})`).call(ni(d).ticks(5).tickSize(-l).tickFormat("")).attr("stroke-opacity",.1),c.append("g").call(Pn(p).tickSize(0).tickPadding(10)).selectAll("text").style("font-size","10px").style("fill","var(--laep-text-muted)");const f=c.selectAll("rect").data(i).enter().append("rect").attr("x",d(0)).attr("y",u=>p(u.label)).attr("width",u=>d(u.value)).attr("height",p.bandwidth()).attr("fill",u=>u.color).attr("rx",2).style("cursor",n?"default":"pointer");if(!n&&t){const u=ri().on("drag",function(m,h){const b=m.x,S=Math.max(0,Math.min(1,d.invert(b)));We(this).attr("width",d(S)),c.selectAll(".value-label").filter(w=>w.key===h.key).attr("x",d(S)+5).text(S.toFixed(2))}).on("end",function(m,h){const b=m.x,S=Math.max(0,Math.min(1,d.invert(b))),w={...e,[h.key]:S};t(w)});f.call(u)}c.selectAll(".value-label").data(i).enter().append("text").attr("class","value-label").attr("x",u=>d(u.value)+5).attr("y",u=>p(u.label)+p.bandwidth()/2+4).text(u=>u.value.toFixed(2)).style("font-size","9px").style("fill","var(--laep-text-soft)")},[e,n]),s.jsxs("div",{className:"laep-panel-muted rounded-md p-2 border",children:[s.jsx("div",{className:"text-[10px] laep-soft uppercase tracking-tighter mb-1 font-semibold",children:n?"Priority Weighting":"Priority Weighting (Drag to adjust)"}),s.jsx("svg",{ref:r})]})},Ge="all",ct="selection",dt="predefined",rt="saved",tr=Object.freeze([{id:"all",name:"All buildings",type:"predefined",pct:100},{id:"fuel-poor-top-10",name:"Top 10% most fuel deprived",type:"predefined",sortBy:"fuelPoorPct",dir:"desc",pct:10},{id:"fuel-poor-top-25",name:"Top 25% most fuel deprived",type:"predefined",sortBy:"fuelPoorPct",dir:"desc",pct:25},{id:"pv-potential-top-10",name:"Top 10% PV generation potential",type:"predefined",sortBy:"pvKW",dir:"desc",pct:10},{id:"carbon-top-10",name:"Top 10% carbon baseline (highest)",type:"predefined",sortBy:"carbonBaseline",dir:"desc",pct:10},{id:"imd-most-deprived-10",name:"10% most deprived (IMD)",type:"predefined",sortBy:"imdRank",dir:"asc",pct:10}]);function wo(e,t){if(!e?.length)return[];if(t.id==="all"||t.pct===100)return[...e];const n=t.sortBy||"priorityScore",r=t.dir||"desc",i=Math.min(100,Math.max(1,t.pct||10))/100,a=[...e].sort((l,c)=>{const d=l[n]??0,p=c[n]??0,f=d<p?-1:d>p?1:0;return r==="asc"?f:-f}),o=Math.max(1,Math.floor(a.length*i));return a.slice(0,o)}function hr(e,t){const n=t instanceof Set?t:new Set(t?.map(String)||[]);return n.size===0?e:e.filter(r=>n.has(String(r.uprn)))}function Si(e,t,n=[],r=[]){if(!e)return t;if(!t?.length)return[];switch(e.type){case Ge:return t;case ct:{const i=e.uprns?.length?e.uprns:r;return i.length===0?t:hr(t,i)}case dt:{const i=tr.find(a=>a.id===e.predefinedId);return i?wo(t,i):t}case rt:{const i=n.find(a=>a.id===e.profileId);return i?.uprns?.length?hr(t,i.uprns):t}default:return t}}function wi(){const e=N.useContext(Xn);if(!e)throw new Error("useDashboardStore must be used within DashboardProvider. Ensure <DashboardProvider> wraps your app (e.g. in App.jsx).");const{state:t,dispatch:n,activeScenario:r,activeSession:i,selectedIntervention:a,editingIntervention:o,dataMode:l}=e;return N.useMemo(()=>({state:t,dataMode:l,activeScenario:r,activeSession:i,selectedIntervention:a,editingIntervention:o,actions:{createSession:(c,d="")=>n({type:"CREATE_SESSION",payload:{name:c,description:d}}),setActiveSession:c=>n({type:"SET_ACTIVE_SESSION",payload:{sessionId:c}}),createScenario:(c,d="",p=[])=>n({type:"CREATE_SCENARIO",payload:{name:c,description:d,interventions:p}}),createScenarioVersion:(c,d,p)=>n({type:"CREATE_SCENARIO_VERSION",payload:{scenarioId:c,name:d,changeSummary:p}}),branchScenario:(c,d,p)=>n({type:"BRANCH_SCENARIO",payload:{scenarioId:c,name:d,changeSummary:p}}),setActiveScenario:c=>n({type:"SET_ACTIVE_SCENARIO",payload:{scenarioId:c}}),deleteScenario:c=>n({type:"DELETE_SCENARIO",payload:{scenarioId:c}}),updateScenario:(c,d)=>n({type:"UPSERT_SCENARIO",payload:{scenario:{id:c,...d}}}),addIntervention:(c,d,p={})=>n({type:"ADD_INTERVENTION",payload:{scenarioId:c,intervention:d,...p}}),updateIntervention:(c,d,p,f={})=>n({type:"UPDATE_INTERVENTION",payload:{scenarioId:c,interventionId:d,updates:p,...f}}),reorderIntervention:(c,d,p,f={})=>n({type:"REORDER_INTERVENTION",payload:{scenarioId:c,interventionId:d,direction:p,...f}}),deleteIntervention:(c,d,p={})=>n({type:"DELETE_INTERVENTION",payload:{scenarioId:c,interventionId:d,...p}}),setSelectedIntervention:c=>n({type:"SET_SELECTED_INTERVENTION",payload:{interventionId:c}}),setEditingIntervention:c=>n({type:"SET_EDITING_INTERVENTION",payload:{interventionId:c}}),setCurrentYear:c=>n({type:"SET_CURRENT_YEAR",payload:{year:c}}),setWorkspaceTab:c=>n({type:"SET_WORKSPACE_TAB",payload:{tab:c}}),setPanelVisibility:(c,d)=>n({type:"SET_PANEL_VISIBILITY",payload:{panel:c,visible:d}}),setMapConfig:c=>n({type:"SET_MAP_CONFIG",payload:c}),setTableConfig:c=>n({type:"SET_TABLE_CONFIG",payload:c}),setSimulationOutput:(c,d=null)=>n({type:"SET_SIMULATION_OUTPUT",payload:{output:c,provenanceEvent:d}}),setScenarioResults:(c,d)=>
197n({type:"SET_SCENARIO_RESULTS",payload:{scenarioId:c,output:d}}),setSimulationStatus:(c,d=null)=>n({type:"SET_SIMULATION_STATUS",payload:{status:c,error:d}}),setBuildingTableTab:(c,d={})=>n({type:"SET_BUILDING_TABLE_TAB",payload:{tab:c,...d}}),setWorkflowMode:c=>n({type:"SET_WORKFLOW_MODE",payload:{mode:c}}),setWorkflowStage:c=>n({type:"SET_WORKFLOW_STAGE",payload:{stageId:c}}),setWorkflowTableFilterSummary:c=>n({type:"SET_WORKFLOW_TABLE_FILTER_SUMMARY",payload:{summary:c}}),dismissWorkflowHint:c=>n({type:"DISMISS_WORKFLOW_HINT",payload:{hintId:c}}),setSelection:c=>n({type:"SET_SELECTION",payload:{uprns:c}}),addProfile:(c,d,p={})=>n({type:"ADD_PROFILE",payload:{scenarioId:c,profile:d,...p}}),updateProfile:(c,d,p,f={})=>n({type:"UPDATE_PROFILE",payload:{scenarioId:c,profileId:d,updates:p,...f}}),addComputedField:(c,d={})=>n({type:"ADD_COMPUTED_FIELD",payload:{field:c,...d}}),updateComputedField:(c,d,p={})=>n({type:"UPDATE_COMPUTED_FIELD",payload:{fieldId:c,updates:d,...p}}),deleteComputedField:(c,d={})=>n({type:"DELETE_COMPUTED_FIELD",payload:{fieldId:c,...d}}),recordProvenanceEvent:c=>n({type:"RECORD_PROVENANCE_EVENT",payload:c}),setStorageMode:c=>n({type:"SET_STORAGE_MODE",payload:{storageMode:c}}),setPersistenceStatus:c=>n({type:"SET_PERSISTENCE_STATUS",payload:c}),hydrateFromBundle:(c,d={})=>n({type:"HYDRATE_FROM_BUNDLE",payload:{bundle:c,...d}}),mergeProvenanceEvents:c=>n({type:"MERGE_PROVENANCE_EVENTS",payload:{events:c}})}}),[t,l,r,i,a,o,n])}const _o=["insulation_cavity_wall","insulation_external_wall","insulation_roof","insulation_under_floor"],Le=[{id:"Insulation",label:"Building Insulation",colour:"#14b8a6",carbonFactor:.2,demandChange:-.6,networkScoped:!1,measures:_o,eligible:({row:e,asBool:t,entry:n})=>n.measures.some(r=>t(e[`${r}_suitability`])),cost:({row:e,asBool:t,asFloat:n,entry:r})=>r.measures.reduce((i,a)=>t(e[`${a}_suitability`])?i+n(e[`${a}_total_cost`]):i,0)},{id:"ASHP",label:"Air Source Heat Pumps",colour:"#10b981",carbonFactor:.28,demandChange:1.2,networkScoped:!1,suitabilityColumn:"ashp_suitability",costColumn:"ashp_total_cost"},{id:"PV",label:"Solar PV",colour:"#f59e0b",carbonFactor:.15,demandChange:-.8,networkScoped:!1,suitabilityColumn:"rooftop_pv_suitability",costColumn:"rooftop_pv_total_cost"},{id:"GSHP",label:"Ground Source Heat Pumps",colour:"#6366f1",carbonFactor:.32,demandChange:1,networkScoped:!1,suitabilityColumn:"gshp_suitability",costColumn:"gshp_total_cost"},{id:"Hydrogen",label:"Hydrogen Boilers",colour:"#f43f5e",carbonFactor:.12,demandChange:.5,networkScoped:!1,suitabilityColumn:"hydrogen_boiler_suitability",costColumn:"hydrogen_boiler_total_cost"},{id:"District Heating",label:"District Heating",colour:"#0ea5e9",carbonFactor:.24,demandChange:-.4,networkScoped:!0,suitabilityColumn:"district_heating_suitability",costColumn:"district_heating_total_cost"},{id:"Mixed",label:"Mixed Retrofit",colour:"#64748b",carbonFactor:.36,demandChange:.3,networkScoped:!1,dependsOn:["ASHP","PV","District Heating"],eligible:({resolved:e})=>e.ASHP.suitable&&e.PV.suitable||e["District Heating"].suitable,cost:({row:e,asFloat:t,resolved:n})=>{const r=n.ASHP.cost+n.PV.cost;return r>0?r:t(e.total_cost)}}];new Map(Le.map(e=>[e.id,e]));const _i=Le.map(({id:e,label:t})=>({id:e,label:t})),No=Object.fromEntries(Le.map(e=>[e.id,e.colour])),Co=Object.fromEntries(Le.map(e=>[e.id,e.carbonFactor])),Io=Object.fromEntries(Le.map(e=>[e.id,e.demandChange])),At=Le.filter(e=>e.networkScoped).map(e=>e.id);function gr(e,t){const n={...t,entry:e},r=e.eligible?!!e.eligible(n):t.asBool(t.row[e.suitabilityColumn]),i=e.cost?Number(e.cost(n)):t.asFloat(t.row[e.costColumn]);return{suitable:r,cost:Number.isFinite(i)?i:0}}function Eo(e,{asBool:t,asFloat:n}){const r={},i={row:e,asBool:t,asFloat:n,resolved:r};for(const l of Le)l.dependsOn||(r[l.id]=gr(l,i));for(const l of Le)l.dependsOn&&(r[l.id]=gr(l,i));const a=[],o={};for(const l of Le){const{suitable:c,cost:d}=r[l.id];c&&a.push(l.id),o[l.id]=Math.round(d*100)/100}return{suitableTech:a,estimatedCost:o}}const pt=No,Pc={pvKW:pt.PV,ashpKW:pt.ASHP,gshpKW:pt.GSHP},ye=2026,ke=2050,ko=Array.from({length:ke-ye+1},(e,t)=>ye+t),xn={label:"",tech:"ASHP",profile:{type:Ge},strategy:"multi-objective",startYear:ye,duration:3,budget:4e6,weights:{carbonSavingPotential:.5,fuelPovertyScore:.3,gridCapacityEfficiency:.2},targetEPC:"Any",status:"planned",prioritisation:{type:It,columns:[]},pluginConfig:{budget:!0,history:!0,carbon:!0,demand:!0}},we={label:"intervention-label",profile:"intervention-profile",tech:"intervention-tech",budget:"intervention-budget",startYear:"intervention-start-year",duration:"intervention-duration"},Ao=Object.freeze({budget:!0,history:!0,carbon:!0,demand:!0}
197),To=({analysisItem:e,editingItem:t,onUpdate:n,onDelete:r,interventionCount:i,onAddIntervention:a,onEdit:o,onCancelEdit:l,onStartNew:c,scenarioProfiles:d=[],selectedUprns:p=[],prioritisationColumns:f=[],workflowFocusStageId:u=null})=>{const[m,h]=N.useState(xn),b=!!(t&&e&&t.id===e.id),S=!e,w=!!e&&!b,k=S||b;ze.useEffect(()=>{h(e?{...e}:xn)},[e,b]);const E=m,x=b&&(m.budget!==e.budget||m.label!==e.label||m.tech!==e.tech||m.targetEPC!==e.targetEPC||m.startYear!==e.startYear||m.duration!==e.duration||JSON.stringify(m.profile)!==JSON.stringify(e.profile)||JSON.stringify(m.pluginConfig)!==JSON.stringify(e.pluginConfig)||JSON.stringify(m.budgetAllocations)!==JSON.stringify(e.budgetAllocations)||JSON.stringify(m.prioritisation)!==JSON.stringify(e.prioritisation)||JSON.stringify(m.weights)!==JSON.stringify(e.weights)),{state:_,actions:v}=wi(),A=N.useMemo(()=>{const C=[..._i];return E.tech&&!C.find(T=>T.id===E.tech)&&C.push({id:E.tech,label:E.tech}),C},[E.tech]),P=[{value:"all",label:"All buildings",type:Ge},...p.length>0?[{value:"selection",label:`Current table selection (${p.length} buildings)`,type:ct}]:[],...tr.filter(C=>C.id!=="all").map(C=>({value:C.id,label:C.name,type:dt,predefinedId:C.id})),...d.map(C=>({value:C.id,label:`${C.name} (${C.uprns?.length??0} buildings)`,type:rt,profileId:C.id}))],U=E.profile?.type===Ge?"all":E.profile?.type===dt?E.profile.predefinedId:E.profile?.type===ct?"selection":E.profile?.type===rt?E.profile.profileId:"all";({...Ao,...E.pluginConfig||{}});const $=C=>{if(C==="all"){h({...m,profile:{type:Ge}});return}const T=P.find(H=>H.value===C);T&&(T.type===ct?h({...m,profile:{type:ct}}):T.type===dt?h({...m,profile:{type:dt,predefinedId:T.predefinedId}}):T.type===rt&&h({...m,profile:{type:rt,profileId:T.profileId}}))},B=Kn(E.prioritisation),X=f[0]?.id||"",pe=C=>{if(C===Oe){const T=B.columns.length?B.columns:X?[{field:X,dir:"desc"}]:[];h({...m,prioritisation:{type:Oe,columns:T}})}else h({...m,prioritisation:{type:It,columns:[]}})},R=C=>{h({...m,prioritisation:{type:Oe,columns:C}})};return s.jsx("div",{className:"space-y-3",children:s.jsxs("section",{className:`relative border rounded-lg p-3 shadow-sm transition-all duration-200 ${S?"bg-[var(--laep-surface-panel)] border-[var(--laep-border-subtle)]":"bg-[var(--laep-surface-raised)] border-[var(--laep-border-strong)]"} ${["define-intervention","set-priority"].includes(u)?"ring-2 ring-[var(--laep-focus)] ring-offset-2 ring-offset-[var(--laep-surface-page)]":""}`,children:[s.jsxs("div",{className:"flex items-start justify-between mb-4 gap-2",children:[s.jsxs("div",{className:"min-w-0",children:[s.jsxs("h2",{className:"font-semibold flex items-center gap-2 text-[var(--laep-text)] min-w-0",children:[S?s.jsx(lt,{className:"w-4 h-4 shrink-0 text-[var(--laep-success)]"}):s.jsx(fo,{className:"w-4 h-4 shrink-0 text-[var(--laep-provenance-simulation)]"}),s.jsx("span",{className:"truncate",title:S?"New Intervention":b?"Edit Intervention":e.label||e.tech||"Intervention",children:S?"New Intervention":b?"Edit Intervention":e.label||e.tech||"Intervention"})]}),!S&&s.jsxs("p",{className:"mt-0.5 truncate text-[10px] text-[var(--laep-text-muted)]",children:[e.tech||"Technology"," · £",((e.budget||0)/1e6).toFixed(1),"M",w?" · read-only":""]})]}),s.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[s.jsx("div",{className:"w-3 h-3 rounded-full shadow-sm border border-black/10",style:{backgroundColor:pt[E.tech]||"#cbd5e1"},title:`${E.tech} color indicator`}),s.jsxs("div",{className:"flex items-center gap-1",children:[S&&s.jsx("button",{type:"button",onClick:()=>{a&&(a(m),h({...xn}))},"aria-label":"Add new intervention",className:"inline-flex h-10 w-10 xl:h-7 xl:w-7 items-center justify-center text-[var(--laep-action-contrast)] rounded-md transition-all shadow-sm focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",style:{backgroundColor:pt[E.tech]||"#10b981"},title:"Add new intervention",children:s.jsx(lt,{className:"w-4 h-4"})}),w&&s.jsxs(s.Fragment,{children:[s.jsx("button",{type:"button",onClick:()=>c?.(),"aria-label":"New intervention",className:"inline-flex h-10 w-10 xl:h-7 xl:w-7 items-center justify-center text-[var(--laep-success)] hover:bg-[var(--laep-success-soft)] rounded-md transition-all focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",title:"Start a new intervention",children:s.jsx(lt,{className:"w-4 h-4"})}),s.jsx("button",{type:"button",onClick:()=>o?.(),"aria-label":`Edit ${e.label||e.tech||"intervention"}`,className:"inline-flex h-10 w-10 xl:h-7 xl:w-7 items-center justify-center text-[var(--laep-text-soft)] hover:text-[var(--laep-text)] hover:bg-[var(--laep-surface-muted)] rounded-md transition-all focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",title:"Edit intervention",children:s.jsx(Qn,{className:"w-4 h-4"})})]}),b&&s.jsxs(s.Fragment,{children:[s.jsx("button",{type:"button",onClick:()=>l?.(),"aria-label":"Cancel intervention editing",className:"inline-flex h-10 w-10 xl:h-7 xl:w-7 items-center justify-center text-[var(--laep-text-soft)] hover:text-[var(--laep-text)] hover:bg-[var(--laep-surface-muted)] rounded-md transition-all focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",title:"Cancel editing",children:s.jsx(Mn,{className:"w-4 h-4"})}),s.jsx("button",{type:"button",onClick:()=>r(e.id),"aria-label":"Delete intervention",className:"inline-flex h-10 w-10 xl:h-7 xl:w-7 items-center justify-center text-[var(--laep-text-soft)] hover:text-[var(--laep-danger)] hover:bg-[var(--laep-danger-soft)] rounded-md transition-all focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",title:"Delete intervention",children:s.jsx(er,{className:"w-4 h-4"})}),s.jsxs("button",{type:"button",onClick:()=>{n(e.id,m),l?.()},"aria-label":"Save intervention changes",className:`ml-1 flex min-h-10 xl:min-h-7 items-center gap-1 px-3 xl:px-2 py-1 ${x?"bg-[var(--laep-warning)] hover:brightness-95 animate-pulse":"bg-[var(--laep-action)] hover:bg-[var(--laep-action-hover)]"} text-[var(--laep-action-contrast)] rounded-md text-[10px] font-bold transition-all shadow-sm focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]`,title:"Save changes",children:[s.jsx(za,{className:"w-3 h-3"}),x?"SAVE*":"SAVE"]})]})]})]})]}),s.jsxs("div",{className:"space-y-4",children:[s.jsxs("div",{children:[s.jsx("label",{htmlFor:we.label,className:"text-xs laep-label uppercase tracking-wider block mb-1 font-semibold",children:"Label"}),s.jsx("input",{id:we.label,type:"text",value:E.label,placeholder:S?"Name this intervention":"",disabled:!k,className:"w-full laep-control border rounded-md px-3 py-2 text-sm transition-all disabled:opacity-70 disabled:cursor-not-allowed",onChange:C=>h({...m,label:C.target.value})})]}),s.jsxs("div",{children:[s.jsxs("label",{htmlFor:we.profile,className:"text-xs laep-label uppercase tracking-wider block mb-1 font-semibold flex items-center gap-1",children:[s.jsx(mr,{className:"w-3 h-3"})," Building profile"]}),s.jsx("select",{id:we.profile,value:U,onChange:C=>$(C.target.value),disabled:!k,className:"w-full laep-control border rounded-md px-2 py-2 text-sm disabled:opacity-70 disabled:cursor-not-allowed",children:P.map(C=>s.jsx("option",{value:C.value,children:C.label},C.value))}),s.jsx("p",{className:"text-[10px] laep-soft mt-1",children:"Select via table filters or choose a predefined subset"})]}),s.jsxs("div",{className:"grid grid-cols-1 gap-4",children:[s.jsxs("div",{children:[s.jsxs("label",{htmlFor:we.tech,className:"text-xs laep-label uppercase tracking-wider block mb-1 font-semibold flex items-center gap-1",children:[s.jsx(mr,{className:"w-3 h-3"})," Technology"]}),s.jsx("select",{id:we.tech,value:E.tech,onChange:C=>h({...m,tech:C.target.value}),disabled:!k,className:"w-full laep-control border rounded-md px-2 py-2 text-sm disabled:opacity-70 disabled:cursor-not-allowed",children:A.map(C=>s.jsx("option",{value:C.id,children:C.label},C.id))})]}),s.jsxs("div",{children:[s.jsxs("label",{htmlFor:we.budget,className:"text-xs laep-label uppercase tracking-wider block mb-1 font-semibold flex items-center gap-1",children:[s.jsx(Ja,{className:"w-3 h-3"})," Budget (£m)"]}),s.jsx("input",{id:we.budget,type:"number",value:m.budget/1e6,step:"0.5",min:"0",disabled:!k,className:"w-full laep-control border rounded-md px-3 py-2 text-sm disabled:opacity-70 disabled:cursor-not-allowed",onChange:C=>{const T=parseFloat(C.target.value)*1e6;h({...m,budget:T,budgetAllocations:null})}})]})]}),s.jsxs("div",{children:[s.jsxs("label",{className:"text-xs laep-label uppercase tracking-wider block mb-1 font-semibold flex items-center gap-1",children:[s.jsx(qa,{className:"w-3 h-3"})," Timeline"]}),s.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[s.jsxs("div",{children:[s.jsx("label",{htmlFor:we.startYear,className:"text-[10px] laep-soft block mb-0.5",children:"Start year"}),s.jsx("select",{id:we.startYear,value:E.startYear,onChange:C=>{const T=parseInt(C.target.value,10);h({...m,startYear:T,budgetAllocations:null})},disabled:!k,className:"w-full laep-control border rounded-md px-2 py-1.5 text-sm disabled:opacity-70 disabled:cursor-not-allowed",children:ko.map(C=>s.jsx("option",{value:C,children:C},C))})]}),s.jsxs("div",{children:[s.jsx("label",{htmlFor:we.duration,className:"text-[10px] laep-soft block mb-0.5",children:"Duration (years)"}),s.jsx("select",{id:we.duration,value:E.duration,onChange:C=>{const T=parseInt(C.target.value,10);h({...m,duration:T,budgetAllocations:null})},disabled:!k,className:"w-full laep-control border rounded-md px-2 py-1.5 text-sm disabled:opacity-70 disabled:cursor-not-allowed",children:[1,2,3,4,5,6,7,8,9,10].map(C=>s.jsxs("option",{value:C,children:[C," year",C>1?"s":""]},C))})]})]})]}),E.duration>1&&s.jsx(xo,{totalBudget:E.budget,startYear:E.startYear,duration:E.duration,allocations:E.budgetAllocations,color:pt[E.tech]||"#3b82f6",readOnly:!k,onAllocationsChange:k?C=>{h({...m,budgetAllocations:C})}:void 0}),s.jsxs("div",{className:u==="set-priority"?"rounded-md ring-2 ring-[var(--laep-focus)] ring-offset-2 ring-offset-[var(--laep-surface-page)] p-1 -m-1":"",children:[s.jsxs("label",{htmlFor:"intervention-prioritisation-mode",className:"text-xs laep-label uppercase tracking-wider block mb-1 font-semibold flex items-center gap-1",children:[s.jsx(bi,{className:"w-3 h-3"})," Prioritisation"]}),s.jsxs("select",{id:"intervention-prioritisation-mode",value:B.type,onCh
197ange:C=>pe(C.target.value),disabled:!k,className:"w-full laep-control border rounded-md px-2 py-2 text-sm disabled:opacity-70 disabled:cursor-not-allowed",children:[s.jsx("option",{value:It,children:"Weighted score (default)"}),s.jsxs("option",{value:Oe,disabled:!f.length,children:["Sort by columns",f.length?"":" (no columns available)"]})]}),B.type===It&&s.jsxs("div",{className:"mt-2",children:[s.jsx(So,{weights:E.weights||{},disabled:!k,onChange:C=>h({...m,weights:C})}),s.jsx("p",{className:"text-[10px] laep-soft mt-1",children:"Eligible buildings are ranked by these weights each year until the annual budget runs out. Inputs are normalised across the building stock."})]}),B.type===Oe&&s.jsxs("div",{className:"mt-2 space-y-1.5",children:[B.columns.map((C,T)=>s.jsxs("div",{className:"flex items-center gap-1.5",children:[s.jsxs("select",{value:C.field,"aria-label":`Priority column ${T+1}`,disabled:!k,onChange:H=>{const W=B.columns.map((z,K)=>K===T?{...z,field:H.target.value}:z);R(W)},className:"flex-1 min-w-0 laep-control border rounded-md px-2 py-1.5 text-xs font-mono disabled:opacity-70 disabled:cursor-not-allowed",children:[!f.some(H=>H.id===C.field)&&s.jsx("option",{value:C.field,children:C.field}),["Computed fields","Building attributes"].map(H=>{const W=f.filter(z=>z.group===H);return W.length?s.jsx("optgroup",{label:H,children:W.map(z=>s.jsx("option",{value:z.id,children:z.id},z.id))},H):null})]}),s.jsx("button",{type:"button",disabled:!k,"aria-label":`Toggle sort direction for priority column ${T+1}`,title:C.dir==="asc"?"Ascending: lowest values first":"Descending: highest values first",onClick:()=>{const H=B.columns.map((W,z)=>z===T?{...W,dir:W.dir==="asc"?"desc":"asc"}:W);R(H)},className:"px-2 py-1.5 laep-control border rounded-md text-[10px] font-bold w-14 disabled:opacity-70 disabled:cursor-not-allowed",children:C.dir==="asc"?"ASC":"DESC"}),s.jsx("button",{type:"button",disabled:!k,"aria-label":`Remove priority column ${T+1}`,onClick:()=>R(B.columns.filter((H,W)=>W!==T)),className:"p-1.5 laep-control border rounded-md text-[var(--laep-text-soft)] hover:text-[var(--laep-danger)] disabled:opacity-70 disabled:cursor-not-allowed",children:s.jsx(Mn,{className:"w-3 h-3"})})]},`${C.field}-${T}`)),k&&s.jsxs("button",{type:"button","aria-label":"Add priority column",disabled:!f.length,onClick:()=>R([...B.columns,{field:X,dir:"desc"}]),className:"inline-flex items-center gap-1 px-2 py-1 laep-control border rounded-md text-[10px] disabled:opacity-70 disabled:cursor-not-allowed",children:[s.jsx(lt,{className:"w-3 h-3"})," Add sort column"]}),s.jsx("p",{className:"text-[10px] laep-soft",children:"Eligible buildings are treated in this order each year until the annual budget runs out. Ties fall through to the next column."})]})]})]})]})})};let Sn=null;async function qe(){return Sn||(Sn=ge(()=>import("./vendor-sweetalert-CRdFYMG-.js"),__vite__mapDeps([0,1])).then(e=>e.default)),Sn}const jo=N.lazy(()=>ge(()=>import("./AssistantPanel-CpypnVsz.js"),__vite__mapDeps([2,3,4,5,6,0,1,7]))),yr="inline-flex h-11 w-11 xl:h-7 xl:w-7 items-center justify-center rounded-md border border-transparent text-[var(--laep-text-muted)] transition-colors hover:border-[var(--laep-border-subtle)] hover:bg-[var(--laep-surface-muted)] hover:text-[var(--laep-text)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)] disabled:opacity-50 disabled:cursor-not-allowed",Lt="flex w-full items-center gap-2 px-3 py-2 text-left text-xs font-medium text-[var(--laep-text)] transition-colors hover:bg-[var(--laep-surface-muted)] focus:outline-none focus:bg-[var(--laep-surface-muted)]",Po=["buildings","intervention","simulation","saved"],Ro=({items:e=[],onWorkflowStageSelect:t})=>{const n=Po.map(a=>e.find(o=>o.id===a)).filter(Boolean),r=e.filter(a=>a.status==="complete").length,i=e.length||n.length;return n.length?s.jsxs("section",{className:"rounded-lg border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-panel)] p-3 shadow-sm","aria-labelledby":"scenario-readiness-heading",children:[s.jsxs("div",{className:"flex items-center justify-between gap-2",children:[s.jsxs("div",{className:"min-w-0",children:[s.jsx("h2",{id:"scenario-readiness-heading",className:"text-[10px] font-bold uppercase tracking-widest text-[var(--laep-text-muted)]",children:"Scenario Readiness"}),s.jsxs("p",{className:"mt-0.5 text-[10px] text-[var(--laep-text-soft)]",children:[r,"/",i," checks complete"]})]}),s.jsx("div",{className:"h-1.5 w-16 overflow-hidden rounded-full bg-[var(--laep-surface-muted)]","aria-hidden":"true",children:s.jsx("div",{className:"h-full rounded-full bg-[var(--laep-success)] transition-all",style:{width:`${i?Math.round(r/i*100):0}%`}})})]}),s.jsx("div",{className:"mt-2 space-y-1.5",children:n.map(a=>{const o=a.status==="complete",l=o?vi:Ga;return s.jsxs("button",{type:"button",onClick:()=>t?.(a.stageId),className:"group flex w-full items-start gap-2 rounded-md px-1.5 py-1 text-left transition-colors hover:bg-[var(--laep-surface-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:[s.jsx(l,{"aria-hidden":"true",className:`mt-0.5 h-3.5 w-3.5 shrink-0 ${o?"text-[var(--laep-success)]":"text-[var(--laep-text-soft)]"}`}),s.jsxs("span",{className:"min-w-0 flex-1",children:[s.jsxs("span",{className:"flex items-center justify-between gap-2",children:[s.jsx("span",{className:"truncate text-[10px] font-bold uppercase tracking-wide text-[var(--laep-text-muted)]",children:a.label}),s.jsx("span",{className:`shrink-0 rounded px-1 py-0.5 text-[8px] font-bold uppercase ${o?"bg-[var(--laep-success-soft)] text-[var(--laep-success)]":"bg-[var(--laep-surface-muted)] text-[var(--laep-text-muted)]"}`,children:o?"done":"open"})]}),s.jsx("span",{className:"mt-0.5 block truncate text-[10px] leading-4 text-[var(--laep-text)]",children:a.summary})]})]},a.id)})})]}):null},$o=({scenarios:e,activeSessionId:t,activeScenarioId:n,onSetActiveSession:r,onSetActiveScenario:i,onCreateScenario:a,onCreateScenarioVersion:o,onBranchScenario:l,onDeleteScenario:c,onRenameScenario:d,selectedItem:p,selectedAnalysisItem:f,onEditSelectedIntervention:u,onStartNewIntervention:m,onUpdateIntervention:h,onDeselectIntervention:b,onDeleteIntervention:S,interventionCount:w,onAddIntervention:k,scenarioProfiles:E=[],onRunSimulation:x,isDataLoading:_=!1,simulationStatus:v="idle",hasSimulationOutput:A=!1,hasActiveScenario:P=!1,selectedUprns:U=[],prioritisationColumns:$=[],onLoadDemoScenarios:B,onSaveCheckpoint:X,onExportScenarios:pe,onImportScenarios:R,isDirty:C=!1,lastSavedAt:T=null,workflowFocusStageId:H=null,readinessItems:W=[],onWorkflowStageSelect:z,assistant:K=null})=>{const[Pe,Ke]=N.useState(!1),[Q,Ae]=N.useState(()=>oi()?"assistant":"manual"),de=N.useRef(null),G=N.useMemo(()=>e.filter(Boolean),[e]),Z=G.find(F=>F.id===n),ue="ring-2 ring-[var(--laep-focus)] ring-offset-2 ring-offset-[var(--laep-surface-page)]",Ne=_?"Loading data...":v==="running"?"Running...":v==="stale"?A?"Re-run Simulation":"Run Simulation":v==="ready"?"Results up to date":v==="error"?"Retry Simulation":"Run Simulation",xe=!P||v==="running"||_||v==="ready",V=async()=>{const F=await qe();F.fire({title:"Create New Scenario",input:"text",inputLabel:"Scenario Name",inputValue:"New Scenario",inputPlaceholder:"Enter name...",showCancelButton:!0,confirmButtonText:"Create",confirmButtonColor:"#3b82f6",cancelButtonColor:"#94a3b8",preConfirm:L=>!L||!L.trim()?(F.showValidationMessage("Scenario name is required"),!1):L.trim()}).then(L=>{L.isConfirmed&&a(L.value)})},ee=async()=>
197{if(!Z)return;const F=await qe();F.fire({title:"Rename Scenario",input:"text",inputLabel:"Scenario Name",inputValue:Z.name,showCancelButton:!0,confirmButtonText:"Rename",confirmButtonColor:"#3b82f6",cancelButtonColor:"#94a3b8",preConfirm:L=>!L||!L.trim()?(F.showValidationMessage("Scenario name is required"),!1):L.trim()}).then(L=>{L.isConfirmed&&d(Z.id,L.value)})},oe=async()=>{if(!Z||!o)return;const F=await qe(),L=Number(Z.versionNumber||1);F.fire({title:"Save New Version",input:"text",inputLabel:"What changed?",inputPlaceholder:"e.g. Increased PV budget",showCancelButton:!0,confirmButtonText:"Save Version",confirmButtonColor:"#3b82f6"}).then(me=>{if(me.isConfirmed){const Fe=me.value?.trim()||`New version from ${Z.versionLabel||`v${L}`}`;o(Z.id,`${Z.branchName||Z.name} v${L+1}`,Fe)}})},ne=async()=>{if(!Z||!l)return;const F=await qe();F.fire({title:"Duplicate as Alternative",html:` 198 <input id="branch-name" class="swal2-input" aria-label="Alternative scenario name" placeholder="Alternative name" value="${Z.name} alternative"> 199 <input id="branch-summary" class="swal2-input" aria-label="Alternative scenario change summary" placeholder="What is different?" value=""> 200 `,showCancelButton:!0,confirmButtonText:"Create Alternative",confirmButtonColor:"#3b82f6",preConfirm:()=>{const L=document.getElementById("branch-name")?.value?.trim(),me=document.getElementById("branch-summary")?.value?.trim();return L?{name:L,changeSummary:me}:(F.showValidationMessage("Alternative name is required"),!1)}}).then(L=>{L.isConfirmed&&l(Z.id,L.value.name,L.value.changeSummary||"Created alternative branch")})},ae=async()=>{if(!Z||!c)return;(await qe()).fire({title:"Delete Scenario?",text:`Are you sure you want to delete "${Z.name}"? This action cannot be undone.`,icon:"warning",showCancelButton:!0,confirmButtonText:"Delete",confirmButtonColor:"#ef4444",cancelButtonColor:"#94a3b8"}).then(L=>{L.isConfirmed&&c(Z)})},re=F=>{Ke(!1),F()},be=F=>{const L=G.find(me=>me.id===F);L?.sessionId&&L.sessionId!==t&&r?.(L.sessionId),i(F)};return s.jsxs("aside",{className:"flex h-full min-h-0 flex-col gap-3",children:[s.jsxs("section",{className:`relative bg-[var(--laep-surface-panel)] border border-[var(--laep-border-subtle)] rounded-lg p-3 transition-all ${H==="save-scenario"?ue:""}`,children:[s.jsxs("div",{className:"flex items-center justify-between gap-2",children:[s.jsxs("div",{className:"flex min-w-0 items-center gap-2",children:[s.jsx(Ya,{"aria-hidden":"true",className:"w-4 h-4 text-[var(--laep-text-muted)]"}),s.jsx("h1",{className:"text-xs uppercase tracking-widest text-[var(--laep-text-muted)] font-semibold",children:"Scenario Control"})]}),s.jsx("button",{type:"button",onClick:V,title:"New scenario","aria-label":"Create new scenario",className:"inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-[var(--laep-action)] text-[var(--laep-action-contrast)] transition-colors hover:bg-[var(--laep-action-hover)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:s.jsx(lt,{"aria-hidden":"true",className:"w-4 h-4"})})]}),s.jsxs("div",{className:"mt-3 space-y-3",children:[s.jsxs("div",{className:"flex items-center gap-1.5",children:[G.length>0?s.jsx("select",{value:n||"",onChange:F=>be(F.target.value),className:"min-w-0 flex-1 bg-[var(--laep-surface-raised)] border border-[var(--laep-border-subtle)] text-[var(--laep-text)] text-xs font-medium rounded-md px-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]","aria-label":"Select scenario",title:"Scenario",children:G.map(F=>s.jsxs("option",{value:F.id,children:[F.name," ",F.versionLabel?`[${F.versionLabel}]`:""," (",F.interventions?.length||0,")"]},F.id))}):s.jsx("div",{className:"min-w-0 flex-1 rounded-md border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-raised)] px-2 py-1.5 text-xs italic text-[var(--laep-text-muted)]",children:"No scenarios"}),Z&&s.jsxs("div",{className:"relative shrink-0",children:[s.jsx("button",{type:"button",onClick:()=>Ke(F=>!F),"aria-label":"Scenario actions","aria-haspopup":"menu","aria-expanded":Pe,title:"Scenario actions",className:"inline-flex h-8 w-8 items-center justify-center rounded-md border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-raised)] text-[var(--laep-text-muted)] transition-colors hover:bg-[var(--laep-surface-muted)] hover:text-[var(--laep-text)] focu
200s:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:s.jsx(oo,{"aria-hidden":"true",className:"w-4 h-4"})}),Pe&&s.jsxs(s.Fragment,{children:[s.jsx("button",{type:"button","aria-hidden":"true",tabIndex:-1,onClick:()=>Ke(!1),className:"fixed inset-0 z-20 cursor-default"}),s.jsxs("div",{role:"menu",className:"absolute right-0 top-full z-30 mt-1 min-w-[180px] overflow-hidden rounded-md border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-panel)] py-1 shadow-lg",children:[s.jsxs("button",{type:"button",role:"menuitem",onClick:()=>re(ee),"aria-label":"Rename scenario",className:Lt,children:[s.jsx(so,{"aria-hidden":"true",className:"w-3.5 h-3.5 text-[var(--laep-text-muted)]"}),"Rename"]}),o&&s.jsxs("button",{type:"button",role:"menuitem",onClick:()=>re(oe),"aria-label":"Save as new version",className:Lt,children:[s.jsx(xi,{"aria-hidden":"true",className:"w-3.5 h-3.5 text-[var(--laep-text-muted)]"}),"Save as new version"]}),l&&s.jsxs("button",{type:"button",role:"menuitem",onClick:()=>re(ne),"aria-label":"Duplicate as alternative",className:Lt,children:[s.jsx(ro,{"aria-hidden":"true",className:"w-3.5 h-3.5 text-[var(--laep-text-muted)]"}),"Duplicate as alternative"]}),B&&s.jsxs("button",{type:"button",role:"menuitem",onClick:()=>re(B),"aria-label":"Reload demo scenarios",className:Lt,children:[s.jsx(uo,{"aria-hidden":"true",className:"w-3.5 h-3.5 text-[var(--laep-text-muted)]"}),"Reload demo scenarios"]}),c&&s.jsxs(s.Fragment,{children:[s.jsx("hr",{className:"my-1 border-[var(--laep-border-subtle)]"}),s.jsxs("button",{type:"button",role:"menuitem",onClick:()=>re(ae),"aria-label":"Delete scenario",className:"flex w-full items-center gap-2 px-3 py-2 text-left text-xs font-medium text-[var(--laep-danger)] transition-colors hover:bg-[var(--laep-danger-soft)] focus:outline-none focus:bg-[var(--laep-danger-soft)]",children:[s.jsx(er,{"aria-hidden":"true",className:"w-3.5 h-3.5"}),"Delete"]})]})]})]})]})]}),s.jsxs("div",{className:"flex items-center justify-between gap-2 border-t border-[var(--laep-border-subtle)] pt-2",children:[s.jsxs("div",{className:"flex min-w-0 items-center gap-1.5 text-[10px] font-medium text-[var(--laep-text-muted)]","aria-live":"polite",children:[s.jsx("span",{"aria-hidden":"true",className:`h-1.5 w-1.5 shrink-0 rounded-full ${C?"bg-[var(--laep-warning)]":"bg-[var(--laep-success)]"}`}),s.jsx("span",{className:"truncate",children:C?"Savingâ¦":T?"Saved":"Autosave on"})]}),s.jsxs("div",{className:"flex shrink-0 items-center gap-1",children:[X&&Z&&s.jsxs("button",{type:"button",onClick:X,title:"Save a checkpoint to the decision trail","aria-label":"Save checkpoint",className:"inline-flex h-7 items-center gap-1 rounded-md bg-[var(--laep-action)] px-2 text-[10px] font-semibold text-[var(--laep-action-contrast)] transition-colors hover:bg-[var(--laep-action-hover)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:[s.jsx(to,{"aria-hidden":"true",className:"w-3.5 h-3.5"}),"Checkpoint"]}),pe&&s.jsx("button",{type:"button",onClick:pe,title:"Export scenarios to a file","aria-label":"Export scenarios to a file",className:yr,children:s.jsx(Xa,{"aria-hidden":"true",className:"w-3.5 h-3.5"})}),R&&s.jsxs(s.Fragment,{children:[s.jsx("button",{type:"button",onClick:()=>de.current?.click(),title:"Import scenarios from a file","aria-label":"Import scenarios from a file",className:yr,children:s.jsx(eo,{"aria-hidden":"true",className:"w-3.5 h-3.5"})}),s.jsx("input",{ref:de,type:"file","aria-label":"Import scenarios file",accept:"application/json,.json",className:"hidden",onChange:F=>{const L=F.target.files?.[0];L&&R(L),F.target.value=""}})]})]})]})]})]}),s.jsxs("div",{role:"tablist","aria-label":"Intervention configuration mode",className:"flex gap-1 rounded-md border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-panel)] p-1",children:[s.jsxs("button",{type:"button",role:"tab",id:"config-tab-manual","aria-controls":"config-panel-manual","aria-selected":Q==="manual",onClick:()=>Ae("manual"),className:`flex-1 py-1 rounded text-[10px] uppercase tracking-wider font-bold flex items-center justify-center gap-1.5 transition-all ${Q==="manual"?"bg-[var(--laep-action)] text-[var(--laep-action-contrast)] shadow-sm":"text-[var(--laep-text-soft)] hover:text-[var(--laep-text)] hover:bg-[var(--laep-surface-muted)]"}`,children:[s.jsx(ho,{"aria-hidden":"true",className:"w-3 h-3"}),"Manual"]}),s.jsxs("button",{type:"button",role:"tab",id:"config-tab-assistant","aria-controls":"config-panel-assistant","aria-selected":Q==="assistant",onClick:()=>Ae("assistant"),className:`flex-1 py-1 rounded text-[10px] uppercase tracking-wider font-bold flex items-center justify-center gap-1.5 transition-all ${Q==="assistant"?"bg-[var(--laep-action)] text-[var(--laep-action-contrast)] shadow-sm":"text-[var(--laep-text-soft)] hover:text-[var(--laep-text)] hover:bg-[var(--laep-surface-muted)]"}`,children:[s.jsx(go,{"aria-hidden":"true",className:"w-3 h-3"}),"Assistant"]})]}),Q==="assistant"?s.jsx("div",{id:"config-panel-assistant",role:"tabpanel","aria-labelledby":"
200config-tab-assistant",className:"min-h-0 flex-1 pb-1",children:s.jsx(N.Suspense,{fallback:s.jsx("div",{className:"flex h-full items-center justify-center rounded-lg border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-panel)] text-xs text-[var(--laep-text-soft)]",children:"Loading assistantâ¦"}),children:s.jsx(jo,{assistant:K})})}):s.jsx("div",{id:"config-panel-manual",role:"tabpanel","aria-labelledby":"config-tab-manual",className:"min-h-0 flex-1 overflow-y-auto pr-1 pb-1",children:s.jsxs("div",{className:"space-y-3",children:[s.jsx(To,{analysisItem:f,editingItem:p,onUpdate:h,onEdit:u,onCancelEdit:b,onStartNew:m,onDelete:S,interventionCount:w,onAddIntervention:k,scenarioProfiles:E,selectedUprns:U,prioritisationColumns:$,workflowFocusStageId:H}),s.jsx(Ro,{items:W,onWorkflowStageSelect:z})]})}),x&&s.jsx("section",{"aria-live":"polite",className:`relative bg-[var(--laep-surface-panel)] border border-[var(--laep-border-subtle)] rounded-lg p-3 transition-all ${H==="run-simulation"?ue:""}`,children:s.jsxs("button",{type:"button",onClick:()=>{P&&x()},disabled:xe,"aria-busy":v==="running","aria-label":"Run simulation",className:"w-full flex items-center justify-center gap-2 px-4 py-3 bg-[var(--laep-action)] text-[var(--laep-action-contrast)] rounded-md hover:bg-[var(--laep-action-hover)] text-sm font-bold shadow-md disabled:opacity-50 disabled:cursor-not-allowed transition-all active:scale-[0.98] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:[s.jsx(co,{"aria-hidden":"true",className:"w-4 h-4 fill-current"}),Ne]})})]})},Mo=({title:e,subtitle:t,children:n,action:r,className:i=""})=>s.jsxs("section",{className:`bg-[var(--laep-surface-panel)] border border-[var(--laep-border-subtle)] rounded-lg p-3 h-full min-h-0 flex flex-col ${i}`,children:[s.jsxs("header",{className:"flex items-start justify-between mb-3 shrink-0",children:[s.jsxs("div",{children:[s.jsx("h3",{className:"text-sm font-semibold text-[var(--laep-text)]",children:e}),t?s.jsx("p",{className:"text-xs text-[var(--laep-text-muted)] mt-1",children:t}):null]}),r?s.jsx("div",{children:r}):null]}),s.jsx("div",{className:"flex-1 min-h-0",children:n})]}),Oo=[{id:"label",label:"Label"},{id:"tech",label:"Tech"},{id:"startYear",label:"Start"},{id:"duration",label:"Duration"},{id:"budget",label:"Budget"}],Lo=({interventions:e,simulationOutput:t,tableConfig:n,onTableConfigChange:r})=>{const i=N.useMemo(()=>{const a=n.query.trim().toLowerCase();let o=e.filter(l=>a?l.label.toLowerCase().includes(a)||l.tech.toLowerCase().includes(a):!0);return o=[...o].sort((l,c)=>{const d=l[n.sortBy],p=c[n.sortBy];if(d===p)return 0;const f=d>p?1:-1;return n.sortDir==="asc"?f:-f}),o.map(l=>{const c=t?.interventionSummary?.[l.id]||t?.interventionSummary?.[l.label]||{upgrades:0,carbonSaved:0,demandChange:0};return{...l,simulatedUpgrades:c.upgrades,simulatedCarbon:c.carbonSaved,simulatedDemandChange:c.demandChange||0}})},[e,t,n]);return s.jsx(Mo,{title:"Table View Scaffold",subtitle:"Cohort filtering and sortable scenario outputs",action:s.jsx(bi,{className:"w-4 h-4 laep-muted"}),children:s.jsxs("div",{className:"space-y-3",children:[s.jsxs("div",{className:"flex gap-2",children:[s.jsxs("div",{className:"flex-1 relative",children:[s.jsx(mo,{className:"w-3.5 h-3.5 absolute left-2 top-2.5 laep-muted"}),s.jsx("input",{value:n.query,onChange:a=>r({query:a.target.value}),placeholder:"Search intervention or tech",className:"w-full laep-control border rounded-md pl-7 pr-2 py-1.5 text-sm"})]}),s.jsx("select",{value:n.sortBy,onChange:a=>r({sortBy:a.target.value}),className:"laep-control border rounded-md px-2 py-1.5 text-sm",children:Oo.map(a=>s.jsx("option",{value:a.id,children:a.label},a.id))}),s.jsx("button",{onClick:()=>r({sortDir:n.sortDir==="asc"?"desc":"asc"}),className:"px-2.5 py-1.5 laep-control border rounded-md text-xs",children:n.sortDir.toUpperCase()})]}),s.jsx("div",{className:"border border-[var(--laep-border-subtle)] rounded-lg overflow-hidden",children:s.jsxs("table",{className:"w-full text-xs",children:[s.jsx("thead",{className:"bg-[var(--laep-surface-muted)] text-[var(--laep-text-muted)]",children:s.jsxs("tr",{children:[s.jsx("th",{className:"text-left px-2 py-2",children:"Intervention"}),s.jsx("th",{className:"text-left px-2 py-2",children:"Tech"}),s.jsx("th",{className:"text-left px-2 py-2",children:"Start"}),s.jsx("th",{className:"text-left px-2 py-2",children:"Years"}),s.jsx("th",{className:"text-right px-2 py-2",children:"Budget (£M)"}),s.jsx("th",{className:"text-right px-2 py-2",children:"Sim Upgrades"}),s.jsx("th",{className:"text-right px-2 py-2",children:"Sim Carbon"}),s.jsx("th",{className:"text-right px-2 py-2",children:"Sim Demand"})]})}),s.jsx("tbody",{children:i.map(a=>s.jsxs("tr",{className:"border-t border-[var(--laep-border-subtle)] text-[var(--laep-text-muted)]",children:[s.jsx("td",{className:"px-2 py-2",children:a.label}),s.jsx("td",{className:"px-2 py-2",children:a.tech}),s.jsx("td",{className:"px-2 py-2",children:a.startYear}),s.jsx("td",{className:"px-2 py-2",children:a.duration}),s.jsx("td",{className:"px-2 py-2 text-right font-mono",children:(a.budget/1e6).toFixed(1)}),s.jsx("td",{className:"px-2 py-2 text-right font-mono",children:a.simulatedUpgrades}),s.jsx("td",{className:"px-2 py-2 text-right font-mono",children:a.simulatedCarbon.toFixed(1)}),s.jsx("td",{className:"px-2 py-2 text-right font-mono",children:a.simulatedDemandChange.toFixed(1)})]},a.id))})]})})]})})},Do=N.lazy(()=>ge(()=>import("./Timeline-FzdYx3uT.js"),__vite__mapDeps([8,3,9,6,0,1,7]))),Fo=N.lazy(()=>ge(()=>import("./MapPanel-BCnzR17w.js"),__vite__mapDeps([10,3,11,12,9,6,5,0,1,7]))),Bo=N.lazy(()=>ge(()=>import("./ChartsPanel-B6VoBFMO.js"),__vite__mapDeps([13,3,6,0,1,7]))),Uo=N.lazy(()=>ge(()=>import("./DecisionTrailPanel-BeHSF_3E.js"),__vite__mapDeps([14,3,6,0,1,7]))),Ho=N.lazy(()=>ge(()=>import("./ScenarioExplanationPanel-BxDRobpi.js"),__vite__mapDeps([15,3,4,6,0,1,7]))),Vo=N.lazy(()=>ge(()=>import("./BuildingTable-CBMD9IlM.js"),__vite__mapDeps([16,3,6,0,1,7,17])
200)),Yo=[{id:"explain",label:"Explain",icon:Qa},{id:"table",label:"Data",icon:yo},{id:"charts",label:"Analytics",icon:ao}],et=({label:e})=>s.jsx("div",{role:"status","aria-live":"polite",className:"flex h-full min-h-[160px] items-center justify-center rounded-lg border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-panel)] text-xs font-semibold text-[var(--laep-text-soft)]",children:e}),Dt=(e,t,n)=>Math.min(n,Math.max(t,e)),Wo=(e,t=2e3)=>{if(typeof window<"u"&&typeof window.requestIdleCallback=="function"){const r=window.requestIdleCallback(e,{timeout:t});return()=>window.cancelIdleCallback?.(r)}const n=window.setTimeout(e,Math.min(t,1200));return()=>window.clearTimeout(n)},qo=({interventions:e,currentYear:t,selectedInterventionId:n,onSelectIntervention:r,onEditIntervention:i,onUpdateIntervention:a,onAddIntervention:o,onMoveSelectedIntervention:l,activeWorkspaceTab:c,onWorkspaceTabChange:d,tabPanels:p,tableConfig:f,simulationOutput:u,onCurrentYearChange:m,workflowFocusStageId:h=null,timelineMetric:b="carbon",onTimelineMetricChange:S})=>{const[w,k]=ze.useState("canvas"),[E,x]=ze.useState(p[c]?c:"explain"),_=p[E]?E:"explain",v=()=>{w!=="workspace"&&(x("explain"),d?.("explain")),k("workspace")};return ze.useEffect(()=>{p[c]&&x(c)},[c]),ze.useEffect(()=>{h==="review-timeline"&&k("canvas"),(h==="inspect-results"||h==="save-scenario")&&k("workspace")},[h]),s.jsxs("div",{className:"h-full min-h-0 flex flex-col",children:[s.jsxs("div",{role:"tablist","aria-label":"Workspace panel view",className:"flex gap-1 mb-0 bg-[var(--laep-surface-panel)] p-1 rounded-md border border-[var(--laep-border-subtle)]",children:[s.jsxs("button",{type:"button",role:"tab",id:"workspace-panel-tab-canvas","aria-controls":"workspace-panel-canvas","aria-selected":w==="canvas",onClick:()=>k("canvas"),className:`flex-1 py-1 rounded text-[10px] uppercase tracking-wider font-bold flex items-center justify-center gap-1.5 transition-all ${w==="canvas"?"bg-[var(--laep-action)] text-[var(--laep-action-contrast)] shadow-sm":"text-[var(--laep-text-soft)] hover:text-[var(--laep-text)] hover:bg-[var(--laep-surface-muted)]"}`,children:[s.jsx(Za,{"aria-hidden":"true",className:"w-3 h-3"}),"Timeline"]}),s.jsxs("button",{type:"button",role:"tab",id:"workspace-panel-tab-recap","aria-controls":"workspace-panel-recap","aria-selected":w==="workspace",onClick:v,className:`flex-1 py-1 rounded text-[10px] uppercase tracking-wider font-bold flex items-center justify-center gap-1.5 transition-all ${w==="workspace"?"bg-[var(--laep-action)] text-[var(--laep-action-contrast)] shadow-sm":"text-[var(--laep-text-soft)] hover:text-[var(--laep-text)] hover:bg-[var(--laep-surface-muted)]"}`,children:[s.jsx(Ka,{"aria-hidden":"true",className:"w-3 h-3"}),"Recap"]})]}),s.jsx("div",{className:`flex-1 min-h-0 overflow-hidden transition-all ${h==="review-timeline"?"ring-2 ring-blue-400 ring-offset-2 ring-offset-slate-50 rounded-lg":""}`,children:w==="canvas"?s.jsx("div",{id:"workspace-panel-canvas",role:"tabpanel","aria-labelledby":"workspace-panel-tab-canvas",className:"h-full min-h-0",children:s.jsx(N.Suspense,{fallback:s.jsx(et,{label:"Loading timeline..."}),children:s.jsx(Do,{interventions:e,simulationOutput:u,currentYear:t,setCurrentYear:m,selectedId:n,onSelectIntervention:r,onEditIntervention:i,onUpdateIntervention:a,onAddIntervention:o,onMoveSelectedUp:()=>l("up"),onMoveSelectedDown:()=>l("down"),metricMode:b,onMetricModeChange:S})})}):s.jsxs("section",{id:"workspace-panel-recap",role:"tabpanel","aria-labelledby":"workspace-panel-tab-recap",className:"bg-[var(--laep-surface-muted)] border border-[var(--laep-border-subtle)] rounded-lg p-3 h-full min-h-0 overflow-auto flex flex-col",children:[s.jsx("div",{role:"tablist","aria-label":"Workspace recap sections",className:"flex gap-1 mb-3 shrink-0 bg-[var(--laep-surface-panel)] p-1 rounded-md border border-[var(--laep-border-subtle)]",children:Yo.filter(A=>p[A.id]).map(A=>{const P=A.icon;return s.jsxs("button",{type:"button",role:"tab","aria-selected":_===A.id,onClick:()=>{x(A.id),d?.(A.id)},className:`flex-1 py-1.5 rounded text-[10px] uppercase tracking-wider font-bold flex items-center justify-center gap-1.5 transition-all ${_===A.id?"bg-[var(--laep-action)] text-[var(--laep-action-contrast)] shadow-sm":"text-[var(--laep-text-soft)] hover:text-[var(--laep-text)] hover:bg-[var(--laep-surface-muted)]"}`,children:[s.jsx(P,{"aria-hidden":"true",className:"w-3 h-3"}),A.label]},A.id)})}),s.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto",children:p[_]})]})})]})},zo=({interventions:e,selectedIntervention:t,selectedInterventionId:n,currentYear:r,simulation:i,simulationOutput:a,activeScenarioId:o=null,buildingStock:l=[],tableBuildingStock:c=null,selectedUprns:d=null,isDataLoading:p=!1,parquetCounts:f=null,activeWorkspaceTab:u,mapConfig:m,tableConfig:h,onSelectIntervention:b,onEditIntervention:S,onUpdateIntervention:w,onDeleteIntervention:k,onCurrentYearChange:E,onWorkspaceTabChange:x,onAddIntervention:_,onMoveSelectedIntervention:v,onMapConfigChange:A,onTableConfigChange:P,buildingTableTab:U,dataMode:$="raw",onBuildingTableTabChange:B,onSaveFacetAsProfile:X,onBuildingSelectionChange:pe,onCellClick:R,onRectangleSelect:C,onClearSelection:T,isMapSelectionMode:H=!1,onToggleMapSelectionMode:W,allScenarios:z=[],workflowFocusStageId:K=null,onFacetSummaryChange:Pe,readinessItems:Ke=[],decisionTrailEvents:Q=[],decisionTrailLineage:Ae=[],activeScenario:de=null,compareScenario:G=null,onScenarioSelect:Z,onWorkflowStageSelect:ue,onOpenDecisionHistory:De,onOpenFieldCalculator:Ne,scenarioExplanation:xe=null})=>{const V={explain:s.jsx(N.Suspense,{fallback:s.jsx(et,{label:"Loading explanation..."}),children:s.jsx(Ho,{explanation:xe,onSelectIntervention:b,onScenarioSelect:Z,onWorkflowStageSelect:ue})}),table:s.jsx(Lo,{interventions:e,simulationOutput:a,tableConfig:h,onTableConfigChange:P}),charts:s.jsx(N.Suspense,{fallback:s.jsx(et,{label:"Loading analytics..."}),children:s.jsx(Bo,{simulation:i,simulationOutput:a})})},ee=U??"raw",oe=c??l,[ne,ae]=N.useState(52),[re,be]=N.useState(66),[F,L]=N.useState(300),me=K==="set-area"||H||!!m?.splitView,[Fe,yt]=N.useState(()=>typeof process<"u"&&process?.env?.NODE_ENV==="test"?!0:me);N.useEffect(()=>{if(!Fe){if(me){yt(!0);return}if(!p)return Wo(()=>yt(!0),2200)}},[p,Fe,me]);const dn=q=>{q.preventDefault();const he=q.currentTarget.closest("main")?.getBoundingClientRect?.().height||window.innerHeight||1,Te=q.clientY,Ze=ne,Be=document.body.style.cursor,Ue=document.body.style.userSelect;document.body.style.cursor="row-resize",document.body.style.userSelect="none";const Re=it=>{const bt=Ze+(it.clientY-Te)/he*100;ae(Dt(bt,35,70))},Se=()=>{document.body.style.cursor=Be,document.body.style.userSelect=Ue,window.removeEventListener("pointermove",Re),window.removeEventListener("pointerup",Se)};window.addEventListener("pointermove",Re),window.addEventListener("pointerup",Se)},Tt=q=>{if(!["ArrowUp","ArrowDown","Home","End"].includes(q.key))return;if(q.preventDefault(),q.key==="Home"){ae(35);return}if(q.key==="End"){ae(70);return}const fe=q.shiftKey?8:4;ae(he=>Dt(he+(q.key==="ArrowDown"?fe:-fe),35,70))},un=q=>{q.preventDefault();const he=q.currentTarget.parentElement?.getBoundingClientRect?.().width||window.innerWidth||1,Te=q.clientX,Ze=re,Be=document.body.style.cursor,Ue=document.body.style.userSelect;document.body.style.cursor="col-resize",document.body.style.userSelect="none";const Re=it=>{const bt=Ze+(it.clientX-Te)/he*100;be(Dt(bt,45,78))},Se=()=>{document.body.style.cursor=Be,document.body.style.userSelect=Ue,window.removeEventListener("pointermove",Re),window.removeEventListener("pointerup",Se)};window.addEventListener("pointermove",Re),window.addEventListener("pointerup",Se)},pn=q=>{if(!["ArrowLeft","ArrowRight","Home","End"].includes(q.key))return;if(q.preventDefault(),q.key==="Home"){be(45);return}if(q.key==="End"){be(78);return}const fe=q.shiftKey?8:4;be(he=>Dt(he+(q.key==="ArrowRight"?fe:-fe),45,78))},jt=q=>{q.preventDefault();const fe=q.clientX,he=F,Te=document.body.style.cursor,Ze=document.body.style.userSelect;document.body.style.cursor="col-resize",document.body.style.userSelect="none";
200const Be=Re=>{const Se=he+fe-Re.clientX;L(Math.min(520,Math.max(220,Se)))},Ue=()=>{document.body.style.cursor=Te,document.body.style.userSelect=Ze,window.removeEventListener("pointermove",Be),window.removeEventListener("pointerup",Ue)};window.addEventListener("pointermove",Be),window.addEventListener("pointerup",Ue)},mn=q=>{if(!["ArrowLeft","ArrowRight","Home","End"].includes(q.key))return;if(q.preventDefault(),q.key==="Home"){L(220);return}if(q.key==="End"){L(520);return}const fe=q.shiftKey?40:20;L(he=>{const Te=q.key==="ArrowLeft"?he+fe:he-fe;return Math.min(520,Math.max(220,Te))})};return s.jsxs("main",{className:"min-h-full flex flex-col gap-3 overflow-visible xl:grid xl:h-full xl:grid-rows-[var(--top-pane-height)_8px_minmax(0,1fr)] xl:gap-0 xl:overflow-hidden",style:{"--top-pane-height":`${ne}%`,"--map-pane-width":`${re}%`,"--decision-trail-width":`${F}px`},children:[s.jsxs("section",{className:"grid grid-cols-12 gap-3 min-h-[640px] overflow-visible xl:grid-cols-[minmax(0,var(--map-pane-width))_8px_minmax(280px,1fr)] xl:gap-x-0 xl:min-h-0 xl:overflow-hidden",children:[s.jsx("div",{className:"col-span-12 min-h-[360px] xl:col-span-1 xl:min-h-0 xl:overflow-hidden",children:Fe?s.jsx(N.Suspense,{fallback:s.jsx(et,{label:"Loading map..."}),children:s.jsx(Fo,{simulation:i,interventions:e,simulationOutput:a,currentYear:r,mapConfig:m,onMapConfigChange:A,allScenarios:z,activeScenarioId:o,buildingStock:oe,filteredUprns:d,isDataLoading:p,dataMode:$,tableView:ee,onCellClick:R,onRectangleSelect:C,onClearSelection:T,isMapSelectionMode:H,onToggleMapSelectionMode:W,workflowHighlighted:K==="set-area"})}):s.jsx(et,{label:"Preparing map..."})}),s.jsx("div",{role:"separator","aria-label":"Resize map and timeline panels","aria-orientation":"vertical","aria-valuemin":45,"aria-valuemax":78,"aria-valuenow":Math.round(re),"aria-valuetext":`${Math.round(re)} percent map width`,tabIndex:0,onPointerDown:un,onKeyDown:pn,className:"hidden min-h-0 cursor-col-resize items-stretch justify-center rounded transition-colors hover:bg-[var(--laep-surface-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)] xl:flex",children:s.jsx("span",{className:"my-2 w-px rounded bg-[var(--laep-border-strong)]"})}),s.jsx("div",{className:"col-span-12 min-h-[300px] xl:col-span-1 xl:min-h-0 xl:overflow-hidden flex flex-col gap-3",children:s.jsx(qo,{interventions:e,currentYear:r,selectedInterventionId:n,onSelectIntervention:b,onEditIntervention:S,onUpdateIntervention:w,onAddIntervention:_,onMoveSelectedIntervention:v,activeWorkspaceTab:u,onWorkspaceTabChange:x,tabPanels:V,tableConfig:h,simulationOutput:a,onCurrentYearChange:E,workflowFocusStageId:K,timelineMetric:m?.timelineMetric||"carbon",onTimelineMetricChange:q=>A?.({timelineMetric:q})})})]}),s.jsx("div",{role:"separator","aria-label":"Resize upper workspace and table panels","aria-orientation":"horizontal","aria-valuemin":35,"aria-valuemax":70,"aria-valuenow":Math.round(ne),"aria-valuetext":`${Math.round(ne)} percent upper workspace height`,tabIndex:0,onPointerDown:dn,onKeyDown:Tt,className:"hidden cursor-row-resize items-center justify-stretch rounded transition-colors hover:bg-[var(--laep-surface-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)] xl:flex",children:s.jsx("span",{className:"mx-2 h-px flex-1 rounded bg-[var(--laep-border-strong)]"})}),s.jsxs("section",{className:"grid grid-cols-1 gap-y-3 min-h-[620px] overflow-visible xl:grid-cols-[minmax(0,1fr)_8px_var(--decision-trail-width)] xl:gap-y-0 xl:min-h-0 xl:overflow-hidden",children:[s.jsx("div",{className:`min-h-[360px] xl:min-h-0 xl:overflow-hidden transition-all rounded-lg ${["refine-buildings","inspect-results"].includes(K)?"ring-2 ring-blue-400 ring-offset-2 ring-offset-slate-50":""}`,children:s.jsx(N.Suspense,{fallback:s.jsx(et,{label:"Loading table..."}),children:s.jsx(Vo,{simulationOutput:a,comparisonOutput:G?.results||null,comparisonScenarioName:G?.name||"",isComparisonEnabled:!!(m?.splitView&&G),buildingStock:oe,isDataLoading:p,parquetCounts:f,selectedInterventionId:n,selectedInterventionLabel:t?.label||"",currentYear:r,activeTab:ee,onActiveTabChange:B||(()=>{}),onSaveFacet:X,onSelectionChange:pe,onFacetSummaryChange:Pe,selectedUprns:d,onOpenFieldCalculator:Ne})})}),s.jsx("div",{role:"separator","aria-label":"Resize decision trail","aria-orientation":"vertical","aria-valuemin":220,"aria-valuemax":520,"aria-valuenow":Math.round(F),"aria-valuetext":`${Math.round(F)} pixel decision trail width`,tabIndex:0,onPointerDown:jt,onKeyDown:mn,className:"hidden xl:flex min-h-0 cursor-col-resize items-stretch justify-center rounded transition-colors hover:bg-[var(--laep-surface-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:s.jsx("span",{className:"my-2 w-px rounded bg-[var(--laep-border-strong)]"})}),s.jsx("div",{className:"min-h-[240px] xl:min-h-0 xl:overflow-hidden",children:s.jsx(N.Suspense,{fallback:s.jsx(et,{label:"Loading decision trail..."}),children:s.jsx(Uo,{events:Q,lineage:Ae,activeScenario:de,onScenarioSelect:Z,onOpenHistory:De})})})]})]})},Go=[{id:"buildings",stageId:"refine-buildings",label:"Buildings"},{id:"intervention",stageId:"define-intervention",label:"Intervention"},{id:"priority",stageId:"set-priority",label:"Priority"},{id:"simulation",stageId:"run-simulation",label:"Simulation"},{id:"results",stageId:"inspect-results",label:"Results"},{id:"saved",stageId:"save-scenario",label:"Saved"}];function Ko(e=[],t,n=null){return N.useMemo(()=>{const r=Array.isArray(e)?e:[];if(n?.yearly){const l=n.yearly[String(t)]||{upgrades:0,carbonSaved:0},c=Object.values(n.yearly),d=c.reduce((u,m)=>u+(m?.budget||0),0),p=c.reduce((u,m)=>u+(m?.carbonSaved||0),0),f=c.reduce((u,m)=>u+(m?.demandChange||0),0);return{totalBudget:d,cumulativeCarbonScore:Math.round(p),activeInYear:l.upgrades||0,estimatedGridPressure:Math.max(0,Math.round((l.upgrades||0)*6+(l.carbonSaved||0)*.4+(l.demandChange||0)*2)),estimatedEquityScore:Math.min(100,Math.round(35+(l.upgrades||0)*5)),annualDemandChange:l.demandChange||0,cumulativeDemandChange:Math.round(f*10)/10}}const i=r.reduce((l,c)=>l+(c?.budget||0),0),a=r.reduce((l,c)=>{const d=c?.impact;return Array.isArray(d)&&d.length>0?l+Math.max(...d,0):l},0),o=r.filter(l=>l&&t>=l.startYear&&t<l.startYear+(l.duration||0)).length;return{totalBudget:i,cumulativeCarbonScore:a,activeInYear:o,estimatedGridPressure:Math.max(0,Math.round(o*7+a*.5)),estimatedEquityScore:Math.min(100,Math.round(30+r.length*8))}},[e,t,n])}function Zo(){const[e,t]=N.useState(!1),[n,r]=N.useState(null),[i,a]=N.useState(!1),[o,l]=N.useState(null),{dispatch:c}=N.useContext(Xn),d=N.useCallback(async({session:f,scenario:u,provenanceEvents:m=[]})=>{t(!0),r(null);try{const h=await ge(()=>import("./api-CVce_W2q.js"),__vite__mapDeps([18,19,20,7]));let b;f.source==="remote"?b=f:b=await h.createSession(f.name,f.description||"Created from dashboard"),
200c({type:"UPSERT_SESSION",payload:{session:{id:b.id,name:b.name,description:b.description||"",createdAt:b.created_at||b.createdAt||null,source:"remote"},setActive:!0}});let w=null;if(u){const k=u.source==="remote",E={interventions:u.interventions,created_from:"dashboard-ui",profiles:u.profiles||[],provenanceId:u.provenanceId,lineageRootProvenanceId:u.lineageRootProvenanceId,parentScenarioProvenanceId:u.parentScenarioProvenanceId,branchName:u.branchName,versionNumber:u.versionNumber,versionLabel:u.versionLabel,changeSummary:u.changeSummary,forkedFromEventId:u.forkedFromEventId};if(k){const{supabase:x}=await ge(async()=>{const{supabase:A}=await import("./supabase-Bv9-lbLI.js");return{supabase:A}},__vite__mapDeps([19,20,7])),{data:_,error:v}=await x.from("scenarios").update({name:u.name,config:E}).eq("id",u.id).select().single();if(v)throw v;w=_}else w=await h.createScenario(b.id,u.name,E);c({type:"UPSERT_SCENARIO",payload:{scenario:{id:w.id,sessionId:w.session_id||w.sessionId,name:w.name,description:w.description||"",interventions:w.interventions||w.config?.interventions||[],profiles:w.profiles||w.config?.profiles||[],provenanceId:w.config?.provenanceId||u.provenanceId||w.id,lineageRootProvenanceId:w.config?.lineageRootProvenanceId||u.lineageRootProvenanceId||w.config?.provenanceId||u.provenanceId||w.id,parentScenarioProvenanceId:w.config?.parentScenarioProvenanceId||u.parentScenarioProvenanceId||null,branchName:w.config?.branchName||u.branchName||w.name,versionNumber:w.config?.versionNumber||u.versionNumber||1,versionLabel:w.config?.versionLabel||u.versionLabel||"v1",changeSummary:w.config?.changeSummary||u.changeSummary||null,forkedFromEventId:w.config?.forkedFromEventId||u.forkedFromEventId||null,createdAt:w.created_at||w.createdAt||null,results:w.results||null,source:"remote"},setActive:!0,logEvent:!1}})}return m.length&&await h.syncProvenanceEvents(m),{session:b,scenario:w}}catch(h){throw r(h),h}finally{t(!1)}},[c]),p=N.useCallback(async()=>{a(!0),l(null);try{const f=await ge(()=>import("./api-CVce_W2q.js"),__vite__mapDeps([18,19,20,7])),m=(await f.getSessions()||[]).map(x=>({id:x.id,name:x.name,description:x.description||"",createdAt:x.created_at||x.createdAt||null,source:"remote"}));c({type:"SET_SESSIONS",payload:{sessions:m}});const h=(m||[]).map(async x=>(await f.getScenariosBySession(x.id)||[]).map(v=>({id:v.id,sessionId:v.session_id||v.sessionId,name:v.name,description:v.description||"",interventions:v.interventions&&v.interventions.length>0?v.interventions:v.config?.interventions||[],profiles:v.profiles||v.config?.profiles||[],provenanceId:v.config?.provenanceId||v.id,lineageRootProvenanceId:v.config?.lineageRootProvenanceId||v.config?.provenanceId||v.id,parentScenarioProvenanceId:v.config?.parentScenarioProvenanceId||null,branchName:v.config?.branchName||v.name,versionNumber:v.config?.versionNumber||1,versionLabel:v.config?.versionLabel||"v1",changeSummary:v.config?.changeSummary||null,forkedFromEventId:v.config?.forkedFromEventId||null,createdAt:v.created_at||v.createdAt||null,results:v.results||null,source:"remote"}))),b=(m||[]).map(async x=>{try{return await f.getProvenanceEvents(x.id)}catch(_){return console.warn("Failed to fetch provenance events:",_),[]}}),S=await Promise.all(h),w=await Promise.all(b),k=S.flat(),E=w.flat();return k.length&&c({type:"SET_SCENARIOS",payload:{scenarios:k}}),E.length&&c({type:"MERGE_PROVENANCE_EVENTS",payload:{events:E}}),{sessions:m,scenarios:k,provenanceEvents:E}}catch(f){throw l(f),f}finally{a(!1)}},[c]);return{isSaving:e,saveError:n,saveSessionToBackend:d,isLoadingRemote:i,loadError:o,loadRemoteSessions:p}}class Jo{constructor(t,n){this.columns=t,this.data=n}identityFacet(){return{columns:this.columns.slice(),data:this.data.slice(),getRowCount(){return this.data.length},getRow(t){return this.data[t]}}}}function Xo(e,t,n,r={}){const{includeUntouched:i=!1,keepColumns:a=[],naValue:o="n/a",outputBuilder:l}=r,c=o,d=a===null?[]:Array.isArray(a)?a:[],p=R=>String(R).toLowerCase(),f=new Set(["uprn","year"]),u=Array.from(e||[]),m=[],h=new Set(["uprn","year"]);for(const R of u){if(!R)continue;const C=p(R);f.has(C)||h.has(C)||(m.push(R),h.add(C))}const b=t?.getRowCount?.()??0,S=new Map;for(let R=0;R<b;R++){const C=t.getRow(R)||{},T=C?.uprn??C?.UPRN??C?.id;T!=null&&S.set(String(T),C)}const w=(R,C)=>{if(!R||C==null)return;if(Object.prototype.hasOwnProperty.call(R,C))return R[C];const T=p(C);for(const H in R)if(p(H)===T)return R[H]},k=R=>{const C=Math.min(b,200);for(let T=0;T<C;T++)if(w(t.getRow(T)||{},R)!==void 0)return!0;return!1},E=[],x=[],_=new Set,v=R=>{if(R)for(const C of Object.keys(R)){if(C==="uprn"||C==="id"||C==="building"||C==="year")continue;const T=p(C);f.has(T)||h.has(T)||_.has(T)||(_.add(T),x.push(C),h.add(T))}},A=Object.keys(n||{}).map(R=>Number(R)).filter(R=>!isNaN(R)).sort((R,C)=>R-C);for(const R of A){const C=String(R),T=Array.isArray(n[C])?n[C]:[n[C]];for(const H of T){if(!H)continue;const W=H.stats??{},z=H.building??W.uprn??W.id??W.building;z!=null&&(E.push({uprn:String(z),year:C,stats:W}),v(W))}}const P=[...m];for(const R of d){if(!R)continue;const C=p(R);f.has(C)||h.has(C)||k(R)&&(P.push(R),h.add(C))}const U=["uprn","year",...x,...P],$=[],B=new Set;for(const{uprn:R,year:C,stats:T}of E){const H=S.get(R)||{},W=[];
200W.push(R??c),W.push(C??c);for(const z of x)W.push(Object.prototype.hasOwnProperty.call(T,z)?T[z]:c);for(const z of P){const K=w(H,z);W.push(K!==void 0?K:c)}$.push(W),B.add(R)}if(i)for(let R=0;R<b;R++){const C=t.getRow(R)||{},T=String(C?.uprn??C?.UPRN??C?.id??"");if(!T||B.has(T))continue;const H=[];H.push(C?.uprn??C?.UPRN??C?.id??c),H.push(c);for(const W of x)H.push(c);for(const W of P){const z=w(C,W);H.push(z!==void 0?z:c)}$.push(H)}return l?l(U,$,t):new Jo(U,$).identityFacet()}const Qo=new Map;function br(e){return Qo.get(e)??null}const wn=/^\d+\.\d+\.\d+(-.+)?$/,Ln=["predicate","prioritiser","upgrade","constraint","adapter","outputBuilder","composite"];function es(e){const t=[];if(!e||typeof e!="object")return t.push("manifest must be an object"),{valid:!1,errors:t};(!e.name||typeof e.name!="string")&&t.push("manifest.name is required and must be a string"),(!e.version||typeof e.version!="string"||!wn.test(e.version))&&t.push("manifest.version is required and must be semver (e.g. 1.0.0)");const n=Array.isArray(e.kind)?e.kind:[e.kind];return(!e.kind||n.length===0||n.some(r=>!Ln.includes(r)))&&t.push(`manifest.kind must be one of: ${Ln.join(", ")}`),(!e.entry||typeof e.entry!="string")&&t.push("manifest.entry is required and must be a string"),e.exports&&typeof e.exports!="object"&&t.push("manifest.exports must be an object when present"),e.exports&&Object.values(e.exports).some(r=>typeof r!="string")&&t.push("manifest.exports values must be strings"),e.configSchema&&typeof e.configSchema!="object"&&t.push("manifest.configSchema must be an object when present"),e.trusted!==void 0&&typeof e.trusted!="boolean"&&t.push("manifest.trusted must be a boolean when present"),e.compat&&e.compat.package!=="interactive-scenario-modeller"&&t.push('manifest.compat.package must be "interactive-scenario-modeller" when present'),e.compat?.minVersion&&!wn.test(e.compat.minVersion)&&t.push("manifest.compat.minVersion must be semver when present"),e.compat?.maxVersion&&!wn.test(e.compat.maxVersion)&&t.push("manifest.compat.maxVersion must be semver when present"),{valid:t.length===0,errors:t}}function ts(e){const t=[];if(!e||typeof e!="object")return{valid:!1,errors:["registration must be an object"]};const n=es(e.manifest);n.valid||t.push(...n.errors);const r=Array.isArray(e?.manifest?.kind)?e.manifest.kind:[e?.manifest?.kind],i={predicate:"predicate",prioritiser:"prioritise",upgrade:"upgrade",constraint:"constraint",adapter:"adapter",outputBuilder:"outputBuilder",composite:null};for(const a of r){if(!Ln.includes(a))continue;const o=a,l=i[o];l&&typeof e[l]!="function"&&t.push(`plugin kind "${o}" requires a "${l}" function`)}return{valid:t.length===0,errors:t}}const Ni=new Map;function Ft(e){if(!e?.manifest?.name)throw new Error("Plugin manifest must include name");const t=ts(e);if(!t.valid)throw new Error(`Invalid plugin registration: ${t.errors.join("; ")}`);Ni.set(e.manifest.name,e)}function vr(e){return Ni.get(e)}class ns{constructor(t,n={}){this.name=t,this.description=n.description??"",this.facet=n.facet,this.startYear=n.startYear??null,this.endYear=n.endYear??null,this.propertySpec=n.propertySpec,this.setupBuilding=n.setupBuilding,this._filter=n.filter??(()=>!0),this._prioritise=n.prioritise??(()=>0),this._upgrade=n.upgrade??(()=>({})),this.init=n.init??(()=>{}),this.finalise=n.finalise??(()=>{}),this.initYear=n.initYear??(()=>{}),this.finaliseYear=n.finaliseYear??(()=>{}),this.buildings=null,this.simulatedFacet=null}resolvePredicate(t){if(typeof t=="function")return t;if(typeof t=="string"){const n=br(t);if(n)return n;if(t.includes(":")){const[r,i]=t.split(":"),a=vr(r);if(a&&a[i])return a[i]}}return null}get filter(){return this._filter}set filter(t){this._filter=t}get prioritise(){return this._prioritise}set prioritise(t){this._prioritise=t}get upgrade(){return this._upgrade}set upgrade(t){this._upgrade=t}isSeed(){return!(Number.isFinite(this.startYear)&&Number.isFinite(this.endYear))}update(t){return Object.assign(this,t),t.filter!==void 0&&(this._filter=t.filter),t.prioritise!==void 0&&(this._prioritise=t.prioritise),t.upgrade!==void 0&&(this._upgrade=t.upgrade),this}simulate(t=null){if(this.isSeed())return console.warn(`Intervention "${this.name}" is a seed; simulate() skipped.`),{state:{},metrics:{},buildings:[],columns:new Set};const n=this.propertySpec?.()??{columns:[]};let r=[];if(t){r=t.slice();const u=new Map(r.filter(h=>h&&h.uprn!==void 0).map(h=>[String(h.uprn),h])),m=this.facet?.getRowCount?.()??0;for(let h=0;h<m;h++){const b=this.facet.getRow(h),S=b?.UPRN??b?.uprn;if(S!=null){const w=u.get(String(S));w&&this.setupBuilding&&this.setupBuilding(b,w)}}}else{const u=this.facet?.getRowCount?.()??0;r=new Array(u);for(let m=0;m<u;m++){const h=this.facet.getRow(m);r[m]=this.setupBuilding?this.setupBuilding(h):{...h}}}this.buildings=r;let i=0;const a={},o={},l={year:this.startYear,state:a,resolvePredicate:u=>br(u),resolvePlugin:u=>vr(u),random:u=>{let m=u?String(u).split("").reduce((h,b)=>(h=(h<<5)-h+b.charCodeAt(0),h&h),0):Math.random();return()=>(m=Math.sin(m)*1e4,m-Math.floor(m))},logger:{debug:(...u)=>console.debug(`[${this.name}]`,...u),info:(...u)=>console.log(`[${this.name}]`,...u),warn:(...u)=>console.warn(`[${this.name}]`,...u),error:(...u)=>console.error(`[${this.name}]`,...u)}};this.init(l);const c=this.resolvePredicate(this._filter),d=this.resolvePredicate(this._upgrade),p=this._prioritise==="random"?"random":this.resolvePredicate(this._prioritise);for(let u=this.startYear;u<=this.endYear;u++){o[String(u)]=[],l.year=u,this.initYear(u,l,o);const m=[];for(let h=0;h<r.length;h++){const b=r[h];if(b)try{c&&c(b,l)&&m.push(h)}catch(S){l.logger.error("Filter error:",S)}}p==="random"?this.shuffle(m):p&&m.sort((h,b)=>{try{return p(r[h],r[b],l)||0}catch(S){return l.logger.error("Prioritise error:",S),0}});for(const h of m){const b=r[h];if(!b)continue;let S={};try{d&&(S=d(b,l)||{})}catch(w){l.logger.error("Upgrade error:",w)}if(S&&Object.keys(S).length>0){const w={...S};w.building===void 0&&(w.building=b.uprn??b.UPRN??b.id),w.year===void 0&&(w.year=u),w.order===void 0&&(w.order=++i),o[String(u)].push({building:w.building,stats:w})}}this.finaliseYear(u,l,o)}this.finalise(l);const f=new Set((n.columns||[]).map(u=>typeof u=="string"?u:u.name));return this.simulatedFacet=Xo(f,this.facet,o),{state:a,metrics:o,buildings:r,columns:f}}shuffle(t){for(let n=t.length-1;n>0;n--){const r=Math.floor(Math.random()*(n+1));[t[n],t[r]]=[t[r],t[n]]}return t}getPredicateSource(t){const n=this[`_${t}`]||this[t];return typeof n=="function"?n.toString():String(n)}}const Xt=e=>({getRowCount(){return e.length},getRow(t){return e[t]},colNames:e.length?Object.keys(e[0]):[]});class rs{constructor(t=[]){this.interventions=[],this.interventions=t}add(t){this.interventions.push(t)}run(){const t=[];let n=null;for(const r of this.interventions){const i=r.simulate(n),a={...i,simulatedFacet:r.simulatedFacet??null};t.push({name:r.name,result:a}),n=i.buildings}return t}}function is(e={}){const{name:t="scenario-budget-guard-upgrade",version:n="1.0.0",interventionStateKey:r="currentIntervention",annualBudgetStateKey:i="annualBudget",remainingBudgetStateKey:a="remainingBudget",currentUpgradeCostStateKey:o="currentUpgradeCost"}=e;
200return{manifest:{name:t,version:n,kind:["upgrade"],description:"Ensures annual intervention budget is respected",entry:"internal:plugin",compat:{package:"interactive-scenario-modeller",minVersion:"0.1.0"},trusted:!0,exports:{upgrade:"upgrade"}},upgrade:(c,d)=>{const p=d.state,u=(p[r]??{}).tech;if(!u)return{};const m=Number(c?.estimatedCost?.[u]??0);if(!Number.isFinite(m)||m<=0)return{};const h=Number(p[i]??0),b=Number(p[a]??h);return b<m?{}:(p[a]=b-m,p[o]=m,{cost:m,annualBudget:h,remainingBudget:p[a]})}}}function as(e={}){const{name:t="scenario-intervention-history-upgrade",version:n="1.0.0",interventionStateKey:r="currentIntervention",currentUpgradeCostStateKey:i="currentUpgradeCost"}=e;return{manifest:{name:t,version:n,kind:["upgrade"],description:"Applies building upgrade state and intervention history",entry:"internal:plugin",compat:{package:"interactive-scenario-modeller",minVersion:"0.1.0"},trusted:!0,exports:{upgrade:"upgrade"}},upgrade:(o,l)=>{const c=l.state,d=c[r]??{},p=d.tech;if(!p)return{};const f=Number(c[i]??0);return o.upgraded=!0,o.yearUpgraded||(o.yearUpgraded=l.year),o.deployedTech=p,Array.isArray(o.deployedTechs)||(o.deployedTechs=[]),o.deployedTechs.includes(p)||o.deployedTechs.push(p),Array.isArray(o.interventionHistory)||(o.interventionHistory=[]),o.interventionHistory.push({interventionId:d.id??d.label,interventionLabel:d.label,technology:p,year:l.year,cost:f}),{building:o.uprn??o.UPRN??o.id,interventionId:d.id??d.label,intervention:d.label,technology:p,year:l.year}}}}function os(e={}){const{name:t="scenario-carbon-impact-upgrade",version:n="1.0.0",interventionStateKey:r="currentIntervention",carbonFactorByTech:i={},defaultCarbonFactor:a=.28}=e,o={ASHP:.28,PV:.15,GSHP:.32,Hydrogen:.12,"District Heating":.24,Mixed:.36};return{manifest:{name:t,version:n,kind:["upgrade"],description:"Computes technology-specific carbon impact",entry:"internal:plugin",compat:{package:"interactive-scenario-modeller",minVersion:"0.1.0"},trusted:!0,exports:{upgrade:"upgrade"}},upgrade:(c,d)=>{const u=(d.state[r]??{}).tech;if(!u)return{};const m=i[u]??o[u]??a;return{carbonSaved:Math.round(Number(c.carbonBaseline??0)*m*100)/100}}}}function ss(e={}){const{name:t="scenario-demand-impact-upgrade",version:n="1.0.0",interventionStateKey:r="currentIntervention",demandChangeByTech:i={},defaultDemandChange:a=0}=e,o={ASHP:1.2,PV:-.8,GSHP:1,Hydrogen:.5,"District Heating":-.4,Mixed:.3};return{manifest:{name:t,version:n,kind:["upgrade"],description:"Computes technology-specific demand impact",entry:"internal:plugin",compat:{package:"interactive-scenario-modeller",minVersion:"0.1.0"},trusted:!0,exports:{upgrade:"upgrade"}},upgrade:(c,d)=>{const u=(d.state[r]??{}).tech;return u?{demandChange:i[u]??o[u]??a}:{}}}}const Dn=[{uprn:"B-001",area:"North Ward",priorityScore:92,carbonBaseline:9.2,suitableTech:["ASHP","PV"],estimatedCost:{ASHP:12e4,PV:65e3,Mixed:18e4},location:{lat:51.0621,lon:-1.3184}},{uprn:"B-002",area:"North Ward",priorityScore:81,carbonBaseline:7.5,suitableTech:["ASHP","Mixed"],estimatedCost:{ASHP:11e4,PV:7e4,Mixed:16e4},location:{lat:51.0642,lon:-1.3118}},{uprn:"B-003",area:"Central Ward",priorityScore:88,carbonBaseline:8.8,suitableTech:["PV","Mixed"],estimatedCost:{ASHP:14e4,PV:6e4,Mixed:15e4},location:{lat:51.0576,lon:-1.3049}},{uprn:"B-004",area:"Central Ward",priorityScore:74,carbonBaseline:6.1,suitableTech:["ASHP","PV"],estimatedCost:{ASHP:9e4,PV:52e3,Mixed:145e3},location:{lat:51.0548,lon:-1.3196}},{uprn:"B-005",area:"South Ward",priorityScore:67,carbonBaseline:5.4,suitableTech:["ASHP"],estimatedCost:{ASHP:95e3,PV:76e3,Mixed:135e3},location:{lat:51.0499,lon:-1.3122}},{uprn:"B-006",area:"South Ward",priorityScore:79,carbonBaseline:6.9,suitableTech:["PV","Mixed"],estimatedCost:{ASHP:105e3,PV:57e3,Mixed:152e3},location:{lat:51.0673,lon:-1.2986}},{uprn:"B-007",area:"East Ward",priorityScore:85,carbonBaseline:7.9,suitableTech:["ASHP","Mixed"],estimatedCost:{ASHP:116e3,PV:69e3,Mixed:17e4},location:{lat:51.0711,lon:-1.3254}},{uprn:"B-008",area:"East Ward",priorityScore:71,carbonBaseline:6.3,suitableTech:["PV"],estimatedCost:{ASHP:125e3,PV:53e3,Mixed:148e3},location:{lat:51.0527,lon:-1.2925}},{uprn:"B-009",area:"West Ward",priorityScore:76,carbonBaseline:6.7,suitableTech:["ASHP","PV","Mixed"],estimatedCost:{ASHP:108e3,PV:61e3,Mixed:158e3},location:{lat:51.0605,lon:-1.2874}},{uprn:"B-010",area:"West Ward",priorityScore:64,carbonBaseline:5.2,suitableTech:["ASHP","PV"],estimatedCost:{ASHP:87e3,PV:5e4,Mixed:133e3},location:{lat:51.0463,lon:-1.3041}}],ls=new Set(At),Ci=e=>ls.has(e),cs={},Ii="scenario-budget-guard-upgrade",Ei="scenario-intervention-history-upgrade",ki="scenario-carbon-impact-upgrade",Ai="scenario-demand-impact-upgrade";let xr=!1;const Bt=()=>cs?.VITE_LAEP_DEBUG_SCENARIO==="true";
200function ds(){xr||(Ft(is({name:Ii})),Ft(as({name:Ei})),Ft(os({name:ki,carbonFactorByTech:Co})),Ft(ss({name:Ai,demandChangeByTech:Io})),xr=!0)}let _n=null;async function us(){if(_n)return _n;try{const e=await fetch("/data/winchesterBuildings.json");if(e.ok){const t=await e.json();if(Array.isArray(t)&&t.length>0)return _n=t,t}}catch(e){console.error("Failed to fetch winchesterBuildings:",e)}return Dn}async function ps(e){if(e?.getRowCount&&e?.getRow){const n=e.getRowCount(),r=[];for(let i=0;i<n;i++){const a=e.getRow(i);r.push({...a,upgraded:!1,deployedTech:null,deployedTechs:[],interventionHistory:[]})}return r}return(await us()).map(n=>({...n,upgraded:!1,deployedTech:null,deployedTechs:[],interventionHistory:[]}))}const Qt={carbonSavingPotential:e=>Number(e.annualEnergyCost??e.carbonBaseline)||0,fuelPovertyScore:e=>Number(e.priorityScore)||0,gridCapacityEfficiency:e=>Number(e.secondaryHeadroomMva??e.primaryHeadroomMva)||0};Object.freeze(Object.keys(Qt));function Sr(e,t){if(e.length===0)return NaN;const n=(e.length-1)*t,r=Math.floor(n),i=Math.ceil(n);return r===i?e[r]:e[r]+(e[i]-e[r])*(n-r)}function ms(e){const t={};for(const[n,r]of Object.entries(Qt)){const i=e.map(r).filter(l=>Number.isFinite(l));i.sort((l,c)=>l-c);const a=Sr(i,.01),o=Sr(i,.99);t[n]={min:a,span:o-a}}return(n,r)=>{const{min:i,span:a}=t[r];if(!Number.isFinite(i)||a<=0)return 0;const o=(Qt[r](n)-i)/a;return o<0?0:o>1?1:o}}function fs(e,t={},n){let r=0;for(const i of Object.keys(Qt)){const a=Number(t[i])||0;a<=0||(r+=a*n(e,i))}return r}function hs(e,t,n,r=[]){const i=e.profile;if(!i||i.type===Ge)return null;const a=Si(i,t,n||[],r);return!a.length||a.length>=t.length?null:new Set(a.map(o=>String(o.uprn)))}function gs(e,t,n,r){const i=Math.max(1,Number(e.duration)||1),a=(Number(e.budget)||0)/i,o=e.prioritisation?.type===Oe?ca(e.prioritisation.columns):null,l={};if(Array.isArray(e.budgetAllocations)&&e.budgetAllocations.length>0)for(const p of e.budgetAllocations)l[p.year]=p.budget;const c=new Map,d=p=>{let f=c.get(p);return f===void 0&&(f=fs(p,e.weights,r),c.set(p,f)),f};return new ns(e.label,{facet:t,startYear:e.startYear,endYear:e.startYear+i-1,filter:p=>{if((Array.isArray(p.deployedTechs)?p.deployedTechs:[]).includes(e.tech)||!(!!n&&Ci(e.tech))&&!p.suitableTech?.includes(e.tech)||n&&!n.has(String(p.uprn)))return!1;if(e.targetEPC&&e.targetEPC!=="Any"){const m=p.epcRating??p.epc;if(!m||m>e.targetEPC)return!1}return!0},prioritise:o||((p,f)=>d(f)-d(p)),init:p=>{p.state.currentIntervention={id:e.id??e.label,label:e.label,tech:e.tech},p.state.annualBudget=a},initYear:(p,f)=>{const u=f.year,m=u!=null&&l[u]!=null?l[u]:a;f.state.remainingBudget=m},upgrade:(p,f)=>{const u=e.pluginConfig||{},m={budget:u.budget!==!1,history:u.history!==!1,carbon:u.carbon!==!1,demand:u.demand!==!1},h=E=>{const x=f.resolvePlugin(E);return!x||typeof x.upgrade!="function"?{}:x.upgrade(p,f)||{}};let b={};if(m.budget&&(b=h(Ii),!b||Object.keys(b).length===0))return{};const S=m.history?h(Ei):{},w=m.carbon?h(ki):{},k=m.demand?h(Ai):{};if(m.history&&m.carbon&&Array.isArray(p.interventionHistory)){const E=p.interventionHistory[p.interventionHistory.length-1];E&&E.year===f.year&&E.technology===e.tech&&(E.carbonSaved=w.carbonSaved,E.demandChange=k.demandChange)}return{...S,...b,...w,...k}}})}async function ys(e,t,n={}){ds(),Bt()&&console.log("[Scenario] runScenarioSimulation entry",{interventionCount:e?.length??0,currentYear:t,hasFacet:!!n.facet});const r=[...e].sort((w,k)=>w.startYear-k.startYear),i=n.facet,a=await ps(i);Bt()&&console.log("[Scenario] cloneBuildings done",{buildingCount:a?.length??0});const o=Xt(a),l=n.scenarioProfiles||[],c=n.selectionUprns||[],d=ms(a),p=new rs;r.forEach(w=>{const k=hs(w,a,l,c);p.add(gs(w,o,k,d))});const f=p.run();Bt()&&console.log("[Scenario] runner.run() returned",{rawResultsCount:f?.length??0,rawResultNames:f?.map(w=>w?.name)??[],firstResultKeys:f?.[0]?.result?Object.keys(f[0].result):[]});const u={},m={},h={};for(let w=0;w<f.length;w++){const k=f[w],E=r[w]||{},x=E.id||k.name;m[x]={id:x,label:E.label||k.name,technology:E.tech,upgrades:0,budget:0,carbonSaved:0,demandChange:0},h[x]=k.result?.simulatedFacet??null;for(const[_,v]of Object.entries(k.result.metrics||{})){u[_]||(u[_]={upgrades:0,budget:0,carbonSaved:0,demandChange:0});for(const A of v){const P=Number(A.stats?.cost||0),U=Number(A.stats?.carbonSaved||0),$=Number(A.stats?.demandChange||0);u[_].upgrades+=1,u[_].budget+=P,u[_].carbonSaved+=U,u[_].demandChange+=$,m[x].upgrades+=1,m[x].budget+=P,m[x].carbonSaved+=U,m[x].demandChange+=$}}}const b=f.at(-1)?.result?.buildings??a,S={ranAt:new Date().toISOString(),currentYear:t,yearly:u,interventionSummary:m,perInterventionFacets:h,finalBuildings:b,rawResults:f};
200return Bt()&&console.log("[Scenario] runScenarioSimulation returning",{yearlyKeys:Object.keys(u),interventionSummaryKeys:Object.keys(m),finalBuildingsCount:b?.length??0}),S}const bs={},vs=()=>bs?.VITE_LAEP_DEBUG_SCENARIO==="true";function wr(e=null,t=[]){return{runSimulation:N.useCallback((r,i,a=[])=>(vs()&&console.log("[Scenario] useScenarioModellerRunner.runSimulation invoked",{interventionCount:r?.length??0,currentYear:i,hasFacet:!!e,facetRowCount:e?.getRowCount?.()??null,scenarioProfilesCount:t?.length??0,selectionCount:a?.length??0}),ys(r,i,{facet:e,scenarioProfiles:t,selectionUprns:a})),[e,t])}}function se(e,t=0){if(e==null||e===""||e===void 0)return t;const n=Number(e);return Number.isFinite(n)?n:t}function _r(e){if(e==null)return!1;if(typeof e=="boolean")return e;const t=String(e).trim().toLowerCase();return t==="true"||t==="1"||t==="yes"}function Nr(e,t,n){return Math.max(t,Math.min(n,e))}function xs(e,t){return e==null||t==null||e===0||t===0?!1:49<=e&&e<=53&&-2.2<=t&&t<=.2}function Ss(e){const t=String(e||"").trim();return t?t.split(" ")[0]:"Unknown"}const ws=["primary_code_description","primary_description","post_code","post_code_1","household_data_epc_rating","household_data_epc_property_type","household_data_epc_mains_gas_flag","proportion_of_households_fuel_poor","index_of_multiple_deprivation_imd_rank","current_energy_rating","current_energy_cost","building_area_m2","net_annual_income","latitude","longitude","ashp_suitability","rooftop_pv_suitability","district_heating_suitability","gshp_suitability","hydrogen_boiler_suitability","ashp_capacity","rooftop_pv_capacity","gshp_capacity","ashp_total_cost","rooftop_pv_total_cost","gshp_total_cost","hydrogen_boiler_total_cost","district_heating_total_cost","insulation_cavity_wall_suitability","insulation_external_wall_suitability","insulation_roof_suitability","insulation_under_floor_suitability","insulation_cavity_wall","insulation_external_wall","insulation_roof","insulation_under_floor","insulation_cavity_wall_total_cost","insulation_external_wall_total_cost","insulation_roof_total_cost","insulation_under_floor_total_cost","lsoa_id","lsoa_name","msoa_id","msoa_name","ward_id","ward_name","gsp_name","gsp_headroom_mva","gsp_demand_mva","bsp_name","bsp_headroom_mva","bsp_gen_headroom_mva","primary_id","primary_name","primary_headroom_mva","primary_demand_mva","secondary_id","secondary_name","secondary_capacity_mva","secondary_peak_load_mva","secondary_headroom_mva","primary_potential_ground_pv_gwh","primary_potential_ground_pv_mw","primary_potential_wind_gwh","primary_potential_wind_mw","total_demand_kw_in_lsoa","total_generation_kw_in_lsoa","evchargepoints_total_in_grid_max"];function _s(e){const t={};for(const n of ws)e[n]!==void 0&&(t[n]=e[n]);return t}function Ns(e,t){if(!e||String(e.primary_code_description||e.primary_description||"").trim().toLowerCase()!=="residential")return null;const{suitableTech:r,estimatedCost:i}=Eo(e,{asBool:_r,asFloat:se});if(r.length===0)return null;const a=se(e.proportion_of_households_fuel_poor),o=se(e.index_of_multiple_deprivation_imd_rank,32821),l=Nr(a/24.44,0,1),c=Nr(1-o/32821,0,1),d=Math.round((.65*l+.35*c)*100),p=se(e.current_energy_cost),f=se(e.building_area_m2);let u=p;u<=0&&(u=6);const m=Math.round(u*(f>0?f:81.7)*100)/100,h=se(e.latitude,null),b=se(e.longitude,null);if(!xs(h,b))return null;const S=e.post_code||e.post_code_1||"",w=e.current_energy_rating||e.household_data_epc_rating||"U",k=e.household_data_epc_mains_gas_flag,E=_r(k)||String(k||"").toLowerCase()==="yes";return{..._s(e),uprn:String(e.uprn||`WB-${t+1}`),area:Ss(S),priorityScore:d,fuelPoorPct:Math.round(a*100)/100,imdRank:Math.floor(o),epc:w,epcRating:w,type:e.household_data_epc_property_type||"Unknown",sqm:Math.round(se(e.building_area_m2)*10)/10,income:Math.round(se(e.net_annual_income)),gas:E?"Yes":"No",gspName:e.gsp_name||"",bspName:e.bsp_name||"",primarySubstation:e.primary_name||"",primaryHeadroomMva:Math.round(se(e.primary_headroom_mva)*1e3)/1e3,primaryDemandMva:Math.round(se(e.primary_demand_mva)*1e3)/1e3,secondarySubstation:e.secondary_name||"",secondaryCapacityMva:Math.round(se(e.secondary_capacity_mva)*1e3)/1e3,secondaryPeakLoadMva:Math.round(se(e.secondary_peak_load_mva)*1e3)/1e3,secondaryHeadroomMva:Math.round(se(e.secondary_headroom_mva)*1e3)/1e3,ashpKW:
200Math.round(se(e.ashp_capacity)*100)/100,pvKW:Math.round(se(e.rooftop_pv_capacity)*100)/100,gshpKW:Math.round(se(e.gshp_capacity)*100)/100,suitableTech:r,carbonBaseline:Math.round(u*100)/100,annualEnergyCost:m,estimatedCost:i,location:{lat:Math.round(h*1e6)/1e6,lon:Math.round(b*1e6)/1e6}}}function Cs(e){const t=[];for(let n=0;n<e.length;n++){const r=Ns(e[n],n);r&&t.push(r)}return t}const Is={mvp:{mainModule:Xi,mainWorker:Ji},eh:{mainModule:Zi,mainWorker:Ki}};let Nn=null,Cn=null;async function Es(e="/data/winchester_building_stock.parquet"){if(Nn&&Cn)return{db:Nn,conn:Cn};const t=await Wi(Is),n=new Worker(t.mainWorker),r=new zi,i=new qi(r,n);await i.instantiate(t.mainModule,t.pthreadWorker);const a=typeof window<"u"&&window.location?window.location.origin:"http://localhost",o=(e.startsWith("http")?e:new URL(e,a).toString())+"?v="+Date.now();await i.registerFileURL("buildings.parquet",o,Gi.HTTP,!1);const l=await i.connect();return Nn=i,Cn=l,{db:i,conn:l}}async function mt(e,t){const n=await e.query(t),r=n.numRows,i=[];for(let a=0;a<r;a++){const o=n.get(a);i.push(o.toJSON?o.toJSON():o)}return i}const ks=["LOWER(COALESCE(primary_code_description, primary_description, '')) = 'residential'","latitude BETWEEN 49.0 AND 53.0","longitude BETWEEN -2.2 AND 0.2","(ashp_suitability OR rooftop_pv_suitability OR district_heating_suitability OR gshp_suitability OR hydrogen_boiler_suitability)"],As=["uprn","primary_code_description","primary_description","post_code","household_data_epc_rating","household_data_epc_property_type","household_data_epc_mains_gas_flag","proportion_of_households_fuel_poor","index_of_multiple_deprivation_imd_rank","current_energy_rating","current_energy_cost","building_area_m2","net_annual_income","latitude","longitude","ashp_suitability","rooftop_pv_suitability","district_heating_suitability","gshp_suitability","hydrogen_boiler_suitability","ashp_capacity","rooftop_pv_capacity","gshp_capacity","ashp_total_cost","rooftop_pv_total_cost","gshp_total_cost","hydrogen_boiler_total_cost","district_heating_total_cost","lsoa_id","lsoa_name","msoa_id","msoa_name","ward_id","ward_name","gsp_name","gsp_headroom_mva","gsp_demand_mva","bsp_name","bsp_headroom_mva","bsp_gen_headroom_mva","primary_id","primary_name","primary_headroom_mva","primary_demand_mva","secondary_id","secondary_name","secondary_capacity_mva","secondary_peak_load_mva","secondary_headroom_mva","primary_potential_ground_pv_gwh","primary_potential_ground_pv_mw","primary_potential_wind_gwh","primary_potential_wind_mw","total_demand_kw_in_lsoa","total_generation_kw_in_lsoa","evchargepoints_total_in_grid_max"];function nr(e){const t=[...ks];if(e.bbox){const{minLat:n,maxLat:r,minLon:i,maxLon:a}=e.bbox;t.push(`latitude BETWEEN ${n} AND ${r}`),t.push(`longitude BETWEEN ${i} AND ${a}`)}if(e.areas?.length){const n=e.areas.map(r=>`'${String(r).replace(/'/g,"''")}'`).join(", ");t.push(`SPLIT_PART(COALESCE(post_code,''), ' ', 1) IN (${n})`)}if(e.epcRatings?.length){const n="UPPER(TRIM(COALESCE(current_energy_rating, household_data_epc_rating, 'U')))",r=e.epcRatings.map(i=>`'${String(i).replace(/'/g,"''")}'`).join(", ");t.push(`${n} IN (${r})`)}return t}async function Ts(e,t={}){const r=nr(t).join(" AND "),a=` 201 SELECT 202 ${As.map(l=>`"${l}"`).join(`, 203 `)} 204 FROM read_parquet('buildings.parquet') 205 WHERE ${r} 206 `,o=await mt(e,a);return Cs(o)}async function js(e){const[t,n,r]=await Promise.all([mt(e,"SELECT COUNT(*) as cnt FROM read_parquet('buildings.parquet')"),mt(e,` 207 SELECT COUNT(*) as cnt FROM read_parquet('buildings.parquet') 208 WHERE LOWER(COALESCE(primary_code_description, primary_description, '')) = 'residential' 209 AND latitude BETWEEN 49.0 AND 53.0 210 AND longitude BETWEEN -2.2 AND 0.2 211 `),mt(e,` 212 SELECT COUNT(*) as cnt FROM read_parquet('buildings.parquet') 213 WHERE LOWER(COALESCE(primary_code_description, primary_description, '')) = 'residential' 214 AND latitude BETWEEN 49.0 AND 53.0 215 AND longitude BETWEEN -2.2 AND 0.2 216 AND (ashp_suitability OR rooftop_pv_suitability OR district_heating_suitability OR gshp_suitability OR hydrogen_boiler_suitability) 217 `)]),i=a=>typeof a[0]?.cnt=="number"?a[0].cnt:Number(a[0]?.cnt)||0;return{total:i(t),residential:i(n),withSuitability:i(r)}}async function Rc(e,t={}){const{techColumns:n=[],aggregations:r=[],cellSizeDeg:i=.005,filters:a={}}=t,o=(n||[]).map(m=>{const h=String(m||"").replace(/[^a-z0-9_]/gi,"");return{outCol:h,sql:h,type:"numeric"}}),l=r.length>0?r:o,d=nr(a).join(" AND "),p=l.length>0?l.map(m=>m.type==="numeric"?`SUM(${m.sql}) AS "${m.outCol}"`:`STRING_AGG(CAST(${m.sql} AS VARCHAR), '||') AS "${m.outCol}_str"`).join(`, 218 `):"0 AS placeholder_sum",f=` 219 SELECT 220 (floor(longitude / ${i}) * ${i}) AS lon_bucket, 221 (floor(latitude / ${i}) * ${i}) AS lat_bucket, 222 AVG(longitude) AS lon, 223 AVG(latitude) AS lat, 224 ${p}, 225 COUNT(*) AS cnt 226 FROM read_parquet('buildings.parquet') 227 WHERE ${d} 228 GROUP BY lon_bucket, lat_bucket 229 `;return(await mt(e,f)).map(m=>{const h={lon:Number(m.lon)||0,lat:Number(m.lat)||0,cnt:Number(m.cnt)||0};for(const b of l)if(b.type==="numeric")h[b.outCol]=Number(m[b.outCol]??0);else{const S=m[`${b.outCol}_str`],w=typeof S=="string"?S.split("||"):[],k={};for(const x of w)x!=null&&x!==""&&(k[x]=(k[x]||0)+1);const E=Object.entries(k);E.sort((x,_)=>_[1]-x[1]),h[b.outCol]=E[0]?.[0]??null,h[`${b.outCol}__count`]=E.reduce((x,_)=>x+_[1],0),h[`${b.outCol}__catmap`]=k}return h})}async function $c(e,t={}){const{boundaryIdField:n,techColumns:r=[],aggregations:i=[],filters:a={}}=t;if(!n)throw new Error("boundaryIdField is required for boundary grouping");const o=(r||[]).map(m=>{const h=String(m||"").replace(/[^a-z0-9_]/gi,"");return{outCol:h,sql:h,type:"numeric"}}),l=i.length>0?i:o,d=nr(a).join(" AND "),p=l.length>0?l.map(m=>m.type==="numeric"?`SUM(${m.sql}) AS "${m.outCol}"`:`STRING_AGG(CAST(${m.sql} AS VARCHAR), '||') AS "${m.outCol}_str"`).join(`, 230 `):"0 AS placeholder_sum",f=` 231 SELECT 232 "${n}" AS feature_id, 233 ${p}, 234 COUNT(*) AS cnt 235 FROM read_parquet('buildings.parquet') 236 WHERE ${d} AND "${n}" IS NOT NULL 237 GROUP BY feature_id 238 `;return(await mt(e,f)).map(m=>{const h={feature_id:m.feature_id,cnt:Number(m.cnt)||0};for(const b of l)if(b.type==="numeric")h[b.outCol]=Number(m[b.outCol]??0);else{const S=m[`${b.outCol}_str`],w=typeof S=="string"?S.split("||"):[],k={};for(const x of w)x!=null&&x!==""&&(k[x]=(k[x]||0)+1);const E=Object.entries(k);E.sort((x,_)=>_[1]-x[1]),h[b.outCol]=E[0]?.[0]??null,h[`${b.outCol}__count`]=E.reduce((x,_)=>x+_[1],0),h[`${b.outCol}__catmap`]=k}return h})}const Ps="/data/winchester_building_stock.parquet";function Rs(){const[e,t]=N.useState([]),[n,r]=N.useState(null),[i,a]=N.useState(!0),[o,l]=N.useState(null),[c,d]=N.useState(null),p=N.useCallback(async(f={})=>{a(!0),l(null);try{const{conn:u}=await Es(f.parquetUrl??Ps),[m,h]=await Promise.all([Ts(u),js(u)]);t(m),r(Xt(m)),d(h)}catch(u){console.error("DuckDB data load failed:",u),l(u),t([]),r(null),d(null),t(Dn),r(Xt(Dn))}finally{a(!1)}},[]);return N.useEffect(()=>{p()},[p]),{buildings:e,facet:n,isLoading:i,error:o,parquetCounts:c,refresh:()=>p()}}const ot={all:"All",edit:"Edits",simulation:"Simulation",lineage:"Lineage",storage:"Storage"},$s=[{id:"all",label:ot.all},{id:"edit",label:ot.edit},{id:"simulation",label:ot.simulation},{id:"lineage",label:ot.lineage},{id:"storage",label:ot.storage}];
238function Ms(e){return e?`${e.branchName||e.name||"Scenario"} ${e.versionLabel||`v${e.versionNumber||1}`}`:"Scenario"}function Os(e,t,n){if(e.scenarioId&&t.has(e.scenarioId))return t.get(e.scenarioId);if(e.scenarioProvenanceId&&n.has(e.scenarioProvenanceId))return n.get(e.scenarioProvenanceId);const r=[...e.used||[],...e.generated||[]].find(i=>i?.provenanceId&&n.has(i.provenanceId));return r?n.get(r.provenanceId):null}function Ls(e){return e.summary?e.summary:e.activity?e.activity.replace(/\./g," "):"Decision recorded"}function Ti(e){const t=e.payload?.diffSummary;return Array.isArray(t)?t.filter(Boolean):typeof t=="string"&&t?[t]:e.payload?.changeSummary?[e.payload.changeSummary]:[]}function ji(e){const t=e.payload?.changedFields;return Array.isArray(t)?t.filter(n=>n?.key||n?.summary):[]}function Ds(e){const t=e.payload||{},n=t.label||t.after?.label||t.before?.label||t.name||t.scenarioName;return e.activity==="intervention.updated"?`${n||"Intervention"} updated`:e.activity==="intervention.added"?`Added ${n||"intervention"}`:e.activity==="intervention.deleted"?`Removed ${n||"intervention"}`:e.activity==="intervention.reordered"?`Reordered ${n||"intervention"}`:e.activity==="profile.created"?`Created ${n||t.name||"building profile"}`:e.activity==="profile.updated"?`Updated ${n||t.name||"building profile"}`:e.activity==="computed-field.created"?`Created computed field ${t.name||""}`.trim():e.activity==="computed-field.updated"?`Updated computed field ${t.name||""}`.trim():e.activity==="computed-field.deleted"?`Deleted computed field ${t.name||""}`.trim():e.activity==="simulation.ran"?"Simulation run":e.activity==="scenario.versioned"?`Saved ${t.versionLabel||"new version"}`:e.activity==="scenario.branched"?"Created alternative pathway":e.activity==="scenario.saved"?"Saved scenario":e.activity==="scenario.exported"?"Exported bundle":e.activity==="scenario.imported"?"Imported bundle":e.activity==="scenario.loaded"?"Loaded scenario data":Ls(e)}function Fs(e,t,n){const r=e.payload?.episodeType||li(e.activity);return{id:e.payload?.decisionId||e.id,eventId:e.id,type:r,typeLabel:ot[r]||"Activity",title:Ds(e),timestamp:e.timestamp||null,agent:e.agent||{},activity:e.activity,scenarioId:t?.id||e.scenarioId||null,scenarioProvenanceId:t?.provenanceId||e.scenarioProvenanceId||null,scenarioLinked:n,scenarioLabel:Ms(t),workflowStage:e.payload?.workflowStage||null,source:e.payload?.source||"dashboard",diffSummary:Ti(e),impactSummary:e.payload?.impactSummary||null,changedFields:ji(e),events:[e]}}function Cr(e=[],t=[],n=null,r={}){const i=new Map((t||[]).filter(Boolean).map(p=>[p.id,p])),a=new Map((t||[]).filter(Boolean).map(p=>[p.provenanceId,p])),o=n||t?.[0]||null,l=new Map;for(const p of e||[]){if(!p?.id||!p?.activity)continue;const f=Os(p,i,a),u=f||o||null,m=p.payload?.decisionId||p.id,h=l.get(m);h?(h.events.push(p),h.diffSummary.push(...Ti(p)),h.changedFields.push(...ji(p)),!h.impactSummary&&p.payload?.impactSummary&&(h.impactSummary=p.payload.impactSummary),String(p.timestamp||"")>String(h.timestamp||"")&&(h.timestamp=p.timestamp)):l.set(m,Fs(p,u,!!f))}const c=r.filter||"all",d=String(r.query||"").trim().toLowerCase();return Array.from(l.values()).map(p=>({...p,diffSummary:Array.from(new Set(p.diffSummary.filter(Boolean))).slice(0,6),changedFields:p.changedFields.slice(0,12)})).filter(p=>c==="all"||p.type===c).filter(p=>d?[p.title,p.typeLabel,p.scenarioLabel,p.activity,p.impactSummary,...p.diffSummary].filter(Boolean).join(" ").toLowerCase().includes(d):!0).sort((p,f)=>String(f.timestamp||"").localeCompare(String(p.timestamp||"")))}function Fn(e){if(!e)return"Unknown time";const t=new Date(e);return Number.isNaN(t.getTime())?"Unknown time":t.toLocaleString([],{day:"numeric",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit"})}function Bs(e,t=Date.now()){if(!e)return"Unknown time";const n=new Date(e);if(Number.isNaN(n.getTime()))return"Unknown time";const r=t-n.getTime(),i=60*1e3,a=60*i,o=24*a;if(r>=0&&r<i)return"just now";if(r>=0&&r<a)return`${Math.floor(r/i)}m ago`;if(r>=0&&r<o)return`${Math.floor(r/a)}h ago`;if(r>=0&&r<7*o)return`${Math.floor(r/o)}d ago`;const l=n.getFullYear()===new Date(t).getFullYear();return n.toLocaleDateString([],l?{day:"numeric",month:"short"}:{day:"numeric",month:"short",year:"numeric"})}function Nt(e){return`${e.getFullYear()}
238-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`}function Us(e,t){const n=new Date(t),r=new Date(t-24*60*60*1e3);return Nt(e)===Nt(n)?"Today":Nt(e)===Nt(r)?"Yesterday":e.toLocaleDateString([],{day:"numeric",month:"long",year:"numeric"})}function Hs(e=[],t=Date.now()){const n=[],r=new Map,i={key:"undated",label:"Undated",episodes:[]};for(const a of e){const o=a.timestamp?new Date(a.timestamp):null;if(!o||Number.isNaN(o.getTime())){i.episodes.push(a);continue}const l=Nt(o);let c=r.get(l);c||(c={key:l,label:Us(o,t),episodes:[]},r.set(l,c),n.push(c)),c.episodes.push(a)}return i.episodes.length&&n.push(i),n}function Vs(e=[]){return e.reduce((t,n)=>(t.total+=1,t[n.type]=(t[n.type]||0)+1,t),{total:0,edit:0,simulation:0,lineage:0,storage:0})}const Ys={carbonSavingPotential:"carbon",fuelPovertyScore:"fuel poverty",gridCapacityEfficiency:"grid capacity",cost:"cost"},Ws={budget:"budget guard",history:"deployment history",carbon:"carbon impact",demand:"demand impact"};function ht(e){return Array.isArray(e)?e:[]}function le(e){const t=Number(e||0);return Number.isFinite(t)?t.toLocaleString():"0"}function Bn(e){const t=Number(e||0);return!Number.isFinite(t)||t===0?"£0":Math.abs(t)>=1e6?`£${(t/1e6).toFixed(1)}M`:`£${Math.round(t).toLocaleString()}`}function qs(e,t=le){const n=Number(e||0);return!Number.isFinite(n)||n===0?"0":`${n>0?"+":""}${t(Math.abs(n))}`}function Ir(e){return e==null||e===""?"none":Array.isArray(e)?`${le(e.length)} items`:typeof e=="object"?Number.isFinite(Number(e.count))?`${le(e.count)} items`:e.type?Hn(e):`${Object.keys(e).length} fields`:typeof e=="number"?le(e):typeof e=="boolean"?e?"enabled":"disabled":String(e)}function Pi(e=""){return String(e).replace(/([a-z])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").trim().toLowerCase()}function Un(e){const n=Object.values(e?.yearly||{}).reduce((r,i)=>(r.upgrades+=Number(i?.upgrades??i?.deployedBuildings??0),r.budget+=Number(i?.budget??i?.cost??0),r.carbonSaved+=Number(i?.carbonSaved??0),r.demandChange+=Number(i?.demandChange??0),r),{upgrades:0,budget:0,carbonSaved:0,demandChange:0});return n.upgrades||n.budget||n.carbonSaved||n.demandChange?n:Object.values(e?.interventionSummary||{}).reduce((r,i)=>(r.upgrades+=Number(i?.upgrades||0),r.budget+=Number(i?.budget||0),r.carbonSaved+=Number(i?.carbonSaved||0),r.demandChange+=Number(i?.demandChange||0),r),{upgrades:0,budget:0,carbonSaved:0,demandChange:0})}function Ri(e={}){return Object.entries(e||{}).map(([t,n])=>({key:t,label:Ys[t]||Pi(t),value:Number(n||0)})).filter(t=>Number.isFinite(t.value)&&t.value>0).sort((t,n)=>n.value-t.value)}function zs(e={}){const t=Ri(e);return t.length?t.slice(0,3).map(n=>`${n.label} ${Math.round(n.value*100)}%`).join(", "):"Default balanced weighting"}function Hn(e={},t=[]){if(!e||e.type===Ge||e.type==="all")return"All buildings";if(e.type===ct){const n=e.uprns?.length;return n?`Stored selection (${le(n)} buildings)`:"Current table/map selection"}return e.type===dt?tr.find(r=>r.id===e.predefinedId)?.name||"Predefined building profile":e.type===rt?t.find(r=>r.id===e.profileId)?.name||"Saved building profile":"Custom building profile"}function Gs(e={}){return Object.entries(Ws).filter(([t])=>e[t]!==!1).map(([,t])=>t)}function Ks(e=[],t){if(!t)return[];const n=t.provenanceId,r=t.id;return ht(e).filter(i=>{const a=[i.scenarioProvenanceId,...(i.used||[]).map(o=>o?.provenanceId),...(i.generated||[]).map(o=>o?.provenanceId)].filter(Boolean);return i.scenarioId===r||a.includes(n)}).sort((i,a)=>String(a.timestamp||"").localeCompare(String(i.timestamp||""))).slice(0,5)}function Zs(e={}){const t=e.payload?.before||{},n=e.payload?.after||{},r=Array.from(new Set([...Object.keys(t),...Object.keys(n)])).filter(i=>JSON.stringify(t[i])!==JSON.stringify(n[i]));return r.length?r.slice(0,3).map(i=>`${Pi(i)}: ${Ir(t[i])} -> ${Ir(n[i])}`).join("; "):e.payload?.changeSummary||e.summary||e.activity}function Js(e=[],t=[]){const n=c=>String(c?.id||c?.label||c?.tech||"").toLowerCase(),r=new Map(ht(e).map(c=>[n(c),c])),i=new Map(ht(t).map(c=>[n(c),c])),a=[],o=[],l=[];for(const[c,d]of i){if(!r.has(c)){a.push(d);continue}const p=r.get(c);["tech","profile","strategy","startYear","duration","budget","targetEPC","weights"].some(u=>JSON.stringify(p?.[u])!==JSON.stringify(d?.[u]))&&l.push(d)}for(const[c,d]of r)i.has(c)||o.push(d);return{added:a,removed:o,changed:l}}function Xs({activeScenario:e,allScenarios:t,mapConfig:n,simulationOutput:r}){const i=ht(t).find(p=>p.id===n?.compareScenarioId)||null;if(!n?.splitView||!i)return{headline:"No alternative comparison selected",details:["Enable comparison and choose another scenario to explain alternatives."],kpis:[],available:!1};const a=Js(e?.interventions,i.interventions),o=Un(r||e?.results),l=Un(i.results),c=!!(r||e?.results||i.results),d=a.added.length+a.removed.length+a.changed.length;return{headline:`${i.name||"Alternative"} differs in ${d||0} decision${d===1?"":"s"}`,available:!0,compareScenarioId:i.id,details:[`${le(a.added.length)} added, ${le(a.removed.length)} removed, ${le(a.changed.length)} changed interventions`,i.changeSummary||"No branch summary recorded",c?"Result deltas use the latest available simulation outputs.":"Run simulations to compare result deltas."],kpis:[{label:"Upgrades",current:o.upgrades,compare:l.upgrades,delta:l.upgrades-o.upgrades},{label:"Budget",current:o.budget,compare:l.budget,delta:l.budget-o.budget,format:"money"},{label:"Carbon saved",current:o.carbonSaved,compare:l.carbonSaved,delta:l.carbonSaved-o.carbonSaved}]}}function Qs({activeScenario:e=null,selectedIntervention:t=null,selectedUprns:n=null,tableFilterSummary:r={},simulationOutput:i=null,allScenarios:a=[],mapConfig:o={},provenanceEvents:l=[],currentYear:c,dataMode:d="raw",buildingCounts:p={}}={}){const f=e?.profiles||[],u=Array.isArray(n)?n.length:0,m=Number(r?.visibleRows),h=Number(r?.totalRows),b=Number.isFinite(m)&&Number.isFinite(h)&&h>0&&m<h,S=t||e?.interventions?.[0]||null,w=Un(i||e?.results),k=Gs(S?.pluginConfig||{}),E=Ks(l,e).map(_=>({id:_.id,activity:_.activity,label:_.summary||_.activity,timestamp:_.timestamp,diff:Zs(_)})),x=u?"Current table/map selection":S?Hn(S.profile,f):"Full scenario stock";return{scenarioId:e?.id||null,scenarioName:e?.name||"No scenario selected",selection:{headline:u?`${le(u)} selected buildings`:b?`${le(m)} of ${le(h)} visible rows`:`${le(p.displayed??p.total??0)} buildings in scope`,details:[`Source: ${x}`,`Data view: ${d==="simulated"?"Scenario results":d==="awaiting-simulation"?"Awaiting simulation results":"Raw building stock"}`,b?`Latest table filter: ${ht(r.operations).at(-1)||"active"}`:"No active table filter summary"]},priority:{headline:S?`${S.strategy||"multi-objective"} priority: ${zs(S.weights)}`:"No priority rules configured",weights:Ri(S?.weights),details:S?[`Target EPC: ${S.targetEPC||"Any"}
238`,`Eligibility requires ${S.tech||"selected technology"} suitability.`,"Already-deployed matching technologies are excluded before ranking."]:["Add an intervention to expose priority rules."]},intervention:{id:S?.id||null,headline:S?`${S.label||S.tech||"Intervention"} applies ${S.tech||"technology"}`:"No intervention selected",details:S?[`Cohort: ${Hn(S.profile,f)}`,`Budget and timing: ${Bn(S.budget)} across ${le(S.duration||1)} year${Number(S.duration||1)===1?"":"s"} from ${S.startYear||c||"the current year"}`,`Budget allocation: ${ht(S.budgetAllocations).length?"custom annual curve":"even annual split"}`,`Model plugins: ${k.join(", ")||"none enabled"}`]:["Select or add an intervention to see its receipt."]},assumptions:{headline:i?`${le(w.upgrades)} upgrades, ${Bn(w.budget)}, ${le(Math.round(w.carbonSaved))} carbon saved`:"Simulation assumptions ready; no output in this view yet",details:[`Scenario year: ${c||"not set"}`,"Model applies interventions in timeline order and checks budget before each upgrade.","Profile rules define eligibility; weights only rank eligible buildings.","Output summaries are derived from yearly metrics and intervention summaries, not full per-building traces."]},changes:{headline:E.length?`${le(E.length)} recent scenario change${E.length===1?"":"s"}`:"No scenario changes recorded yet",events:E},comparison:Xs({activeScenario:e,allScenarios:a,mapConfig:o,simulationOutput:i})}}const Mc={formatNumber:le,formatMoney:Bn,formatDelta:qs},Er={edit:{label:"Edit",Icon:Qn,className:"bg-[var(--laep-success-soft)] text-[var(--laep-success)]",accent:"var(--laep-success)"},simulation:{label:"Simulation",Icon:lo,className:"bg-[var(--laep-surface-selected)] text-[var(--laep-provenance-simulation)]",accent:"var(--laep-provenance-simulation)"},lineage:{label:"Lineage",Icon:xi,className:"bg-[var(--laep-surface-muted)] text-[var(--laep-provenance-branch)]",accent:"var(--laep-provenance-branch)"},storage:{label:"Storage",Icon:po,className:"bg-[var(--laep-surface-muted)] text-[var(--laep-text-muted)]",accent:"var(--laep-text-muted)"},activity:{label:"Activity",Icon:io,className:"bg-[var(--laep-surface-muted)] text-[var(--laep-text-muted)]",accent:"var(--laep-text-muted)"}};function el(e){const t=[],n=e.events?.[0]?.payload||{};if(e.type==="edit"){const r=e.changedFields||[];for(const i of r.slice(0,2))t.push({id:`field-${i.key}`,label:i.label||i.key,value:`${i.beforeLabel??"before"} â ${i.afterLabel??"after"}`});r.length>2&&t.push({id:"field-more",value:`+${r.length-2} more field${r.length-2===1?"":"s"}`}),!t.length&&n.after?.expression&&t.push({id:"expression",label:"Rule",value:n.after.expression,mono:!0}),!t.length&&Number.isFinite(Number(n.uiContext?.selectionCount))&&t.push({id:"cohort",label:"Cohort",value:`${n.uiContext.selectionCount} buildings`})}else if(e.type==="simulation"){const r=Number(n.results?.finalBuildingsCount??n.results?.rawResultsCount);Number.isFinite(r)&&t.push({id:"results",label:"Results",value:`${r.toLocaleString()} buildings`}),Number.isFinite(Number(n.interventionCount))&&t.push({id:"plan",label:"Plan",value:`${n.interventionCount} intervention${Number(n.interventionCount)===1?"":"s"}`}),n.currentYear&&t.push({id:"horizon",label:"Horizon",value:`to ${n.currentYear}`})}else e.type==="lineage"?n.changeSummary?t.push({id:"change",value:n.changeSummary}):n.description&&t.push({id:"description",value:n.description}):e.type==="storage"&&(n.storageMode&&t.push({id:"mode",label:"Storage",value:n.storageMode}),Number.isFinite(Number(n.scenarioCount))&&t.push({id:"bundle",label:"Bundle",value:`${n.scenarioCount} scenario${Number(n.scenarioCount)===1?"":"s"}`}));if(!t.length)for(const r of(e.diffSummary||[]).slice(0,2))t.push({id:`diff-${r}`,value:r});return!t.length&&e.impactSummary&&t.push({id:"impact",value:e.impactSummary}),t.slice(0,3)}function tl({items:e,accent:t}){return e.length?s.jsx("span",{className:"flex min-w-0 flex-wrap content-start items-start gap-1",children:e.map(n=>s.jsxs("span",{className:"inline-flex max-w-full min-w-0 items-baseline gap-1 rounded border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-panel)] py-0.5 pl-1.5 pr-1.5 text-[10px] leading-4",style:{borderLeft:`2px solid ${t}`},children:[n.label?s.jsx("span",{className:"shrink-0 font-semibold text-[var(--laep-text-muted)]",children:n.label}):null,s.jsx("span",{className:`truncate text-[var(--laep-text)] ${n.mono?"font-mono":""}`,children:n.value})]},n.id))}):null}function kr({episode:e,className:t=""}){return s.jsx("time",{dateTime:e.timestamp||void 0,title:Fn(e.timestamp),className:`shrink-0 text-[10px] font-medium tabular-nums text-[var(--laep-text-muted)] ${t}`,children:Bs(e.timestamp)})}function Ar({episode:e,typeLabel:t=null}){const n=e.agent?.label||e.agent?.id||"Dashboard user",r=e.source?` · ${e.source}`:"";return s.jsxs("div",{className:"mt-0.5 truncate text-[10px] text-[var(--laep-text-soft)]",children:[t?s.jsxs("span",{className:"font-bold uppercase tracking-wide text-[var(--laep-text-muted)]",children:[t," · "]}):null,n,r]})}function nl({fields:e=[]}){return e.length?s.jsx("div",{className:"mt-2 overflow-hidden rounded-md border border-[var(--laep-border-subtle)]",children:e.slice(0,6).map((t,n)=>s.jsxs("div",{className:"grid grid-cols-[minmax(72px,0.8fr)_minmax(0,1fr)] gap-2 border-t border-[var(--laep-border-subtle)] px-2 py-1.5 first:border-t-0",children:[s.jsx("div",{className:"truncate text-[10px] font-semibold text-[var(--laep-text-muted)]",children:t.label||t.key}),s.jsxs("div",{className:"min-w-0 text-[10px] text-[var(--laep-text)]",children:[s.jsx("span",{className:"text-[var(--laep-text-soft)]",children:t.beforeLabel??"before"}),s.jsx("span",{"aria-hidden":"true",className:"px-1 text-[var(--laep-text-soft)]",children:"to"}),s.jsx("span",{className:"font-semibold",children:t.afterLabel??"after"})]})]},`${t.key}-${n}`))}):null}function Tr({episode:e}){return s.jsxs("div",{className:"border-t border-[var(--laep-border-subtle)] px-2.5 py-2",children:[e.impactSummary?s.jsxs("div",{className:"flex items-start gap-1.5 rounded bg-[var(--laep-surface-panel)] px-2 py-1.5 text-[10px] leading-snug text-[var(--laep-text-muted)]",children:[s.jsx(vi,{"aria-hidden":"true",className:"mt-0.5 h-3 w-3 shrink-0 text-[var(--laep-success)]"}),s.jsx("span",{children:e.impactSummary})]}
238):null,s.jsx(nl,{fields:e.changedFields}),s.jsxs("details",{className:"mt-2",children:[s.jsx("summary",{className:"cursor-pointer text-[10px] font-semibold text-[var(--laep-text-muted)] hover:text-[var(--laep-text)]",children:"Technical event"}),s.jsx("pre",{className:"mt-1 max-h-44 overflow-auto rounded bg-slate-900 p-2 text-[10px] leading-relaxed text-slate-100",children:JSON.stringify(e.events[0],null,2)})]})]})}function rl({episode:e,expanded:t,onToggle:n,relaxed:r=!1}){const i=Er[e.type]||Er.activity,a=i.Icon,o=!!(e.changedFields.length||e.impactSummary||e.events.length);if(r){const l=el(e);return s.jsxs("article",{className:"rounded-md border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-raised)] text-sm",children:[s.jsxs("button",{type:"button",onClick:n,"aria-expanded":t,className:"grid w-full grid-cols-[minmax(0,5fr)_minmax(0,4fr)_auto] items-start gap-3 rounded-md px-2.5 py-2 text-left transition-colors hover:bg-[var(--laep-surface-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:[s.jsxs("span",{className:"flex min-w-0 items-start gap-2",children:[s.jsx("span",{className:`mt-0.5 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded ${i.className}`,children:s.jsx(a,{"aria-hidden":"true",className:"h-3.5 w-3.5"})}),s.jsxs("span",{className:"min-w-0",children:[s.jsx("span",{className:"block truncate text-xs font-semibold text-[var(--laep-text)]",children:e.title}),s.jsx(Ar,{episode:e,typeLabel:i.label}),s.jsx("span",{className:"mt-0.5 block truncate text-[10px] font-medium text-[var(--laep-text-muted)]",children:e.scenarioLabel})]})]}),s.jsx(tl,{items:l,accent:i.accent}),s.jsxs("span",{className:"flex shrink-0 items-center gap-1.5",children:[s.jsx(kr,{episode:e}),o?s.jsx(Jt,{"aria-hidden":"true",className:`h-3.5 w-3.5 shrink-0 text-[var(--laep-text-soft)] transition-transform ${t?"rotate-180":""}`}):null]})]}),t&&o?s.jsx(Tr,{episode:e}):null]})}return s.jsxs("article",{className:"rounded-md border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-raised)]",children:[s.jsxs("button",{type:"button",onClick:n,"aria-expanded":t,className:"flex w-full min-w-0 items-start gap-2 rounded-md px-2.5 py-2 text-left transition-colors hover:bg-[var(--laep-surface-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:[s.jsx("span",{className:`mt-0.5 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded ${i.className}`,children:s.jsx(a,{"aria-hidden":"true",className:"h-3.5 w-3.5"})}),s.jsxs("span",{className:"min-w-0 flex-1",children:[s.jsxs("span",{className:"flex min-w-0 items-center gap-1.5",children:[s.jsx("span",{className:"truncate text-xs font-semibold text-[var(--laep-text)]",children:e.title}),s.jsx("span",{className:"shrink-0 rounded bg-[var(--laep-surface-panel)] px-1.5 py-0.5 text-[9px] font-bold uppercase tracking-wide text-[var(--laep-text-muted)]",children:i.label}),s.jsx(kr,{episode:e,className:"ml-auto pl-1"})]}),s.jsx(Ar,{episode:e}),s.jsx("span",{className:"mt-1 block truncate text-[10px] font-medium text-[var(--laep-text-muted)]",children:e.scenarioLabel})]}),o?s.jsx(Jt,{"aria-hidden":"true",className:`mt-1 h-3.5 w-3.5 shrink-0 text-[var(--laep-text-soft)] transition-transform ${t?"rotate-180":""}`}):null]}),e.diffSummary.length?s.jsx("ul",{className:"space-y-1 px-2.5 pb-2",children:e.diffSummary.slice(0,3).map(l=>s.jsx("li",{className:"text-[11px] leading-snug text-[var(--laep-text-muted)]",children:l},l))}):null,t&&o?s.jsx(Tr,{episode:e}):null]})}const Ut=26,jr=12,Ht=10,Pr={edit:"var(--laep-success)",simulation:"var(--laep-provenance-simulation)",lineage:"var(--laep-provenance-branch)",storage:"var(--laep-text-muted)",activity:"var(--laep-text-muted)"};function Rr(e){if(!e)return null;const t=Date.parse(e);return Number.isNaN(t)?null:t}function il(e){return e.provenanceId||e.id}function al(e){return`${e.branchName||e.name||"Scenario"} ${e.versionLabel||`v${e.versionNumber||1}`}`}const ol=60*60*1e3;function sl(e){const t=[...new Set(e)].sort((i,a)=>i-a),n=new Map;let r=0;for(let i=0;i<t.length;i+=1)i>0&&(r+=Math.min(t[i]-t[i-1],ol)),n.set(t[i],r);return{positions:n,totalUnits:Math.max(r,1)}}function ll(e,t=Date.now()){const n=[...new Set(e)].sort((a,o)=>a-o),r=[],i=new Set;for(const a of n){const o=new Date(a),l=o.toDateString();if(i.has(l))continue;i.add(l);const c=l===new Date(t).toDateString();r.push({time:a,label:c?"Today":o.toLocaleDateString([],{day:"numeric",month:"short"})})}return r}function cl(){const[e,t]=N.useState(null),[n,r]=N.useState(0);return N.useLayoutEffect(()=>{if(!e)return;const i=()=>r(e.clientWidth);if(i(),typeof ResizeObserver>"u")return;const a=new ResizeObserver(i);return a.observe(e),()=>a.disconnect()},[e]),[t,n]}function dl({episodes:e=[],lineage:t=[],activeScenarioId:n=null,selectedKey:r=null,onSelectLane:i,onSelectEpisode:a}){const[o,l]=cl(),c=N.useMemo(()=>{const x=t.filter(Boolean).map(($,B)=>
238({scenario:$,key:il($),label:al($),index:B,createdAt:Rr($.createdAt),episodes:[]})),_=new Map(x.map($=>[$.key,$])),v=new Map(x.map($=>[$.scenario.id,$]));for(const $ of e){if($.scenarioLinked===!1)continue;const B=$.scenarioProvenanceId&&_.get($.scenarioProvenanceId)||$.scenarioId&&v.get($.scenarioId)||null,X=Rr($.timestamp);!B||X===null||B.episodes.push({episode:$,time:X})}const A=[];for(const $ of x){$.createdAt!==null&&A.push($.createdAt);for(const B of $.episodes)A.push(B.time)}const{positions:P,totalUnits:U}=sl(A);return{lanes:x,positions:P,totalUnits:U,dayTicks:ll(A)}},[e,t]),{lanes:d,positions:p,totalUnits:f,dayTicks:u}=c;if(d.length===0)return null;const m=d.length*Ut,h=Math.max(l-jr*2,1),b=x=>jr+(p.get(x)??0)/f*h,S=x=>x*Ut+Ut/2,w=new Map(d.map(x=>[x.key,x])),k=d.map(x=>{const _=x.episodes.map(v=>v.time);return x.createdAt!==null&&_.push(x.createdAt),_.length?{lane:x,start:Math.min(..._),end:Math.max(..._)}:null}).filter(Boolean),E=d.map(x=>{const _=x.scenario.parentScenarioProvenanceId,v=_?w.get(_):null;return!v||x.createdAt===null?null:{x:b(x.createdAt),fromY:S(v.index),toY:S(x.index),key:x.key}}).filter(Boolean);return s.jsxs("div",{className:"min-w-0",children:[s.jsxs("div",{className:"mb-1.5 flex items-center justify-between gap-2",children:[s.jsx("div",{className:"text-[10px] font-semibold uppercase tracking-wide text-[var(--laep-text-muted)]",children:"Pathways over time"}),r?s.jsx("button",{type:"button",onClick:()=>i?.(null),className:"rounded px-1.5 py-0.5 text-[10px] font-semibold text-[var(--laep-action)] hover:bg-[var(--laep-surface-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:"Show all pathways"}):null]}),s.jsxs("div",{className:"grid grid-cols-[minmax(120px,170px)_minmax(0,1fr)] gap-2",children:[s.jsx("div",{className:"flex flex-col",role:"tablist","aria-label":"Filter history by scenario pathway","aria-orientation":"vertical",children:d.map(x=>{const _=r===x.key,v=x.scenario.id===n;return s.jsxs("button",{type:"button",role:"tab","aria-selected":_,title:`${x.label}${v?" (current scenario)":""} â click to filter`,onClick:()=>i?.(_?null:x.key),style:{height:Ut},className:`flex min-w-0 items-center gap-1.5 rounded border px-1.5 text-left text-[11px] transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)] ${_?"border-[var(--laep-action)] bg-[var(--laep-action)] text-[var(--laep-action-contrast)]":"border-transparent text-[var(--laep-text-muted)] hover:bg-[var(--laep-surface-muted)] hover:text-[var(--laep-text)]"}`,children:[v?s.jsx("span",{"aria-hidden":"true",className:`h-1.5 w-1.5 shrink-0 rounded-full ${_?"bg-[var(--laep-action-contrast)]":"bg-[var(--laep-action)]"}`}):null,s.jsx("span",{className:"truncate font-medium",children:x.label})]},x.key)})}),s.jsx("div",{ref:o,className:"relative min-w-0 rounded border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-raised)]",style:{height:m},children:l>0?s.jsxs(s.Fragment,{children:[s.jsxs("svg",{"aria-hidden":"true",className:"absolute inset-0 h-full w-full",width:l,height:m,children:[u.map(x=>s.jsx("line",{x1:b(x.time),x2:b(x.time),y1:2,y2:m-2,stroke:"var(--laep-border-subtle)",strokeWidth:1,strokeDasharray:"2 4",opacity:.7},`day-${x.time}`)),k.map(({lane:x,start:_,end:v})=>s.jsx("line",{x1:b(_),x2:Math.max(b(v),b(_)+2),y1:S(x.index),y2:S(x.index),stroke:"var(--laep-border-subtle)",strokeWidth:r&&r!==x.key?1:2,strokeLinecap:"round"},`lane-${x.key}`)),E.map(x=>s.jsx("path",{d:`M ${x.x} ${x.fromY} C ${x.x} ${(x.fromY+x.toY)/2}, ${x.x} ${(x.fromY+x.toY)/2}, ${x.x} ${x.toY}`,fill:"none",stroke:"var(--laep-provenance-branch)",strokeWidth:1.5,strokeDasharray:"3 2",opacity:.7},`fork-${x.key}`))]}),d.flatMap(x=>x.episodes.map(({episode:_,time:v})=>{const A=r&&r!==x.key;return s.jsx("button",{type:"button","data-minimap-dot":_.id,title:`${_.title} â ${Fn(_.timestamp)}`,"aria-label":`${_.title}, ${Fn(_.timestamp)}, ${x.label}`,onClick:()=>a?.(_),className:"absolute rounded-full border border-[var(--laep-surface-raised)] transition-transform hover:scale-125 focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",style:{width:Ht,height:Ht,left:b(v)-Ht/2,top:S(x.index)-Ht/2,backgroundColor:Pr[_.type]||Pr.activity,opacity:A?.3:1}},`dot-${_.id}-${x.key}`)}))]}):null})]}),s.jsxs("div",{className:"mt-0.5 grid grid-cols-[minmax(120px,170px)_minmax(0,1fr)] gap-2",children:[s.jsx("div",{}),s.jsx("div",{className:"relative h-4 min-w-0",children:l>0&&u.length<=10?u.map((x,_)=>s.jsx("span",{className:"absolute top-0 whitespace-nowrap text-[9px] tabular-nums text-[var(--laep-text-soft)]",style:_===u.length-1&&u.length>1?{right:Math.max(l-b(x.time)-20,0)}:{left:b(x.time)},children:x.label},x.time)):null})]})]})}const en=/^[A-Za-z_][A-Za-z0-9_]*$/,ul=new Set(["and","or","not","true","false","null"]),In={or:1,"||":1,and:2,"&&":2,"==":3,"!=":3,"<":4,"<=":4,">":4,">=":4,"+":5,"-":5,"*":6,"/":6,"%":6};function ve(e){if(typeof e=="number")return Number.isFinite(e)?e:null;if(typeof e=="boolean")return e?1:0;if(typeof e=="string"){const t=e.trim();if(t==="")return null;const n=Number(t);return Number.isFinite(n)?n:null}return null}function Ct(e){return!(e==null||e===!1||e===0||e==="")}function tn(e){return typeof e=="number"&&Number.isFinite(e)?e:null}function Vt(e,t){const n=ve(e);return n===null?null:tn(t(n))}function $r(e,t){const n=e.map(ve).filter(r=>r!==null);return n.length?t(...n):null}const cn={min:{signature:"min(a, b, ...)",minArgs:1,maxArgs:1/0,apply:e=>$r(e,Math.min)},max:{signature:"max(a, b, ...)",minArgs:1,maxArgs:1/0,apply:e=>$r(e,Math.max)},abs:{signature:"abs(x)",minArgs:1,maxArgs:1,apply:([e])=>Vt(e,Math.abs)},round:{signature:"round(x, digits?)",minArgs:1,maxArgs:2,apply:([e,t])=>{const n=ve(e);
238if(n===null)return null;const r=t===void 0?0:ve(t);if(r===null)return null;const i=10**Math.trunc(r);return tn(Math.round(n*i)/i)}},floor:{signature:"floor(x)",minArgs:1,maxArgs:1,apply:([e])=>Vt(e,Math.floor)},ceil:{signature:"ceil(x)",minArgs:1,maxArgs:1,apply:([e])=>Vt(e,Math.ceil)},sqrt:{signature:"sqrt(x)",minArgs:1,maxArgs:1,apply:([e])=>Vt(e,Math.sqrt)},pow:{signature:"pow(x, y)",minArgs:2,maxArgs:2,apply:([e,t])=>{const n=ve(e),r=ve(t);return n===null||r===null?null:tn(n**r)}},coalesce:{signature:"coalesce(a, b, ...)",minArgs:1,maxArgs:1/0,apply:e=>e.find(t=>t!=null)??null},if:{signature:"if(condition, then, else)",minArgs:3,maxArgs:3,apply:([e,t,n])=>Ct(e)?t:n},concat:{signature:"concat(a, b, ...)",minArgs:1,maxArgs:1/0,apply:e=>e.filter(t=>t!=null).map(String).join("")},lower:{signature:"lower(x)",minArgs:1,maxArgs:1,apply:([e])=>e==null?null:String(e).toLowerCase()},upper:{signature:"upper(x)",minArgs:1,maxArgs:1,apply:([e])=>e==null?null:String(e).toUpperCase()}},pl=new Set([...ul,...Object.keys(cn)]),ml=Object.entries(cn).map(([e,t])=>({name:e,signature:t.signature})),fl=new Set(["==","!=","<=",">=","&&","||"]),hl=new Set(["+","-","*","/","%","<",">","(",")",",",".","!"]),gl=/^[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?/;function yl(e){const t=String(e),n=[];let r=0;for(;r<t.length;){const i=t[r];if(/\s/.test(i)){r+=1;continue}if(/[0-9]/.test(i)||i==="."&&/[0-9]/.test(t[r+1]||"")){const o=gl.exec(t.slice(r));n.push({type:"number",value:Number(o[0]),pos:r}),r+=o[0].length;continue}if(i==='"'||i==="'"){let o="",l=r+1,c=!1;for(;l<t.length;){const d=t[l];if(d==="\\"&&l+1<t.length){o+=t[l+1],l+=2;continue}if(d===i){c=!0,l+=1;break}o+=d,l+=1}if(!c)throw new Error(`Unterminated string starting at position ${r}`);n.push({type:"string",value:o,pos:r}),r=l;continue}if(/[A-Za-z_]/.test(i)){const o=/^[A-Za-z0-9_]+/.exec(t.slice(r));n.push({type:"identifier",value:o[0],pos:r}),r+=o[0].length;continue}const a=t.slice(r,r+2);if(fl.has(a)){n.push({type:"op",value:a,pos:r}),r+=2;continue}if(hl.has(i)){n.push({type:"op",value:i,pos:r}),r+=1;continue}throw i==="="?new Error(`Use "==" for comparison (position ${r})`):i==="&"||i==="|"?new Error(`Use "${i}${i}" or "${i==="&"?"and":"or"}" (position ${r})`):new Error(`Unexpected character "${i}" at position ${r}`)}return n.push({type:"eof",value:null,pos:t.length}),n}function bl(e){let t=0;const n=new Set,r=()=>e[t],i=()=>e[t++];function a(u){const m=i();if(m.type!=="op"||m.value!==u)throw new Error(`Expected "${u}" but found ${m.type==="eof"?"end of expression":`"${m.value}"`}`)}function o(){const u=r();if(u.type==="op"&&In[u.value]!=null)return u.value;if(u.type==="identifier"){const m=u.value.toLowerCase();if(m==="and"||m==="or")return m}return null}function l(u){let m=c();for(;;){const h=o();if(h===null||In[h]<u)break;i();const b=l(In[h]+1),S=h==="&&"?"and":h==="||"?"or":h;m=S==="and"||S==="or"?{type:"logical",op:S,left:m,right:b}:{type:"binary",op:S,left:m,right:b}}return m}function c(){const u=r();return u.type==="op"&&(u.value==="-"||u.value==="!")?(i(),{type:"unary",op:u.value==="!"?"not":"-",operand:c()}):u.type==="identifier"&&u.value.toLowerCase()==="not"?(i(),{type:"unary",op:"not",operand:c()}):d()}function d(){const u=i();if(u.type==="number"||u.type==="string")return{type:"literal",value:u.value};if(u.type==="op"&&u.value==="("){const m=l(0);return a(")"),m}if(u.type==="identifier"){const m=u.value.toLowerCase();if(m==="true")return{type:"literal",value:!0};if(m==="false")return{type:"literal",value:!1};if(m==="null")return{type:"literal",value:null};if(m==="and"||m==="or"||m==="not")throw new Error(`Unexpected keyword "${u.value}"`);if(r().type==="op"&&r().value==="("){i();const b=cn[m];if(!b)throw new Error(`Unknown function "${u.value}"`);const S=[];if(!(r().type==="op"&&r().value===")"))for(S.push(l(0));r().type==="op"&&r().value===",";)i(),S.push(l(0));if(a(")"),S.length<b.minArgs)throw new Error(`Function "${m}" expects at least ${b.minArgs} argument${b.minArgs===1?"":"s"}`);if(S.length>b.maxArgs)throw new Error(`Function "${m}" expects at most ${b.maxArgs} argument${b.maxArgs===1?"":"s"}`);return{type:"call",name:m,args:S}}const h=[u.value];for(;r().type==="op"&&r().value===".";){i();const b=i();if(b.type!=="identifier")throw new Error('Expected a field name after "."');h.push(b.value)}return n.add(h[0]),{type:"field",path:h}}throw u.type==="eof"?new Error("Unexpected end of expression"):new Error(`Unexpected token "${u.value}"`)}const p=l(0),f=r();if(f.type!=="eof")throw new Error(`Unexpected token "${f.value}" after expression`);return{ast:p,referencedFields:[...n]}}function gt(e){try{const{ast:t,referencedFields:n}=bl(yl(e));return{ast:t,referencedFields:n,error:null}}catch(t){return{ast:null,referencedFields:[],error:t?.message||"Invalid expression"}}}function Mr(e,t){const n=e==null,r=t==null;if(n||r)return n&&r;const i=ve(e),a=ve(t);return i!==null&&a!==null?i===a:String(e)===String(t)}function vl(e,t,n){if(e==null||t===null||t===void 0)return null;let r,i;if(typeof e=="string"&&typeof t=="string")r=e,i=t;else if(r=ve(e),i=ve(t),r===null||i===null)return null;switch(n){case"<":return r<i;case"<=":return r<=i;case">":return r>i;case">=":return r>=i;default:return null}}function xl(e,t){const{op:n}=e,r=Ee(e.left,t),i=Ee(e.right,t);if(n==="==")return Mr(r,i);if(n==="!=")return!Mr(r,i);if(n==="<"||n==="<="||n===">"||n===">=")return vl(r,i,n);if(n==="+"&&typeof r=="string"&&typeof i=="string")return r+i;const a=ve(r),o=ve(i);if(a===null||o===null)return null;let l;switch(n){case"+":l=a+o;break;case"-":l=a-o;break;case"*":l=a*o;break;case"/":l=o===0?NaN:a/o;break;case"%":l=o===0?NaN:a%o;break;default:return null}return tn(l)}function Ee(e,t){if(!e)return null;switch(e.type){case"literal":return e.value;case"field":{let n=t;for(const r of e.path){if(n==null||typeof n!="object")return null;n=n[r]}return n===void 0?null:n}case"unary":{if(e.op==="not")return!Ct(Ee(e.operand,t));const n=ve(Ee(e.operand,t));return n===null?null:-n}case"logical":{const n=Ct(Ee(e.left,t));return e.op==="and"?n?Ct(Ee(e.right,t)):!1:n?!0:Ct(Ee(e.right,t))}case"binary":return xl(e,t);case"call":{const n=cn[e.name];return n?n.apply(e.args.map(r=>Ee(r,t))):null}default:return null}}function Sl(e){return e===!0?1:e===!1?0:e==null?null:typeof e=="number"?Number.isFinite(e)?e:null:typeof e=="string"?e:null}function wl(e){const t=new Map;for(const c of e)t.set(c.name,c);const n=[...t.values()],r=new Map(n.map(c=>[c.name,0])),i=new Map(n.map(c=>[c.name,[]]));for(const c of n)for(const d of c.referencedFields)t.has(d)&&(r.set(c.name,r.get(c.name)+1),i.get(d).push(c.name));const a=n.filter(c=>r.get(c.name)===0).map(c=>c.name),o=[],l=new Set;for(;a.length;){const c=a.shift();l.add(c),o.push(t.get(c));for(const d of i.get(c))r.set(d,r.get(d)-1),r.get(d)===0&&a.push(d)}for(const c of n)l.has(c.name)||o.push({...c,ast:null});return o}function _l(e,t){if(!Array.isArray(e)||e.length===0)return e;const n=[];for(const i of Array.isArray(t)?t:[]){if(!i||typeof i.name!="string"||!en.test(i.name))continue;const{ast:a,referencedFields:o,error:l}=gt(i.expression??"");
238l||!a||n.push({name:i.name,ast:a,referencedFields:o})}if(n.length===0)return e;const r=wl(n);return e.map(i=>{const a={...i};for(const o of r){let l=null;if(o.ast)try{l=Sl(Ee(o.ast,a))}catch{l=null}a[o.name]=l}return a})}function Nl(e,t,n){const r=new Map;for(const o of n||[]){if(!o||typeof o.name!="string")continue;const{referencedFields:l,error:c}=gt(o.expression??"");r.set(o.name,c?[]:l)}r.set(e,t);const i=[...t],a=new Set;for(;i.length;){const o=i.pop();if(o===e)return!0;if(!a.has(o)){a.add(o);for(const l of r.get(o)||[])i.push(l)}}return!1}function Vn(e,{existingColumns:t=[],otherDefs:n=[]}={}){const r=[],i=[],a=String(e?.name??"").trim(),o=new Set(t.map(c=>String(c).split(".")[0]));if(!a)r.push("Field name is required.");else if(!en.test(a))r.push("Field name must start with a letter or underscore and use only letters, digits, and underscores.");else if(pl.has(a.toLowerCase()))r.push(`"${a}" is a reserved word and cannot be used as a field name.`);else{const c=a.toLowerCase();new Set([...o].map(f=>f.toLowerCase())).has(c)&&r.push(`"${a}" collides with an existing column.`);const p=(n||[]).find(f=>f&&f.id!==e?.id&&String(f.name).toLowerCase()===c);p&&r.push(`"${a}" collides with the computed field "${p.name}".`)}const l=String(e?.expression??"").trim();if(!l)r.push("Expression is required.");else{const{referencedFields:c,error:d}=gt(l);if(d)r.push(d);else{const p=new Set((n||[]).map(f=>String(f?.name??"")));for(const f of c)f!==a&&!o.has(f)&&!p.has(f)&&i.push(`Unknown field "${f}" â it will evaluate to null.`);a&&Nl(a,c,n)&&r.push("Expression creates a circular reference between computed fields.")}}return{ok:r.length===0,errors:r,warnings:i}}const Or={name:"",expression:""},Cl=5;function Yn(e){return e==null?"null":typeof e=="number"?Number.isInteger(e)?String(e):e.toFixed(4).replace(/0+$/,"").replace(/\.$/,""):String(e)}function Il(e){const t=e.filter(i=>i!=null),n=t.filter(i=>typeof i=="number"),r=[`${t.length}/${e.length} non-null`];return n.length&&(r.push(`min ${Yn(Math.min(...n))}`),r.push(`max ${Yn(Math.max(...n))}`)),r.join(" · ")}const El=({computedFields:e=[],availableColumns:t=[],sampleRows:n=[],onAdd:r,onUpdate:i,onDelete:a,onClose:o})=>{const[l,c]=N.useState(Or),[d,p]=N.useState(null),[f,u]=N.useState(""),m=N.useRef(null);N.useEffect(()=>{const v=A=>{A.key==="Escape"&&o?.()};return window.addEventListener("keydown",v),()=>window.removeEventListener("keydown",v)},[o]);const h=N.useMemo(()=>Vn({id:d,name:l.name,expression:l.expression},{existingColumns:t,otherDefs:e}),[l.name,l.expression,d,t,e]),b=l.name.trim()!==""||l.expression.trim()!=="",S=N.useMemo(()=>{const v=l.expression.trim();if(!v||!n.length)return null;const{ast:A,error:P}=gt(v);if(P||!A)return null;const U=n.map($=>{try{return Ee(A,$)}catch{return null}});return{rows:n.slice(0,Cl).map(($,B)=>({uprn:$?.uprn??`#${B+1}`,value:U[B]})),summary:Il(U)}},[l.expression,n]),w=N.useMemo(()=>{const v=f.trim().toLowerCase();return v?t.filter(A=>A.toLowerCase().includes(v)):t},[t,f]),k=v=>{const A=m.current;c(P=>{const U=P.expression,$=A?.selectionStart??U.length,B=A?.selectionEnd??U.length,pe=`${$>0&&!/[\s(,+\-*/%<>=!]$/.test(U.slice(0,$))?" ":""}${v}`,R=U.slice(0,$)+pe+U.slice(B);return requestAnimationFrame(()=>{if(!A)return;A.focus();const C=$+pe.length;A.setSelectionRange(C,C)}),{...P,expression:R}})},E=()=>{c(Or),p(null)},x=v=>{p(v.id),c({name:v.name||"",expression:v.expression||""})},_=()=>{if(!h.ok)return;const v={name:l.name.trim(),expression:l.expression.trim()};d?i?.(d,v):r?.({...v,label:null}),E()};return s.jsx("div",{className:"fixed inset-0 z-[60] bg-slate-950/40 flex items-center justify-center p-4",children:s.jsxs("div",{role:"dialog","aria-modal":"true","aria-labelledby":"field-calculator-title","aria-describedby":"field-calculator-description",className:"w-full max-w-3xl max-h-[86vh] bg-[var(--laep-surface-panel)] rounded-lg shadow-xl border border-[var(--laep-border-subtle)] flex flex-col",children:[s.jsxs("div",{className:"flex items-start justify-between gap-3 px-4 py-3 border-b border-[var(--laep-border-subtle)]",children:[s.jsxs("div",{className:"min-w-0 flex items-center gap-2",children:[s.jsx(no,{className:"w-4 h-4 text-[var(--laep-text-muted)]"}),s.jsxs("div",{children:[s.jsx("h2",{id:"field-calculator-title",className:"text-sm font-semibold text-[var(--laep-text)]",children:"Field Calculator"}),s.jsx("p",{id:"field-calculator-description",className:"text-xs text-[var(--laep-text-muted)]",children:"Add computed columns to the building table. Fields are computed before a simulation run and shared by all scenarios in this session."})]})]}),s.jsx("button",{type:"button",onClick:o,"aria-label":"Close field calculator",className:"p-1 rounded laep-control border",children:s.jsx(Mn,{className:"w-4 h-4"})})]}),s.jsxs("div",{className:"overflow-auto p-4 space-y-4",children:[e.length>0&&s.jsxs("section",{"aria-label":"Existing computed fields",className:"space-y-1.5",children:[s.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wider text-[var(--laep-text-muted)]",children:"Computed fields"}),e.map(v=>s.jsxs("div",{className:`flex items-center gap-2 px-2.5 py-1.5 rounded-md border text-xs ${d===v.id?"border-[var(--laep-focus)] bg-[var(--laep-surface-raised)]":"border-[var(--laep-border-subtle)] bg-[var(--laep-surface-raised)]"}`,children:[s.jsx("span",{className:"font-semibold text-[var(--laep-text)]",children:v.name}),s.jsx("code",{className:"flex-1 truncate font-mono text-[var(--laep-text-muted)]",title:v.expression,children:v.expression}),s.jsx("button",{type:"button",onClick:()=>x(v),"aria-label":`Edit computed field ${v.name}`,className:"p-1 rounded laep-control border",children:s.jsx(Qn,{className:"w-3 h-3"})}),s.jsx("button",{type:"button",onClick:()=>{d===v.id&&E(),a?.(v.id)},"aria-label":`Delete computed field ${v.name}`,className:"p-1 rounded laep-control border",children:s.jsx(er,{className:"w-3 h-3"})})]},v.id))]}),s.jsxs("section",{"aria-label":d?"Edit computed field":"New computed field",className:"space-y-3",children:[s.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wider text-[var(--laep-text-muted)]",children:d?"Edit field":"New field"}),s.jsxs("div",{className:"space-y-1",children:[s.jsx("label",{htmlFor:"computed-field-name",className:"block text-xs font-medium text-[var(--laep-text)]",children:"Field name"}),s.jsx("input",{id:"computed-field-name",value:l.name,onChange:v=>c(A=>({...A,name:v.target.value})),placeholder:"e.g. costEffectivenessRatio",className:"w-full laep-control border rounded-md px-2 py-1.5 text-sm font-mono"})]}),s.jsxs("div",{className:"space-y-1",children:[s.jsx("label",{htmlFor:"computed-field-expression",className:"block text-xs font-medium text-[var(--laep-text)]",children:"Expression"}),s.jsx("textarea",{id:"computed-field-expression",ref:m,value:l.expression,onChange:v=>c(A=>({...A,expression:v.target.value})),placeholder:"e.g. estimatedCost.ASHP / annualEnergyCost",rows:3,className:"w-full laep-control border rounded-md px-2 py-1.5 text-sm font-mono resize-y"})]}),s.jsxs("div",{className:"space-y-1",children:[s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx("span",{className:"text-xs font-medium text-[var(--laep-text)]",children:"Available fields"}),s.jsx("input",{value:f,onChange:v=>u(v.target.value),placeholder:"Filterâ¦","aria-label":"Filter available fields",className:"laep-control border rounded px-1.5 py-0.5 text-[10px] w-28"})]}),s.jsxs("div",{className:"flex flex-wrap gap-1 max-h-24 overflow-auto p-1 border border-[var(--laep-border-subtle)] rounded-md",children:[w.map(v=>s.jsx("button",{type:"button",onClick:()=>k(v),className:"px-1.5 py-0.5 rounded text-[10px] font-mono laep-control border hover:bg-[var(--laep-surface-muted)]",title:`Insert ${v}`,children:v},v)),w.length===0&&s.jsx("span",{className:"text-[10px] text-[var(--laep-text-muted)] px-1",children:"No fields match the filter."})]})]}),b&&h.errors.length>0&&s.jsx("ul",{role:"alert",className:"space-y-0.5 text-xs text-rose-600 dar
238k:text-rose-400",children:h.errors.map(v=>s.jsx("li",{children:v},v))}),b&&h.warnings.length>0&&s.jsx("ul",{className:"space-y-0.5 text-xs text-amber-600 dark:text-amber-400",children:h.warnings.map(v=>s.jsx("li",{children:v},v))}),S&&s.jsxs("div",{className:"border border-[var(--laep-border-subtle)] rounded-md overflow-hidden",children:[s.jsxs("div",{className:"px-2 py-1 text-[10px] uppercase tracking-wider bg-[var(--laep-surface-muted)] text-[var(--laep-text-muted)]",children:["Preview · ",S.summary]}),s.jsx("table",{className:"w-full text-xs",children:s.jsx("tbody",{children:S.rows.map(v=>s.jsxs("tr",{className:"border-t border-[var(--laep-border-subtle)]",children:[s.jsx("td",{className:"px-2 py-1 font-mono text-[var(--laep-text-muted)]",children:v.uprn}),s.jsx("td",{className:`px-2 py-1 text-right font-mono ${v.value==null?"italic text-[var(--laep-text-muted)]":"text-[var(--laep-text)]"}`,children:Yn(v.value)})]},v.uprn))})})]}),s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsxs("button",{type:"button",onClick:_,disabled:!b||!h.ok,className:"inline-flex items-center gap-1 px-3 py-1.5 rounded-md text-xs font-bold bg-[var(--laep-action)] text-[var(--laep-action-contrast)] disabled:opacity-40 disabled:cursor-not-allowed",children:[s.jsx(lt,{className:"w-3.5 h-3.5"}),d?"Save changes":"Add field"]}),(d||b)&&s.jsx("button",{type:"button",onClick:E,className:"px-3 py-1.5 rounded-md text-xs laep-control border",children:"Cancel"})]}),s.jsxs("details",{className:"text-xs text-[var(--laep-text-muted)]",children:[s.jsxs("summary",{className:"cursor-pointer inline-flex items-center gap-1 font-medium",children:[s.jsx(Jt,{className:"w-3 h-3"}),"Expression reference"]}),s.jsxs("div",{className:"mt-2 space-y-2 pl-1",children:[s.jsxs("p",{children:["Operators: ",s.jsx("code",{className:"font-mono",children:"+ - * / %"}),", comparisons ",s.jsx("code",{className:"font-mono",children:"> >= < <= == !="}),", logic ",s.jsx("code",{className:"font-mono",children:"and or not"}),". Nested values use dots: ",s.jsx("code",{className:"font-mono",children:"estimatedCost.ASHP"}),"."]}),s.jsx("p",{className:"font-mono",children:ml.map(v=>v.signature).join(" · ")}),s.jsxs("p",{children:["Missing values evaluate to ",s.jsx("code",{className:"font-mono",children:"null"})," and propagate. True/false results are stored as 1/0 so they work with table histograms. Text compares alphabetically: for EPC ratings, ",s.jsx("code",{className:"font-mono",children:"epc >= 'D'"})," matches D through G (higher letter = worse rating). Keys containing space
238s (e.g. the District Heating cost) are not addressable yet."]})]})]})]})]})]})})};class Ye extends Error{constructor(t,n){super(n),this.name="AssistantProviderError",this.code=t}}function nn(e){if(e instanceof Ye)return e;if(e?.name==="AbortError"||e?.message==="Request was aborted.")return new Ye("aborted","Request cancelled.");const t=e?.status??e?.response?.status;return t===401||t===403?new Ye("auth","Invalid API key â check your key in the assistant settings."):t===404?new Ye("bad_request",`Model not found: ${e?.message||"unknown model id"}.`):t===429?new Ye("rate_limit","Rate limited by the provider â wait a moment and try again."):t===400?new Ye("bad_request",e?.message||"The provider rejected the request."):e?.name==="APIConnectionError"||e?.message?.includes("Connection error")?new Ye("network","Could not reach the provider â check your connection."):new Ye("other",e?.message||"Unexpected provider error.")}let En=null,Lr=null;async function Dr(e){return(!En||Lr!==e)&&(Lr=e,En=ge(async()=>{const{default:t}=await import("./index-CDGEgwxr.js");return{default:t}},__vite__mapDeps([21,3,6,0,1,7])).then(({default:t})=>new t({apiKey:e,dangerouslyAllowBrowser:!0}))),En}function kl(e){return e.map(t=>({name:t.name,description:t.description,input_schema:t.parameters}))}function Al({apiKey:e,model:t}){return{id:"anthropic",async validateKey(){try{return await(await Dr(e)).models.retrieve(t),{ok:!0}}catch(n){return{ok:!1,error:nn(n).message}}},formatUserTurn(n,r){const i=[{type:"text",text:n}];return r&&i.push({type:"text",text:r}),{role:"user",content:i}},isPlainUserTurn(n){return n?.role==="user"&&Array.isArray(n.content)&&n.content[0]?.type==="text"},formatToolResults(n){return[{role:"user",content:n.map(r=>({type:"tool_result",tool_use_id:r.id,content:r.content,...r.isError?{is_error:!0}:{}}))}]},async streamTurn({system:n,tools:r,messages:i,onTextDelta:a,signal:o}){const l=await Dr(e);try{const c=l.messages.stream({model:t,max_tokens:16e3,...t.startsWith("claude-opus")?{thinking:{type:"adaptive"}}:{},system:[{type:"text",text:n,cache_control:{type:"ephemeral"}}],tools:kl(r),messages:i},{signal:o});a&&c.on("text",a);const d=await c.finalMessage(),p=d.content.filter(f=>f.type==="tool_use").map(f=>({id:f.id,name:f.name,input:f.input}));return{assistantMessage:{role:"assistant",content:d.content},toolCalls:p,stopReason:d.stop_reason==="tool_use"?"tool_use":"end"}}catch(c){throw nn(c)}}}}let kn=null,Fr=null;async function Br(e,t){const n=`${t||""}::${e}`;return(!kn||Fr!==n)&&(Fr=n,kn=ge(async()=>{const{default:r}=await import("./index-CeL_WccI.js");return{default:r}},[]).then(({default:r})=>new r({apiKey:e,dangerouslyAllowBrowser:!0,...t?{baseURL:t}:{}}))),kn}function Tl(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.parameters}}))}function jl(e){try{return e?JSON.parse(e):{}}catch{return{__malformed_arguments:e}}}function Pl({apiKey:e,model:t,baseUrl:n=""}){return{id:"openai",async validateKey(){try{const r=await Br(e,n);try{await r.models.retrieve(t)}catch(i){const a=i?.status??i?.response?.status;if(a!==404&&a!==405)throw i;const l=((await r.models.list())?.data||[]).map(c=>c.id);if(l.length&&!l.includes(t))return{ok:!1,error:`Key works, but model "${t}" is not in this endpoint's model list.`}}return{ok:!0}}catch(r){return{ok:!1,error:nn(r).message}}},formatUserTurn(r,i){return{role:"user",content:i?`${r} 239 240${i}`:r}},isPlainUserTurn(r){return r?.role==="user"},formatToolResults(r){return r.map(i=>({role:"tool",tool_call_id:i.id,content:i.isError?`ERROR: ${i.content}`:i.content}))},async streamTurn({system:r,tools:i,messages:a,onTextDelta:o,signal:l}){const c=await Br(e,n);try{const d=await c.chat.completions.create({model:t,stream:!0,messages:[{role:"system",content:r},...a],tools:Tl(i)},{signal:l});let p="";const f=new Map;let u=null;for await(const b of d){const S=b.choices?.[0];if(S){S.delta?.content&&(p+=S.delta.content,o&&o(S.delta.content));for(const w of S.delta?.tool_calls||[]){const k=f.get(w.index)||{id:"",name:"",arguments:""};w.id&&(k.id=w.id),w.function?.name&&(k.name+=w.function.name),w.function?.arguments&&(k.arguments+=w.function.arguments),f.set(w.index,k)}S.finish_reason&&(u=S.finish_reason)}}const m=[...f.entries()].sort(([b],[S])=>b-S).map(([,b])=>b);return{assistantMessage:{role:"assistant",content:p||null,...m.length?{tool_calls:m.map(b=>({id:b.id,type:"function",function:{name:b.name,arguments:b.arguments||"{}"}}))}:{}},toolCalls:m.map(b=>({id:b.id,name:b.name,input:jl(b.arguments)})),stopReason:u==="tool_calls"||m.length?"tool_use":"end"}}catch(d){throw nn(d)}}}}function Yt(e,t){if(t)for(const n of e.split(/(?<=\s)/))t(n)}function Rl(){return{id:"mock",async validateKey(){return{ok:!0}},formatUserTurn(e,t){return{role:"user",kind:"user",text:e,stateBlock:t}},isPlainUserTurn(e){return e?.kind==="user"},formatToolResults(e){return[{role:"user",kind:"tool_results",results:e}]},async streamTurn({messages:e,onTextDelta:t}){await new Promise(a=>setTimeout(a,30));const n=e[e.length-1];if(n?.kind==="tool_results"){const o=n.results.some(l=>l.isError)?"That action failed â see the tool output for details.":`Done â **check these views**: 241 242- the *timeline* 243- the map 244- the decision trail 245 246| what | where | 247| --- | --- | 248| change | logged |`;return Yt(o,t),{assistantMessage:{role:"assistant",kind:"text",text:o},toolCalls:[],stopReason:"end"}}const r=[...e].reverse().find(a=>a.kind==="user")?.text||"";
248if(/computed/i.test(r)){const a="I'll create the ashpCostEffectiveness computed field.";return Yt(a,t),{assistantMessage:{role:"assistant",kind:"tool_use",text:a},toolCalls:[{id:`mock-call-${e.length}`,name:"add_computed_field",input:{name:"ashpCostEffectiveness",expression:"estimatedCost.ASHP / max(annualEnergyCost, 1)"}}],stopReason:"tool_use"}}if(/filter/i.test(r)){const a=r.match(/(ashpCostEffectiveness|costEffectivenessRatio)/i)?.[1],o=a?`I'll select buildings by their ${a} value.`:"I'll select the buildings with the highest energy-cost intensity for you.";return Yt(o,t),{assistantMessage:{role:"assistant",kind:"tool_use",text:o},toolCalls:[{id:`mock-call-${e.length}`,name:"filter_buildings",input:{criteria:[a?{field:a,op:"gt",value:0}:{field:"carbonBaseline",op:"gt",value:7}]}}],stopReason:"tool_use"}}const i="I'll add an air-source heat pump intervention for you.";return Yt(i,t),{assistantMessage:{role:"assistant",kind:"tool_use",text:i},toolCalls:[{id:`mock-call-${e.length}`,name:"add_intervention",input:{label:"ASHP rollout (assistant)",tech:"ASHP",budget_gbp:5e6,start_year:2027,duration_years:3}}],stopReason:"tool_use"}}}}function $l(e){if(sa())return Rl();switch(e.provider){case"openai":return Pl(e);case"anthropic":default:return Al(e)}}const rn=_i.map(e=>e.id),an=["Any","A","B","C","D","E","F","G"],on=["carbonSavingPotential","fuelPovertyScore","gridCapacityEfficiency"],Ml=`You are the planning assistant embedded in the LAEP Strategy Dashboard, a visual analytics tool for Local Area Energy Planning (LAEP). Users are local-authority energy planners exploring decarbonisation scenarios for the building stock of Winchester, UK. 249 250## What the dashboard does 251Planners assemble a *scenario* out of *interventions* (retrofit programmes such as heat pumps or insulation), each with a budget, schedule, and building-targeting rules. Running the simulation rolls the interventions out year by year against the building stock: each year an intervention spends its budget upgrading the highest-priority eligible buildings until the yearly budget is exhausted, then continues the next year. Results (upgrades, spend, carbon saved, demand change) appear on the map, timeline, table, and charts. 252 253## Intervention schema 254- label: short human-readable name. 255- tech: one of ${rn.join(", ")}. ${At.join(" and ")} target differently from the rest -- see "Heat networks" below. 256- budget: total GBP across the intervention's duration (may be split per-year via budget allocations; default is an even split). 257- startYear and duration (years). Years run ${ye}-${ke}. 258- targetEPC: only buildings at or below this EPC band are eligible (${an.join(", ")}; "Any" = no restriction). 259- profile: which buildings the intervention targets â {type:"all"} for the whole stock, {type:"selection"} for the user's current table/map selection, {type:"predefined", predefinedId} for built-in cohorts (e.g. "fuel-poor-top-10", "pv-potential-top-10", "carbon-top-10", "imd-most-deprived-10"), or {type:"saved", profileId} for a profile the user saved earlier. 260- weights: multi-objective prioritisation weights that rank eligible buildings (${on.join(", ")} â should sum to about 1). 261- prioritisation: {type:"weights"} to rank by the weighted score, or {type:"columns", columns:[{field, dir}]} to sort by explicit data columns instead. 262 263## How to behave 264- Ground every answer in tool results. Call get_dashboard_state when unsure of the current scenario, and never fabricate simulation numbers â read them with get_simulation_results or run_simulation. 265- After changing something, tell the user briefly what you changed and where to see it (timeline, map, decision trail). Keep responses concise; planners read them in a narrow side panel. 266- Interventions you add are drafts on the active scenario; simulation only runs when run_simulation is called. Run it when the user asks for results or clearly wants to see the impact of changes. 267- When the user's request is ambiguous (e.g. no budget given), pick a sensible default, state the assumption, and invite correction â do not stall with questions for minor details. 268- Currency is GBP. Carbon figures are tonnes CO2e unless stated otherwise. 269- You cannot undo actions; deleting an intervention or scenario and branching a scenario require the user's explicit confirmation in the UI. 270 271## Targeting buildings 272The usual workflow for a targeted programme: filter_buildings with data-dictionary criteria (this selects the matches on the map and table) â save_selection_as_profile to make the cohort reusable â add_intervention with profile {type:"saved", profileId} (or {type:"selection"} for a one-off). Prefer the built-in predefined profiles when they already express the user's intent (e.g. "fuel-poor-top-10"). 273 274## Heat networks 275${At.join(" and ")} do not work like the other technologies. Whether a dwelling can connect is a planning decision about where pipes are laid, not a property of the building, so the per-building suitability flag in the data encodes just one assumed network and covers only a small share of the stock (roughly 3,400 of 62,700 residential buildings). 276 277Because of that, scoping such an intervention to a *zone* makes the zone define eligibility in place of the flag: every building in the zone is treated as connectable. A zone is any profile that resolves to a strict, non-empty subset of the stock -- {type:"saved"}, {type:"selection"}, or {type:"predefined"}. {type:"all"} is not a zone, and neither is a saved profile that happens to cover the whole stock: in both cases the sparse flag still applies and the rollout will be small. This latitude is confined to the technologies named above; ASHP, PV and the rest keep their per-building suitability check even inside a zone. 278 279So to model a heat network, define the area it serves first (filter_buildings -> save_selection_as_profile) and give the intervention that profile. If the user asks for district heating across the whole stock, explain that a network reaching every dwelling is not a zone and propose a served area instead. Costs for these technologies are a flat per-building placeholder rather than a
279network-design estimate, so do not present their spend as a costed network design. 280 281## Computed fields (field calculator) 282add_computed_field creates a derived column from a formula over building attributes; it is materialized on every row and immediately usable in filter_buildings criteria, prioritisation columns, and map glyph_fields. Typical use: "cost-effectiveness against baseline energy spend" -> add_computed_field {name:"costEffectivenessRatio", expression:"estimatedCost.ASHP / annualEnergyCost"} then prioritise or filter by it. Use annualEnergyCost for a building's own annual energy spend in pounds. Do not use carbonBaseline for that: it is the EPC-band cost intensity in pounds per m2 per year and takes only one value per band, so a ratio built on it cannot tell two buildings in the same band apart. Neither field is tonnes of carbon, so name derived fields accordingly. 283Expression language: field names (nested via dots, e.g. estimatedCost.ASHP), numbers, quoted strings, + - * / %, comparisons (== != < <= > >=, strings compare lexicographically so epc >= "D" matches D-G), and/or/not, functions min, max, abs, round(x, digits?), floor, ceil, sqrt, pow, coalesce, if(condition, then, else), concat, lower, upper. Missing fields and division by zero evaluate to null, which propagates; booleans materialize as 1/0. Names must be valid identifiers and not collide with existing columns. Computed fields may reference other computed fields (no cycles). Existing computed fields and their expressions appear in the dashboard state. 284 285## Plan order and budget curves 286- Interventions in the dashboard state are listed in plan order (drawn top to bottom on the timeline). reorder_intervention moves one up or down; use steps to move several places. 287- Each intervention's total budget defaults to an even per-year split. set_budget_curve reshapes it: named curves (linear, sqrt/log ramps, quad/cubic/exp ramps, invert to flip front/back-loading) or explicit yearly_budgets that must sum to the total budget â to change the total too, update_intervention budget_gbp first. Changing an intervention's budget, start year, or duration resets any custom curve to an even split. 288 289## Views and scenarios 290- set_current_year moves the timeline; set_map_config changes what the map shows (glyph columns, raw vs deployment layer, split-view scenario comparison). 291- Scenarios are alternative plans. branch_scenario copies an existing one to explore an alternative; switch_scenario changes which is active. Comparing two scenarios on the map: set_map_config with split_view and compare_scenario_id. 292- create_scenario/branch_scenario make the new scenario active; its generated id shows up in the next <dashboard_state> block or via get_dashboard_state. 293 294## Data dictionary 295`;function Ol({dataDictionary:e}){return Ml+(e||"No building data loaded yet.")}const Ur=/^[A-Za-z_$][A-Za-z0-9_$]*$/,Hr=500,Ll=12,Dl=60;let Vr=null,An="";function Fl(e){const t=[];for(const[n,r]of Object.entries(e))if(Ur.test(n)&&!Array.isArray(r)){if(r!==null&&typeof r=="object"){for(const i of Object.keys(r))Ur.test(i)&&t.push(`${n}.${i}`);continue}t.push(n)}return t.sort((n,r)=>n.localeCompare(r))}function Bl(e,t){if(!t.includes("."))return e?.[t];const[n,r]=t.split(".");return e?.[n]?.[r]}function Ul(e){if(!e?.length)return"No building data loaded yet.";if(e===Vr)return An;const t=Fl(e[0]).slice(0,Dl),n=Math.max(1,Math.floor(e.length/Hr)),r=[];for(let a=0;a<e.length&&r.length<Hr;a+=n)r.push(e[a]);const i=["| column | type | details |","| --- | --- | --- |"];for(const a of t){let o=1/0,l=-1/0,c=0;const d=new Set;let p=!1;for(const f of r){const u=Bl(f,a);u==null||u===""||(typeof u=="number"&&Number.isFinite(u)?(c+=1,u<o&&(o=u),u>l&&(l=u)):p||(d.add(String(u)),d.size>Ll&&(p=!0)))}if(c>r.length/2){const f=u=>Math.abs(u)>=1e3?Math.round(u).toLocaleString("en-GB"):String(Math.round(u*100)/100);i.push(`| ${a} | number | range ~${f(o)} to ${f(l)} |`)}else if(!p&&d.size>0){const f=[...d].sort().join(", ");i.push(`| ${a} | string | values: ${f} |`)}else i.push(`| ${a} | string | high cardinality |`)}
295return Vr=e,An=`Building stock: ${e.length.toLocaleString("en-GB")} buildings. Columns (sampled): 296${i.join(` 297`)}`,An}const Hl=25,Vl=15,Yl=40,Wl=30,ql=15;function je(e,t=1){const n=Number(e);if(!Number.isFinite(n))return 0;const r=10**t;return Math.round(n*r)/r}function Wt(e,t){return Array.isArray(e)?e.length<=t?{items:e,truncated:0}:{items:e.slice(0,t),truncated:e.length-t}:{items:[],truncated:0}}function zl(e,t=[]){if(!e||e.type==="all")return"all buildings";if(e.type==="selection")return"current table/map selection";if(e.type==="predefined")return`predefined profile "${e.predefinedId}"`;if(e.type==="saved"){const n=t.find(r=>r.id===e.profileId);return n?`saved profile "${n.name}" (${n.uprns?.length??0} buildings)`:`saved profile ${e.profileId} (missing)`}return String(e.type)}function $i(e,t=[]){const n=e.budgetAllocations;return{id:e.id,label:e.label,tech:e.tech,budget:e.budget,startYear:e.startYear,duration:e.duration,...Array.isArray(n)&&n.length?{yearlyBudgets:Object.fromEntries(n.map(r=>[r.year,Math.round(r.budget)]))}:{},targetEPC:e.targetEPC,weights:e.weights,prioritisation:e.prioritisation?.type==="columns"?`by columns: ${(e.prioritisation.columns||[]).map(r=>`${r.field} ${r.dir}`).join(", ")}`:"by weights",target:zl(e.profile,t)}}function Mi(e){const t=e.activeScenario,n=t?.profiles||[],r=t?.interventions||[],{items:i,truncated:a}=Wt(r.map(h=>$i(h,n)),Hl),{items:o,truncated:l}=Wt(n.map(h=>({id:h.id,name:h.name,buildings:h.uprns?.length??0})),Vl),c=(e.prioritisationColumns||[]).map(h=>typeof h=="string"?h:h.id),{items:d,truncated:p}=Wt(c,Yl),{items:f,truncated:u}=Wt((e.activeSession?.computedFields||[]).map(h=>({id:h.id,name:h.name,expression:h.expression})),ql),m={activeScenario:t?{id:t.id,name:t.name,description:t.description||void 0}:null,scenarios:(e.state?.scenarios||[]).map(h=>({id:h.id,name:h.name,active:h.id===t?.id||void 0})),currentYear:e.state?.ui?.currentYear,dataMode:e.dataMode,buildingCount:e.derivedBuildings?.length??0,selectedBuildingCount:e.selectedUprns?.length??0,interventions:i,...a?{interventionsNote:`...and ${a} more`}:{},savedProfiles:o,...l?{savedProfilesNote:`...and ${l} more`}:{},simulationStatus:e.state?.ui?.simulationStatus,hasSimulationResults:!!e.state?.ui?.simulationOutput,prioritisationColumns:d,...p?{columnsNote:`...and ${p} more`}:{},...f.length?{computedFields:f}:{},...u?{computedFieldsNote:`...and ${u} more`}:{}};return JSON.stringify(m)}function Yr(e,{scope:t="summary",year:n,interventionId:r}={}){if(!e)return JSON.stringify({error:"No simulation results available. Run the simulation first."});if(t==="year"){const c=e.yearly?.[String(n)]??e.yearly?.[n];return JSON.stringify(c?{year:n,upgrades:c.upgrades,budgetSpent:Math.round(c.budget),carbonSaved:je(c.carbonSaved),demandChange:je(c.demandChange)}:{year:n,note:"No activity in this year."})}if(t==="intervention"){const c=e.interventionSummary?.[r];return JSON.stringify(c?{id:c.id,label:c.label,technology:c.technology,upgrades:c.upgrades,budgetSpent:Math.round(c.budget),carbonSaved:je(c.carbonSaved),demandChange:je(c.demandChange)}:{interventionId:r,error:"No results for this intervention id."})}const i=Object.keys(e.yearly||{}).sort(),a={upgrades:0,budget:0,carbonSaved:0,demandChange:0},o={};for(const c of i.slice(0,Wl)){const d=e.yearly[c];o[c]={upgrades:d.upgrades,budgetSpent:Math.round(d.budget),carbonSaved:je(d.carbonSaved),demandChange:je(d.demandChange)},a.upgrades+=d.upgrades,a.budget+=d.budget,a.carbonSaved+=d.carbonSaved,a.demandChange+=d.demandChange}const l=Object.values(e.interventionSummary||{}).map(c=>({id:c.id,label:c.label,technology:c.technology,upgrades:c.upgrades,budgetSpent:Math.round(c.budget),carbonSaved:je(c.carbonSaved),demandChange:je(c.demandChange)}));return JSON.stringify({ranAt:e.ranAt,currentYear:e.currentYear,totals:{upgrades:a.upgrades,budgetSpent:Math.round(a.budget),carbonSaved:je(a.carbonSaved),demandChange:je(a.demandChange)},yearly:o,perIntervention:l})}const Gl={type:"object",description:"Prioritisation weights; should sum to about 1. Omit to keep defaults (carbon 0.5, fuel poverty 0.3, grid 0.2).",properties:Object.fromEntries(on.map(e=>[e,{type:"number",minimum:0,maximum:1}])),additionalProperties:!1},Kl={type:"object",description:`Which buildings the intervention targets. For a network-scoped technology (${At.join(", ")}) this doubles as the network's extent: anything other than {type:"all"} defines where the network runs and makes those buildings eligible.`,properties:{type:{type:"string",enum:["all","selection","predefined","saved"]},predefinedId:{type:"string",description:'Required when type is "predefined".',enum:["all","fuel-poor-top-10","fuel-poor-top-25","pv-potential-top-10","carbon-top-10","imd-most-deprived-10"]},profileId:{type:"string",description:'Required when type is "saved". Use a saved profile id from the dashboard state.'}},required:["type"],additionalProperties:!1},Zl={type:"object",description:"How eligible buildings are ranked. Default: by weights.",properties:{type:{type:"string",enum:["weights","columns"]},columns:{type:"array",description:'Required when type is "columns". Sort keys applied in order; field must be a known data column.',items:{type:"object",properties:{field:{type:"string"},dir:{type:"string",enum:["asc","desc"]}},required:["field","dir"],additionalProperties:!1}}},required:["type"],additionalProperties:!1},Wr={label:{type:"string",description:'Short human-readable name, e.g. "ASHP rollout phase 1".'},tech:{type:"string",enum:rn,description:`Technology to deploy. ${At.join(" and ")} are network-scoped: eligibility comes from the profile the intervention is scoped to rather than from a per-building flag, so give one of these a profile covering the area the network serves. Scoped to {type:"all"} they fall back to a sparse suitability flag and reach very few buildings.`},budget_gbp:{type:"number",description:"Total budget in GBP across the whole duration."},start_year:{type:"integer",minimum:ye,maximum:ke},duration_years:{type:"integer",minimum:1,maximum:15},target_epc:{type:"string",enum:an,description:'Only buildings at or below this EPC band are eligible. "Any" = no restriction.'},weights:Gl,profile:Kl,prioritisation:Zl},Jl=Object.freeze([{name:"get_dashboard_state",description:"Read the current dashboard state: active scenario, its interventions, saved profiles, selection count, simulation status, and available data columns. Call this whenever you are unsure what the user is looking at.",parameters:{type:"object",properties:{},additionalProperties:!1}},{name:"add_intervention",description:"Add a new intervention to the active scenario. Only label and tech are required; everything else has sensible defaults (budget £4m, start at current year, 3 years, all buildings, default weights). State your assumptions to the user afterwards.",parameters:{type:"object",properties:Wr,required:["label","tech"],additionalProperties:!1}},{name:"update_intervention",description:"Update fields of an existing intervention on the active scenario. Only include the fields you want to change.",parameters:{type:"object",properties:{intervention_id:{type:"string",description:"Id of the intervention to change (see get_dashboard_state)."},updates:{type:"object",properties:Wr,additionalProperties:!1}},required:["intervention_id","updates"],additionalProperties:!1}},{name:"delete_intervention",description:"Delete an intervention from the active scenario. The user must approve this in the UI before it executes.",parameters:{type:"object",properties:{intervention_id:{type:"string"}},required:["intervention_id"],additionalProperties:!1}},{name:"run_simulation",description:"Run the scenario simulation against the building stock and return a summary of the results. Takes a few seconds on the full dataset.",parameters:{type:"object",properties:{},additionalProperties:!1}},{name:"get_simulation_results",description:'Read results of the most recent simulation run without re-running it. scope "summary" gives totals + per-year + per-intervention aggregates; "year" and "intervention" drill in.',parameters:{type:"object",properties:{scope:{type:"string",enum:["summary","year","intervention"]},year:{type:"integer",minimum:ye,maximum:ke,description:'Required when scope is "year".'},intervention_id:{type:"string",description:'Required when scope is "intervention".'}},required:["scope"],additionalProperties:!1}}]),Xl=Object.freeze([{name:"filter_buildings",description:'Filter the building stock by data-column criteria and (by default) select the matching buildings on the map and table. Selected buildings can then be targeted by interventions via profile {type:"selection"} or saved as a reusable profile. Fields must come from the data dictionary.',parameters:{type:"object",properties:{criteria:{type:"array",minItems:1,items:{type:"object",properties:{field:{type:"string",description:'A column from the data dictionary, e.g. "annualEnergyCost" or "estimatedCost.ASHP".'}
297,op:{type:"string",enum:["eq","neq","gt","gte","lt","lte","in","contains"]},value:{description:'Comparison value. Use an array for "in"; a string for "contains"; numbers for range operators.',anyOf:[{type:"string"},{type:"number"},{type:"boolean"},{type:"array",items:{anyOf:[{type:"string"},{type:"number"}]}}]}},required:["field","op","value"],additionalProperties:!1}},combine:{type:"string",enum:["and","or"],description:'How criteria combine. Default "and".'},select:{type:"boolean",description:"Whether to select the matches in the UI. Default true."}},required:["criteria"],additionalProperties:!1}},{name:"save_selection_as_profile",description:'Save the currently selected buildings as a named reusable profile on the active scenario, so interventions can target it via profile {type:"saved"}.',parameters:{type:"object",properties:{name:{type:"string",description:'Short descriptive name, e.g. "High-carbon off-gas homes".'}},required:["name"],additionalProperties:!1}},{name:"clear_selection",description:"Clear the current building selection (map + table).",parameters:{type:"object",properties:{},additionalProperties:!1}},{name:"set_current_year",description:"Move the dashboard timeline to a specific year. Affects the map and results views.",parameters:{type:"object",properties:{year:{type:"integer",minimum:ye,maximum:ke}},required:["year"],additionalProperties:!1}},{name:"set_map_config",description:"Change what the map shows. Use glyph_fields to visualise numeric columns as map glyphs, layer to switch raw stock vs simulated deployment, split_view + compare_scenario_id to compare scenarios side by side.",parameters:{type:"object",properties:{layer:{type:"string",enum:["raw","deployment"],description:'"raw" building stock or simulated "deployment" results.'},glyph_fields:{type:"array",items:{type:"string"},description:"Numeric data columns to show as map glyphs."},glyph_metric:{type:"string",enum:["sum","mean"]},show_glyph_layer:{type:"boolean"},split_view:{type:"boolean",description:"Side-by-side scenario comparison."},compare_scenario_id:{type:"string",description:"Scenario to compare against (with split_view)."},compare_year:{type:"integer",minimum:ye,maximum:ke},timeline_metric:{type:"string",enum:["carbon","cost","upgrades"]},basemap:{type:"string",enum:["light","dark"]}},additionalProperties:!1}},{name:"create_scenario",description:"Create a new empty scenario and make it active.",parameters:{type:"object",properties:{name:{type:"string"},description:{type:"string"}},required:["name"],additionalProperties:!1}},{name:"switch_scenario",description:"Switch the active scenario. Note: this clears unsimulated results views.",parameters:{type:"object",properties:{scenario_id:{type:"string",description:"Scenario id from the dashboard state."}},required:["scenario_id"],additionalProperties:!1}},{name:"branch_scenario",description:"Branch an existing scenario into an alternative (copies its interventions and profiles, starts a new lineage branch, becomes active). The user must approve this in the UI.",parameters:{type:"object",properties:{scenario_id:{type:"string"},name:{type:"string",description:"Name for the new branch."},change_summary:{type:"string",description:"One line on why this branch exists."}},required:["scenario_id","name"],additionalProperties:!1}},{name:"delete_scenario",description:"Delete a scenario permanently. The user must approve this in the UI.",parameters:{type:"object",properties:{scenario_id:{type:"string"}},required:["scenario_id"],additionalProperties:!1}}]),Ql=Object.freeze([{name:"add_computed_field",description:'Create a computed (calculated) column from a formula over building attributes, e.g. "estimatedCost.ASHP / annualEnergyCost". The new column is materialized on every building row and becomes usable in filter_buildings, prioritisation columns, and map glyphs. Expression language: arithmetic (+ - * / %), comparisons (== != < <= > >=), and/or/not, string literals in quotes, nested fields via dots, functions min/max/abs/round/floor/ceil/sqrt/pow/coalesce/if/concat/lower/upper. Missing values evaluate to null and propagate.',parameters:{type:"object",properties:{name:{type:"string",description:'Column name: letters, digits, underscores; must start with a letter or underscore. E.g. "costEffectivenessRatio".'},expression:{type:"string",description:'The formula, e.g. "estimatedCost.ASHP / annualEnergyCost" or "if(fuelPoorPct > 20, 1, 0)". Prefer annualEnergyCost over carbonBaseline for the annual spend of an individual building: carbonBaseline is a per-m2 band intensity with one value per EPC band.'},label:{type:"string",description:"Optional human-readable label shown in the UI."}},required:["name","expression"],additionalProperties:!1}},{name:"update_computed_field",description:"Change the name, expression, or label of an existing computed field.",parameters:{type:"object",properties:{field:{type:"string",description:"Id or name of the computed field (see dashboard state)."},updates:{type:"object",properties:{name:{type:"string"},expression:{type:"string"},label:{type:"string"}},additionalProperties:!1}},required:["field","updates"],additionalProperties:!1}},{name:"delete_computed_field",description:"Delete a computed field. Anything still referencing it (other computed fields, prioritisation columns) will see nulls.",parameters:{type:"object",properties:{field:{type:"string",description:"Id or name of the computed field."}},required:["field"],additionalProperties:!1}},{name:"reorder_intervention",description:"Move an intervention up or down in the scenario plan order (the order interventions are listed and drawn on the timeline). Interventions in the dashboard state are listed in plan order; use steps to move more than one place.",parameters:{type:"object",properties:{intervention_id:{type:"string"},direction:{type:"string",enum:["up","down"]},steps:{type:"integer",minimum:1,description:"How many places to move. Default 1."}},required:["intervention_id","direction"],additionalProperties:!1}},{name:"set_budget_curve",description:"Shape how an intervention's total budget is spread across its years. Either pick a named curve (linear = even split; sqrt/log = front-loaded ramps; quad/cubic/exp = back-loaded ramps; invert flips front/back), or pass explicit yearly_budgets that must cover the intervention's years and sum to its total budget.",parameters:{type:"object",properties:{intervention_id:{type:"string"},curve:{type:"string",enum:["linear","log","sqrt","exp","quad","cubic"]},invert:{type:"boolean",description:"Flip the curve (front-loaded â back-loaded). Only with curve."},yearly_budgets:{type:"array",description:"Explicit per-year spend. Years must fall within the intervention schedule; the sum must equal the intervention budget (±1%).",items:{type:"object",properties:{year:{type:"integer",minimum:ye,maximum:ke},budget_gbp:{type:"number",minimum:0}},required:["year","budget_gbp"],additionalProperties:!1}}},required:["intervention_id"],additionalProperties:!1}}]),ec=Object.freeze([...Jl,...Xl,...Ql]),tc=new Set(["delete_intervention","branch_scenario","delete_scenario"]),Oc={get_dashboard_state:"Read dashboard state",add_intervention:"Add intervention",update_intervention:"Update intervention",delete_intervention:"Delete intervention",run_simulation:"Run simulation",get_simulation_results:"Read simulation results",filter_buildings:"Filter buildings",save_selection_as_profile:"Save selection as profile",clear_selection:"Clear selection",set_current_year:"Set timeline year",set_map_config:"Configure map",create_scenario:"Create scenario",switch_scenario:"Switch scenario",branch_scenario:"Branch scenario",delete_scenario:"Delete scenario",add_computed_field:"Add computed field",update_computed_field:"Update computed field",delete_computed_field:"Delete computed field",reorder_intervention:"Reorder intervention",set_budget_curve:"Set budget curve"}
297,nc=["eq","neq","gt","gte","lt","lte","in","contains"];class ft extends Error{}function St(e,t){if(!t.includes("."))return e?.[t];const[n,r]=t.split(".");return e?.[n]?.[r]}function rc(e){const t=e?.[0];if(!t)return new Set;const n=new Set;for(const[r,i]of Object.entries(t)){if(Array.isArray(i)){n.add(r);continue}if(i!==null&&typeof i=="object"){for(const a of Object.keys(i))n.add(`${r}.${a}`);continue}n.add(r)}return n}function ic(e){const{field:t,op:n,value:r}=e;switch(n){case"eq":return i=>{const a=St(i,t);return typeof r=="string"?String(a)===r:a===r};case"neq":return i=>{const a=St(i,t);return typeof r=="string"?String(a)!==r:a!==r};case"gt":case"gte":case"lt":case"lte":{const i=Number(r);if(!Number.isFinite(i))throw new ft(`Operator "${n}" on "${t}" needs a numeric value.`);return a=>{const o=Number(St(a,t));return Number.isFinite(o)?n==="gt"?o>i:n==="gte"?o>=i:n==="lt"?o<i:o<=i:!1}}case"in":{if(!Array.isArray(r)||!r.length)throw new ft(`Operator "in" on "${t}" needs a non-empty array value.`);const i=new Set(r.map(String));return a=>i.has(String(St(a,t)))}case"contains":{const i=String(r).toLowerCase();return a=>{const o=St(a,t);return Array.isArray(o)?o.some(l=>String(l).toLowerCase()===i):String(o??"").toLowerCase().includes(i)}}default:throw new ft(`Unknown operator "${n}". Valid: ${nc.join(", ")}.`)}}function ac(e,t,n="and"){if(!Array.isArray(t)||!t.length)throw new ft("At least one filter criterion is required.");if(n!=="and"&&n!=="or")throw new ft('combine must be "and" or "or".');const r=rc(e);for(const a of t)if(r.size&&!r.has(a.field))throw new ft(`Unknown field "${a.field}". Valid fields are listed in the data dictionary.`);const i=t.map(ic);return(e||[]).filter(a=>n==="and"?i.every(o=>o(a)):i.some(o=>o(a)))}const Tn=e=>`${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;class M extends Error{}function Xe(e){if(!e.activeScenario)throw new M("No active scenario. Ask the user to create or select a scenario first.");return e.activeScenario}function qt(e,t){const n=(e.interventions||[]).find(r=>r.id===t);if(!n)throw new M(`No intervention with id "${t}" in the active scenario. Call get_dashboard_state to list interventions.`);return n}function oc(e){const t={};let n=0;for(const r of Object.keys(e)){if(!on.includes(r))throw new M(`Unknown weight "${r}".`);const i=Number(e[r]);if(!Number.isFinite(i)||i<0||i>1)throw new M(`Weight "${r}" must be a number between 0 and 1.`);t[r]=i,n+=i}for(const r of on)r in t||(t[r]=0);if(n<.5||n>1.5)throw new M(`Weights should sum to about 1 (got ${n.toFixed(2)}).`);return t}function qr(e,t){return!Ci(e)||t&&t.type!=="all"?null:`${e} is network-scoped: with a stock-wide profile its eligibility falls back to the sparse per-building suitability flag, which covers only a small share of the stock. Scope it to a saved profile or selection covering the area the network serves to make that zone define eligibility.`}function sc(e,t){const n=t.activeScenario;switch(e.type){case"all":return{type:"all"};case"selection":{if(!(t.selectedUprns?.length??0))throw new M("No buildings are currently selected. Ask the user to select buildings on the map or table first, or target a different profile.");return{type:"selection"}}case"predefined":{if(!e.predefinedId)throw new M("predefinedId is required for a predefined profile.");return{type:"predefined",predefinedId:e.predefinedId}}case"saved":{if(!(n?.profiles||[]).find(i=>i.id===e.profileId))throw new M(`No saved profile with id "${e.profileId}". Call get_dashboard_state to list saved profiles.`);return{type:"saved",profileId:e.profileId}}default:throw new M(`Unknown profile type "${e.type}".`)}}function lc(e,t){if(e.type==="weights")return{type:"weights",columns:[]};if(e.type!=="columns")throw new M(`Unknown prioritisation type "${e.type}".`);const n=e.columns||[];if(!n.length)throw new M("Column prioritisation needs at least one column.");const r=new Set((t.prioritisationColumns||[]).map(a=>typeof a=="string"?a:a.id));return{type:"columns",columns:n.map(a=>{if(r.size&&!r.has(a.field))throw new M(`Unknown column "${a.field}". Valid columns are listed in the dashboard state.`);if(a.dir!=="asc"&&a.dir!=="desc")throw new M(`Sort direction for "${a.field}" must be "asc" or "desc".`);return{field:a.field,dir:a.dir}})}}function zr(e,t){const n={};if(e.label!==void 0){const r=String(e.label).trim();if(!r)throw new M("label must not be empty.");n.label=r}if(e.tech!==void 0){if(!rn.includes(e.tech))throw new M(`Unknown tech "${e.tech}". Valid: ${rn.join(", ")}.`);n.tech=e.tech}if(e.budget_gbp!==void 0){const r=Number(e.budget_gbp);if(!Number.isFinite(r)||r<=0)throw new M("budget_gbp must be a positive number.");n.budget=Math.round(r)}if(e.start_year!==void 0){const r=Number(e.start_year);if(!Number.isInteger(r)||r<ye||r>ke)throw new M(`start_year must be an integer between ${ye} and ${ke}.`);n.startYear=r}if(e.duration_years!==void 0){const r=Number(e.duration_years);if(!Number.isInteger(r)||r<1||r>15)throw new M("duration_years must be an integer between 1 and 15.");n.duration=r}if(e.target_epc!==void 0){if(!an.includes(e.target_epc))throw new M(`target_epc must be one of ${an.join(", ")}.`);n.targetEPC=e.target_epc}return e.weights!==void 0&&(n.weights=oc(e.weights)),e.profile!==void 0&&(n.profile=sc(e.profile,t)),e.prioritisation!==void 0&&(n.prioritisation=lc(e.prioritisation,t)),n}function Gr(e,t){const n=e.activeSession?.computedFields||[],r=n.find(i=>i.id===t)||n.find(i=>i.name===t);if(!r)throw new M(`No computed field "${t}". Computed fields are listed in the dashboard state.`);return r}function Kr(e){const t=(e.derivedBuildings||[])[0];if(!t)return[];const n=new Set((e.activeSession?.computedFields||[]).map(r=>r.name));return Object.keys(t).filter(r=>!n.has(r))}function Zr(e,t){const{ast:n,error:r}=gt(e);return r||!n?[]:(t.derivedBuildings||[]).slice(0,5).map(i=>{try{const a=Ee(n,i);return typeof a=="number"?Number.isFinite(a)?Math.round(a*100)/100:null:a??null}catch{return null}})}const Me=Object.freeze({source:"assistant",uiContext:Object.freeze({surface:"assistant-chat"})}),cc={get_dashboard_state(e,t){return Mi(t)},add_intervention(e,t){const n=Xe(t),r=zr(e,t);if(!r.label||!r.tech)throw new M("label and tech are required.");const i={id:Tn("intv"),strategy:"multi-objective",profile:{type:"all"},startYear:t.state?.ui?.currentYear??ye,duration:3,budget:4e6,weights:{carbonSavingPotential:.5,fuelPovertyScore:.3,gridCapacityEfficiency:.2},targetEPC:"Any",status:"planned",prioritisation:{type:"weights",columns:[]},pluginConfig:{budget:!0,history:!0,carbon:!0,demand:!0},...r};t.actions.addIntervention(n.id,i,Me);const a=qr(i.tech,i.profile);return JSON.stringify({status:"added",intervention:$i(i,n.profiles||[]),note:"Draft added to the active scenario; run_simulation to see its impact.",...a?{warning:a}:{}})},update_intervention(e,t){const n=Xe(t),r=qt(n,e.intervention_id),i=zr(e.updates||{},t);if(!Object.keys(i).length)throw new M("No valid fields to update.");const a=(i.budget!==void 0||i.startYear!==void 0||i.duration!==void 0)&&Array.isArray(r.budgetAllocations)&&r.budgetAllocations.length>0;a&&(i.budgetAllocations=null),t.actions.updateIntervention(n.id,r.id,i,Me);const o={};for(const d of Object.keys(i))o[d]={from:r[d],to:i[d]};const l={...r,...i},c=qr(l.tech,l.profile);return JSON.stringify({status:"updated",id:r.id,changed:o,...a?{note:"The per-year budget curve was reset to an even split; use set_budget_curve to reshape it."}:{},...c?{warning:c}:{}})},delete_intervention(e,t){const n=Xe(t),r=qt(n,e.intervention_id);return t.actions.deleteIntervention(n.id,r.id,Me),JSON.stringify({status:"deleted",id:r.id,label:r.label})},async run_simulation(e,t){if(Xe(t),typeof t.runSimulation!="function")throw new M("Simulation is not available right now.");const n=await t.runSimulation();if(!n)throw new M("Simulation failed or produced no output. The dashboard shows the error state.");return Yr(n,{scope:"summary"})},get_simulation_results(e,t){const n=t.state?.ui?.simulationOutput;return Yr(n,{scope:e.scope||"summary",year:e.year,interventionId:e.intervention_id})},filter_buildings(e,t){const n=t.derivedBuildings||[];if(!n.length)throw new M("No building data loaded yet.");let r;try{r=ac(n,e.criteria,e.combine||"and")}catch(o){throw new M(o.message)}const i=e.select!==!1,a=r.map(o=>String(o.uprn));return i&&t.actions.setSelection(a.length?a:null),JSON.stringify({matched:r.length,total:n.length,selected:i&&r.length>0,sampleUprns:a.slice(0,10),...r.length>10?{note:`...and ${r.length-10} more`}:{}})},save_selection_as_profile(e,t){const n=Xe(t),r=String(e.name||"").trim();if(!r)throw new M("name must not be empty.");const i=t.selectedUprns||[];if(!i.length)throw new M("No buildings are selected. Use filter_buildings first, or ask the user to select some.");const a={id:Tn("profile"),name:r,uprns:[...i]};return t.actions.addProfile(n.id,a,Me),JSON.stringify({status:"saved",profile:{id:a.id,name:r,buildings:i.length},note:'Target it with profile {type:"saved", profileId} on an intervention.'})},clear_selection(e,t){return t.actions.setSelection(null),JSON.stringify({status:"cleared"})},set_current_year(e,t){const n=Number(e.year);if(!Number.isInteger(n)||n<ye||n>ke)throw new M(`year must be an integer between ${ye} and ${ke}.`);return t.actions.setCurrentYear(n),JSON.stringify({status:"set",year:n})},set_map_config(e,t){const n={};if(e.layer!==void 0&&(n.layer=e.layer),e.glyph_fields!==void 0){if(!Array.isArray(e.glyph_fields))throw new M("glyph_fields must be an array of column names.");n.glyphFields=e.glyph_fields,n.mapEncodings=e.glyph_fields.map(r=>({field:r,type:"numeric",mode:"magnitude",aggregation:e.glyph_metric||"sum"})),n.mapEncoding=n.mapEncodings[0]||null}if(e.glyph_metric!==void 0&&(n.glyphMetric=e.glyph_metric),e.show_glyph_layer!==void 0&&(n.showGlyphLayer=!!e.show_glyph_layer),e.split_view!==void 0&&(n.splitView=!!e.split_view),e.compare_scenario_id!==void 0){if(!(t.state?.scenarios||[]).some(i=>i.id===e.compare_scenario_id))throw new M(`No scenario with id "${e.compare_scenario_id}".`);n.compareScenarioId=e.compare_scenario_id}if(e.compare_year!==void 0&&(n.compareYear=Number(e.compare_year)),e.timeline_metric!==void 0&&(n.timelineMetric=e.timeline_metric),e.basemap!==void 0&&(n.basemap=e.basemap),!Object.keys(n).length)throw new M("No map settings provided.");return t.actions.setMapConfig(n),JSON.stringify({status:"updated",applied:Object.keys(n)})},create_scenario(e,t){const n=String(e.name||"").trim();if(!n)throw new M("name must not be empty.");return t.actions.createScenario(n,e.description||"",[]),JSON.stringify({status:"created",
297name:n,note:"The new scenario is now active. Its id appears in the next dashboard state."})},switch_scenario(e,t){const n=(t.state?.scenarios||[]).find(r=>r.id===e.scenario_id);if(!n)throw new M(`No scenario with id "${e.scenario_id}". Call get_dashboard_state to list scenarios.`);return t.actions.setActiveScenario(n.id),JSON.stringify({status:"switched",id:n.id,name:n.name})},branch_scenario(e,t){const n=(t.state?.scenarios||[]).find(i=>i.id===e.scenario_id);if(!n)throw new M(`No scenario with id "${e.scenario_id}".`);const r=String(e.name||"").trim();if(!r)throw new M("name must not be empty.");return t.actions.branchScenario(n.id,r,e.change_summary||""),JSON.stringify({status:"branched",from:{id:n.id,name:n.name},name:r,note:"The branch is now active. Its id appears in the next dashboard state."})},delete_scenario(e,t){const n=(t.state?.scenarios||[]).find(r=>r.id===e.scenario_id);if(!n)throw new M(`No scenario with id "${e.scenario_id}".`);if((t.state?.scenarios||[]).length<=1)throw new M("Cannot delete the only scenario.");return t.actions.deleteScenario(n.id),JSON.stringify({status:"deleted",id:n.id,name:n.name})},add_computed_field(e,t){if(!(t.derivedBuildings||[]).length)throw new M("No building data loaded yet.");const n={id:Tn("cfield"),name:String(e.name||"").trim(),expression:String(e.expression||"").trim(),label:e.label?String(e.label):null},{ok:r,errors:i,warnings:a}=Vn(n,{existingColumns:Kr(t),otherDefs:t.activeSession?.computedFields||[]});if(!r)throw new M(i.join(" "));return t.actions.addComputedField(n,Me),JSON.stringify({status:"added",field:{id:n.id,name:n.name,expression:n.expression},sampleValues:Zr(n.expression,t),...a.length?{warnings:a}:{},note:"The column is now usable in filter_buildings, intervention prioritisation columns, and map glyphs."})},update_computed_field(e,t){const n=Gr(t,e.field),r={};if(e.updates?.name!==void 0&&(r.name=String(e.updates.name).trim()),e.updates?.expression!==void 0&&(r.expression=String(e.updates.expression).trim()),e.updates?.label!==void 0&&(r.label=String(e.updates.label)),!Object.keys(r).length)throw new M("No valid fields to update.");const i={...n,...r},{ok:a,errors:o,warnings:l}=Vn(i,{existingColumns:Kr(t),otherDefs:t.activeSession?.computedFields||[]});if(!a)throw new M(o.join(" "));t.actions.updateComputedField(n.id,r,Me);const c={};for(const d of Object.keys(r))c[d]={from:n[d],to:r[d]};return JSON.stringify({status:"updated",id:n.id,changed:c,...r.expression?{sampleValues:Zr(r.expression,t)}:{},...l.length?{warnings:l}:{}})},delete_computed_field(e,t){const n=Gr(t,e.field),r=(t.activeSession?.computedFields||[]).filter(a=>a.id!==n.id).filter(a=>gt(a.expression||"").referencedFields.includes(n.name)).map(a=>a.name),i=(t.activeScenario?.interventions||[]).filter(a=>(a.prioritisation?.columns||[]).some(o=>o.field===n.name)).map(a=>a.label);return t.actions.deleteComputedField(n.id,Me),JSON.stringify({status:"deleted",id:n.id,name:n.name,...r.length?{warning:`Computed field(s) ${r.join(", ")} reference "${n.name}" and will now evaluate to null.`}:{},...i.length?{prioritisationWarning:`Intervention(s) ${i.join(", ")} sort by this column; their prioritisation should be updated.`}:{}})},reorder_intervention(e,t){const n=Xe(t),r=qt(n,e.intervention_id);if(e.direction!=="up"&&e.direction!=="down")throw new M('direction must be "up" or "down".');const i=e.steps===void 0?1:Number(e.steps);if(!Number.isInteger(i)||i<1)throw new M("steps must be a positive integer.");const a=n.interventions||[],o=a.findIndex(p=>p.id===r.id),l=e.direction==="up"?o:a.length-1-o;if(l===0)throw new M(`"${r.label}" is already at the ${e.direction==="up"?"top":"bottom"} of the plan.`);const c=Math.min(i,l);for(let p=0;p<c;p+=1)t.actions.reorderIntervention(n.id,r.id,e.direction,Me);const d=e.direction==="up"?o-c:o+c;return JSON.stringify({status:"reordered",id:r.id,label:r.label,position:{from:o+1,to:d+1,of:a.length},...c<i?{note:`Moved ${c} place(s) â hit the ${e.direction==="up"?"top":"bottom"} of the plan.`}:{}})},set_budget_curve(e,t){const n=Xe(t),r=qt(n,e.intervention_id),{startYear:i,duration:a,budget:o}=r,l=i+a-1,c=e.curve!==void 0,d=e.yearly_budgets!==void 0;if(c===d)throw new M("Provide exactly one of curve or yearly_budgets.");let p;if(c){const u=["linear","log","sqrt","exp","quad","cubic"];if(!u.includes(e.curve))throw new M(`curve must be one of ${u.join(", ")}.`);p=On(o,i,a,e.curve,{},!!e.invert).map(m=>({year:m.year,budget:Math.round(m.budget)}))}else{const u=Array.isArray(e.yearly_budgets)?e.yearly_budgets:[];if(!u.length)throw new M("yearly_budgets must be a non-empty array.");const m=new Map;for(const S of u){const w=Number(S.year),k=Number(S.budget_gbp);if(!Number.isInteger(w)||w<i||w>l)throw new M(`Year ${S.year} is outside the intervention's schedule (${i}-${l}).`);if(m.has(w))throw new M(`Duplicate year ${w} in yearly_budgets.`);
297if(!Number.isFinite(k)||k<0)throw new M(`Budget for ${w} must be a non-negative number.`);m.set(w,k)}const h=[...m.values()].reduce((S,w)=>S+w,0);if(h<=0)throw new M("yearly_budgets must sum to a positive amount.");if(Math.abs(h-o)/o>.01)throw new M(`yearly_budgets sum to £${Math.round(h).toLocaleString("en-GB")} but the intervention budget is £${Math.round(o).toLocaleString("en-GB")}. Change the budget first with update_intervention, or fix the numbers.`);const b=o/h;p=[];for(let S=i;S<=l;S+=1)p.push({year:S,budget:Math.round((m.get(S)||0)*b)})}const f=Math.round(o)-p.reduce((u,m)=>u+m.budget,0);if(f!==0){const u=p.reduce((m,h)=>h.budget>m.budget?h:m);u.budget+=f}return t.actions.updateIntervention(n.id,r.id,{budgetAllocations:p},Me),JSON.stringify({status:"updated",id:r.id,label:r.label,...c?{curve:e.curve,inverted:!!e.invert||void 0}:{},yearlyBudgets:Object.fromEntries(p.map(u=>[u.year,u.budget]))})}};async function dc(e,t,n){const r=cc[e];if(!r)throw new Error(`Unknown tool "${e}".`);return r(t||{},n)}const uc=12,Jr=60;let pc=0;const Et=()=>`msg-${++pc}`;function mc(e,t){const n=[...e],r=n[n.length-1];if(!r||r.role!=="assistant")return n.push({id:Et(),role:"assistant",segments:[{type:"text",text:t}]}),n;const i=[...r.segments],a=i[i.length-1];return a?.type==="text"?i[i.length-1]={...a,text:a.text+t}:i.push({type:"text",text:t}),n[n.length-1]={...r,segments:i},n}function fc(e,t){const n=[...e],r={type:"tool",callId:t.id,name:t.name,input:t.input,status:"running",result:null},i=n[n.length-1];return!i||i.role!=="assistant"?n.push({id:Et(),role:"assistant",segments:[r]}):n[n.length-1]={...i,segments:[...i.segments,r]},n}function zt(e,t,n){return e.map(r=>r.role!=="assistant"||!r.segments.some(i=>i.type==="tool"&&i.callId===t)?r:{...r,segments:r.segments.map(i=>i.type==="tool"&&i.callId===t?{...i,...n}:i)})}function hc(e,t){if(e.length<=Jr)return e;let n=e.length-Math.floor(Jr*.66);for(;n<e.length&&!(t.isPlainUserTurn?.(e[n])??!0);)n+=1;return e.slice(n)}function gc(e){const[t,n]=N.useState([]),[r,i]=N.useState("idle"),[a,o]=N.useState(null),l=N.useRef([]),c=N.useRef(null),d=N.useRef(!1),p=N.useCallback(()=>e.current||{},[e]),f=N.useCallback(()=>{d.current||(l.current=[],n([]),i("idle"),o(null))},[]),u=N.useCallback(()=>{c.current?.abort()},[]),m=N.useCallback(async h=>{const b=String(h||"").trim();if(!b||d.current)return;d.current=!0;const S=ra(),w=$l(S),k=new AbortController;c.current=k;const E=Ol({dataDictionary:Ul(p().derivedBuildings)});l.current=hc(l.current,w),l.current.push(w.formatUserTurn(b,`<dashboard_state> 298${Mi(p())} 299</dashboard_state>`)),n(x=>[...x,{id:Et(),role:"user",text:b}]);try{for(let x=0;x<uc;x++){i("streaming");const _=await w.streamTurn({system:E,tools:ec,messages:l.current,onTextDelta:A=>n(P=>mc(P,A)),signal:k.signal});if(l.current.push(_.assistantMessage),_.stopReason!=="tool_use"||!_.toolCalls.length)break;i("executing");const v=[];for(const A of _.toolCalls){if(n(P=>fc(P,A)),tc.has(A.name)){i("awaiting-confirmation"),n(U=>zt(U,A.id,{status:"awaiting"}));const P=await new Promise(U=>o({toolCall:A,resolve:U}));if(o(null),i("executing"),!P){v.push({id:A.id,content:"The user declined this action."}),n(U=>zt(U,A.id,{status:"denied"}));continue}}try{const P=await dc(A.name,A.input,p());v.push({id:A.id,content:P}),n(U=>zt(U,A.id,{status:"done",result:P}))}catch(P){v.push({id:A.id,content:String(P.message),isError:!0}),n(U=>zt(U,A.id,{status:"error",result:String(P.message)}))}}l.current.push(...w.formatToolResults(v))}i("idle")}catch(x){l.current[l.current.length-1]?.role==="assistant"&&l.current.pop(),x?.code==="aborted"?(n(v=>[...v,{id:Et(),role:"notice",text:"Stopped."}]),i("idle")):(n(v=>[...v,{id:Et(),role:"error",text:x?.message||"Something went wrong."}]),i("error"))}finally{d.current=!1,c.current=null}},[p]);return{transcript:t,status:r,pendingConfirmation:a,sendMessage:m,cancel:u,clearConversation:f}}const yc={},bc=[],Wn=220,qn=560,vc=320,Xr=e=>Math.min(qn,Math.max(Wn,e)),Qr=[{tech:"Insulation",color:"teal",label:"Fabric First Insulation"},{tech:"ASHP",color:"emerald",label:"ASHP Program"},{tech:"PV",color:"amber",label:"Solar PV Expansion"},{tech:"GSHP",color:"indigo",label:"Geothermal Pilot"},{tech:"Hydrogen",color:"rose",label:"Hydrogen Cluster"},{tech:"Mixed",color:"slate",label:"District Integration"}],jn=()=>yc?.VITE_LAEP_DEBUG_SCENARIO==="true",xc=(e,t)=>{const n=Qr[t%Qr.length],r=3+t%4;return{label:`${n.label} ${t+1}`,tech:n.tech,profile:{type:"all"},strategy:"multi-objective",startYear:e,duration:r,budget:4e6+t*12e5,weights:{carbonSavingPotential:.5,fuelPovertyScore:.3,gridCapacityEfficiency:.2},targetEPC:"Any",color:n.color,status:"planned",pluginConfig:{budget:!0,history:!0,carbon:!0,demand:!0}}},Sc=e=>`${e}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`;function wc(e){const t=Number(e||0);return t?t>=1e6?`£${(t/1e6).toFixed(1)}
299M`:`£${Math.round(t).toLocaleString()}`:"£0"}function _c(e={}){const n=[["carbonSavingPotential","carbon"],["fuelPovertyScore","poverty"],["gridCapacityEfficiency","grid"],["cost","cost"]].map(([r,i])=>{const a=Number(e[r]);return!Number.isFinite(a)||a<=0?null:`${i} ${Math.round(a*100)}%`}).filter(Boolean);return n.length?n.join(", "):"Default balanced weighting"}function Nc({facet:e,uprns:t,selectedIntervention:n}){const r=t?.length??0,i=n?.label||n?.tech||"Selection",a=e?.getColumnNames?.()||[],o=p=>{if(!e?.getRowCount||!e?.getRow||!a.includes(p))return null;const f=e.getRowCount();if(!f)return null;const u=e.getRow(0)?.[p];for(let m=1;m<f;m++)if(e.getRow(m)?.[p]!==u)return null;return u},l=o("area"),c=o("epc")||o("epcRating"),d=[i];return l&&d.push(String(l)),c&&d.push(`EPC-${String(c)}`),d.push(`${r} bldgs`),d.join(" | ")}const Cc=()=>{const{state:e,dataMode:t,activeScenario:n,activeSession:r,selectedIntervention:i,editingIntervention:a,actions:o}=wi(),[l,c]=N.useState(!1),[d,p]=N.useState(!1),[f,u]=N.useState(null),[m,h]=N.useState("all"),[b,S]=N.useState(""),[w,k]=N.useState(null),[E,x]=N.useState(()=>new Set),_=e.ui.selectionState?.selectedUprns,{buildings:v,facet:A,isLoading:P,parquetCounts:U}=Rs(),$=r?.computedFields??bc,B=N.useMemo(()=>_l(v,$),[v,$]),X=N.useMemo(()=>B===v?A:Xt(B),[B,v,A]),[pe,R]=N.useState(!1),[C,T]=N.useState(vc),H=y=>{y.preventDefault();const I=y.clientX,j=C,J=document.body.style.cursor,te=document.body.style.userSelect;document.body.style.cursor="col-resize",document.body.style.userSelect="none";const Pt=fn=>{T(Xr(j+fn.clientX-I))},vt=()=>{document.body.style.cursor=J,document.body.style.userSelect=te,window.removeEventListener("pointermove",Pt),window.removeEventListener("pointerup",vt)};window.addEventListener("pointermove",Pt),window.addEventListener("pointerup",vt)},W=y=>{if(!["ArrowLeft","ArrowRight","Home","End"].includes(y.key))return;if(y.preventDefault(),y.key==="Home"){T(Wn);return}if(y.key==="End"){T(qn);return}const I=y.shiftKey?40:20;T(j=>Xr(j+(y.key==="ArrowRight"?I:-I)))},z=n?.profiles??[],{runSimulation:K}=wr(X,z),Pe=Ko(n?.interventions??[],e.ui.currentYear,e.ui.simulationOutput),{saveSessionToBackend:Ke}=Zo(),Q=N.useMemo(()=>e.scenarios.find(y=>y.id===e.ui.mapConfig.compareScenarioId),[e.scenarios,e.ui.mapConfig.compareScenarioId]),Ae=Array.isArray(Q?.results?.finalBuildings),de=N.useMemo(()=>e.scenarios.filter(y=>y.sessionId===e.activeSessionId),[e.scenarios,e.activeSessionId]),G=N.useMemo(()=>{if(!n)return[];const y=n.lineageRootProvenanceId||n.provenanceId;return de.filter(j=>(j.lineageRootProvenanceId||j.provenanceId)===y||j.provenanceId===y).sort((j,J)=>{const te=String(j.branchName||j.name).localeCompare(String(J.branchName||J.name));return te!==0?te:Number(j.versionNumber||1)-Number(J.versionNumber||1)})},[n,de]),Z=N.useMemo(()=>{if(!n)return[];const y=new Set(G.map(j=>j.provenanceId).filter(Boolean)),I=new Set(G.map(j=>j.id).filter(Boolean));return n.provenanceId&&y.add(n.provenanceId),n.id&&I.add(n.id),(e.provenanceEvents||[]).filter(j=>{const J=[j.scenarioProvenanceId,...(j.used||[]).map(te=>te?.provenanceId),...(j.generated||[]).map(te=>te?.provenanceId)].filter(Boolean);return I.has(j.scenarioId)||J.some(te=>y.has(te))||j.entityType==="session"&&j.sessionId===n.sessionId||j.entityType==="computed-field"&&j.sessionId===n.sessionId}).sort((j,J)=>String(J.timestamp||"").localeCompare(String(j.timestamp||"")))},[G,n,e.provenanceEvents]),ue=N.useMemo(()=>Cr(Z,G,n),[G,n,Z]),De=N.useMemo(()=>Cr(Z,G,n,{filter:m,query:b}),[G,n,Z,m,b]),Ne=N.useMemo(()=>Vs(ue),[ue]),xe=N.useMemo(()=>w&&G.some(I=>I.provenanceId===w||I.id===w)?w:null,[G,w]),V=N.useMemo(()=>{if(!xe)return De;const y=G.find(I=>I.provenanceId===xe||I.id===xe);return De.filter(I=>I.scenarioLinked!==!1&&(I.scenarioProvenanceId===xe||y&&I.scenarioId===y.id))},[xe,G,De]),ee=N.useMemo(()=>Hs(V),[V]),oe=N.useCallback(y=>{x(I=>{const j=new Set(I);return j.has(y)?j.delete(y):j.add(y),j})},[]),ne=N.useCallback(y=>{V.some(j=>j.id===y.id)||(h("all"),S(""),k(null)),x(j=>new Set(j).add(y.id)),requestAnimationFrame(()=>{document.getElementById(`history-episode-${y.id}`)?.scrollIntoView({behavior:"smooth",block:"center"})})},[V]),ae=e.ui.workflow||{},re=N.useMemo(()=>(e.provenanceEvents||[]).filter(y=>y.activity==="simulation.ran"&&y.scenarioId===n?.id).sort((y,I)=>String(I.timestamp||"").localeCompare(String(y.timestamp||"")))[0]||null,[n?.id,e.provenanceEvents]),be=N.useMemo(()=>(e.provenanceEvents||[]).filter(y=>["scenario.saved","scenario.exported"].includes(y.activity)&&(!n||y.scenarioId===n.id||y.scenarioProvenanceId===n.provenanceId)).sort((y,I)=>String(I.timestamp||"").localeCompare(String(y.timestamp||"")))[0]||null,[n,e.provenanceEvents]),{runSimulation:F}=wr(X,Q?.profiles??[]),L=N.useMemo(()=>{const y=i?.profile;return!y||y.type===Ge?B:Si(y,B,z,_??[])},[B,i?.profile,z,_]),me=N.useMemo(()=>{const y=v[0];if(!y)return[];const I=[];for(const[j,J]of Object.entries(y))if(en.test(j)&&!Array.isArray(J)){if(J!==null&&typeof J=="object"){for(const te of Ob
299ject.keys(J))en.test(te)&&I.push(`${j}.${te}`);continue}I.push(j)}return I.sort((j,J)=>j.localeCompare(J))},[v]),Fe=N.useMemo(()=>[...$.map(y=>({id:y.name,group:"Computed fields"})),...me.map(y=>({id:y,group:"Building attributes"}))],[$,me]),yt=N.useMemo(()=>{const y=_?.length||0,I=e.ui.mapConfig.morphBoundary&&e.ui.mapConfig.morphBoundary!=="none"?e.ui.mapConfig.morphBoundary.toUpperCase():null,j=ae.tableFilterSummary||{},J=Number(j.visibleRows),te=Number(j.totalRows),Pt=Number.isFinite(J)&&Number.isFinite(te)&&te>0&&J<te,vt=Array.isArray(j.operations)&&j.operations.length?j.operations[j.operations.length-1]:null,fn=(n?.profiles||[]).length>0,hn=(n?.interventions||[]).length>0,He=i||n?.interventions?.[0]||null,xt=!!e.ui.simulationOutput,rr=!!be||e.persistence?.dirty===!1,Li={area:y?`${y.toLocaleString()} buildings selected`:I?`${I} geography in view`:P?"Loading Winchester stock":"Full Winchester stock",buildings:Pt?`${J.toLocaleString()} of ${te.toLocaleString()} rows visible${vt?` · ${vt}`:""}`:y?`${y.toLocaleString()} selected buildings`:fn?`${n.profiles.length} saved profile${n.profiles.length===1?"":"s"}`:"All buildings in scope",intervention:He?`${He.label||He.tech||"Intervention"} · ${He.tech||"tech"} · ${wc(He.budget)}`:"No intervention configured yet",priority:He?`${He.strategy||"multi-objective"} · ${_c(He.weights)}`:"Add an intervention to set priorities",simulation:e.ui.simulationStatus==="running"?"Simulation running":e.ui.simulationStatus==="stale"?xt?"Scenario changed since last run":"Ready to run":xt?`Last run ${re?.timestamp?new Date(re.timestamp).toLocaleString():"available"}`:hn?"Ready to run":"Add an intervention first",results:xt?e.ui.mapConfig.splitView&&Q?`Comparing with ${Q.name}`:"Scenario outputs available":"Run simulation to inspect outputs",saved:e.persistence?.dirty?"Unsaved changes":be?.timestamp?`Saved ${new Date(be.timestamp).toLocaleString()}`:rr?"Clean local state":"Not saved yet"},Di={area:!P&&v.length>0,buildings:!P&&v.length>0,intervention:hn,priority:hn,simulation:xt&&e.ui.simulationStatus!=="stale",results:xt&&e.ui.simulationStatus!=="stale",saved:rr};return Go.map(gn=>({...gn,summary:Li[gn.id],status:Di[gn.id]?"complete":"pending"}))},[n,v.length,Q,P,be,re,i,_,e.persistence?.dirty,e.ui.mapConfig.morphBoundary,e.ui.mapConfig.splitView,e.ui.simulationOutput,e.ui.simulationStatus,ae.tableFilterSummary]),dn=N.useMemo(()=>Qs({activeScenario:n,selectedIntervention:i,selectedUprns:_,tableFilterSummary:ae.tableFilterSummary,simulationOutput:e.ui.simulationOutput,allScenarios:de,mapConfig:e.ui.mapConfig,provenanceEvents:e.provenanceEvents,currentYear:e.ui.currentYear,dataMode:t,buildingCounts:{displayed:L.length,total:v.length,parquetTotal:U?.total}}),[n,v.length,t,L.length,U?.total,de,i,_,e.provenanceEvents,e.ui.currentYear,e.ui.mapConfig,e.ui.simulationOutput,ae.tableFilterSummary]);N.useEffect(()=>{if(!f)return;const y=window.setTimeout(()=>u(null),3800);return()=>window.clearTimeout(y)},[f]);const Tt=N.useCallback(y=>{if(o.setWorkflowStage(y),u(y),["define-intervention","set-priority"].includes(y)){const I=i?.id||n?.interventions?.[0]?.id;I&&(o.setEditingIntervention(I),o.setSelectedIntervention(I))}y==="refine-buildings"&&o.setBuildingTableTab("raw",{preserveSelection:!0}
299),y==="inspect-results"&&e.ui.simulationOutput&&(o.setBuildingTableTab("results",{preserveSelection:!0}),o.setWorkspaceTab("table")),y==="save-scenario"&&o.setWorkspaceTab("explain"),y==="review-timeline"&&o.setWorkspaceTab("table")},[o,n?.interventions,i?.id,e.ui.simulationOutput]),un=y=>{o.createScenario(y,"",[])},pn=async y=>{if(y)try{y.source==="remote"&&await(await ge(()=>import("./api-CVce_W2q.js"),__vite__mapDeps([18,19,20,7]))).deleteScenario(y.id),o.deleteScenario(y.id)}catch(I){console.error("Failed to delete scenario:",I)}},jt=y=>{if(!n)return;const I=xc(e.ui.currentYear,n.interventions.length),j=y?{...I,...y}:I;o.addIntervention(n.id,j)},mn=N.useCallback(({uprns:y,facet:I})=>{if(!n||!y?.length)return;const j=Sc("profile"),J=Nc({facet:I,uprns:y,selectedIntervention:i});o.addProfile(n.id,{id:j,name:J,uprns:y},{source:"building-table",uiContext:{surface:"building-table",selectionCount:y.length}}),o.setSelection(y),i?.id&&o.updateIntervention(n.id,i.id,{profile:{type:rt,profileId:j}},{source:"building-table",uiContext:{surface:"building-table",selectionCount:y.length}})},[n,o,i]),q=N.useCallback(y=>{o.setSelection(y)},[o]),fe=N.useCallback(({uprns:y})=>{o.setSelection(y?.length?y:null)},[o]),he=N.useCallback(()=>{o.setSelection(null)},[o]),Te=N.useCallback((y,I={})=>D({activity:y,session:r,scenario:n,entityType:"scenario",entityId:n?.id,payload:{scenarioName:n?.name,...I}}),[n,r]),Ze=async()=>{if(!n)return;const y=Te("scenario.saved",{storageMode:e.persistence?.storageMode||"browser-local",checkpoint:!0}),I=await qe();try{yi({...e,provenanceEvents:[...e.provenanceEvents||[],y]}),o.recordProvenanceEvent(y),o.setPersistenceStatus({lastSavedAt:y.timestamp,dirty:!1,error:null}),I.fire({title:"Checkpoint Saved",text:"This scenario state was recorded in the decision trail.",icon:"success",toast:!0,position:"top-end",timer:2500,showConfirmButton:!1})}catch(j){o.setPersistenceStatus({error:j.message,dirty:!0}),I.fire({title:"Checkpoint Failed",text:j.message,icon:"error"})}},Be=async()=>{const y=await qe(),I=Jn({loadedBy:"dashboard-control"});o.hydrateFromBundle(I,{activity:"scenario.loaded",payload:{source:"local-demo",scenarioCount:I.scenarios.length},dirty:!1}),o.setSimulationStatus("idle"),y.fire({title:"Demo Scenarios Loaded",text:"Local demo pathways, versions, branches, and provenance history were restored.",icon:"success",toast:!0,position:"top-end",timer:3e3,showConfirmButton:!1})},Ue=async()=>{if(!r)return;const y=Te("scenario.exported",{scenarioCount:de.length}),I=mi({...e,provenanceEvents:[...e.provenanceEvents||[],y]}),j=new Date().toISOString().slice(0,10);Ma(I,`laep-scenarios-${j}.json`),o.recordProvenanceEvent(y)},Re=async y=>{if(!y)return;const I=await qe();try{const j=await Oa(y);o.hydrateFromBundle(j,{activity:"scenario.imported",payload:{fileName:y.name,scenarioCount:j.scenarios.length}}),I.fire({title:"Imported",text:"Scenario bundle imported.",icon:"success",toast:!0,position:"top-end",timer:2500,showConfirmButton:!1})}catch(j){I.fire({title:"Import Failed",text:j.message,icon:"error"})}},Se=async()=>{if(n){jn()&&console.log("[Scenario] handleSimulate called",{scenarioName:n?.name,interventionCount:n?.interventions?.length??0,currentYear:e.ui.currentYear,hasFacet:!!X}),o.setSimulationStatus("running");try{const y=await K(n.interventions,e.ui.currentYear,_??[]);jn()&&console.log("[Scenario] runSimulation returned",{ranAt:y?.ranAt,yearlyKeys:y?.yearly?Object.keys(y.yearly):[],interventionSummaryKeys:y?.interventionSummary?Object.keys(y.interventionSummary):[],finalBuildingsCount:y?.finalBuildings?.length??0,rawResultsCount:y?.rawResults?.length??0});const I=D({activity:"simulation.ran",session:r,scenario:n,entityType:"simulation",entityId:y?.ranAt||n?.id,generated:[{type:"simulation-result",id:y?.ranAt||n?.id}],payload:{currentYear:e.ui.currentYear,interventionCount:n?.interventions?.length??0,results:kt(y)}});return o.setSimulationOutput(y,I),o.setSimulationStatus("ready"),r&&n&&e.persistence?.storageMode==="supabase"&&await Ke({session:r,scenario:n,provenanceEvents:[...e.provenanceEvents||[],I]}),y}catch(y){return console.error("[Scenario] handleSimulate error",y),o.setSimulationStatus("error",y.message),null}}},it=N.useRef(null);it.current={state:e,actions:o,dataMode:t,activeScenario:n,activeSession:r,selectedIntervention:i,derivedBuildings:B,scenarioProfiles:z,prioritisationColumns:Fe,selectedUprns:_??[],runSimulation:Se};const bt=gc(it);N.useEffect(()=>{const y=n?.interventions?.length>0,I=!e.ui.simulationOutput&&e.ui.simulationStatus==="idle";n&&y&&!P&&X&&I&&Se()},[n,X,P,e.ui.simulationOutput,e.ui.simulationStatus,t,Se]),N.useEffect(()=>{e.ui.mapConfig.splitView&&Q&&Q.interventions?.length>0&&!P&&X&&!Ae&&(async()=>{try{const y=e.ui.mapConfig.compareYear||e.ui.currentYear,I=await F(Q.interventions,y,_??[]);
299o.setScenarioResults(Q.id,I),jn()&&console.log("[Scenario Comparison] Auto-simulated compared scenario",Q.id)}catch(y){console.error("[Scenario Comparison] error",y)}})()},[e.ui.mapConfig.splitView,Q,Ae,P,X,e.ui.mapConfig.compareYear,e.ui.currentYear,_,F,o]),N.useEffect(()=>{const y=I=>{try{const j=Array.isArray(I?.detail?.fields)?I.detail.fields:[],J=Array.isArray(I?.detail?.encodings)?I.detail.encodings:[],te=I?.detail?.glyphMetric==="mean"?"mean":"sum";o.setMapConfig({glyphFields:j,glyphMetric:te,glyphMode:I?.detail?.glyphMode||e.ui.mapConfig.glyphMode,showGlyphLayer:I?.detail?.showGlyphLayer??e.ui.mapConfig.showGlyphLayer,mapEncodings:J,mapEncoding:J[0]||null})}catch{}};return window.addEventListener("laep:table:visualize",y),()=>window.removeEventListener("laep:table:visualize",y)},[o,e.ui.mapConfig.glyphMode,e.ui.mapConfig.showGlyphLayer]);const Oi=N.useCallback(({uprns:y})=>{if(!l){if(!y?.length){o.setSelection(null);return}o.setSelection(y)}},[o,l]);return s.jsxs("div",{className:"min-h-dvh xl:h-dvh bg-[var(--laep-surface-page)] text-[var(--laep-text)] font-sans p-3 flex flex-col overflow-y-auto xl:overflow-hidden",children:[s.jsxs("div",{className:"grid grid-cols-12 gap-3 flex-1 min-h-0 xl:grid-cols-[var(--rail-width)_8px_minmax(0,1fr)] xl:gap-x-0 xl:overflow-hidden",style:{"--rail-width":`${C}px`},children:[s.jsx("div",{className:"col-span-12 min-h-[320px] xl:col-span-1 xl:min-h-0 xl:overflow-hidden",children:s.jsx($o,{sessions:e.sessions,scenarios:e.scenarios,activeSessionId:e.activeSessionId,activeScenarioId:e.activeScenarioId,onSetActiveSession:o.setActiveSession,onSetActiveScenario:o.setActiveScenario,onCreateSession:y=>o.createSession(y),onCreateScenario:un,onCreateScenarioVersion:o.createScenarioVersion,onBranchScenario:o.branchScenario,onDeleteScenario:pn,onRenameScenario:(y,I)=>o.updateScenario(y,{name:I}),selectedItem:a,selectedAnalysisItem:i,onEditSelectedIntervention:()=>{i?.id&&o.setEditingIntervention(i.id)},onStartNewIntervention:()=>{o.setEditingIntervention(null),o.setSelectedIntervention(null)},onDeselectIntervention:()=>o.setEditingIntervention(null),onUpdateIntervention:(y,I)=>o.updateIntervention(n.id,y,I,{source:"configuration",uiContext:{surface:"configuration-panel"}}),onDeleteIntervention:y=>o.deleteIntervention(n.id,y),interventionCount:n?.interventions.length??0,onAddIntervention:y=>jt(y),scenarioProfiles:n?.profiles??[],selectedUprns:_??[],prioritisationColumns:Fe,onRunSimulation:Se,isDataLoading:P,simulationStatus:e.ui.simulationStatus,hasSimulationOutput:!!e.ui.simulationOutput,hasActiveScenario:!!n,onLoadDemoScenarios:Be,onSaveCheckpoint:Ze,onExportScenarios:Ue,onImportScenarios:Re,isDirty:!!e.persistence?.dirty,lastSavedAt:e.persistence?.lastSavedAt||null,workflowFocusStageId:f,readinessItems:yt,onWorkflowStageSelect:Tt,assistant:bt})}),s.jsx("div",{role:"separator","aria-label":"Resize scenario rail","aria-orientation":"vertical","aria-valuemin":Wn,"aria-valuemax":qn,"aria-valuenow":Math.round(C),"aria-valuetext":`${Math.round(C)} pixel scenario rail width`,tabIndex:0,onPointerDown:H,onKeyDown:W,className:"hidden min-h-0 cursor-col-resize items-stretch justify-center rounded transition-colors hover:bg-[var(--laep-surface-muted)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)] xl:flex",children:s.jsx("span",{className:"my-2 w-px rounded bg-[var(--laep-border-strong)]"})}),s.jsx("div",{className:"col-span-12 min-h-[760px] xl:col-span-1 xl:min-h-0 xl:overflow-hidden",children:n?s.jsx(zo,{interventions:n.interventions,selectedIntervention:i,selectedInterventionId:e.ui.selectedInterventionId,currentYear:e.ui.currentYear,simulation:Pe,simulationOutput:e.ui.simulationOutput,activeScenarioId:n.id,buildingStock:L,tableBuildingStock:B,onOpenFieldCalculator:()=>R(!0),isDataLoading:P,parquetCounts:U,dataMode:t,buildingTableTab:e.ui.buildingTableTab,onBuildingTableTabChange:o.setBuildingTableTab,activeWorkspaceTab:e.ui.activeWorkspaceTab,mapConfig:e.ui.mapConfig,tableConfig:e.ui.tableConfig,allScenarios:de,selectedUprns:_,isMapSelectionMode:l,workflowFocusStageId:f,readinessItems:yt,decisionTrailEvents:Z,decisionTrailLineage:G,activeScenario:n,compareScenario:Q,onScenarioSelect:o.setActiveScenario,onWorkflowStageSelect:Tt,onSelectIntervention:o.setSelectedIntervention,onEditIntervention:o.setEditingIntervention,onUpdateIntervention:(y,I)=>o.updateIntervention(n.id,y,I,{source:"timeline",uiContext:{surface:"timeline"}}),onDeleteIntervention:y=>o.deleteIntervention(n.id,y),onCurrentYearChange:o.setCurrentYear,onWorkspaceTabChange:o.setWorkspaceTab,onAddIntervention:y=>jt(y),onMoveSelectedIntervention:y=>{e.ui.selectedInterventionId&&o.reorderIntervention(n.id,e.ui.selectedInterventionId,y)},onMapConfigChange:o.setMapConfig,onTableConfigChange:o.setTableConfig,onSaveFacetAsProfile:n?mn:void 0,onBuildingSelectionChange:q,onFacetSummaryChange:o.setWorkflowTableFilterSummary,onCellClick:Oi,onRectangleSelect:fe,onClearSelection:he,onToggleMapSelectionMode:()=>c(y=>!y),onOpenDecisionHistory:()=>p(!0),scenarioExplanation:dn}):s.jsx("div",{className:"h-full flex items-center justify-center",children:s.jsxs("div",{className:"bg-[var(--laep-surface-panel)] border border-[var(--laep-border-subtle)] rounded-lg p-6 w-full max-w-md text-center shadow-sm",children:[s.jsx("h2",{className:"text-lg font-semibold text-[var(--laep-text)] mb-2",children:"LAEP Strategy Dashboard"}),s.jsx("p",{className:"text-sm text-[var(--laep-text-muted)] mb-4",children:"Select a scenario from the left rail or create a new one to begin."}),s.jsxs("div",{className:"flex items-center justify-center gap-3",children:[s.jsx("button",{type:"button",onClick:()=>o.createScenario("Default Scenario","Auto-generated",[]),className:"px-4 py-2 bg-[var(--laep-action)] text-[var(--laep-action-contrast)] rounded-md hover:bg-[var(--laep-action-hover)] text-sm font-semibold shadow-sm focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:"Qu
299ick Start"}),s.jsx("button",{type:"button",onClick:()=>o.createScenario("Blank Scenario","User created",[]),className:"px-3 py-2 bg-[var(--laep-surface-panel)] border border-[var(--laep-border-subtle)] rounded-md text-sm text-[var(--laep-text-muted)] hover:bg-[var(--laep-surface-muted)] hover:text-[var(--laep-text)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:"Create Scenario"})]})]})})})]}),d&&s.jsx("div",{className:"fixed inset-0 z-[60] bg-slate-950/40 flex items-center justify-center p-4",children:s.jsxs("div",{role:"dialog","aria-modal":"true","aria-labelledby":"decision-history-title","aria-describedby":"decision-history-description",className:"w-full max-w-5xl max-h-[86vh] bg-[var(--laep-surface-panel)] rounded-lg shadow-xl border border-[var(--laep-border-subtle)] flex flex-col",children:[s.jsxs("div",{className:"flex items-start justify-between gap-3 px-4 py-3 border-b border-[var(--laep-border-subtle)]",children:[s.jsxs("div",{className:"min-w-0",children:[s.jsx("h2",{id:"decision-history-title",className:"text-sm font-semibold text-[var(--laep-text)]",children:"Decision History"}),s.jsx("p",{id:"decision-history-description",className:"text-xs text-[var(--laep-text-muted)] truncate max-w-lg",children:n?`${Ne.total} decision${Ne.total===1?"":"s"} across ${G.length||1} pathway${(G.length||1)===1?"":"s"} of ${n.name}`:"No scenario selected"})]}),s.jsx("button",{type:"button",onClick:()=>p(!1),"aria-label":"Close decision trail history",className:"px-2 py-1 text-sm text-[var(--laep-text-muted)] hover:text-[var(--laep-text)] hover:bg-[var(--laep-surface-muted)] rounded focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]",children:"Close"})]}),s.jsxs("div",{className:"border-b border-[var(--laep-border-subtle)] px-4 py-3",children:[s.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[s.jsx("label",{htmlFor:"decision-history-search",className:"sr-only",children:"Search decision history"}),s.jsx("input",{id:"decision-history-search",type:"search",value:b,onChange:y=>S(y.target.value),placeholder:"Search decisions, changes, activities...",className:"min-w-[200px] flex-1 rounded-md border border-[var(--laep-border-subtle)] bg-[var(--laep-surface-raised)] px-3 py-2 text-sm text-[var(--laep-text)] focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)]"}),s.jsx("div",{className:"flex gap-1 overflow-x-auto pb-1",role:"tablist","aria-label":"Decision history filters",children:$s.map(y=>{const I=y.id==="all"?Ne.total:Ne[y.id]||0,j=m===y.id;return s.jsxs("button",{type:"button",role:"tab","aria-selected":j,onClick:()=>h(y.id),className:`shrink-0 rounded-md border px-2 py-1 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-[var(--laep-focus)] ${j?"border-[var(--laep-action)] bg-[var(--laep-action)] text-[var(--laep-action-contrast)]":"border-[var(--laep-border-subtle)] bg-[var(--laep-surface-raised)] text-[var(--laep-text-muted)] hover:bg-[var(--laep-surface-muted)] hover:text-[var(--laep-text)]"}`,children:[y.label," ",I?`(${I})`:""]},y.id)})})]}),G.length>0&&s.jsx("div",{className:"mt-3",children:s.jsx(dl,{episodes:ue,lineage:G,activeScenarioId:n?.id||null,selectedKey:xe,onSelectLane:k,onSelectEpisode:ne})})]}),s.jsx("div",{className:"overflow-auto px-4 pb-4",children:ee.length?ee.map(y=>s.jsxs("section",{"aria-label":`Decisions on ${y.label}`,children:[s.jsxs("div",{className:"sticky top-0 z-10 -mx-1 flex items-baseline gap-2 bg-[var(--laep-surface-panel)] px-1 pb-2 pt-4",children:[s.jsx("h3",{className:"text-xs font-bold uppercase tracking-wide text-[var(--laep-text)]",children:y.label}),s.jsxs("span",{className:"text-[10px] text-[var(--laep-text-muted)]",children:[y.episodes.length," decision",y.episodes.length===1?"":"s"]}),s.jsx("span",{"aria-hidden":"true",className:"h-px flex-1 self-center bg-[var(--laep-border-subtle)]"})]}),s.jsx("div",{className:"ml-1.5 space-y-2 border-l-2 border-[var(--laep-border-subtle)] pb-2 pl-4",children:y.episodes.map(I=>s.jsxs("div",{id:`history-episode-${I.id}`,className:"relative",children:[s.jsx("span",{"aria-hidden":"true",className:"absolute -left-[23px] top-3 h-2.5 w-2.5 rounded-full border-2 border-[var(--laep-surface-panel)] bg-[var(--laep-text-soft)]"}),s.jsx(rl,{episode:I,expanded:E.has(I.id),onToggle:()=>
299oe(I.id),relaxed:!0})]},I.id))})]},y.key)):s.jsx("div",{role:"status",className:"mt-4 text-sm text-[var(--laep-text-muted)] bg-[var(--laep-surface-raised)] border border-[var(--laep-border-subtle)] rounded-md p-4",children:"No decisions match the current history filter."})})]})}),pe&&s.jsx(El,{computedFields:$,availableColumns:me,sampleRows:B.slice(0,200),onAdd:y=>o.addComputedField(y),onUpdate:(y,I)=>o.updateComputedField(y,I),onDelete:y=>o.deleteComputedField(y),onClose:()=>R(!1)})]})},Ic=()=>s.jsx(Fa,{children:s.jsx(Cc,{})});typeof window<"u"&&!window.__publicField&&(window.__publicField=(e,t,n)=>(t in e?Object.defineProperty(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,n));oa();Fi.createRoot(document.getElementById("root")).render(ze.createElement(ze.StrictMode,null,ze.createElement(Ic,null)));export{ta as A,no as B,za as C,na as D,ke as E,Qa as F,io as H,pt as I,ao as L,ea as P,Go as R,go as S,Oc as T,Mn as X,ge as _,Jt as a,fo as b,Y as c,so as d,Za as e,co as f,$l as g,Es as h,sa as i,Rc as j,Pc as k,ra as l,$c as m,ai as n,qe as o,Mo as p,ye as q,Cr as r,jc as s,Vs as t,Ko as u,$s as v,rl as w,lo as x,ho as y,Mc as z};
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.