// ============================================================================
// IMS — Influencer Profile (shared across roles, tabs scoped by role)
// ============================================================================

function CopyButton({ text }) {
  const [copied, setCopied] = useState(false);
  return (
    <button className="btn ghost sm" onClick={() => {
      navigator.clipboard.writeText(text).then(() => {
        setCopied(true);
        setTimeout(() => setCopied(false), 2000);
      });
    }}>
      {copied ? "Copied!" : "Copy"}
    </button>
  );
}

function ProfilePage({ influencer, from, fromCampaign }) {
  const { role, setPage, notify, moveToLeads, data, activePersonId, removeFromUnassigned, updateInfluencer, updateCollabRecord, addRequest, promoteOSBonus, archiveInfluencer, dropInfluencer, restoreDroppedInfluencer, completeStage, overrideInfluencerStatus, notifyAdminOfOSStatus, notifyAdminOfOverrideDispute } = useApp();

  const fromPeople = from === "people-influencers";

  // Derive live campaign record for this assignment (if any)
  const campaignRecord = useMemo(() => {
    const cid = influencer.campaignId || fromCampaign?.id;
    return cid ? (data.campaigns || []).find(c => c.id === cid) || null : null;
  }, [data, influencer.campaignId, fromCampaign]);
  const campaignStatus = campaignRecord?.status || null;
  const campaignBlocked = campaignStatus && campaignStatus !== "Active"; // Paused / Completed / Archived

  // which tabs to show
  const tabs = useMemo(() => {
    const hasCMData = !!(influencer.cmId || influencer.currentStage);
    const allCollabCount = (data.collabInProgress || []).filter(r => r.id === influencer.id && !r.deletedAt).length;

    // People → Influencers: only Overview + Campaigns (no stage/payment/activity clutter)
    if (fromPeople) {
      const t = [{ key: "overview", label: "Overview" }];
      if (allCollabCount > 0) t.push({ key: "campaigns", label: `Campaigns (${allCollabCount})` });
      return t;
    }

    // All other contexts (CM in-progress, campaign-detail, OS in-progress, etc.)
    const t = [{ key: "overview", label: "Overview" }];
    if (role === "outreach" || role === "admin") t.push({ key: "conversation", label: "Conversation / Outreach" });
    if (role === "collab" && hasCMData) t.push({ key: "stages", label: "Stages" });
    if (role === "admin" && hasCMData) t.push({ key: "stages", label: "Stages" });
    if (role === "admin") t.push({ key: "payments", label: "Payments" });
    t.push({ key: "activity", label: "Activity Log" });
    t.push({ key: "requests", label: "Requests" });
    return t;
  }, [role, influencer, from, data]);

  const [tab, setTab] = useState(tabs[0].key);
  const [statusPrompt, setStatusPrompt] = useState(null);
  const [stagePrompt, setStagePrompt] = useState(null);
  const [requestOpen, setRequestOpen] = useState(false);
  const [addNoteOpen, setAddNoteOpen] = useState(false);
  const [overrideOpen, setOverrideOpen] = useState(false);
  const [reassignOpen, setReassignOpen] = useState(false);
  const [editOpen, setEditOpen] = useState(false);
  const [dropOpen, setDropOpen] = useState(false);
  const [archiveOpen, setArchiveOpen] = useState(false);
  const [influencerData, setInfluencerData] = useState(influencer);

  // Admin-override banner (shown to OS and CM when adminOverridePending is true)
  const [overrideBanner, setOverrideBanner] = useState((role === "outreach" || role === "collab") && !!influencer.adminOverridePending);

  const goBack = () => {
    if (from === "campaign-detail" && fromCampaign) setPage({ key: "campaign-detail", campaign: fromCampaign });
    else setPage({ key: from || "os-in-progress" });
  };

  return (
    <div className="page" style={{ paddingTop: 0 }}>
      <div style={{ position: "sticky", top: 0, background: "var(--bg)", zIndex: 6, paddingTop: 24, paddingBottom: 0, borderBottom: "1px solid var(--line)" }}>
        <button className="btn ghost sm" onClick={() => goBack()} style={{ marginBottom: 12 }}>
          <Ic.arrowLeft /> Back
        </button>

        <div className="profile-head">
          <div className="avatar-lg">{influencerData.name.split(" ").map(n => n[0]).slice(0,2).join("")}</div>
          <div style={{ flex: 1 }}>
            <h2>{influencerData.name}</h2>
            <div className="handle-line">
              <span className="handle">{influencerData.handle}</span>
              <span className="sep">·</span>
              <span>{influencerData.platform}</span>
              <span className="sep">·</span>
              <span>{influencerData.followers} followers</span>
              <span className="sep">·</span>
              <span>{influencerData.category}</span>
              <span className="sep">·</span>
              <span>{influencerData.location}</span>
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 10, flexWrap: "wrap" }}>
              {influencerData.bundleId && <BundleIdChip id={influencerData.bundleId} />}
              {influencerData.status && <StatusChip status={influencerData.status} />}
              {influencerData.hasSignedContract && (
                <Chip tone="ok"><Ic.check /> Contract Signed</Chip>
              )}
              {(() => {
                const allCamps = (data.collabInProgress || []).filter(r => r.id === influencerData.id && !r.deletedAt);
                if (allCamps.length > 1) {
                  // Multiple campaigns — just show count, details in Campaigns tab
                  return <Chip tone="info">{allCamps.length} Active Campaigns</Chip>;
                }
                if (allCamps.length === 1) {
                  const c = allCamps[0];
                  return <Chip tone={c.stageState === "Complete" ? "ok" : "info"}>
                    {c.campaignName} · {c.stageState === "Complete" ? "Done" : `S${c.currentStage}`}
                  </Chip>;
                }
                // Single collab record from influencer object (non-people context)
                if (influencerData.currentStage && (role === "admin" || role === "collab")) {
                  return influencerData.stageState === "Complete"
                    ? <Chip tone="ok">Completed</Chip>
                    : <Chip tone="info">Stage {influencerData.currentStage} · {influencerData.stageState}</Chip>;
                }
                return null;
              })()}
              {influencerData.previouslyRejected && <Chip tone="bad"><Ic.info /> Previously Rejected</Chip>}
            </div>
          </div>
          <div style={{ display: "flex", gap: 8, flexDirection: "column", alignItems: "flex-end" }}>
            <div style={{ display: "flex", gap: 8 }}>
              {influencerData.bundleId && (
                <button className="btn sm" onClick={() => window.open("https://linear.app", "_blank")}>
                  Open Linear
                </button>
              )}
              {role === "admin" && (
                <button className="btn sm" onClick={() => setEditOpen(true)}>
                  Edit Profile
                </button>
              )}
              {role === "admin" && (
                <button className="btn sm danger" onClick={() => setArchiveOpen(true)}>
                  Archive
                </button>
              )}
              {role === "admin" && (
                <button className="btn sm" onClick={() => setAddNoteOpen(true)}>
                  <Ic.plus /> Add Note
                </button>
              )}
            </div>
            <div style={{ display: "flex", gap: 8 }}>
              {(role === "outreach" || role === "collab") && (
                <button className="btn sm" onClick={() => setRequestOpen(true)}>
                  <Ic.info /> Request Help
                </button>
              )}
              {role === "outreach" && (() => {
                const st = influencerData.status;
                if (!st || st === "Not Contacted") {
                  return <button className="btn sm" onClick={() => setStatusPrompt("Contacted")}>Mark Contacted</button>;
                }
                if (st === "Contacted") {
                  return <>
                    <button className="btn sm accent" onClick={() => setStatusPrompt("Interested")}>Mark Interested</button>
                    <button className="btn sm" onClick={() => setStatusPrompt("No Response")}>No Response</button>
                    <button className="btn sm danger" onClick={() => setStatusPrompt("Rejected")}>Reject</button>
                  </>;
                }
                if (st === "No Response") {
                  return <button className="btn sm accent" onClick={() => setStatusPrompt("Future Response Received")}>Mark Future Response</button>;
                }
                if (influencerData.adminOverridePending) {
                  return <button className="btn sm danger" onClick={() => setStatusPrompt("Contacted")}>Change Status Back</button>;
                }
                return null;
              })()}
              {role === "collab" && !fromPeople && (
                <>
                  <button
                    className="btn sm accent"
                    disabled={!!campaignBlocked || influencerData.stageState === "Complete" || influencerData.stageState === "Dropped"}
                    title={campaignBlocked ? `Campaign is ${campaignStatus} — stage progression not allowed` : undefined}
                    onClick={() => setStagePrompt({ stage: (influencerData.currentStage || 1), action: influencerData.stageState === "In Progress" ? "complete" : "advance" })}>
                    Progress Stage
                  </button>
                  <button className="btn sm danger" disabled={!!campaignBlocked} onClick={() => setDropOpen(true)}>Drop</button>
                </>
              )}
              {role === "admin" && influencerData.specialistId && from !== "people-influencers" && (
                <button className="btn sm" onClick={() => setReassignOpen(true)}>
                  <Ic.arrowRight /> Reassign
                </button>
              )}
              {role === "admin" && influencerData.specialistId && from !== "people-influencers" && (
                <button className="btn sm accent" onClick={() => setOverrideOpen(true)}>
                  Admin: Override Status
                </button>
              )}
              {/* Fix 3: Restore dropped influencer — admin only */}
              {role === "admin" && influencerData.stageState === "Dropped" && influencerData.assignmentId && (
                <button className="btn sm" style={{ borderColor: "var(--ok)", color: "var(--ok)" }}
                  onClick={() => {
                    restoreDroppedInfluencer(influencerData.assignmentId);
                    notify(`${influencerData.name} restored to Unassigned Leads pool.`);
                    setPage({ key: "cm-unassigned" });
                  }}>
                  Restore to Unassigned
                </button>
              )}
            </div>
          </div>
        </div>

        <div className="tabs">
          {tabs.map(t => (
            <div key={t.key} className={`tab ${tab === t.key ? "active" : ""}`} onClick={() => setTab(t.key)}>
              {t.label}
            </div>
          ))}
        </div>
      </div>

      <div style={{ paddingTop: 20 }}>
        {overrideBanner && (
          <div className="banner" style={{ borderLeftColor: "var(--warn)", background: "var(--warn-bg, #fffbe6)" }}>
            <Ic.warn />
            <div>Admin changed this status to <strong>{influencerData.adminOverrideToStatus || influencerData.status}</strong>{influencerData.adminOverrideBy ? ` — ${influencerData.adminOverrideBy}` : ""}{influencerData.adminOverrideAt ? ` · ${influencerData.adminOverrideAt}` : ""}. {influencerData.adminOverrideReason ? <><br /><em>Reason: {influencerData.adminOverrideReason}</em></> : ""} Confirm receipt, or change it back if you disagree.</div>
            <div className="spacer" />
            <button className="btn sm primary" onClick={() => {
              setOverrideBanner(false);
              updateInfluencer(influencerData.id, { adminOverridePending: false });
              setInfluencerData(d => ({ ...d, adminOverridePending: false }));
              notify("Override receipt confirmed. You may change status back if you disagree.");
            }}>
              Confirm Receipt
            </button>
          </div>
        )}
        {campaignBlocked && campaignRecord && (
          <div className="banner" style={{ borderColor: campaignStatus === "Paused" ? "var(--warn)" : "var(--line-2)", background: campaignStatus === "Paused" ? "var(--warn-bg, #fffbe6)" : "var(--bg-2)" }}>
            <Ic.warn />
            <div style={{ flex: 1 }}>
              Campaign <strong>{campaignRecord.name}</strong> is <strong>{campaignStatus}</strong>.
              {campaignStatus === "Paused" && " Stage progression is paused. Existing progress and payments are preserved."}
              {campaignStatus === "Completed" && " This campaign has been marked complete. All records are read-only."}
              {campaignStatus === "Archived" && " This campaign is archived. Records are preserved for audit."}
            </div>
            {/* Fix 4: CM can request campaign be unpaused */}
            {campaignStatus === "Paused" && role === "collab" && (
              <button className="btn sm ghost" style={{ flexShrink: 0 }} onClick={() => setRequestOpen(true)}>
                Request Unpaused
              </button>
            )}
          </div>
        )}

        {tab === "overview" && <OverviewTab influencer={influencerData} from={from} />}
        {tab === "conversation" && <ConversationTab influencer={influencerData} />}
        {tab === "stages" && <StagesTab influencer={influencerData} campaignBlocked={campaignBlocked} onProgress={() => setStagePrompt({ stage: influencerData.currentStage || 1, action: "complete" })} />}
        {tab === "campaigns" && <CampaignsTab influencer={influencerData} from={from} />}
        {tab === "payments" && <InfluencerPaymentsTab influencer={influencerData} onUpdate={(updates) => {
          setInfluencerData(d => ({ ...d, ...updates }));
          // If opened from a campaign context, scope payment to this assignment only
          if (influencerData.assignmentId) updateCollabRecord(influencerData.assignmentId, updates);
          else updateInfluencer(influencerData.id, updates);
        }} />}
        {tab === "activity" && <ActivityTab influencer={influencerData} scopedAssignmentId={from && from !== "people-influencers" ? influencerData.assignmentId : null} />}
        {tab === "requests" && <RequestsTab influencer={influencerData} onNew={() => setRequestOpen(true)} />}
      </div>

      {statusPrompt && <StatusChangeModal kind={statusPrompt} onClose={() => setStatusPrompt(null)} onDone={(msg, updates) => {
        if (updates) {
          const sp = data.outreachSpecialists?.find(s => s.id === activePersonId);
          const byName = role === "outreach" ? (sp ? `OS — ${sp.name}` : "Outreach Specialist") : "Admin";
          const actEntry = updates.status ? { at: new Date().toLocaleDateString("en-GB", { day: "2-digit", month: "short" }) + ", " + new Date().toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" }), what: `Status changed to "${updates.status}"${updates.aiFlag ? " (AI flagged)" : ""}`, by: byName } : null;
          setInfluencerData(d => ({ ...d, ...updates }));
          if (updates.status === "Interested") {
            moveToLeads({ ...influencerData, ...updates, activity: [...(influencerData.activity || []), ...(actEntry ? [actEntry] : [])] });
          } else {
            updateInfluencer(influencerData.id, updates, actEntry);
          }
          if (role === "outreach" && (updates.status === "No Response" || updates.status === "Rejected")) {
            const spName = sp?.name || "Outreach Specialist";
            notifyAdminOfOSStatus(influencerData, updates.status, updates.rejectReason || "", spName);
          }
          // Notify admin when OS or CM changes status back after an admin override (dispute)
          if ((role === "outreach" || role === "collab") && influencerData.adminOverridePending && updates.status) {
            const spName = sp?.name || (role === "collab" ? "Collaboration Manager" : "Outreach Specialist");
            notifyAdminOfOverrideDispute(influencerData, updates.status, spName);
          }
        }
        setStatusPrompt(null);
        notify(msg);
      }} influencer={influencerData} />}
      {stagePrompt && <StageEvidenceModal stage={stagePrompt.stage} influencer={influencerData} onClose={() => setStagePrompt(null)} onDone={({ msg, signedContract, evidenceFile, videoEditor, videoEditorAmount }) => {
        const completedStage = stagePrompt.stage;
        const nextStage = completedStage + 1;
        const now = new Date().toLocaleDateString("en-GB", { day: "2-digit", month: "short", year: "numeric" });
        const stageUpdates = {
          currentStage: nextStage <= 4 ? nextStage : completedStage,
          stageState: nextStage <= 4 ? "In Progress" : "Complete",
          stages: (influencerData.stages || []).map(s => ({
            ...s,
            state: s.n < completedStage ? "Complete" : s.n === completedStage ? "Complete" : s.n === nextStage ? "In Progress" : s.state,
            evidence: s.n <= completedStage ? "Provided" : s.evidence,
            paymentStatus: s.paymentStatus,
            evidenceFile: s.n === completedStage ? (evidenceFile || `evidence-stage-${s.n}.png`) : s.evidenceFile,
            completedAt: s.n === completedStage ? now : s.completedAt,
            ...(s.n === completedStage && videoEditor ? { videoEditor, videoEditorAmount } : {}),
          })),
          ...(signedContract ? { signedContract } : {}),
        };
        setInfluencerData(d => ({ ...d, ...stageUpdates }));
        const cm = data.collabManagers?.find(c => c.id === (influencerData.cmId || activePersonId));
        completeStage(influencerData.assignmentId, stageUpdates, {
          completedStage,
          cmName: cm?.name || influencerData.cmName || "Collaboration Manager",
          influencerName: influencerData.name,
          specialistId: influencerData.specialistId,
          campaignName: influencerData.campaignName,
        });
        setStagePrompt(null);
        notify(msg);
        if (completedStage === 1) {
          setTimeout(() => notify(`Stage 1 complete — ${influencerData.name}'s outreach bonus automatically promoted to Approved.`), 600);
        }
      }} />}
      {requestOpen && <RequestTicketModal influencer={influencerData} onClose={() => setRequestOpen(false)} onDone={(msg) => { setRequestOpen(false); notify(msg); }} />}
      {addNoteOpen && <AddNoteModal
        influencer={influencerData}
        notes={influencerData.notes || []}
        onSave={(body) => {
          const at = new Date().toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric" }) + ", " + new Date().toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
          const entry = { by: "Farah K. — Admin", at, body };
          const notes = [...(influencerData.notes || []), entry];
          const actEntry = { at, what: "Note added by Admin", by: "Admin — Farah K." };
          setInfluencerData(d => ({ ...d, notes, note: body }));
          updateInfluencer(influencerData.id, { notes, note: body }, actEntry);
          notify("Note saved.");
        }}
        onClose={() => setAddNoteOpen(false)}
      />}
      {editOpen && <EditInfluencerModal influencer={influencerData} onClose={() => setEditOpen(false)} onSave={(updated) => {
        const actEntry = { at: new Date().toLocaleDateString("en-GB", { day: "2-digit", month: "short" }) + ", " + new Date().toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" }), what: "Profile edited by Admin", by: "Admin — Farah K." };
        setInfluencerData(updated);
        updateInfluencer(updated.id, updated, actEntry);
        setEditOpen(false);
        notify(`${updated.name} updated.`);
      }} />}
      {overrideOpen && <AdminOverrideStatusModal influencer={influencerData} onClose={() => setOverrideOpen(false)} onSave={(newStatus, reason) => {
        setInfluencerData(d => ({ ...d, status: newStatus, adminOverridePending: true, adminOverrideToStatus: newStatus, adminOverrideReason: reason || "" }));
        const isCM = !!(influencerData.cmId || influencerData.currentStage);
        overrideInfluencerStatus(influencerData.id, newStatus, influencerData.name, influencerData.specialistId, influencerData.cmId, "Farah K.", reason || "");
        setOverrideOpen(false);
        notify(`Status overridden to "${newStatus}" for ${influencerData.name}. ${isCM ? "CM" : "OS"} notified.`);
      }} />}
      {reassignOpen && <ReassignModal influencer={influencerData} onClose={() => setReassignOpen(false)} onSave={(type, specialist) => { setReassignOpen(false); notify(`${influencerData.name} reassigned to ${specialist.name}.`); }} />}
      {dropOpen && <DropInfluencerModal influencer={influencerData} onClose={() => setDropOpen(false)} onDone={(reason) => {
        dropInfluencer(influencerData.assignmentId, reason);
        setDropOpen(false);
        notify(`${influencerData.name} dropped and removed from pipeline. Reason recorded.`);
        goBack();
      }} />}
      {archiveOpen && <ArchiveInfluencerModal influencer={influencerData} onClose={() => setArchiveOpen(false)} onDone={(reason) => {
        archiveInfluencer(influencerData.id, reason);
        setArchiveOpen(false);
        notify(`${influencerData.name} archived. Record preserved for audit.`);
        goBack();
      }} />}
    </div>
  );
}

// ---------------- Overview ----------------

function OverviewTab({ influencer, from }) {
  const { role, data, activePersonId } = useApp();
  const isAdmin = role === "admin";
  const osPerson = data?.outreachSpecialists?.find(s => s.id === influencer.specialistId);
  const osPerContact = influencer.lockedPerContact ?? osPerson?.perContact ?? 0.30;
  const osBonus      = influencer.lockedBonus      ?? osPerson?.bonus      ?? 2.00;

  // Opened from people page = show all campaigns; opened from a specific context = show that campaign only
  const fromPeople = from === "people-influencers";

  // All active collab records for this influencer
  const allCollabRecords = (data.collabInProgress || []).filter(r => r.id === influencer.id && !r.deletedAt);

  // For CM role: only show records managed by this CM
  const visibleCollabRecords = role === "collab"
    ? allCollabRecords.filter(r => r.cmId === activePersonId)
    : allCollabRecords;

  // When opened from a specific context (in-progress, campaign-detail), scope to that assignment
  const scopedRecord = !fromPeople && influencer.assignmentId
    ? allCollabRecords.find(r => r.assignmentId === influencer.assignmentId) || null
    : null;

  // What to show in the Collab Stages payment card
  const collabRecordsToShow = scopedRecord ? [scopedRecord] : visibleCollabRecords;

  const hasCM   = collabRecordsToShow.length > 0 || !!(influencer.cmId || influencer.currentStage);
  const isCM    = !isAdmin && hasCM;

  const stageLabels = ["Signed contract", "Content draft approved", "Content published", "Performance milestone"];

  // Sub-label separator inside a card (admin dual-section cards)
  const SubLabel = ({ children }) => (
    <div style={{ fontSize: 10, fontFamily: "var(--font-mono)", color: "var(--ink-4)", textTransform: "uppercase", letterSpacing: "0.1em", paddingBottom: 4, marginTop: 2 }}>
      {children}
    </div>
  );
  const Divider = () => (
    <div style={{ borderTop: "1px solid var(--line)", margin: "10px 0 8px" }} />
  );

  return (
    <div className="grid-3" style={{ marginTop: 14 }}>

      {/* ── Card 1: Status & Assignment ── */}
      <div className="card">
        <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em", marginBottom: 10 }}>Status & Assignment</div>
        <div className="kv-list">
          <div className="kv">
            <div className="k">Current Status</div>
            <div className="v">
              {influencer.status
                ? <StatusChip status={influencer.status} />
                : influencer.currentStage && (isAdmin || role === "collab")
                  ? (influencer.stageState === "Complete"
                      ? <Chip tone="ok">Completed</Chip>
                      : <Chip tone="info">Stage {influencer.currentStage} · {influencer.stageState}</Chip>)
                  : !influencer.status && !influencer.currentStage
                    ? <Chip tone="neutral">Unassigned</Chip>
                    : null}
            </div>
          </div>

          {/* Outreach Specialist — admin and OS only, never CM */}
          {(isAdmin || role === "outreach") && (influencer.specialistName ? (<>
            <div className="kv">
              <div className="k">Outreach Specialist</div>
              <div className="v">{influencer.specialistName} <span className="text-xs text-mute" style={{ fontFamily: "var(--font-mono)" }}>· {influencer.specialistId}</span></div>
            </div>
            {influencer.specialistId && (
              <div className="kv">
                <div className="k">OS Rate</div>
                <div className="v text-mono text-small">
                  ${osPerContact} per contact · ${osBonus} bonus on Interested
                  <span style={{ display: "block", fontSize: 11, color: "var(--mute)", marginTop: 2 }}>Locked at bundle acceptance</span>
                </div>
              </div>
            )}
          </>) : isAdmin && (
            <div className="kv">
              <div className="k">Outreach Specialist</div>
              <div className="v"><span className="text-mute text-small">Not assigned</span></div>
            </div>
          ))}

          {/* Collab Manager — admin only, never shown from People context (CM is campaign-scoped) */}
          {isAdmin && !fromPeople && (influencer.cmName ? (<>
            <div className="kv">
              <div className="k">Collab Manager</div>
              <div className="v">{influencer.cmName} <span className="text-xs text-mute" style={{ fontFamily: "var(--font-mono)" }}>· {influencer.cmId}</span></div>
            </div>
            {influencer.cmAssignedAt && (
              <div className="kv">
                <div className="k">CM Assigned</div>
                <div className="v">{influencer.cmAssignedAt}</div>
              </div>
            )}
            {influencer.sourceBundle && (
              <div className="kv">
                <div className="k">Lead Bundle</div>
                <div className="v"><BundleIdChip id={influencer.sourceBundle} /></div>
              </div>
            )}
            {influencer.commission && (
              <div className="kv">
                <div className="k">Agreement</div>
                <div className="v text-mono text-small">{influencer.commission || "—"}{influencer.commissionDuration ? ` · ${influencer.commissionDuration}` : ""}</div>
              </div>
            )}
          </>) : (
            <div className="kv">
              <div className="k">Collab Manager</div>
              <div className="v"><span className="text-mute text-small">Not yet assigned to CM</span></div>
            </div>
          ))}

          {/* Outreach context — admin and OS only, not shown from People (no single campaign context) */}
          {(isAdmin || role === "outreach") && !fromPeople && influencer.markedInterestedBy && (
            <div className="kv">
              <div className="k">Marked Interested By</div>
              <div className="v">{influencer.markedInterestedBy} <span className="text-xs text-mute">· {influencer.markedAt || ""}</span></div>
            </div>
          )}

          {/* Outreach verification fields: admin and OS only, not in People context */}
          {(isAdmin || role === "outreach") && !fromPeople && <>
            <div className="kv"><div className="k">Screenshot</div><div className="v">
              {influencer.screenshotUploaded
                ? <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}><span className="tick" /> Uploaded</span>
                : <Chip tone="neutral">Not uploaded</Chip>}
            </div></div>
            <div className="kv"><div className="k">AI Verification</div><div className="v">
              {influencer.aiVerified
                ? <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}><span className="tick" /> Verified</span>
                : influencer.aiFlag
                  ? <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}><span className="tick warn" /> Mismatch — admin review</span>
                  : <Chip tone="neutral">Pending</Chip>}
            </div></div>
            <div className="kv"><div className="k">Contacted</div><div className="v">{influencer.contactedAt || "—"}</div></div>
          </>}

          {influencer.campaignName && !fromPeople && (
            <div className="kv">
              <div className="k">Campaign</div>
              <div className="v"><Chip tone="info">{influencer.campaignName}</Chip></div>
            </div>
          )}
          {influencer.isReturning && !fromPeople && (
            <div className="kv">
              <div className="k">Collaborator Type</div>
              <div className="v"><Chip tone="accent">Returning — Stage 1 on file</Chip></div>
            </div>
          )}
          {influencer.rejectReason && (
            <div className="kv"><div className="k">Rejection Reason</div><div className="v"><Chip tone="bad" xs>{influencer.rejectReason}</Chip></div></div>
          )}
          {influencer.dropReason && (
            <div className="kv"><div className="k">Drop Reason</div><div className="v"><Chip tone="bad" xs>{influencer.dropReason}</Chip></div></div>
          )}
        </div>
      </div>

      {/* ── Card 2: Payments & Bonus — admin sees both sections ── */}
      {isAdmin && <div className="card">
        <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em", marginBottom: 10 }}>Payments & Bonus</div>
        <div className="kv-list">
          {hasCM && <SubLabel>Outreach</SubLabel>}
          <div className="kv"><div className="k">Amount Owed</div><div className="v text-mono">${(influencer.amountOwed ?? 0).toFixed(2)}</div></div>
          <div className="kv"><div className="k">Paid Status</div><div className="v">{influencer.paidStatus ? <StatusChip status={influencer.paidStatus} /> : <span className="text-mute">—</span>}</div></div>
          <div className="kv"><div className="k">Bonus Amount</div><div className="v text-mono">${(influencer.bonusAmount ?? 0).toFixed(2)}</div></div>
          <div className="kv"><div className="k">Bonus Status</div><div className="v">{influencer.bonusStatus ? <StatusChip status={influencer.bonusStatus} /> : <span className="text-mute">—</span>}</div></div>

          {hasCM && <>
            <div style={{ display: "flex", alignItems: "center", gap: 8, margin: "10px 0 8px" }}>
              <div style={{ flex: 1, height: 1, background: "var(--line)" }} />
              <span className="text-mono text-xs" style={{ color: "var(--ink-4)", textTransform: "uppercase", letterSpacing: "0.1em", whiteSpace: "nowrap" }}>Collaboration Stages</span>
              <div style={{ flex: 1, height: 1, background: "var(--line)" }} />
            </div>
            {fromPeople && collabRecordsToShow.length > 1
              ? <div className="text-small text-mute" style={{ padding: "10px 0" }}>
                  {collabRecordsToShow.length} campaigns active. See the <strong>Campaigns</strong> tab for stage-by-stage payment breakdown.
                </div>
              : collabRecordsToShow.length > 0
                ? collabRecordsToShow.map((rec, ri) => (
                    <div key={rec.assignmentId || ri} style={{ marginBottom: ri < collabRecordsToShow.length - 1 ? 12 : 0 }}>
                      {collabRecordsToShow.length > 1 && (
                        <div style={{ fontSize: 11, fontFamily: "var(--font-mono)", color: "var(--accent)", fontWeight: 600, marginBottom: 6, letterSpacing: "0.04em" }}>
                          {rec.campaignName || "Campaign"} · {rec.cmName}
                          {rec.isReturning && <span style={{ marginLeft: 6, color: "var(--ok)" }}>· Returning</span>}
                        </div>
                      )}
                      {(rec.stages || []).map((s, i) => (
                        <div key={s.n} className="kv">
                          <div className="k">
                            Stage {s.n}
                            <span className="text-xs text-mute" style={{ display: "block", fontFamily: "var(--font-sans)", textTransform: "none", letterSpacing: 0 }}>{stageLabels[i]}</span>
                          </div>
                          <div className="v" style={{ display: "flex", alignItems: "center", gap: 8 }}>
                            <span className="text-mono">${s.amount}</span>
                            <StatusChip status={s.paymentStatus === "Skipped" ? "Skipped" : s.paymentStatus || "Pending"} />
                          </div>
                        </div>
                      ))}
                      <div className="kv" style={{ marginTop: 2 }}>
                        <div className="k">Commission</div>
                        <div className="v text-mono text-small">{(() => { const c = rec.commission || influencer.commission; const d = rec.commissionDuration || influencer.commissionDuration; return c ? (d ? `${c} · ${d}` : c) : "—"; })()}</div>
                      </div>
                      {ri < collabRecordsToShow.length - 1 && <div style={{ borderTop: "1px solid var(--line)", margin: "10px 0 4px" }} />}
                    </div>
                  ))
                : influencer.stages
                  ? influencer.stages.map((s, i) => (
                      <div key={s.n} className="kv">
                        <div className="k">
                          Stage {s.n}
                          <span className="text-xs text-mute" style={{ display: "block", fontFamily: "var(--font-sans)", textTransform: "none", letterSpacing: 0 }}>{stageLabels[i]}</span>
                        </div>
                        <div className="v" style={{ display: "flex", alignItems: "center", gap: 8 }}>
                          <span className="text-mono">${s.amount}</span>
                          <StatusChip status={s.paymentStatus || "Pending"} />
                        </div>
                      </div>
                    ))
                  : <div className="text-mute text-small">No collab assignments yet.</div>}
          </>}
        </div>
      </div>}

      {/* ── Card 2b: Payments & Bonus — CM role sees only their campaigns ── */}
      {role === "collab" && hasCM && <div className="card">
        <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em", marginBottom: 10 }}>Payments & Bonus</div>
        <div className="kv-list">
          {fromPeople && collabRecordsToShow.length > 1
            ? <div className="text-small text-mute" style={{ padding: "10px 0" }}>
                {collabRecordsToShow.length} campaigns active. See the <strong>Campaigns</strong> tab for stage-by-stage breakdown.
              </div>
            : collabRecordsToShow.length > 0
              ? collabRecordsToShow.map((rec, ri) => (
                  <div key={rec.assignmentId || ri} style={{ marginBottom: ri < collabRecordsToShow.length - 1 ? 12 : 0 }}>
                    {collabRecordsToShow.length > 1 && (
                      <div style={{ fontSize: 11, fontFamily: "var(--font-mono)", color: "var(--accent)", fontWeight: 600, marginBottom: 6, letterSpacing: "0.04em" }}>
                        {rec.campaignName || "Campaign"}
                        {rec.isReturning && <span style={{ marginLeft: 6, color: "var(--ok)" }}>· Returning</span>}
                      </div>
                    )}
                    {(rec.stages || []).map((s, i) => (
                      <div key={s.n} className="kv">
                        <div className="k">
                          Stage {s.n}
                          <span className="text-xs text-mute" style={{ display: "block", fontFamily: "var(--font-sans)", textTransform: "none", letterSpacing: 0 }}>{stageLabels[i]}</span>
                        </div>
                        <div className="v" style={{ display: "flex", alignItems: "center", gap: 8 }}>
                          <span className="text-mono">${s.amount}</span>
                          <StatusChip status={s.paymentStatus === "Skipped" ? "Skipped" : s.paymentStatus || "Pending"} />
                        </div>
                      </div>
                    ))}
                    <div className="kv" style={{ marginTop: 2 }}>
                      <div className="k">Commission</div>
                      <div className="v text-mono text-small">{(() => { const c = rec.commission || influencer.commission; const d = rec.commissionDuration || influencer.commissionDuration; return c ? (d ? `${c} · ${d}` : c) : "—"; })()}</div>
                    </div>
                    {ri < collabRecordsToShow.length - 1 && <div style={{ borderTop: "1px solid var(--line)", margin: "10px 0 4px" }} />}
                  </div>
                ))
              : <div className="text-mute text-small">No stage payment data.</div>}
        </div>
      </div>}

      {/* ── Outreach Intelligence — shown when influencer has been marked Interested ── */}
      {(influencer.phoneNumber || influencer.conversionTechniques || influencer.candidateNotes) && (isAdmin || role === "outreach") && (
        <div className="card">
          <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em", marginBottom: 10 }}>Outreach Intelligence</div>
          <div className="kv-list">
            {influencer.phoneNumber && (
              <div className="kv">
                <div className="k">WhatsApp</div>
                <div className="v" style={{ display: "flex", alignItems: "center", gap: 8 }}>
                  <span style={{ fontSize: 16 }}>📱</span>
                  <span style={{ fontFamily: "var(--font-mono)", fontSize: 13, letterSpacing: "0.04em" }}>{influencer.phoneNumber}</span>
                </div>
              </div>
            )}
            {influencer.conversionTechniques && (
              <div style={{ marginTop: 10 }}>
                <div className="text-xs text-mute" style={{ marginBottom: 4 }}>Conversion techniques</div>
                <div style={{ fontSize: 13, lineHeight: 1.6, color: "var(--ink-2)", background: "var(--bg-2)", padding: "8px 12px", borderRadius: 6 }}>{influencer.conversionTechniques}</div>
              </div>
            )}
            {influencer.candidateNotes && (
              <div style={{ marginTop: 10 }}>
                <div className="text-xs text-mute" style={{ marginBottom: 4 }}>Candidate notes</div>
                <div style={{ fontSize: 13, lineHeight: 1.6, color: "var(--ink-2)", background: "var(--bg-2)", padding: "8px 12px", borderRadius: 6 }}>{influencer.candidateNotes}</div>
              </div>
            )}
          </div>
        </div>
      )}

      {/* ── Outreach Hook — shown for OS/admin when hook is present ── */}
      {(isAdmin || role === "outreach") && influencer.outreachHook && (
        <div className="card" style={{ gridColumn: "1 / -1" }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }}>
            <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em" }}>
              Outreach Hook
            </div>
            <CopyButton text={influencer.outreachHook} />
          </div>
          <div style={{ fontStyle: "italic", color: "var(--ink-2)", lineHeight: 1.6, fontSize: 13.5, background: "var(--bg-2)", padding: "10px 14px", borderRadius: 6 }}>
            "{influencer.outreachHook}"
          </div>
        </div>
      )}

    </div>
  );
}

// ---------------- Collab Stages Table (People page — multi-campaign view) ----------------

function CollabStagesTable({ records, stageLabels }) {
  const stageNums = [1, 2, 3, 4];
  return (
    <div style={{ marginTop: 4, overflowX: "auto" }}>
      <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12 }}>
        <thead>
          <tr>
            <th style={{ textAlign: "left", padding: "4px 8px 4px 0", fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--ink-4)", textTransform: "uppercase", letterSpacing: "0.08em", borderBottom: "1px solid var(--line)", whiteSpace: "nowrap" }}>Campaign</th>
            <th style={{ textAlign: "left", padding: "4px 8px 4px 0", fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--ink-4)", textTransform: "uppercase", letterSpacing: "0.08em", borderBottom: "1px solid var(--line)", whiteSpace: "nowrap" }}>CM</th>
            {stageNums.map(n => (
              <th key={n} style={{ textAlign: "center", padding: "4px 6px", fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--ink-4)", textTransform: "uppercase", letterSpacing: "0.08em", borderBottom: "1px solid var(--line)" }}>S{n}</th>
            ))}
            <th style={{ textAlign: "left", padding: "4px 0 4px 8px", fontFamily: "var(--font-mono)", fontSize: 10, color: "var(--ink-4)", textTransform: "uppercase", letterSpacing: "0.08em", borderBottom: "1px solid var(--line)" }}>Commission</th>
          </tr>
        </thead>
        <tbody>
          {records.map((rec, ri) => (
            <tr key={rec.assignmentId || ri} style={{ borderBottom: "1px solid var(--line)" }}>
              <td style={{ padding: "7px 8px 7px 0", verticalAlign: "middle" }}>
                <div style={{ fontWeight: 500, fontSize: 12, color: "var(--ink-1)" }}>{rec.campaignName || "—"}</div>
                {rec.isReturning && <span style={{ fontSize: 10, fontFamily: "var(--font-mono)", color: "var(--ok)" }}>Returning</span>}
              </td>
              <td style={{ padding: "7px 8px 7px 0", verticalAlign: "middle", color: "var(--ink-2)", whiteSpace: "nowrap" }}>{rec.cmName || "—"}</td>
              {stageNums.map(n => {
                const s = (rec.stages || []).find(st => st.n === n);
                const status = s?.paymentStatus;
                const bg = status === "Paid" ? "var(--ok)" : status === "Pending" ? "var(--warn)" : status === "Unpaid" ? "var(--line-2)" : status === "Skipped" ? "var(--line)" : "var(--line)";
                const color = status === "Paid" ? "#fff" : status === "Pending" ? "#7a4a00" : "var(--ink-3)";
                const label = status === "Skipped" ? "—" : status === "Paid" ? "✓" : status ? "$" + (s?.amount || "") : "—";
                return (
                  <td key={n} style={{ padding: "7px 6px", textAlign: "center", verticalAlign: "middle" }}>
                    <span title={`S${n}: ${status || "—"} ${s ? `$${s.amount}` : ""}`} style={{
                      display: "inline-flex", alignItems: "center", justifyContent: "center",
                      minWidth: 28, height: 20, borderRadius: 3, fontSize: 10, fontFamily: "var(--font-mono)",
                      fontWeight: 600, background: bg, color, padding: "0 4px"
                    }}>{label}</span>
                  </td>
                );
              })}
              <td style={{ padding: "7px 0 7px 8px", verticalAlign: "middle", fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--ink-3)" }}>
                {rec.commission ? (rec.commissionDuration ? `${rec.commission} · ${rec.commissionDuration}` : rec.commission) : "—"}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
      <div className="text-xs text-mute" style={{ marginTop: 6, fontFamily: "var(--font-mono)" }}>
        Hover a stage cell to see amount and status. ✓ = Paid · $ = amount due · — = Skipped
      </div>
    </div>
  );
}

// ---------------- Conversation ----------------

function ConversationTab({ influencer }) {
  // Read-only record of screenshots taken during status changes (Contacted + Interested)
  const screenshots = [
    influencer.screenshotUploaded && {
      label: "Contact screenshot",
      at: influencer.contactedAt || "",
      aiVerified: influencer.aiVerified,
      aiFlag: influencer.aiFlag,
    },
    influencer.interestedScreenshot && {
      label: "Interested conversation screenshot",
      at: influencer.interestedAt || "",
    },
  ].filter(Boolean);

  if (screenshots.length === 0) {
    return (
      <div style={{ marginTop: 14 }}>
        <div className="card" style={{ color: "var(--ink-3)", textAlign: "center", padding: "40px 24px" }}>
          No screenshots yet — they appear here when the OS marks Contacted or Interested.
        </div>
      </div>
    );
  }

  return (
    <div style={{ marginTop: 14 }}>
      <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em", marginBottom: 12 }}>
        Evidence screenshots <span style={{ marginLeft: 6, background: "var(--accent)", color: "#fff", borderRadius: 4, padding: "1px 6px", fontSize: 10 }}>{screenshots.length}</span>
      </div>
      <div className="grid-2">
        {screenshots.map((s, i) => (
          <div key={i} className="card" style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            <div className="shot-placeholder" style={{ minHeight: 120, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--ink-3)" }}>
              <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
            </div>
            <div style={{ fontWeight: 500, fontSize: 13 }}>{s.label}</div>
            {s.at && <div className="text-xs text-mute">{s.at}</div>}
            {s.aiVerified && <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 12, color: "var(--good)" }}><span className="tick" /> AI verified</span>}
            {s.aiFlag && <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 12, color: "var(--warn)" }}><span className="tick warn" /> AI mismatch flagged</span>}
          </div>
        ))}
      </div>
    </div>
  );
}

// ---------------- Stages ----------------

function StagesTab({ influencer, onProgress, campaignBlocked }) {
  const { role } = useApp();
  const stages = influencer.stages || [1, 2, 3, 4].map(n => ({ n, state: "Locked", evidence: "Pending", amount: [15,30,50,75][n-1], paymentStatus: "" }));
  const contract = influencer.signedContract;
  const [selectedN, setSelectedN] = useState(influencer.currentStage || 1);
  const selected = stages.find(s => s.n === selectedN) || stages[0];
  const stageLabels = ["Signed contract", "Content draft approved", "Content published", "Performance milestone"];

  return (
    <div>
      {influencer.campaignName && (
        <div className="text-mono text-xs text-mute" style={{ marginTop: 12, marginBottom: 4, textTransform: "uppercase", letterSpacing: "0.1em" }}>
          Campaign: {influencer.campaignName}{influencer.isReturning ? " · Returning — Stage 1 on file" : ""}
        </div>
      )}
      <div className="stage-rail" style={{ marginTop: 16 }}>
        {stages.map(s => {
          const isComplete = s.state === "Complete";
          const isCurrent  = s.state === "In Progress";
          const isSelected = s.n === selectedN;
          return (
            <div key={s.n}
              className={`stage-card ${isComplete ? "complete" : isCurrent ? "current" : "locked"} ${isSelected ? "selected" : ""}`}
              style={{ cursor: "pointer", outline: isSelected ? "2px solid var(--accent)" : "none", outlineOffset: 2 }}
              onClick={() => setSelectedN(s.n)}>
              <div className="num">Stage {s.n}</div>
              <div className="name">{["Signed contract","Content draft","Content live","Performance"][s.n-1]}</div>
              <div className="amt">${s.amount}</div>
              <div className="foot">
                <Chip tone={s.evidence === "Provided" ? "ok" : "neutral"}>{s.evidence}</Chip>
                {isComplete ? <span className="tick" /> :
                 isCurrent  ? <Chip tone="info">In Progress</Chip> :
                              <Chip tone="neutral">Locked</Chip>}
              </div>
              {s.n === 1 && (
                <div style={{ marginTop: 6 }}>
                  {contract ? <Chip tone="ok" xs>Contract signed</Chip> : <Chip tone="neutral" xs>Contract pending</Chip>}
                </div>
              )}
            </div>
          );
        })}
      </div>

      {/* Uploads for selected stage — only show if something exists or it's actionable */}
      {(() => {
        const hasContract = selected.n === 1 && contract;
        const hasEvidence = !!selected.evidenceFile;
        const isActionable = selected.state === "In Progress" && (role === "collab" || role === "admin");
        if (!hasContract && !hasEvidence && !isActionable) return null;
        return (
          <div className="card" style={{ marginTop: 12 }}>
            <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.1em", marginBottom: 10 }}>
              Stage {selected.n} · Documents
            </div>

            {hasContract && (
              <div style={{ marginBottom: hasEvidence ? 10 : 0 }}>
                <div className="text-xs text-mute" style={{ marginBottom: 6 }}>Signed Contract</div>
                <div className="shot-placeholder" style={{ height: 56, display: "flex", alignItems: "center", justifyContent: "center", gap: 10 }}>
                  <span className="tick" />
                  <span style={{ fontSize: 13 }}>{contract.fileName}</span>
                  <span className="text-xs text-mute">· {contract.uploadedAt}</span>
                </div>
              </div>
            )}

            {hasEvidence && (
              <div>
                <div className="text-xs text-mute" style={{ marginBottom: 6 }}>Evidence</div>
                <div className="shot-placeholder" style={{ height: 56, display: "flex", alignItems: "center", justifyContent: "center", gap: 10 }}>
                  <span className="tick" />
                  <span style={{ fontSize: 13 }}>{selected.evidenceFile}</span>
                  {selected.completedAt && <span className="text-xs text-mute">· {selected.completedAt}</span>}
                </div>
              </div>
            )}

            {/* Stage 2 — Video Editor info */}
            {selected.n === 2 && selected.videoEditor && (
              <div style={{ marginTop: 10 }}>
                <div className="text-xs text-mute" style={{ marginBottom: 6 }}>Video Editor</div>
                <div className="kv-list">
                  <div className="kv">
                    <div className="k">Editor</div>
                    <div className="v">{selected.videoEditor.name} <span className="text-xs text-mute" style={{ fontFamily: "var(--font-mono)" }}>· {selected.videoEditor.id}</span></div>
                  </div>
                  <div className="kv">
                    <div className="k">Amount</div>
                    <div className="v text-mono">${selected.videoEditorAmount}</div>
                  </div>
                </div>
              </div>
            )}

            {isActionable && (
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: hasContract || hasEvidence ? 12 : 0 }}>
                <div className="text-mute text-small">
                  {campaignBlocked
                    ? "Stage progression is locked — campaign is not Active."
                    : selected.n === 1 && !contract ? "Upload the signed contract to complete Stage 1." : "Upload evidence to mark this stage complete."}
                </div>
                <button className="btn primary" disabled={!!campaignBlocked} onClick={onProgress}>
                  Progress Stage <Ic.arrowRight />
                </button>
              </div>
            )}
          </div>
        );
      })()}
    </div>
  );
}

// ---------------- Campaigns Tab ----------------

function CampaignsTab({ influencer }) {
  const { data, activePersonId, role } = useApp();
  const [pg, setPg] = useState(1);
  const perPage = 8;

  const allRecords = (data.collabInProgress || []).filter(r => r.id === influencer.id && !r.deletedAt);
  const records = role === "collab"
    ? allRecords.filter(r => r.cmId === activePersonId)
    : allRecords;

  const totalPages = Math.max(1, Math.ceil(records.length / perPage));
  const paged = records.slice((pg - 1) * perPage, pg * perPage);

  const stageBar = (stages, currentStage, stageState) => (
    <div style={{ display: "inline-flex", gap: 3 }}>
      {(stages || []).map(s => (
        <div key={s.n} title={`S${s.n}: ${s.state}`} style={{
          width: 20, height: 5, borderRadius: 2,
          background: s.state === "Complete" ? "var(--ok)" : s.n === currentStage && stageState !== "Complete" ? "var(--accent)" : "var(--line-2)",
        }} />
      ))}
    </div>
  );

  return (
    <div style={{ marginTop: 14 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 10 }}>
        <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em" }}>
          Campaign Assignments
        </div>
        <span className="text-mono text-xs text-mute">{records.length} assignment{records.length !== 1 ? "s" : ""}</span>
      </div>

      {records.length === 0 ? (
        <div style={{ textAlign: "center", padding: "48px 0", color: "var(--ink-3)", fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.06em" }}>
          NO ACTIVE CAMPAIGN ASSIGNMENTS
        </div>
      ) : (
        <>
          <div className="table-wrap">
            <table className="ims">
              <thead>
                <tr>
                  <th>Campaign</th>
                  <th>Collab Manager</th>
                  <th>Type</th>
                  <th>Progress</th>
                  <th>Stage</th>
                  <th>S1</th>
                  <th>S2</th>
                  <th>S3</th>
                  <th>S4</th>
                  <th>Commission</th>
                  <th>Evidence</th>
                </tr>
              </thead>
              <tbody>
                {paged.map(rec => (
                  <tr key={rec.assignmentId}>
                    <td>
                      <div style={{ fontWeight: 500, fontSize: 13 }}>{rec.campaignName || "—"}</div>
                      <div className="text-mono text-xs text-mute">{rec.campaignId}</div>
                    </td>
                    <td className="text-small">{rec.cmName}</td>
                    <td>
                      {rec.isReturning
                        ? <Chip tone="ok" xs>Returning</Chip>
                        : <Chip tone="neutral" xs>First-time</Chip>}
                    </td>
                    <td>{stageBar(rec.stages, rec.currentStage, rec.stageState)}</td>
                    <td>
                      {rec.stageState === "Complete"
                        ? <Chip tone="ok" xs>Done</Chip>
                        : <Chip tone="info" xs>S{rec.currentStage} · {rec.stageState}</Chip>}
                    </td>
                    {[1, 2, 3, 4].map(n => {
                      const s = (rec.stages || []).find(st => st.n === n);
                      const ps = s?.paymentStatus;
                      return (
                        <td key={n} style={{ textAlign: "center" }}>
                          {!s ? <span className="text-mute">—</span>
                            : ps === "Skipped" ? <span className="text-mute text-xs" style={{ fontFamily: "var(--font-mono)" }}>—</span>
                            : <span title={`$${s.amount} · ${ps}`} style={{
                                display: "inline-block", width: 22, height: 18, borderRadius: 3,
                                fontSize: 9, fontFamily: "var(--font-mono)", fontWeight: 600,
                                textAlign: "center", lineHeight: "18px",
                                background: ps === "Paid" ? "var(--ok)" : ps === "Pending" ? "var(--warn)" : "var(--line-2)",
                                color: ps === "Paid" ? "#fff" : ps === "Pending" ? "#7a4a00" : "var(--ink-3)",
                              }}>
                                ${s.amount}
                              </span>}
                        </td>
                      );
                    })}
                    <td className="text-mono text-xs">{rec.commission ? (rec.commissionDuration ? `${rec.commission} · ${rec.commissionDuration}` : rec.commission) : "—"}</td>
                    <td className="text-mono text-xs">{(rec.stages || []).filter(s => s.evidence === "Provided").length}/4</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <TablePagination page={pg} totalPages={totalPages} onPage={setPg} total={records.length} perPage={perPage} />
        </>
      )}
    </div>
  );
}

// ---------------- Activity Log ----------------

function ActivityTab({ influencer, scopedAssignmentId }) {
  // When opened from a specific campaign context, filter activity to that campaign
  const allRows = [...(influencer.activity || [])].reverse();
  const rows = scopedAssignmentId
    ? allRows.filter(a => !a.assignmentId || a.assignmentId === scopedAssignmentId)
    : allRows;

  return (
    <div style={{ marginTop: 14 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 10 }}>
        <div>
          <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em" }}>Activity Log</div>
          {scopedAssignmentId && <div className="text-xs text-mute" style={{ marginTop: 2 }}>Showing activity for this campaign only</div>}
        </div>
        <span className="text-mono text-xs text-mute">{rows.length} event{rows.length !== 1 ? "s" : ""}</span>
      </div>
      {rows.length === 0 ? (
        <div className="text-mute text-small" style={{ padding: "32px 0", textAlign: "center" }}>
          No activity recorded yet. Actions like status changes, stage completions, notes, and overrides will appear here.
        </div>
      ) : (
        <div className="activity">
          {rows.map((a, i) => (
            <div className="row" key={i}>
              <div className="at">{a.at}</div>
              <div>
                <div className="what">{a.what}</div>
                <div className="by">by {a.by}</div>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ---------------- Requests ----------------

function RequestsTab({ influencer, onNew }) {
  const { data, role, setPage } = useApp();
  // When in campaign context, scope to this campaign's requests only
  const mine = data.requests.filter(r => {
    if (r.influencer.id !== influencer.id && r.influencer.name !== influencer.name) return false;
    if (influencer.campaignId) {
      // Requests with no campaignId are old records (pre-campaign scoping) — include them
      if (r.campaignId && r.campaignId !== influencer.campaignId) return false;
    }
    return true;
  });

  return (
    <div style={{ marginTop: 14 }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 10 }}>
        <div>
          <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em" }}>
            Request Tickets
            <span style={{ marginLeft: 8, color: "var(--ink-3)" }}>({mine.length})</span>
          </div>
          <div className="text-xs text-mute" style={{ marginTop: 2 }}>
            {influencer.campaignName
              ? `Scoped to campaign: ${influencer.campaignName}`
              : "All requests for this influencer"}
          </div>
        </div>
        {(role === "outreach" || role === "collab") && <button className="btn sm" onClick={onNew}><Ic.plus /> New Request</button>}
      </div>

      {mine.length === 0 && (
        <div className="text-mute text-small" style={{ padding: "32px 0", textAlign: "center" }}>
          No request tickets yet for this influencer.
        </div>
      )}

      {mine.length > 0 && (
        <div className="table-wrap">
          <table className="ims">
            <thead>
              <tr>
                <th>ID</th>
                <th>Type</th>
                <th>Raised By</th>
                <th>Summary</th>
                <th>Messages</th>
                <th>Status</th>
                <th>Date</th>
              </tr>
            </thead>
            <tbody>
              {mine.map(r => (
                <tr key={r.id} className="clickable" onClick={() => setPage({ key: "requests", openReqId: r.id })}>
                  <td><span className="pill" style={{ fontFamily: "var(--font-mono)", fontSize: 11 }}>{r.id}</span></td>
                  <td><span className="text-small">{r.type}</span></td>
                  <td>
                    <Chip tone={r.raisedBy.kind === "OS" ? "info" : "accent-soft"} xs>
                      {r.raisedBy.kind === "OS" ? "OS" : "CM"} · {r.raisedBy.name}
                    </Chip>
                  </td>
                  <td style={{ maxWidth: 220 }}>
                    <div className="text-small" style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{r.summary}</div>
                  </td>
                  <td><span className="text-mono text-xs text-mute">{(r.thread || []).length}</span></td>
                  <td><StatusChip status={r.status} /></td>
                  <td><span className="text-mono text-xs text-mute">{r.at}</span></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

// ============================================================================
// Mic button — voice dictation indicator (11Labs in production)
// ============================================================================

function MicButton({ onActivate }) {
  const { notify } = useApp();
  const [active, setActive] = useState(false);
  const handle = () => {
    setActive(true);
    setTimeout(() => setActive(false), 2000);
    notify("Voice dictation via 11Labs — transcription enabled in production.");
    onActivate?.();
  };
  return (
    <button
      type="button"
      title="Dictate (powered by 11Labs)"
      onClick={handle}
      style={{
        position: "absolute", right: 10, bottom: 10,
        background: active ? "var(--accent)" : "var(--bg-2)",
        border: `1px solid ${active ? "var(--accent)" : "var(--line-2)"}`,
        borderRadius: "50%", width: 28, height: 28,
        display: "flex", alignItems: "center", justifyContent: "center",
        cursor: "pointer", color: active ? "#fff" : "var(--ink-3)",
        transition: "background 0.15s, color 0.15s, border-color 0.15s",
        flexShrink: 0,
      }}
    >
      <Ic.mic />
    </button>
  );
}

// ============================================================================
// Status-change modal (OS): Contacted / Interested / Rejected
// ============================================================================

function StatusChangeModal({ kind, onClose, onDone, influencer }) {
  const [step, setStep] = useState(1);
  const [uploaded, setUploaded] = useState(false);
  const [aiResult, setAiResult] = useState(null); // 'ok' | 'warn'
  const [reason, setReason] = useState("");
  const [q1, setQ1] = useState("");
  const [q2, setQ2] = useState("");
  const [phone, setPhone] = useState("");

  const doUpload = () => {
    setUploaded(true);
    setTimeout(() => {
      // randomly warn 15% of time
      setAiResult(Math.random() < 0.15 ? "warn" : "ok");
    }, 700);
  };

  if (kind === "Contacted") {
    return (
      <Modal open={true} onClose={onClose}
        title="Mark as Contacted"
        sub="Evidence required"
        foot={<>
          <span className="text-xs text-mute">AI vision model will verify the screenshot.</span>
          <div style={{ display: "flex", gap: 8 }}>
            <button className="btn" onClick={onClose}>Cancel</button>
            <button className="btn primary" disabled={!uploaded || aiResult == null}
              onClick={() => onDone(`${influencer.name}: status → Contacted. $0.30 payable. ${aiResult === "warn" ? "AI flag saved." : "AI verified."}`, {
                status: "Contacted",
                screenshotUploaded: true,
                amountOwed: 0.30,
                paidStatus: "Unpaid",
                aiFlag: aiResult === "warn",
                aiVerified: aiResult === "ok",
                contactedAt: new Date().toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric" }),
              })}>
              {aiResult === "warn" ? "Continue anyway" : "Save Contacted"}
            </button>
          </div>
        </>}>
        <div className="text-mute" style={{ marginBottom: 14 }}>Please upload a screenshot of your contact (DM or email) to record this step.</div>
        {!uploaded && (
          <div onClick={doUpload} style={{ cursor: "pointer" }}>
            <div className="shot-placeholder" style={{ height: 180 }}>
              <div style={{ textAlign: "center" }}>
                <Ic.upload />
                <div style={{ marginTop: 8 }}>Click to upload screenshot</div>
              </div>
            </div>
          </div>
        )}
        {uploaded && (
          <>
            <div className="shot-placeholder" style={{ height: 180 }}>screenshot · contact.png</div>
            {aiResult === null && (
              <div className="banner info" style={{ marginTop: 12 }}><Ic.info /> <div>AI vision model checking…</div></div>
            )}
            {aiResult === "ok" && (
              <div className="banner info" style={{ marginTop: 12, background: "var(--ok-bg)", borderLeftColor: "var(--ok)" }}>
                <span className="tick" />
                <div><strong>AI verified</strong> — this appears to be a valid DM screenshot.</div>
              </div>
            )}
            {aiResult === "warn" && (
              <div className="banner" style={{ marginTop: 12 }}>
                <Ic.warn />
                <div><strong>Issue detected.</strong> What you uploaded doesn't seem to be a screenshot of a message. Admin will see a flag on the payment row.</div>
              </div>
            )}
          </>
        )}
      </Modal>
    );
  }

  if (kind === "Interested") {
    return (
      <Modal open={true} onClose={onClose}
        title="Mark as Interested"
        sub={`Step ${step} of 2`}
        foot={<>
          <div className="step-dots">
            <span className={`dot ${step >= 1 ? "active" : ""}`} />
            <span className={`dot ${step >= 2 ? "active" : ""}`} />
          </div>
          <div style={{ display: "flex", gap: 8 }}>
            {step > 1 && <button className="btn" onClick={() => setStep(step - 1)}>Back</button>}
            {step === 1 && <button className="btn primary" disabled={!uploaded} onClick={() => setStep(2)}>Continue <Ic.arrowRight /></button>}
            {step === 2 && <button className="btn primary" disabled={!q1.trim() || (!influencer.phoneNumber && !phone.trim())}
              onClick={() => onDone(`${influencer.name} → Interested. $2 bonus Pending. Moved to Unassigned Potential Leads.`, {
                status: "Interested",
                bonusAmount: 2,
                bonusStatus: "Pending",
                interestedScreenshot: true,
                interestedAt: new Date().toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric" }),
                phoneNumber: phone.trim() || influencer.phoneNumber,
                conversionTechniques: q1.trim(),
                candidateNotes: q2.trim() || null,
              })}>Submit</button>}
          </div>
        </>}>
        {step === 1 && (
          <>
            <div className="text-mute" style={{ marginBottom: 14 }}>Upload a screenshot of your conversation with this influencer.</div>
            {!uploaded && (
              <div onClick={() => setUploaded(true)} style={{ cursor: "pointer" }}>
                <div className="shot-placeholder" style={{ height: 180 }}>
                  <div style={{ textAlign: "center" }}><Ic.upload /><div style={{ marginTop: 8 }}>Click to upload</div></div>
                </div>
              </div>
            )}
            {uploaded && <div className="shot-placeholder" style={{ height: 180 }}>interested-conversation.png</div>}
          </>
        )}
        {step === 2 && (
          <>
            {influencer.phoneNumber ? (
              <div className="banner ok" style={{ marginBottom: 12 }}>
                <Ic.check />
                <div>WhatsApp already on file: <strong style={{ fontFamily: "var(--font-mono)" }}>📱 {influencer.phoneNumber}</strong></div>
              </div>
            ) : (
              <>
                <div className="banner info" style={{ marginBottom: 12 }}>
                  <Ic.info />
                  <div>Tell the influencer: <em>"A colleague will get back to you very soon via WhatsApp."</em> Then collect their number below.</div>
                </div>
                <div className="field">
                  <label>WhatsApp phone number <span style={{ color: "var(--bad)" }}>*</span></label>
                  <input className="input" value={phone} onChange={e => setPhone(e.target.value)} placeholder="+44 7700 900000" style={{ fontFamily: "var(--font-mono)" }} />
                </div>
              </>
            )}
            <div className="field">
              <label>What techniques did you use to convert this lead? <span style={{ color: "var(--bad)" }}>*</span></label>
              <div style={{ position: "relative" }}>
                <textarea className="textarea" value={q1} onChange={e => setQ1(e.target.value)} placeholder="Describe the techniques you used…" style={{ paddingRight: 44 }} />
                <MicButton />
              </div>
            </div>
            <div className="field">
              <label>Anything else you want to tell us about this candidate?</label>
              <div style={{ position: "relative" }}>
                <textarea className="textarea" value={q2} onChange={e => setQ2(e.target.value)} placeholder="Optional notes…" style={{ paddingRight: 44 }} />
                <MicButton />
              </div>
            </div>
          </>
        )}
      </Modal>
    );
  }

  if (kind === "No Response") {
    return (
      <Modal open={true} onClose={onClose}
        title="Mark as No Response"
        sub="Two contact attempts made — no reply"
        foot={<>
          <span className="text-xs text-mute">A polite closing message will be sent automatically.</span>
          <div style={{ display: "flex", gap: 8 }}>
            <button className="btn" onClick={onClose}>Cancel</button>
            <button className="btn primary"
              onClick={() => onDone(`${influencer.name} marked No Response. Closing message sent.`, { status: "No Response" })}>Confirm</button>
          </div>
        </>}>
        <div className="banner info">
          <Ic.info />
          <div>Use this only after <strong>2 contact attempts</strong> with no reply. A polite closing message will be sent on your behalf.</div>
        </div>
      </Modal>
    );
  }

  if (kind === "Future Response Received") {
    return (
      <Modal open={true} onClose={onClose}
        title="Future Response Received"
        sub="Influencer has re-contacted after No Response"
        foot={<>
          <span className="text-xs text-mute">$2 bonus re-activated as Pending.</span>
          <div style={{ display: "flex", gap: 8 }}>
            <button className="btn" onClick={onClose}>Cancel</button>
            <button className="btn primary"
              onClick={() => onDone(`${influencer.name} → Future Response Received. $2 bonus re-activated.`, {
                status: "Future Response Received",
                bonusAmount: 2,
                bonusStatus: "Pending",
              })}>Confirm</button>
          </div>
        </>}>
        <div className="banner info">
          <Ic.info />
          <div>The influencer previously did not reply and has now re-contacted you. The <strong>$2 positive response bonus</strong> is re-activated as Pending.</div>
        </div>
      </Modal>
    );
  }

  if (kind === "Rejected") {
    return (
      <Modal open={true} onClose={onClose}
        title="Mark as Rejected"
        sub="Status change — influencer declined"
        foot={<>
          <span className="text-xs text-mute">Influencer stays in your In Progress list. Not returned to Admin Inbox.</span>
          <div style={{ display: "flex", gap: 8 }}>
            <button className="btn" onClick={onClose}>Cancel</button>
            <button className="btn danger" disabled={!reason.trim()}
              onClick={() => onDone(`Rejection noted for ${influencer.name}. Reason saved.`, { status: "Rejected", rejectReason: reason.trim() })}>Submit</button>
          </div>
        </>}>
        <div className="text-mute" style={{ marginBottom: 12 }}>Enter a reason for rejection.</div>
        <div style={{ position: "relative" }}>
          <textarea className="textarea" value={reason} onChange={e => setReason(e.target.value)} placeholder="e.g. Not a fit — audience mismatch." style={{ paddingRight: 44 }} />
          <MicButton />
        </div>
      </Modal>
    );
  }
}

// ============================================================================
// Stage evidence modal (CM)
// ============================================================================

function StageEvidenceModal({ stage, influencer, onClose, onDone }) {
  const { data } = useApp();
  const isStage1 = stage === 1;
  const isStage2 = stage === 2;
  const contractOnFile = !!(influencer?.signedContract);
  const needsContract = isStage1 && !contractOnFile;

  const [contractUploaded, setContractUploaded] = useState(false);
  const [evidenceUploaded, setEvidenceUploaded] = useState(false);
  const [selectedVE, setSelectedVE] = useState("");
  const [veAmount, setVEAmount] = useState("");

  const videoEditors = data?.videoEditors || [];
  const stageLabel = stage === 1 ? "Signed contract" : stage === 2 ? "Content draft approved" : stage === 3 ? "Content published" : "Performance milestone";

  const canConfirm = (() => {
    if (!evidenceUploaded) return false;
    if (needsContract && !contractUploaded) return false;
    if (isStage2 && (!selectedVE || !veAmount || +veAmount <= 0)) return false;
    return true;
  })();

  const handleConfirm = () => {
    const now = new Date().toLocaleDateString("en-GB", { day: "2-digit", month: "short", year: "numeric" });
    const signedContract = (isStage1 && contractUploaded)
      ? { fileName: "signed-contract.pdf", uploadedAt: now }
      : (isStage1 && contractOnFile ? influencer.signedContract : undefined);
    const ve = videoEditors.find(v => v.id === selectedVE);
    onDone({
      msg: `Stage ${stage} complete · evidence attached · payable recorded.`,
      signedContract,
      evidenceFile: `evidence-stage-${stage}.png`,
      videoEditor: isStage2 && ve ? { id: ve.id, name: ve.name } : undefined,
      videoEditorAmount: isStage2 && veAmount ? +veAmount : undefined,
    });
  };

  return (
    <Modal open={true} onClose={onClose}
      title={`Complete Stage ${stage} · ${stageLabel}`}
      sub="Evidence required to progress"
      foot={<>
        <span className="text-xs text-mute">{canConfirm ? "Ready to confirm." : "All required uploads must be completed."}</span>
        <div style={{ display: "flex", gap: 8 }}>
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn primary" disabled={!canConfirm} onClick={handleConfirm}>Confirm Stage {stage}</button>
        </div>
      </>}>

      {/* Stage 1 — contract section */}
      {isStage1 && (
        <div style={{ marginBottom: 16 }}>
          <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.1em", marginBottom: 8 }}>Signed Contract</div>
          {contractOnFile ? (
            <div className="banner" style={{ background: "var(--ok-bg, #f0faf4)", borderColor: "var(--ok)", display: "flex", alignItems: "center", gap: 10 }}>
              <span className="tick" />
              <div>
                <div style={{ fontWeight: 600, fontSize: 13 }}>Contract already on file</div>
                <div className="text-xs text-mute">{influencer.signedContract.fileName} · signed {influencer.signedContract.uploadedAt}</div>
              </div>
              <Chip tone="ok" xs style={{ marginLeft: "auto" }}>Reused</Chip>
            </div>
          ) : (
            <>
              <div className="text-mute text-xs" style={{ marginBottom: 8 }}>
                The influencer must sign the contract before Stage 1 can be completed. Upload the signed PDF or image. This is stored on the influencer record and will not be required again for future deals.
              </div>
              {!contractUploaded ? (
                <div onClick={() => setContractUploaded(true)} style={{ cursor: "pointer" }}>
                  <div className="shot-placeholder" style={{ height: 120 }}>
                    <div style={{ textAlign: "center" }}><Ic.upload /><div style={{ marginTop: 6, fontSize: 12 }}>Click to upload signed contract (PDF / image)</div></div>
                  </div>
                </div>
              ) : (
                <div className="shot-placeholder" style={{ height: 80, display: "flex", alignItems: "center", justifyContent: "center", gap: 8 }}>
                  <span className="tick" /><span style={{ fontSize: 13 }}>signed-contract.pdf — uploaded</span>
                </div>
              )}
            </>
          )}
        </div>
      )}

      {/* Stage 2 — Video Editor assignment */}
      {isStage2 && (
        <div style={{ marginBottom: 16 }}>
          <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.1em", marginBottom: 8 }}>Video Editor <span style={{ color: "var(--bad)" }}>*</span></div>
          <div className="text-mute text-xs" style={{ marginBottom: 8 }}>Select the video editor assigned to this content draft and enter the agreed project amount.</div>
          <div className="grid-2">
            <div className="field" style={{ margin: 0 }}>
              <label>Video Editor</label>
              <select className="select" value={selectedVE} onChange={e => setSelectedVE(e.target.value)}>
                <option value="">— Select editor —</option>
                {videoEditors.map(v => <option key={v.id} value={v.id}>{v.name} · {v.id}</option>)}
              </select>
            </div>
            <div className="field" style={{ margin: 0 }}>
              <label>Amount (USD)</label>
              <input className="input" type="number" min="0" step="10" placeholder="e.g. 120" value={veAmount} onChange={e => setVEAmount(e.target.value)} />
            </div>
          </div>
        </div>
      )}

      {/* Evidence upload (all stages) */}
      <div>
        <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.1em", marginBottom: 8 }}>
          {stage === 1 ? "Additional Evidence" : "Stage Evidence"}
        </div>
        <div className="text-mute text-xs" style={{ marginBottom: 8 }}>
          {stage === 1 ? "Screenshot or document confirming stage completion." :
           stage === 2 ? "Screenshot of approved content draft." :
           stage === 3 ? "Screenshot of published content (post, story, reel)." :
           "Screenshot or report showing performance milestone reached."}
        </div>
        {!evidenceUploaded ? (
          <div onClick={() => setEvidenceUploaded(true)} style={{ cursor: "pointer" }}>
            <div className="shot-placeholder" style={{ height: 140 }}>
              <div style={{ textAlign: "center" }}><Ic.upload /><div style={{ marginTop: 6, fontSize: 12 }}>Click to upload evidence (screenshot / PDF)</div></div>
            </div>
          </div>
        ) : (
          <div className="shot-placeholder" style={{ height: 80, display: "flex", alignItems: "center", justifyContent: "center", gap: 8 }}>
            <span className="tick" /><span style={{ fontSize: 13 }}>evidence-stage-{stage}.png — uploaded</span>
          </div>
        )}
      </div>
    </Modal>
  );
}

// ============================================================================
// Request ticket modal
// ============================================================================

function RequestTicketModal({ influencer, onClose, onDone }) {
  const { role, activePersonId, data, addRequest } = useApp();
  const [type, setType] = useState("Inquiry");
  const [message, setMessage] = useState("");
  const [pasted, setPasted] = useState("");

  const submit = () => {
    const now = new Date();
    const dateStr = now.toLocaleDateString("en-GB", { day: "2-digit", month: "short" });
    const timeStr = now.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
    const reqId = `REQ-${Date.now().toString().slice(-4)}`;
    // Resolve real person name from activePersonId
    let raisedBy;
    if (role === "outreach") {
      const person = (data.outreachSpecialists || []).find(p => p.id === activePersonId);
      raisedBy = { kind: "OS", id: activePersonId || "OS-01", name: person?.name || "Outreach Specialist" };
    } else {
      const person = (data.collabManagers || []).find(p => p.id === activePersonId);
      raisedBy = { kind: "CM", id: activePersonId || "CM-01", name: person?.name || "Collab Manager" };
    }
    addRequest({
      id: reqId,
      type,
      priority: type === "High Percentage" ? "high" : "normal",
      at: `${dateStr}, ${timeStr}`,
      raisedBy,
      influencer,
      bundle: influencer.bundleId || "",
      campaignId: influencer.campaignId || null,
      campaignName: influencer.campaignName || null,
      assignmentId: influencer.assignmentId || null,
      summary: message.trim().substring(0, 80),
      aiSummary: `${raisedBy.name} raised ${/^[aeiou]/i.test(type) ? "an" : "a"} ${type.toLowerCase()} request about ${influencer.name}.`,
      status: "Open",
      thread: [{ from: raisedBy.name, at: `${dateStr}, ${timeStr}`, body: message.trim() }],
      adminViewed: false,
      transcript: pasted.trim() || null,
    });
    onDone("Request ticket submitted — Admin has been notified in their inbox.");
  };

  return (
    <Modal open={true} onClose={onClose}
      title="Request Help"
      sub={`For ${influencer.name} · routed to Admin`}
      size="wide"
      foot={<>
        <span className="text-xs text-mute">A Linear task is auto-created in your Requests section.</span>
        <div style={{ display: "flex", gap: 8 }}>
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn primary" disabled={!message.trim()} onClick={submit}>Submit</button>
        </div>
      </>}>
      <div className="field">
        <label>Type</label>
        <div style={{ display: "flex", gap: 8 }}>
          {["Inquiry", "High Percentage", "Other"].map(t => (
            <button key={t} className={`btn sm ${type === t ? "primary" : ""}`} onClick={() => setType(t)}>{t}</button>
          ))}
        </div>
      </div>
      <div className="field">
        <label>Describe the situation</label>
        <div style={{ position: "relative" }}>
          <textarea className="textarea" rows="5" value={message} onChange={e => setMessage(e.target.value)}
            placeholder="What do you need from admin?" style={{ paddingRight: 44 }} />
          <MicButton />
        </div>
      </div>
      <div className="grid-2">
        <div className="field">
          <label>Attachments (optional)</label>
          <div className="shot-placeholder" style={{ height: 100 }}>Drag screenshots here · or click</div>
        </div>
        <div className="field">
          <label>Paste transcript (optional)</label>
          <textarea className="textarea" rows="4" value={pasted} onChange={e => setPasted(e.target.value)} placeholder="Paste conversation text for context…" />
        </div>
      </div>
    </Modal>
  );
}

// ============================================================================
// Edit Influencer Modal
// ============================================================================

function EditInfluencerModal({ influencer, onClose, onSave }) {
  const [name, setName] = useState(influencer.name);
  const [handle, setHandle] = useState(influencer.handle);
  const [platform, setPlatform] = useState(influencer.platform);
  const [category, setCategory] = useState(influencer.category);
  const [followers, setFollowers] = useState(influencer.followers);
  const [location, setLocation] = useState(influencer.location);
  const [er, setEr] = useState(influencer.er || "");
  const [whatsapp, setWhatsapp] = useState(influencer.phoneNumber || "");

  return (
    <Modal open={true} onClose={onClose} size="wide"
      title={`Edit · ${influencer.name}`}
      sub={`${influencer.id} · ${influencer.handle || influencer.platform || "Influencer profile"}`}
      foot={<>
        <span className="text-xs text-mute">Changes apply to this profile immediately.</span>
        <div style={{ display: "flex", gap: 8 }}>
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn primary" disabled={!name.trim() || !handle.trim()}
            onClick={() => onSave({ ...influencer, name, handle, platform, category, followers, location, er, phoneNumber: whatsapp.trim() || null })}>
            Save Changes
          </button>
        </div>
      </>}>
      <div className="grid-2">
        <div className="field"><label>Full Name</label><input className="input" value={name} onChange={e => setName(e.target.value)} autoFocus /></div>
        <div className="field"><label>Handle</label><input className="input" value={handle} onChange={e => setHandle(e.target.value)} /></div>
      </div>
      <div className="grid-2">
        <div className="field"><label>Platform</label>
          <select className="select" value={platform} onChange={e => setPlatform(e.target.value)}>
            <option>Instagram</option><option>TikTok</option><option>YouTube</option>
          </select>
        </div>
        <div className="field"><label>Category</label>
          <select className="select" value={category} onChange={e => setCategory(e.target.value)}>
            <option>Fitness</option><option>Lifestyle</option><option>Beauty</option><option>Tech</option><option>Food</option><option>Travel</option><option>Fashion</option><option>Finance</option>
          </select>
        </div>
      </div>
      <div className="grid-2">
        <div className="field"><label>Followers</label><input className="input" value={followers} onChange={e => setFollowers(e.target.value)} placeholder="e.g. 1.2M" /></div>
        <div className="field"><label>Engagement Rate</label><input className="input" value={er} onChange={e => setEr(e.target.value)} placeholder="e.g. 2.4%" /></div>
      </div>
      <div className="grid-2">
        <div className="field"><label>Location</label><input className="input" value={location} onChange={e => setLocation(e.target.value)} placeholder="City, Country" /></div>
        <div className="field"><label>WhatsApp <span className="text-xs text-mute">(optional)</span></label><input className="input" value={whatsapp} onChange={e => setWhatsapp(e.target.value)} placeholder="+44 7700 900000" style={{ fontFamily: "var(--font-mono)" }} /></div>
      </div>
    </Modal>
  );
}

// ============================================================================
// Influencer Payments Tab — tracks what the brand pays TO the influencer
// ============================================================================

function AddInfluencerPaymentModal({ onClose, onSave }) {
  const [amount, setAmount] = useState("");
  const [description, setDescription] = useState("");
  const [status, setStatus] = useState("Pending");
  const [note, setNote] = useState("");

  const valid = amount && parseFloat(amount) > 0 && description.trim();

  return (
    <Modal open={true} onClose={onClose} title="Add Influencer Payment" sub="Admin only — tracks payments made to this influencer"
      foot={<>
        <button className="btn" onClick={onClose}>Cancel</button>
        <button className="btn primary" disabled={!valid} onClick={() => onSave({
          id: "INF-PAY-" + Date.now(),
          amount: parseFloat(amount),
          description: description.trim(),
          status,
          note: note.trim(),
          date: new Date().toLocaleDateString("en-GB", { day: "2-digit", month: "short", year: "numeric" }),
        })}>Add Payment</button>
      </>}>
      <div className="grid-2">
        <div className="field">
          <label>Amount (USD)</label>
          <input className="input" type="number" step="0.01" min="0" value={amount} onChange={e => setAmount(e.target.value)} autoFocus placeholder="e.g. 500.00" />
        </div>
        <div className="field">
          <label>Status</label>
          <select className="select" value={status} onChange={e => setStatus(e.target.value)}>
            <option>Pending</option>
            <option>Paid</option>
          </select>
        </div>
      </div>
      <div className="field">
        <label>Description</label>
        <input className="input" value={description} onChange={e => setDescription(e.target.value)} placeholder="e.g. Campaign fee · Stage 1, Brand deal payment" />
      </div>
      <div className="field">
        <label>Note <span className="text-mute">(optional)</span></label>
        <textarea className="textarea" rows={2} value={note} onChange={e => setNote(e.target.value)} placeholder="e.g. Transferred via PayPal on 1 May 2026" />
      </div>
    </Modal>
  );
}

function InfluencerPaymentsTab({ influencer, onUpdate }) {
  const { notify } = useApp();
  const entries = influencer.influencerPayments || [];
  const [addOpen, setAddOpen] = useState(false);
  const [pg, setPg] = useState(1);
  const perPage = 8;

  const totalPaid = entries.filter(e => e.status === "Paid").reduce((s, e) => s + e.amount, 0);
  const totalPending = entries.filter(e => e.status !== "Paid").reduce((s, e) => s + e.amount, 0);
  const totalPages = Math.max(1, Math.ceil(entries.length / perPage));
  const paged = [...entries].reverse().slice((pg - 1) * perPage, pg * perPage);

  const addEntry = (entry) => {
    const updated = [...entries, entry];
    onUpdate({ influencerPayments: updated });
    setAddOpen(false);
    notify(`Payment entry added — $${entry.amount.toFixed(2)} · ${entry.description}`);
  };

  const markPaid = (id) => {
    const updated = entries.map(e => e.id === id ? { ...e, status: "Paid" } : e);
    onUpdate({ influencerPayments: updated });
    notify("Payment marked as Paid.");
  };

  const markPending = (id) => {
    const updated = entries.map(e => e.id === id ? { ...e, status: "Pending" } : e);
    onUpdate({ influencerPayments: updated });
    notify("Payment marked as Pending.");
  };

  return (
    <div style={{ marginTop: 14 }}>
      <div className="toolbar" style={{ marginBottom: 16 }}>
        <div style={{ fontSize: 13, color: "var(--ink-2)" }}>Payments made directly to this influencer by the brand/company.</div>
        <div className="spacer" />
        <button className="btn primary sm" onClick={() => setAddOpen(true)}><Ic.plus /> Add Payment</button>
      </div>

      {entries.length > 0 && (
        <div className="kpi-row" style={{ marginBottom: 20 }}>
          <div className="kpi"><div className="label">Total Entries</div><div className="value">{entries.length}</div><div className="delta">all time</div></div>
          <div className="kpi"><div className="label">Total Paid</div><div className="value">${totalPaid.toFixed(2)}</div><div className="delta">confirmed</div></div>
          <div className="kpi featured"><div className="label">Pending</div><div className="value">${totalPending.toFixed(2)}</div><div className="delta">awaiting payment</div></div>
        </div>
      )}

      {entries.length === 0 ? (
        <div style={{ textAlign: "center", padding: "48px 0", color: "var(--ink-3)", fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.06em" }}>
          NO PAYMENTS YET — USE ADD PAYMENT TO LOG BRAND PAYMENTS TO THIS INFLUENCER
        </div>
      ) : (
        <>
          <div className="table-wrap">
            <table className="ims">
              <thead>
                <tr>
                  <th>Date</th>
                  <th>Description</th>
                  <th className="num">Amount</th>
                  <th>Status</th>
                  <th>Note</th>
                  <th style={{ width: 120 }}></th>
                </tr>
              </thead>
              <tbody>
                {paged.map(entry => (
                  <tr key={entry.id}>
                    <td className="text-xs text-mute" style={{ whiteSpace: "nowrap" }}>{entry.date}</td>
                    <td style={{ fontSize: 13 }}>{entry.description}</td>
                    <td className="num" style={{ fontFamily: "var(--font-mono)", fontWeight: 600 }}>${entry.amount.toFixed(2)}</td>
                    <td><StatusChip status={entry.status} /></td>
                    <td className="text-xs text-mute">{entry.note || "—"}</td>
                    <td style={{ textAlign: "right" }}>
                      {entry.status !== "Paid"
                        ? <button className="btn sm" onClick={() => markPaid(entry.id)}>Mark Paid</button>
                        : <button className="btn sm ghost" onClick={() => markPending(entry.id)}>Undo</button>}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <TablePagination page={pg} totalPages={totalPages} onPage={setPg} total={entries.length} perPage={perPage} />
        </>
      )}

      {addOpen && <AddInfluencerPaymentModal onClose={() => setAddOpen(false)} onSave={addEntry} />}
    </div>
  );
}

// ---------------- Admin Override Status Modal ----------------

function AdminOverrideStatusModal({ influencer, onClose, onSave }) {
  const isCM = !!(influencer.cmId || influencer.currentStage);
  const STATUS_OPTIONS = isCM
    ? [
        { label: "Stage 1 · In Progress", value: "Stage 1 In Progress" },
        { label: "Stage 1 · Complete",    value: "Stage 1 Complete" },
        { label: "Stage 2 · In Progress", value: "Stage 2 In Progress" },
        { label: "Stage 2 · Complete",    value: "Stage 2 Complete" },
        { label: "Stage 3 · In Progress", value: "Stage 3 In Progress" },
        { label: "Stage 4 · In Progress", value: "Stage 4 In Progress" },
      ]
    : [
        { label: "Not Contacted",  value: "Not Contacted" },
        { label: "Contacted",      value: "Contacted" },
        { label: "Interested",     value: "Interested" },
        { label: "Rejected",       value: "Rejected" },
        { label: "Not Interested", value: "Not Interested" },
        { label: "Not Responding", value: "Not Responding" },
        { label: "Accepted",       value: "Accepted" },
      ];

  const currentVal = isCM
    ? `Stage ${influencer.currentStage} ${influencer.stageState}`
    : (influencer.status || "Not Contacted");

  const [selected, setSelected] = useState(currentVal);
  const [reason, setReason]     = useState("");

  return (
    <Modal open={true} onClose={onClose}
      title={`Override Status · ${influencer.name}`}
      sub="Admin Override — bypasses payment freeze"
      foot={<>
        <span className="text-xs text-mute" style={{ fontFamily: "var(--mono)" }}>
          {isCM ? "Collaboration Manager" : "Outreach Specialist"} will receive a banner to confirm receipt
        </span>
        <div style={{ display: "flex", gap: 8 }}>
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn primary" onClick={() => onSave(selected, reason)}>
            Override Status
          </button>
        </div>
      </>}
    >
      <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
        {/* Warning banner */}
        <div style={{
          display: "flex", alignItems: "flex-start", gap: 10,
          padding: "10px 14px",
          background: "var(--warn-bg)", border: "1px solid var(--warn)",
          borderRadius: "var(--r-md)", fontSize: 13, color: "var(--warn-dark)",
          lineHeight: 1.5,
        }}>
          <Ic.warn style={{ flexShrink: 0, marginTop: 1 }} />
          <span>This overrides the current status and notifies the assigned specialist. They must confirm receipt and may change it back.</span>
        </div>

        {/* Current status badge */}
        <div className="kv-list" style={{ borderRadius: "var(--r-md)", border: "1px solid var(--line)", overflow: "hidden" }}>
          <div className="kv" style={{ padding: "8px 14px" }}>
            <div className="k">Current Status</div>
            <div className="v"><StatusChip status={influencer.status || (influencer.currentStage ? `Stage ${influencer.currentStage}` : "Unassigned")} /></div>
          </div>
        </div>

        {/* Status picker */}
        <div className="field">
          <label>Select New Status</label>
          <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
            {STATUS_OPTIONS.map(({ label, value }) => (
              <button
                key={value}
                className={`btn sm ${selected === value ? "primary" : ""}`}
                onClick={() => setSelected(value)}
              >
                {label}
              </button>
            ))}
          </div>
        </div>

        {/* Reason field */}
        <div className="field">
          <label>Reason / Admin Note <span className="text-mute">(optional)</span></label>
          <textarea
            className="textarea"
            rows={3}
            placeholder="Explain why you're overriding this status…"
            value={reason}
            onChange={e => setReason(e.target.value)}
          />
        </div>
      </div>
    </Modal>
  );
}

// ---------------- Reassign Modal ----------------

function ReassignModal({ influencer, onClose, onSave }) {
  const { data } = useApp();

  // Auto-detect assignment type — CM if in collab pipeline, else OS
  const isCM = !!(influencer.cmId || influencer.currentStage);
  const type  = isCM ? "cm" : "os";
  const specialists = isCM ? data.collabManagers : data.outreachSpecialists;
  const typeLabel   = isCM ? "Collaboration Manager" : "Outreach Specialist";

  // Current assignee ID
  const currentId = isCM ? influencer.cmId : influencer.specialistId;

  const [selected, setSelected] = useState(null);
  const [reason,   setReason]   = useState("");

  return (
    <Modal open={true} onClose={onClose}
      title={`Reassign · ${influencer.name}`}
      sub={influencer.bundleId ? `${typeLabel} reassignment · current bundle ${influencer.bundleId}` : `${typeLabel} reassignment`}
      size="wide"
      foot={<>
        <span className="text-xs text-mute" style={{ fontFamily: "var(--mono)" }}>
          New specialist notified to confirm on assign
        </span>
        <div style={{ display: "flex", gap: 8 }}>
          <button className="btn" onClick={onClose}>Cancel</button>
          <button
            className="btn primary"
            disabled={!selected}
            onClick={() => onSave(type, selected)}
          >
            Confirm Reassign
          </button>
        </div>
      </>}
    >
      <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
        {/* Context chip */}
        <div style={{
          display: "flex", alignItems: "center", gap: 8,
          padding: "10px 14px",
          background: "var(--bg-2)", border: "1px solid var(--line)",
          borderRadius: "var(--r-md)", fontSize: 13,
        }}>
          <span className="text-mute" style={{ fontFamily: "var(--mono)", fontSize: 11, textTransform: "uppercase", letterSpacing: "0.08em" }}>{typeLabel}</span>
          <span style={{ color: "var(--line-2)" }}>·</span>
          <span>Select a new {typeLabel.toLowerCase()} to take over this influencer.</span>
        </div>

        {/* Specialist list */}
        <div className="field">
          <label>Select {typeLabel}</label>
          <div style={{ display: "flex", flexDirection: "column", gap: 5 }}>
            {specialists.map(s => {
              const isCurrent = s.id === currentId;
              const isSelected = selected?.id === s.id;
              return (
                <div
                  key={s.id}
                  onClick={() => !isCurrent && setSelected(s)}
                  style={{
                    display: "flex", alignItems: "center", gap: 12,
                    padding: "10px 14px",
                    border: `1px solid ${isSelected ? "var(--accent)" : "var(--line)"}`,
                    borderRadius: "var(--r-md)",
                    cursor: isCurrent ? "default" : "pointer",
                    background: isSelected ? "var(--accent-bg)" : isCurrent ? "var(--bg-2)" : "var(--paper)",
                    opacity: isCurrent ? 0.55 : 1,
                    transition: "border-color 0.1s, background 0.1s",
                  }}
                >
                  {/* Radio indicator */}
                  <div style={{
                    width: 16, height: 16, borderRadius: "50%", flexShrink: 0,
                    border: `2px solid ${isSelected ? "var(--accent)" : "var(--line-2)"}`,
                    background: isSelected ? "var(--accent)" : "transparent",
                    display: "flex", alignItems: "center", justifyContent: "center",
                    transition: "border-color 0.1s, background 0.1s",
                  }}>
                    {isSelected && <div style={{ width: 6, height: 6, borderRadius: "50%", background: "var(--paper)" }} />}
                  </div>
                  {/* Avatar */}
                  <div style={{
                    width: 34, height: 34, borderRadius: "50%", flexShrink: 0,
                    background: isSelected ? "var(--accent)" : "var(--ink-3)",
                    color: "var(--paper)",
                    display: "flex", alignItems: "center", justifyContent: "center",
                    fontSize: 12, fontWeight: 700,
                    fontFamily: "var(--mono)", letterSpacing: "0.05em",
                    transition: "background 0.15s",
                  }}>
                    {(s.initials || s.name.split(" ").map(n => n[0]).join("").substring(0, 2)).toUpperCase()}
                  </div>
                  {/* Info */}
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontWeight: 600, fontSize: 14, color: "var(--ink)" }}>
                      {s.name}
                      {isCurrent && <span className="pill" style={{ marginLeft: 8, fontSize: 11, background: "var(--bg-3)", color: "var(--ink-3)", border: "none" }}>Current</span>}
                    </div>
                    <div style={{ fontFamily: "var(--mono)", fontSize: 11, color: "var(--ink-3)", marginTop: 2 }}>
                      {s.id}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>

        {/* Reason */}
        <div className="field">
          <label>Reason for Reassignment <span className="text-mute">(optional)</span></label>
          <textarea
            className="textarea"
            rows={2}
            placeholder="E.g. capacity issue, territory mismatch, specialist request…"
            value={reason}
            onChange={e => setReason(e.target.value)}
          />
        </div>
      </div>
    </Modal>
  );
}

function DropInfluencerModal({ influencer, onClose, onDone }) {
  const [reason, setReason] = useState("");
  return (
    <Modal open onClose={onClose} sub="Drop influencer" title={`Drop · ${influencer.name}`}
      foot={<>
        <button className="btn" onClick={onClose}>Cancel</button>
        <button className="btn danger" disabled={!reason.trim()} onClick={() => onDone(reason.trim())}>Confirm Drop</button>
      </>}>
      <div className="text-mute text-xs" style={{ marginBottom: 12 }}>
        The influencer will be removed from your active pipeline. Their record is preserved in the Influencer DB with the reason attached.
      </div>
      <div className="field">
        <label>Reason for dropping</label>
        <textarea className="textarea" rows="3" value={reason} onChange={e => setReason(e.target.value)} placeholder="e.g. Influencer decided not to proceed with collaboration." autoFocus />
      </div>
    </Modal>
  );
}

function ArchiveInfluencerModal({ influencer, onClose, onDone }) {
  const [reason, setReason] = useState("");
  const isActive = ["Contacted", "Interested", "In Progress"].includes(influencer.status);
  return (
    <Modal open onClose={onClose} sub="Archive influencer" title={`Archive · ${influencer.name}`}
      foot={<>
        <button className="btn" onClick={onClose}>Cancel</button>
        <button className="btn danger" onClick={() => onDone(reason.trim())}>Archive</button>
      </>}>
      {isActive && (
        <div className="banner bad" style={{ marginBottom: 12 }}>
          <Ic.warn /> This influencer is currently <strong>{influencer.status}</strong>. Archiving will remove them from the active pipeline and any unpaid earnings will remain recorded.
        </div>
      )}
      <div className="text-mute text-xs" style={{ marginBottom: 12 }}>
        The influencer record will be preserved for audit purposes but removed from all active lists and searches.
      </div>
      <div className="field">
        <label>Reason for archiving <span className="text-mute">(optional)</span></label>
        <textarea className="textarea" rows="3" value={reason} onChange={e => setReason(e.target.value)} placeholder="e.g. Duplicate entry, test account, no longer relevant…" autoFocus />
      </div>
    </Modal>
  );
}

Object.assign(window, { ProfilePage, OverviewTab, ConversationTab, StagesTab, CampaignsTab, ActivityTab, RequestsTab, StatusChangeModal, StageEvidenceModal, RequestTicketModal, EditInfluencerModal, InfluencerPaymentsTab, AddInfluencerPaymentModal, AdminOverrideStatusModal, ReassignModal, DropInfluencerModal, ArchiveInfluencerModal });
