1const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/papaparse.min-CoL0ml_G.js","assets/index-CUS1_xmJ.js"])))=>i.map(i=>d[i]); 2import{N as b,Q as y,T as N,G as ee,z as F,r as _,j as e,s as Ee,t as E,ar as Oe,L as Fe,U as Ge}from"./index-CUS1_xmJ.js";import{u as j}from"./useServerFn-X5sYOSZ0.js";import{T as ze,a as Ve,b as z,c as V}from"./tabs-Bku-gK2s.js";import{B as R}from"./button-kobz9rSE.js";import{L as O}from"./loader-circle-0g1Y8Blc.js";import{D as He}from"./download-DMg7-hyG.js";import{P as Be}from"./progress-CULLvCVh.js";import{U as be}from"./upload-oByUpbLS.js";import{R as We,S as Qe,m as Xe,X as Je,Y as Ye,T as Ze,o as et,n as tt}from"./ScatterChart-XkJ0Kg46.js";import{u as De}from"./useMutation-Ll_AvINT.js";import{R as st}from"./refresh-cw-B8t3rPDQ.js";import{I as ye}from"./input-HR6gKWrA.js";import{B as X}from"./badge-tcRnBQx0.js";import{R as at}from"./RealityCheckBand-Z_DJAv_9.js";import{L as rt,W as Se,R as nt}from"./Run3BenchmarkPanel-DZ7Erl6_.js";import{a as lt}from"./pilot-data.functions-O_bPZePJ.js";import{G as it}from"./gauge-NU0jiLkZ.js";import{T as ct}from"./triangle-alert-CBH320fe.js";import"./index-DEtgLWO2.js";import"./index-7jse-r6P.js";import"./index-D8YOBGSM.js";import"./index-D5MywICZ.js";import"./index-BK_v6nvB.js";import"./index-DIQejLkY.js";import"./utils-BQHNewu7.js";import"./index-BnuaxMs4.js";import"./index-LHNt3CwB.js";import"./index-Dr0ff3Jh.js";const ot=b({method:"GET"}).middleware([y]).handler(N("3ebe3d638f454373c8de69dfaf8e141e98e31787fb7f9e31950356e617935477")),dt=b({method:"POST"}).middleware([y]).handler(N("288b100cdaf169d880dba13769c026e5bce61cd16e76c05a491be2947be5979a")),mt=b({method:"POST"}).middleware([y]).handler(N("d02130750650cd019f365309d18efaee255d3346bf00958f464e9fb376eec985")),ut=b({method:"POST"}).middleware([y]).handler(N("9d674f4f997e03bd393a58b06776d267271da9cd019c52baca0a17b2e6f1206c")),ht=b({method:"POST"}).middleware([y]).handler(N("5a2f776c8cfea9a40150316b1e96a16db41ae748a5d374525de578dc2bd48293")),xt=b({method:"POST"}).middleware([y]).handler(N("0acd6018ed126b3ab0f53e66bdd068d7dbfc40b1c89c405d37036efee3cfa6c0")),pt=b({method:"POST"}).middleware([y]).handler(N("c737c1a8ab71c4a1ba12f2b76079089efde25ac2c54117018c062a68035fc044")),ft=b({method:"POST"}).middleware([y]).handler(N("1da63b5a22a3632c9315eaea430a4473fedfee717f125c7b277e24b670c57d14")),gt=b({method:"POST"}).middleware([y]).handler(N("cde1765a13273cd0037fac342ed9ac6a15f3043342dfe3b4e4751038c00972d4")),jt=b({method:"POST"}).middleware([y]).handler(N("f30c3c67bdc9917d31da0b962a94722bdfad81be631a65dff077efe1346b6649")),te=t=>typeof t=="number"?`${(t*100).toFixed(1)}%`:"â",fe=t=>typeof t=="number"?t.toFixed(1):"â";function bt(){const t=ee(),s=j(ft),i=j(jt),o=j(gt),r=F({queryKey:["ld-validation-log"],queryFn:()=>s()}),[a,c]=_.useState(null),[d,m]=_.useState(null),h=async u=>{c(u);try{const{markdown:x}=await i({data:{version:u}}),f=URL.createObjectURL(new Blob([x],{type:"text/markdown"})),w=document.createElement("a");w.href=f,w.download=`demand-lens-model-card-${u}.md`,w.click(),URL.revokeObjectURL(f)}finally{c(null)}},l=async u=>{if(window.confirm("Unseal the holdout? This can only ever be done once; the holdout is then spent.")){m(null),c(u);try{await o({data:{id:u,confirm:!0}}),await t.invalidateQueries({queryKey:["ld-validation-log"]})}catch(x){m(x.message)}finally{c(null)}}};return e.jsxs("section",{className:"space-y-3 rounded-lg border border-border p-4",children:[e.jsxs("div",{className:"flex items-baseline justify-between",children:[e.jsx("h3",{className:"font-semibold",children:"Validation log"}),r.data&&e.jsxs("span",{className:"text-xs text-muted-foreground",children:["Sealed holdout: ",r.data.holdout.groups," site groups · ",r.data.holdout.spent?"spent (never re-use)":"sealed"]})]}),d&&e.jsx("p",{className:"text-xs text-destructive",children:d}),r.isLoading?e.jsx(O,{className:"h-4 w-4 animate-spin"}):(r.data?.entries??[]).map(u=>e.jsxs("div",{className:"space-y-1 border-t border-border pt-2 text-xs",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"font-medium",children:[u.version," ",u.is_active&&e.jsx("span",{className:"ml-1 rounded bg-primary px-1.5 py-0.5 text-primary-foreground",children:"active"})]}),e.jsxs(R,{size:"sm",variant:"outline",disabled:a===u.version,onClick:()=>h(u.version),children:[e.jsx(He,{className:"mr-1 h-3 w-3"}),"Model card"]})]}),e.jsx("p",{className:"text-muted-foreground",children:u.notes??"â"}),e.jsxs("p",{children:["Tested: ",u.runs.length?u.runs.map(x=>`${x.mode}${x.scope?` (${x.scope})`:""}`).join(", "):"no back-test runs"," · analyst-cohort correction ",u.analyst_correction?"on":"off"]}),u.correction_oof&&e.jsxs("p",{children:["Auto OOF: MAE ",fe(u.correction_oof.mae)," · coverage ",te(u.correction_oof.coverage)," · width ",te(u.correction_oof.median_width_pct)]}),u.consultant_oof&&e.jsxs("p",{children:["Consultant OOF: MAE ",fe(u.consultant_oof.mae)," · coverage ",te(u.consultant_oof.coverage)," · width ",te(u.consultant_oof.median_width_pct)]}),u.registry.map(x=>e.jsxs("div",{className:"rounded bg-muted p-2",children:[e.jsxs("p",{children:["Pre-registered ",new Date(x.created_at).toLocaleStr
2ing()," · status ",e.jsx("b",{children:x.status})," · predictions ",x.predictions_hash?"locked":"not locked"]}),x.result?.checks?e.jsx("table",{className:"mt-1 w-full",children:e.jsx("tbody",{children:x.result.checks.map(f=>e.jsxs("tr",{children:[e.jsx("td",{children:f.mode}),e.jsxs("td",{children:[f.id,f.detail?` (${f.detail})`:""]}),e.jsx("td",{children:f.target}),e.jsx("td",{children:/coverage|width/.test(f.id)?te(f.value):fe(f.value)}),e.jsx("td",{className:f.pass?"text-primary":"text-destructive",children:f.pass?"PASS":"FAIL"})]},f.mode+f.id))})}):x.status==="registered"&&x.predictions_hash?e.jsx(R,{size:"sm",className:"mt-1",disabled:a===x.id,onClick:()=>l(x.id),children:"Unseal holdout (once)"}):null,x.activated_at&&e.jsxs("p",{children:["Activated ",new Date(x.activated_at).toLocaleString()]})]},x.id))]},u.version))]})}const yt="A01 A02 A03 A04 B05 B06 B07 B08 B09 C10 C11 C12 C13 D14 D15 D16 D17 E18 E19 E20 E21 F22 F23 F24 F25 G26 G27 G28 G29 H30 H31 H32 H33 H34 H35 I36 I37 I38 I39 J40 J41 J42 J43 K44 K45 K46 K47 K48 L49 L50 L51 L52 L53 M54 M55 M56 N57 N58 N59 N60 O61 O62 O63 O64 O65 O66 U99".split(" "),Nt=["case_id","source_file","site_group","tldci_site_id","consultant_base","catchment_pop","membership","has_membership","site_stations","site_has_pool","filter_has_public","filter_has_private","filter_pool_no","filter_residential_daytime","filter_country_england","filter_stations_min","filter_stations_max","filter_catchment_min","filter_catchment_max","consultant_n_comparables"],$e=[...Nt,...yt.map(t=>`pop_${t}`)],Le=2061;function _t(t){t.charCodeAt(0)===65279&&(t=t.slice(1));const s=t.slice(0,t.search(/\r|\n/)===-1?t.length:t.search(/\r|\n/)),i={",":s.split(",").length,";":s.split(";").length," ":s.split(" ").length},o=Object.entries(i).sort((m,h)=>h[1]-m[1])[0][0],r=[];let a=[],c="",d=!1;for(let m=0;m<t.length;m++){const h=t[m];d?h==='"'?t[m+1]==='"'?(c+='"',m++):d=!1:c+=h:h==='"'?d=!0:h===o?(a.push(c),c=""):h===` 3`||h==="\r"?(h==="\r"&&t[m+1]===` 4`&&m++,a.push(c),c="",a.some(l=>l!=="")&&r.push(a),a=[]):c+=h}return a.push(c),a.some(m=>m!=="")&&r.push(a),r}function wt(t){const s=new Uint8Array(t);return s[0]===255&&s[1]===254?new TextDecoder("utf-16le").decode(s):s[0]===254&&s[1]===255?new TextDecoder("utf-16be").decode(s):new TextDecoder("utf-8").decode(s)}function vt(t){return t.map(s=>{const i=s.replace(/^\uFEFF/,"").trim().replace(/^"|"$/g,"").trim(),o=/^pop[_ ]?([a-z])(\d{2})$/i.exec(i);return o?`pop_${o[1].toUpperCase()}${o[2]}`:i.toLowerCase().replace(/\s+/g,"_")})}function St(t){const s=new Set(t.map(o=>o.trim())),i=new Set($e);return{missing:$e.filter(o=>!s.has(o)),extra:[...s].filter(o=>!i.has(o))}}const ie={auto_default:"Auto default",legacy_default:"Legacy default (undocumented provenance)"},L=t=>t==null||Number.isNaN(Number(t))?"â":Number(t).toLocaleString("en-GB",{maximumFractionDigits:0}),se=t=>t==null?"â":Number(t).toLocaleString("en-GB",{maximumFractionDigits:1}),H=t=>t==null?"â":`${(Number(t)*100).toFixed(1)}%`;function $t(){const t=ee(),[s,i]=_.useState("auto_default"),o=j(xt),{data:r,isLoading:a,error:c}=F({queryKey:["ld-calibration",s],queryFn:()=>o({data:{scatterMode:s}})}),d=()=>t.invalidateQueries({queryKey:["ld-calibration"]}),m=j(dt),h=j(mt),l=j(ut),u=j(ht),x=j(pt),f=F({queryKey:["ld-pop-basis"],queryFn:()=>x(),staleTime:1/0}),w=_.useRef(null),[re,G]=_.useState(null),[k,p]=_.useState(!1),[$,B]=_.useState([]),[v,T]=_.useState(null),[J,de]=_.useState(""),[S,D]=_.useState(null);async function A(n){T("import"),B([]),p(!1),G(`Reading ${n.name} (${Math.round(n.size/1024)} KB)â¦`);const g=q=>{p(!0),G(`Import failed â ${q}`)};let C="reading the file";try{const q=_t(wt(await n.arrayBuffer())),he=vt(q[0]??[]),Y=St(he);if(Y.missing.length){g(`header rejected. Missing ${Y.missing.length} column(s): ${Y.missing.slice(0,20).join(", ")}${Y.missing.length>20?"â¦":""}. First columns seen: ${he.slice(0,6).join(", ")||"(none)"}.`);return}const U=q.slice(1);if(!U.length){g("the file has a header but no data rows.");return}let xe=0;const pe=[];for(let M=0;M<U.length;M+=250){C=`uploading rows ${M+1}â${Math.min(M+250,U.length)}`,G(`Uploading rows ${M+1}â${Math.min(M+250,U.length)} of ${U.length}â¦`);const le=await m({data:{header:he,rows:U.slice(M,M+250),first:M===0}});if(le.headerError){g(le.headerError);return}xe+=le.loaded,pe.push(...le.rejected.map(ve=>({line:ve.line+M+2,reason:ve.reason})))}const Ie=U.length!==Le?` Warning: ${U.length} data rows, ${Le} expected.`:"",Ke=Y.extra.length?` Ignored extra columns: ${Y.extra.join(", ")}.`:"";p(xe===0),G(`${xe} rows loaded, ${pe.length} rejected.${Ie}${Ke}`),B(pe),d()}catch(q){console.error("[ld-import]",q),g(`error while ${C}: ${q?.message||String(q)}`)}finally{T(null),w.current&&(w.current.value="")}}async function me(n){for(;;){const g=await l({data:{runId:n}});if(D({done:g.progress,total:g.total}),g.status==="done")break}await u({data:{runId:n}})}async function we(n){T(n),D(null);try{const g=r?.latest?.[n],C=!J&&g&&g.status!=="done"?g.id:(await h({data:{cohortMode:n,configVersion:J||void 0}}
4)).runId;await me(C),d()}catch(g){G(`Run interrupted: ${g.message} â press the button again to resume.`)}finally{T(null)}}const Ae=r?.latest?.auto_default,qe=r?.latest?.legacy_default,Ue=[{label:"Status",get:n=>n?`${n.status} (${n.progress} cases)`:"not run"},{label:"n scored",get:n=>L(n?.summary?.n_scored)},{label:"Refusals",get:n=>`${L(n?.summary?.refusals)} (${H(n?.summary?.refusal_rate)})`},{label:"MAE",get:n=>se(n?.summary?.mae)},{label:"Median APE",get:n=>H(n?.summary?.median_ape)},{label:"Bias (engine â consultant)",get:n=>se(n?.summary?.bias)},{label:"Holdout coverage (P10âP90)",get:n=>H(n?.summary?.calibration?.overall_coverage)},{label:"Oversized cohort",get:n=>H(n?.summary?.oversized_share)},{label:"Penetration anomaly",get:n=>`${L(n?.summary?.anomaly_count)} (${H(n?.summary?.anomaly_share)})`},{label:"Bridged cases / subject in own cohort",get:n=>`${L(n?.summary?.bridged_cases)} / ${L(n?.summary?.subject_in_cohort)}`},...["public","private","mixed_unknown"].map(n=>({label:`MAE â ${n.replace("_","/")}`,get:g=>{const C=g?.summary?.mae_by_sector?.[n];return C?`${se(C.mae)} (n=${C.n})`:"â"}})),...["membership_known","membership_unknown"].map(n=>({label:`MAE â ${n.replace("_"," ")}`,get:g=>{const C=g?.summary?.mae_by_membership?.[n];return C?`${se(C.mae)} (n=${C.n})`:"â"}}))],ue=r?.scatter??[],ne=Math.max(1e3,...ue.map(n=>Math.max(n.engine,n.consultant)));return e.jsxs("div",{className:"space-y-6",children:[a&&e.jsxs("p",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:[e.jsx(O,{className:"h-4 w-4 animate-spin"})," Loading calibrationâ¦"]}),c&&e.jsx("p",{className:"text-sm text-destructive",children:c.message}),e.jsxs("section",{className:"rounded-lg border border-border p-4 space-y-3",children:[e.jsx("h2",{className:"font-medium",children:"Back-test cases"}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:[L(r?.caseCount)," cases loaded",r?.syntheticCount?` (${r.syntheticCount} synthetic test cases â replaced on import)`:""," · engine config ",r?.configVersion??"â"," · live rollout switch ",r?.rolloutSwitch?"ON":"off"," (not changed here)."]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("input",{ref:w,type:"file",accept:".csv,.txt,text/csv,text/plain,application/vnd.ms-excel",className:"hidden",onChange:n=>n.target.files?.[0]&&A(n.target.files[0])}),e.jsxs(R,{variant:"outline",size:"sm",disabled:!!v,onClick:()=>w.current?.click(),children:[e.jsx(be,{className:"mr-1 h-4 w-4"})," Import back-test cases (CSV)"]})]}),re&&e.jsxs("p",{role:"status","data-testid":"ld-import-status",className:`rounded-md border p-2 text-sm ${k?"border-destructive text-destructive":"border-border"}`,children:[v==="import"&&e.jsx(O,{className:"mr-1 inline h-3 w-3 animate-spin"}),re]}),!!$.length&&e.jsx("ul",{className:"max-h-40 overflow-auto text-xs text-destructive",children:$.slice(0,100).map(n=>e.jsxs("li",{children:["Line ",n.line,": ",n.reason]},n.line))})]}),e.jsxs("section",{className:"rounded-lg border border-border p-4 space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsxs("label",{className:"text-sm text-muted-foreground",children:["Config version"," ",e.jsxs("select",{className:"rounded-md border border-border bg-background px-2 py-1 text-sm",value:J,onChange:n=>de(n.target.value),children:[e.jsxs("option",{value:"",children:[r?.configVersion??"active"," (active)"]}),(r?.versions??[]).filter(n=>!n.is_active).map(n=>e.jsx("option",{value:n.version,children:n.version},n.version))]})]}),e.jsxs(R,{size:"sm",disabled:!!v||!r?.caseCount,onClick:()=>we("auto_default"),children:[v==="auto_default"&&e.jsx(O,{className:"mr-1 h-4 w-4 animate-spin"})," Run back-test (auto default)"]}),e.jsxs(R,{size:"sm",variant:"outline",disabled:!!v||!r?.caseCount,onClick:()=>we("legacy_default"),children:[v==="legacy_default"&&e.jsx(O,{className:"mr-1 h-4 w-4 animate-spin"})," Run back-test (",ie.legacy_default,")"]})]}),S&&e.jsxs("div",{className:"space-y-1",children:[e.jsx(Be,{value:S.total?S.done/S.total*100:0}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[S.done," of ",S.total," cases"]})]}),e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-muted-foreground",children:[e.jsx("th",{className:"py-1",children:"Metric"}),e.jsx("th",{children:ie.auto_default}),e.jsx("th",{children:ie.legacy_default})]})}),e.jsx("tbody",{children:Ue.map(n=>e.jsxs("tr",{className:"border-t border-border",children:[e.jsx("td",{className:"py-1",children:n.label}),e.jsx("td",{children:n.get(Ae)}),e.jsx("td",{children:n.get(qe)})]},n.label))})]}),e.jsx("p",{className:"rounded-md bg-muted p-3 text-xs",children:"Fixed benchmark â LD handover kit, same consultant targets: ML model with consultant filters 226.7 MAE · ML model self-serve 343.6 MAE · naive penetration transfer 446 MAE."})]}),e.jsxs("section",{className:"rounded-lg border border-border p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h2",{className:"font-medium",children:"Engine vs consultant base"}),e.jsx("div",{className:"flex gap-1",children:["auto_default","legacy_default"].map(n=>e.jsx("button",{onClick:()=>i(n),className:`rounded-full border px-3 py-1 text-xs ${s===n?"border-primary bg-primary/10":"border-border"}`,children:ie[n]},n))})]}),ue.length?e.jsx("div",{className:"h-80",children:e.jsx(We,{children:e.jsxs(Qe,{margin:{top:10,right:20,bottom:20,left
4:10},children:[e.jsx(Xe,{stroke:"hsl(var(--border))"}),e.jsx(Je,{type:"number",dataKey:"engine",name:"Engine",domain:[0,ne],label:{value:"Engine base",position:"bottom"}}),e.jsx(Ye,{type:"number",dataKey:"consultant",name:"Consultant",domain:[0,ne]}),e.jsx(Ze,{cursor:{strokeDasharray:"3 3"}}),e.jsx(et,{segment:[{x:0,y:0},{x:ne,y:ne}],stroke:"hsl(var(--muted-foreground))",strokeDasharray:"4 4"}),e.jsx(tt,{data:ue,fill:"hsl(var(--primary))",fillOpacity:.5})]})})}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"No scored cases for this mode yet."})]}),e.jsxs("section",{className:"rounded-lg border border-border p-4 space-y-2",children:[e.jsx("h2",{className:"font-medium",children:"Calibrated ranges (not active)"}),e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-muted-foreground",children:[e.jsx("th",{children:"Mode"}),e.jsx("th",{children:"Segment"}),e.jsx("th",{children:"Level"}),e.jsx("th",{children:"n"}),e.jsx("th",{children:"MAE"}),e.jsx("th",{children:"Median APE"}),e.jsx("th",{children:"P10"}),e.jsx("th",{children:"P50"}),e.jsx("th",{children:"P90"}),e.jsx("th",{children:"Holdout cov."}),e.jsx("th",{children:"Active"})]})}),e.jsx("tbody",{children:(r?.calibration??[]).map(n=>e.jsxs("tr",{className:"border-t border-border",children:[e.jsx("td",{children:n.cohort_mode==="legacy_default"?"Legacy":"Auto"}),e.jsx("td",{children:n.segment_key}),e.jsx("td",{children:n.fallback}),e.jsx("td",{children:n.n}),e.jsx("td",{children:se(n.mae)}),e.jsx("td",{children:H(n.median_ape)}),e.jsx("td",{children:Number(n.ratio_p10??0).toFixed(2)}),e.jsx("td",{children:Number(n.ratio_p50??0).toFixed(2)}),e.jsx("td",{children:Number(n.ratio_p90??0).toFixed(2)}),e.jsx("td",{children:H(n.holdout_coverage)}),e.jsx("td",{children:n.is_active?"yes":"no"})]},n.id))})]})]}),e.jsxs("section",{className:"rounded-lg border border-border p-4 space-y-2",children:[e.jsx("h2",{className:"font-medium",children:"50 largest absolute errors (auto default)"}),e.jsx("div",{className:"max-h-[32rem] overflow-auto",children:e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-muted-foreground",children:[e.jsx("th",{children:"Case"}),e.jsx("th",{children:"Site group"}),e.jsx("th",{children:"Consultant"}),e.jsx("th",{children:"Engine"}),e.jsx("th",{children:"|Error|"}),e.jsx("th",{children:"Cohort"}),e.jsx("th",{children:"Flags"}),e.jsx("th",{children:"Trail"})]})}),e.jsx("tbody",{children:(r?.topErrors??[]).map(n=>e.jsxs("tr",{className:"border-t border-border align-top",children:[e.jsx("td",{children:n.case_id}),e.jsx("td",{children:n.site_group}),e.jsx("td",{children:L(n.consultant_base)}),e.jsx("td",{children:L(n.engine_base)}),e.jsx("td",{children:L(n.abs_error)}),e.jsx("td",{children:n.cohort_sites}),e.jsx("td",{children:(n.flags??[]).join(", ")}),e.jsx("td",{children:(n.trail??[]).map(g=>`${g.filter} â ${g.sites} (${L(g.ld_estimate)})`).join(" · ")})]},n.case_id))})]})})]}),e.jsxs("section",{className:"rounded-lg border border-border p-4 space-y-2",children:[e.jsx("h2",{className:"font-medium",children:"Population basis note"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Summed comparator population_count for five distance-radius catchments, next to ONS totals for LSOAs with a postcode inside the radius. ONS data here has all ages and 16+; there is no 15+ total, so 16+ is the nearest proxy. Informational only â nothing is changed on the basis of it."}),f.isLoading?e.jsx("p",{className:"text-xs",children:"Computingâ¦"}):f.data?.error?e.jsx("p",{className:"text-xs text-destructive",children:f.data.error}):e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-muted-foreground",children:[e.jsx("th",{children:"Input"}),e.jsx("th",{children:"Site"}),e.jsx("th",{children:"Radius (mi)"}),e.jsx("th",{children:"Comparator pop."}),e.jsx("th",{children:"ONS all ages"}),e.jsx("th",{children:"ONS 16+"}),e.jsx("th",{children:"Basis"})]})}),e.jsx("tbody",{children:(f.data?.rows??[]).map(n=>e.jsxs("tr",{className:"border-t border-border",children:[e.jsx("td",{children:n.input_id}
4),e.jsxs("td",{children:[n.site_name," (",n.postcode,")"]}),e.jsx("td",{children:n.radius_miles}),e.jsx("td",{children:L(n.comparator_population)}),e.jsx("td",{children:L(n.ons_all_ages)}),e.jsx("td",{children:L(n.ons_16_plus)}),e.jsx("td",{children:n.verdict})]},n.input_id))})]})]}),e.jsx(bt,{})]})}function Lt(){const t=F({queryKey:["ld-data-source-registry"],queryFn:async()=>{const{data:s,error:i}=await Ee.from("ld_data_source_registry").select("*").order("key");if(i)throw i;return s}});return t.data?.length?e.jsxs("div",{className:"space-y-2",children:[e.jsx("h4",{className:"text-sm font-medium",children:"Outcome-model sources (Phase O0)"}),e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"text-left text-muted-foreground",children:e.jsxs("tr",{children:[e.jsx("th",{children:"Source"}),e.jsx("th",{children:"Publisher"}),e.jsx("th",{children:"Geography"}),e.jsx("th",{children:"Year"}),e.jsx("th",{children:"Licence"}),e.jsx("th",{children:"Rows"}),e.jsx("th",{children:"Loaded"})]})}),e.jsx("tbody",{children:t.data.map(s=>e.jsxs("tr",{className:"border-t border-border align-top",children:[e.jsx("td",{className:"py-1",children:s.url?.startsWith("http")?e.jsx("a",{className:"underline",href:s.url,target:"_blank",rel:"noreferrer",children:s.name}):s.name}),e.jsx("td",{children:s.publisher}),e.jsxs("td",{children:[s.geography," · ",s.nation]}),e.jsx("td",{children:s.reference_year}),e.jsx("td",{children:s.licence}),e.jsx("td",{children:s.rows_loaded?.toLocaleString()??"â"}),e.jsx("td",{children:s.loaded_at?new Date(s.loaded_at).toLocaleDateString("en-GB"):"â"})]},s.key))})]})]}):null}const kt=b({method:"GET"}).middleware([y]).handler(N("259606e85705785242a2e404b5b338da6215259a622ddb70a43b790973c599ba")),Ct=b({method:"POST"}).middleware([y]).handler(N("b6a428b0a50a4e203482750014f05e6570ce6b999675de8bce41ecff02673786"));function Rt(){const t=j(kt),s=j(Ct),i=ee(),o=F({queryKey:["tldci-data-sources"],queryFn:()=>t()}),r=De({mutationFn:()=>s({data:{reason:"staff refresh from Data sources"}}),onSuccess:c=>{E.success(`Refresh done â comparator data v${c?.comparator_version}, ${(c?.flagged_reports??[]).length} reports flagged for review`),i.invalidateQueries({queryKey:["tldci-data-sources"]})},onError:c=>E.error(c.message)});if(o.isLoading)return e.jsxs("p",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:[e.jsx(O,{className:"h-4 w-4 animate-spin"})," Loading data sourcesâ¦"]});if(o.error)return e.jsx("p",{className:"text-sm text-destructive",children:o.error.message});const a=o.data;return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"text-sm text-muted-foreground",children:["Comparator data version ",e.jsxs("b",{className:"text-foreground",children:["v",a.comparator_version?.version??"?"]})," (",a.comparator_version?.reason??"â",") · Active engine ",e.jsx("b",{className:"text-foreground",children:a.positioning.active_engine})," uses club list ",e.jsx("b",{className:"text-foreground",children:a.positioning.universe})," (",a.positioning.v1_clubs.toLocaleString()," clubs; expanded list ",a.positioning.v2_clubs.toLocaleString(),")"]}),e.jsxs(R,{size:"sm",onClick:()=>r.mutate(),disabled:r.isPending,children:[r.isPending?e.jsx(O,{className:"mr-2 h-4 w-4 animate-spin"}):e.jsx(st,{className:"mr-2 h-4 w-4"}),"Rebuild after a load"]})]}),e.jsx(Lt,{}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Rebuild re-runs cleaning and quality checks, rebuilds both club lists and bumps the data version. It never recalculates reports â it lists the ones whose inputs changed."}),e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"text-left text-muted-foreground",children:e.jsxs("tr",{children:[e.jsx("th",{children:"Table"}),e.jsx("th",{children:"Rows"}),e.jsx("th",{children:"Last loaded"}),e.jsx("th",{children:"Source"}),e.jsx("th",{children:"Cleaning"}),e.jsx("th",{children:"Open issues"})]})}),e.jsx("tbody",{children:a.tables.map(c=>e.jsxs("tr",{className:"border-t border-border",children:[e.jsx("td",{className:"py-1 font-mono text-xs",children:c.table}
4),e.jsx("td",{children:c.rows?.toLocaleString()??"â"}),e.jsx("td",{children:c.last_loaded}),e.jsx("td",{children:c.source}),e.jsx("td",{children:c.normalised}),e.jsx("td",{children:c.open_issues})]},c.table))})]}),e.jsxs("div",{children:[e.jsx("h3",{className:"mb-2 text-sm font-medium",children:"Data-quality checks"}),e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"text-left text-muted-foreground",children:e.jsxs("tr",{children:[e.jsx("th",{children:"Issue"}),e.jsx("th",{children:"Table"}),e.jsx("th",{children:"Rows"}),e.jsx("th",{children:"Example ids"})]})}),e.jsx("tbody",{children:a.issues.map(c=>e.jsxs("tr",{className:"border-t border-border",children:[e.jsx("td",{className:"py-1",children:c.issue}),e.jsx("td",{className:"font-mono text-xs",children:c.table_name}),e.jsx("td",{children:c.row_count.toLocaleString()}),e.jsx("td",{className:"font-mono text-xs",children:(c.example_ids??[]).join(", ")})]},c.issue))})]})]}),e.jsxs("div",{children:[e.jsx("h3",{className:"mb-2 text-sm font-medium",children:"Refresh log"}),a.log.length?e.jsx("ul",{className:"space-y-1 text-sm",children:a.log.map(c=>e.jsxs("li",{children:[new Date(c.created_at).toLocaleString()," â v",c.comparator_version,", comparator data ",c.comparator_hash_before===c.comparator_hash_after?"unchanged":"changed",", clubs ",c.universe_before,"â",c.universe_after,", ",(c.flagged_reports??[]).length," reports flagged"]},c.id))}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"No refreshes recorded yet."})]})]})}const Ne=18,_e=68,ke="ABCDEFGHIJKLMNOPQR".split(""),K=t=>String(t??"").trim(),ge=t=>t.toLowerCase().replace(/[^a-z0-9]/g,"");function P(t,s){const i=t.map(ge);for(const o of s){const r=i.indexOf(ge(o));if(r>=0)return t[r]}for(const o of s){const r=i.findIndex(a=>a.includes(ge(o)));if(r>=0)return t[r]}return null}const Tt=t=>{const s=K(t).toUpperCase().replace(/\s+/g,"");return s.length>=5?`${s.slice(0,-3)} ${s.slice(-3)}`:s};function Mt(t){const s=Object.keys(t[0]??{}),i={type:P(s,["type code","mosaic type","type"]),typeName:P(s,["type name","type description short","type label"]),group:P(s,["group code","mosaic group","group"]),groupName:P(s,["group name","group label"]),desc:P(s,["description","type description","pen portrait"]),colour:P(s,["colour","color","hex","rgb"])},o=[],r=new Map;for(const a of t){const c=K(i.type?a[i.type]:"").toUpperCase(),d=(K(i.group?a[i.group]:"")||c.slice(0,1)).toUpperCase(),m=K(i.groupName?a[i.groupName]:"");d&&d.length===1&&!r.has(d)&&r.set(d,{code:d,name:m}),d&&m&&!r.get(d)?.name&&r.set(d,{code:d,name:m}),!(!c||c.length<2)&&o.push({code:c,group_code:d,group_name:m||void 0,name:K(i.typeName?a[i.typeName]:""),description:K(i.desc?a[i.desc]:"")||void 0,colour:K(i.colour?a[i.colour]:"")||void 0})}return{columns:i,types:o,groups:[...r.values()]}}function Pt(t,s){const i=[],o=new Set;for(const a of t)o.has(a.code)&&i.push(`Duplicate type code ${a.code}`),o.add(a.code),/^[A-R]\d{2}$/.test(a.code)||i.push(`Unexpected type code format ${a.code}`),a.code.slice(0,1)!==a.group_code&&i.push(`Type ${a.code} is listed under group ${a.group_code}`),a.name||i.push(`Type ${a.code} has no name`);const r=new Set(s.map(a=>a.code));for(const a of t)r.add(a.group_code);r.size!==Ne&&i.push(`Found ${r.size} groups; expected ${Ne}`);for(const a of ke)r.has(a)||i.push(`Group ${a} missing`);for(const a of r)ke.includes(a)||i.push(`Unexpected group ${a}`);o.size!==_e&&i.push(`Found ${o.size} types; expected ${_e}`);for(const a of s)a.name||i.push(`Group ${a.code} has no name`);return{ok:i.length===0,issues:i,groups:r.size,types:o.size}}function Et(t){const s=Object.keys(t[0]??{}),i={pc:P(s,["postcode","pcd","post code"]),type:P(s,["mosaic type","type code","type"]),hh:P(s,["households","household count","hh"]),pop:P(s,["population","persons","adults"])};if(!i.pc||!i.type)throw new Error("Postcode lookup needs a postcode column and a Mosaic type column.");const o=a=>{const c=Number(String(a??"").replace(/,/g,""));return Number.isFinite(c)&&String(a??"").trim()!==""?Math.round(c):null},r=[];for(const a of t){const c=Tt(a[i.pc]),d=K(a[i.type]).toUpperCase();
4!c||!d||r.push({postcode:c,type_code:d,households:i.hh?o(a[i.hh]):null,population:i.pop?o(a[i.pop]):null})}return{columns:i,rows:r}}const Ot=b({method:"GET"}).middleware([y]).handler(N("8bd906107c7f7b934c31ca7c71896c9c7dfeddd8c7fb2ba6b4f824f0cd985558")),Ft=b({method:"POST"}).middleware([y]).handler(N("d559614d83383b6a763bbd3cb327f9a3a9d920dc0f136a96f8eb7872987c5854")),Bt=b({method:"POST"}).middleware([y]).handler(N("8efbc7bbdb9647767227f013e15b75c3fc33900ff79b9c109c98e0256a5e6d46")),Dt=b({method:"POST"}).middleware([y]).handler(N("58e7a57bc43997fefb74175c09a250b54a53fbaeeb127d33b683af892da33ecb")),At=b({method:"POST"}).middleware([y]).handler(N("1fb0fa646ff2f66aa6fac76e1eb69b52f834e349ceed5deabe4fde30d8ce91df"));async function Ce(t){const s=await Oe(()=>import("./xlsx-CNerDvZX.js"),[]),i=s.read(await t.arrayBuffer(),{type:"array"});return s.utils.sheet_to_json(i.Sheets[i.SheetNames[0]],{defval:""})}function qt(){const t=j(Ot),s=j(Ft),i=j(Bt),o=j(Dt),r=j(At),a=ee(),c=F({queryKey:["mosaic-v2-status"],queryFn:()=>t()}),[d,m]=_.useState(""),[h,l]=_.useState(""),[u,x]=_.useState(null),[f,w]=_.useState([]);async function re(p){x("Reading reference fileâ¦"),w([]);try{const{types:$,groups:B}=Mt(await Ce(p)),v=Pt($,B);if(w(v.issues),!v.ok&&!confirm(`The file doesn't match ${Ne} groups / ${_e} types: 5 6${v.issues.slice(0,8).join(` 7`)} 8 9Load it anyway?`))return;const T=await s({data:{file_name:p.name,release_label:d||void 0,file_date:h||void 0,types:$,groups:B,force:!v.ok}});E.success(T.ok?`Loaded ${v.groups} groups / ${v.types} types`:"Not loaded")}catch($){E.error($.message)}finally{x(null),a.invalidateQueries({queryKey:["mosaic-v2-status"]})}}async function G(p){w([]);try{x("Reading postcode lookupâ¦");let $;if(/\.csv$/i.test(p.name)){const S=(await Oe(async()=>{const{default:D}=await import("./papaparse.min-CoL0ml_G.js").then(A=>A.p);return{default:D}},__vite__mapDeps([0,1]))).default;$=await new Promise((D,A)=>S.parse(p,{header:!0,skipEmptyLines:!0,complete:me=>D(me.data),error:A}))}else $=await Ce(p);const{rows:B}=Et($),{import_id:v}=await i({data:{file_name:p.name,release_label:d||void 0,file_date:h||void 0,replace:!0}}),T=[];let J=0;for(let S=0;S<B.length;S+=5e3){x(`Loading postcodes ${S.toLocaleString()} / ${B.length.toLocaleString()}â¦`);const D=await o({data:{import_id:v,rows:B.slice(S,S+5e3)}});J+=D.loaded;for(const A of D.issues)!T.includes(A)&&T.length<150&&T.push(A)}x("Checking coverageâ¦");const de=await r({data:{import_id:v,issues:T}});w(de.issues),E.success(`Loaded ${J.toLocaleString()} postcodes`)}catch($){E.error($.message)}finally{x(null),a.invalidateQueries({queryKey:["mosaic-v2-status"]})}}const k=c.data;return e.jsxs("section",{className:"space-y-4 rounded-lg border p-4",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-base font-semibold",children:"Current Experian Mosaic (staff only)"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Load the licensed Experian files. Nothing here changes live figures â reports stay on Mosaic UK 7 until the dual-run passes and is approved."})]}),c.isLoading?e.jsx(O,{className:"h-4 w-4 animate-spin"}):k&&e.jsxs("p",{className:"text-sm",children:["Reference: ",e.jsx("b",{children:k.groups})," groups / ",e.jsx("b",{children:k.types})," types (",k.reference_source==="official"?"official Experian file":k.reference_source==="web"?"web-sourced draft â replace with the official file":"not loaded",") · Postcode lookup: ",e.jsx("b",{children:k.postcodes.toLocaleString()})," postcodes"]}),e.jsxs("div",{className:"grid gap-3 sm:grid-cols-2",children:[e.jsxs("label",{className:"text-sm",children:["Release name",e.jsx(ye,{value:d,onChange:p=>m(p.target.value),placeholder:"e.g. Mosaic UK 2025"})]}),e.jsxs("label",{className:"text-sm",children:["File date",e.jsx(ye,{type:"date",value:h,onChange:p=>l(p.target.value)})]})]}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsx(R,{variant:"outline",asChild:!0,disabled:!!u,children:e.jsxs("label",{className:"cursor-pointer",children:[e.jsx(be,{className:"mr-2 h-4 w-4"}),"Reference file (.xlsx/.csv)",e.jsx("input",{type:"file",accept:".xlsx,.xls,.csv",className:"sr-only",onChange:p=>p.target.files?.[0]&&re(p.target.files[0])})]})}),e.jsx(R,{variant:"outline",asChild:!0,disabled:!!u||k?.reference_source!=="official",children:e.jsxs("label",{className:"cursor-pointer",children:[e.jsx(be,{className:"mr-2 h-4 w-4"}),"Postcode lookup (.csv/.xlsx)",e.jsx("input",{type:"file",accept:".csv,.xlsx",className:"sr-only",disabled:k?.reference_source!=="official",onChange:p=>p.target.files?.[0]&&G(p.target.files[0])})]})})]}),u&&e.jsxs("p",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:[e.jsx(O,{className:"h-4 w-4 animate-spin"}),u]}),!!f.length&&e.jsx("ul",{className:"list-disc pl-5 text-sm text-destructive",children:f.slice(0,20).map(p=>e.jsx("li",{children:p},p))}),!!k?.imports.length&&e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-muted-foreground",children:[e.jsx("th",{children:"When"}),e.jsx("th",{children:"File"}),e.jsx("th",{children:"Kind"}),e.jsx("th",{children:"Release"}),e.jsx("th",{children:"Rows"}),e.jsx("th",{children:"Groups/Types"}),e.jsx("th",{children:"Status"}),e.jsx("th",{children:"Issues"})]})}),e.jsx("tbody",{children:k.imports.map(p=>e.jsxs("tr",{className:"border-t",children:[e.jsx("td",{children:new Date(p.created_at).toLocaleDateString()}),e.jsx("td",{children:p.file_name}),e.jsx("td",{children:p.kind}),e.jsx("td",{children:p.release_label??"â"}
9),e.jsx("td",{children:p.rows_loaded?.toLocaleString()}),e.jsxs("td",{children:[p.groups_found??"â","/",p.types_found??"â"]}),e.jsx("td",{children:p.status}),e.jsx("td",{children:(p.issues??[]).length})]},p.id))})]})]})}const Ut=b({method:"GET"}).middleware([y]).handler(N("edf456285d6ab53ebda2bebf641af05963595a8659e3196fcfe3349dff1cb8b5")),It=b({method:"POST"}).middleware([y]).handler(N("4c8a5a1531c26df49346f63fd9af4766ebaac6d5ae3db67ae2e31e8d1813947d")),Kt=b({method:"POST"}).middleware([y]).handler(N("dee1f25be2470dbaa8437ee459e85a74e6d7195ee4e61a3da27f2f131a790d36")),Gt=b({method:"POST"}).middleware([y]).handler(N("3667eabaa217192c5d2ffe6b27f265ae6cc8057d979613eee173a4a79ba6e018")),W=t=>t==null?"â":Math.round(t).toLocaleString("en-GB"),ae=t=>t==null?"â":`${t>0?"+":""}${Math.round(t).toLocaleString("en-GB")}`;async function zt(t){const s=new Uint8Array(await t.arrayBuffer());let i="";for(let o=0;o<s.length;o+=32768)i+=String.fromCharCode(...s.subarray(o,o+32768));return btoa(i)}function Vt(t){const i=[["Site","Client","Legacy date","Metric","Legacy","Legacy source","New","Difference","Diff %"]];for(const o of t)for(const r of o.lines)i.push([o.site,o.client,o.legacy_date??"",r.label,r.legacy.value==null?r.legacy.text??"not stated":String(r.legacy.value),r.legacy.source??"",r.next==null?"":String(r.next),r.diff==null?"":String(Math.round(r.diff)),r.diff_pct==null?"":r.diff_pct.toFixed(1)]);return i.map(o=>o.map(r=>`"${String(r).replace(/"/g,'""')}"`).join(",")).join(` 10`)}function Ht(t){const s=t.lines.find(o=>o.key==="competition_reduction"),i=t.competition_assessed??{legacy:s.legacy.value!=null,next:s.next!=null};return`${i.legacy&&s.legacy.value!=null?`â${W(s.legacy.value)}`:"Not assessed"} / ${i.next&&s.next!=null?`â${W(s.next)}`:"Not assessed"}`}function Wt(){const t=ee(),s=j(Ut),i=F({queryKey:["legacy-comparison"],queryFn:()=>s()}),o=j(Gt),r=De({mutationFn:l=>o({data:{id:l}}),onSuccess:()=>{E.success("Report restored"),t.invalidateQueries({queryKey:["legacy-comparison"]})}});if(i.isLoading)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loadingâ¦"});if(i.error)return e.jsx("p",{className:"text-sm text-destructive",children:i.error.message});const a=i.data,c=a.sites.filter(l=>l.run===1).map(l=>l.comparison).filter(Boolean),d=a.sites.filter(l=>l.run===2),m=a.summary,h=()=>{const l=new Blob([Vt(c)],{type:"text/csv"}),u=document.createElement("a");u.href=URL.createObjectURL(l),u.download="legacy-vs-new-platform.csv",u.click()};return e.jsxs("div",{className:"space-y-6 print:space-y-4",children:[e.jsxs("header",{className:"flex flex-wrap items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"font-display text-xl",children:"Legacy vs new-platform comparison"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:`Staff only. Original consultant outputs against fresh runs on the active engine with automatic comparable sites. "Not stated" means the legacy file doesn't give the figure.`})]}),e.jsxs("div",{className:"flex gap-2 print:hidden",children:[e.jsx(R,{variant:"outline",size:"sm",onClick:h,children:"Export CSV"}),e.jsx(R,{variant:"outline",size:"sm",onClick:()=>window.print(),children:"Export PDF"})]})]}),e.jsx(rt,{}),e.jsx(Yt,{sites:a.sites}),e.jsx("h4",{className:"font-display text-lg",children:"Run 1 â platform test packs, criteria registered after the fact"}),e.jsx(Xt,{a:a.acceptance}),e.jsxs("section",{className:"rounded-md border border-border p-4 text-sm",children:[e.jsxs("h4",{className:"font-medium",children:["Summary across ",m.sites," sites"]}),e.jsxs("ul",{className:"mt-2 list-disc space-y-1 pl-5",children:[e.jsxs("li",{children:["Total demand: new vs legacy median ",ae(m.total.median)," (",m.total.median_pct==null?"â":`${m.total.median_pct.toFixed(1)}%`,"), mean ",ae(m.total.mean),"; higher at ",m.total.higher,", lower at ",m.total.lower," of ",m.total.n," comparable sites."]}),e.jsxs("li",{children:["Base demand: median ",ae(m.base.median),"; latent demand: median ",ae(m.latent.median),"."]}),e.jsxs("li",{children:["Legacy total inside the new 80% accuracy range at ",m.legacy_in_range," sites, outside at ",m.legacy_outside_range,"."]}),e.jsxs("li",{children:["Dominant driver per site: ",m.dominant_drivers.map(([l,u])=>`${l} (${u})`).join(", ")||"â","."]})]})]}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"text-left text-muted-foreground",children:e.jsxs("tr",{children:[e.jsx("th",{className:"p-2",children:"Site"}),e.jsx("th",{className:"p-2",children:"Population L / N"}),e.jsx("th",{className:"p-2",children:"Base L / N"}),e.jsx("th",{className:"p-2",children:"Outside % L / N"}),e.jsx("th",{className:"p-2",children:"Competition L / N"}),e.jsx("th",{className:"p-2",children:"Total L / N"}),e.jsx("th",{className:"p-2",children:"New 80% range"}),e.jsx("th",{className:"p-2",children:"Legacy in range"}),e.jsx("th",{className:"p-2",children:"Membership L / N"}),e.jsx("th",{className:"p-2",children:"Latent L / N"}),e.jsx("th",{className:"p-2",children:"New signal"})]})}),e.jsx("tbody",{children:c.map(l=>{const u=f=>l.lines.find(w=>w.key===f),x=(f,w="")=>`${u(f).legacy.value==null?"not stated":W(u(f).legacy.value)+w} / ${u(f).next==null?"â":W(u(f).next)+w}`;return e.jsxs("tr",{className:"border-t border-border align-top",children:[e.jsxs("td",{className:"p-2 font-medium",children:[l.site,e.jsx("div",{className:"text-xs text-muted-foreground",children:l.legacy_date??"date not stated"})]}),e.jsx("td",{className:"p-2",children:x("adult_population")}),e.jsx("td",{className:"p-2",children:x("within_catchment_demand")}),e.jsx("td",{className:"p-2",children:x("outside_uplift_pct","%")}),e.jsx("td",{className:"p-2",children:Ht(l)}),e.jsx("td",{className:"p-2",children:x("total_demand")}),e.jsx("td",{className:"p-2",children:l.range?`${W(l.range.low)}â${W(l.range.high)}`:"no figure (refused)"}),e.jsx("td",{className:"p-2",children:l.legacy_in_range==null?"â":l.legacy_in_range?e.jsx(X,{variant:"secondary",children:"inside"}):e.jsx(X,{variant:"destructive",children:"outside"})}),e.jsx("td",{className:"p-2",children:x("current_membership")}),e.jsx("td",{className:"p-2",children:x("latent_demand")}),e.jsx("td",{className:"p-2",children:l.signal_new??"â"})]},l.site)})})]})}),d.length?e.jsx("h4",{className:"font-display text-lg",children:"Run 2 sites â extracted figures, corrections and waterfall"}):null,d.map(l=>l.comparison?e.jsx(Re,{caseId:l.case_id,c:l.comparison,metrics:l.metrics,reality:l.reality},l.case_id):null),a.sites.filter(l=>
10l.run===1).map(l=>l.comparison?e.jsx(Re,{caseId:l.case_id,c:l.comparison,metrics:l.metrics,reality:l.reality},l.case_id):null),e.jsxs("section",{className:"rounded-md border border-border p-4 text-sm print:hidden",children:[e.jsxs("h4",{className:"font-medium",children:["Archived â legacy (",a.archived.length,")"]}),e.jsx("ul",{className:"mt-2 space-y-1",children:a.archived.map(l=>e.jsxs("li",{className:"flex items-center justify-between gap-2",children:[e.jsxs("span",{children:[l.title," ",e.jsxs("span",{className:"text-xs text-muted-foreground",children:["· was ",l.archived_prior_status," · ",String(l.archived_at).slice(0,10)]})]}),e.jsx(R,{size:"sm",variant:"ghost",disabled:r.isPending,onClick:()=>r.mutate(l.id),children:"Restore"})]},l.id))})]})]})}function Re({caseId:t,c:s,metrics:i,reality:o}){const r=ee(),a=j(Kt),c=j(It),[d,m]=_.useState(!1),h=async l=>{if(l){m(!0);try{const u=await a({data:{case_id:t,filename:l.name,file:await zt(l)}});E.success(`${l.name}: ${u.stated} of ${u.total} figures found`),r.invalidateQueries({queryKey:["legacy-comparison"]})}catch(u){E.error(u.message)}finally{m(!1)}}};return e.jsxs("details",{className:"rounded-md border border-border p-4 text-sm",children:[e.jsxs("summary",{className:"cursor-pointer font-medium",children:[s.site," â drivers, legacy figures and what actually happened"]}),e.jsx("div",{className:"mt-3",children:o?e.jsx(at,{rc:o.band,reason:o.reason}):null}),e.jsxs("div",{className:"mt-3 grid gap-4 lg:grid-cols-2",children:[e.jsxs("div",{children:[e.jsx("h5",{className:"mb-1 font-medium",children:"Why the figures differ (effect on total demand)"}),e.jsx("table",{className:"w-full",children:e.jsx("tbody",{children:s.drivers.map(l=>e.jsxs("tr",{className:"border-t border-border align-top",children:[e.jsx("td",{className:"p-1",children:l.label}),e.jsx("td",{className:"p-1 text-muted-foreground",children:l.legacy}),e.jsx("td",{className:"p-1",children:l.next}),e.jsx("td",{className:"p-1 text-right",children:ae(l.effect)})]},l.key))})}),s.waterfalls?.total?e.jsx(Se,{title:"Waterfall â total demand",w:s.waterfalls.total}):null,s.waterfalls?.latent?e.jsx(Se,{title:"Waterfall â latent / headroom",w:s.waterfalls.latent}):null,e.jsxs("p",{className:"mt-2 text-xs text-muted-foreground",children:["Engine ",s.engine_version??"â",". What actually happened: ",s.actual.length?s.actual.map(l=>`${l.year}: ${W(l.membership)} (${l.source})`).join("; "):"no register membership recorded after the legacy report date."]}),s.notes.map(l=>e.jsx("p",{className:"text-xs italic text-muted-foreground",children:l},l))]}),e.jsxs("div",{children:[e.jsxs("div",{className:"mb-2 flex items-center justify-between print:hidden",children:[e.jsx("h5",{className:"font-medium",children:"Legacy consultant figures (extracted)"}),e.jsxs("label",{className:"text-xs underline",children:[d?"Readingâ¦":"Upload output file",e.jsx("input",{type:"file",accept:".xlsx,.xlsm,.xls,.pdf",className:"hidden",disabled:d,onChange:l=>h(l.target.files?.[0])})]})]}),e.jsx("table",{className:"w-full",children:e.jsx("tbody",{children:i.map(l=>e.jsx(Qt,{m:l,onSave:async(u,x)=>{await c({data:{id:l.id,value:u,text:x}}),r.invalidateQueries({queryKey:["legacy-comparison"]}),E.success("Saved")}},l.id))})})]})]})]})}function Qt({m:t,onSave:s}){const i=t.expected_value==null&&t.value_text!=null||["catchment_definition","mosaic_version","comparator_settings","report_date"].includes(t.metric_key),[o,r]=_.useState(i?t.value_text??"":t.expected_value==null?"":String(t.expected_value));return e.jsxs("tr",{className:"border-t border-border align-top",children:[e.jsxs("td",{className:"p-1",children:[t.metric_key.replace(/_/g," "),e.jsxs("div",{className:"text-xs text-muted-foreground",children:[t.source_file,t.source_cell?` · ${t.source_cell}`:""]})]}),e.jsx("td",{className:"p-1 w-40",children:e.jsx(ye,{value:o,placeholder:"not stated",onChange:a=>r(a.target.value),className:"h-7 text-xs"})}),e.jsx("td",{className:"p-1 text-xs",children:t.value_status==="not_stated"?"not stated":t.value_status==="corrected"?"corrected":`${Math.round(Number(t.confidence??0)*100)}%`}),e.jsx("td",{className:"p-1 print:hidden",children:e.jsx(R,{size:"sm",variant:"ghost",className:"h-7",onClick:()=>{const a=o.trim();s(i||!a?null:Number(a.replace(/[,£%]/g,"")),i&&a||null)},children:"Save"})})]})}function Xt({a:t}){if(!t)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Acceptance criteria not registered."});const s=t.result,i=r=>s?.criteria?.find(a=>a.key===r),o=r=>r==="pass"?e.jsx(X,{variant:"secondary",children:"pass"}):r==="fail"?e.jsx(X,{variant:"destructive",children:"fail"}):e.jsx(X,{variant:"outline",children:r??"not evaluated"});return e.jsxs("section",{className:"rounded-md border border-border p-4 text-sm",children:[e.jsx("h4",{className:"font-medium",children:"Pre-registered acceptance criteria"}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Registered ",String(t.created_at).slice(0,16).replace("T"," ")," UTC · engine ",t.engine_version," · ",t.status==="unsealed"?`evaluated once ${String(t.unsealed_at).slice(0,16).replace("T"," ")} UTC`:"awaiting evaluation"]}),t.notes&&e.jsx("p",{className:"mt-1 text-xs italic text-muted-foreground",children:t.notes}),e.jsxs("p",{className:"mt-2 text-xs",children:["Basis: (a) ",t.criteria.basis.a," (b) ",t.criteria.basis.b]}),e.jsx("table",{className:"mt-2 w-full",children:e.jsx("tbody",{children:Object.entries(t.criteria.primary).map(([r,a])=>{const c=i(r);return e.jsxs("tr",{className:"border-t border-border align-top",children:[e.jsxs("td",{className:"p-1 font-medium",children:[r," ",a.label]}),e.jsx("td",{className:"p-1 text-muted-foreground",children:a.rule}),e.jsx("td",{className:"p-1",children:o(c?.verdict)}),e.jsxs("td",{className:"p-1 text-xs",children:[c?.detail,c?.sites?.length?e.jsxs("details",{children:[e.jsx("summary",{className:"cursor-pointer",children:"sites"}),e.jsx("ul",{children:c.sites.map(d=>e.jsxs("li",{children:[d.ok===!0?"â":d.ok===!1?"â":"â"," ",d.site,": ",d.note]},d.site))})]}):null]})]},r)})})}),s?.secondary&&e.jsxs("ul",{className:"mt-2 list-disc pl-5 text-xs",children:[e.jsxs("li",{children:["Systematic bias: median ",s.secondary.bias.median_pct?.toFixed(1),"% (",s.secondary.bias.direction,", ",s.secondary.bias.n," sites)",s.secondary.bias.flagged?" â flagged (> 15% one way)":" â not flagged","."]}),e.jsx("li",{children:s.secondary.time_to_report}),e.jsxs("li",{children:["Data dates: ",s.secondary.data_dates.map(r=>`${r.site} legacy ${r.legacy} / new ${r.new}`).join("; "),"."]})]}),e.jsx("p",{className:"mt-2 text-xs font-medium",children:t.criteria.caveat})]})}function Jt(t){return String(t??"").trim().split(/\s+/)[0]?.toLowerCase()??""}function Yt({sites:t}){const s=new Map;for(const a of t){if(!a.comparison)continue;const c=Jt(a.comparison.site),d=s.get(c)??{site:a.comparison.site};a.run===2?d.r2=a.comparison:d.r1=a.comparison,s.set(c,d)}const i=[...s.values()].filter(a=>a.r1&&a.r2);if(!i.length)return null;const o=a=>a?.lines.find(c=>c.key==="total_demand"),r=a=>
10a==null?"â":Math.round(a).toLocaleString("en-GB");return e.jsxs("section",{className:"rounded-md border border-border p-4 text-sm","data-testid":"run-side-by-side",children:[e.jsx("h4",{className:"font-display text-lg",children:"Run 1 vs run 2 â same sites"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Run 2 is a confirmation run on previously seen sites â not blind. Legacy figures come only from the consultant documents."}),e.jsxs("table",{className:"mt-2 w-full",children:[e.jsx("thead",{className:"text-left text-muted-foreground",children:e.jsxs("tr",{children:[e.jsx("th",{className:"p-2",children:"Site"}),e.jsx("th",{className:"p-2",children:"Legacy total"}),e.jsx("th",{className:"p-2",children:"Run 1 new"}),e.jsx("th",{className:"p-2",children:"Run 2 new"}),e.jsx("th",{className:"p-2",children:"Run 2 â run 1"}),e.jsx("th",{className:"p-2",children:"Run 1 / run 2 80% range"}),e.jsx("th",{className:"p-2",children:"Legacy inside (1 / 2)"})]})}),e.jsx("tbody",{children:i.map(a=>{const c=o(a.r1),d=o(a.r2),m=c?.next!=null&&d?.next!=null?d.next-c.next:null,h=u=>u?.range?`${r(u.range.low)}â${r(u.range.high)}`:"â",l=u=>u?.legacy_in_range==null?"â":u.legacy_in_range?"inside":"outside";return e.jsxs("tr",{className:"border-t border-border",children:[e.jsx("td",{className:"p-2 font-medium",children:a.site}),e.jsx("td",{className:"p-2",children:d?.legacy.value==null?c?.legacy.value==null?"not stated":r(c.legacy.value):r(d.legacy.value)}),e.jsx("td",{className:"p-2",children:r(c?.next)}),e.jsx("td",{className:"p-2",children:r(d?.next)}),e.jsx("td",{className:"p-2",children:m==null?"â":`${m>0?"+":""}${r(m)}`}),e.jsxs("td",{className:"p-2",children:[h(a.r1)," / ",h(a.r2)]}),e.jsxs("td",{className:"p-2",children:[l(a.r1)," / ",l(a.r2)]})]},a.site)})})]})]})}const Q=t=>t==null?"â":typeof t=="number"?Math.round(t).toLocaleString("en-GB"):String(t),Te=t=>t==null?"â":`${t>0?"+":""}${t.toFixed(1)}%`,je=t=>t?String(t).replace(/_/g," "):"â",Me=[{key:"title",label:"Report",get:t=>t.title},{key:"run",label:"Run",get:t=>t.run??""},{key:"engine",label:"Stored engine",get:t=>t.before?.engine??""},{key:"within",label:"Within (stored â new)",get:t=>t.after?.within??0},{key:"outside",label:"Outside",get:t=>t.after?.outside??0},{key:"workforce",label:"Workforce",get:t=>t.after?.workforce??0},{key:"new_homes",label:"New homes",get:t=>t.after?.new_homes??0},{key:"competition",label:"Competition",get:t=>t.after?.competition??0},{key:"cap",label:"Capacity step",get:t=>t.after?.capacity_factor??1},{key:"total",label:"Total (stored â new)",get:t=>t.after?.total??0},{key:"pct",label:"Change",get:t=>Math.abs(t.total_pct??0)},{key:"range",label:"Range (new)",get:t=>t.after?.range_low??0},{key:"signal",label:"Headroom signal",get:t=>t.signal_flip?1:0},{key:"flags",label:"Checks",get:t=>t.after?.capacity_check??""},{key:"client",label:"Client total",get:t=>t.client_total??0}],Z=(t,s)=>t===s||t==null&&s==null?Q(s):`${Q(t)} â ${Q(s)}`;function Zt(){const{data:t,isLoading:s,error:i}=F({queryKey:["engine-impact"],queryFn:async()=>{const{data:d,error:m}=await Ee.from("ld_engine_impact_runs").select("*").order("created_at",{ascending:!1}).limit(1).maybeSingle();if(m)throw m;return d}}),[o,r]=_.useState({key:"pct",dir:-1}),a=_.useMemo(()=>{const d=Me.find(m=>m.key===o.key);return[...t?.rows??[]].sort((m,h)=>{const l=d.get(m),u=d.get(h);return(l>u?1:l<u?-1:0)*o.dir})},[t,o]);if(s)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loadingâ¦"});if(i)return e.jsx("p",{className:"text-sm text-destructive",children:i.message});if(!t)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"No impact run recorded yet."});const c=t.summary??{};return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsxs("h2",{className:"text-lg font-semibold",children:["Engine impact â ",t.engine_version," vs stored figures"]}),e.jsxs("p",{className:"max-w-3xl text-sm text-muted-foreground",children:["Dry run on ",new Date(t.created_at).toLocaleString("en-GB"),". Nothing was saved or recomputed â use this to decide which reports to recompute."," ",c.n," reports · ",c.moved_15," move by more than 15% · ",c.flips," headroom-signal changes. Staff only."]})]}),e.jsx("div",{className:"overflow-x-auto rounded-md border",children:e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{className:"bg-muted/50",children:e.jsx("tr",{children:Me.map(d=>e.jsxs("th",{className:"cursor-pointer select-none whitespace-nowrap px-2 py-2 text-left font-medium",onClick:()=>r(m=>({key:d.key,dir:m.key===d.key?m.dir===1?-1:1:-1})),children:[d.label,o.key===d.key?o.dir===1?" â²":" â¼":""]},d.key))})}),e.jsx("tbody",{children:a.map(d=>{const m=d.before??{},h=d.after??{};return e.jsxs("tr",{id:`impact-${d.report_id}`,className:`border-t ${d.big_move||d.signal_flip?"bg-accent/40":""}`,children:[e.jsx("td",{className:"max-w-[220px] px-2 py-1.5",children:e.jsx(Fe,{to:"/app/reports/$id",params:{id:d.report_id},className:"underline-offset-2 hover:underline",children:d.title})}),e.jsx("td",{className:"px-2",children:d.run??"â"}),e.jsx("td",{className:"px-2",children:m.engine??"â"}),e.jsx("td",{className:"whitespace-nowrap px-2",children:Z(m.within,h.within)}),e.jsx("td",{className:"whitespace-nowrap px-2",children:Z(m.outside,h.outside)}),e.jsx("td",{className:"whitespace-nowrap px-2",children:Z(m.workforce,h.workforce)}),e.jsx("td",{className:"whitespace-nowrap px-2",children:Z(m.new_homes,h.new_homes)}),e.jsx("td",{className:"whitespace-nowrap px-2",children:Z(m.competition,h.competition)}),e.jsx("td",{className:"whitespace-nowrap px-2",children:h.capacity_factor!=null?`Ã${Number(h.capacity_factor).toFixed(3)} (${h.capacity_members>0?"+":""}${Q(h.capacity_members)})`:"â"}),e.jsx("td",{className:"whitespace-nowrap px-2 font-medium",children:Z(m.total,h.total)}),e.jsx("td",{className:"px-2",children:d.big_move?e.jsx(X,{variant:"destructive",children:Te(d.total_pct)}):Te(d.total_pct)}),e.jsxs("td",{className:"whitespace-nowrap px-2",children:[Q(h.range_low),"â",Q(h.range_high)]}),e.jsx("td",{className:"whitespace-nowrap px-2",children:d.signal_flip?e.jsxs(X,{variant:"outline",children:[je(m.signal)," â ",je(h.signal)]}):je(h.signal)}
10),e.jsxs("td",{className:"whitespace-nowrap px-2",children:[`capacity ${h.capacity_check??"â"}`,h.daytime?" · daytime":""]}),e.jsx("td",{className:"px-2",children:Q(d.client_total)})]},d.report_id)})})]})}),a.some(d=>d.error)&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"Some reports were refused by the engine in the dry run; see the error column in the impact doc."})]})}function es(){const t=j(lt),{data:s,isLoading:i}=F({queryKey:["ml-training-pool"],queryFn:()=>t()});return i||!s?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loadingâ¦"}):e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"rounded-md border border-border p-4",children:[e.jsxs("p",{className:"text-sm font-medium",children:[s.clubs," of ",s.target," clubs with member-postcode data"]}),e.jsx(Be,{value:Math.min(100,s.clubs/s.target*100),className:"mt-2"}),e.jsxs("p",{className:"mt-2 text-xs text-muted-foreground",children:[s.from_pilot," from the pilot data pack · ",s.with_membership," with a dated current membership. Reaching ",s.target," lets us re-examine paused models ",s.models.join(", ")," (still off until their own pre-registered tests pass)."]})]}),e.jsxs("table",{className:"w-full text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-muted-foreground",children:[e.jsx("th",{className:"py-1",children:"Club"}),e.jsx("th",{children:"Organisation"}),e.jsx("th",{children:"Source"}),e.jsx("th",{className:"text-right",children:"Members / postcodes"}),e.jsx("th",{className:"text-right",children:"Current membership"}),e.jsx("th",{children:"As at"})]})}),e.jsx("tbody",{children:s.list.map(o=>e.jsxs("tr",{className:"border-t border-border",children:[e.jsx("td",{className:"py-1",children:o.site}),e.jsx("td",{children:o.organisation??"â"}),e.jsx("td",{children:o.source}),e.jsx("td",{className:"text-right",children:Number(o.members).toLocaleString()}),e.jsx("td",{className:"text-right",children:o.current_membership?.toLocaleString()??"â"}),e.jsx("td",{children:o.as_at??"â"})]},o.key))})]})]})}const I=(t,s=0)=>t==null?"not stated":t.toLocaleString("en-GB",{maximumFractionDigits:s}),ce=t=>t==null?"not stated":`${t.toFixed(2)}%`;function Pe({pct:t}){if(t==null)return e.jsx("span",{className:"text-muted-foreground",children:"â"});const s=Math.abs(t)<2?"text-emerald-600 dark:text-emerald-400":Math.abs(t)<10?"text-amber-600 dark:text-amber-400":"text-destructive";return e.jsxs("span",{className:s,children:[t>0?"+":"",t.toFixed(1),"%"]})}function oe({label:t,value:s,hint:i}){return e.jsxs("div",{className:"rounded-md border border-border p-3",children:[e.jsx("div",{className:"text-[11px] uppercase tracking-wide text-muted-foreground",children:t}),e.jsx("div",{className:"mt-1 text-sm font-medium",children:s}),i&&e.jsx("div",{className:"mt-0.5 text-xs text-muted-foreground",children:i})]})}function ts({site:t}){const[s,i]=_.useState(!1),o=t.figures.reduce((r,a)=>a.delta_pct==null?r:r==null?Math.abs(a.delta_pct):Math.max(r,Math.abs(a.delta_pct)),null);return e.jsxs("article",{className:"rounded-lg border border-border",children:[e.jsxs("header",{className:"flex flex-wrap items-start justify-between gap-3 border-b border-border p-4",children:[e.jsxs("div",{children:[e.jsxs("h3",{className:"font-medium",children:[t.site,t.scenario?e.jsxs("span",{className:"text-muted-foreground",children:[" â ",t.scenario]}):null]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[t.client," · ",(t.lenses??[]).join(", ")||"no lenses recorded",t.run_at?` · last run ${new Date(t.run_at).toLocaleDateString("en-GB")}`:" · not run yet",t.demand_version?` · recompute v${t.demand_version}`:""]})]}),e.jsxs("div",{className:"flex items-center gap-3 text-sm",children:[e.jsx("span",{className:"text-muted-foreground",children:"Largest gap"}),e.jsx(Pe,{pct:o??null}),t.report_id&&e.jsx(Fe,{to:"/app/reports/$id",params:{id:t.report_id},className:"text-sm underline",children:"Open report"})]})]}),e.jsxs("div",{className:"grid gap-3 p-4 sm:grid-cols-2 lg:grid-cols-4",children:[e.jsx(oe,{label:"Catchment",value:t.catchment.definition??"not stated",hint:`${I(t.catchment.adult_population)} adults recorded${t.catchment.mosaic_types?` · ${t.catchment.mosaic_types} Mosaic Types`:""}`}),e.jsx(oe,{label:"Comparator cohort",value:t.cohort.label??"standard group",hint:`${I(t.cohort.sites)} clubs${t.cohort.steps?` · ${t.cohort.steps} narrowing steps`:""}${t.cohort.replayable?"":" · trail not replayable"}`}),e.jsx(oe,{label:"Penetration applied",value:ce(t.penetration.average_pct),hint:`client ${ce(t.penetration.historical_pct)}${t.penetration.min_pct!=null?` · range ${t.penetration.min_pct.toFixed(2)}â${t.penetration.max_pct.toFixed(2)}%`:""}${t.penetration.overrides?` · ${t.penetration.overrides} analyst overrides`:""}`}),e.jsx(oe,{label:"Uplift and drag",value:t.uplift.outside_pct==null?"not stated":`+${t.uplift.outside_pct}% outside catchment`,hint:`${I(t.uplift.outside_members)}
10 members added${t.uplift.workforce?` · workforce ${I(t.uplift.workforce)}`:""}${t.uplift.new_homes?` · new homes ${I(t.uplift.new_homes)}`:""} · competition ${t.uplift.competition_members==null?"not stated":t.uplift.competition_members===0?"none applied":`â${I(t.uplift.competition_members)}`}`})]}),e.jsx("div",{className:"overflow-x-auto border-t border-border",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-muted/50 text-left",children:e.jsxs("tr",{children:[e.jsx("th",{className:"p-3 font-medium",children:"Figure"}),e.jsx("th",{className:"p-3 text-right font-medium",children:"Client was given"}),e.jsx("th",{className:"p-3 text-right font-medium",children:"Our model"}),e.jsx("th",{className:"p-3 text-right font-medium",children:"Change"})]})}),e.jsx("tbody",{children:t.figures.map(r=>e.jsxs("tr",{className:"border-t border-border",children:[e.jsx("td",{className:"p-3",children:r.label}),e.jsx("td",{className:"p-3 text-right tabular-nums",children:r.unit==="pct"?ce(r.historical):I(r.historical)}),e.jsx("td",{className:"p-3 text-right tabular-nums",children:r.unit==="pct"?ce(r.ours):I(r.ours)}),e.jsx("td",{className:"p-3 text-right tabular-nums",children:e.jsx(Pe,{pct:r.delta_pct})})]},r.key))})]})}),(t.cohort.unmapped?.length||t.parse_warnings?.length)&&e.jsxs("div",{className:"border-t border-border p-4 text-xs text-muted-foreground",children:[e.jsxs("button",{className:"flex items-center gap-2 underline",onClick:()=>i(r=>!r),children:[e.jsx(ct,{className:"h-3.5 w-3.5"}),s?"Hide":"Show"," what we could not reproduce"]}),s&&e.jsxs("ul",{className:"mt-2 list-disc space-y-1 pl-5",children:[(t.cohort.unmapped??[]).map((r,a)=>e.jsxs("li",{children:["Cohort step not reproducible: ",r]},`u${a}`)),(t.parse_warnings??[]).map((r,a)=>e.jsx("li",{children:r},`w${a}`))]})]})]})}function Rs(){const t=j(ot),{data:s,isLoading:i,error:o}=F({queryKey:["demand-model-board"],queryFn:()=>t(),staleTime:6e4}),[r,a]=_.useState("all"),c=s?.sites??[],d=Array.from(new Set(c.map(l=>l.client))),m=r==="all"?c:c.filter(l=>l.client===r),h=c.filter(l=>l.run_at).length;return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("header",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:[e.jsx(it,{className:"h-4 w-4"})," Demand model"]}),e.jsx("h1",{className:"text-3xl font-semibold tracking-tight",children:"How each site's demand was modelled"}),e.jsx("p",{className:"max-w-3xl text-muted-foreground",children:`One card per site: the catchment it was modelled on, the comparator group its penetration rates came from, the rates applied and the uplifts and reductions on top â each figure beside the one that site's client was actually given. Anything not recorded reads as "not stated", never as zero.`})]}),e.jsxs(ze,{defaultValue:typeof window<"u"&&window.location.hash.startsWith("#impact")?"impact":"sites",children:[e.jsxs(Ve,{children:[e.jsx(z,{value:"sites",children:"Sites"}),e.jsx(z,{value:"calibration",children:"Calibration"}),e.jsx(z,{value:"data-sources",children:"Data sources"}),e.jsx(z,{value:"legacy",children:"Legacy comparison"}),e.jsx(z,{value:"run3",children:"Legacy â run 3"}),e.jsx(z,{value:"impact",children:"Engine impact"}),e.jsx(z,{value:"ml-pool",children:"ML training pool"})]}),e.jsxs(V,{value:"sites",className:"space-y-6",children:[i&&e.jsxs("p",{className:"flex items-center gap-2 text-sm text-muted-foreground",children:[e.jsx(O,{className:"h-4 w-4 animate-spin"})," Loading the modelâ¦"]}),o&&e.jsx("p",{className:"text-sm text-destructive",children:o.message}),!!c.length&&e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-sm",children:[e.jsxs("span",{className:"flex items-center gap-1 text-muted-foreground",children:[e.jsx(Ge,{className:"h-4 w-4"})," ",h," of ",c.length," sites modelled"]}),e.jsx("span",{className:"text-muted-foreground",children:"·"}),["all",...d].map(l=>e.jsx("button",{onClick:()=>a(l),className:`rounded-full border px-3 py-1 text-xs ${r===l?"border-primary bg-primary/10":"border-border hover:bg-muted"}`,children:l==="all"?"All clients":l},l))]}),e.jsx("div",{className:"space-y-4",children:m.map(l=>e.jsx(ts,{site:l},l.case_id))})]}),e.jsx(V,{value:"calibration",children:e.jsx($t,{})}),e.jsx(V,{value:"data-sources",children:e.jsxs("div",{className:"space-y-6",children:[e.jsx(Rt,{}),e.jsx(qt,{})]})}),e.jsx(V,{value:"legacy",children:e.jsx(Wt,{})}),e.jsx(V,{value:"run3",children:e.jsx(nt,{})}),e.jsx(V,{value:"impact",children:e.jsx(Zt,{})}),e.jsx(V,{value:"ml-pool",children:e.jsx(es,{})})]})]})}export{Rs as component};
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.