// Clusters page + Cluster detail + New-cluster dialog
// Concept: multiple projects roll up into a cluster (client / dept / product line).

const CLUSTER_PALETTE = [
  { id:"none",   color:"transparent", line:"var(--line-2)",  swatch:"none" },
  { id:"indigo", color:"#5b50ee",     line:"#5b50ee",       swatch:"solid" },
  { id:"green",  color:"#0f8a4f",     line:"#0f8a4f",       swatch:"solid" },
  { id:"amber",  color:"#b9710d",     line:"#b9710d",       swatch:"solid" },
  { id:"red",    color:"#c93a3a",     line:"#c93a3a",       swatch:"solid" },
  { id:"blue",   color:"#4285f4",     line:"#4285f4",       swatch:"solid" },
  { id:"purple", color:"#9b5cf6",     line:"#9b5cf6",       swatch:"solid" },
  { id:"orange", color:"#d97757",     line:"#d97757",       swatch:"solid" },
  { id:"teal",   color:"#10a37f",     line:"#10a37f",       swatch:"solid" },
];

// Mock clusters mapped onto existing PROJECTS data
const CLUSTERS = [
  {
    id:"meridian-legal", name:"Meridian Legal", client:"Meridian Legal LLP",
    color:"#5b50ee", projectSlugs:["contract-ai","email-classifier","cv-screener"],
    members:["ap","jl"], owner:"ap", budget:400, createdAt:"2026-01-04",
    description:"Contract review, email classification, and candidate screening tools.",
    tags:["client","legal","ai-automation"],
  },
  {
    id:"foxgrove", name:"Foxgrove Studio", client:"Foxgrove Studio",
    color:"#d97757", projectSlugs:["document-processor","content-generator","translation-api","image-describer"],
    members:["ap","sm"], owner:"ap", budget:200, createdAt:"2026-02-14",
    description:"Document processing pipeline, content generation, and multilingual APIs.",
    tags:["client","media","content"],
  },
  {
    id:"arcline", name:"Arcline Systems", client:"Arcline Systems",
    color:"#0f8a4f", projectSlugs:["chat-support-bot","data-extractor","onboarding-flow"],
    members:["jl"], owner:"jl", budget:150, createdAt:"2026-03-01",
    description:"Customer support automation and data extraction for enterprise workflows.",
    tags:["client","enterprise","automation"],
  },
  {
    id:"cairn", name:"Cairn Analytics", client:"Cairn Analytics",
    color:"#4285f4", projectSlugs:["research-agent","sql-assistant","sentiment-tagger"],
    members:["ap","sm"], owner:"ap", budget:80, createdAt:"2026-03-20",
    description:"Research synthesis, SQL query assistant, and sentiment analysis.",
    tags:["client","analytics","data"],
  },
  {
    id:"internal", name:"Internal", client:"Meridian Studio",
    color:"#9b5cf6", projectSlugs:["code-reviewer","meeting-notes","test-harness","sandbox"],
    members:["ap","jl","sm"], owner:"ap", budget:60, createdAt:"2026-01-01",
    description:"Internal productivity tools, code review, and engineering sandbox.",
    tags:["internal","ops"],
  },
];

// Projects NOT in any cluster
function unclusteredProjects(){
  const claimed = new Set(CLUSTERS.flatMap(c => c.projectSlugs));
  return PROJECTS.filter(p => !claimed.has(p.slug));
}

// Aggregate a cluster's stats
function clusterStats(c){
  const projects = c.projectSlugs.map(s => PROJECTS.find(p => p.slug === s)).filter(Boolean);
  const spend     = projects.reduce((s,p)=>s+p.spend, 0);
  const requests  = projects.reduce((s,p)=>s+p.requests, 0);
  const activeCount = projects.filter(p => p.status === "active").length;
  const lastActive = projects.reduce((m,p) => {
    const days = parseInt(p.lastActive) || 99;
    return Math.min(m, days);
  }, 99);
  const utilisation = spend / c.budget;
  return { projects, spend, requests, activeCount, lastActive, utilisation };
}

function Clusters({ setScreen, setCluster }){
  const [search, setSearch] = useState("");
  const [view, setView] = useState("grid"); // grid | list
  const [sort, setSort] = useState("spend"); // spend | projects | recent | name
  const [showNew, setShowNew] = useState(false);

  let rows = CLUSTERS.map(c => ({ ...c, ...clusterStats(c) }));
  if (search) rows = rows.filter(c => c.name.toLowerCase().includes(search.toLowerCase()) || c.client.toLowerCase().includes(search.toLowerCase()));
  rows.sort((a,b) => {
    if (sort === "projects") return b.projects.length - a.projects.length;
    if (sort === "name")     return a.name.localeCompare(b.name);
    if (sort === "recent")   return a.lastActive - b.lastActive;
    return b.spend - a.spend;
  });

  const totalClusters  = CLUSTERS.length;
  const totalProjects  = CLUSTERS.reduce((s,c)=>s+c.projectSlugs.length, 0);
  const totalSpend     = rows.reduce((s,c)=>s+c.spend, 0);
  const unclust = unclusteredProjects();
  const unclustSpend = unclust.reduce((s,p)=>s+p.spend, 0);

  return (
    <div data-screen-label="03b Clusters" style={{ padding:"24px 28px 40px", maxWidth:1380, margin:"0 auto", display:"flex", flexDirection:"column", gap:20 }}>
      {/* Header */}
      <header style={{ display:"flex", alignItems:"flex-end", justifyContent:"space-between", gap:16 }}>
        <div>
          <div style={{ fontSize:11, letterSpacing:0.08, textTransform:"uppercase", color:"var(--fg-3)", fontWeight:600, marginBottom:6 }}>Workspace</div>
          <h1 style={{ margin:0, fontSize:28, fontWeight:600, letterSpacing:-0.5 }}>Clusters</h1>
          <div style={{ color:"var(--fg-2)", fontSize:13, marginTop:5 }}>Group projects by client, department, or product line · roll up budgets, reports, and access</div>
        </div>
        <div style={{ display:"flex", gap:8 }}>
          <PeriodSwitcher/>
          <button style={btnSecondary()}><Icon name="download" size={13}/> Export</button>
          <button style={btnPrimary()} onClick={()=>setShowNew(true)}><Icon name="plus" size={14}/> New cluster</button>
        </div>
      </header>

      {/* KPI strip */}
      <div className="card" style={{ padding:0, display:"grid", gridTemplateColumns:"repeat(4, 1fr)", overflow:"hidden" }}>
        <CKPI label="Clusters"          value={totalClusters} sub={`across ${totalProjects} project${totalProjects!==1?"s":""}`} icon="layers"/>
        <CKPI label="Period spend"      value={<Money value={totalSpend} size="lg"/>} sub={<><span className="mono">{((totalSpend/PERIOD.totalGBP)*100).toFixed(0)}%</span> of workspace</>} icon="wallet" border raw/>
        <CKPI label="Top cluster"       value={rows[0].name}  sub={<><Money value={rows[0].spend} size="sm" strong={false}/> · <span className="mono">{rows[0].projects.length}</span> projects</>} icon="starOn" border accent raw/>
        <UnclusteredKPI count={unclust.length} spend={unclustSpend} setScreen={setScreen} border/>
      </div>

      {/* Filter bar */}
      <section className="card" style={{ padding:"12px 18px", display:"flex", flexWrap:"wrap", alignItems:"center", gap:12 }}>
        <div style={{ position:"relative", width:280 }}>
          <span style={{ position:"absolute", left:10, top:"50%", transform:"translateY(-50%)", color:"var(--fg-3)" }}><Icon name="search" size={13} stroke="var(--fg-3)"/></span>
          <input
            placeholder="Search clusters or clients…"
            value={search}
            onChange={e=>setSearch(e.target.value)}
            style={{ height:32, padding:"0 10px 0 32px", width:"100%", border:"1px solid var(--line-2)", borderRadius:8, background:"#fff", fontSize:12.5, outline:"none" }}
          />
        </div>
        <Segmented value={sort} onChange={setSort} options={[
          { id:"spend",    label:"Spend" },
          { id:"projects", label:"Projects" },
          { id:"recent",   label:"Last active" },
          { id:"name",     label:"Name" },
        ]}/>
        <div style={{ flex:1 }}/>
        <span style={{ fontSize:11.5, color:"var(--fg-2)" }}>{rows.length} of {CLUSTERS.length}</span>
        <div style={{ width:1, height:20, background:"var(--line-1)", margin:"0 4px" }}/>
        <span style={{ fontSize:11, color:"var(--fg-3)", textTransform:"uppercase", letterSpacing:0.08, fontWeight:600 }}>View</span>
        <Segmented value={view} onChange={setView} options={[
          { id:"grid", label:"Grid" },
          { id:"list", label:"List" },
        ]}/>
      </section>

      {/* Clusters */}
      {view === "grid" ? (
        <div style={{ display:"grid", gridTemplateColumns:"repeat(2, minmax(0, 1fr))", gap:14 }}>
          {rows.map(c => <ClusterCard key={c.id} c={c} onOpen={()=>{ setCluster(c.id); setScreen("cluster-detail"); }}/>)}
        </div>
      ) : (
        <section className="card" style={{ padding:0, overflow:"hidden" }}>
          <div style={{ display:"grid", gridTemplateColumns:"28px minmax(220px, 1.4fr) minmax(140px, 1fr) 110px 110px 130px 110px 14px", gap:14, padding:"11px 18px", fontSize:10.5, letterSpacing:0.06, textTransform:"uppercase", color:"var(--fg-2)", fontWeight:500, borderBottom:"1px solid var(--line-1)", background:"rgba(20,16,8,0.012)" }}>
            <div></div><div>Cluster</div><div>Client</div><div className="right">Projects</div><div className="right">Period spend</div><div>Utilisation</div><div className="right">Last active</div><div></div>
          </div>
          {rows.map((c, i) => <ClusterRow key={c.id} c={c} divider={i>0} onOpen={()=>{ setCluster(c.id); setScreen("cluster-detail"); }}/>)}
        </section>
      )}

      {/* Unclustered projects strip */}
      {unclust.length > 0 && <UnclusteredStrip projects={unclust} totalSpend={unclustSpend}/>}

      {/* New cluster modal */}
      {showNew && <NewClusterDialog onClose={()=>setShowNew(false)}/>}
    </div>
  );
}

// ── KPI tiles ────────────────────────────────────────────
function CKPI({ label, value, sub, icon, border, accent, raw }){
  return (
    <div style={{ padding:"16px 20px", borderLeft: border ? "1px solid var(--line-1)" : "none", background: accent ? "linear-gradient(135deg, rgba(91,80,238,0.04), transparent 80%)" : "transparent" }}>
      <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:8 }}>
        <span style={{ display:"inline-flex", alignItems:"center", gap:7, fontSize:10.5, letterSpacing:0.08, textTransform:"uppercase", color:"var(--fg-3)", fontWeight:600 }}>
          <Icon name={icon} size={12.5} stroke={accent ? "var(--accent)" : "var(--fg-3)"}/>{label}
        </span>
      </div>
      <div style={{ display:"flex", alignItems:"baseline", gap:8 }}>
        {raw ? value : <span className="mono" style={{ fontSize:22, fontWeight:600, color:"var(--fg-0)", letterSpacing:-0.3 }}>{value}</span>}
      </div>
      <div style={{ fontSize:11, color:"var(--fg-2)", marginTop:5 }}>{sub}</div>
    </div>
  );
}

function UnclusteredKPI({ count, spend, setScreen, border }){
  const tone = count > 0 ? "warn" : "neutral";
  return (
    <div style={{ padding:"16px 20px", borderLeft: border ? "1px solid var(--line-1)" : "none", background: count > 0 ? "linear-gradient(180deg, var(--warn-soft), transparent 60%)" : "transparent" }}>
      <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:8 }}>
        <span style={{ display:"inline-flex", alignItems:"center", gap:7, fontSize:10.5, letterSpacing:0.08, textTransform:"uppercase", color:"var(--fg-3)", fontWeight:600 }}>
          <Icon name="alert" size={12.5} stroke={count > 0 ? "var(--warn)" : "var(--fg-3)"}/>Unclustered
        </span>
      </div>
      <div style={{ display:"flex", alignItems:"baseline", gap:8 }}>
        <span className="mono" style={{ fontSize:22, fontWeight:600, color: count > 0 ? "var(--warn)" : "var(--fg-0)", letterSpacing:-0.3 }}>{count}</span>
        <Money value={spend} size="sm" strong={false}/>
      </div>
      <div style={{ fontSize:11, color:"var(--fg-2)", marginTop:5, display:"flex", justifyContent:"space-between", alignItems:"center" }}>
        <span>projects · {fmtGBP(spend)}</span>
        {count > 0 && <button style={{ ...btnSubtle(), color:"var(--accent)", padding:0, fontSize:11 }} onClick={()=>setScreen("projects")}>Assign <Icon name="arrow" size={11} stroke="var(--accent)"/></button>}
      </div>
    </div>
  );
}

// ── Cluster card (grid view) ────────────────────────────
function ClusterCard({ c, onOpen }){
  const series = c.projects.length ? makeSeries(c.spend, 11, "rising") : Array(11).fill(0);
  const topProjects = [...c.projects].sort((a,b)=>b.spend-a.spend).slice(0,4);
  const over = c.utilisation > 1;
  const watch = c.utilisation > 0.85;

  return (
    <article
      onClick={onOpen}
      style={{
        position:"relative",
        background:"var(--bg-2)", border:"1px solid var(--line-1)",
        borderRadius:10, boxShadow:"var(--sh-1)",
        padding:0,
        cursor:"pointer", transition:"transform 120ms ease, box-shadow 120ms ease, border-color 120ms ease",
        overflow:"hidden",
        display:"flex", flexDirection:"column",
      }}
      onMouseEnter={e=>{ e.currentTarget.style.transform="translateY(-1px)"; e.currentTarget.style.boxShadow="var(--sh-2)"; e.currentTarget.style.borderColor="var(--line-2)" }}
      onMouseLeave={e=>{ e.currentTarget.style.transform="translateY(0)"; e.currentTarget.style.boxShadow="var(--sh-1)"; e.currentTarget.style.borderColor="var(--line-1)" }}
    >
      {/* Coloured top stripe */}
      <span style={{ position:"absolute", top:0, left:0, right:0, height:3, background:c.color }}/>

      {/* Header row */}
      <div style={{ padding:"16px 18px 12px", display:"grid", gridTemplateColumns:"40px 1fr auto", gap:12, alignItems:"flex-start" }}>
        <div style={{ width:40, height:40, borderRadius:9, background:c.color, color:"#fff", display:"flex", alignItems:"center", justifyContent:"center", fontSize:16, fontWeight:600, boxShadow:"0 1px 0 rgba(255,255,255,0.18) inset" }}>{c.name.charAt(0)}</div>
        <div style={{ minWidth:0 }}>
          <div style={{ display:"flex", alignItems:"center", gap:8 }}>
            <h3 style={{ margin:0, fontSize:15, fontWeight:600, color:"var(--fg-0)", letterSpacing:-0.2 }}>{c.name}</h3>
            {c.tags.includes("internal") && <span className="badge badge--ghost" style={{ fontSize:10 }}>internal</span>}
            {c.tags.includes("client") && <span className="badge badge--accent" style={{ fontSize:10 }}>client</span>}
          </div>
          <div style={{ fontSize:11.5, color:"var(--fg-2)", marginTop:3 }}>{c.client}</div>
        </div>
        <div style={{ textAlign:"right" }}>
          <Money value={c.spend} size="lg"/>
          <div style={{ fontSize:10.5, color:"var(--fg-3)", marginTop:2 }} className="mono">
            of <span style={{ color:"var(--fg-2)" }}>£{c.budget}</span> budget
          </div>
        </div>
      </div>

      {/* Budget utilisation */}
      <div style={{ padding:"0 18px 14px" }}>
        <div style={{ position:"relative", height:6, background:"var(--bg-3)", borderRadius:99, overflow:"hidden" }}>
          <div style={{ position:"absolute", left:0, top:0, bottom:0, width:Math.min(100, c.utilisation*100)+"%", background: over ? "var(--neg)" : watch ? "var(--warn)" : c.color, borderRadius:99 }}/>
        </div>
        <div style={{ display:"flex", justifyContent:"space-between", marginTop:5, fontSize:10.5, color:"var(--fg-3)" }}>
          <span className="mono">{(c.utilisation*100).toFixed(0)}% used</span>
          <span className={over?"badge badge--neg":watch?"badge badge--warn":"badge badge--pos"} style={{ fontSize:9.5, padding:"1px 6px" }}>
            {over ? "over budget" : watch ? "watch" : "on track"}
          </span>
        </div>
      </div>

      {/* Stats strip */}
      <div style={{ display:"grid", gridTemplateColumns:"repeat(4, 1fr)", padding:"10px 18px", background:"rgba(20,16,8,0.012)", borderTop:"1px solid var(--line-1)", borderBottom:"1px solid var(--line-1)" }}>
        <Stat label="Projects" value={c.projects.length} icon="folder"/>
        <Stat label="Active"   value={`${c.activeCount}/${c.projects.length}`} icon="dot"/>
        <Stat label="Requests" value={c.requests.toLocaleString()} icon="activity"/>
        <Stat label="Members"  value={c.members.length} icon="user"/>
      </div>

      {/* Top projects chips + sparkline */}
      <div style={{ padding:"12px 18px 14px", display:"flex", flexDirection:"column", gap:10, flex:1 }}>
        <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center" }}>
          <span style={{ fontSize:10.5, color:"var(--fg-3)", textTransform:"uppercase", letterSpacing:0.06, fontWeight:600 }}>Top projects</span>
          <Sparkline data={series} w={70} h={14} color={c.color} fill={false}/>
        </div>
        <div style={{ display:"flex", flexWrap:"wrap", gap:6 }}>
          {topProjects.map(p => (
            <span key={p.slug} style={{ display:"inline-flex", alignItems:"center", gap:6, padding:"3px 9px 3px 7px", borderRadius:99, background:"var(--bg-3)", border:"1px solid var(--line-1)", fontSize:11, color:"var(--fg-1)", maxWidth:160, overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap" }}>
              <Icon name="folder" size={10} stroke="var(--fg-3)"/>
              <span className="mono" style={{ overflow:"hidden", textOverflow:"ellipsis" }}>{p.name}</span>
              <span style={{ color:"var(--fg-3)" }} className="mono">£{p.spend.toFixed(p.spend<1?2:0)}</span>
            </span>
          ))}
          {c.projects.length > 4 && (
            <span style={{ display:"inline-flex", alignItems:"center", padding:"3px 9px", borderRadius:99, background:"transparent", border:"1px dashed var(--line-2)", fontSize:11, color:"var(--fg-3)" }} className="mono">
              +{c.projects.length - 4} more
            </span>
          )}
        </div>
      </div>

      {/* Footer */}
      <div style={{ padding:"10px 18px", borderTop:"1px solid var(--line-1)", display:"flex", alignItems:"center", justifyContent:"space-between" }}>
        <div style={{ display:"flex", alignItems:"center", gap:8 }}>
          <MemberStack ids={c.members}/>
          <span style={{ fontSize:11, color:"var(--fg-3)" }} className="mono">last active <span style={{ color:"var(--fg-2)" }}>{c.lastActive < 99 ? `${c.lastActive}d ago` : "never"}</span></span>
        </div>
        <button onClick={e=>{ e.stopPropagation(); onOpen(); }} style={{ ...btnSubtle(), color:"var(--accent)", padding:0 }}>
          Open <Icon name="arrow" size={11} stroke="var(--accent)"/>
        </button>
      </div>
    </article>
  );
}

function Stat({ label, value, icon }){
  return (
    <div style={{ display:"flex", flexDirection:"column", gap:2, paddingRight:8 }}>
      <span style={{ display:"inline-flex", alignItems:"center", gap:5, fontSize:9.5, color:"var(--fg-3)", textTransform:"uppercase", letterSpacing:0.06, fontWeight:600 }}>
        <Icon name={icon} size={10} stroke="var(--fg-3)"/>{label}
      </span>
      <span className="mono" style={{ fontSize:13, fontWeight:600, color:"var(--fg-0)" }}>{value}</span>
    </div>
  );
}

function MemberStack({ ids }){
  return (
    <div style={{ display:"flex" }}>
      {ids.slice(0,3).map((id, i) => (
        <div key={id} style={{ marginLeft: i===0 ? 0 : -8, zIndex:3-i, border:"2px solid #fff", borderRadius:"50%", display:"inline-block" }}>
          <Avatar seed={id} name={id==="vk"?"Alex Pemberton":id==="sm"?"Jamie Lowe":id} size={22}/>
        </div>
      ))}
      {ids.length > 3 && <span style={{ marginLeft:-8, width:22, height:22, borderRadius:"50%", border:"2px solid #fff", background:"var(--bg-3)", color:"var(--fg-2)", fontSize:9, fontWeight:600, display:"inline-flex", alignItems:"center", justifyContent:"center" }}>+{ids.length-3}</span>}
    </div>
  );
}

// ── Cluster list row ────────────────────────────────────
function ClusterRow({ c, divider, onOpen }){
  const over = c.utilisation > 1;
  const watch = c.utilisation > 0.85;
  return (
    <button
      onClick={onOpen}
      style={{
        appearance:"none", border:"none", background:"transparent",
        width:"100%", padding:"13px 18px", textAlign:"left",
        display:"grid", gridTemplateColumns:"28px minmax(220px, 1.4fr) minmax(140px, 1fr) 110px 110px 130px 110px 14px",
        gap:14, alignItems:"center",
        borderTop: divider ? "1px solid var(--line-1)" : "none",
        cursor:"pointer", transition:"background 80ms ease",
      }}
      onMouseEnter={e=>e.currentTarget.style.background="rgba(20,16,8,0.025)"}
      onMouseLeave={e=>e.currentTarget.style.background="transparent"}
    >
      <span style={{ width:24, height:24, borderRadius:6, background:c.color, color:"#fff", display:"inline-flex", alignItems:"center", justifyContent:"center", fontSize:11, fontWeight:600 }}>{c.name.charAt(0)}</span>
      <div style={{ display:"flex", flexDirection:"column", gap:1, minWidth:0 }}>
        <span style={{ fontSize:13, fontWeight:500, color:"var(--fg-0)" }}>{c.name}</span>
        <span style={{ fontSize:11, color:"var(--fg-3)" }}>{c.tags.join(" · ")}</span>
      </div>
      <span style={{ fontSize:12.5, color:"var(--fg-1)" }}>{c.client}</span>
      <div className="right" style={{ display:"flex", flexDirection:"column", gap:1, alignItems:"flex-end" }}>
        <span className="mono" style={{ fontSize:13, color:"var(--fg-0)", fontWeight:500 }}>{c.projects.length}</span>
        <span className="mono" style={{ fontSize:10.5, color:"var(--fg-3)" }}>{c.activeCount} active</span>
      </div>
      <div className="right"><Money value={c.spend} size="sm"/></div>
      <div style={{ display:"flex", alignItems:"center", gap:8 }}>
        <div style={{ flex:1, height:5, background:"var(--bg-3)", borderRadius:99, position:"relative", overflow:"hidden" }}>
          <div style={{ position:"absolute", left:0, top:0, bottom:0, width:Math.min(100, c.utilisation*100)+"%", background: over?"var(--neg)":watch?"var(--warn)":c.color, borderRadius:99 }}/>
        </div>
        <span className="mono" style={{ fontSize:11, color: over?"var(--neg)":watch?"var(--warn)":"var(--fg-2)", minWidth:32, textAlign:"right" }}>{(c.utilisation*100).toFixed(0)}%</span>
      </div>
      <span className="right mono" style={{ fontSize:11.5, color:"var(--fg-2)" }}>{c.lastActive < 99 ? `${c.lastActive}d ago` : "—"}</span>
      <Icon name="chevron" size={13} stroke="var(--fg-3)"/>
    </button>
  );
}

// ── Unclustered strip ────────────────────────────────────
function UnclusteredStrip({ projects, totalSpend }){
  const top = [...projects].sort((a,b)=>b.spend-a.spend).slice(0,6);
  return (
    <section className="card" style={{ padding:0, overflow:"hidden", borderColor:"rgba(185,113,13,0.22)", background:"linear-gradient(180deg, var(--warn-soft), transparent 30%)" }}>
      <div style={{ padding:"14px 18px", display:"flex", alignItems:"center", justifyContent:"space-between", gap:12 }}>
        <div style={{ display:"flex", alignItems:"center", gap:11 }}>
          <div style={{ width:32, height:32, borderRadius:8, background:"#fff", color:"var(--warn)", border:"1px solid rgba(185,113,13,0.22)", display:"flex", alignItems:"center", justifyContent:"center" }}>
            <Icon name="alert" size={14}/>
          </div>
          <div>
            <div style={{ fontSize:13, fontWeight:600, color:"var(--fg-0)" }}>{projects.length} unclustered project{projects.length!==1?"s":""}</div>
            <div style={{ fontSize:11.5, color:"var(--fg-2)", marginTop:2 }}>
              <span className="mono">{fmtGBP(totalSpend)}</span> not rolling up to any cluster. Assign them so budgets and reports stay clean.
            </div>
          </div>
        </div>
        <button style={btnSecondary()}>Bulk assign <Icon name="arrow" size={11}/></button>
      </div>
      <div style={{ borderTop:"1px solid var(--line-1)", padding:"10px 18px 12px", display:"flex", flexWrap:"wrap", gap:6 }}>
        {top.map(p => (
          <span key={p.slug} style={{ display:"inline-flex", alignItems:"center", gap:6, padding:"4px 10px 4px 8px", borderRadius:99, background:"#fff", border:"1px dashed var(--line-2)", fontSize:11.5, color:"var(--fg-1)" }}>
            <Icon name="folder" size={10} stroke="var(--fg-3)"/>
            <span className="mono">{p.name}</span>
            <span className="mono" style={{ color:"var(--fg-3)" }}>£{p.spend.toFixed(p.spend<1?2:0)}</span>
          </span>
        ))}
        {projects.length > 6 && <span style={{ fontSize:11.5, color:"var(--fg-3)", padding:"4px 4px" }}>+{projects.length-6} more</span>}
      </div>
    </section>
  );
}

// ── New cluster dialog ──────────────────────────────────
function NewClusterDialog({ onClose }){
  const [name, setName] = useState("");
  const [client, setClient] = useState("");
  const [color, setColor] = useState("#5b50ee");
  const [tag, setTag] = useState("client"); // internal | client
  const [budget, setBudget] = useState(50);

  return (
    <div onClick={onClose} style={{ position:"fixed", inset:0, background:"rgba(20,16,8,0.32)", backdropFilter:"blur(2px)", zIndex:80, display:"flex", alignItems:"center", justifyContent:"center" }}>
      <div onClick={e=>e.stopPropagation()} style={{
        background:"var(--bg-2)", border:"1px solid var(--line-2)",
        borderRadius:14, boxShadow:"0 20px 60px rgba(20,16,8,0.20)",
        width:480, maxWidth:"calc(100vw - 40px)",
        overflow:"hidden",
      }}>
        <div style={{ padding:"20px 22px 14px", borderBottom:"1px solid var(--line-1)" }}>
          <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between" }}>
            <h2 style={{ margin:0, fontSize:17, fontWeight:600, letterSpacing:-0.2 }}>New cluster</h2>
            <button onClick={onClose} style={{ background:"transparent", border:"none", color:"var(--fg-3)", cursor:"pointer", padding:6 }}><Icon name="plus" size={14} stroke="currentColor" strokeWidth={1.8}/></button>
          </div>
          <p style={{ margin:"6px 0 0", fontSize:12.5, color:"var(--fg-2)", lineHeight:1.5 }}>Group projects by client, department, or product line. Assign projects from each project's settings, or bulk-assign from the unclustered queue.</p>
        </div>

        <div style={{ padding:"18px 22px", display:"flex", flexDirection:"column", gap:14 }}>
          <Field label="Name" required>
            <input value={name} onChange={e=>setName(e.target.value)} placeholder="e.g. Acme Co. or Internal R&D"
              style={inputStyle()}/>
          </Field>

          <Field label="Client" hint="Optional. Shown on reports and invoices.">
            <input value={client} onChange={e=>setClient(e.target.value)} placeholder="e.g. Acme Co. Ltd"
              style={inputStyle()}/>
          </Field>

          <Field label="Type">
            <div style={{ display:"flex", gap:6 }}>
              <SegBtn active={tag==="client"}   onClick={()=>setTag("client")}   icon="user"   label="Client engagement"/>
              <SegBtn active={tag==="internal"} onClick={()=>setTag("internal")} icon="layers" label="Internal / R&D"/>
            </div>
          </Field>

          <Field label="Monthly budget" hint={`Warns at 85%, blocks at 100%${tag==="client"?" — reflected on invoices.":""}`}>
            <div style={{ position:"relative", width:"100%" }}>
              <span style={{ position:"absolute", left:12, top:"50%", transform:"translateY(-50%)", color:"var(--fg-3)", fontFamily:"var(--font-mono)" }}>£</span>
              <input type="number" value={budget} onChange={e=>setBudget(+e.target.value || 0)}
                style={{ ...inputStyle(), paddingLeft:24 }}/>
            </div>
          </Field>

          <Field label="Colour" hint="Used on cards, charts, and reports.">
            <div style={{ display:"flex", gap:8, alignItems:"center" }}>
              {CLUSTER_PALETTE.filter(p => p.id !== "none").map(p => {
                const selected = color === p.color;
                return (
                  <button key={p.id} type="button" onClick={()=>setColor(p.color)} title={p.id} style={{
                    width:28, height:28, borderRadius:"50%",
                    background:p.color,
                    border:"2px solid "+(selected ? "var(--fg-0)" : "transparent"),
                    cursor:"pointer", padding:0,
                    boxShadow: selected ? "0 0 0 2px #fff" : "none",
                  }}/>
                );
              })}
            </div>
          </Field>

          {/* Live preview */}
          <div style={{ padding:"11px 13px", border:"1px dashed var(--line-2)", borderRadius:9, background:"var(--bg-3)" }}>
            <div style={{ fontSize:10, color:"var(--fg-3)", textTransform:"uppercase", letterSpacing:0.08, fontWeight:600, marginBottom:7 }}>Preview</div>
            <div style={{ display:"flex", alignItems:"center", gap:10 }}>
              <div style={{ width:32, height:32, borderRadius:8, background:color, color:"#fff", display:"flex", alignItems:"center", justifyContent:"center", fontSize:13, fontWeight:600 }}>{(name || "C").charAt(0).toUpperCase()}</div>
              <div style={{ flex:1, minWidth:0 }}>
                <div style={{ display:"flex", alignItems:"center", gap:6 }}>
                  <span style={{ fontSize:13, fontWeight:500, color:"var(--fg-0)" }}>{name || "Cluster name"}</span>
                  <span className={tag==="client"?"badge badge--accent":"badge badge--ghost"} style={{ fontSize:9.5 }}>{tag}</span>
                </div>
                <div style={{ fontSize:11, color:"var(--fg-3)", marginTop:2 }}>{client || "—"} · budget <span className="mono" style={{ color:"var(--fg-2)" }}>£{budget}/mo</span></div>
              </div>
            </div>
          </div>
        </div>

        <div style={{ padding:"14px 22px", borderTop:"1px solid var(--line-1)", background:"rgba(20,16,8,0.012)", display:"flex", justifyContent:"flex-end", gap:8 }}>
          <button onClick={onClose} style={btnSecondary()}>Cancel</button>
          <button onClick={onClose} disabled={!name.trim()} style={{ ...btnPrimary(), opacity: name.trim() ? 1 : 0.5, cursor: name.trim() ? "pointer" : "not-allowed" }}>
            <Icon name="plus" size={13}/> Create cluster
          </button>
        </div>
      </div>
    </div>
  );
}

function Field({ label, required, hint, children }){
  return (
    <label style={{ display:"flex", flexDirection:"column", gap:5 }}>
      <span style={{ fontSize:12, fontWeight:500, color:"var(--fg-0)" }}>
        {label} {required && <span style={{ color:"var(--neg)" }}>*</span>}
      </span>
      {children}
      {hint && <span style={{ fontSize:11, color:"var(--fg-3)" }}>{hint}</span>}
    </label>
  );
}
function inputStyle(){
  return {
    height:36, padding:"0 12px", width:"100%",
    border:"1px solid var(--line-2)", borderRadius:8, background:"#fff",
    fontFamily:"inherit", fontSize:13, color:"var(--fg-0)", outline:"none",
  };
}
function SegBtn({ active, onClick, icon, label }){
  return (
    <button type="button" onClick={onClick} style={{
      appearance:"none", flex:1, padding:"9px 12px", borderRadius:8,
      border:"1px solid "+(active ? "var(--accent)" : "var(--line-2)"),
      background: active ? "var(--accent-soft)" : "#fff",
      color: active ? "var(--accent)" : "var(--fg-1)",
      fontSize:12.5, fontWeight: active ? 500 : 400,
      display:"inline-flex", alignItems:"center", gap:7, justifyContent:"center",
      cursor:"pointer",
    }}>
      <Icon name={icon} size={13}/>{label}
    </button>
  );
}

// ─────────────────────────────────────────────────────────────
//  Cluster detail sub-page
// ─────────────────────────────────────────────────────────────
function ClusterDetail({ id, setScreen, setProject }){
  const cluster = CLUSTERS.find(c => c.id === id) || CLUSTERS[0];
  const stats = clusterStats(cluster);
  const [tab, setTab] = useState("overview");
  const trajectory = stats.spend / PERIOD.daysElapsed * PERIOD.daysTotal;

  return (
    <div data-screen-label="03c Cluster Detail" style={{ padding:"20px 28px 40px", maxWidth:1380, margin:"0 auto", display:"flex", flexDirection:"column", gap:18 }}>
      {/* Breadcrumb */}
      <div style={{ display:"flex", alignItems:"center", gap:8, fontSize:12.5, color:"var(--fg-2)" }}>
        <button onClick={()=>setScreen("clusters")} style={{ background:"none", border:"none", color:"var(--fg-2)", padding:0, cursor:"pointer", fontSize:12.5, display:"inline-flex", alignItems:"center", gap:5 }}>
          <Icon name="chevLeft" size={12}/> Clusters
        </button>
        <span style={{ color:"var(--fg-3)" }}>/</span>
        <span style={{ color:"var(--fg-0)", fontWeight:500 }}>{cluster.name}</span>
      </div>

      {/* Header */}
      <header className="card" style={{ padding:0, overflow:"hidden", position:"relative" }}>
        <span style={{ position:"absolute", top:0, left:0, right:0, height:3, background:cluster.color }}/>
        <div style={{ position:"absolute", inset:"3px 0 0", background:`linear-gradient(135deg, ${cluster.color}10 0%, transparent 55%)`, pointerEvents:"none" }}/>
        <div style={{ padding:"22px 26px 18px", display:"flex", justifyContent:"space-between", alignItems:"flex-start", gap:24, position:"relative" }}>
          <div style={{ display:"flex", gap:18, alignItems:"flex-start" }}>
            <div style={{ width:60, height:60, borderRadius:12, background:cluster.color, color:"#fff", display:"flex", alignItems:"center", justifyContent:"center", fontSize:24, fontWeight:600, boxShadow:"0 1px 0 rgba(255,255,255,0.2) inset, 0 2px 6px rgba(20,16,8,0.10)" }}>{cluster.name.charAt(0)}</div>
            <div>
              <div style={{ display:"flex", alignItems:"center", gap:10 }}>
                <h1 style={{ margin:0, fontSize:24, fontWeight:600, letterSpacing:-0.4 }}>{cluster.name}</h1>
                {cluster.tags.map(t => (
                  <span key={t} className={t==="client"?"badge badge--accent":"badge badge--ghost"} style={{ fontSize:10 }}>{t}</span>
                ))}
              </div>
              <div style={{ display:"flex", gap:14, marginTop:6, fontSize:12.5, color:"var(--fg-2)" }}>
                <span>{cluster.client}</span>
                <span style={{ color:"var(--fg-3)" }}>·</span>
                <span>Created <span className="mono">{cluster.createdAt}</span></span>
                <span style={{ color:"var(--fg-3)" }}>·</span>
                <span style={{ display:"inline-flex", alignItems:"center", gap:5, color:"var(--pos)" }}>
                  <span style={{ width:6, height:6, borderRadius:"50%", background:"var(--pos)" }}/>{stats.activeCount} active project{stats.activeCount!==1?"s":""}
                </span>
              </div>
              {cluster.description && <p style={{ margin:"10px 0 0", fontSize:12.5, color:"var(--fg-1)", lineHeight:1.5, maxWidth:560 }}>{cluster.description}</p>}
            </div>
          </div>
          <div style={{ display:"flex", gap:8 }}>
            <button style={btnSecondary()}><Icon name="cog" size={13}/> Edit</button>
            <button style={btnSecondary()}><Icon name="plus" size={13}/> Add project</button>
            <button style={btnPrimary()}><Icon name="download" size={13}/> Generate report</button>
          </div>
        </div>

        {/* KPI strip */}
        <div style={{ display:"grid", gridTemplateColumns:"repeat(5, 1fr)", borderTop:"1px solid var(--line-1)", background:"rgba(20,16,8,0.012)" }}>
          <CDStat label="Period spend"      value={<Money value={stats.spend} size="sm"/>} sub={<span><Delta pct={0.42}/> vs April</span>} raw/>
          <CDStat label="Budget utilisation"value={`${(stats.utilisation*100).toFixed(0)}%`} sub={<><span className="mono">{fmtGBP(stats.spend)}</span> of {fmtGBP(cluster.budget)}</>} border tone={stats.utilisation>1?"neg":stats.utilisation>0.85?"warn":"pos"}/>
          <CDStat label="Projects"          value={`${stats.activeCount} / ${cluster.projectSlugs.length}`} sub="active / total" border/>
          <CDStat label="Requests"          value={stats.requests.toLocaleString()} sub={`${Math.round(stats.requests/PERIOD.daysElapsed)}/day`} border/>
          <CDStat label="Projected EOM"     value={fmtGBP(trajectory)} sub={trajectory > cluster.budget ? "over budget" : "within budget"} border tone={trajectory > cluster.budget ? "warn" : "pos"} raw/>
        </div>
      </header>

      {/* Tabs */}
      <div style={{ display:"flex", alignItems:"center", borderBottom:"1px solid var(--line-1)", marginTop:-4 }}>
        {[
          { id:"overview", label:"Overview" },
          { id:"projects", label:"Projects", count: stats.projects.length },
          { id:"members",  label:"Members & access", count: cluster.members.length },
          { id:"settings", label:"Settings" },
        ].map(t => {
          const active = tab === t.id;
          return (
            <button key={t.id} onClick={()=>setTab(t.id)} style={{
              appearance:"none", background:"transparent", border:"none",
              padding:"10px 14px",
              fontSize:13, fontWeight: active?500:400,
              color: active?"var(--fg-0)":"var(--fg-2)",
              borderBottom: active?`2px solid ${cluster.color}`:"2px solid transparent",
              marginBottom:-1, cursor:"pointer",
              display:"inline-flex", alignItems:"center", gap:8,
            }}>
              {t.label}
              {t.count != null && <span className="mono" style={{ fontSize:10.5, color:"var(--fg-3)" }}>{t.count}</span>}
            </button>
          );
        })}
      </div>

      {tab === "overview" && (
        <div style={{ display:"grid", gridTemplateColumns:"minmax(0, 1fr) 320px", gap:18 }}>
          <div style={{ display:"flex", flexDirection:"column", gap:18 }}>
            <ClusterSpendChart cluster={cluster} stats={stats}/>
            <ClusterProjectsTable cluster={cluster} stats={stats} onOpenProject={slug=>{ setProject(slug); setScreen("project-detail"); }}/>
          </div>
          <aside style={{ display:"flex", flexDirection:"column", gap:14 }}>
            <ClusterMembersCard cluster={cluster}/>
            <ClusterModelMixCard stats={stats}/>
            <ClusterReportsCard/>
          </aside>
        </div>
      )}

      {tab === "projects" && <ClusterProjectsTable cluster={cluster} stats={stats} expanded onOpenProject={slug=>{ setProject(slug); setScreen("project-detail"); }}/>}
      {tab === "members"  && <ClusterMembersFull cluster={cluster}/>}
      {tab === "settings" && <ClusterSettingsPanel cluster={cluster}/>}
    </div>
  );
}

function CDStat({ label, value, sub, border, raw, tone }){
  const tones = { neg:"var(--neg)", warn:"var(--warn)", pos:"var(--pos)", accent:"var(--accent)" };
  const color = tones[tone] || "var(--fg-0)";
  return (
    <div style={{ padding:"14px 18px", borderLeft: border ? "1px solid var(--line-1)" : "none", display:"flex", flexDirection:"column", gap:5 }}>
      <span style={{ fontSize:10.5, letterSpacing:0.08, textTransform:"uppercase", color:"var(--fg-3)", fontWeight:600 }}>{label}</span>
      {raw ? <span style={{ fontSize:17, color, fontWeight:600 }}>{value}</span> :
        <span className="mono" style={{ fontSize:17, fontWeight:600, color, letterSpacing:-0.2 }}>{value}</span>}
      <span style={{ fontSize:10.5, color:"var(--fg-2)" }}>{sub}</span>
    </div>
  );
}

// Cluster spend chart — stacked by project (top 5)
function ClusterSpendChart({ cluster, stats }){
  const ref = useRef(null);
  const w = useWidth(ref);
  const h = 220;
  const padL = 50, padR = 18, padT = 14, padB = 30;
  const innerW = Math.max(100, w - padL - padR);
  const innerH = h - padT - padB;
  const n = 11;
  const top = [...stats.projects].sort((a,b)=>b.spend-a.spend).slice(0,5);

  const data = Array.from({length:n}, (_, i) => {
    const day = { d:i+1, _total:0 };
    top.forEach((p, pi) => {
      const series = makeSeries(p.spend, n, p.shape);
      day[p.slug] = series[i];
      day._total += series[i];
    });
    return day;
  });
  const max = Math.max(...data.map(d => d._total), 0.01) * 1.18;
  const x = i => (i/(n-1))*innerW;
  const y = v => innerH - (v/max)*innerH;

  function stackPath(idx){
    const upper = data.map((d,i) => {
      const tot = top.slice(0, idx+1).reduce((s,p)=>s+(d[p.slug]||0), 0);
      return [x(i), y(tot)];
    });
    const lower = data.map((d,i) => {
      const tot = top.slice(0, idx).reduce((s,p)=>s+(d[p.slug]||0), 0);
      return [x(i), y(tot)];
    }).reverse();
    return "M" + [...upper, ...lower].map(([px,py])=>`${px.toFixed(1)},${py.toFixed(1)}`).join(" L") + " Z";
  }

  const yTicks = [0, 0.25, 0.5, 0.75, 1].map(t => ({ v: t*max, y: y(t*max) }));

  return (
    <section className="card" style={{ padding:"20px 22px" }}>
      <SectionHeader
        title="Cluster spend over time"
        subtitle="Stacked by project · top 5 · 11 days"
        action={
          <div style={{ display:"flex", flexWrap:"wrap", gap:10 }}>
            {top.map((p, i) => (
              <span key={p.slug} style={{ display:"inline-flex", alignItems:"center", gap:6, fontSize:11, color:"var(--fg-2)" }}>
                <span style={{ width:8, height:8, borderRadius:2, background:cluster.color, opacity: 1 - i*0.15 }}/>{p.name}
              </span>
            ))}
          </div>
        }
      />
      <div ref={ref} style={{ position:"relative", width:"100%", height:h }}>
        <svg width={w} height={h}>
          {yTicks.map((t,i) => (
            <g key={i}>
              <line x1={padL} x2={padL+innerW} y1={padT+t.y} y2={padT+t.y} stroke="var(--line-1)" strokeDasharray={i===0?"":"2 4"}/>
              <text x={padL-10} y={padT+t.y+3} textAnchor="end" fontSize="10" fontFamily="var(--font-mono)" fill="var(--fg-3)">£{t.v.toFixed(t.v<1?2:0)}</text>
            </g>
          ))}
          <g transform={`translate(${padL},${padT})`}>
            {top.map((p, idx) => (
              <path key={p.slug} d={stackPath(idx)} fill={cluster.color} fillOpacity={1 - idx*0.15} stroke={cluster.color} strokeOpacity="0.4" strokeWidth="0.5"/>
            ))}
          </g>
          {data.map((d,i) => (i===0 || i===n-1 || i%2===0) && (
            <text key={i} x={padL+x(i)} y={h-10} textAnchor="middle" fontSize="10" fontFamily="var(--font-mono)" fill="var(--fg-3)">{d.d} May</text>
          ))}
        </svg>
      </div>
    </section>
  );
}

function ClusterProjectsTable({ cluster, stats, expanded, onOpenProject }){
  return (
    <section className="card" style={{ padding:0, overflow:"hidden" }}>
      <div style={{ padding:"16px 22px", borderBottom:"1px solid var(--line-1)", display:"flex", justifyContent:"space-between", alignItems:"center" }}>
        <div>
          <h2 style={{ margin:0, fontSize:14, fontWeight:600 }}>Projects in {cluster.name}</h2>
          <div style={{ fontSize:11.5, color:"var(--fg-2)", marginTop:3 }}>{stats.projects.length} project{stats.projects.length!==1?"s":""} · sorted by spend</div>
        </div>
        <div style={{ display:"flex", gap:8 }}>
          <button style={btnSecondary()}><Icon name="plus" size={12}/> Add project</button>
        </div>
      </div>
      <table className="tbl">
        <thead>
          <tr>
            <th style={{ paddingLeft:22 }}>Project</th>
            <th>Status</th>
            <th className="right">Period spend</th>
            <th className="right">Requests</th>
            <th>Trend</th>
            <th>Primary model</th>
            <th style={{ paddingRight:22 }}>Last active</th>
          </tr>
        </thead>
        <tbody>
          {[...stats.projects].sort((a,b)=>b.spend-a.spend).map(p => {
            const series = makeSeries(p.spend, 11, p.shape);
            return (
              <tr key={p.slug} className="clickable" onClick={()=>onOpenProject(p.slug)}>
                <td style={{ paddingLeft:22 }}>
                  <div style={{ display:"flex", flexDirection:"column", gap:1 }}>
                    <span style={{ color:"var(--fg-0)", fontWeight:500 }}>{p.name}</span>
                    <span className="mono" style={{ fontSize:11, color:"var(--fg-3)" }}>/{p.slug}</span>
                  </div>
                </td>
                <td>
                  <span style={{ display:"inline-flex", alignItems:"center", gap:5, fontSize:11.5, color:"var(--pos)", padding:"2px 8px", borderRadius:99, background:"var(--pos-soft)", border:"1px solid rgba(15,138,79,0.22)" }}>
                    <span style={{ width:5, height:5, borderRadius:"50%", background:"var(--pos)" }}/>Active
                  </span>
                </td>
                <td className="right"><Money value={p.spend} size="sm"/></td>
                <td className="right mono" style={{ color:"var(--fg-1)" }}>{p.requests.toLocaleString()}</td>
                <td><Sparkline data={series} w={90} h={20} color={cluster.color}/></td>
                <td><ModelBadge model={p.primaryModel}/></td>
                <td className="mono" style={{ color:"var(--fg-2)", fontSize:12, paddingRight:22 }}>{p.lastActive}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </section>
  );
}

function ClusterMembersCard({ cluster }){
  return (
    <div className="card" style={{ padding:"16px 18px" }}>
      <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom:12 }}>
        <h3 style={{ margin:0, fontSize:12.5, fontWeight:600 }}>Members</h3>
        <button style={{ ...btnSubtle(), color:"var(--accent)", padding:0 }}><Icon name="plus" size={11} stroke="var(--accent)"/> Add</button>
      </div>
      <div style={{ display:"flex", flexDirection:"column", gap:10 }}>
        {cluster.members.map(mid => {
          const isOwner = mid === cluster.owner;
          return (
            <div key={mid} style={{ display:"flex", alignItems:"center", gap:10 }}>
              <Avatar seed={mid} name={mid==="vk"?"Alex Pemberton":"Jamie Lowe"} size={28}/>
              <div style={{ flex:1, minWidth:0 }}>
                <div style={{ fontSize:12.5, fontWeight:500, color:"var(--fg-0)" }}>{mid==="vk"?"Alex Pemberton":"Jamie Lowe"}</div>
                <div style={{ fontSize:10.5, color:"var(--fg-3)" }}>{isOwner ? "Owner · all projects" : "Editor · contributor"}</div>
              </div>
              {isOwner && <span className="badge badge--accent" style={{ fontSize:9.5 }}>owner</span>}
            </div>
          );
        })}
      </div>
    </div>
  );
}

function ClusterModelMixCard({ stats }){
  // Aggregate model usage from cluster projects' primary models
  const mix = {};
  stats.projects.forEach(p => {
    if (!mix[p.primaryModel]) mix[p.primaryModel] = { model:p.primaryModel, cost:0, requests:0 };
    mix[p.primaryModel].cost += p.spend;
    mix[p.primaryModel].requests += p.requests;
  });
  const arr = Object.values(mix).sort((a,b)=>b.cost-a.cost);
  const total = arr.reduce((s,m)=>s+m.cost, 0);
  return (
    <div className="card" style={{ padding:"16px 18px" }}>
      <h3 style={{ margin:"0 0 10px", fontSize:12.5, fontWeight:600 }}>Model mix</h3>
      <div style={{ display:"flex", height:9, borderRadius:99, overflow:"hidden", background:"var(--bg-3)", marginBottom:10 }}>
        {arr.map(m => {
          const meta = MODELS[m.model];
          return <div key={m.model} style={{ width:Math.max(1, m.cost/total*100)+"%", background:PROVIDERS[meta.provider].color }}/>;
        })}
      </div>
      <div style={{ display:"flex", flexDirection:"column", gap:7 }}>
        {arr.map(m => {
          const meta = MODELS[m.model];
          return (
            <div key={m.model} style={{ display:"flex", justifyContent:"space-between", alignItems:"baseline", fontSize:11.5 }}>
              <span style={{ display:"inline-flex", alignItems:"center", gap:6 }}>
                <span style={{ width:6, height:6, borderRadius:2, background:PROVIDERS[meta.provider].color }}/>
                <span className="mono" style={{ color:"var(--fg-1)" }}>{meta.short}</span>
              </span>
              <span className="mono" style={{ color:"var(--fg-0)" }}>{fmtGBP(m.cost)}</span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function ClusterReportsCard(){
  return (
    <div className="card" style={{ padding:"16px 18px", borderColor:"var(--accent-line)", background:"linear-gradient(180deg, rgba(91,80,238,0.04), transparent 50%)" }}>
      <div style={{ display:"flex", alignItems:"center", gap:7, marginBottom:8 }}>
        <Icon name="receipt" size={13} stroke="var(--accent)"/>
        <h3 style={{ margin:0, fontSize:12.5, fontWeight:600 }}>Cluster reports</h3>
      </div>
      <div style={{ fontSize:11.5, color:"var(--fg-2)", marginBottom:10 }}>Generate one report covering every project in this cluster.</div>
      <div style={{ display:"flex", flexDirection:"column", gap:6 }}>
        <button style={{ ...btnSecondary(), width:"100%", justifyContent:"flex-start" }}><Icon name="receipt" size={12}/> Client invoice (PDF)</button>
        <button style={{ ...btnSecondary(), width:"100%", justifyContent:"flex-start" }}><Icon name="chart" size={12}/> Executive summary</button>
        <button style={{ ...btnSecondary(), width:"100%", justifyContent:"flex-start" }}><Icon name="download" size={12}/> Cost CSV</button>
      </div>
    </div>
  );
}

function ClusterMembersFull({ cluster }){
  return (
    <section className="card" style={{ padding:0, overflow:"hidden" }}>
      <div style={{ padding:"16px 22px", borderBottom:"1px solid var(--line-1)" }}>
        <h2 style={{ margin:0, fontSize:14, fontWeight:600 }}>Members & access</h2>
        <div style={{ fontSize:11.5, color:"var(--fg-2)", marginTop:3 }}>People with access to all projects in this cluster</div>
      </div>
      <table className="tbl">
        <thead>
          <tr>
            <th style={{ paddingLeft:22 }}>Member</th>
            <th>Role in cluster</th>
            <th className="right">Their spend</th>
            <th className="right">Requests</th>
            <th style={{ paddingRight:22 }}>Granted</th>
          </tr>
        </thead>
        <tbody>
          {cluster.members.map(mid => (
            <tr key={mid}>
              <td style={{ paddingLeft:22 }}>
                <div style={{ display:"flex", alignItems:"center", gap:10 }}>
                  <Avatar seed={mid} name={mid==="vk"?"Alex Pemberton":"Jamie Lowe"} size={28}/>
                  <div>
                    <div style={{ fontSize:13, fontWeight:500, color:"var(--fg-0)" }}>{mid==="vk"?"Alex Pemberton":"Jamie Lowe"}</div>
                    <div className="mono" style={{ fontSize:11, color:"var(--fg-3)" }}>{mid==="vk"?"vikrant@meridian-studio.com":"sarah@meridian-studio.com"}</div>
                  </div>
                </div>
              </td>
              <td>{mid === cluster.owner ? <span className="badge badge--accent" style={{ fontSize:10 }}>Owner</span> : <span className="badge badge--ghost" style={{ fontSize:10 }}>Editor</span>}</td>
              <td className="right"><Money value={mid==="vk"?244.53:33.35} size="sm"/></td>
              <td className="right mono" style={{ color:"var(--fg-1)" }}>{mid==="vk"?"5,980":"755"}</td>
              <td className="mono" style={{ color:"var(--fg-2)", fontSize:12, paddingRight:22 }}>{cluster.createdAt}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </section>
  );
}

function ClusterSettingsPanel({ cluster }){
  return (
    <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:18 }}>
      <section className="card" style={{ padding:"20px 22px" }}>
        <h2 style={{ margin:"0 0 14px", fontSize:14, fontWeight:600 }}>General</h2>
        <div style={{ display:"flex", flexDirection:"column", gap:14 }}>
          <Field label="Name" required><input defaultValue={cluster.name} style={inputStyle()}/></Field>
          <Field label="Client"><input defaultValue={cluster.client} style={inputStyle()}/></Field>
          <Field label="Description"><textarea defaultValue={cluster.description} rows={3} style={{ ...inputStyle(), height:"auto", padding:"8px 12px", resize:"vertical", fontFamily:"inherit" }}/></Field>
          <Field label="Monthly budget"><input defaultValue={cluster.budget} type="number" style={inputStyle()}/></Field>
          <Field label="Colour">
            <div style={{ display:"flex", gap:8 }}>
              {CLUSTER_PALETTE.filter(p => p.id !== "none").map(p => (
                <span key={p.id} style={{ width:26, height:26, borderRadius:"50%", background:p.color, border:"2px solid "+(p.color === cluster.color ? "var(--fg-0)" : "transparent") }}/>
              ))}
            </div>
          </Field>
          <div style={{ display:"flex", justifyContent:"flex-end", gap:8, paddingTop:6 }}>
            <button style={btnSecondary()}>Cancel</button>
            <button style={btnPrimary()}>Save changes</button>
          </div>
        </div>
      </section>

      <section style={{ display:"flex", flexDirection:"column", gap:14 }}>
        <div className="card" style={{ padding:"20px 22px" }}>
          <h2 style={{ margin:"0 0 14px", fontSize:14, fontWeight:600 }}>Notifications</h2>
          <Toggle label="Notify on 85% of budget" defaultChecked/>
          <Toggle label="Notify on 100% of budget" defaultChecked/>
          <Toggle label="Weekly digest email" defaultChecked/>
          <Toggle label="Notify when a new project is auto-tagged into this cluster"/>
        </div>
        <div className="card" style={{ padding:"20px 22px", borderColor:"rgba(201,58,58,0.22)" }}>
          <h2 style={{ margin:"0 0 8px", fontSize:14, fontWeight:600, color:"var(--neg)" }}>Danger zone</h2>
          <p style={{ margin:"0 0 14px", fontSize:12, color:"var(--fg-2)", lineHeight:1.5 }}>Deleting a cluster un-assigns its projects. Project data is preserved.</p>
          <div style={{ display:"flex", gap:8 }}>
            <button style={{ ...btnGhost(), color:"var(--warn)", borderColor:"rgba(185,113,13,0.3)" }}>Archive cluster</button>
            <button style={{ ...btnGhost(), color:"var(--neg)", borderColor:"rgba(201,58,58,0.3)" }}>Delete cluster</button>
          </div>
        </div>
      </section>
    </div>
  );
}

function Toggle({ label, defaultChecked }){
  const [on, setOn] = useState(!!defaultChecked);
  return (
    <label style={{ display:"flex", alignItems:"center", justifyContent:"space-between", padding:"9px 0", borderBottom:"1px solid var(--line-1)", cursor:"pointer", fontSize:12.5 }}>
      <span style={{ color:"var(--fg-1)" }}>{label}</span>
      <span onClick={()=>setOn(!on)} style={{
        width:32, height:18, borderRadius:99,
        background: on ? "var(--accent)" : "var(--bg-4)",
        position:"relative", transition:"background 120ms",
      }}>
        <span style={{
          position:"absolute", top:2, left: on ? 16 : 2,
          width:14, height:14, borderRadius:"50%", background:"#fff",
          transition:"left 120ms",
          boxShadow:"0 1px 2px rgba(0,0,0,0.2)",
        }}/>
      </span>
    </label>
  );
}

Object.assign(window, { Clusters, ClusterDetail });
