// projects-page.jsx — Проєктна діяльність: реєстр проєктів ГО + воркспейс одного
// проєкту (вкладки Огляд / Деліверабли / Задачі / Оплати / Команда / Документи)
// + картка контракту ГО для розділу «Договори».

(function () {
  const SYS = window.SYS_DATE || "2026-05-29";
  const money = (n) => (window.formatMoney ? window.formatMoney(n) : n);
  const fdate = (iso) => (window.formatDate ? window.formatDate(iso) : iso);
  const daysTo = (iso) => Math.round((new Date(iso + "T00:00:00") - new Date(SYS + "T00:00:00")) / 86400000);
  const ENTITY = (k) => (k === "fop" ? "ФОП Підкапка М.І." : "ТОВ «Укрбудпроєкт»");
  const ENTITY_SHORT = (k) => (k === "fop" ? "ФОП" : "ТОВ");

  // ════════════════════ РЕЄСТР ════════════════════
  function ProjectActivityPage({ role, onOpenProject }) {
    const projects = window.useProjects ? window.useProjects() : (window.DATA.PROJECTS || []);
    const [filter, setFilter] = React.useState("all");
    const [creating, setCreating] = React.useState(false);
    const canEdit = role === "director" || role === "accountant";

    const active = projects.filter(p => p.status === "active");
    const closed = projects.filter(p => p.status === "closed" || p.status === "archived");
    const shown = filter === "active" ? active : filter === "closed" ? closed : projects;

    // KPI
    const fopPaid = projects
      .filter(p => p.execEntity === "fop")
      .reduce((a, p) => a + window.projectSummary(p).paid, 0);
    const dlvLive = active.reduce((a, p) => a + (p.deliverables || []).filter(d => d.status === "in_progress").length, 0);
    const partners = (window.DATA.NGO_PARTNERS || []).length;

    return (
      <div className="page">
        <div className="page-head">
          <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 16 }}>
            <div>
              <h1 className="page-h1">Проєктна діяльність</h1>
              <div className="page-sub">
                <span>{projects.length} {window.plural(projects.length, "проєкт", "проєкти", "проєктів")} з ГО</span>
                <span className="dot"></span>
                <span>{active.length} активних · {closed.length} закритих</span>
                <span className="dot"></span>
                <span>грантові / донорські проєкти</span>
              </div>
            </div>
            {canEdit && <button className="btn btn-primary" style={{ flexShrink: 0 }} onClick={() => setCreating(true)}>
              <window.Icon.Plus /> Новий проєкт
            </button>}
          </div>
        </div>

        <div className="hint-box" style={{ marginTop: 0 }}>
          <b>Що це.</b> Робота в межах проєкту громадської організації (ГО): контракт живе рівно стільки, скільки сам проєкт донора —
          коли проєкт закривається, контракт переходить у статус «Закрито» й іде в архів. Виконавцем може бути <b>ФОП</b> або <b>ТОВ</b>;
          дохід ФОП-проєктів автоматично враховується в «Єдиний податок (ФОП)» (5% + 1% ВЗ).
        </div>

        <div className="kpi-row" style={{ gridTemplateColumns: "repeat(4, 1fr)" }}>
          <div className="kpi">
            <div className="kpi-label">Активних проєктів</div>
            <div className="kpi-value">{active.length}</div>
            <div className="kpi-sub">{closed.length} у архіві</div>
          </div>
          <div className="kpi">
            <div className="kpi-label">Отримано (ФОП, разом)</div>
            <div className="kpi-value">{money(fopPaid)} <span style={{ fontSize: 15, color: "var(--ink-3)" }}>₴</span></div>
            <div className="kpi-sub">оподатковано 5% + 1% ВЗ</div>
          </div>
          <div className="kpi">
            <div className="kpi-label">Деліверабли у роботі</div>
            <div className="kpi-value">{dlvLive}</div>
            <div className="kpi-sub">по активних проєктах</div>
          </div>
          <div className="kpi">
            <div className="kpi-label">Партнерів-ГО</div>
            <div className="kpi-value">{partners}</div>
            <div className="kpi-sub">у довіднику</div>
          </div>
        </div>

        <div className="toolbar" style={{ marginTop: 20 }}>
          <div className="filter-pill" role="tablist">
            <button className={`filter-pill-item ${filter === "all" ? "is-active" : ""}`} onClick={() => setFilter("all")}>
              Усі <span className="filter-pill-count">{projects.length}</span>
            </button>
            <button className={`filter-pill-item ${filter === "active" ? "is-active" : ""}`} onClick={() => setFilter("active")}>
              Активні <span className="filter-pill-count">{active.length}</span>
            </button>
            <button className={`filter-pill-item ${filter === "closed" ? "is-active" : ""}`} onClick={() => setFilter("closed")}>
              Закриті <span className="filter-pill-count">{closed.length}</span>
            </button>
          </div>
        </div>

        <div className="proj-stack">
          {shown.map(p => <ProjectCard key={p.id} project={p} onOpen={() => onOpenProject(p.id)} />)}
          {shown.length === 0 && <div className="empty" style={{ padding: 24 }}>Проєктів у цій категорії немає.</div>}
        </div>

        {creating && window.CreateGoProjectModal && (
          <window.CreateGoProjectModal onClose={() => setCreating(false)} onCreated={(p) => { setCreating(false); onOpenProject(p.id); }} />
        )}
      </div>
    );
  }

  function ProjectCard({ project, onOpen }) {
    const p = project;
    const partner = window.getNgoPartner(p.partner);
    const donor = window.getDonor(p.donor);
    const st = window.PROJECT_STATUS[p.status];
    const sum = window.projectSummary(p);

    return (
      <div className="proj-card" onClick={onOpen}>
        <div className="proj-card-top">
          <div className="proj-card-head">
            <span className="proj-code td-mono">{p.code}</span>
            <span className={`pd-entity pd-entity-${p.execEntity}`}>{ENTITY_SHORT(p.execEntity)}</span>
            <span className={`status-tag tone-${st.tone}`}>{st.label}</span>
          </div>
          <h3 className="proj-name">{p.name}</h3>
          <div className="proj-meta">
            <span><b>{partner?.short}</b></span>
            <span className="dot"></span>
            <span>донор: {donor?.name}</span>
            <span className="dot"></span>
            <span>{p.scope}</span>
          </div>
        </div>

        <div className="proj-card-side">
          <div className="proj-period">
            <span className="proj-period-label">Період</span>
            <span className="proj-period-val td-mono">{fdate(p.start)} → {p.closedDate ? fdate(p.closedDate) : fdate(p.end)}</span>
          </div>
          <div className="proj-amount">
            <div className="proj-amount-val td-mono">{money(sum.total)} <span style={{ color: "var(--ink-3)", fontWeight: 500, fontSize: 12 }}>₴</span></div>
            <div className="proj-amount-paid">отримано {money(sum.paid)} ₴ · {sum.paidPct}%</div>
          </div>
          <div className="proj-team">
            {(p.team || []).map(id => {
              const t = window.getTeam(id);
              return <div key={id} className="team-avatar" style={{ width: 26, height: 26, fontSize: 10 }} title={`${t?.name} · ${t?.role}`}>{t?.initials}</div>;
            })}
          </div>
        </div>

        <div className="obj-overall" style={{ padding: "0 18px 14px", gridColumn: "1 / -1" }}>
          <div className="obj-overall-bar"><div className="obj-overall-fill" style={{ width: sum.paidPct + "%" }}></div></div>
          <div className="obj-overall-meta">
            <span>деліверабли: {sum.dlvDone}/{sum.dlvTotal} готово</span>
            <span>оплата {sum.paidPct}%</span>
          </div>
        </div>
      </div>
    );
  }

  // ════════════════════ ВОРКСПЕЙС ════════════════════
  const PRJ_TABS = [
    { id: "overview",     label: "Огляд" },
    { id: "deliverables", label: "Деліверабли" },
    { id: "tasks",        label: "Задачі" },
    { id: "billing",      label: "Оплати" },
    { id: "team",         label: "Команда" },
    { id: "docs",         label: "Документи" },
  ];

  function ProjectGoWorkspace({ projId, role, onBack }) {
    if (window.useProjects) window.useProjects(); // реактивність при змінах стору
    const project = window.getGoProject(projId);
    const canEdit = role === "director" || role === "accountant";
    const [tab, setTab] = React.useState("overview");
    const [tasks, setTasks] = React.useState(() => (project ? (project.tasks || []).map(window.normalizeTask) : []));
    const [drawerTask, setDrawerTask] = React.useState(null);
    const [closing, setClosing] = React.useState(false);
    const [editing, setEditing] = React.useState(false);
    const [, forceTick] = React.useState(0);
    const persist = () => { if (window.ProjectsStore) window.ProjectsStore.save(); forceTick(x => x + 1); };

    React.useEffect(() => {
      const onKey = (e) => { if (e.key === "Escape") { if (drawerTask) setDrawerTask(null); else onBack(); } };
      window.addEventListener("keydown", onKey);
      return () => window.removeEventListener("keydown", onKey);
    }, [onBack, drawerTask]);

    // зберігаємо зміни задач у самому проєкті + у сторі (між перезавантаженнями)
    React.useEffect(() => { if (project) { project.tasks = tasks; if (window.ProjectsStore) window.ProjectsStore.save(); } }, [tasks, project]);

    if (!project) return <div className="page"><div className="empty">Проєкт не знайдено.</div></div>;

    const partner = window.getNgoPartner(project.partner);
    const donor = window.getDonor(project.donor);
    const st = window.PROJECT_STATUS[project.status];

    const onStatusChange = (taskId, status) => {
      setTasks(prev => prev.map(x => x.id === taskId ? { ...x, status } : x));
      setDrawerTask(d => d && d.id === taskId ? { ...d, status } : d);
    };
    const onTaskPatch = (taskId, patch) => {
      const apply = (x) => (typeof patch === "function" ? patch(x) : { ...x, ...patch });
      setTasks(prev => prev.map(x => x.id === taskId ? apply(x) : x));
      setDrawerTask(d => (d && d.id === taskId ? apply(d) : d));
    };

    return (
      <div className="page pw">
        <div className="pw-top">
          <button className="pw-back" onClick={onBack} title="До списку проєктів (Esc)">
            <svg width="15" height="15" viewBox="0 0 16 16" fill="none"><path d="M10 3L5 8l5 5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" /></svg>
            <span>Проєкти</span>
          </button>
          <div className="pw-top-main">
            <div className="pw-top-id">
              <span className="pw-code">{project.code}</span>
              <span className={`pd-entity pd-entity-${project.execEntity}`}>{ENTITY_SHORT(project.execEntity)}</span>
              <span className={`status-tag tone-${st.tone}`}>{st.label}</span>
            </div>
            <h1 className="pw-name">{project.name}</h1>
            <div className="pw-top-meta">
              <span><b>{partner?.short}</b></span>
              <span className="dot"></span>
              <span>донор: {donor?.name}</span>
              <span className="dot"></span>
              <span>{project.scope}</span>
            </div>
          </div>
          <div className="pw-top-side">
            <div className="pw-top-team">
              {(project.team || []).map(id => {
                const t = window.getTeam(id);
                return <div key={id} className="team-avatar" title={`${t?.name} · ${t?.role}`} style={{ width: 30, height: 30, fontSize: 11 }}>{t?.initials}</div>;
              })}
            </div>
            <div style={{ display: "flex", gap: 8 }}>
              {canEdit && <button className="btn btn-ghost" onClick={() => setEditing(true)}>Редагувати</button>}
              {canEdit && project.status === "active" && <button className="btn btn-ghost" onClick={() => setClosing(true)}>Закрити проєкт</button>}
              {canEdit && project.status !== "active" && <button className="btn btn-ghost" onClick={() => { window.reopenProject(projId); persist(); }}>Відновити</button>}
              <button className="btn btn-ghost">Drive ↗</button>
            </div>
          </div>
        </div>

        <div className="tab-bar pw-tabs">
          {PRJ_TABS.map(tb => {
            let c = null;
            if (tb.id === "tasks") c = tasks.filter(t => t.status !== "done").length;
            if (tb.id === "deliverables") c = (project.deliverables || []).filter(d => d.status !== "done").length;
            return (
              <button key={tb.id} className={`tab ${tab === tb.id ? "is-active" : ""}`} onClick={() => setTab(tb.id)}>
                {tb.label}{c != null && c > 0 && <span className="tab-count">{c}</span>}
              </button>
            );
          })}
        </div>

        {tab === "overview"     && <PrjOverview project={project} tasks={tasks} />}
        {tab === "deliverables" && <PrjDeliverables project={project} canEdit={canEdit} onChange={persist} />}
        {tab === "tasks"        && <PrjBoard tasks={tasks} setTasks={setTasks} onOpenTask={setDrawerTask} canEdit={canEdit} manager={project.manager} />}
        {tab === "billing"      && <PrjBilling project={project} />}
        {tab === "team"         && <PrjTeam project={project} tasks={tasks} />}
        {tab === "docs"         && <PrjDocs project={project} canEdit={canEdit} onChange={persist} />}

        {closing && (
          <CloseProjectConfirm
            project={project}
            onCancel={() => setClosing(false)}
            onConfirm={(note) => { window.closeProject(projId, note); persist(); setClosing(false); }}
          />
        )}

        {editing && window.CreateGoProjectModal && (
          <window.CreateGoProjectModal project={project} onClose={() => setEditing(false)} onCreated={() => { setEditing(false); persist(); }} />
        )}

        {drawerTask && window.Drawer && (
          <window.Drawer task={drawerTask} onClose={() => setDrawerTask(null)} onStatusChange={onStatusChange} onTaskPatch={onTaskPatch} onOpenProject={() => {}} />
        )}
      </div>
    );
  }

  // ── Підтвердження закриття проєкту ──
  function CloseProjectConfirm({ project, onCancel, onConfirm }) {
    const [note, setNote] = React.useState("Усі деліверабли передано, фінальний звіт донору затверджено. Проєкт завершено.");
    React.useEffect(() => {
      const onKey = (e) => e.key === "Escape" && onCancel();
      window.addEventListener("keydown", onKey);
      return () => window.removeEventListener("keydown", onKey);
    }, [onCancel]);
    return (
      <React.Fragment>
        <div className="drawer-overlay" onClick={onCancel}></div>
        <div className="report-modal" style={{ maxWidth: 480, inset: "auto", top: 80, bottom: "auto", left: "50%", transform: "translateX(-50%)", width: "calc(100% - 48px)" }}>
          <div className="report-toolbar">
            <button className="drawer-close" onClick={onCancel}><window.Icon.X /></button>
            <div className="nt-head-icon"><window.Ico name="check" /></div>
            <div>
              <div style={{ fontSize: 14, fontWeight: 600 }}>Закрити проєкт?</div>
              <div style={{ fontSize: 11.5, color: "var(--ink-3)" }}>{project.name}</div>
            </div>
          </div>
          <div style={{ padding: "20px 24px" }}>
            <p style={{ margin: "0 0 14px", fontSize: 13, color: "var(--ink-2)", lineHeight: 1.55 }}>
              Проєкт перейде у статус <b>«Закрито»</b> з датою {window.formatDate(window.SYS_DATE)} й одразу потрапить в архів. Контракт вважається закритим. Це можна скасувати кнопкою «Відновити».
            </p>
            <label className="cp-label">Підстава закриття</label>
            <textarea className="cp-input" rows={3} value={note} onChange={e => setNote(e.target.value)} style={{ resize: "vertical", width: "100%" }} />
          </div>
          <div className="report-foot" style={{ display: "flex", gap: 10, justifyContent: "flex-end", padding: "14px 24px", borderTop: "1px solid var(--line)" }}>
            <button className="btn btn-ghost" onClick={onCancel}>Скасувати</button>
            <button className="btn btn-primary" onClick={() => onConfirm(note.trim())}>Закрити проєкт</button>
          </div>
        </div>
      </React.Fragment>
    );
  }

  // ── Огляд ──
  function PrjOverview({ project, tasks }) {
    const p = project;
    const partner = window.getNgoPartner(p.partner);
    const donor = window.getDonor(p.donor);
    const sum = window.projectSummary(p);
    const activeTasks = tasks.filter(t => t.status !== "done").length;
    const lateTasks = tasks.filter(t => t.status === "late").length;
    const dl = daysTo(p.closedDate || p.end);
    const sched = (p.contract && p.contract.schedule) || [];
    const nextPay = sched.find(s => !s.paidDate);

    return (
      <div className="pw-grid">
        <div className="pw-main">
          <div className="kpi-row" style={{ marginBottom: 20 }}>
            <div className="kpi">
              <div className="kpi-label">Деліверабли</div>
              <div className="kpi-value">{sum.dlvDone}<span style={{ fontSize: 16, color: "var(--ink-3)" }}>/{sum.dlvTotal}</span></div>
              <div className="kpi-sub">{sum.dlvPct}% готово</div>
            </div>
            <div className="kpi">
              <div className="kpi-label">Отримано</div>
              <div className="kpi-value">{sum.paidPct}<span style={{ fontSize: 16, color: "var(--ink-3)" }}>%</span></div>
              <div className="kpi-sub">{money(sum.paid)} з {money(sum.total)} ₴</div>
            </div>
            <div className={`kpi ${lateTasks > 0 ? "is-warn" : ""}`}>
              <div className="kpi-label">Активних задач</div>
              <div className="kpi-value">{activeTasks}</div>
              <div className="kpi-sub">{lateTasks > 0 ? <span style={{ color: "var(--late)" }}>{lateTasks} прострочено</span> : "без прострочень"}</div>
            </div>
            <div className="kpi">
              <div className="kpi-label">{p.status === "closed" ? "Закрито" : "До завершення"}</div>
              <div className="kpi-value">{p.status === "closed" ? "✓" : dl}{p.status !== "closed" && <span style={{ fontSize: 15, color: "var(--ink-3)" }}> дн</span>}</div>
              <div className="kpi-sub">{p.status === "closed" ? fdate(p.closedDate) : `до ${fdate(p.end)}`}</div>
            </div>
          </div>

          {p.status === "closed" && (
            <div className="vat-alerts">
              <div className="vat-alert tone-neutral">
                <span className="vat-alert-ic"><window.Ico name="check" /></span>
                <div className="vat-alert-text">
                  <div className="vat-alert-title">Проєкт закрито {fdate(p.closedDate)} — контракт в архіві</div>
                  <div className="vat-alert-sub">{p.closeNote}</div>
                </div>
              </div>
            </div>
          )}
          {p.status === "active" && nextPay && (
            <div className="vat-alerts">
              <div className="vat-alert tone-blue">
                <span className="vat-alert-ic"><window.Ico name="calendar" /></span>
                <div className="vat-alert-text">
                  <div className="vat-alert-title">Наступний транш: {nextPay.stage} · {money(nextPay.amount)} ₴</div>
                  <div className="vat-alert-sub">план {fdate(nextPay.dueDate)} · {daysTo(nextPay.dueDate)} дн</div>
                </div>
              </div>
            </div>
          )}

          <div className="pw-card">
            <div className="pw-card-h">Предмет і обсяг робіт</div>
            <p style={{ margin: 0, fontSize: 13.5, color: "var(--ink-2)", lineHeight: 1.6 }}>{p.role}</p>
            <div style={{ marginTop: 12, fontSize: 12.5, color: "var(--ink-3)" }}>
              Громади ({(p.communities || []).length}):
            </div>
            <div className="pd-chips">
              {(p.communities || []).map((c, i) => (
                <span key={i} className="pd-chip" title={`${c.region} · ${c.facility}`}>{c.name}</span>
              ))}
            </div>
          </div>
        </div>

        <div className="pw-rail">
          <div className="pw-card">
            <div className="pw-card-h">Паспорт проєкту</div>
            <dl className="info-grid pw-passport">
              <div><dt>Шифр</dt><dd className="td-mono">{p.code}</dd></div>
              <div><dt>№ контракту</dt><dd className="td-mono">{p.number}</dd></div>
              <div><dt>Партнер</dt><dd>{partner?.name}</dd></div>
              <div><dt>Донор</dt><dd>{donor?.name}</dd></div>
              <div><dt>Виконавець</dt><dd>{ENTITY(p.execEntity)}</dd></div>
              <div><dt>Оподаткування</dt><dd>{p.execEntity === "fop" ? "ЄП 5% + 1% ВЗ" : "загальна (ПДВ)"}</dd></div>
              <div><dt>Старт</dt><dd>{fdate(p.start)}</dd></div>
              <div><dt>{p.status === "closed" ? "Закрито" : "Планове завершення"}</dt><dd>{fdate(p.closedDate || p.end)}</dd></div>
            </dl>
          </div>

          <div className="pw-card">
            <div className="pw-card-h">Партнер-ГО</div>
            <div style={{ fontSize: 13.5, fontWeight: 600 }}>{partner?.name}</div>
            <div style={{ fontSize: 12, color: "var(--ink-3)", marginTop: 2 }}>ЄДРПОУ {partner?.edrpou} · {partner?.city}</div>
            <div style={{ fontSize: 12.5, color: "var(--ink-2)", marginTop: 8, lineHeight: 1.5 }}>{partner?.focus}</div>
            {partner?.contact && (
              <div className="pd-contact">
                <div className="pd-contact-name">{partner.contact.name}</div>
                <div className="pd-contact-role">{partner.contact.role}</div>
                <div className="pd-contact-line td-mono">{partner.contact.phone}</div>
                <div className="pd-contact-line td-mono">{partner.contact.email}</div>
              </div>
            )}
          </div>
        </div>
      </div>
    );
  }

  // ── Деліверабли ──
  const DLV_CYCLE = { todo: "in_progress", in_progress: "done", done: "todo" };
  function PrjDeliverables({ project, canEdit, onChange }) {
    const dlv = project.deliverables || [];
    const DS = window.DELIVERABLE_STATUS;
    const [adding, setAdding] = React.useState(false);
    const [title, setTitle] = React.useState("");
    const [due, setDue] = React.useState("");

    const cycle = (d) => { if (!canEdit) return; d.status = DLV_CYCLE[d.status] || "todo"; onChange && onChange(); };
    const add = () => {
      const t = title.trim(); if (!t) return;
      project.deliverables = [...dlv, { id: "dl-" + Math.random().toString(36).slice(2, 6), title: t, due: due || project.end, status: "todo" }];
      setTitle(""); setDue(""); setAdding(false); onChange && onChange();
    };
    const remove = (id) => { project.deliverables = dlv.filter(x => x.id !== id); onChange && onChange(); };

    return (
      <div>
        <div className="hint-box" style={{ marginTop: 0 }}>
          <b>Деліверабли / етапи робіт.</b> Узгоджені з донором результати. {canEdit && <>Натисніть на статус, щоб змінити готовність.</>}
        </div>
        <table className="data-table">
          <thead><tr><th style={{ width: 44 }}>№</th><th>Деліверабл</th><th>Строк</th><th>Статус</th>{canEdit && <th style={{ width: 40 }}></th>}</tr></thead>
          <tbody>
            {dlv.map((d, i) => {
              const meta = DS[d.status] || DS.todo;
              const over = d.status !== "done" && daysTo(d.due) < 0;
              return (
                <tr key={d.id}>
                  <td className="td-mono" style={{ color: "var(--ink-3)" }}>{i + 1}</td>
                  <td style={{ fontWeight: 500 }}>{d.title}</td>
                  <td className="td-mono" style={{ fontSize: 12.5, color: over ? "var(--late)" : "var(--ink-2)" }}>{fdate(d.due)}</td>
                  <td>
                    <span className={`status-tag tone-${meta.tone}`} onClick={() => cycle(d)} style={{ cursor: canEdit ? "pointer" : "default" }} title={canEdit ? "Змінити статус" : ""}>{meta.label}</span>
                  </td>
                  {canEdit && <td><button className="prj-row-del" title="Видалити" onClick={() => remove(d.id)}><window.Ico name="x" size={13} /></button></td>}
                </tr>
              );
            })}
            {dlv.length === 0 && <tr><td colSpan={canEdit ? 5 : 4}><div className="empty" style={{ padding: "8px 0" }}>Деліверабли ще не додані.</div></td></tr>}
          </tbody>
        </table>
        {canEdit && (adding ? (
          <div className="prj-add-row">
            <input className="cp-input" autoFocus placeholder="Назва деліверабла" value={title} onChange={e => setTitle(e.target.value)} onKeyDown={e => e.key === "Enter" && add()} style={{ flex: 1 }} />
            <input className="cp-input" type="date" value={due} onChange={e => setDue(e.target.value)} style={{ width: 160 }} />
            <button className="btn btn-primary btn-sm" onClick={add}>Додати</button>
            <button className="btn btn-ghost btn-sm" onClick={() => { setAdding(false); setTitle(""); }}>Скасувати</button>
          </div>
        ) : (
          <button className="btn btn-sm" style={{ marginTop: 12 }} onClick={() => setAdding(true)}><window.Icon.Plus /> Додати деліверабл</button>
        ))}
      </div>
    );
  }

  // ── Задачі (дошка) ──
  const BOARD_COLS = [
    { id: "todo", label: "To Do",       color: "var(--ink-3)" },
    { id: "live", label: "У роботі",    color: "var(--c-green-deep)" },
    { id: "late", label: "Прострочено", color: "var(--late)" },
    { id: "done", label: "Виконано",    color: "var(--c-green)" },
  ];
  function PrjBoard({ tasks, setTasks, onOpenTask, canEdit, manager }) {
    const moveTask = (taskId, newStatus) => setTasks(prev => prev.map(t => t.id === taskId ? { ...t, status: newStatus } : t));
    const [addCol, setAddCol] = React.useState(null);
    const [title, setTitle] = React.useState("");
    const addTask = (status) => {
      const t = title.trim(); if (!t) return;
      const nt = window.normalizeTask({ id: "pt-" + Math.random().toString(36).slice(2, 6), title: t, obj: null, stage: "admin", section: "Проєкт ГО", assignee: manager || "ok", est: "—", status });
      setTasks(prev => [nt, ...prev]);
      setTitle(""); setAddCol(null);
    };
    const byStatus = {};
    BOARD_COLS.forEach(c => byStatus[c.id] = tasks.filter(t => t.status === c.id));
    return (
      <div className="kanban-board" style={{ marginTop: 4 }}>
        {BOARD_COLS.map(col => {
          const list = byStatus[col.id];
          return (
            <div key={col.id} className="kanban-col">
              <div className="kanban-col-head">
                <span className="kanban-col-title" style={{ color: col.color }}>{col.label}</span>
                <span className="kanban-col-count">{list.length}</span>
              </div>
              <div className="kanban-col-list">
                {list.length === 0
                  ? <div className="kanban-empty">—</div>
                  : list.map(task => (
                    <window.KanbanCard key={task.id} task={task} onOpen={() => onOpenTask(task)} onMove={(s) => moveTask(task.id, s)} columns={BOARD_COLS} />
                  ))}
              </div>
              {canEdit && (addCol === col.id ? (
                <div style={{ padding: 8 }}>
                  <input className="cp-input" autoFocus placeholder="Назва задачі" value={title} onChange={e => setTitle(e.target.value)} onKeyDown={e => { if (e.key === "Enter") addTask(col.id); if (e.key === "Escape") { setAddCol(null); setTitle(""); } }} style={{ width: "100%", marginBottom: 6 }} />
                  <div style={{ display: "flex", gap: 6 }}>
                    <button className="btn btn-primary btn-sm" onClick={() => addTask(col.id)}>Додати</button>
                    <button className="btn btn-ghost btn-sm" onClick={() => { setAddCol(null); setTitle(""); }}>×</button>
                  </div>
                </div>
              ) : (
                <button className="kanban-add" onClick={() => { setAddCol(col.id); setTitle(""); }}><window.Icon.Plus /> Додати задачу</button>
              ))}
            </div>
          );
        })}
      </div>
    );
  }

  // ── Оплати (переюз графіка фінансування) ──
  function PrjBilling({ project }) {
    const [printDraft, setPrintDraft] = React.useState(null);
    const [printAct, setPrintAct] = React.useState(null);
    const [donorBuilder, setDonorBuilder] = React.useState(false);
    const [donorModel, setDonorModel] = React.useState(null);
    const save = () => { if (window.ProjectsStore) window.ProjectsStore.save(); };
    return (
      <div>
        <div className="hint-box" style={{ marginTop: 0 }}>
          <b>Графік фінансування проєкту.</b> Транші донора через партнера-ГО. {project.execEntity === "fop"
            ? <React.Fragment>Надходження на рахунок <b>ФОП</b> оподатковуються єдиним податком <b>5% + 1% ВЗ</b> і відображаються в «Єдиний податок (ФОП)».</React.Fragment>
            : <React.Fragment>Надходження на рахунок <b>ТОВ</b> — за загальною системою.</React.Fragment>}
        </div>

        <div style={{ display: "flex", gap: 10, margin: "0 0 14px", flexWrap: "wrap" }}>
          <button className="btn btn-primary" onClick={() => setDonorBuilder(true)}>
            <window.Ico name="clipboard" size={15} /> Акт за шаблоном донора
          </button>
        </div>

        {window.ContractSchedule
          ? <window.ContractSchedule contract={project.contract} role={window.__role}
              onPrintInvoice={(d) => { setPrintDraft(d); save(); }}
              onPrintAct={(a) => { setPrintAct(a); save(); }} />
          : <div className="empty">Графік недоступний.</div>}

        {printDraft && window.InvoicePrintDoc && <window.InvoicePrintDoc invoice={printDraft} onClose={() => setPrintDraft(null)} />}
        {printAct && window.ActPrintDoc && <window.ActPrintDoc act={printAct} onClose={() => setPrintAct(null)} />}
        {donorBuilder && window.DonorActBuilder && <window.DonorActBuilder project={project} onClose={() => setDonorBuilder(false)} onOpenDoc={(m) => { setDonorBuilder(false); setDonorModel(m); }} />}
        {donorModel && window.DonorActPrintDoc && <window.DonorActPrintDoc model={donorModel} onClose={() => setDonorModel(null)} />}
      </div>
    );
  }

  // ── Команда ──
  function PrjTeam({ project, tasks }) {
    return (
      <div className="pw-card" style={{ maxWidth: 640 }}>
        <div className="pw-card-h">Команда проєкту</div>
        <div className="pw-team">
          {(project.team || []).map(id => {
            const p = window.getTeam(id);
            const mine = tasks.filter(t => t.assignee === id && t.status !== "done").length;
            const late = tasks.filter(t => t.assignee === id && t.status === "late").length;
            const isManager = project.manager === id;
            return (
              <div key={id} className="pw-team-row">
                <div className="team-avatar" style={{ width: 30, height: 30, fontSize: 11 }}>{p?.initials}</div>
                <div className="pw-team-meta">
                  <div className="pw-team-name">{p?.name}{isManager && <span className="pd-manager">менеджер проєкту</span>}</div>
                  <div className="pw-team-role">{p?.role}</div>
                </div>
                <div className="pw-team-tasks">
                  <span>{mine} задач</span>
                  {late > 0 && <span className="pw-team-late">{late} простр.</span>}
                </div>
              </div>
            );
          })}
        </div>
      </div>
    );
  }

  // ── Документи ──
  const DOC_LABEL = { contract: "Договір", tz: "ТЗ", report: "Звіт", act: "Акт", other: "Інше" };
  function PrjDocs({ project, canEdit, onChange }) {
    const docs = project.docs || [];
    const [adding, setAdding] = React.useState(false);
    const [name, setName] = React.useState("");
    const [type, setType] = React.useState("report");
    const add = () => {
      const n = name.trim(); if (!n) return;
      project.docs = [...docs, { name: n, type, date: window.SYS_DATE }];
      setName(""); setType("report"); setAdding(false); onChange && onChange();
    };
    const remove = (i) => { project.docs = docs.filter((_, idx) => idx !== i); onChange && onChange(); };
    const openDrive = () => window.open("https://drive.google.com", "_blank");
    const SUBF = ["01-Договір", "02-ТЗ", "03-Робочі матеріали", "04-Звіти донору", "05-Акти"];
    return (
      <div>
        <div className="drive-status" style={{ marginTop: 0 }}>
          <div className="drive-status-icon"><window.Ico name="folder" /></div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 13.5, fontWeight: 600, color: "var(--ink)" }}>Папка проєкту в Google Drive</div>
            <div className="td-mono" style={{ fontSize: 11.5, color: "var(--ink-3)", marginTop: 2 }}>[{project.code}] {project.name}</div>
            <div className="pd-chips" style={{ marginTop: 8 }}>
              {SUBF.map(s => <span key={s} className="pd-chip" style={{ fontSize: 11 }}>{s}</span>)}
            </div>
          </div>
          {canEdit && <button className="btn" onClick={openDrive}>Завантажити файл</button>}
          <button className="btn btn-primary" onClick={openDrive}>Відкрити у Drive ↗</button>
        </div>
        <div className="hint-box" style={{ marginTop: 14 }}>
          <b>Файли — у Google Drive.</b> Документи зберігаються у спільному акаунті <code>files@ukrbudproiekt.ua</code> (100 GB).
          Записи нижче — посилання на файли в папці проєкту; «Drive ↗» відкриває файл у Drive.
        </div>
        <table className="data-table">
          <thead><tr><th>Документ</th><th style={{ width: 130 }}>Тип</th><th style={{ width: 120 }}>Дата</th><th style={{ width: 140 }}></th></tr></thead>
          <tbody>
            {docs.map((d, i) => (
              <tr key={i}>
                <td style={{ fontWeight: 500 }}><span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}><window.Ico name="file" size={14} /> {d.name}</span></td>
                <td><span className="status-tag tone-neutral">{DOC_LABEL[d.type] || d.type}</span></td>
                <td className="td-mono" style={{ fontSize: 12.5, color: "var(--ink-2)" }}>{fdate(d.date)}</td>
                <td style={{ display: "flex", gap: 6, justifyContent: "flex-end" }}>
                  <button className="btn btn-sm" onClick={openDrive}><window.Ico name="externalLink" size={13} /> Drive</button>
                  {canEdit && <button className="prj-row-del" title="Видалити" onClick={() => remove(i)}><window.Ico name="x" size={13} /></button>}
                </td>
              </tr>
            ))}
            {docs.length === 0 && <tr><td colSpan={4}><div className="empty" style={{ padding: "8px 0" }}>Документів ще немає.</div></td></tr>}
          </tbody>
        </table>
        {canEdit && (adding ? (
          <div className="prj-add-row">
            <input className="cp-input" autoFocus placeholder="Назва документа" value={name} onChange={e => setName(e.target.value)} onKeyDown={e => e.key === "Enter" && add()} style={{ flex: 1 }} />
            <select className="cp-input" value={type} onChange={e => setType(e.target.value)} style={{ width: 130 }}>
              {Object.keys(DOC_LABEL).map(k => <option key={k} value={k}>{DOC_LABEL[k]}</option>)}
            </select>
            <button className="btn btn-primary btn-sm" onClick={add}>Додати</button>
            <button className="btn btn-ghost btn-sm" onClick={() => { setAdding(false); setName(""); }}>Скасувати</button>
          </div>
        ) : (
          <button className="btn btn-sm" style={{ marginTop: 12 }} onClick={() => setAdding(true)}><window.Icon.Plus /> Додати документ</button>
        ))}
      </div>
    );
  }

  // ════════════════════ КАРТКА КОНТРАКТУ ГО (для «Договори») ════════════════════
  function ProjectContractCard({ project, isOpen, onToggle }) {
    const p = project;
    const partner = window.getNgoPartner(p.partner);
    const donor = window.getDonor(p.donor);
    const c = p.contract;
    const st = window.PROJECT_STATUS[p.status];
    const paid = (c.schedule || []).filter(s => s.paidDate).reduce((s, x) => s + x.amount, 0);
    const total = c.total;
    const progressPct = total ? Math.round(paid / total * 100) : 0;

    return (
      <div className={`contract-card ${isOpen ? "is-open" : ""}`}>
        <div className="contract-card-head" onClick={onToggle}>
          <div className="contract-num">
            <div className="contract-num-val">№ {c.number}</div>
            <div className="contract-num-date">{fdate(c.date)}</div>
          </div>
          <div className="contract-main">
            <div className="contract-name">
              {p.name} <span style={{ fontWeight: 400, color: "var(--ink-3)" }}>· {p.code}</span>
              <span className="pd-badge">Проєкт ГО</span>
            </div>
            <div className="contract-meta">
              <span>{partner?.short}</span>
              <span className="dot"></span>
              <span>донор: {donor?.name}</span>
              <span className="dot"></span>
              <span className={`pd-entity pd-entity-${p.execEntity}`}>{ENTITY_SHORT(p.execEntity)}</span>
              <span className="dot"></span>
              <span>{(c.schedule || []).length} {window.plural((c.schedule || []).length, "транш", "транші", "траншів")}</span>
            </div>
          </div>
          <div className="contract-amount">
            <div className="contract-amount-val">{money(total)} <span style={{ color: "var(--ink-3)", fontWeight: 500, fontSize: 13 }}>₴</span></div>
            <div className="contract-amount-paid">отримано {money(paid)} ₴</div>
          </div>
          <span className={`status-tag tone-${st.tone}`}>{st.label}</span>
          <button className="obj-card-toggle">
            <svg width="14" height="14" viewBox="0 0 14 14" fill="none" style={{ transform: isOpen ? "rotate(180deg)" : "none", transition: "transform 0.2s" }}>
              <path d="M3 5L7 9L11 5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </button>
        </div>

        <div className="obj-overall">
          <div className="obj-overall-bar"><div className="obj-overall-fill" style={{ width: progressPct + "%" }}></div></div>
          <div className="obj-overall-meta">
            <span>{paid > 0 ? `отримано ${progressPct}%` : "очікує першого траншу"}</span>
            <span>{money(paid)} / {money(total)} ₴</span>
          </div>
        </div>

        {isOpen && (
          <div className="contract-schedule">
            {window.ContractSchedule && <window.ContractSchedule contract={c} role={window.__role} />}
          </div>
        )}
      </div>
    );
  }

  // ════════════════════ ДОВІДНИК ПАРТНЕРІВ ГО / ДОНОРІВ ════════════════════
  function NgoDirectoryPage({ role }) {
    if (window.useProjects) window.useProjects();
    const partners = window.DATA.NGO_PARTNERS || [];
    const donors = window.DATA.DONORS || [];
    const projects = window.DATA.PROJECTS || [];
    const prjCountBy = (key, id) => projects.filter(p => p[key] === id).length;

    return (
      <div className="page">
        <div className="page-head">
          <h1 className="page-h1">Партнери та донори</h1>
          <div className="page-sub">
            <span>{partners.length} {window.plural(partners.length, "партнер", "партнери", "партнерів")}-ГО</span>
            <span className="dot"></span>
            <span>{donors.length} {window.plural(donors.length, "донор", "донори", "донорів")}</span>
            <span className="dot"></span>
            <span>довідник для проєктної діяльності</span>
          </div>
        </div>

        <section className="section">
          <div className="section-head"><h2 className="section-h2">Партнери-ГО</h2><span className="section-sub">{partners.length}</span></div>
          <div className="ngo-dir-grid">
            {partners.map(p => {
              const cnt = prjCountBy("partner", p.id);
              const r = p.requisites || {};
              return (
                <div key={p.id} className="pw-card" style={{ marginBottom: 0 }}>
                  <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 10 }}>
                    <div>
                      <div style={{ fontSize: 14.5, fontWeight: 700 }}>{p.name}</div>
                      <div style={{ fontSize: 12, color: "var(--ink-3)", marginTop: 2 }}>ЄДРПОУ {r.edrpou || p.edrpou} · {p.city}</div>
                    </div>
                    {cnt > 0 && <span className="status-tag tone-live">{cnt} {window.plural(cnt, "проєкт", "проєкти", "проєктів")}</span>}
                  </div>
                  <div style={{ fontSize: 12.5, color: "var(--ink-2)", marginTop: 8, lineHeight: 1.5 }}>{p.focus}</div>
                  {p.contact && (
                    <div className="pd-contact">
                      <div className="pd-contact-name">{p.contact.name}</div>
                      <div className="pd-contact-role">{p.contact.role}</div>
                      {p.contact.phone && <div className="pd-contact-line td-mono">{p.contact.phone}</div>}
                      {p.contact.email && <div className="pd-contact-line td-mono">{p.contact.email}</div>}
                    </div>
                  )}
                  {r.iban && <div style={{ marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--line)", fontSize: 11.5, color: "var(--ink-3)" }}>
                    <div className="td-mono" style={{ wordBreak: "break-all" }}>IBAN {r.iban}</div>
                    <div>{r.bank}</div>
                  </div>}
                </div>
              );
            })}
          </div>
        </section>

        <section className="section">
          <div className="section-head"><h2 className="section-h2">Донори</h2><span className="section-sub">{donors.length}</span></div>
          <div className="ngo-dir-grid">
            {donors.map(d => {
              const cnt = prjCountBy("donor", d.id);
              return (
                <div key={d.id} className="pw-card" style={{ marginBottom: 0 }}>
                  <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 10 }}>
                    <div>
                      <div style={{ fontSize: 14.5, fontWeight: 700 }}>{d.name}</div>
                      {d.nameUk && d.nameUk !== d.name && <div style={{ fontSize: 12, color: "var(--ink-3)", marginTop: 2 }}>{d.nameUk}</div>}
                    </div>
                    {cnt > 0 && <span className="status-tag tone-live">{cnt} {window.plural(cnt, "проєкт", "проєкти", "проєктів")}</span>}
                  </div>
                  <div style={{ fontSize: 12.5, color: "var(--ink-3)", marginTop: 8 }}>{d.country} · {d.kind}</div>
                  {d.note && <div style={{ fontSize: 12.5, color: "var(--ink-2)", marginTop: 8, lineHeight: 1.5 }}>{d.note}</div>}
                </div>
              );
            })}
          </div>
        </section>

        <div className="hint-box">
          Нові партнери й донори додаються автоматично під час створення проєкту («Проєктна діяльність → Новий проєкт → + Інша ГО / + Інший донор»).
        </div>
      </div>
    );
  }

  window.ProjectActivityPage = ProjectActivityPage;
  window.ProjectGoWorkspace = ProjectGoWorkspace;
  window.ProjectContractCard = ProjectContractCard;
  window.NgoDirectoryPage = NgoDirectoryPage;
})();
