/* Tract Console v2 — feature panels: Overview (dashboard), Documents, Chat, Due diligence, Funds.
   All read the active deal via useDeal(). */
const { Icon, Avatar, Composer, RichText, Modal, Popover, useStore, useDeal, Store, useState, useEffect, useRef } = window;
const Dv = window.V2DATA;
const money = Dv.money;
const STAGE_BY = Object.fromEntries(Dv.STAGES.map((s) => [s.id, s]));

/* ---------- cost model ---------- */
function costModel(dl) {
  const items = dl.ddItems;
  const counted = items.filter((i) => ["needed", "ordered", "done"].includes(i.state));
  const committed = items.filter((i) => ["ordered", "done"].includes(i.state));
  const PER = 300, BASE = Dv.BASE_FEE, baseAdvisor = 1100, baseAttorney = 900;
  return {
    counted, committed,
    ordered: items.filter((i) => i.state === "ordered").length,
    done: items.filter((i) => i.state === "done").length,
    needed: items.filter((i) => i.state === "needed").length,
    estimate: BASE + counted.length * PER,
    paidNow: BASE + committed.length * PER,
    pending: (counted.length - committed.length) * PER,
    base: BASE, per: PER,
    advisorEarn: baseAdvisor + committed.length * 150,
    attorneyEarn: baseAttorney + committed.length * 150,
    min: Dv.BASE_FEE, max: Dv.MAX_EST,
  };
}
function stripHtml(h) { const d = document.createElement("div"); d.innerHTML = h; return d.textContent || ""; }
function docInStage(d, stageId) { return !stageId || d.tags.includes(stageId); }
function StageTags({ tags }) { return <span style={{ display: "inline-flex", gap: 4, flexWrap: "wrap" }}>{tags.map((t) => <span key={t} className="tag">{STAGE_BY[t] ? STAGE_BY[t].short : t}</span>)}</span>; }
function visibleThreads(role) { if (role === "attorney" || role === "admin") return ["group"]; return ["advisor-buyer", "group"]; }

/* ============== doc row + modal ============== */
function DocRow({ doc, onOpen }) {
  return (
    <button onClick={onOpen} style={{ width: "100%", textAlign: "left", border: "none", background: "transparent", padding: "12px 4px", display: "flex", gap: 12, alignItems: "flex-start", cursor: "pointer", borderRadius: 9 }}
      onMouseEnter={(e) => e.currentTarget.style.background = "var(--bg-soft)"} onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}>
      <span style={{ flex: "none", width: 34, height: 34, borderRadius: 8, background: "var(--bg-soft)", border: "1px solid var(--line)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--ink-2)" }}><Icon name="file-text" size={17} /></span>
      <span style={{ flex: 1, minWidth: 0 }}>
        <span style={{ display: "flex", alignItems: "center", gap: 8 }}><span style={{ fontWeight: 600, fontSize: 14 }}>{doc.name}</span><span className="faint" style={{ fontSize: 12 }}>{doc.kind}</span></span>
        <span style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 4 }}><StageTags tags={doc.tags} /></span>
        {doc.note ? <span style={{ display: "block", fontSize: 12.5, color: "var(--ink-2)", marginTop: 5, fontStyle: "italic" }}>{doc.note}</span> : null}
      </span>
      <span className="faint" style={{ fontSize: 11.5, flex: "none" }}>{doc.date}</span>
    </button>
  );
}
function DocModal({ doc, onClose }) {
  const [note, setNote] = useState(doc.note);
  const [tags, setTags] = useState(doc.tags);
  const dl = useDeal();
  const toggle = (id) => setTags((t) => t.includes(id) ? t.filter((x) => x !== id) : [...t, id]);
  const save = () => { Store.dispatch({ type: "DOC_NOTE", id: doc.id, note }); Store.dispatch({ type: "DOC_TAGS", id: doc.id, tags }); onClose(); };
  return (
    <Modal icon="file-text" iconColor="var(--ink)" title={doc.name} onClose={onClose} width={560}
      footer={<><button className="btn btn--ghost" onClick={onClose}>Close</button><button className="btn btn--acc" onClick={save}><Icon name="check" size={15} />Save</button></>}>
      <div style={{ background: "#fff", border: "1px solid var(--line-2)", borderRadius: 10, padding: "26px 28px", boxShadow: "var(--sh-1)" }}>
        <div style={{ textAlign: "center", fontWeight: 700, textTransform: "uppercase", letterSpacing: ".04em", fontSize: 14 }}>{doc.name}</div>
        <div style={{ textAlign: "center", fontSize: 11, color: "var(--ink-3)", marginTop: 3 }}>{dl.state} · {dl.name}</div>
        <div style={{ marginTop: 18, display: "flex", flexDirection: "column", gap: 9 }}>{[94, 100, 88, 97, 72].map((w, i) => <div key={i} style={{ height: 8, width: w + "%", background: "#efeee9", borderRadius: 4 }} />)}</div>
      </div>
      <div style={{ marginTop: 16 }}>
        <div className="eyebrow" style={{ marginBottom: 8 }}>Applies to stages</div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
          {Dv.STAGES.map((s) => <button key={s.id} className={"tag" + (tags.includes(s.id) ? " tag--on" : "")} style={{ cursor: "pointer", height: 26, padding: "0 11px" }} onClick={() => toggle(s.id)}>{tags.includes(s.id) && <Icon name="check" size={12} style={{ marginRight: 4 }} />}{s.short}</button>)}
        </div>
      </div>
      <div style={{ marginTop: 16 }}>
        <div className="eyebrow" style={{ marginBottom: 8 }}>Note <span style={{ textTransform: "none", letterSpacing: 0, fontWeight: 500, color: "var(--ink-3)" }}>· what this file is, in plain words</span></div>
        <textarea className="input" value={note} onChange={(e) => setNote(e.target.value)} placeholder="e.g. Schedule B exceptions flagged for attorney review" style={{ height: 70, padding: 11, resize: "vertical", lineHeight: 1.5 }} />
      </div>
    </Modal>
  );
}

/* ============== Chat ============== */
function ChatThread({ thread, role, big }) {
  const dl = useDeal();
  const t = dl.threads[thread];
  const scroller = useRef(null);
  const isMember = t.members.includes(role) && !dl.frozen;
  useEffect(() => { if (scroller.current) scroller.current.scrollTop = scroller.current.scrollHeight; }, [t.messages.length, thread]);
  const send = (html) => Store.dispatch({ type: "CHAT_ADD", thread, from: role, html });
  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%", minHeight: 0 }}>
      <div ref={scroller} style={{ flex: 1, overflowY: "auto", padding: big ? "6px 4px" : "6px 2px", display: "flex", flexDirection: "column", gap: 16 }}>
        {t.messages.length === 0 && <div className="empty" style={{ margin: "auto" }}>No messages yet.</div>}
        {t.messages.map((m, i) => {
          const mine = m.from === role;
          const p = Dv.PEOPLE[m.from] || { name: m.from, role: "tenant", handle: "" };
          return (
            <div key={i} className="fade" style={{ display: "flex", gap: 10, flexDirection: mine ? "row-reverse" : "row", alignItems: "flex-start" }}>
              <Avatar who={m.from} size={30} />
              <div style={{ maxWidth: "76%" }}>
                <div style={{ display: "flex", gap: 7, alignItems: "baseline", justifyContent: mine ? "flex-end" : "flex-start", marginBottom: 4 }}>
                  <span style={{ fontSize: 12.5, fontWeight: 700 }}>{mine ? "You" : p.name}</span>
                  <span className="faint" style={{ fontSize: 11 }}>{p.handle} · {m.at}</span>
                </div>
                <div style={{ padding: "10px 13px", borderRadius: 13, background: mine ? "var(--green-soft)" : "var(--bg-soft)", border: "1px solid " + (mine ? "var(--green-line)" : "var(--line)") }}><RichText html={m.html} /></div>
              </div>
            </div>
          );
        })}
      </div>
      <div style={{ paddingTop: 12 }}>
        {isMember
          ? <Composer placeholder={"Message " + t.title.toLowerCase() + "…  (paste from your AI keeps formatting)"} onSend={send} />
          : <div style={{ padding: "12px 14px", background: "var(--bg-soft)", border: "1px dashed var(--line-2)", borderRadius: 11, fontSize: 13, color: "var(--ink-2)", display: "flex", gap: 9, alignItems: "center" }}><Icon name={dl.frozen ? "lock" : "eye"} size={16} />{dl.frozen ? "This deal is closed — chat is read-only." : "You're viewing this thread as oversight — read only."}</div>}
      </div>
    </div>
  );
}
/* ============== Chat (primary) — chat centre + documents on the right ============== */
function DocsPanel({ stageId, onClearStage }) {
  const dl = useDeal();
  const [open, setOpen] = useState(null);
  const list = dl.documents.filter((d) => docInStage(d, stageId));
  return (
    <div className="card" style={{ display: "flex", flexDirection: "column", minHeight: 0, overflow: "hidden" }}>
      <div className="card__h" style={{ justifyContent: "space-between" }}>
        <span style={{ display: "flex", alignItems: "center", gap: 8 }}><Icon name="folder" size={17} color="var(--ink-2)" /><span className="card__t" style={{ fontSize: 15 }}>Documents</span></span>
        {stageId
          ? <button className="pill pill--acc" onClick={onClearStage} style={{ cursor: "pointer" }}>{STAGE_BY[stageId].short}<Icon name="x" size={13} /></button>
          : <span className="pill">All · {list.length}</span>}
      </div>
      <div style={{ padding: "4px 14px 12px", overflowY: "auto", flex: 1, minHeight: 0 }}>
        {stageId && <div className="faint" style={{ fontSize: 12, padding: "8px 4px 4px" }}>Tagged for <b style={{ color: "var(--ink-2)" }}>{STAGE_BY[stageId].label}</b>.</div>}
        {list.length === 0 ? <div className="empty" style={{ padding: 24 }}>No documents tagged here.</div> : list.map((d) => <DocRow key={d.id} doc={d} onOpen={() => setOpen(d)} />)}
      </div>
      {open && <DocModal doc={open} onClose={() => setOpen(null)} />}
    </div>
  );
}
function ChatTab({ role, stageId, onClearStage, focus }) {
  const dl = useDeal();
  const threads = visibleThreads(role);
  const [active, setActive] = useState(threads[0]);
  useEffect(() => { if (!threads.includes(active)) setActive(threads[0]); }, [role]);
  const t = dl.threads[active];
  return (
    <div className="wrap" style={{ paddingTop: focus ? 12 : 16, paddingBottom: focus ? 14 : 18, height: "100%", display: "flex", flexDirection: "column", minHeight: 0, maxWidth: focus ? 1080 : 1180 }}>
      <div style={{ flex: 1, minHeight: 0, display: "grid", gridTemplateColumns: focus ? "minmax(0,1fr)" : "minmax(0,1fr) 340px", gap: 18 }}>
        {/* chat — primary */}
        <div className="card" style={{ display: "flex", flexDirection: "column", minHeight: 0, overflow: "hidden" }}>
          <div className="card__h" style={{ justifyContent: "space-between", gap: 14 }}>
            <div style={{ display: "flex", gap: 4, background: "var(--bg-soft)", border: "1px solid var(--line)", borderRadius: 10, padding: 3 }}>
              {threads.map((id) => <button key={id} onClick={() => setActive(id)} style={{ height: 32, padding: "0 14px", border: "none", borderRadius: 7, background: active === id ? "var(--card)" : "transparent", boxShadow: active === id ? "var(--sh-1)" : "none", fontWeight: 600, fontSize: 13, color: active === id ? "var(--ink)" : "var(--ink-2)", cursor: "pointer", display: "flex", alignItems: "center", gap: 7 }}>
                <Icon name={dl.threads[id].kind === "group" ? "users" : "user"} size={15} />{dl.threads[id].title}</button>)}
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 6 }}>{t.members.map((mid) => <span key={mid} title={Dv.PEOPLE[mid].name}><Avatar who={mid} size={26} /></span>)}</div>
          </div>
          <div style={{ flex: 1, minHeight: 0, padding: "14px 18px 16px", display: "flex", flexDirection: "column" }}><ChatThread thread={active} role={role} big /></div>
        </div>
        {/* documents — right (hidden in full-screen) */}
        {!focus && <DocsPanel stageId={stageId} onClearStage={onClearStage} />}
      </div>
    </div>
  );
}

/* ============== Overview — dashboard ============== */
const NEXT_BY_STAGE = {
  assess: "Tract is building the property profile and a starting valuation. Upload the seller's initial documents to move forward.",
  loi: "Negotiating the letter of intent. Once both sides sign, the PSA stage opens.",
  psa: "The binding agreement. Tract drafts it; the attorney reviews and approves before anyone signs.",
  dd: "Inspections, title and environmental are underway. Order the items your advisor has flagged.",
  close: "Final settlement statement, signatures and recording. Funds disburse through escrow.",
};
function Activity({ role }) {
  const dl = useDeal();
  const list = dl.activity || [];
  return (
    <div className="wrap" style={{ paddingTop: 22, paddingBottom: 30, maxWidth: 720 }}>
      <h2 style={{ fontSize: 19, fontWeight: 700, letterSpacing: "-.02em", margin: "0 0 4px" }}>Activity</h2>
      <p className="muted" style={{ fontSize: 13.5, margin: "0 0 18px" }}>Everything that's happened on {dl.name}, most recent first.</p>
      <div className="card">
        <div style={{ padding: "16px 20px 4px" }}>
          {list.length === 0 ? <div className="empty">No activity yet.</div> : list.map((a, i) => (
            <div key={i} style={{ display: "flex", gap: 14, alignItems: "stretch" }}>
              <div style={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
                <span style={{ flex: "none", width: 30, height: 30, borderRadius: 8, background: "var(--bg-soft)", border: "1px solid var(--line)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--ink-2)" }}><Icon name={a.ic} size={15} /></span>
                {i < list.length - 1 && <span style={{ flex: 1, width: 2, background: "var(--line)", marginTop: 4 }} />}
              </div>
              <div style={{ flex: 1, paddingBottom: 18 }}>
                <RichText html={window.mdToHtml(a.t)} />
                <div className="faint" style={{ fontSize: 11.5, marginTop: 3 }}>{a.at}</div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}
function Mini({ n, l, c }) { return <div style={{ textAlign: "center", padding: "8px 4px", background: "var(--bg-soft)", borderRadius: 10 }}><div className="num" style={{ fontSize: 22, fontWeight: 700, color: c }}>{n}</div><div className="faint" style={{ fontSize: 11, fontWeight: 600, marginTop: 1 }}>{l}</div></div>; }
function CostMini({ cm, onTab }) {
  const pct = Math.min(100, Math.round(((cm.estimate - cm.min) / (cm.max - cm.min)) * 100));
  return (
    <div className="card" style={{ padding: 18 }}>
      <div className="eyebrow">Your estimated cost</div>
      <div style={{ display: "flex", alignItems: "baseline", gap: 8, marginTop: 6 }}><span className="num" style={{ fontSize: 28, fontWeight: 700 }}>{money(cm.estimate)}</span><span className="faint" style={{ fontSize: 12 }}>of {money(cm.max)} max</span></div>
      <div style={{ height: 8, borderRadius: 99, background: "var(--bg-soft)", marginTop: 10, overflow: "hidden" }}><div style={{ height: "100%", width: pct + "%", background: "var(--green)", borderRadius: 99, transition: "width .5s var(--ease)" }} /></div>
      <div className="faint" style={{ fontSize: 11.5, marginTop: 6 }}>{money(cm.min)} base · +{money(cm.per)} per item you order</div>
      <button className="btn btn--ghost btn--sm btn--block" style={{ marginTop: 12 }} onClick={() => onTab("funds")}>Cost breakdown</button>
    </div>
  );
}
function EarnMini({ cm, role }) {
  const v = role === "attorney" ? cm.attorneyEarn : role === "advisor" ? cm.advisorEarn : cm.advisorEarn + cm.attorneyEarn;
  const lbl = role === "admin" ? "Platform revenue" : "Your fees on this deal";
  return (
    <div className="card" style={{ padding: 18 }}>
      <div className="eyebrow">{lbl}</div>
      <div className="num" style={{ fontSize: 28, fontWeight: 700, marginTop: 6 }}>{money(v)}</div>
      <div className="faint" style={{ fontSize: 11.5, marginTop: 4 }}>{cm.committed.length} item{cm.committed.length === 1 ? "" : "s"} ordered · grows with due diligence</div>
    </div>
  );
}

/* ============== Documents tab ============== */
function DocumentsTab({ role, stageId, setStageFilter }) {
  const dl = useDeal();
  const [open, setOpen] = useState(null);
  const [adding, setAdding] = useState(false);
  const [q, setQ] = useState("");
  const list = dl.documents.filter((d) => docInStage(d, stageId) && (!q || d.name.toLowerCase().includes(q.toLowerCase())));
  return (
    <div className="wrap" style={{ paddingTop: 18, paddingBottom: 30 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 16, flexWrap: "wrap" }}>
        <div style={{ position: "relative", flex: 1, minWidth: 200, maxWidth: 320 }}>
          <span style={{ position: "absolute", left: 12, top: 11, color: "var(--ink-3)" }}><Icon name="search" size={16} /></span>
          <input className="input" value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search documents…" style={{ paddingLeft: 36 }} />
        </div>
        <div className="gap" />
        {!dl.frozen && <button className="btn btn--acc btn--sm" onClick={() => setAdding(true)}><Icon name="upload" size={15} />Add document</button>}
      </div>
      <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 12 }}>
        <button className={"tag" + (!stageId ? " tag--on" : "")} style={{ cursor: "pointer", height: 28, padding: "0 12px" }} onClick={() => setStageFilter(null)}>All documents</button>
        {Dv.STAGES.map((s) => <button key={s.id} className={"tag" + (stageId === s.id ? " tag--on" : "")} style={{ cursor: "pointer", height: 28, padding: "0 12px" }} onClick={() => setStageFilter(s.id)}>{s.short}</button>)}
      </div>
      <div className="card"><div style={{ padding: "8px 16px" }}>
        {list.length === 0 ? <div className="empty">No matching documents.</div> : list.map((d, i) => <div key={d.id} style={{ borderTop: i ? "1px solid var(--line)" : "none" }}><DocRow doc={d} onOpen={() => setOpen(d)} /></div>)}
      </div></div>
      <div className="faint" style={{ fontSize: 12.5, marginTop: 12, display: "flex", gap: 8, alignItems: "center" }}><Icon name="info" size={14} />One flat library. Tag each file with the stages it applies to — the same file can serve several stages.</div>
      {open && <DocModal doc={open} onClose={() => setOpen(null)} />}
      {adding && <AddDoc onClose={() => setAdding(false)} stageId={stageId} />}
    </div>
  );
}
function AddDoc({ onClose, stageId }) {
  const [name, setName] = useState("");
  const [note, setNote] = useState("");
  const [tags, setTags] = useState(stageId ? [stageId] : []);
  const [file, setFile] = useState(null);
  const fileRef = useRef(null);
  const toggle = (id) => setTags((t) => t.includes(id) ? t.filter((x) => x !== id) : [...t, id]);
  const pick = (f) => { if (!f) return; setFile({ name: f.name, size: f.size }); if (!name.trim()) setName(f.name.replace(/\.[^.]+$/, "")); };
  const fmtSize = (b) => b > 1e6 ? (b / 1e6).toFixed(1) + " MB" : Math.max(1, Math.round(b / 1e3)) + " KB";
  return (
    <Modal icon="upload" iconColor="var(--green)" title="Add document" onClose={onClose}
      footer={<><button className="btn btn--ghost" onClick={onClose}>Cancel</button><button className="btn btn--acc" disabled={!name.trim()} onClick={() => { Store.dispatch({ type: "DOC_ADD", name: name.trim(), tags, note }); onClose(); }}><Icon name="check" size={15} />Add to library</button></>}>
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        <input ref={fileRef} type="file" style={{ display: "none" }} onChange={(e) => pick(e.target.files[0])} />
        <div onClick={() => fileRef.current && fileRef.current.click()}
          onDragOver={(e) => { e.preventDefault(); e.currentTarget.style.borderColor = "var(--green)"; e.currentTarget.style.background = "var(--green-soft)"; }}
          onDragLeave={(e) => { e.currentTarget.style.borderColor = "var(--line-2)"; e.currentTarget.style.background = "var(--bg-soft)"; }}
          onDrop={(e) => { e.preventDefault(); e.currentTarget.style.borderColor = "var(--line-2)"; e.currentTarget.style.background = "var(--bg-soft)"; pick(e.dataTransfer.files[0]); }}
          style={{ border: "1.5px dashed var(--line-2)", background: "var(--bg-soft)", borderRadius: 11, padding: file ? "14px 16px" : "22px 16px", textAlign: "center", cursor: "pointer", transition: "border-color .12s, background .12s" }}>
          {file ? (
            <div style={{ display: "flex", alignItems: "center", gap: 11, textAlign: "left" }}>
              <span style={{ flex: "none", width: 38, height: 38, borderRadius: 9, background: "var(--card)", border: "1px solid var(--line)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--green-700)" }}><Icon name="file-check" size={18} /></span>
              <div style={{ flex: 1, minWidth: 0 }}><div style={{ fontWeight: 600, fontSize: 13.5, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{file.name}</div><div className="faint" style={{ fontSize: 12 }}>{fmtSize(file.size)} · ready to upload</div></div>
              <button onClick={(e) => { e.stopPropagation(); setFile(null); }} className="cbtn" title="Remove"><Icon name="x" size={16} /></button>
            </div>
          ) : (
            <>
              <Icon name="upload-cloud" size={26} color="var(--ink-3)" />
              <div style={{ fontWeight: 600, fontSize: 13.5, marginTop: 6 }}>Click to upload or drag a file here</div>
              <div className="faint" style={{ fontSize: 12, marginTop: 2 }}>PDF, image or document</div>
            </>
          )}
        </div>
        <label><div className="sec-title" style={{ marginBottom: 6 }}>File name</div><input className="input" value={name} onChange={(e) => setName(e.target.value)} placeholder="e.g. Roof inspection report" /></label>
        <div><div className="sec-title" style={{ marginBottom: 6 }}>Applies to stages</div><div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>{Dv.STAGES.map((s) => <button key={s.id} className={"tag" + (tags.includes(s.id) ? " tag--on" : "")} style={{ cursor: "pointer", height: 28, padding: "0 12px" }} onClick={() => toggle(s.id)}>{s.short}</button>)}</div></div>
        <label><div className="sec-title" style={{ marginBottom: 6 }}>Note <span className="faint" style={{ fontWeight: 500 }}>· optional</span></div><textarea className="input" value={note} onChange={(e) => setNote(e.target.value)} style={{ height: 60, padding: 11, resize: "vertical" }} placeholder="What is this file?" /></label>
      </div>
    </Modal>
  );
}

/* ============== Due diligence ============== */
const DD_STATE = {
  idle:    { label: "Available", cls: "pill" },
  needed:  { label: "Needed", cls: "pill pill--amber" },
  ordered: { label: "Ordered · paid", cls: "pill pill--acc" },
  done:    { label: "Done", cls: "pill pill--dark" },
};
function DueDiligenceTab({ role }) {
  const dl = useDeal();
  const cm = costModel(dl);
  const [pay, setPay] = useState(null);
  const cats = ["Inspections", "Surveys & reports", "Title & legal"];
  const isAdvisor = role === "advisor", isBuyer = role === "buyer";
  return (
    <div className="wrap" style={{ paddingTop: 18, paddingBottom: 30 }}>
      <div style={{ display: "grid", gridTemplateColumns: "minmax(0,1fr) 300px", gap: 20, alignItems: "start" }}>
        <div>
          <h2 style={{ fontSize: 18, fontWeight: 700, margin: "0 0 2px", letterSpacing: "-.01em" }}>Due-diligence items</h2>
          <p className="muted" style={{ fontSize: 13, marginTop: 2, marginBottom: 18, maxWidth: 560 }}>
            {isAdvisor ? "Mark the items this deal needs. The buyer orders and pays each one directly — third-party vendors do the work. Mark an item done once the report is in and reviewed."
              : isBuyer ? "Your advisor flags what this property needs. Order and pay for each item — it goes straight to the third-party vendor. Each item is about $300."
              : "What this deal requires and where each item stands. The buyer orders and pays each item directly."}
          </p>
          {cats.map((cat) => {
            const items = dl.ddItems.filter((i) => i.cat === cat);
            return (
              <div key={cat} style={{ marginBottom: 18 }}>
                <div className="eyebrow" style={{ marginBottom: 8 }}>{cat}</div>
                <div className="card">
                  {items.map((it, idx) => (
                    <div key={it.id} style={{ display: "flex", alignItems: "center", gap: 12, padding: "13px 16px", borderTop: idx ? "1px solid var(--line)" : "none" }}>
                      <span style={{ flex: 1, minWidth: 0 }}><span style={{ fontWeight: 600, fontSize: 14 }}>{it.label}</span><span className="faint num" style={{ fontSize: 12, marginLeft: 8 }}>· {money(it.price)}</span></span>
                      <span className={DD_STATE[it.state].cls}>{it.state === "done" && <Icon name="check" size={13} />}{DD_STATE[it.state].label}</span>
                      {!dl.frozen && <DDActions it={it} role={role} onPay={() => setPay(it)} />}
                    </div>
                  ))}
                </div>
              </div>
            );
          })}
        </div>
        <div className="card" style={{ padding: 16, position: "sticky", top: 14 }}>
          <div className="eyebrow">{isBuyer ? "Your running cost" : "Deal cost estimate"}</div>
          <div className="num" style={{ fontSize: 27, fontWeight: 700, marginTop: 6 }}>{money(cm.estimate)}</div>
          <div className="faint" style={{ fontSize: 12, marginTop: 2 }}>est. final · range {money(cm.min)}–{money(cm.max)}</div>
          <div style={{ marginTop: 14, display: "flex", flexDirection: "column", gap: 9, fontSize: 13 }}>
            <Line l="Base (PSA + closing)" v={money(cm.base)} />
            <Line l={cm.committed.length + " item" + (cm.committed.length === 1 ? "" : "s") + " ordered"} v={money(cm.committed.length * cm.per)} />
            <Line l={cm.needed + " flagged, not ordered"} v={money(cm.needed * cm.per)} faint />
            <div style={{ borderTop: "1px solid var(--line)", paddingTop: 9, display: "flex", justifyContent: "space-between", fontWeight: 700 }}><span>Estimated total</span><span className="num">{money(cm.estimate)}</span></div>
          </div>
          {isBuyer && <div style={{ marginTop: 12, padding: "10px 12px", background: "var(--green-soft)", border: "1px solid var(--green-line)", borderRadius: 10, fontSize: 12, color: "var(--green-700)", display: "flex", gap: 8 }}><Icon name="shield-check" size={15} />Paid only for what you order. Vendor fees go to the providers, not Tract.</div>}
        </div>
      </div>
      {pay && <PayModal it={pay} onClose={() => setPay(null)} />}
    </div>
  );
}
function Line({ l, v, faint }) { return <div style={{ display: "flex", justifyContent: "space-between", color: faint ? "var(--ink-3)" : "var(--ink-2)" }}><span>{l}</span><span className="num" style={{ color: faint ? "var(--ink-3)" : "var(--ink)", fontWeight: 600 }}>{v}</span></div>; }
function DDActions({ it, role, onPay }) {
  if (role === "advisor") return (
    <span style={{ display: "flex", gap: 6 }}>
      {it.state === "idle" && <button className="btn btn--ghost btn--sm" onClick={() => Store.dispatch({ type: "DD_SET", id: it.id, state: "needed" })}><Icon name="flag" size={14} />Mark needed</button>}
      {it.state === "needed" && <button className="btn btn--quiet btn--sm" onClick={() => Store.dispatch({ type: "DD_SET", id: it.id, state: "idle" })}>Unflag</button>}
      {it.state === "ordered" && <button className="btn btn--ghost btn--sm" onClick={() => Store.dispatch({ type: "DD_SET", id: it.id, state: "done" })}><Icon name="check" size={14} />Mark done</button>}
      {it.state === "done" && <button className="btn btn--quiet btn--sm" onClick={() => Store.dispatch({ type: "DD_SET", id: it.id, state: "ordered" })}>Reopen</button>}
    </span>
  );
  if (role === "buyer") return it.state === "needed" ? <button className="btn btn--acc btn--sm" onClick={onPay}><Icon name="credit-card" size={14} />Order &amp; pay</button> : <span style={{ width: 1 }} />;
  return <span style={{ width: 1 }} />;
}
function PayModal({ it, onClose }) {
  return (
    <Modal icon="credit-card" iconColor="var(--green)" title={"Order — " + it.label} onClose={onClose} width={460}
      footer={<><button className="btn btn--ghost" onClick={onClose}>Cancel</button><button className="btn btn--acc" onClick={() => { Store.dispatch({ type: "DD_SET", id: it.id, state: "ordered" }); onClose(); }}><Icon name="check" size={15} />Pay {money(it.price)}</button></>}>
      <p className="muted" style={{ fontSize: 13.5, lineHeight: 1.55, marginTop: 0 }}>Your advisor flagged <b style={{ color: "var(--ink)" }}>{it.label}</b> as needed. Ordering sends the job to a third-party vendor and charges your card on file.</p>
      <div style={{ border: "1px solid var(--line)", borderRadius: 11, overflow: "hidden" }}>
        <div style={{ display: "flex", justifyContent: "space-between", padding: "11px 14px", borderBottom: "1px solid var(--line)" }}><span>{it.label}</span><span className="num" style={{ fontWeight: 600 }}>{money(it.price)}</span></div>
        <div style={{ display: "flex", justifyContent: "space-between", padding: "11px 14px", fontWeight: 700, background: "var(--bg-soft)" }}><span>Due now</span><span className="num">{money(it.price)}</span></div>
      </div>
    </Modal>
  );
}

/* ============== Funds ============== */
function FStatus({ s }) {
  const M = { requested: ["pill pill--amber", "Requested"], released: ["pill pill--acc", "Released"], approved: ["pill pill--acc", "Approved"], declined: ["pill", "Declined"] };
  const m = M[s] || M.requested;
  return <span className={m[0]}>{s === "released" || s === "approved" ? <Icon name="check" size={12} /> : null}{m[1]}</span>;
}
function FundsTab({ role }) {
  const dl = useDeal();
  const cm = costModel(dl);
  const [refund, setRefund] = useState(false);
  const [toast, setToast] = useState(null);
  const payouts = dl.payouts || [];
  const refunds = dl.refunds || [];

  if (role === "buyer") {
    const pct = Math.min(100, Math.round((cm.paidNow / cm.estimate) * 100));
    return (
      <div className="wrap" style={{ paddingTop: 18, paddingBottom: 30, maxWidth: 760 }}>
        <h2 style={{ fontSize: 19, fontWeight: 700, margin: "0 0 4px" }}>What this deal will cost you</h2>
        <p className="muted" style={{ fontSize: 13.5, marginTop: 0, marginBottom: 18 }}>A live estimate. It starts at {money(cm.min)} and grows only as you order due-diligence items.</p>
        <div className="card" style={{ padding: 20 }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 12 }}>
            <div><div className="eyebrow">Estimated total</div><div className="num" style={{ fontSize: 34, fontWeight: 700, letterSpacing: "-.02em" }}>{money(cm.estimate)}</div></div>
            <div style={{ textAlign: "right" }}><div className="faint" style={{ fontSize: 12 }}>Paid so far</div><div className="num" style={{ fontSize: 18, fontWeight: 700, color: "var(--green-700)" }}>{money(cm.paidNow)}</div></div>
          </div>
          <div style={{ height: 12, borderRadius: 99, background: "var(--bg-soft)", overflow: "hidden", position: "relative" }}>
            <div style={{ position: "absolute", inset: 0, width: Math.min(100, ((cm.estimate - cm.min) / (cm.max - cm.min)) * 100) + "%", background: "var(--green-soft)", borderRight: "2px solid var(--green-line)" }} />
            <div style={{ position: "absolute", inset: 0, width: pct * (cm.estimate - cm.min) / (cm.max - cm.min) + "%", background: "var(--green)" }} />
          </div>
          <div className="faint" style={{ fontSize: 11.5, marginTop: 6, display: "flex", justifyContent: "space-between" }}><span>{money(cm.min)} min</span><span>{money(cm.max)} typical max</span></div>
          <div style={{ marginTop: 18, display: "flex", flexDirection: "column", gap: 11 }}>
            <Line l="Base — PSA drafting + closing coordination" v={money(cm.base)} />
            <Line l={cm.committed.length + " due-diligence item" + (cm.committed.length === 1 ? "" : "s") + " ordered"} v={money(cm.committed.length * cm.per)} />
            <Line l={cm.needed + " flagged, awaiting your order"} v={money(cm.needed * cm.per)} faint />
          </div>
        </div>
        {/* refunds */}
        <div className="card" style={{ marginTop: 16 }}>
          <div className="card__h" style={{ justifyContent: "space-between" }}><span className="card__t">Refunds</span>{!dl.frozen && <button className="btn btn--ghost btn--sm" onClick={() => setRefund(true)}><Icon name="rotate-ccw" size={14} />Request a refund</button>}</div>
          <div className="card__b">
            {refunds.length === 0 ? <div className="muted" style={{ fontSize: 13 }}>No refund requests. If a deal doesn't proceed, you can request a refund of the Tract subscription here.</div>
              : refunds.map((r) => (
                <div key={r.id} style={{ display: "flex", alignItems: "center", gap: 12, padding: "11px 0", borderBottom: "1px solid var(--line)" }}>
                  <Icon name="rotate-ccw" size={16} color="var(--ink-2)" />
                  <div style={{ flex: 1 }}><div style={{ fontWeight: 600, fontSize: 13.5 }}>{money(r.amount)}</div><div className="faint" style={{ fontSize: 12 }}>{r.reason} · {r.at}</div></div>
                  <FStatus s={r.status} />
                </div>
              ))}
          </div>
        </div>
        {refund && <RefundModal max={cm.paidNow} onClose={() => setRefund(false)} onDone={() => { setRefund(false); setToast("Refund requested"); }} />}
        {toast && <window.Toast msg={toast} onDone={() => setToast(null)} />}
      </div>
    );
  }

  const mine = role === "attorney" ? cm.attorneyEarn : cm.advisorEarn;
  const myRole = role === "attorney" ? "attorney" : "advisor";
  const myName = Dv.PEOPLE[myRole].name;
  const myReq = payouts.find((p) => p.role === myRole);
  const isAdmin = role === "admin";

  return (
    <div className="wrap" style={{ paddingTop: 18, paddingBottom: 30, maxWidth: 820 }}>
      <h2 style={{ fontSize: 19, fontWeight: 700, margin: "0 0 16px" }}>{isAdmin ? "Deal funds" : "Your earnings"}</h2>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(3,1fr)", gap: 14, marginBottom: 18 }}>
        <Stat l={isAdmin ? "Collected from buyer" : "Earned this deal"} v={money(isAdmin ? cm.paidNow : mine)} sub={cm.committed.length + " items ordered"} />
        <Stat l="Advisor fees" v={money(cm.advisorEarn)} sub={money(Dv.RATES.advisor) + "/hr"} />
        <Stat l="Attorney fees" v={money(cm.attorneyEarn)} sub={money(Dv.RATES.attorney) + "/hr"} />
      </div>

      {!isAdmin && (
        <div className="card">
          <div className="card__h"><span className="card__t">Your payout</span></div>
          <div className="card__b" style={{ display: "flex", alignItems: "center", gap: 14 }}>
            <div style={{ flex: 1 }}><div className="num" style={{ fontSize: 22, fontWeight: 700 }}>{money(mine)}</div><div className="faint" style={{ fontSize: 12.5, marginTop: 2 }}>{myReq ? (myReq.status === "released" ? "Released " + myReq.at : "Requested " + myReq.at + " — awaiting admin") : "Available to request from Tract."}</div></div>
            {myReq ? <FStatus s={myReq.status} /> : <button className="btn btn--primary" onClick={() => { Store.dispatch({ type: "REQUEST_PAYOUT", who: myName, role: myRole, amount: mine }); setToast("Payout requested"); }}><Icon name="arrow-down-left" size={15} />Request payout</button>}
          </div>
        </div>
      )}

      {isAdmin && (
        <>
          <div className="card" style={{ marginBottom: 16 }}>
            <div className="card__h" style={{ justifyContent: "space-between" }}><span className="card__t">Payout requests</span><span className="pill">{payouts.filter((p) => p.status === "requested").length} pending</span></div>
            <div className="card__b" style={{ paddingTop: 6, paddingBottom: 6 }}>
              {payouts.length === 0 ? <div className="muted" style={{ fontSize: 13, padding: "8px 0" }}>No payout requests yet.</div>
                : payouts.map((p) => (
                  <div key={p.id} style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 0", borderTop: "1px solid var(--line)" }}>
                    <Avatar who={p.role} size={32} />
                    <div style={{ flex: 1 }}><div style={{ fontWeight: 600, fontSize: 13.5 }}>{p.who}<span className="faint" style={{ fontWeight: 500 }}> · {Dv.PEOPLE[p.role].handle}</span></div><div className="faint" style={{ fontSize: 12 }}>{money(p.amount)} · {p.at}</div></div>
                    {p.status === "requested" ? <button className="btn btn--acc btn--sm" onClick={() => { Store.dispatch({ type: "RELEASE_PAYOUT", id: p.id }); setToast("Payout released"); }}><Icon name="banknote" size={14} />Release</button> : <FStatus s={p.status} />}
                  </div>
                ))}
            </div>
          </div>
          <div className="card">
            <div className="card__h" style={{ justifyContent: "space-between" }}><span className="card__t">Refund requests</span><span className="pill">{refunds.filter((r) => r.status === "requested").length} pending</span></div>
            <div className="card__b" style={{ paddingTop: 6, paddingBottom: 6 }}>
              {refunds.length === 0 ? <div className="muted" style={{ fontSize: 13, padding: "8px 0" }}>No refund requests.</div>
                : refunds.map((r) => (
                  <div key={r.id} style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 0", borderTop: "1px solid var(--line)" }}>
                    <Avatar who="buyer" size={32} />
                    <div style={{ flex: 1 }}><div style={{ fontWeight: 600, fontSize: 13.5 }}>{r.who} · {money(r.amount)}</div><div className="faint" style={{ fontSize: 12 }}>{r.reason} · {r.at}</div></div>
                    {r.status === "requested" ? <span style={{ display: "flex", gap: 6 }}><button className="btn btn--ghost btn--sm" onClick={() => { Store.dispatch({ type: "RESOLVE_REFUND", id: r.id, status: "declined" }); setToast("Refund declined"); }}>Decline</button><button className="btn btn--acc btn--sm" onClick={() => { Store.dispatch({ type: "RESOLVE_REFUND", id: r.id, status: "approved" }); setToast("Refund approved"); }}><Icon name="check" size={14} />Approve</button></span> : <FStatus s={r.status} />}
                  </div>
                ))}
            </div>
          </div>
        </>
      )}
      {toast && <window.Toast msg={toast} onDone={() => setToast(null)} />}
    </div>
  );
}
function RefundModal({ max, onClose, onDone }) {
  const [amount, setAmount] = useState(String(Dv.SUBSCRIPTION));
  const [reason, setReason] = useState("Deal did not proceed");
  const amt = Number((amount || "").replace(/[^0-9]/g, "")) || 0;
  return (
    <Modal icon="rotate-ccw" iconColor="var(--ink)" title="Request a refund" onClose={onClose} width={460}
      footer={<><button className="btn btn--ghost" onClick={onClose}>Cancel</button><button className="btn btn--acc" disabled={!amt || !reason.trim()} onClick={() => { Store.dispatch({ type: "REQUEST_REFUND", amount: amt, reason: reason.trim() }); onDone(); }}><Icon name="check" size={15} />Submit request</button></>}>
      <p className="muted" style={{ fontSize: 13.5, marginTop: 0, marginBottom: 14 }}>Refunds are reviewed by Tract admin. You've paid {money(max)} so far on this deal.</p>
      <label><div className="sec-title" style={{ marginBottom: 6 }}>Amount</div><div style={{ display: "flex", alignItems: "center", gap: 8, height: 40, padding: "0 13px", border: "1px solid var(--line-2)", borderRadius: "var(--r-sm)", background: "var(--bg)" }}><span className="faint">$</span><input value={amount} onChange={(e) => setAmount(e.target.value)} style={{ flex: 1, border: "none", outline: "none", background: "transparent", font: "inherit", fontSize: 14 }} /></div></label>
      <label style={{ display: "block", marginTop: 13 }}><div className="sec-title" style={{ marginBottom: 6 }}>Reason</div><textarea className="input" value={reason} onChange={(e) => setReason(e.target.value)} style={{ height: 64, padding: 11, resize: "vertical" }} /></label>
    </Modal>
  );
}
function Stat({ l, v, sub }) { return <div className="card" style={{ padding: 15 }}><div className="eyebrow">{l}</div><div className="num" style={{ fontSize: 25, fontWeight: 700, marginTop: 5 }}>{v}</div><div className="faint" style={{ fontSize: 11.5, marginTop: 2 }}>{sub}</div></div>; }

window.Panels = { costModel, Activity, ChatTab, DocsPanel, DocumentsTab, DueDiligenceTab, FundsTab, visibleThreads, stripHtml };
