PageSourceSearch

https://spend360.ai/assets/roi-dashboard-DpxlWoU0.js

js spend360.ai collected 2026-10-05 15:52:25 UTC 43,444 bytes, 141 lines download raw bytes

1import{r as x,j as e,t as L,c as je,b as Ne,Y as Me,a as Ue,k as Ge,L as _e}from"./index-DjzIOXvK.js";import{T as de,h as qe,l as He,A as ne,P as Ke}from"./app-layout-hqYcwUuU.js";import{v as Qe,r as Ye,U as Je,R as ge,T as We}from"./roi-benefit.functions-C8zJu--q.js";import{I as ae}from"./input-DDlwxqAK.js";import{L as D}from"./label-DPxkNdlk.js";import{u as P}from"./useServerFn-BFCw7tvg.js";import{B as G}from"./button-BpFQ6a0a.js";import{L as Xe}from"./loader-circle-DSo0irRW.js";import{S as Ze}from"./shield-check-Dljj2tk4.js";import{C as et}from"./circle-check-FtUKtXrD.js";import{r as $e}from"./auth-middleware-D0yiOKQU.js";import{c as tt}from"./createLucideIcon-WxGQwEG1.js";import{l as st}from"./provider-keys.functions-BaQYy_VU.js";import{u as le}from"./useQuery-DuhQKVWo.js";import{g as at}from"./roi-allocations.functions-BpOe-rdS.js";import{l as rt,C as ot}from"./vendor-spend-DJy0N1M2.js";import{l as it,b as nt,d as lt}from"./roi.functions-CIdfbq-r.js";import{i as dt,t as ct,c as mt,u as w,a as ve,b as ye,d as ut}from"./roi-use-cases-D4H-SzNe.js";import{C as pt}from"./chevron-right-heRz30cp.js";import"./useRouterState-Dd-adRvV.js";import"./use-org-role-DcC7gSmn.js";import"./use-access-BNDkyNar.js";import"./plug-CV03pjS4.js";import"./wallet-B9WAdQeN.js";import"./trending-up-DK2csFOz.js";import"./users-vjPV1zhb.js";import"./x-BAe1bp4b.js";import"./dialog-3Dxb2m_v.js";import"./index-CwzhbtQv.js";import"./index-DmtKEe2m.js";import"./index-Cd7-4BTx.js";import"./index-BSbPCLMV.js";import"./index-CrF9k-hg.js";import"./index-un-fAjHK.js";import"./utils-BQHNewu7.js";import"./textarea-U8x6UELo.js";import"./select-AjUc0mZq.js";import"./index-Cla8Lmlr.js";import"./index-Bfr7faop.js";import"./index-JthLKuMH.js";import"./index-DvVDyBkh.js";import"./chevron-down-CBDFrrph.js";import"./check-CwY8R6Uy.js";import"./index-apQIIV-0.js";import"./index-LHNt3CwB.js";const xt=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]],ft=tt("file-text",xt);function ht({row:s,computed:r,onRevise:d}){const[u,c]=x.useState(!1),[m,h]=x.useState("idle"),[C,k]=x.useState(null),[I,R]=x.useState(!1),[b,$]=x.useState(""),[y,f]=x.useState(null),j=P(Qe),p=P(Ye),E=s.kind==="time-saved"?s.baseline:s.baselineRate,n=s.kind==="time-saved"?s.postAi:s.postRate;async function S(){c(!0);try{const A=await j({data:{useCaseId:s.id,name:s.name,kind:s.kind,department:s.department||null,unit:s.kind==="time-saved"?s.unit??"minutes":null,baseline:E,postAi:n,volume:s.volume,unitValue:s.unitValue,attribution:s.attribution,gross:r.gross,attributed:r.attributed,cost:typeof s.cost=="number"?s.cost:null,roi:r.roi}});R(!1),$(""),f(null),A.ok?(h("passed"),k(null)):(h("flagged"),k(A.objection))}catch(A){const M=A instanceof Error?A.message:String(A);L.error("Review unavailable",{description:M})}finally{c(!1)}}async function g(A){try{await p({data:{useCaseId:s.id,name:s.name,objection:C??"",justification:A}}),f(A?"Justification recorded in the audit trail.":"Dismissed without justification — recorded in the audit trail.")}catch(M){const re=M instanceof Error?M.message:String(M);L.error("Could not record that",{description:re})}}return e.jsxs("div",{children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs(G,{type:"button",onClick:S,disabled:u,title:"Run an AI plausibility review of these inputs",size:"sm",children:[u?e.jsx(Xe,{className:"h-3.5 w-3.5 animate-spin"}):e.jsx(Ze,{className:"h-3.5 w-3.5"}),"Validate inputs"]}),m==="passed"&&e.jsxs("span",{className:"inline-flex items-center gap-1.5 text-xs text-success",children:[e.jsx(et,{className:"h-3.5 w-3.5"}),"A second AI model reviewed these inputs and found no issues."]}),e.jsx("span",{className:"text-[11px] text-muted-foreground",children:"Optional — never blocks saving."})]}),m==="flagged"&&C&&e.jsxs("div",{className:"mt-3 space-y-3 rounded-lg border border-yellow-500/40 bg-yellow-500/10 p-3",children:[e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(de,{className:"h-4 w-4 shrink-0 text-yellow-600 dark:text-yellow-400"}),e.jsxs("div",{className:"text-xs",children:[e.jsx("p",{className:"font-semibold text-yellow-700 dark:text-yellow-300",children:"A second AI model flagged a potential issue:"}),e.jsx("p",{className:"mt-1 text-foreground",children:C})]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("button",{type:"button",onClick:()=>{R(!1),g(null),d()},className:"rounded-md border border-border bg-background px-2.5 py-1 text-xs font-medium hover:bg-muted",children:"Revise inputs"}),e.jsx("button",{type:"button",onClick:()=>R(!0),className:"rounded-md border border-border bg-background px-2.5 py-1 text-xs font-medium hover:bg-muted",children:"Add justification"})]}),I&&e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(D,{htmlFor:`${s.id}-justify`,className:"text-xs",children:"One line explaining why these inputs are correct"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(ae,{id:`${s.id}-justify`,placeholder:"e.g. Hourly rate is the blended offshore rate for this team.",value:b,onChange:A=>$(A.target.value)}),e.jsx("button",{type:"button",disabled:!b.trim(),onClick:()=>{g(b.trim())},className:"rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:opacity-90 disabled:opacity-50",children:"Save"})]})]}),y&&e.jsx("p",{className:"text-[11px] text-muted-foreground",children:y})]})]})}const bt=je({method:"POST"}).middleware([$e]).handler(Ne("e1ae6723201f7d134d0f73cbe4a3ecff30222da6a9007c0d50ef70e2fae594b7")),gt={Scale:"The use case returns more value than it costs; expand deliberately.",Maintain:"The use case covers its cost; continue running it as-is under review.",Redesign:"The use case does not yet cover its cost; revise scope, inputs or design.",Stop:"The use case costs materially more than it returns; a considered decision to retire or pause it."},vt={metered:"Metered",imported:"Imported",invoiced:"Invoiced",estimated:"Estimated"},yt={metered:"Cost taken from live provider usage metering (highest confidence).",imported:"Cost taken from uploaded provider usage data.",invoiced:"Cost taken from a provider invoice for the peri
1od.",estimated:"Cost projected from available usage (lowest confidence)."};function H(s){const r=Math.round(s),d="$"+Math.abs(r).toLocaleString("en-US");return r<0?"−"+d:d}function F(s){return s.replace(/[&<>"]/g,r=>r==="&"?"&amp;":r==="<"?"&lt;":r===">"?"&gt;":"&quot;")}function jt(s){const r=s.roiPct===null?"—":`${s.roiPct.toFixed(0)}%`,d=s.net===null?"—":H(s.net),u=[F(s.orgName),s.businessUnitName?F(s.businessUnitName):null,F(s.department)].filter(Boolean).join(" &middot; ");return`<!doctype html>
2<html lang="en"><head><meta charset="utf-8">
3<title>${F(s.refId)} — Governance Decision Record</title>
4<style>
5  @page { size: A4; margin: 18mm; }
6  * { box-sizing: border-box; }
7  body { font-family: ui-sans-serif, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
8         color: #16181d; margin: 0; padding: 32px; max-width: 820px; line-height: 1.45; }
9  .eyebrow { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: #6b7280; }
10  h1 { font-size: 22px; margin: 6px 0 2px; }
11  .scope { font-size: 12px; color: #4b5563; }
12  hr { border: 0; border-top: 1px solid #e5e7eb; margin: 20px 0; }
13  .verdict { display: inline-block; border: 1px solid #d1d5db; border-radius: 6px;
14             padding: 4px 10px; font-size: 13px; font-weight: 600; }
15  .verdict-note { font-size: 12px; color: #4b5563; margin-top: 6px; }
16  table { width: 100%; border-collapse: collapse; margin-top: 6px; }
17  th, td { text-align: left; font-size: 13px; padding: 8px 10px; border-bottom: 1px solid #eef0f3; }
18  th { font-weight: 500; color: #6b7280; width: 45%; }
19  td { font-variant-numeric: tabular-nums; font-weight: 600; }
20  .basis { font-size: 12px; color: #4b5563; margin-top: 8px; }
21  .basis b { color: #16181d; }
22  .meta { font-size: 11px; color: #6b7280; margin-top: 24px; }
23  footer { margin-top: 28px; border-top: 1px solid #e5e7eb; padding-top: 10px;
24           font-size: 10.5px; color: #6b7280; }
25  @media print { body { padding: 0; } .noprint { display: none; } }
26  .noprint { margin-bottom: 20px; }
27  button { font: inherit; padding: 6px 12px; border-radius: 6px; border: 1px solid #d1d5db;
28           background: #f9fafb; cursor: pointer; }
29</style></head>
30<body>
31  <div class="noprint"><button onclick="window.print()">Print / Save as PDF</button></div>
32
33  <div class="eyebrow">Governance Decision Record</div>
34  <h1>${F(s.useCaseName)}</h1>
35  <div class="scope">${u}</div>
36
37  <hr>
38
39  <div class="verdict">Verdict: ${F(s.verdict)}</div>
40  <div class="verdict-note">${F(gt[s.verdict])}</div>
41
42  <hr>
43
44  <table>
45    <tr><th>Gross benefit</th><td>${H(s.gross)}</td></tr>
46    <tr><th>Attributed benefit (${s.attributionPct}% attribution)</th><td>${H(s.attributedBenefit)}</td></tr>
47    <tr><th>Allocated AI cost</th><td>${H(s.allocatedCost)}</td></tr>
48    <tr><th>Other costs</th><td>${H(s.otherCosts)}</td></tr>
49    <tr><th>Total cost</th><td>${H(s.totalCost)}</td></tr>
50    <tr><th>Net value</th><td>${d}</td></tr>
51    <tr><th>ROI</th><td>${r}</td></tr>
52    <tr><th>Cost basis</th><td>${F(vt[s.costBasis])}</td></tr>
53  </table>
54  <div class="basis"><b>Cost basis:</b> ${F(yt[s.costBasis])}</div>
55
56  <div class="meta">
57    Reference ${F(s.refId)}<br>
58    Generated by ${F(s.generatedBy)} at ${F(s.generatedAtUtc.replace("T"," ").replace(/\..*/,""))} UTC
59  </div>
60
61  <footer>
62    Generated by spend360 using its Closed-Loop ROI Attribution methodology (patent-pending).
63    Based on billing metadata only; no prompts or content are accessed.
64  </footer>
65</body></html>`}function Nt(s){const r=window.open("","_blank");return r?(r.document.write(jt(s)),r.document.close(),!0):!1}function _t({useCaseId:s,verdict:r,costBasis:d,gross:u,attributionPct:c,attributedBenefit:m,allocatedCost:h,otherCosts:C,totalCost:k,net:I,roiPct:R}){const b=P(bt),[$,y]=x.useState(!1);async function f(){y(!0);try{const{record:j}=await b({data:{useCaseId:s,verdict:r,costBasis:d,gross:u,attributionPct:c,attributedBenefit:m,allocatedCost:h,otherCosts:C,totalCost:k,net:I,roiPct:R}});Nt(j)?L.success(`Record ${j.refId} generated`):L.error("Allow pop-ups to open the record.")}catch(j){L.error(j instanceof Error?j.message:"Failed to generate record")}finally{y(!1)}}return e.jsxs(G,{variant:"outline",size:"sm",onClick:f,disabled:$,children:[e.jsx(ft,{className:"mr-1.5 h-3.5 w-3.5"}),$?"Generating…":"Generate governance record"]})}const $t=je({method:"POST"}).middleware([$e]).handler(Ne("89ad4d173b045c5c7ec92bf5099eb67f72a525a6409722ee1373915395c27b10")),_=s=>s.replace(/[&<>"']/g,r=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[r]),X={Scale:"background:#dcfce7;color:#166534;border-color:#86efac",Maintain:"background:#dbeafe;color:#1e40af;border-color:#93c5fd",Redesign:"background:#fef3c7;color:#92400e;border-color:#fcd34d",Stop:"background:#fee2e2;color:#991b1b;border-color:#fca5a5"},wt={openai:"OpenAI",anthropic:"Anthropic",google:"Google (Gemini / Vertex AI)",azure:"Azure OpenAI"},V=s=>{const r=Math.round(s);
65return r<0?`-$${Math.abs(r).toLocaleString()}`:`$${r.toLocaleString()}`},Ct=s=>wt[s.trim().toLowerCase()]??s;function kt(s){const r=new Date,d=r.toISOString().slice(0,10),u=r.toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric"}),c=s.items.filter(n=>n.configured),m=c.reduce((n,S)=>n+S.aiSpend,0),h=c.reduce((n,S)=>n+S.attributed,0),C=c.reduce((n,S)=>n+S.totalCost,0),k=h-C,I=s.items.some(n=>n.fromTemplate),R=' <span class="dflt">(illustrative default)</span>',b=s.items.map(n=>n.configured?`<tr><td>${_(n.name)}</td><td>${_(n.department)}</td><td>${_(n.benefitType??"—")}</td>
66        <td class="num">${V(n.attributed)}</td><td class="num">${V(n.totalCost)}</td>
67        <td class="num ${n.net>=0?"pos":"neg"}">${V(n.net)}</td>
68        <td><span class="verdict" style="${X[n.verdict]}">${n.verdict}</span></td></tr>`:`<tr><td>${_(n.name)}</td><td>${_(n.department)}</td><td>${_(n.benefitType??"—")}</td>
69          <td colspan="4" class="muted">Inputs not entered</td></tr>`).join(""),$=s.items.map(n=>{const S=n.configured?`<table class="kv">${n.inputs.map(g=>`<tr><td>${_(g.label)}</td><td class="num">${_(g.value)}${n.fromTemplate?R:""}</td></tr>`).join("")}
70            <tr><td>AI spend by provider</td><td class="num">${n.providers.length?n.providers.map(g=>`${_(Ct(g.provider))}: ${V(g.amount)}`).join("<br/>"):"None linked"}</td></tr></table>`:'<p class="muted">Inputs not entered</p>';return`<div class="detail"><h3>${_(n.name)} <span class="muted">· ${_(n.department)}</span></h3>${S}</div>`}).join(""),y=$?$.slice(0,$.indexOf("</div>")+6):"",f=y?$.slice(y.length):"",j=`<!DOCTYPE html><html><head><meta charset="utf-8" />
71<title>spend360-roi-report-${d}</title>
72<style>
73  @page { size: letter portrait; margin: 0.7in 0.6in;
74    @bottom-left { content: "Spend360"; font: 10px sans-serif; color: #777; }
75    @bottom-right { content: "Page " counter(page); font: 10px sans-serif; color: #777; }
76    
77  }
78  * { box-sizing: border-box; margin: 0; padding: 0; }
79  body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; color: #111; font-size: 11px; line-height: 1.45; }
80  .header { display: flex; justify-content: space-between; border-bottom: 2px solid #111; padding-bottom: 14px; margin-bottom: 18px; }
81  h1 { font-size: 22px; letter-spacing: -0.3px; }
82  .meta { text-align: right; color: #555; }
83  .note { color: #555; margin-top: 4px; }
84  h2 { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: #555; margin: 20px 0 8px; }
85  .summary { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
86  .card { background: #f4f4f5; border-radius: 6px; padding: 10px; }
87  .card .l { font-size: 9px; text-transform: uppercase; color: #666; }
88  .card .v { font-size: 16px; font-weight: 700; margin-top: 2px; }
89  table { width: 100%; border-collapse: collapse; }
90  thead { display: table-header-group; }
91  tr { page-break-inside: avoid; }
92  th { text-align: left; font-size: 9px; text-transform: uppercase; color: #666; padding: 6px; border-bottom: 1px solid #ccc; }
93  td { padding: 6px; border-bottom: 1px solid #eee; vertical-align: top; word-break: break-word; }
94  .num { text-align: right; white-space: nowrap; }
95  .pos { color: #166534; } .neg { color: #991b1b; }
96  .muted { color: #777; }
97  .verdict { display: inline-block; white-space: nowrap; border: 1px solid; border-radius: 4px; padding: 1px 6px; font-weight: 600; font-size: 10px; }
98  .details-start, .detail { break-inside: avoid-page; page-break-inside: avoid; }
99  .details-start h2 { break-after: avoid-page; page-break-after: avoid; }
100  .detail { border: 1px solid #e4e4e7; border-radius: 6px; padding: 10px; margin-bottom: 10px; }
101  .detail h3 { font-size: 12px; margin-bottom: 6px; }
102  .kv td:first-child { color: #555; width: 45%; }
103  .dflt { color: #b45309; font-size: 9px; }
104  .footnote { margin-top: 10px; font-size: 10px; color: #92400e; }
105  .sample { border: 2px solid #f59e0b; background: #fffbeb; color: #92400e; font-weight: 700; text-align: center; padding: 6px; margin-bottom: 12px; }
106  .legend { break-inside: avoid; } .legend p { margin-bottom: 3px; }
107</style></head><body>
108  
109  <div class="header">
110    <div><h1>AI ROI Report</h1><div style="font-size:13px;margin-top:2px">${_(s.orgName)}</div>
111      <div class="note">Billing metadata only. No prompts or documents.</div></div>
112    <div class="meta"><div>Reporting period: ${_(s.periodLabel)}</div><div>Generated ${u}</div></div>
113  </div>
114
115  <h2>Summary</h2>
116  <div class="summary">
117    <div class="card"><div class="l">Total AI spend</div><div class="v">${V(m)}</div></div>
118    <div class="card"><div class="l">Total attributed benefit</div><div class="v pos">${V(h)}</div></div>
119    <div class="card"><div class="l">Total cost</div><div class="v">${V(C)}</div></div>
120    <div class="card"><div class="l">Net value</div><div class="v ${k>=0?"pos":"neg"}">${V(k)}</div></div>
121  </div>
122  <p class="muted" style="margin-top:6px">${c.length} of ${s.items.length} use case${s.items.length===1?"":"s"} have benefit inputs and are included in totals. Total cost is AI spend plus other costs, annualized.</p>
123  ${I?'<p class="footnote">Some inputs are illustrative defaults and have not been confirmed.</p>':""}
124
125  <h2>Use cases</h2>
126  <table><thead><tr><th>Name</th><th>Department</th><th>Benefit type</th><th class="num">Attributed benefit</th><th class="num">Total cost</th><th class="num">Net value</th><th>Verdict</th></tr></thead>
127  <tbody>${b||'<tr><td colspan="7" class="muted">No use cases.</td></tr>'}</tbody></table>
128
129  <h2>Legend</h2>
130  <div class="legend">
131    <p><span class="verdict" style="${X.Scale}">Scale</span> Delivering strong value; expand its use.</p>
132    <p><span class="verdict" style="${X.Maintain}">Maintain</span> Paying for itself; keep it running as is.</p>
133    <p><span class="verdict" style="${X.Redesign}">Redesign</span> Costing more than it returns; rework it before investing further.</p>
134    <p><span class="verdict" style="${X.Stop}">Stop</span> Costs far exceed benefit; consider retiring it.</p>
135    ${s.benefitFormulas.map(n=>`<p><strong>${_(n.label)}:</strong> ${_(n.formula)}, multiplied by attribution %.</p>`).join("")}
136  </div>
137
138  <div class="details-start"><h2>Use case details</h2>${y}</div>
139  ${f}
140  <script>window.onload = () => window.print();<\/script>
141</body></html>`,p=new Blob([j],{type:"text/html"}),E=URL.createObjectURL(p);window.open(E,"_blank","noopener,noreferrer"),setTimeout(()=>URL.revokeObjectURL(E),1e4)}const St=We.filter(s=>s!=="formula_type"&&s!=="time_unit");function At(s){return{id:s.id,name:s.name,department:s.department,category:s.category??null,formula_type:s.formula_type??null,time_unit:s.time_unit??null,baseline:s.baseline===null||s.baseline===void 0?null:Number(s.baseline),post_ai:s.post_ai===null||s.post_ai===void 0?null:Number(s.post_ai),baseline_rate:s.baseline_rate===null||s.baseline_rate===void 0?null:Number(s.baseline_rate),post_rate:s.post_rate===null||s.post_rate===void 0?null:Number(s.post_rate),volume:s.volume===null||s.volume===void 0?null:Number(s.volume),unit_value:s.unit_value===null||s.unit_value===void 0?null:Number(s.unit_value),attribution:s.attribution===null||s.attribution===void 0?null:Number(s.attribution),other_costs:s.other_costs===null||s.other_costs===void 0?null:Number(s.other_costs),linked_providers:s.linked_providers??[],template_key:s.template_key??null,from_template:s.from_template===!0}}function It(s){return s.kind==="time-saved"?s.unit==="minutes"?"((Baseline − Post-AI min) / 60) × Volume × Hourly Value":"(Baseline − Post-AI hrs) × Volume × Hourly Value":s.kind==="revenue-lift"?"(Post − Baseline conv rate) × Opportunities × Revenue / Conversion":"(Baseline − Post rate) × Volume × Cost / Event"}function Rt(s){return rt(s.map(r=>r.costBasis))}const Tt={metered:"border-success/40 bg-success/10 text-success",imported:"border-primary/40 bg-primary/10 text-primary",invoiced:"border-warning/40 bg-warning/10 text-warning",estimated:"border-border bg-muted/50 text-muted-foreground"};function Bt({items:s}){const r=s.reduce((m,h)=>m+h.totalCost,0),d=s.reduce((m,h)=>m+h.attributed,0),u=d-r,c=m=>s.filter(h=>h.costBasis===m).length;return e.jsxs("div",{children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-3 gap-4",children:[e.jsxs("div",{className:"rounded-xl border border-border bg-card p-5",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Total Portfolio Spend"}),e.jsx("div",{className:"text-2xl font-bold tabular-nums mt-1",children:w(r)})]}),e.jsxs("div",{className:"rounded-xl border border-border bg-card p-5",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Total Portfolio Value"}),e.jsx("div",{className:"text-2xl font-bold tabular-nums text-success mt-1",children:w(d)})]}),e.jsxs("div",{className:"rounded-xl border border-border bg-card p-5",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Net Portfolio Value"}),e.jsx("div",{className:"text-2xl font-bold tabular-nums mt-1 "+(u>=0?"text-success":"text-destructive"),children:w(u)}),e.jsxs("div",{className:"text-[10px] text-muted-foreground mt-1",children:[s.length," configured use case",s.length===1?"":"s"," included"]})]})]}),s.length>0&&e.jsxs("p",{className:"mt-2 text-xs text-muted-foreground",children:["Cost basis across ",s.length," configured use case",s.length===1?"":"s",":"," ",c("metered")," live-metered, ",c("imported")," imported, ",c("invoiced")," ","invoiced, ",c("estimated")," estimated."]})]})}function Ss(){qe();
141const[s,r]=x.useState({}),[d,u]=x.useState(null),[c,m]=x.useState({}),[h,C]=x.useState({}),[k,I]=x.useState({}),[R,b]=x.useState({}),[$,y]=x.useState(!1),{uc:f}=Me.useSearch(),j=Ue(),p=Ge(),{data:E,isLoading:n,isError:S}=He(),[g,A]=x.useState(90),M=P(at),re=P(it),we=P(nt),Ce=P(lt),ke=P(st),Se=P($t),[Ae,me]=x.useState(!1),{data:Z}=le({queryKey:["roi-allocations",g],queryFn:()=>M({data:{days:g}}),enabled:!!E,staleTime:0,refetchOnMount:"always"}),{data:Ie,isLoading:Q}=le({queryKey:["roi-use-cases"],queryFn:()=>re(),enabled:!!E}),{data:Re}=le({queryKey:["provider_keys"],queryFn:()=>ke(),enabled:!!E,staleTime:3e4}),Te=Re?.keys??[],oe=(Ie?.useCases??[]).map(At),Be=new Map((Z?.spend??[]).map(t=>[t.useCaseId,t]));x.useEffect(()=>{n||S||E===!1&&j({to:"/pricing"})},[n,S,E,j]);const[Fe,ue]=x.useState(null),pe=x.useRef(null);x.useEffect(()=>{if(!f||Q||pe.current===f||!oe.some(o=>o.id===f))return;b(o=>o[f]?o:{...o,[f]:!0});let t=0,i;const a=()=>{const o=document.getElementById(`uc-card-${f}`);if(o){pe.current=f,o.scrollIntoView({behavior:"smooth",block:"start"}),ue(f);for(const T of[700,1500,2500])setTimeout(()=>{const B=document.getElementById(`uc-card-${f}`);B&&Math.abs(B.getBoundingClientRect().top)>40&&B.scrollIntoView({behavior:"smooth",block:"start"})},T);i=setTimeout(()=>ue(null),3500);return}t++<40&&(i=setTimeout(a,100))};return i=setTimeout(a,50),()=>{i&&clearTimeout(i)}},[f,Q,oe.length]);function O(t,i,a){r(o=>({...o,[t]:{...o[t],[i]:a}})),I(o=>{if(!o[t])return o;const T={...o};return delete T[t],T}),St.includes(i)&&r(o=>({...o,[t]:{...o[t],from_template:!1}}))}function Le(t,i){const a=ge.find(o=>o.key===i);a&&(r(o=>({...o,[t]:{...o[t],...a.values,from_template:!0}})),m(o=>({...o,[t]:a.costPeriod})),C(o=>({...o,[t]:!0})),I(o=>({...o,[t]:`${a.department} - ${a.name}`})),L.success(`${a.department} template applied`,{description:"Illustrative defaults — confirm or edit, then save."}))}async function Ee(t){if(!t.formula_type){L.error("Pick a benefit type before saving.");return}u(t.id);try{await we({data:{id:t.id,formula_type:t.formula_type,time_unit:t.formula_type==="time-saved"?t.time_unit??"minutes":null,baseline:t.baseline,post_ai:t.post_ai,baseline_rate:t.baseline_rate,post_rate:t.post_rate,volume:t.volume,unit_value:t.unit_value,attribution:t.attribution,other_costs:t.other_costs,from_template:t.from_template===!0}}),p.setQueryData(["roi-use-cases"],i=>i&&{...i,useCases:i.useCases.map(a=>a.id===t.id?{...a,formula_type:t.formula_type,time_unit:t.formula_type==="time-saved"?t.time_unit??"minutes":null,baseline:t.baseline,post_ai:t.post_ai,baseline_rate:t.baseline_rate,post_rate:t.post_rate,volume:t.volume,unit_value:t.unit_value,attribution:t.attribution,other_costs:t.other_costs,from_template:t.from_template===!0}:a)}),r(i=>{const a={...i};return delete a[t.id],a}),I(i=>{if(!i[t.id])return i;const a={...i};return delete a[t.id],a}),L.success("Inputs saved")}catch(i){L.error(i instanceof Error?i.message:"Failed to save inputs")}finally{u(null)}}async function Oe(t){if(confirm(`Delete "${t.name}"? This removes it for your organization only.`))try{await Ce({data:{id:t.id}}),await p.invalidateQueries({queryKey:["roi-use-cases"]}),L.success("Use case deleted")}catch(i){L.error(i instanceof Error?i.message:"Failed to delete use case")}}if(S)return e.jsx(ne,{children:e.jsx("div",{className:"mx-auto max-w-lg p-6 text-sm text-destructive",children:"We couldn't verify your plan access just now. This is a temporary lookup failure, not a change to your entitlement — please retry in a moment."})});if(n||!E)return e.jsx(ne,{children:e.jsx("div",{className:"flex min-h-[40vh] items-center justify-center text-sm text-muted-foreground",children:"Checking access…"})});const ee=oe.map(t=>({...t,...s[t.id]})).map(t=>{const i=dt(t),a=ct(t),o=Be.get(t.id),T=Z?.periodDays??g,B=o?o.aiSpend/T*365:0,z=t.other_costs??0,q=B+z,Y=mt(q>0?{...a,cost:q}:a),U=Rt(o?.breakdown??[]);return{uc:t,configured:i,row:a,spend:o,aiSpend:B,other:z,totalCost:q,costBasis:U,...Y}}),Pe=ee.filter(t=>t.configured).map(t=>({totalCost:t.totalCost,attributed:t.attributed,costBasis:t.costBasis}));return e.jsxs(ne,{children:[e.jsx(Ke,{title:"AI ROI Dashboard",description:"Your organization's AI use cases. Add the benefit inputs to see value, net and decision."}),e.jsxs("div",{className:"mb-4 flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(D,{htmlFor:"roi-alloc-period",className:"text-xs text-muted-foreground",children:"AI spend period"}),e.jsxs("select",{id:"roi-alloc-period",value:g,onChange:t=>A(Number(t.target.value)),className:"h-9 rounded-md border border-input bg-background px-2 text-sm",children:[e.jsx("option",{value:30,children:"Last 30 days"}),e.jsx("option",{value:90,children:"Last 90 days"}),e.jsx("option",{value:365,children:"Last 365 days"})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(G,{variant:"outline",size:"sm",disabled:Ae||Q,onClick:async()=>{me(!0);try{const{orgName:t}=await Se(),i=(a,o="")=>
141a==null?"—":`${Number(a).toLocaleString()}${o}`;kt({orgName:t,periodLabel:`AI spend over the last ${g} days, annualized`,sample:!1,benefitFormulas:[{label:"Time Saved",formula:"(Baseline − Post-AI time) × Volume × Hourly Value"},{label:"Revenue Lift",formula:"(Post − Baseline conv rate) × Opportunities × Revenue / Conversion"},{label:"Cost Reduction",formula:"(Baseline − Post rate) × Volume × Cost / Event"}],items:ee.map(a=>{const o=a.uc.formula_type==="revenue-lift"||a.uc.formula_type==="cost-reduction",T=a.uc.time_unit==="hours"?" hrs":" min";return{name:a.uc.name,department:a.uc.department,benefitType:a.uc.formula_type?ye(a.row.kind):null,configured:a.configured,verdict:ve(a.roi),attributed:a.attributed,totalCost:a.totalCost,net:a.attributed-a.totalCost,aiSpend:a.aiSpend,fromTemplate:a.uc.from_template===!0,inputs:[{label:"Baseline",value:o?i(a.uc.baseline_rate,"%"):i(a.uc.baseline,T)},{label:"Post-AI",value:o?i(a.uc.post_rate,"%"):i(a.uc.post_ai,T)},{label:"Volume per year",value:i(a.uc.volume)},{label:"Unit value",value:a.uc.unit_value===null?"—":w(a.uc.unit_value)},{label:"Attribution",value:i(a.uc.attribution,"%")},{label:"Other costs (annual)",value:a.uc.other_costs===null?"—":w(a.uc.other_costs)}],providers:(a.spend?.breakdown??[]).map(B=>({provider:B.provider,amount:B.amount/(Z?.periodDays??g)*365}))}})})}catch(t){L.error(t instanceof Error?t.message:"Could not export the ROI report")}finally{me(!1)}},children:"Export ROI report (PDF)"}),e.jsx(G,{variant:"outline",size:"sm",onClick:()=>y(!0),children:"New use case"}),e.jsx(_e,{to:"/roi-allocations",children:e.jsx(G,{variant:"outline",size:"sm",children:"Edit AI spend allocation"})})]})]}),e.jsx(Je,{open:$,onOpenChange:y,providerKeys:Te,onSaved:()=>{p.invalidateQueries({queryKey:["roi-use-cases"]}),p.invalidateQueries({queryKey:["roi-allocations"]})}}),e.jsx(Bt,{items:Pe}),e.jsxs("div",{className:"space-y-6 mt-6",children:[Q&&e.jsx("div",{className:"text-sm text-muted-foreground",children:"Loading use cases…"}),!Q&&ee.length===0&&e.jsx("div",{className:"rounded-xl border border-dashed border-border p-6 text-sm text-muted-foreground",children:"No use cases yet. Use “Add use case” to create one."}),ee.map(({uc:t,configured:i,row:a,spend:o,aiSpend:T,other:B,totalCost:z,costBasis:q,gross:Y,attributed:U,net:J,roi:te})=>{const ie=ve(te),De=c[t.id]??"annual",xe=!!s[t.id],ze=(Z?.allocations??[]).some(N=>N.use_case_id===t.id),fe=t.attribution!==null&&(t.attribution<50||t.attribution>90);return e.jsxs("div",{id:`uc-card-${t.id}`,className:`rounded-xl border bg-card p-5 scroll-mt-6 transition-shadow duration-500 ${Fe===t.id?"border-primary ring-2 ring-primary/40 shadow-lg":"border-border"}`,children:[e.jsxs("div",{className:"flex items-start justify-between gap-4 mb-4",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-semibold tracking-tight",children:t.name}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-0.5",children:[t.department,t.category?` · ${t.category}`:"",t.formula_type?` · ${ye(a.kind)}`:""]})]}),e.jsx("div",{className:"text-right",children:i?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold "+ut(ie),children:ie}),e.jsx("div",{className:"text-xs text-muted-foreground mt-2",children:"Attributed Benefit"}),e.jsx("div",{className:"text-2xl font-bold tabular-nums text-success",children:w(U)})]}):e.jsx("span",{className:"inline-flex items-center rounded-md border border-dashed border-border bg-muted/50 px-2.5 py-0.5 text-xs font-semibold text-muted-foreground",children:"Not configured"})})]}),!i&&e.jsx("div",{className:"mb-4 rounded-lg border border-dashed border-border bg-muted/30 p-3 text-xs text-muted-foreground",children:"Add the benefit inputs below to include this use case in portfolio totals and get a Scale / Maintain / Redesign / Stop decision."}),(()=>{const N=l=>t.from_template===!0,v=t.formula_type,se=v==="revenue-lift"||v==="cost-reduction",W=R[t.id]??!1;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-3 flex flex-wrap items-end gap-3",children:[e.jsxs("div",{className:"min-w-[240px]",children:[e.jsx(D,{htmlFor:`${t.id}-template`,className:"text-[11px] text-muted-foreground",children:"Start from a template"}),e.jsxs("select",{id:`${t.id}-template`,value:"",onChange:l=>{const he=l.target.value;if(!he)return;const Ve=[t.baseline,t.post_ai,t.baseline_rate,t.post_rate,t.volume,t.unit_value,t.attribution].some(be=>be!=null);t.from_template!==!0&&Ve&&!window.confirm("This will replace your current numbers with illustrative defaults. Continue?")||Le(t.id,he)},className:"mt-1 h-9 w-full rounded-md border border-input bg-background px-2 text-sm",children:[e.jsx("option",{value:"",children:"Choose a department template…"}),ge.map(l=>e.jsxs("option",{value:l.key,children:[l.department," — ",l.name]},l.key))]})]}),k[t.id]&&e.jsxs("p",{className:"pb-2 text-[11px] font-medium text-foreground",children:["Applied: ",k[t.id]," (illustrative defaults, not saved yet)"]}),t.from_template===!0&&e.jsxs("p",{className:"text-[11px] text-muted-foreground pb-2",children:["Fields marked"," ",e.jsx("span",{className:"font-medium text-warning",children:"illustrative default"})," ","are template values, not measured data — confirm or edit, then Save."]})]}),e.jsxs("section",{className:"rounded-lg border border-border bg-muted/20 p-4",children:[e.jsx("h3",{className:"mb-3 text-sm font-semibold",children:"1. Confirm your numbers"}),e.jsxs("div",{className:"flex flex-wrap items-end gap-4",children:[e.jsxs("div",{className:"grid min-w-0 flex-1 grid-cols-1 gap-3 sm:grid-cols-2 lg:max-w-xl",children:[e.jsx(K,{id:`${t.id}-volume`,label:v==="revenue-lift"?"Opportunities / yr":"Volume / yr",value:t.volume,onChange:l=>O(t.id,"volume",l),isDefault:N()}),e.jsx(K,{id:`${t.id}-unitvalue`,label:v==="revenue-lift"?"Revenue / Conversion ($)":v==="cost-reduction"?"Cost / Event ($)":"Hourly Value ($/hr)",value:t.unit_value,onChange:l=>O(t.id,"unit_value",l),isDefault:N()})]}),i&&e.jsx(ht,{row:a,computed:{gross:Y,attributed:U,net:J,roi:te},onRevise:()=>{b(l=>({...l,[t.id]:!0})),requestAnimationFrame(()=>{const l=document.getElementById(`${t.id}-baseline`);l instanceof HTMLInputElement&&(l.focus(),l.select())})}})]}),fe&&!W&&e.jsxs("p",{className:"mt-2 inline-flex items-center gap-1 text-[11px] text-warning",children:[e.jsx(de,{className:"h-3 w-3"})," Attribution is outside the default 50–90% range — review it under Advanced."]})]}),e.jsxs("section",{className:"mt-3 rounded-lg border border-border bg-muted/20 p-4",children:[e.jsxs("button",{type:"button",onClick:()=>b(l=>({...l,[t.id]:!W})),className:"flex w-full items-center justify-between gap-3 text-left","aria-expanded":W,children:[e.jsxs("span",{children:[e.jsx("span",{className:"block text-sm font-semibold text-foreground",children:"2. Advanced assumptions"}),e.jsx("span",{className:"mt-0.5 block text-[11px] font-normal text-muted-foreground",children:"Benefit type, baseline, post-AI, and attribution"})]}),e.jsx(pt,{className:"h-4 w-4 shrink-0 text-muted-foreground transition-transform "+(W?"rotate-90":"")})]}),W&&e.jsxs("div",{className:"mt-4 border-t border-border pt-4",children:[e.jsxs("div",{className:"mb-3 flex flex-wrap items-end gap-3",children:[e.jsxs("div",{className:"min-w-[180px]",children:[e.jsxs(D,{htmlFor:`${t.id}-formula`,className:"text-[11px] text-muted-foreground",children:["Benefit type",N()?" · illustrative default":""]}),e.jsxs("select",{id:`${t.id}-formula`,value:t.formula_type??"",onChange:l=>O(t.id,"formula_type",l.target.value||null),className:"mt-1 h-9 w-full rounded-md border border-input bg-background px-2 text-sm",children:[e.jsx("option",{value:"",children:"Select…"}),e.jsx("option",{value:"time-saved",children:"Time Saved"}),e.jsx("option",{value:"revenue-lift",children:"Revenue Lift"}),e.jsx("option",{value:"cost-reduction",children:"Cost Reduction"})]})]}),v==="time-saved"&&e.jsxs("div",{className:"min-w-[140px]",children:[e.jsxs(D,{htmlFor:`${t.id}-unit`,className:"text-[11px] text-muted-foreground",children:["Time unit",N()?" · illustrative default":""]}),e.jsxs("select",{id:`${t.id}-unit`,value:t.time_unit??"minutes",onChange:l=>O(t.id,"time_unit",l.target.value),className:"mt-1 h-9 w-full rounded-md border border-input bg-background px-2 text-sm",children:[e.jsx("option",{value:"minutes",children:"Minutes"}),e.jsx("option",{value:"hours",children:"Hours"})]})]})]}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-3 gap-3",children:[se?e.jsxs(e.Fragment,{children:[e.jsx(K,{id:`${t.id}-baseline`,label:v==="revenue-lift"?"Baseline conv (%)":"Baseline rate (%)",value:t.baseline_rate,onChange:l=>O(t.id,"baseline_rate",l),isDefault:N()}),e.jsx(K,{id:`${t.id}-post`,label:v==="revenue-lift"?"Post-AI conv (%)":"Post-AI rate (%)",value:t.post_rate,onChange:l=>O(t.id,"post_rate",l),isDefault:N()})]}):e.jsxs(e.Fragment,{children:[e.jsx(K,{id:`${t.id}-baseline`,label:t.time_unit==="hours"?"Baseline (hrs)":"Baseline (min)",value:t.baseline,onChange:l=>O(t.id,"baseline",l),isDefault:N()}),e.jsx(K,{id:`${t.id}-postai`,label:t.time_unit==="hours"?"Post-AI (hrs)":"Post-AI (min)",value:t.post_ai,onChange:l=>O(t.id,"post_ai",l),isDefault:N()})]}),e.jsx(Lt,{id:t.id,value:t.attribution,onChange:l=>O(t.id,"attribution",l),attrOutOfRange:fe,isDefault:N()})]})]})]})]})})(),e.jsx(Ft,{rowId:t.id,aiSpend:T,other:B,totalCost:z,period:De,periodIsDefault:t.from_template===!0&&h[t.id]===!0,onOtherChange:N=>O(t.id,"other_costs",N),onPeriodChange:N=>{m(v=>({...v,[t.id]:N})),C(v=>({...v,[t.id]:!1})),I(v=>{if(!v[t.id])return v;const se={...v};return delete se[t.id],se})},spendSource:o?o.source:"estimated",hasCustomAllocation:ze,costBasis:q,breakdown:o?.breakdown??[],periodDays:g,noBenefitNumbers:!i}),e.jsxs("div",{className:"mt-3 flex flex-wrap items-center gap-2",children:[e.jsx(G,{size:"sm",disabled:!xe||d===t.id,onClick:()=>Ee(t),children:d===t.id?"Saving…":xe?"Save inputs":"Saved"}),e.jsx(G,{size:"sm",variant:"ghost",onClick:()=>Oe(t),children:"Delete"})]}),i&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mt-3 grid grid-cols-1 sm:grid-cols-3 gap-3",children:[e.jsxs("div",{className:"rounded-lg bg-muted/50 p-3",children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:"Gross Benefit"}),e.jsx("div",{className:"text-lg font-semibold tabular-nums",children:w(Y)}),e.jsx("div",{className:"text-[10px] text-muted-foreground mt-0.5",children:It(a)})]}),e.jsxs("div",{className:"rounded-lg bg-muted/50 p-3",children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:"Attributed Benefit"}),e.jsx("div",{className:"text-lg font-semibold tabular-nums text-success",children:w(U)}),e.jsx("div",{className:"text-[10px] text-muted-foreground mt-0.5",children:"Gross × Attribution %"})]}),J!==null?e.jsxs("div",{className:"rounded-lg bg-muted/50 p-3",children:[e.jsxs("div",{className:"text-[11px] text-muted-foreground",children:["Net Value (after ",w(z)," total cost of ownership)"]}),e.jsx("div",{className:"text-lg font-semibold tabular-nums "+(J>=0?"":"text-destructive"),children:w(J)}),e.jsxs("div",{className:"text-[10px] text-muted-foreground mt-0.5",children:["ROI:"," ",e.jsxs("span",{className:"tabular-nums font-medium",children:[te.toFixed(0),"%"]}),z>0&&U/z>20&&e.jsxs("span",{className:"ml-2 inline-flex items-start gap-1 font-medium text-warning",children:[e.jsx(de,{className:"h-3 w-3"}),`AI spend estimate may be too low for this use case's volume — consider setting "Other costs" manually.`]})]})]}):e.jsxs("div",{className:"rounded-lg border border-dashed border-border p-3",children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:"Net Value / ROI"}),e.jsx("div",{className:"text-xs text-muted-foreground mt-1",children:"No allocated cost yet. Allocate AI spend or add other costs to compute net value and ROI."})]})]}),e.jsx("div",{className:"mt-4 flex justify-end",children:e.jsx(_t,{useCaseId:t.id,verdict:ie,costBasis:q,gross:Y,attributionPct:a.attribution,attributedBenefit:U,allocatedCost:T,otherCosts:B,totalCost:z,net:J,roiPct:te})})]})]},t.id)})]})]})}function Ft({rowId:s,aiSpend:r,other:d,totalCost:u,period:c,periodIsDefault:m,onOtherChange:h,onPeriodChange:C,spendSource:k,hasCustomAllocation:I,costBasis:R,breakdown:b,periodDays:$,noBenefitNumbers:y=!1}){const f=k==="allocated"?"Allocated":"Estimated",j=ot[R];return e.jsxs("section",{className:"mt-3 rounded-lg border border-border bg-muted/20 p-4",children:[e.jsx("h3",{className:"mb-3 text-sm font-semibold",children:"3. Cost"}),e.jsxs("div",{className:"flex flex-wrap items-end gap-3",children:[e.jsxs("div",{className:"min-w-[160px]",children:[e.jsxs("div",{className:"flex items-center gap-1.5 text-[11px] text-muted-foreground",children:[e.jsx("span",{children:"AI spend (auto)"}),e.jsx("span",{title:k==="allocated"?"Derived from your saved provider allocation percentages.":"No allocation saved yet — split evenly across use cases linking each provider.",className:"rounded-full border border-border bg-muted px-1.5 py-0.5 text-[9px] font-medium leading-none",children:f}),e.jsx("span",{title:j.help,className:"rounded-full border px-1.5 py-0.5 text-[9px] font-medium leading-none "+Tt[R],children:j.label})]}),e.jsx("div",{className:"mt-1 h-9 flex items-center rounded-md bg-muted/50 px-3 text-sm font-medium tabular-nums",children:y&&r===0?e.jsx("span",{className:"text-muted-foreground",title:"Add benefit numbers to receive spend",children:"—"}):w(r)}),!I&&e.jsxs("p",{className:"mt-1.5 text-[10px] text-muted-foreground",children:["Equal split by default."," ",e.jsx(_e,{to:"/roi-allocations",className:"font-medium text-primary hover:underline",children:"Edit allocation"})]})]}),e.jsxs("div",{className:"min-w-[160px]",children:[e.jsx(D,{htmlFor:`${s}-other-costs`,className:"text-[11px] text-muted-foreground",children:"Other 
141costs"}),e.jsx(ae,{id:`${s}-other-costs`,type:"number",min:0,value:d,onChange:p=>h(Math.max(0,Number(p.target.value)||0)),className:"mt-1 h-9 tabular-nums"})]}),e.jsxs("div",{className:"min-w-[180px]",children:[e.jsx(D,{htmlFor:`${s}-cost-period`,className:"text-[11px] text-muted-foreground",children:"Period"}),e.jsxs("select",{id:`${s}-cost-period`,value:c,onChange:p=>C(p.target.value),className:"mt-1 h-9 w-full rounded-md border border-input bg-background px-2 text-sm",children:[e.jsx("option",{value:"annual",children:"Annual run rate"}),e.jsx("option",{value:"one-time",children:"Includes one-time costs"})]}),m&&e.jsx(ce,{})]}),e.jsxs("div",{className:"min-w-[180px]",children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:"Total cost of ownership"}),e.jsx("div",{className:"mt-1 h-9 flex items-center text-sm font-semibold tabular-nums",children:w(u)})]})]}),b.length>0?e.jsxs("details",{className:"mt-2 group",children:[e.jsxs("summary",{className:"cursor-pointer text-[10px] text-muted-foreground hover:text-foreground",children:["Show AI spend breakdown (",b.length," provider",b.length===1?"":"s",", last ",$," days)"]}),e.jsxs("table",{className:"mt-2 w-full text-[11px]",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-muted-foreground text-left",children:[e.jsx("th",{className:"font-normal py-1",children:"Provider"}),e.jsx("th",{className:"font-normal py-1 text-right",children:"Org spend"}),e.jsx("th",{className:"font-normal py-1 text-right",children:"Percent"}),e.jsx("th",{className:"font-normal py-1 text-right",children:"Amount"})]})}),e.jsx("tbody",{children:b.map(p=>e.jsxs("tr",{className:"border-t border-border/60",children:[e.jsx("td",{className:"py-1 capitalize",children:p.provider}),e.jsx("td",{className:"py-1 text-right tabular-nums",children:w(p.orgSpend)}),e.jsxs("td",{className:"py-1 text-right tabular-nums",children:[p.percent.toFixed(1),"%"]}),e.jsx("td",{className:"py-1 text-right tabular-nums",children:y&&p.amount===0?e.jsx("span",{title:"Add benefit numbers to receive spend",children:"—"}):w(p.amount)})]},p.provider))})]})]}):e.jsx("p",{className:"text-[10px] text-muted-foreground mt-2",children:"No provider spend allocated to this use case yet. Link providers and set allocation percentages to compute real AI spend."}),c==="one-time"&&e.jsx("p",{className:"text-[10px] text-warning-foreground mt-1",children:"Gross benefit is annual, so this comparison spans different periods."})]})}function ce(){return e.jsx("p",{className:"text-[10px] font-medium text-warning",children:"Illustrative default, confirm or edit"})}function K({id:s,label:r,value:d,onChange:u,isDefault:c}){return e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(D,{htmlFor:s,className:"text-xs",children:r}),e.jsx(ae,{id:s,type:"number",inputMode:"decimal",min:0,placeholder:"—",value:d===null?"":d,onChange:m=>u(m.target.value===""?null:Number(m.target.value))}),c&&e.jsx(ce,{})]})}function Lt({id:s,value:r,onChange:d,attrOutOfRange:u,isDefault:c}){return e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(D,{htmlFor:`${s}-attr`,className:"text-xs",children:"Attribution (%)"}),e.jsx(ae,{id:`${s}-attr`,type:"number",inputMode:"decimal",min:0,max:100,placeholder:"—",value:r===null?"":r,onChange:m=>d(m.target.value===""?null:Number(m.target.value)),className:u?"border-yellow-500/60 focus-visible:ring-yellow-500/40":void 0}),c&&e.jsx(ce,{}),e.jsx("p",{className:"text-[10px] text-muted-foreground",children:"Default range 50–90%."})]})}export{Ss 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.