// Project Detail — desktop: main + right summary panel; mobile: top summary card + tabs.
(function () {
  window.SCREENS = window.SCREENS || {};
  const { useState } = React;
  const IC = window.IC, D = window.DATA;
  const sm = D.statusMeta, rm = D.riskMeta;
  const toneVar = { ok: "var(--ok)", warn: "var(--warn)", danger: "var(--danger)", info: "var(--info)", neutral: "var(--neutral)" };
  const detailFor = (p) => D.detail[p.id] || D.genericPhases(p);

  function SummaryCard({ p, det, mobile, onEdit }) {
    const spentPct = Math.round((p.spent / p.budget) * 100);
    const cur = det.phases.find((ph) => ph.status === "active") || det.phases.find((ph) => ph.status === "todo") || det.phases[det.phases.length - 1];
    let nextMile = null;
    det.phases.forEach((ph) => (ph.tasks || []).forEach((t) => { if (window.isMilestone(t) && t.status !== "done" && !nextMile) nextMile = t; }));
    return (
      <div className={"summary-card" + (mobile ? " mobile-only" : "")}>
        <div className="sc-prog">
          <div className="pt"><span>ความคืบหน้ารวม</span><b className="tnum">{p.progress}%</b></div>
          <div className="prog-bar"><i style={{ width: p.progress + "%" }} /></div>
        </div>
        <div className="sc-row"><span className="k">สถานะ</span><span className="v"><span className={"pill " + sm[p.status].tone}><i />{sm[p.status].th}</span></span></div>
        <div className="sc-row"><span className="k">เจ้าของงาน</span><span className="v" style={{ display: "flex", alignItems: "center", gap: 8 }}><span className="avatar sm">{p.ownerInit}</span>{p.owner}</span></div>
        <div className="sc-row"><span className="k">ขั้นตอนปัจจุบัน</span><span className="v">{cur.name}</span></div>
        <div className="sc-row"><span className="k">ความเสี่ยง</span><span className="v" style={{ display: "flex", alignItems: "center", gap: 7, color: toneVar[rm[p.risk].tone] }}><i style={{ width: 7, height: 7, borderRadius: "50%", background: toneVar[rm[p.risk].tone] }} />{p.riskNote}</span></div>
        <div className="sc-row"><span className="k">เหตุการณ์ถัดไป</span><span className="v">{nextMile ? nextMile.name : "—"}</span></div>
        <div className="sc-row"><span className="k">กำหนดส่ง</span><span className="v mono">{p.due}</span></div>
        <div className="budget-bar" style={{ paddingTop: 12 }}>
          <div className="bt"><span>งบประมาณ</span><b>{window.fmtBaht(p.spent)} / {window.fmtBaht(p.budget)}</b></div>
          <div className="prog-bar thin"><i style={{ width: spentPct + "%", background: spentPct > 90 ? "var(--danger)" : "var(--accent)" }} /></div>
        </div>
        <div style={{ display: "flex", gap: 9, marginTop: 16 }}>
          {window.can("editProject")
            ? <button className="btn pri" style={{ flex: 1 }} onClick={onEdit}>แก้ไขโครงการ</button>
            : <button className="btn pri" style={{ flex: 1 }} onClick={() => window.navigate("updates")}>ดูอัปเดต</button>}
          <button className="btn" onClick={() => window.openReport("exec")}>{IC.download}</button>
        </div>
      </div>
    );
  }

  function Phase({ ph, idx, open, onToggle }) {
    return (
      <div className={"phase" + (open ? " open" : "")}>
        <div className="ph-h" onClick={onToggle}>
          <span className="ph-no">{idx + 1}</span>
          <div><div className="ph-name">{ph.name}</div><div className="ph-en">{ph.en} · {ph.owner}</div></div>
          <div className="ph-right">
            <span className={"pill " + ((D.phaseStatusMeta[ph.status]||{tone:"neutral"}).tone)}><i />{(D.phaseStatusMeta[ph.status]||{th:ph.status}).th}</span>
            <div className="ph-prog"><div className="pct tnum">{ph.progress}%</div><div className="prog-bar thin"><i style={{ width: ph.progress + "%", background: ph.status === "done" ? "var(--ok)" : "var(--accent)" }} /></div></div>
            <span className="ph-chev">{IC.chevR}</span>
          </div>
        </div>
        {open && (ph.tasks && ph.tasks.length > 0) && (
          <div className="ph-tasks">
            {ph.tasks.map((t) => {
              const hard = (t.deps || []).filter((d) => d.type === "hard").length;
              const soft = (t.deps || []).filter((d) => d.type === "soft").length;
              const isMile = window.isMilestone(t);
              return (
                <div className={"task-row" + (isMile ? " milestone" : "")} key={t.id}>
                  <span className="tk-ic" title={isMile ? "เหตุการณ์สำคัญ" : "งานดำเนินการ"}>{isMile ? <span style={{ color: t.status === "done" ? "var(--ok)" : "var(--accent)" }}>♦</span> : window.taskIcon(t.status)}</span>
                  <span className="tk-name">{t.name}{isMile && <span style={{ color: "var(--faint)", fontWeight: 400 }}> · เหตุการณ์สำคัญ</span>}</span>
                  {(hard > 0 || soft > 0) && <span className="tk-dep">{IC.link}{hard > 0 ? hard + " hard" : ""}{hard > 0 && soft > 0 ? " · " : ""}{soft > 0 ? soft + " soft" : ""}</span>}
                  <span className="avatar sm" style={{ background: "var(--raised2)", color: "var(--muted)" }}>{t.owner}</span>
                </div>
              );
            })}
          </div>
        )}
      </div>
    );
  }

  function Overview({ p, det }) {
    const [openId, setOpenId] = useState((det.phases.find((ph) => ph.status === "active") || {}).id);
    const done = det.phases.filter((ph) => ph.status === "done").length;
    let nextMile = null;
    det.phases.forEach((ph) => (ph.tasks || []).forEach((t) => { if (window.isMilestone(t) && t.status !== "done" && !nextMile) nextMile = t; }));
    return (
      <div>
        <div className="metric-grid">
          <div className="metric"><div className="ml">ความคืบหน้า</div><div className="mv tnum">{p.progress}%</div><div className="ms">{done}/{det.phases.length} ขั้นตอนเสร็จ</div></div>
          <div className="metric"><div className="ml">งบประมาณใช้ไป</div><div className="mv tnum">{window.fmtBaht(p.spent)}</div><div className="ms">จาก {window.fmtBaht(p.budget)}</div></div>
          <div className="metric"><div className="ml">เหตุการณ์ถัดไป</div><div className="mv" style={{ fontSize: 15, lineHeight: 1.3 }}>{nextMile ? nextMile.name : "—"}</div><div className="ms">{p.dueShort}</div></div>
          <div className="metric"><div className="ml">อัปเดตล่าสุด</div><div className="mv tnum">{(det.updates || []).length}</div><div className="ms">{(det.decisions || []).length} การตัดสินใจ</div></div>
        </div>

        <div className="block">
          <div className="sh"><span className="sec-title">ขั้นตอน & รายการ</span><a className="lnk" href={"#/timeline/" + p.id}>ดู Timeline →</a></div>
          {det.phases.map((ph, i) => <Phase key={ph.id} ph={ph} idx={i} open={openId === ph.id} onToggle={() => setOpenId(openId === ph.id ? null : ph.id)} />)}
        </div>

        {det.meetings && det.meetings.length > 0 && (
          <div className="block">
            <div className="sh"><span className="sec-title">การประชุมล่าสุด</span><a className="lnk" href="#/meetings">ทั้งหมด →</a></div>
            <div className="rail-card">
              {det.meetings.map((m) => (
                <div className="mt-item" key={m.id}>
                  <div className="cal"><b className="tnum">{m.date.split(" ")[0]}</b><span>{m.date.split(" ")[1]}</span></div>
                  <div style={{ flex: 1 }}><div className="mn">{m.title}</div><div className="mm">{m.type}{m.outcome !== "—" && m.outcome ? " · " + m.outcome : ""}</div></div>
                </div>
              ))}
            </div>
          </div>
        )}
      </div>
    );
  }

  function Vendors({ det }) {
    if (!det.vendors || det.vendors.length === 0) return <div className="empty">ยังไม่มีข้อมูล Vendor</div>;
    return (
      <div className="rail-card">
        {det.vendors.map((v, i) => (
          <div className="vendor" key={i}>
            <span className="avatar md" style={{ background: "var(--raised2)", color: "var(--muted)", borderRadius: 10 }}>{v.name.slice(0, 2)}</span>
            <div style={{ minWidth: 0 }}><div className="vn">{v.name}</div><div className="vr">{v.role} · {v.contact}</div></div>
            <div className="vstage">
              <span className={"pill " + v.tone}><i />{v.stage}</span>
              <div className="prog-bar thin vbar"><i style={{ width: v.stagePct + "%", background: toneVar[v.tone] }} /></div>
            </div>
          </div>
        ))}
      </div>
    );
  }

  function Documents({ det }) {
    if (!det.documents || det.documents.length === 0) return <div className="empty">ยังไม่มีเอกสาร</div>;
    const openDoc = async (d) => { if (window.Files && d.fileId) await window.Files.open(d); else if (d.fileUrl) window.open(d.fileUrl, "_blank", "noopener"); else window.toast("เอกสารนี้ยังไม่ได้อัปโหลด"); };
    return (
      <div className="rail-card">
        {det.documents.map((d, i) => (
          <div className="doc-row" key={i}>
            <span className={"doc-ic " + (d.type || "other").toLowerCase()}>{(d.type || "OTH").slice(0, 3).toUpperCase()}</span>
            <div style={{ flex: 1, minWidth: 0 }}><div className="dn">{d.name}</div><div className="dm">{d.type} · {d.size} · {d.by} · {d.date}</div></div>
            <span className="dver">{d.ver}</span>
            <button className="icon-btn" title={(d.fileId || d.fileUrl) ? "เปิดไฟล์" : "ยังไม่ได้อัปโหลด"} onClick={() => openDoc(d)}>{IC.download}</button>
          </div>
        ))}
      </div>
    );
  }

  function Decisions({ p, det, onChange }) {
    const [show, setShow] = useState(false);
    const [editing, setEditing] = useState(null);
    const canEdit = window.can("edit");
    const onDelete = async (d) => { if (!confirm("ลบบันทึก Decision นี้?\n\"" + d.change + "\"")) return; await window.DB.deleteDecision(d.id); window.toast("ลบ Decision แล้ว"); onChange(); };
    return (
      <div>
        <div className="sh"><span className="sec-title">Decision Log</span>
          {canEdit && <button className="btn sm pri" onClick={() => setShow(true)}>{IC.plus} สร้างบันทึก Decision</button>}
        </div>
        {(!det.decisions || det.decisions.length === 0)
          ? <window.EmptyState icon="dec" title="ยังไม่มีบันทึกการตัดสินใจ" sub="บันทึกการตัดสินใจที่สำคัญของโครงการ พร้อมเหตุผลและผลกระทบ" ctaLabel={canEdit ? "สร้างบันทึก Decision" : undefined} onCta={canEdit ? () => setShow(true) : undefined} />
          : (
        <div className="dlog">
          {det.decisions.map((d) => (
            <div className={"dlog-item" + (d.by === "คณะกรรมการ" ? " exec" : "")} key={d.id}>
              <div className="dlog-card">
                <div className="dlog-top">
                  <span className="dlog-date">{d.date}</span>
                  <div style={{ display:"flex", gap:7, alignItems:"center", flexWrap:"wrap" }}>
                    {d.impact && <span className="pill warn" style={{ whiteSpace:"normal", maxWidth:240 }}><i />{d.impact}</span>}
                    {canEdit && <>
                      <button className="icon-btn" title="แก้ไข" onClick={() => setEditing(d)} style={{ width:30, height:30 }}>{IC.settings}</button>
                      <button className="icon-btn" title="ลบ" onClick={() => onDelete(d)} style={{ width:30, height:30, color:"var(--danger)" }}>{IC.x}</button>
                    </>}
                  </div>
                </div>
                <div className="dlog-change" style={{ wordBreak:"break-word", overflowWrap:"anywhere" }}><window.ExpandableText text={d.change} lines={2} title="หัวข้อการตัดสินใจ" /></div>
                {d.reason && <div className="dlog-reason"><window.ExpandableText text={d.reason} lines={3} title="เหตุผล / รายละเอียด" /></div>}
                <div className="dlog-foot">
                  {d.by && <span className="fitem">{IC.user}<b style={{ wordBreak:"break-word" }}>{d.by}</b></span>}
                  {d.attachment && <span className="fitem" style={{ wordBreak:"break-all" }}>{IC.doc} {d.attachment}</span>}
                </div>
              </div>
            </div>
          ))}
        </div>
        )}
        {show && window.DecisionModal && <window.DecisionModal fixedProjectId={p.id} onClose={() => setShow(false)} onDone={onChange} />}
        {editing && window.DecisionModal && <window.DecisionModal edit={editing} onClose={() => setEditing(null)} onDone={onChange} />}
      </div>
    );
  }

  function Raci({ det }) {
    if (!det.raci || det.raci.length === 0) return <div className="empty">ยังไม่มีข้อมูล RACI</div>;
    return (
      <div className="rail-card" style={{ padding: "4px 0", overflowX: "auto" }}>
        <table className="raci-table">
          <thead><tr><th>ผู้เกี่ยวข้อง</th><th>R</th><th>A</th><th>C</th><th>I</th></tr></thead>
          <tbody>
            {det.raci.map((r, i) => (
              <tr key={i}>
                <td><b style={{ fontWeight: 600 }}>{r.name}</b><div style={{ fontSize: 11.5, color: "var(--muted)" }}>{r.role}</div></td>
                <td>{r.r && <span className="raci-badge R">R</span>}</td>
                <td>{r.a && <span className="raci-badge A">A</span>}</td>
                <td>{r.c && <span className="raci-badge C">C</span>}</td>
                <td>{r.i && <span className="raci-badge I">I</span>}</td>
              </tr>
            ))}
          </tbody>
        </table>
        <div style={{ display: "flex", gap: 16, flexWrap: "wrap", padding: "12px 16px", fontSize: 11.5, color: "var(--muted)" }}>
          <span><b style={{ color: "var(--ink2)" }}>R</b> Responsible</span><span><b style={{ color: "var(--ink2)" }}>A</b> Accountable</span><span><b style={{ color: "var(--ink2)" }}>C</b> Consulted</span><span><b style={{ color: "var(--ink2)" }}>I</b> Informed</span>
        </div>
      </div>
    );
  }

  // Admin timeline editor — add / status / delete items (CRUD)
  const ediSel = { border:0, background:"none", outline:"none", font:"inherit", fontSize:13.5, flex:1, color:"var(--ink)" };

  // Phase add/edit modal — name + rich status + calendar start/end
  function PhaseModal({ projectId, edit, onClose, onDone }) {
    const isEdit = !!edit;
    const [f, setF, safeClose] = window.useDirty({
      name: isEdit ? edit.name : "", status: isEdit ? edit.status : "todo",
      startISO: isEdit ? (edit.startISO || window.todayISO()) : window.todayISO(),
      endISO: isEdit ? (edit.endISO || window.todayISO()) : window.todayISO(),
    }, onClose);
    const [saving, setSaving] = useState(false);
    const set = (k) => (e) => setF((p) => ({ ...p, [k]: e.target.value }));
    const submit = async (e) => {
      e.preventDefault(); if (!f.name.trim()) return; setSaving(true);
      if (isEdit) await window.DB.updatePhase(projectId, edit.id, f);
      else await window.DB.createPhase(projectId, f);
      setSaving(false); window.toast(isEdit ? "บันทึกเฟสแล้ว" : "เพิ่มเฟสแล้ว"); onDone(); onClose();
    };
    return (
      <div className="login-overlay" onClick={window.NOOP}>
        <form className="login-card" style={{ maxWidth:460, width:"92vw" }} onClick={(e) => e.stopPropagation()} onSubmit={submit}>
          <button type="button" className="login-x icon-btn" onClick={safeClose}>{IC.x}</button>
          <div className="login-badge">{IC.gantt}</div>
          <h2>{isEdit ? "แก้ไขเฟส" : "เพิ่มเฟส"}</h2>
          <div style={{ display:"grid", gap:11, marginTop:4 }}>
            <label className="login-field"><span>ชื่อเฟส *</span><div className="login-input"><input value={f.name} onChange={set("name")} placeholder="เช่น งานโครงสร้าง" required /></div></label>
            <label className="login-field"><span>สถานะ</span><div className="login-input"><select value={f.status} onChange={set("status")} style={ediSel}>{Object.entries(D.phaseStatusMeta).map(([v, m]) => <option key={v} value={v}>{m.th}</option>)}</select></div></label>
            <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:10 }}>
              <window.DateField label="วันที่เริ่ม" value={f.startISO} onChange={(v) => setF((p) => ({ ...p, startISO: v }))} />
              <window.DateField label="วันที่สิ้นสุด" value={f.endISO} onChange={(v) => setF((p) => ({ ...p, endISO: v }))} />
            </div>
          </div>
          <div className="login-acts" style={{ marginTop:16 }}>
            <button type="button" className="btn" onClick={safeClose}>ยกเลิก</button>
            <button type="submit" className="btn pri" disabled={saving}>{saving ? "กำลังบันทึก…" : (isEdit ? "บันทึก" : "เพิ่มเฟส")}</button>
          </div>
        </form>
      </div>
    );
  }

  // Timeline item add/edit modal — start+end · title · detail · assignee · attachment · move-to-phase
  function ItemModal({ projectId, phaseId, edit, onClose, onDone }) {
    const isEdit = !!edit;
    const { useRef } = React;
    const fileRef = useRef(null);
    // find current phaseId for edit (item may live in any phase)
    const det = D.detail[projectId] || { phases: [] };
    let curPhaseId = phaseId;
    if (isEdit) det.phases.forEach((ph) => (ph.tasks || []).forEach((t) => { if (t.id === edit.id) curPhaseId = ph.id; }));
    const initSISO = isEdit ? (edit.dateISO || window.todayISO()) : window.todayISO();
    const initEISO = isEdit ? (edit.dateISOEnd || edit.dateISO || window.todayISO()) : window.todayISO();
    const [f, setF, safeClose] = window.useDirty({
      dateISO: initSISO,
      dateISOEnd: initEISO,
      title: isEdit ? edit.name : "", detail: isEdit ? (edit.detail || "") : "",
      assignee: isEdit ? (edit.assignee || "") : "", attachment: isEdit ? (edit.attachment || "") : "",
      // Default = auto-classify from dates. User can click to override.
      type: isEdit ? (edit.type || window.autoTypeFromDates(initSISO, initEISO)) : window.autoTypeFromDates(initSISO, initEISO),
      typeManual: isEdit && (edit.type === "milestone" || edit.type === "task"),
      status: isEdit ? edit.status : "todo",
      phaseId: curPhaseId,
    }, onClose);
    const [saving, setSaving] = useState(false);
    const fileBlobRef = React.useRef(null);
    const set = (k) => (e) => setF((p) => ({ ...p, [k]: e.target.value }));
    const submit = async (e) => {
      e.preventDefault(); if (!f.title.trim()) return;
      const sISO = f.dateISO, eISO = (f.dateISOEnd && f.dateISOEnd >= sISO) ? f.dateISOEnd : sISO;
      setSaving(true);
      let attachment = f.attachment;
      if (fileBlobRef.current && window.Files) {
        const up = await window.Files.safeUpload(fileBlobRef.current, { projectId, kind: "timeline" });
        attachment = up.url || up.name || attachment;
      }
      const payload = { ...f, dateISO: sISO, dateISOEnd: eISO, attachment };
      if (isEdit) {
        await window.DB.updateTimelineItem(projectId, edit.id, payload);
        if (f.phaseId && f.phaseId !== curPhaseId) await window.DB.moveTimelineItem(projectId, edit.id, f.phaseId);
      } else {
        await window.DB.createTimelineItem(projectId, phaseId, payload);
      }
      setSaving(false); window.toast(isEdit ? "บันทึกรายการแล้ว" : "เพิ่มรายการแล้ว"); onDone(); onClose();
    };
    return (
      <div className="login-overlay" onClick={window.NOOP}>
        <form className="login-card" style={{ maxWidth:500, width:"94vw", maxHeight:"92vh", overflowY:"auto" }} onClick={(e) => e.stopPropagation()} onSubmit={submit}>
          <button type="button" className="login-x icon-btn" onClick={safeClose}>{IC.x}</button>
          <div className="login-badge">{IC.flag}</div>
          <h2>{isEdit ? "แก้ไขรายการ" : "เพิ่มรายการ Timeline"}</h2>
          <div style={{ display:"grid", gap:11, marginTop:4 }}>
            <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:10 }}>
              <window.DateField label="วันที่เริ่มต้น" value={f.dateISO} onChange={(v) => setF((p) => {
                const newE = (p.dateISOEnd && p.dateISOEnd >= v) ? p.dateISOEnd : v;
                return { ...p, dateISO: v, dateISOEnd: newE, type: p.typeManual ? p.type : window.autoTypeFromDates(v, newE) };
              })} />
              <window.DateField label="วันที่สิ้นสุด" value={f.dateISOEnd} onChange={(v) => setF((p) => ({ ...p, dateISOEnd: v, type: p.typeManual ? p.type : window.autoTypeFromDates(p.dateISO, v) }))} />
            </div>
            <label className="login-field"><span>หัวข้อ *</span><div className="login-input"><input value={f.title} onChange={set("title")} placeholder="เช่น เริ่มงานฐานราก" required /></div></label>
            <label className="login-field"><span>รายละเอียด</span><div className="login-input" style={{ alignItems:"flex-start" }}><window.AutoTextarea value={f.detail} onChange={set("detail")} rows={3} placeholder="รายละเอียดของรายการ" /></div></label>
            <label className="login-field"><span>ผู้รับเรื่อง</span><div className="login-input"><input list="assignee-opts" value={f.assignee} onChange={set("assignee")} placeholder="พิมพ์หรือเลือก…" autoComplete="off" /><datalist id="assignee-opts">{(D.assignees||[]).map((a) => <option key={a} value={a} />)}</datalist></div></label>
            {/* Type — default auto-classify by dates, user can override by clicking */}
            <div>
              <div style={{ fontSize:12.5, color:"var(--muted)", marginBottom:5, display:"flex", alignItems:"center", justifyContent:"space-between", gap:8, flexWrap:"wrap" }}>
                <span>ประเภท{!f.typeManual && <span style={{ marginLeft:6, fontSize:11, color:"var(--faint)" }}>(ระบบเลือกให้ตามวันที่ — คลิกเพื่อปรับเอง)</span>}</span>
                {f.typeManual && <button type="button" onClick={() => setF((p) => ({ ...p, typeManual: false, type: window.autoTypeFromDates(p.dateISO, p.dateISOEnd) }))}
                  style={{ background:"none", border:0, color:"var(--accent)", fontSize:11.5, fontWeight:600, cursor:"pointer", padding:"2px 4px" }}>↻ ใช้ค่าอัตโนมัติ</button>}
              </div>
              <div style={{ display:"flex", gap:8, flexWrap:"wrap" }}>
                {[["milestone","♦","เหตุการณ์สำคัญ"],["task","🟢","งานดำเนินการ"]].map(([val, icon, label]) => {
                  const on = f.type === val;
                  return (
                    <button type="button" key={val}
                      onClick={() => setF((p) => ({ ...p, type: val, typeManual: true }))}
                      style={{ flex:"1 1 130px", display:"flex", alignItems:"center", justifyContent:"center", gap:7,
                               padding:"10px 12px", borderRadius:10, fontSize:13.5, fontWeight:600, cursor:"pointer",
                               border: on ? "2px solid var(--accent)" : "1px solid var(--line)",
                               background: on ? "var(--accent-tint)" : "var(--bg)",
                               color: on ? "var(--accent-d)" : "var(--ink2)" }}>
                      <span style={{ fontSize:16 }}>{icon}</span> {label}
                    </button>
                  );
                })}
              </div>
            </div>
            {isEdit && det.phases.length > 1 && (
              <label className="login-field"><span>ย้ายไปเฟส</span><div className="login-input"><select value={f.phaseId} onChange={set("phaseId")} style={ediSel}>{det.phases.map((ph) => <option key={ph.id} value={ph.id}>{ph.name}</option>)}</select></div></label>
            )}
            <input ref={fileRef} type="file" onChange={(e) => { const fl = e.target.files && e.target.files[0]; if (!fl) return; if (window.Files && fl.size > window.Files.MAX_BYTES) { window.toast("ไฟล์ใหญ่เกิน 100 MB"); return; } fileBlobRef.current = fl; setF((p) => ({ ...p, attachment: fl.name })); }} style={{ display:"none" }} />
            <button type="button" className="btn" style={{ width:"100%", justifyContent:"center", borderStyle:"dashed", padding:"11px" }} onClick={() => fileRef.current && fileRef.current.click()}>{IC.upload} {f.attachment ? f.attachment : "แนบไฟล์ (ถ้ามี)…"}</button>
          </div>
          <div className="login-acts" style={{ marginTop:16 }}>
            <button type="button" className="btn" onClick={safeClose}>ยกเลิก</button>
            <button type="submit" className="btn pri" disabled={saving}>{saving ? "กำลังบันทึก…" : (isEdit ? "บันทึก" : "เพิ่มรายการ")}</button>
          </div>
        </form>
      </div>
    );
  }

  // Full editable timeline: phases (add/edit/delete/reorder + drag) + items per phase (drag between phases)
  function TimelineEditor({ p, det, onChange }) {
    const [phaseModal, setPhaseModal] = useState(null);
    const [itemModal, setItemModal] = useState(null);
    const [editDates, setEditDates] = useState(false);
    const dragPhase = React.useRef(null);
    const dragItem  = React.useRef(null);   // { id, fromPhaseId }
    const reorderPhase = async (id, dir) => { await window.DB.reorderPhase(p.id, id, dir); onChange(); };
    const delPhase = async (ph) => { if (!confirm("ลบเฟส \"" + ph.name + "\" และรายการทั้งหมดในเฟส?")) return; await window.DB.deletePhase(p.id, ph.id); onChange(); window.toast("ลบเฟสแล้ว"); };
    const setPhaseStatus = async (ph, status) => { await window.DB.updatePhase(p.id, ph.id, { status }); onChange(); };
    const reorderItem = async (phId, id, dir) => { await window.DB.reorderTimelineItem(p.id, phId, id, dir); onChange(); };
    const delItem = async (id, name) => { if (!confirm("ลบรายการ \"" + name + "\" ?")) return; await window.DB.deleteTimelineItem(p.id, id); onChange(); window.toast("ลบรายการแล้ว"); };
    const onPhaseDrop = async (toId) => {
      const from = dragPhase.current; dragPhase.current = null;
      if (!from || from === toId) return;
      const i = det.phases.findIndex((x) => x.id === from), j = det.phases.findIndex((x) => x.id === toId);
      if (i < 0 || j < 0) return;
      const dir = j > i ? 1 : -1; const steps = Math.abs(j - i);
      for (let k = 0; k < steps; k++) await window.DB.reorderPhase(p.id, from, dir);
      onChange();
    };
    const onItemDrop = async (toPhaseId, toIndex) => {
      const d = dragItem.current; dragItem.current = null;
      if (!d) return;
      if (d.fromPhaseId === toPhaseId) { await window.DB.moveTimelineItem(p.id, d.id, toPhaseId, toIndex); }
      else { await window.DB.moveTimelineItem(p.id, d.id, toPhaseId, toIndex); }
      window.toast("ย้ายรายการแล้ว"); onChange();
    };
    const ctrlBtn = { width:28, height:28, padding:0, minHeight:0, borderRadius:7 };
    const statSel = { fontSize:11.5, padding:"3px 6px", borderRadius:7, border:"1px solid var(--line)", background:"var(--bg)", color:"var(--ink2)" };
    return (
      <div className="block">
        <div className="sh"><span className="sec-title">จัดการ Timeline</span>
          <div style={{ display:"flex", gap:6, flexWrap:"wrap" }}>
            <button className="btn sm" onClick={() => setEditDates(true)}>{IC.cal} ช่วงเวลาโครงการ</button>
            <button className="btn sm pri" onClick={() => setPhaseModal({})}>{IC.plus} เพิ่มเฟส</button>
          </div>
        </div>
        <div style={{ fontSize:12.5, color:"var(--muted)", margin:"-2px 2px 12px" }}>{IC.cal} ช่วงโครงการ: <b>{window.isoToBE(p.start)}</b> — <b>{window.isoToBE(p.end)}</b></div>

        {det.phases.map((ph, i) => {
          const psMeta = (D.phaseStatusMeta && D.phaseStatusMeta[ph.status]) || { tone: "neutral" };
          return (
          <div className="rail-card" key={ph.id} style={{ marginBottom:12, padding:0 }}
               onDragOver={(e) => { if (dragPhase.current) e.preventDefault(); }}
               onDrop={() => onPhaseDrop(ph.id)}>
            <div style={{ display:"flex", alignItems:"center", gap:8, padding:"11px 13px", borderBottom: (ph.tasks||[]).length ? "1px solid var(--line)" : "none" }}
                 draggable
                 onDragStart={(e) => { dragPhase.current = ph.id; e.dataTransfer.effectAllowed = "move"; }}
                 onDragEnd={() => { dragPhase.current = null; }}
                 title="ลากเพื่อจัดลำดับเฟส">
              <span className="ph-no" style={{ flex:"none", cursor:"grab" }}>{i+1}</span>
              <div style={{ flex:1, minWidth:0 }}>
                <div style={{ fontWeight:600, fontSize:14 }}>{ph.name}</div>
                <div style={{ fontSize:11.5, color:"var(--faint)" }}>{window.isoToBE(ph.startISO)} — {window.isoToBE(ph.endISO)}</div>
              </div>
              <select value={ph.status} onChange={(e) => setPhaseStatus(ph, e.target.value)} style={{ ...statSel, color:"var(--" + psMeta.tone + ")" }} title="เปลี่ยนสถานะ">
                {Object.entries(D.phaseStatusMeta).map(([v, m]) => <option key={v} value={v}>{m.th}</option>)}
              </select>
              <button className="icon-btn" title="เลื่อนขึ้น" style={ctrlBtn} disabled={i===0} onClick={() => reorderPhase(ph.id, -1)}>{IC.arrowUp}</button>
              <button className="icon-btn" title="เลื่อนลง" style={ctrlBtn} disabled={i===det.phases.length-1} onClick={() => reorderPhase(ph.id, 1)}>{IC.arrowDown}</button>
              <button className="icon-btn" title="แก้ไขเฟส" style={ctrlBtn} onClick={() => setPhaseModal({ edit: ph })}>{IC.settings}</button>
              <button className="icon-btn" title="ลบเฟส" style={{ ...ctrlBtn, color:"var(--danger)" }} onClick={() => delPhase(ph)}>{IC.x}</button>
            </div>
            <div onDragOver={(e) => { if (dragItem.current) e.preventDefault(); }}
                 onDrop={() => onItemDrop(ph.id, (ph.tasks||[]).length)}>
              {(ph.tasks||[]).map((t, ti) => {
                const span = t.dateISOEnd && t.dateISOEnd !== t.dateISO ? (window.isoToBE(t.dateISO) + " — " + window.isoToBE(t.dateISOEnd)) : (t.item_date || window.isoToBE(t.dateISO));
                const isMile = window.isMilestone(t);
                return (
                <div key={t.id} style={{ display:"flex", alignItems:"center", gap:9, padding:"8px 13px", borderBottom:"1px solid var(--line-soft)" }}
                     draggable
                     onDragStart={(e) => { dragItem.current = { id: t.id, fromPhaseId: ph.id }; e.dataTransfer.effectAllowed = "move"; e.stopPropagation(); }}
                     onDragOver={(e) => { if (dragItem.current) { e.preventDefault(); e.stopPropagation(); } }}
                     onDrop={(e) => { e.stopPropagation(); onItemDrop(ph.id, ti); }}
                     onDragEnd={() => { dragItem.current = null; }}
                     title="ลากเพื่อจัดลำดับ / ย้ายระหว่างเฟส">
                  <span style={{ color: isMile ? "var(--accent)" : "var(--muted)", flex:"none", cursor:"grab", fontSize: isMile ? 16 : 14, lineHeight:1 }} title={isMile ? "เหตุการณ์สำคัญ" : "งานดำเนินการ"}>{isMile ? "♦" : window.taskIcon(t.status)}</span>
                  <div style={{ flex:1, minWidth:0 }}>
                    <div style={{ fontSize:13.5, fontWeight:500, whiteSpace:"nowrap", overflow:"hidden", textOverflow:"ellipsis", display:"flex", gap:6, alignItems:"center" }}>{t.name}
                      <span className={"pill " + (isMile ? "info" : "ok")} style={{ fontSize:10.5, padding:"1px 7px", height:"auto", minHeight:0, flex:"none" }}>{isMile ? "เหตุการณ์สำคัญ" : "งานดำเนินการ"}</span>
                    </div>
                    <div style={{ fontSize:11, color:"var(--faint)" }}>{span}{t.assignee ? " · " + t.assignee : ""}</div>
                  </div>
                  <button className="icon-btn" title="ขึ้น" style={ctrlBtn} disabled={ti===0} onClick={() => reorderItem(ph.id, t.id, -1)}>{IC.arrowUp}</button>
                  <button className="icon-btn" title="ลง" style={ctrlBtn} disabled={ti===ph.tasks.length-1} onClick={() => reorderItem(ph.id, t.id, 1)}>{IC.arrowDown}</button>
                  <button className="icon-btn" title="แก้ไข" style={ctrlBtn} onClick={() => setItemModal({ phaseId: ph.id, edit: t })}>{IC.settings}</button>
                  <button className="icon-btn" title="ลบ" style={{ ...ctrlBtn, color:"var(--danger)" }} onClick={() => delItem(t.id, t.name)}>{IC.x}</button>
                </div>
              ); })}
            </div>
            <button className="btn sm" style={{ margin:10 }} onClick={() => setItemModal({ phaseId: ph.id })}>{IC.plus} เพิ่มรายการในเฟสนี้</button>
          </div>
        ); })}
        {det.phases.length === 0 && <div className="empty" style={{ padding:16, fontSize:13 }}>ยังไม่มีเฟส — กด "เพิ่มเฟส" เพื่อเริ่ม</div>}

        {phaseModal && <PhaseModal projectId={p.id} edit={phaseModal.edit} onClose={() => setPhaseModal(null)} onDone={onChange} />}
        {itemModal && <ItemModal projectId={p.id} phaseId={itemModal.phaseId} edit={itemModal.edit} onClose={() => setItemModal(null)} onDone={onChange} />}
        {editDates && window.ProjectFormModal && <window.ProjectFormModal edit={p} onClose={() => setEditDates(false)} onDone={onChange} />}
      </div>
    );
  }

  // Level 2 — Phase Timeline: each phase aggregates milestones + updates
  function PhaseTimeline({ p, det }) {
    const [open, setOpen] = useState(det.phases[0] ? det.phases[0].id : null);
    return (
      <div className="block">
        <div className="sh"><span className="sec-title">ไทม์ไลน์ระดับขั้นตอน</span><span className="page-sub" style={{ marginTop: 0 }}>เหตุการณ์สำคัญ · อัปเดต · การตัดสินใจ · ประชุม รายขั้นตอน</span></div>
        {det.phases.map((ph, i) => {
          const ups = (det.updates || []).filter((u) => u.phaseId === ph.id);
          const miles = (ph.tasks || []).filter((t) => window.isMilestone(t));
          const isOpen = open === ph.id;
          return (
            <div className={"phase" + (isOpen ? " open" : "")} key={ph.id}>
              <div className="ph-h" onClick={() => setOpen(isOpen ? null : ph.id)}>
                <span className="ph-no">{i + 1}</span>
                <div><div className="ph-name">{ph.name}</div><div className="ph-en">{ph.en} · {ph.owner}</div></div>
                <div className="ph-right">
                  <span className={"pill " + ((D.phaseStatusMeta[ph.status]||{tone:"neutral"}).tone)}><i />{(D.phaseStatusMeta[ph.status]||{th:ph.status}).th}</span>
                  {ups.length > 0 && <span className="pill neutral"><i />{ups.length} อัปเดต</span>}
                  <span className="ph-chev">{IC.chevR}</span>
                </div>
              </div>
              {isOpen && (
                <div style={{ padding: "2px 16px 14px" }}>
                  {miles.length > 0 && <div style={{ marginTop: 8 }}><div style={{ fontSize: 11.5, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: ".04em", marginBottom: 4 }}>เหตุการณ์สำคัญ</div>
                    {miles.map((t) => <div className="task-row milestone" key={t.id} style={{ paddingLeft: 0 }}><span className="tk-ic" style={{ color: t.status === "done" ? "var(--ok)" : "var(--accent)", fontSize:16 }}>♦</span><span className="tk-name">{t.name}</span></div>)}</div>}
                  {ups.length > 0 && <div style={{ marginTop: 12 }}><div style={{ fontSize: 11.5, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: ".04em", marginBottom: 4 }}>อัปเดต</div>
                    {ups.map((u) => { const m = D.updateTypes[u.type] || D.updateTypes.general; return (
                      <div key={u.id} style={{ display: "flex", gap: 9, padding: "5px 0", fontSize: 13.5 }}><i style={{ width: 7, height: 7, borderRadius: "50%", marginTop: 6, flexShrink: 0, background: "var(--" + m.tone + ")" }} /><span>{u.title} <span style={{ color: "var(--faint)" }}>· {m.th} · {u.date}</span></span></div>
                    ); })}</div>}
                  {miles.length === 0 && ups.length === 0 && <div className="empty" style={{ padding: 10, fontSize: 12.5 }}>ยังไม่มีเหตุการณ์สำคัญหรืออัปเดตในขั้นตอนนี้</div>}
                </div>
              )}
            </div>
          );
        })}
      </div>
    );
  }

  function UpdatesTab({ p, det, onChange }) {
    const [show, setShow] = useState(false);
    const [editing, setEditing] = useState(null);
    const canEdit = window.can("edit");
    const ups = det.updates || [];
    return (
      <div>
        <div className="sh"><span className="sec-title">อัปเดตโครงการ</span>
          {canEdit && <button className="btn sm pri" onClick={() => setShow(true)}>{IC.plus} อัปเดต</button>}
        </div>
        {ups.length === 0
          ? <window.EmptyState icon="trend" title="ยังไม่มีอัปเดต" sub="บันทึกความเคลื่อนไหวล่าสุดของโครงการ เช่น เริ่มงานฐานราก, ได้รับ BOQ, รออนุมัติงบ" ctaLabel={canEdit ? "บันทึกอัปเดตแรก" : undefined} onCta={canEdit ? () => setShow(true) : undefined} />
          : <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>{ups.map((u) => <window.UpdateCard key={u.id} u={u} onEdit={canEdit ? setEditing : null} />)}</div>}
        {show && window.UpdateModal && <window.UpdateModal fixedProjectId={p.id} onClose={() => setShow(false)} onDone={onChange} />}
        {editing && window.UpdateModal && <window.UpdateModal edit={editing} onClose={() => setEditing(null)} onDone={onChange} />}
      </div>
    );
  }

  function MeetingsTab({ p }) {
    const ms = D.meetingRecords.filter((m) => m.projectId === p.id || m.project === p.name);
    if (!ms.length) return <div className="empty">ยังไม่มีการประชุมสำหรับโครงการนี้ — เพิ่มได้ที่เมนู “การประชุม”</div>;
    return (
      <div className="rail-card">
        {ms.map((m) => (
          <div className="mt-item" key={m.id}>
            <div className="cal"><b className="tnum">{(m.date || "").split(" ")[0]}</b><span>{(m.date || "").split(" ")[1]}</span></div>
            <div style={{ flex: 1 }}><div className="mn">{m.title}</div><div className="mm">{m.type} · {m.time}{m.outcome ? " · " + m.outcome : ""}</div></div>
            <a className="btn sm" href="#/meetings">เปิด</a>
          </div>
        ))}
      </div>
    );
  }

  function BudgetTab({ p, det }) {
    const spentPct = p.budget ? Math.round(p.spent / p.budget * 100) : 0;
    const remain = Math.round((p.budget - p.spent) * 10) / 10;
    const budgetUps = (det.updates || []).filter((u) => u.type === "budget" || u.type === "approval");
    return (
      <div>
        <div className="metric-grid">
          <div className="metric"><div className="ml">งบประมาณรวม</div><div className="mv tnum">{window.fmtBaht(p.budget)}</div><div className="ms">ตามแผน</div></div>
          <div className="metric"><div className="ml">เบิกจ่ายแล้ว</div><div className="mv tnum">{window.fmtBaht(p.spent)}</div><div className="ms">{spentPct}% ของงบ</div></div>
          <div className="metric"><div className="ml">คงเหลือ</div><div className="mv tnum">{window.fmtBaht(remain)}</div><div className="ms">{100 - spentPct}% คงเหลือ</div></div>
          <div className="metric"><div className="ml">ผู้อนุมัติ</div><div className="mv" style={{ fontSize: 15, lineHeight: 1.3 }}>{p.approver}</div></div>
        </div>
        <div className="block">
          <div className="budget-bar">
            <div className="bt"><span>การใช้งบประมาณ</span><b>{window.fmtBaht(p.spent)} / {window.fmtBaht(p.budget)}</b></div>
            <div className="prog-bar"><i style={{ width: spentPct + "%", background: spentPct > 90 ? "var(--danger)" : "var(--accent)" }} /></div>
          </div>
        </div>
        {budgetUps.length > 0 && (
          <div className="block">
            <div className="sh"><span className="sec-title">ความเคลื่อนไหวด้านงบประมาณ</span></div>
            <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>{budgetUps.map((u) => <window.UpdateCard key={u.id} u={u} />)}</div>
          </div>
        )}
      </div>
    );
  }

  function ReportingTab({ p, det }) {
    const done = det.phases.filter((ph) => ph.status === "done").length;
    const latestUp = (det.updates || [])[0];
    const latestDec = (det.decisions || [])[0];
    const spentPct = p.budget ? Math.round(p.spent / p.budget * 100) : 0;
    return (
      <div>
        <div className="metric-grid">
          <div className="metric"><div className="ml">ความคืบหน้า</div><div className="mv tnum">{p.progress}%</div><div className="ms">{done}/{det.phases.length} เฟสเสร็จ</div></div>
          <div className="metric"><div className="ml">งบใช้ไป</div><div className="mv tnum">{spentPct}%</div><div className="ms">{window.fmtBaht(p.spent)} / {window.fmtBaht(p.budget)}</div></div>
          <div className="metric"><div className="ml">เฟสปัจจุบัน</div><div className="mv" style={{ fontSize: 15, lineHeight: 1.3 }}>{(det.phases.find((ph) => ph.status === "active") || det.phases[0] || {}).name || "—"}</div></div>
          <div className="metric"><div className="ml">ความเสี่ยง</div><div className="mv" style={{ fontSize: 15, lineHeight: 1.3 }}>{rm[p.risk] ? rm[p.risk].th : p.risk}</div><div className="ms">{p.riskNote}</div></div>
        </div>
        <div className="block">
          <div className="sh"><span className="sec-title">สรุปสำหรับผู้บริหาร</span></div>
          <div className="rail-card" style={{ padding: 16, lineHeight: 1.7, fontSize: 14 }}>
            <div><b>{p.name}</b> ({p.code}) — สถานะ <b>{sm[p.status].th}</b> ความคืบหน้า <b>{p.progress}%</b></div>
            <div style={{ color: "var(--ink2)", marginTop: 6 }}>เจ้าของงาน: {p.owner} · ผู้อนุมัติ: {p.approver} · กำหนดส่ง: {p.due}</div>
            {latestUp && <div style={{ marginTop: 8 }}>อัปเดตล่าสุด: <b>{latestUp.title}</b> ({latestUp.date}){latestUp.impact ? " — " + latestUp.impact : ""}</div>}
            {latestDec && <div style={{ marginTop: 4 }}>Decision ล่าสุด: <b>{latestDec.change}</b> ({latestDec.date})</div>}
            <div style={{ marginTop: 14 }}>
              <button className="btn pri" onClick={() => window.openReport("exec")}>{IC.download} เปิดรายงานฉบับเต็ม</button>
            </div>
          </div>
        </div>
      </div>
    );
  }

  function TimelineTab({ p, det, onChange }) {
    const [mode, setMode] = useState("admin");
    const [expanded, setExpanded] = useState(false);
    React.useEffect(() => {
      if (!expanded) return;
      const onKey = (e) => { if (e.key === "Escape") setExpanded(false); };
      document.addEventListener("keydown", onKey);
      return () => document.removeEventListener("keydown", onKey);
    }, [expanded]);
    const ganttBlock = (
      <div className={"gantt-wrap" + (expanded ? " gantt-expanded" : "")}>
        <div className="gantt-tools">
          <div className="legend" style={{ marginLeft: 0 }}>
            <span className="lg"><span className="barx" style={{ background: "var(--accent)" }} />กำลังทำ</span>
            <span className="lg"><span className="barx" style={{ background: "var(--ok)" }} />เสร็จ</span>
            <span className="lg"><span className="barx" style={{ background: "#B9B0A0" }} />ยังไม่เริ่ม</span>
            <span className="lg"><span className="dia" />เหตุการณ์สำคัญ</span>
            {mode === "admin" && <span className="lg"><span className="ln hard" />Hard</span>}
            {mode === "admin" && <span className="lg"><span className="ln soft" />Soft</span>}
          </div>
        </div>
        {(() => { const g = window.ganttScale(p, det); return <window.Gantt phases={g.phases} mode={mode} startISO={g.startISO} todayDay={g.todayDay} totalDays={g.totalDays} />; })()}
      </div>
    );
    return (
      <div>
        <div className="toolbar" style={{ marginTop: 0 }}>
          <div className="seg">
            <button className={mode === "exec" ? "on" : ""} onClick={() => setMode("exec")}>{IC.target} Executive</button>
            <button className={mode === "admin" ? "on" : ""} onClick={() => setMode("admin")}>{IC.layers} Admin</button>
          </div>
          <div className="seg">
            <button className={!expanded ? "on" : ""} onClick={() => setExpanded(false)}>ปกติ</button>
            <button className={expanded ? "on" : ""} onClick={() => setExpanded(true)}>ขยายเต็มหน้าจอ</button>
          </div>
          <span className="pill neutral" style={{ marginLeft: 4 }}><i />ระดับ 1 · โครงการ</span>
        </div>
        {!expanded && ganttBlock}
        {expanded && (
          <div className="gantt-overlay" onClick={(e) => { if (e.target.classList.contains("gantt-overlay")) setExpanded(false); }}>
            <div className="gantt-overlay-inner">
              <div className="gantt-overlay-bar">
                <div style={{ fontWeight: 600, fontSize: 15 }}>{p.name} · Timeline</div>
                <div className="seg">
                  <button className={mode === "exec" ? "on" : ""} onClick={() => setMode("exec")}>{IC.target} Executive</button>
                  <button className={mode === "admin" ? "on" : ""} onClick={() => setMode("admin")}>{IC.layers} Admin</button>
                </div>
                <button className="btn" onClick={() => setExpanded(false)}>{IC.x} ปิด (Esc)</button>
              </div>
              {ganttBlock}
            </div>
          </div>
        )}
        <PhaseTimeline p={p} det={det} />
        {mode === "admin" && window.can("edit") && <TimelineEditor p={p} det={det} onChange={onChange} />}
      </div>
    );
  }

  window.SCREENS.project = function ProjectDetail({ route }) {
    window.useLiveData();
    const [, bump] = useState(0);
    const refresh = () => bump((n) => n + 1);
    const [showEdit, setShowEdit] = useState(false);
    const p = D.projects.find((x) => x.id === route.id) || D.projects[0];
    if (!p) return <div className="page wide"><div className="empty">ไม่พบโครงการ</div></div>;
    const det = detailFor(p);
    const meetCt = D.meetingRecords.filter((m) => m.projectId === p.id || m.project === p.name).length;
    const TABS = [
      { id: "overview", label: "ภาพรวม" },
      { id: "timeline", label: "Timeline" },
      { id: "updates", label: "อัปเดต", ct: (det.updates || []).length },
      { id: "meetings", label: "ประชุม", ct: meetCt },
      { id: "decisions", label: "Decision", ct: det.decisions ? det.decisions.length : 0 },
      { id: "documents", label: "เอกสาร", ct: det.documents ? det.documents.length : 0 },
      { id: "budget", label: "งบประมาณ" },
      { id: "reporting", label: "รายงาน" },
      { id: "vendors", label: "Vendor", ct: det.vendors ? det.vendors.length : 0 },
      { id: "raci", label: "ทีม / RACI" },
    ];
    const [tab, setTab] = useState(route.tab && TABS.find((t) => t.id === route.tab) ? route.tab : "overview");

    return (
      <div className="page wide">
        <a className="backlink" href="#/projects">{IC.chevL} โครงการทั้งหมด</a>
        <div className="pd-grid">
          <div className="pd-main">
            <div className="pd-head">
              <div className="pd-title-row">
                <div style={{ flex: 1 }}>
                  <div className="eyebrow">{p.code} · {p.phaseTh}</div>
                  <h1 className="pd-title">{p.name}</h1>
                </div>
                <span className={"pill " + sm[p.status].tone}><i />{sm[p.status].th}</span>
              </div>
            </div>

            <SummaryCard p={p} det={det} mobile={true} onEdit={() => setShowEdit(true)} />

            <div className="tabs">
              {TABS.map((t) => (
                <button key={t.id} className={"tab" + (tab === t.id ? " on" : "")} onClick={() => setTab(t.id)}>
                  {t.label}{t.ct ? <span className="tb-ct">{t.ct}</span> : null}
                </button>
              ))}
            </div>

            <div className="tab-body">
              {tab === "overview" && <Overview p={p} det={det} />}
              {tab === "timeline" && <TimelineTab p={p} det={det} onChange={refresh} />}
              {tab === "updates" && <UpdatesTab p={p} det={det} onChange={refresh} />}
              {tab === "meetings" && <MeetingsTab p={p} />}
              {tab === "decisions" && <Decisions p={p} det={det} onChange={refresh} />}
              {tab === "documents" && <Documents det={det} />}
              {tab === "budget" && <BudgetTab p={p} det={det} />}
              {tab === "reporting" && <ReportingTab p={p} det={det} />}
              {tab === "vendors" && <Vendors det={det} />}
              {tab === "raci" && <Raci det={det} />}
            </div>
          </div>

          <aside className="pd-summary">
            <SummaryCard p={p} det={det} mobile={false} onEdit={() => setShowEdit(true)} />
          </aside>
        </div>

        {showEdit && window.ProjectFormModal && <window.ProjectFormModal edit={p} onClose={() => setShowEdit(false)} onDone={refresh} />}
      </div>
    );
  };
})();
