/**
 * Upstream Command Center — Sales & System Pages
 * Loaded BEFORE app.jsx so components are available for NAV_SECTIONS.
 *
 * Pages: OverviewPage, ActivityLogPage, AnalyticsPage
 * Placeholder pages: ProspectFeedPage, SequencesPage, DealBoardPage,
 *   ReplyInboxPage, ContactsPage, SegmentsPage
 */

// ---------------------------------------------------------------------------
// Helpers (apiFetch defined in app.jsx but this loads first — use window.fetch)
// ---------------------------------------------------------------------------

function salesApiFetch(path, options = {}) {
  const base = window.__UPSTREAM_API_BASE || "";
  return fetch(base + path, {
    ...options,
    credentials: "include",
    headers: { ...options.headers, "Content-Type": "application/json" },
  });
}

function relativeTime(isoStr) {
  if (!isoStr) return "";
  const diff = Date.now() - new Date(isoStr).getTime();
  const mins = Math.floor(diff / 60000);
  if (mins < 1) return "just now";
  if (mins < 60) return mins + "m ago";
  const hrs = Math.floor(mins / 60);
  if (hrs < 24) return hrs + "h ago";
  const days = Math.floor(hrs / 24);
  return days + "d ago";
}

// ---------------------------------------------------------------------------
// OverviewPage — unified metrics from both engines
// ---------------------------------------------------------------------------

function OverviewPage() {
  const [dashboard, setDashboard] = React.useState(null);
  const [analytics, setAnalytics] = React.useState(null);
  const [activity, setActivity] = React.useState(null);
  const [deals, setDeals] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    Promise.all([
      salesApiFetch("/api/dashboard").then(r => r.ok ? r.json() : null).catch(() => null),
      salesApiFetch("/api/analytics").then(r => r.ok ? r.json() : null).catch(() => null),
      salesApiFetch("/api/activity-log").then(r => r.ok ? r.json() : null).catch(() => null),
      salesApiFetch("/api/sales/deals").then(r => r.ok ? r.json() : null).catch(() => null),
    ]).then(([dash, anal, act, dl]) => {
      setDashboard(dash);
      setAnalytics(anal);
      setActivity(act);
      setDeals(dl);
      setLoading(false);
    }).catch(err => {
      setError(err.message);
      setLoading(false);
    });
  }, []);

  if (loading) return <div className="loading">Loading overview...</div>;
  if (error) return <div className="error-state">{error}</div>;

  const subscribers = analytics?.funnel?.find(s => s.stage === "subscribers")?.count || 0;
  const prospects = analytics?.funnel?.find(s => s.stage === "prospects")?.count || 0;
  const dealCount = deals?.summary ? Object.values(deals.summary).reduce((sum, n) => sum + n, 0) : 0;
  const repliesToday = activity?.summary?.today?.reply_received || 0;

  const tracks = dashboard?.tracks || [];
  const salesPaused = deals?.paused || false;
  const sequencesActive = deals?.summary?.sequencing || 0;

  const todaySummary = activity?.summary?.today || {};

  return (
    <div className="page">
      <div className="page-header">
        <h2>Overview</h2>
        <p className="subtitle">Unified command center — content + sales engines</p>
      </div>

      <div className="metric-cards">
        <div className="metric-card">
          <div className="overview-metric-value">{subscribers}</div>
          <div className="overview-metric-label">Subscribers</div>
        </div>
        <div className="metric-card">
          <div className="overview-metric-value">{prospects}</div>
          <div className="overview-metric-label">Active Prospects</div>
        </div>
        <div className="metric-card">
          <div className="overview-metric-value">{dealCount}</div>
          <div className="overview-metric-label">Deals in Pipeline</div>
        </div>
        <div className="metric-card">
          <div className="overview-metric-value">{repliesToday}</div>
          <div className="overview-metric-label">Replies Today</div>
        </div>
      </div>

      <div className="card-grid">
        <div className="card">
          <div className="card-title">Content Engine</div>
          {tracks.length > 0 ? tracks.map(t => (
            <div key={t.name} className="metric-row" style={{ marginBottom: 6 }}>
              <span className="metric-label">{t.name}</span>
              <span className={"badge " + (t.status === "active" ? "badge-ok" : t.status === "error" ? "badge-error" : "badge-pending")}>{t.status}</span>
            </div>
          )) : (
            <div className="text-muted" style={{ fontSize: 13 }}>No track data available</div>
          )}
        </div>
        <div className="card">
          <div className="card-title">Sales Engine</div>
          <div className="metric-row" style={{ marginBottom: 6 }}>
            <span className="metric-label">Status</span>
            <span className={"badge " + (salesPaused ? "badge-error" : "badge-ok")}>
              {salesPaused ? "paused" : "active"}
            </span>
          </div>
          <div className="metric-row" style={{ marginBottom: 6 }}>
            <span className="metric-label">Active Sequences</span>
            <span style={{ fontWeight: 600 }}>{sequencesActive}</span>
          </div>
          {analytics?.costs && (
            <div className="metric-row">
              <span className="metric-label">Monthly Cost</span>
              <span style={{ fontWeight: 600 }}>${(analytics.costs.total_this_month || 0).toFixed(2)}</span>
            </div>
          )}
        </div>
      </div>

      {Object.keys(todaySummary).length > 0 && (
        <div className="card" style={{ marginTop: 0 }}>
          <div className="card-title">Today</div>
          <div style={{ fontSize: 14, color: "var(--text-primary)" }}>
            {Object.entries(todaySummary).map(([type, count], i) => (
              <span key={type}>
                {i > 0 ? ", " : ""}
                <strong>{count}</strong> {type.replace(/_/g, " ")}
              </span>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// ActivityLogPage — reverse-chronological system actions
// ---------------------------------------------------------------------------

const ACTIVITY_TYPE_COLORS = {
  email_sent: "#2D7DD2",
  reply_received: "#4CAF7D",
  prospect_discovered: "#9B59B6",
  stage_change: "#E67E22",
  note: "#6B7A8D",
  meeting_booked: "#C9A84C",
};

const ACTIVITY_FILTERS = [
  { key: "all", label: "All" },
  { key: "email_sent", label: "Emails" },
  { key: "reply_received", label: "Replies" },
  { key: "prospect_discovered", label: "Discoveries" },
  { key: "stage_change", label: "Stage Changes" },
];

function ActivityLogPage() {
  const [entries, setEntries] = React.useState([]);
  const [summary, setSummary] = React.useState({});
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [filter, setFilter] = React.useState("all");
  const [expandedIdx, setExpandedIdx] = React.useState(null);

  React.useEffect(() => {
    salesApiFetch("/api/activity-log")
      .then(r => {
        if (!r.ok) throw new Error("Failed to load activity log");
        return r.json();
      })
      .then(data => {
        setEntries(data.entries || []);
        setSummary(data.summary?.today || {});
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) return <div className="loading">Loading activity log...</div>;
  if (error) return <div className="error-state">{error}</div>;

  const filtered = filter === "all" ? entries : entries.filter(e => e.type === filter);

  const summaryParts = Object.entries(summary);

  return (
    <div className="page">
      <div className="page-header">
        <h2>Activity Log</h2>
        <p className="subtitle">System actions from the last 7 days</p>
      </div>

      {summaryParts.length > 0 && (
        <div className="card" style={{ marginBottom: 20 }}>
          <div style={{ fontSize: 14 }}>
            <strong>Today:</strong>{" "}
            {summaryParts.map(([type, count], i) => (
              <span key={type}>
                {i > 0 ? ", " : ""}
                {count} {type.replace(/_/g, " ")}
              </span>
            ))}
          </div>
        </div>
      )}

      <div className="filter-tabs">
        {ACTIVITY_FILTERS.map(f => (
          <button
            key={f.key}
            className={"filter-tab" + (filter === f.key ? " active" : "")}
            onClick={() => setFilter(f.key)}
          >
            {f.label}
          </button>
        ))}
      </div>

      {filtered.length === 0 ? (
        <div className="empty-state">No activity entries found</div>
      ) : (
        <div>
          {filtered.map((entry, idx) => {
            const dotColor = ACTIVITY_TYPE_COLORS[entry.type] || "#6B7A8D";
            const isExpanded = expandedIdx === idx;
            return (
              <div
                key={idx}
                className="activity-entry"
                onClick={() => setExpandedIdx(isExpanded ? null : idx)}
              >
                <div className="activity-dot" style={{ backgroundColor: dotColor }} />
                <div className="activity-time">{relativeTime(entry.at)}</div>
                <div className="activity-detail">
                  <div>
                    {entry.contact_name && (
                      <strong>{entry.contact_name}</strong>
                    )}
                    {entry.contact_name && " — "}
                    <span className="text-muted">{entry.type.replace(/_/g, " ")}</span>
                  </div>
                  {isExpanded && entry.detail && (
                    <div className="activity-expand">{entry.detail}</div>
                  )}
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// AnalyticsPage — funnel, attribution, costs
// ---------------------------------------------------------------------------

function AnalyticsPage() {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [sortCol, setSortCol] = React.useState("prospects");
  const [sortAsc, setSortAsc] = React.useState(false);

  React.useEffect(() => {
    salesApiFetch("/api/analytics")
      .then(r => {
        if (!r.ok) throw new Error("Failed to load analytics");
        return r.json();
      })
      .then(d => {
        setData(d);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) return <div className="loading">Loading analytics...</div>;
  if (error) return <div className="error-state">{error}</div>;

  const funnel = data?.funnel || [];
  const maxCount = Math.max(...funnel.map(s => s.count), 1);

  const FUNNEL_COLORS = [
    "#2D7DD2", "#3A8FD6", "#47A1DA", "#54B3DE",
    "#5FC4D6", "#4CAF7D", "#3FA06A",
  ];

  const attribution = data?.attribution || [];
  const sortedAttribution = [...attribution].sort((a, b) => {
    const va = a[sortCol] ?? 0;
    const vb = b[sortCol] ?? 0;
    return sortAsc ? va - vb : vb - va;
  });

  function handleSort(col) {
    if (col === sortCol) {
      setSortAsc(!sortAsc);
    } else {
      setSortCol(col);
      setSortAsc(false);
    }
  }

  const sortIndicator = (col) => {
    if (col !== sortCol) return "";
    return sortAsc ? " \u25B2" : " \u25BC";
  };

  const costs = data?.costs || {};
  const services = costs.services || [];
  const budgetPct = costs.budget_cap > 0
    ? Math.min((costs.total_this_month / costs.budget_cap) * 100, 100)
    : 0;
  const budgetColor = budgetPct > 90 ? "var(--danger)" : budgetPct > 70 ? "var(--cta-gold)" : "var(--data-positive)";

  return (
    <div className="page">
      <div className="page-header">
        <h2>Analytics</h2>
        <p className="subtitle">Funnel performance, content attribution, and cost tracking</p>
      </div>

      <div className="section-block">
        <div className="section-title">Conversion Funnel</div>
        <div className="card">
          {funnel.map((stage, idx) => (
            <React.Fragment key={stage.stage}>
              <div className="funnel-row">
                <div className="funnel-label">{stage.stage.replace(/_/g, " ")}</div>
                <div className="funnel-bar-container">
                  <div
                    className="funnel-bar"
                    style={{
                      width: (stage.count / maxCount * 100) + "%",
                      backgroundColor: FUNNEL_COLORS[idx] || FUNNEL_COLORS[0],
                    }}
                  />
                </div>
                <div className="funnel-count">{stage.count}</div>
              </div>
              {idx < funnel.length - 1 && funnel[idx].count > 0 && (
                <div className="funnel-conversion">
                  {funnel[idx].count} &rarr; {funnel[idx + 1].count}
                  {" "}({(funnel[idx + 1].count / funnel[idx].count * 100).toFixed(1)}%)
                </div>
              )}
            </React.Fragment>
          ))}
        </div>
      </div>

      <div className="section-block">
        <div className="section-title">Content Attribution</div>
        {sortedAttribution.length === 0 ? (
          <div className="empty-state">No attribution data yet</div>
        ) : (
          <table className="data-table">
            <thead>
              <tr>
                <th>Article</th>
                <th className="sortable-col" onClick={() => handleSort("prospects")}>
                  Prospects{sortIndicator("prospects")}
                </th>
                <th className="sortable-col" onClick={() => handleSort("replies")}>
                  Replies{sortIndicator("replies")}
                </th>
                <th className="sortable-col" onClick={() => handleSort("meetings")}>
                  Meetings{sortIndicator("meetings")}
                </th>
                <th className="sortable-col" onClick={() => handleSort("revenue")}>
                  Revenue{sortIndicator("revenue")}
                </th>
              </tr>
            </thead>
            <tbody>
              {sortedAttribution.map(row => (
                <tr key={row.slug}>
                  <td>{row.slug}</td>
                  <td>{row.prospects}</td>
                  <td>{row.replies}</td>
                  <td>{row.meetings}</td>
                  <td>${(row.revenue || 0).toFixed(0)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>

      <div className="section-block">
        <div className="section-title">Cost Breakdown</div>
        <table className="data-table">
          <thead>
            <tr>
              <th>Service</th>
              <th>This Month</th>
              <th>Last Month</th>
              <th>Delta</th>
            </tr>
          </thead>
          <tbody>
            {services.map(svc => (
              <tr key={svc.service}>
                <td>{svc.service}</td>
                <td>${(svc.this_month || 0).toFixed(2)}</td>
                <td>${(svc.last_month || 0).toFixed(2)}</td>
                <td className={svc.delta > 0 ? "text-negative" : svc.delta < 0 ? "text-positive" : ""}>
                  {svc.delta > 0 ? "+" : ""}{(svc.delta || 0).toFixed(2)}
                </td>
              </tr>
            ))}
            <tr style={{ fontWeight: 700 }}>
              <td>Total</td>
              <td>${(costs.total_this_month || 0).toFixed(2)}</td>
              <td>${(costs.total_last_month || 0).toFixed(2)}</td>
              <td className={(costs.total_this_month - costs.total_last_month) > 0 ? "text-negative" : "text-positive"}>
                {(costs.total_this_month - costs.total_last_month) > 0 ? "+" : ""}
                {((costs.total_this_month || 0) - (costs.total_last_month || 0)).toFixed(2)}
              </td>
            </tr>
          </tbody>
        </table>

        {costs.budget_cap > 0 && (
          <div style={{ marginTop: 16 }}>
            <div style={{ fontSize: 12, color: "var(--text-muted)", marginBottom: 4 }}>
              Budget: ${(costs.total_this_month || 0).toFixed(2)} / ${(costs.budget_cap || 0).toFixed(2)}
            </div>
            <div className="budget-bar-container">
              <div
                className="budget-bar-fill"
                style={{ width: budgetPct + "%", backgroundColor: budgetColor }}
              />
            </div>
          </div>
        )}

        {costs.cac != null && (
          <div style={{ marginTop: 12, fontSize: 14, fontWeight: 600, color: "var(--text-primary)" }}>
            Customer Acquisition Cost: ${(costs.cac || 0).toFixed(2)}
          </div>
        )}
      </div>

      {/* Flywheel Metrics */}
      {data?.flywheel && (
        <div className="section-block" style={{marginTop: '1.5rem'}}>
          <div className="section-title">Flywheel Metrics</div>
          <div className="card">
            <div style={{display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '1rem', marginTop: '1rem'}}>
              <div className="stat-box">
                <div className="stat-value">{data.flywheel.content_sourced_prospects || 0}</div>
                <div className="stat-label">Content-Sourced Prospects</div>
              </div>
              <div className="stat-box">
                <div className="stat-value">{data.flywheel.outbound_subscriber_rate || 0}%</div>
                <div className="stat-label">Outbound-to-Subscriber Rate</div>
              </div>
              <div className="stat-box">
                <div className="stat-value">{data.flywheel.hot_leads_with_content || 0}</div>
                <div className="stat-label">Hot Leads with Content Data</div>
              </div>
              <div className="stat-box">
                <div className="stat-value">{data.flywheel.contacts_with_content_data || 0}</div>
                <div className="stat-label">Contacts with Content Interests</div>
              </div>
            </div>
            {/* Pillar demand from reply signals */}
            {data.flywheel.pillar_demand && Object.keys(data.flywheel.pillar_demand).length > 0 && (
              <div style={{marginTop: '1rem'}}>
                <div className="section-title" style={{marginBottom: '0.5rem'}}>Reply Topic Demand</div>
                <div style={{display: 'flex', gap: '0.5rem', flexWrap: 'wrap', marginTop: '0.5rem'}}>
                  {Object.entries(data.flywheel.pillar_demand)
                    .sort((a, b) => b[1] - a[1])
                    .map(([pillar, count]) => (
                      <span key={pillar} className="badge" style={{padding: '0.25rem 0.75rem'}}>
                        {pillar.replace(/_/g, ' ')}: {count}
                      </span>
                    ))}
                </div>
              </div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Placeholder pages — replaced by plans 09-03 and 09-04
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
// ProspectCard — compact row with tier/layer badges, score, actions
// ---------------------------------------------------------------------------

function ProspectCard({ prospect, activeTab, expanded, onToggle, onAction }) {
  const tierColors = { S: "tier-S", A: "tier-A", B: "tier-B", C: "tier-C" };
  const layerColors = {
    relationship: "layer-relationship",
    operator: "layer-operator",
    bdr: "layer-bdr",
    newsletter: "layer-newsletter",
  };

  const [acting, setActing] = React.useState(false);

  function handleAction(e, action) {
    e.stopPropagation();
    if (acting) return;
    setActing(true);
    onAction(prospect.id, action).finally(() => setActing(false));
  }

  const interactions = prospect.interactions || [];
  const tags = prospect.tags || [];

  return (
    <div>
      <div className="prospect-card" onClick={onToggle}>
        <span className={"tier-badge " + (tierColors[prospect.tier] || "tier-C")}>
          {prospect.tier || "?"}
        </span>
        <span
          className="prospect-name contact-link"
          onClick={(e) => { e.stopPropagation(); window.location.hash = "#contact/" + prospect.id; }}
        >{prospect.name || "Unknown"}</span>
        <span className="prospect-role">
          {prospect.title || ""}{prospect.title && prospect.company ? " @ " : ""}{prospect.company || ""}
        </span>
        <span className={"layer-badge " + (layerColors[prospect.layer] || "")}>
          {prospect.layer || ""}
        </span>
        <span className="prospect-score">{prospect.total_score || 0}/100</span>
        <span className="prospect-pain">{prospect.pain_summary || ""}</span>
        <div className="prospect-actions">
          {activeTab === "pending" && (
            <>
              <button className="btn-approve" disabled={acting} onClick={(e) => handleAction(e, "approve")}>Approve</button>
              <button className="btn-skip" disabled={acting} onClick={(e) => handleAction(e, "skip")}>Skip</button>
            </>
          )}
          {activeTab === "approved" && <span className="badge badge-ok">Approved</span>}
          {activeTab === "skipped" && <span className="badge badge-error">Skipped</span>}
        </div>
      </div>
      {expanded && (
        <div className="prospect-expand">
          <div>
            <div className="section-title">Research Dossier</div>
            <div style={{ fontSize: 13, marginBottom: 12, lineHeight: 1.6 }}>
              {prospect.pain_summary || "No pain signals recorded."}
            </div>
            <div className="section-title">Scores</div>
            <div style={{ fontSize: 13, lineHeight: 1.8 }}>
              <div>Fit: <strong>{prospect.fit_score || 0}</strong>/40</div>
              <div>Pain: <strong>{prospect.pain_score || 0}</strong>/40</div>
              <div>Access: <strong>{prospect.access_score || 0}</strong>/20</div>
              <div style={{ marginTop: 4, fontWeight: 700 }}>Total: {prospect.total_score || 0}/100</div>
            </div>
            {tags.length > 0 && (
              <div style={{ marginTop: 12 }}>
                <div className="section-title">Tags</div>
                <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
                  {tags.map(t => <span key={t} className="badge badge-pending">{t}</span>)}
                </div>
              </div>
            )}
          </div>
          <div>
            <div className="section-title">Recent Interactions</div>
            {interactions.length === 0 ? (
              <div className="text-muted" style={{ fontSize: 13 }}>No interactions yet</div>
            ) : (
              <div>
                {interactions.slice(0, 5).map((ix, i) => (
                  <div key={i} style={{ fontSize: 13, marginBottom: 8, borderBottom: "1px solid var(--border)", paddingBottom: 6 }}>
                    <div style={{ fontWeight: 600, fontSize: 12, color: "var(--text-muted)" }}>
                      {ix.type ? ix.type.replace(/_/g, " ") : "action"} {ix.at ? " — " + relativeTime(ix.at) : ""}
                    </div>
                    <div>{ix.detail || ""}</div>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// ProspectFeedPage — filterable prospect action queue
// ---------------------------------------------------------------------------

function ProspectFeedPage() {
  const [prospects, setProspects] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [activeTab, setActiveTab] = React.useState("pending");
  const [expandedId, setExpandedId] = React.useState(null);
  const [page, setPage] = React.useState(1);
  const [totalPages, setTotalPages] = React.useState(1);

  function fetchProspects(tab, pg) {
    setLoading(true);
    setError(null);
    const status = tab === "all" ? "" : "&status=" + tab;
    salesApiFetch("/api/sales/prospects?page=" + pg + "&per_page=20" + status)
      .then(r => {
        if (!r.ok) throw new Error("Failed to load prospects");
        return r.json();
      })
      .then(data => {
        setProspects(data.prospects || []);
        setTotalPages(data.pages || 1);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }

  React.useEffect(() => {
    fetchProspects(activeTab, page);
  }, [activeTab, page]);

  function handleTabChange(tab) {
    setActiveTab(tab);
    setPage(1);
    setExpandedId(null);
  }

  function handleAction(prospectId, action) {
    const body = action === "approve"
      ? { action: "approve" }
      : action === "skip"
      ? { action: "skip" }
      : { action: "pause" };

    return salesApiFetch("/api/sales/prospects/" + prospectId, {
      method: "PUT",
      body: JSON.stringify(body),
    }).then(r => {
      if (!r.ok) throw new Error("Action failed");
      if (activeTab === "pending") {
        setProspects(prev => prev.filter(p => p.id !== prospectId));
      } else {
        fetchProspects(activeTab, page);
      }
    }).catch(err => {
      console.error("Prospect action error:", err);
    });
  }

  const tabs = [
    { key: "pending", label: "Pending" },
    { key: "approved", label: "Approved" },
    { key: "skipped", label: "Skipped" },
    { key: "all", label: "All" },
  ];

  return (
    <div className="page">
      <div className="page-header">
        <h2>Prospect Feed</h2>
        <p className="subtitle">Review and approve prospects for outreach sequences</p>
      </div>

      <div className="filter-tabs">
        {tabs.map(t => (
          <button
            key={t.key}
            className={"filter-tab" + (activeTab === t.key ? " active" : "")}
            onClick={() => handleTabChange(t.key)}
          >
            {t.label}
          </button>
        ))}
      </div>

      {loading && <div className="loading">Loading prospects...</div>}
      {error && <div className="error-state">{error}</div>}

      {!loading && !error && prospects.length === 0 && (
        <div className="empty-state">No {activeTab === "all" ? "" : activeTab + " "}prospects found</div>
      )}

      {!loading && !error && prospects.length > 0 && (
        <div className="card" style={{ padding: 0, overflow: "hidden" }}>
          {prospects.map(p => (
            <ProspectCard
              key={p.id}
              prospect={p}
              activeTab={activeTab}
              expanded={expandedId === p.id}
              onToggle={() => setExpandedId(expandedId === p.id ? null : p.id)}
              onAction={handleAction}
            />
          ))}
        </div>
      )}

      {!loading && totalPages > 1 && (
        <div className="pagination">
          <button
            className="filter-tab"
            disabled={page <= 1}
            onClick={() => setPage(p => Math.max(1, p - 1))}
          >
            Prev
          </button>
          <span className="pagination-info">Page {page} of {totalPages}</span>
          <button
            className="filter-tab"
            disabled={page >= totalPages}
            onClick={() => setPage(p => Math.min(totalPages, p + 1))}
          >
            Next
          </button>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// SequencesPage — contacts grouped by layer with delivery timeline
// ---------------------------------------------------------------------------

function SequenceContactCard({ contact }) {
  const layerColors = {
    relationship: "layer-relationship",
    operator: "layer-operator",
    bdr: "layer-bdr",
    newsletter: "layer-newsletter",
  };

  function getStatusClass(contact) {
    if (contact.sequence_paused) return "status-paused";
    if (!contact.sequence_next_send) return "status-on-track";
    const nextSend = new Date(contact.sequence_next_send);
    return nextSend < new Date() ? "status-overdue" : "status-on-track";
  }

  function formatNextSend(isoStr) {
    if (!isoStr) return "Not scheduled";
    const d = new Date(isoStr);
    const now = new Date();
    const diffMs = d - now;
    const diffDays = Math.ceil(diffMs / 86400000);
    if (diffDays < 0) return Math.abs(diffDays) + "d overdue";
    if (diffDays === 0) return "Today";
    if (diffDays === 1) return "Tomorrow";
    return "In " + diffDays + "d";
  }

  return (
    <div className="sequence-card">
      <div className={"sequence-status-dot " + getStatusClass(contact)} />
      <span style={{ fontWeight: 600, width: 160, flexShrink: 0 }}>{contact.name || "Unknown"}</span>
      <span className="text-muted" style={{ flex: 1, fontSize: 13 }}>{contact.company || ""}</span>
      <span className={"layer-badge " + (layerColors[contact.layer] || "")} style={{ flexShrink: 0 }}>
        {contact.layer || ""}
      </span>
      <span className="sequence-touch">
        Touch {contact.sequence_touch || "?"} of {contact.sequence_total || "?"}
      </span>
      <span className="sequence-next">{formatNextSend(contact.sequence_next_send)}</span>
      {contact.last_interaction && (
        <span className="text-muted" style={{ fontSize: 12, flexShrink: 0, maxWidth: 200, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
          {contact.last_interaction.detail || contact.last_interaction.type || ""}
        </span>
      )}
    </div>
  );
}

function SequencesPage() {
  const [sequences, setSequences] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    salesApiFetch("/api/sales/sequences")
      .then(r => {
        if (!r.ok) throw new Error("Failed to load sequences");
        return r.json();
      })
      .then(data => {
        setSequences(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) return <div className="loading">Loading sequences...</div>;
  if (error) return <div className="error-state">{error}</div>;

  const layers = ["relationship", "operator", "bdr"];
  const layerLabels = { relationship: "Relationship", operator: "Operator", bdr: "BDR" };
  const seqData = sequences?.sequences || {};
  const totalActive = sequences?.total_active || 0;

  return (
    <div className="page">
      <div className="page-header">
        <h2>Active Sequences</h2>
        <p className="subtitle">Contacts currently in outreach sequences</p>
      </div>

      <div className="card" style={{ marginBottom: 20, padding: "14px 20px" }}>
        <span style={{ fontSize: 14 }}>
          <strong>{totalActive}</strong> active sequence{totalActive !== 1 ? "s" : ""} across {layers.length} layers
        </span>
      </div>

      {layers.map(layer => {
        const contacts = seqData[layer] || [];
        return (
          <div key={layer} className="sequence-section">
            <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 8 }}>
              <h3 style={{ fontSize: 14, fontWeight: 700, margin: 0 }}>{layerLabels[layer]}</h3>
              <span className="kanban-count">{contacts.length}</span>
            </div>
            {contacts.length === 0 ? (
              <div className="empty-state" style={{ padding: "24px 16px" }}>No active {layer} sequences</div>
            ) : (
              <div className="card" style={{ padding: 0, overflow: "hidden" }}>
                {contacts.map(c => <SequenceContactCard key={c.id} contact={c} />)}
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

// ---------------------------------------------------------------------------
// DealCard — compact Kanban card with inline expand
// ---------------------------------------------------------------------------

const DEAL_STAGES = ["discovery", "qualified", "meeting", "proposal", "closed_won", "closed_lost"];
const DEAL_STAGE_LABELS = {
  discovery: "Discovery",
  qualified: "Qualified",
  meeting: "Meeting",
  proposal: "Proposal",
  closed_won: "Closed Won",
  closed_lost: "Closed Lost",
};

function DealCard({ deal, expanded, onToggle, onStageChange, onNoteSave }) {
  const layerColors = {
    relationship: "layer-relationship",
    operator: "layer-operator",
    bdr: "layer-bdr",
    newsletter: "layer-newsletter",
  };

  const [noteText, setNoteText] = React.useState(deal.notes || "");
  const [noteDirty, setNoteDirty] = React.useState(false);
  const [saving, setSaving] = React.useState(false);

  function handleNoteBlur() {
    if (!noteDirty) return;
    setSaving(true);
    onNoteSave(deal.id, noteText).finally(() => {
      setSaving(false);
      setNoteDirty(false);
    });
  }

  function handleStageChange(e) {
    const newStage = e.target.value;
    if (newStage && newStage !== deal.stage) {
      onStageChange(deal.id, newStage);
    }
  }

  return (
    <div>
      <div className="deal-card" onClick={onToggle}>
        <div
          className="deal-name contact-link"
          onClick={(e) => { e.stopPropagation(); window.location.hash = "#contact/" + deal.contact_id; }}
        >{deal.contact_name || "Unknown"}</div>
        <div className="deal-company">{deal.contact_company || ""}</div>
        <div className="deal-meta">
          <span className={"layer-badge " + (layerColors[deal.layer] || "")}>
            {deal.layer || ""}
          </span>
          <span className="days-badge">{deal.days_in_stage || 0}d</span>
        </div>
        {deal.last_interaction && (
          <div style={{ fontSize: 11, color: "var(--text-muted)", marginTop: 4, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
            {deal.last_interaction}
          </div>
        )}
      </div>
      {expanded && (
        <div className="deal-expand">
          <div style={{ marginBottom: 10 }}>
            <div className="section-title">Stage</div>
            <div className="stage-dropdown">
              <select value={deal.stage} onChange={handleStageChange}>
                {DEAL_STAGES.map(s => (
                  <option key={s} value={s}>{DEAL_STAGE_LABELS[s]}</option>
                ))}
              </select>
            </div>
          </div>

          {deal.stage_history && deal.stage_history.length > 0 && (
            <div style={{ marginBottom: 10 }}>
              <div className="section-title">Stage History</div>
              {deal.stage_history.slice(-3).map((sh, i) => (
                <div key={i} style={{ fontSize: 12, color: "var(--text-muted)", marginBottom: 2 }}>
                  {DEAL_STAGE_LABELS[sh.stage] || sh.stage} {sh.at ? " — " + relativeTime(sh.at) : ""}
                </div>
              ))}
            </div>
          )}

          <div className="deal-notes">
            <div className="section-title">Notes {saving && <span className="text-muted">(saving...)</span>}</div>
            <textarea
              value={noteText}
              onChange={(e) => { setNoteText(e.target.value); setNoteDirty(true); }}
              onBlur={handleNoteBlur}
              placeholder="Add notes about this deal..."
            />
          </div>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// DealBoardPage — 6-column Kanban
// ---------------------------------------------------------------------------

function DealBoardPage() {
  const [stageData, setStageData] = React.useState({});
  const [summary, setSummary] = React.useState({});
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [expandedDealId, setExpandedDealId] = React.useState(null);
  const [closedCollapsed, setClosedCollapsed] = React.useState(true);

  function fetchDeals() {
    return salesApiFetch("/api/sales/deals")
      .then(r => {
        if (!r.ok) throw new Error("Failed to load deals");
        return r.json();
      })
      .then(data => {
        setStageData(data.stages || {});
        setSummary(data.summary || {});
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }

  React.useEffect(() => { fetchDeals(); }, []);

  function handleStageChange(dealId, newStage) {
    salesApiFetch("/api/sales/deals/" + dealId, {
      method: "PUT",
      body: JSON.stringify({ stage: newStage }),
    }).then(r => {
      if (!r.ok) throw new Error("Stage change failed");
      setExpandedDealId(null);
      return fetchDeals();
    }).catch(err => console.error("Stage change error:", err));
  }

  function handleNoteSave(dealId, noteText) {
    return salesApiFetch("/api/sales/deals/" + dealId, {
      method: "PUT",
      body: JSON.stringify({ notes: noteText }),
    }).then(r => {
      if (!r.ok) throw new Error("Note save failed");
    }).catch(err => console.error("Note save error:", err));
  }

  if (loading) return <div className="loading">Loading deals...</div>;
  if (error) return <div className="error-state">{error}</div>;

  const isClosedStage = (s) => s === "closed_won" || s === "closed_lost";

  return (
    <div className="page">
      <div className="page-header">
        <h2>Deal Board</h2>
        <p className="subtitle">Pipeline stages from discovery to close</p>
      </div>

      <div className="kanban-board">
        {DEAL_STAGES.map(stage => {
          const deals = stageData[stage] || [];
          const count = summary[stage] || deals.length;
          const isClosed = isClosedStage(stage);
          const isCollapsed = isClosed && closedCollapsed;

          return (
            <div key={stage} className={"kanban-column" + (isCollapsed ? " column-collapsed" : "")}>
              <div
                className={"kanban-header" + (isClosed ? " collapse-toggle" : "")}
                onClick={isClosed ? () => setClosedCollapsed(!closedCollapsed) : undefined}
              >
                <h3>
                  {DEAL_STAGE_LABELS[stage]}
                  {isClosed && <span style={{ marginLeft: 6, fontSize: 10 }}>{closedCollapsed ? "+" : "-"}</span>}
                </h3>
                <span className="kanban-count">{count}</span>
              </div>
              {!isCollapsed && deals.length === 0 && (
                <div className="text-muted" style={{ fontSize: 12, textAlign: "center", padding: "16px 0" }}>No deals</div>
              )}
              {!isCollapsed && deals.map(deal => (
                <DealCard
                  key={deal.id}
                  deal={deal}
                  expanded={expandedDealId === deal.id}
                  onToggle={() => setExpandedDealId(expandedDealId === deal.id ? null : deal.id)}
                  onStageChange={handleStageChange}
                  onNoteSave={handleNoteSave}
                />
              ))}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Toast — brief success notification
// ---------------------------------------------------------------------------

function Toast({ message, onDone }) {
  React.useEffect(() => {
    const timer = setTimeout(onDone, 2000);
    return () => clearTimeout(timer);
  }, [onDone]);
  return <div className="toast">{message}</div>;
}

// ---------------------------------------------------------------------------
// ReplyInboxPage — sentiment-tagged replies with quick actions
// ---------------------------------------------------------------------------

function ReplyInboxPage() {
  const [replies, setReplies] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [expandedId, setExpandedId] = React.useState(null);
  const [noteText, setNoteText] = React.useState({});
  const [showNoteFor, setShowNoteFor] = React.useState(null);
  const [stageFor, setStageFor] = React.useState(null);
  const [toast, setToast] = React.useState(null);

  function fetchReplies() {
    setLoading(true);
    salesApiFetch("/api/sales/replies")
      .then(r => {
        if (!r.ok) throw new Error("Failed to load replies");
        return r.json();
      })
      .then(data => {
        setReplies(data.replies || []);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }

  React.useEffect(() => { fetchReplies(); }, []);

  function handleAction(contactId, action, detail) {
    const body = { action };
    if (detail) body.detail = detail;
    return salesApiFetch("/api/sales/replies/" + contactId + "/action", {
      method: "POST",
      body: JSON.stringify(body),
    }).then(r => {
      if (!r.ok) throw new Error("Action failed");
      const labels = {
        book_meeting: "Meeting booked",
        log_note: "Note logged",
        change_stage: "Stage changed",
        pause_sequence: "Sequence paused",
      };
      setToast(labels[action] || "Done");
      setShowNoteFor(null);
      setStageFor(null);
      fetchReplies();
    }).catch(err => console.error("Reply action error:", err));
  }

  if (loading) return <div className="loading">Loading replies...</div>;
  if (error) return <div className="error-state">{error}</div>;

  const sentimentClass = {
    positive: "sentiment-positive",
    neutral: "sentiment-neutral",
    negative: "sentiment-negative",
  };

  const sentimentLabel = {
    positive: "Positive",
    neutral: "Neutral",
    negative: "Negative",
  };

  return (
    <div className="page">
      <div className="page-header">
        <h2>Reply Inbox</h2>
        <p className="subtitle">Triage replies and take action on warm leads</p>
      </div>

      {replies.length === 0 ? (
        <div className="empty-state">No replies yet. Outreach sequences will generate replies here.</div>
      ) : (
        <div className="card" style={{ padding: 0, overflow: "hidden" }}>
          {replies.map((reply, idx) => {
            const isExpanded = expandedId === idx;
            return (
              <div key={idx}>
                <div className="reply-card" onClick={() => setExpandedId(isExpanded ? null : idx)}>
                  <div className="reply-header">
                    <span className={"sentiment-badge " + (sentimentClass[reply.sentiment] || "sentiment-neutral")}>
                      {sentimentLabel[reply.sentiment] || "Neutral"}
                    </span>
                    <span
                      className="reply-sender contact-link"
                      onClick={(e) => { e.stopPropagation(); window.location.hash = "#contact/" + reply.contact_id; }}
                    >
                      {reply.contact_name || "Unknown"}
                    </span>
                    <span className="reply-company">{reply.contact_company || ""}</span>
                    <span className="reply-time">{relativeTime(reply.at)}</span>
                  </div>
                  <div className="reply-summary">{reply.summary || ""}</div>
                </div>
                {isExpanded && (
                  <div className="reply-expand">
                    <div style={{ fontSize: 14, lineHeight: 1.7, marginBottom: 12, whiteSpace: "pre-wrap" }}>
                      {reply.detail || reply.summary || ""}
                    </div>
                    <div className="reply-actions">
                      <button onClick={(e) => { e.stopPropagation(); handleAction(reply.contact_id, "book_meeting"); }}>
                        Book Meeting
                      </button>
                      <button onClick={(e) => {
                        e.stopPropagation();
                        setShowNoteFor(showNoteFor === idx ? null : idx);
                        setStageFor(null);
                      }}>
                        Log Note
                      </button>
                      <button onClick={(e) => {
                        e.stopPropagation();
                        setStageFor(stageFor === idx ? null : idx);
                        setShowNoteFor(null);
                      }}>
                        Change Stage
                      </button>
                      <button onClick={(e) => { e.stopPropagation(); handleAction(reply.contact_id, "pause_sequence"); }}>
                        Pause Sequence
                      </button>
                    </div>
                    {showNoteFor === idx && (
                      <div style={{ marginTop: 10 }}>
                        <textarea
                          className="note-inline-textarea"
                          placeholder="Add a note..."
                          value={noteText[idx] || ""}
                          onChange={(e) => setNoteText(prev => ({ ...prev, [idx]: e.target.value }))}
                          onClick={(e) => e.stopPropagation()}
                        />
                        <button
                          className="btn-approve"
                          style={{ marginTop: 6 }}
                          onClick={(e) => { e.stopPropagation(); handleAction(reply.contact_id, "log_note", noteText[idx] || ""); }}
                        >
                          Save Note
                        </button>
                      </div>
                    )}
                    {stageFor === idx && (
                      <div style={{ marginTop: 10 }} onClick={(e) => e.stopPropagation()}>
                        <select
                          defaultValue=""
                          onChange={(e) => { if (e.target.value) handleAction(reply.contact_id, "change_stage", e.target.value); }}
                          style={{ padding: "4px 8px", borderRadius: 4, border: "1px solid var(--border)", fontSize: 12 }}
                        >
                          <option value="" disabled>Select stage...</option>
                          <option value="discovery">Discovery</option>
                          <option value="qualified">Qualified</option>
                          <option value="meeting">Meeting</option>
                          <option value="proposal">Proposal</option>
                          <option value="closed_won">Closed Won</option>
                          <option value="closed_lost">Closed Lost</option>
                        </select>
                      </div>
                    )}
                  </div>
                )}
              </div>
            );
          })}
        </div>
      )}

      {toast && <Toast message={toast} onDone={() => setToast(null)} />}
    </div>
  );
}

// ---------------------------------------------------------------------------
// ContactDetailPage — unified timeline + editable notes/tags + research
// ---------------------------------------------------------------------------

function ContactDetailPage() {
  const [contact, setContact] = React.useState(null);
  const [deals, setDeals] = React.useState([]);
  const [research, setResearch] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [notes, setNotes] = React.useState("");
  const [notesDirty, setNotesDirty] = React.useState(false);
  const [saving, setSaving] = React.useState(false);
  const [tags, setTags] = React.useState([]);
  const [newTag, setNewTag] = React.useState("");
  const [toast, setToast] = React.useState(null);

  function getContactId() {
    const hash = window.location.hash || "";
    const parts = hash.split("/");
    return parts.length > 1 ? parts[1] : null;
  }

  const contactId = getContactId();

  function fetchContact() {
    if (!contactId) { setError("No contact ID"); setLoading(false); return; }
    setLoading(true);
    salesApiFetch("/api/contacts/" + contactId)
      .then(r => {
        if (!r.ok) throw new Error("Failed to load contact");
        return r.json();
      })
      .then(data => {
        const c = data.contact || data;
        setContact(c);
        setNotes(c.notes || "");
        setTags(c.tags || []);
        setDeals(data.deals || []);
        setResearch(data.research || null);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }

  React.useEffect(() => { fetchContact(); }, []);

  function saveNotes() {
    if (!notesDirty) return;
    setSaving(true);
    salesApiFetch("/api/contacts/" + contactId, {
      method: "PUT",
      body: JSON.stringify({ notes }),
    }).then(r => {
      if (!r.ok) throw new Error("Save failed");
      setSaving(false);
      setNotesDirty(false);
      setToast("Notes saved");
    }).catch(err => {
      console.error("Notes save error:", err);
      setSaving(false);
    });
  }

  function saveTags(updatedTags) {
    setTags(updatedTags);
    salesApiFetch("/api/contacts/" + contactId, {
      method: "PUT",
      body: JSON.stringify({ tags: updatedTags }),
    }).then(r => {
      if (!r.ok) throw new Error("Tag save failed");
      setToast("Tags updated");
    }).catch(err => console.error("Tag save error:", err));
  }

  function removeTag(tag) {
    saveTags(tags.filter(t => t !== tag));
  }

  function addTag() {
    const trimmed = newTag.trim();
    if (!trimmed || tags.includes(trimmed)) return;
    saveTags([...tags, trimmed]);
    setNewTag("");
  }

  function handleTagKeyDown(e) {
    if (e.key === "Enter") { e.preventDefault(); addTag(); }
  }

  function handlePauseResume() {
    salesApiFetch("/api/sales/prospects/" + contactId, {
      method: "PUT",
      body: JSON.stringify({ action: contact?.sequence_status === "paused" ? "resume" : "pause" }),
    }).then(r => {
      if (!r.ok) throw new Error("Action failed");
      setToast(contact?.sequence_status === "paused" ? "Sequence resumed" : "Sequence paused");
      fetchContact();
    }).catch(err => console.error("Pause/resume error:", err));
  }

  function handleStageChange(dealId, newStage) {
    salesApiFetch("/api/sales/deals/" + dealId, {
      method: "PUT",
      body: JSON.stringify({ stage: newStage }),
    }).then(r => {
      if (!r.ok) throw new Error("Stage change failed");
      setToast("Deal stage changed");
      fetchContact();
    }).catch(err => console.error("Stage change error:", err));
  }

  if (loading) return <div className="loading">Loading contact...</div>;
  if (error) return <div className="error-state">{error}</div>;
  if (!contact) return <div className="error-state">Contact not found</div>;

  const TIMELINE_DOT_CLASS = {
    email_sent: "dot-email",
    reply_received: "dot-reply",
    reply: "dot-reply",
    prospect_discovered: "dot-discovery",
    discovery: "dot-discovery",
    stage_change: "dot-stage",
    note: "dot-note",
    meeting_booked: "dot-meeting",
    meeting: "dot-meeting",
    subscribed: "dot-subscribed",
  };

  const interactions = contact.interactions || [];
  const typeLabel = { subscriber: "Subscriber", prospect: "Prospect", customer: "Customer", churned: "Churned" };
  const tierColors = { S: "tier-S", A: "tier-A", B: "tier-B", C: "tier-C" };
  const layerColors = {
    relationship: "layer-relationship", operator: "layer-operator",
    bdr: "layer-bdr", newsletter: "layer-newsletter",
  };

  return (
    <div className="page">
      <button
        className="back-btn"
        onClick={() => { window.location.hash = "#contacts"; }}
        style={{ marginBottom: 12, cursor: "pointer", background: "none", border: "none", color: "var(--sidebar-active)", fontSize: 13, fontWeight: 500 }}
      >
        &larr; Back to Contacts
      </button>

      <div className="contact-header">
        <div className="contact-name">{contact.name || "Unknown"}</div>
        <div className="contact-role">
          {contact.title || ""}{contact.title && contact.company ? " @ " : ""}{contact.company || ""}
        </div>
        <div className="contact-badges">
          {contact.type && <span className="badge badge-ok">{typeLabel[contact.type] || contact.type}</span>}
          {contact.tier && <span className={"tier-badge " + (tierColors[contact.tier] || "tier-C")}>{contact.tier}</span>}
          {contact.layer && <span className={"layer-badge " + (layerColors[contact.layer] || "")}>{contact.layer}</span>}
          {contact.total_score != null && (
            <span style={{ fontSize: 14, fontWeight: 600, color: "var(--text-primary)" }}>
              {contact.total_score}/100
            </span>
          )}
        </div>
      </div>

      <div className="quick-actions">
        <button onClick={handlePauseResume}>
          {contact.sequence_status === "paused" ? "Resume Sequence" : "Pause Sequence"}
        </button>
        {deals.length > 0 && (
          <select
            value={deals[0].stage}
            onChange={(e) => handleStageChange(deals[0].id, e.target.value)}
            style={{ padding: "6px 10px", borderRadius: 4, border: "1px solid var(--border)", fontSize: 13, cursor: "pointer" }}
          >
            <option value="discovery">Discovery</option>
            <option value="qualified">Qualified</option>
            <option value="meeting">Meeting</option>
            <option value="proposal">Proposal</option>
            <option value="closed_won">Closed Won</option>
            <option value="closed_lost">Closed Lost</option>
          </select>
        )}
      </div>

      <div className="section-block">
        <div className="section-title">Timeline</div>
        {interactions.length === 0 ? (
          <div className="empty-state">No interactions recorded yet</div>
        ) : (
          <div className="timeline">
            {interactions.map((ix, i) => (
              <div key={i} className="timeline-event">
                <div className={"timeline-dot " + (TIMELINE_DOT_CLASS[ix.type] || "dot-note")} />
                <div className="timeline-date">
                  {ix.at ? relativeTime(ix.at) : ""}
                  {ix.source && (
                    <span className={"source-badge " + (ix.source === "content" ? "source-content" : "source-sales")}>
                      {ix.source}
                    </span>
                  )}
                </div>
                <div className="timeline-detail">
                  <span style={{ fontWeight: 500, fontSize: 12, textTransform: "uppercase", letterSpacing: "0.04em", color: "var(--text-muted)" }}>
                    {(ix.type || "").replace(/_/g, " ")}
                  </span>
                  {" "}{ix.detail || ""}
                </div>
              </div>
            ))}
          </div>
        )}
      </div>

      <div className="section-block">
        <div className="section-title">Notes {saving && <span className="text-muted">(saving...)</span>}</div>
        <div className="contact-notes">
          <textarea
            value={notes}
            onChange={(e) => { setNotes(e.target.value); setNotesDirty(true); }}
            onBlur={saveNotes}
            placeholder="Add notes about this contact..."
          />
        </div>
      </div>

      <div className="section-block">
        <div className="section-title">Tags</div>
        <div className="contact-tags">
          {tags.map(tag => (
            <span key={tag} className="tag-pill">
              {tag}
              <span className="tag-remove" onClick={() => removeTag(tag)}>&times;</span>
            </span>
          ))}
          <input
            className="tag-input"
            value={newTag}
            onChange={(e) => setNewTag(e.target.value)}
            onKeyDown={handleTagKeyDown}
            placeholder="Add tag..."
          />
        </div>
      </div>

      {research && (
        <div className="section-block">
          <div className="section-title">Research Dossier</div>
          <div className="card">
            {research.company_summary && (
              <div style={{ fontSize: 14, marginBottom: 12, lineHeight: 1.6 }}>{research.company_summary}</div>
            )}
            {research.pain_signals && research.pain_signals.length > 0 && (
              <div style={{ marginBottom: 12 }}>
                <div style={{ fontWeight: 600, fontSize: 13, marginBottom: 4 }}>Pain Signals</div>
                <ul style={{ paddingLeft: 20, fontSize: 13 }}>
                  {research.pain_signals.map((sig, i) => <li key={i}>{sig}</li>)}
                </ul>
              </div>
            )}
            {research.recommended_angle && (
              <div>
                <div style={{ fontWeight: 600, fontSize: 13, marginBottom: 4 }}>Recommended Angle</div>
                <div style={{ fontSize: 14, color: "var(--sidebar-active)", fontWeight: 500 }}>{research.recommended_angle}</div>
              </div>
            )}
          </div>
        </div>
      )}

      {deals.length > 0 && (
        <div className="section-block">
          <div className="section-title">Deals</div>
          {deals.map(deal => (
            <div key={deal.id} className="card" style={{ marginBottom: 8 }}>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                <span style={{ fontWeight: 600, textTransform: "capitalize" }}>{(deal.stage || "").replace(/_/g, " ")}</span>
                <span className="days-badge">{deal.days_in_stage || 0}d in stage</span>
              </div>
            </div>
          ))}
        </div>
      )}

      {toast && <Toast message={toast} onDone={() => setToast(null)} />}
    </div>
  );
}

// ---------------------------------------------------------------------------
// ContactsPage — filterable, searchable contact table
// ---------------------------------------------------------------------------

function ContactsPage() {
  const [contacts, setContacts] = React.useState([]);
  const [total, setTotal] = React.useState(0);
  const [page, setPage] = React.useState(1);
  const [totalPages, setTotalPages] = React.useState(1);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [typeFilter, setTypeFilter] = React.useState("all");
  const [layerFilter, setLayerFilter] = React.useState("all");
  const [search, setSearch] = React.useState("");
  const searchTimer = React.useRef(null);

  function fetchContacts(pg, type, layer, q) {
    setLoading(true);
    let url = "/api/contacts?page=" + pg + "&per_page=20";
    if (type && type !== "all") url += "&type=" + type;
    if (layer && layer !== "all") url += "&layer=" + layer;
    if (q) url += "&search=" + encodeURIComponent(q);
    salesApiFetch(url)
      .then(r => {
        if (!r.ok) throw new Error("Failed to load contacts");
        return r.json();
      })
      .then(data => {
        setContacts(data.contacts || []);
        setTotal(data.total || 0);
        setTotalPages(data.pages || 1);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }

  React.useEffect(() => {
    fetchContacts(page, typeFilter, layerFilter, search);
  }, [page, typeFilter, layerFilter]);

  function handleSearchInput(e) {
    const val = e.target.value;
    setSearch(val);
    if (searchTimer.current) clearTimeout(searchTimer.current);
    searchTimer.current = setTimeout(() => {
      setPage(1);
      fetchContacts(1, typeFilter, layerFilter, val);
    }, 300);
  }

  function handleTypeChange(e) {
    setTypeFilter(e.target.value);
    setPage(1);
  }

  function handleLayerChange(e) {
    setLayerFilter(e.target.value);
    setPage(1);
  }

  const tierColors = { S: "tier-S", A: "tier-A", B: "tier-B", C: "tier-C" };

  return (
    <div className="page">
      <div className="page-header">
        <h2>All Contacts</h2>
        <p className="subtitle">Unified contact database with search and filters</p>
      </div>

      <div className="contacts-filters">
        <select value={typeFilter} onChange={handleTypeChange}>
          <option value="all">All Types</option>
          <option value="subscriber">Subscriber</option>
          <option value="prospect">Prospect</option>
          <option value="customer">Customer</option>
          <option value="churned">Churned</option>
        </select>
        <select value={layerFilter} onChange={handleLayerChange}>
          <option value="all">All Layers</option>
          <option value="relationship">Relationship</option>
          <option value="operator">Operator</option>
          <option value="bdr">BDR</option>
          <option value="newsletter">Newsletter</option>
        </select>
        <input
          type="text"
          placeholder="Search contacts..."
          value={search}
          onChange={handleSearchInput}
        />
      </div>

      <div className="contacts-count">{total} contact{total !== 1 ? "s" : ""}</div>

      {loading && <div className="loading">Loading contacts...</div>}
      {error && <div className="error-state">{error}</div>}

      {!loading && !error && contacts.length === 0 && (
        <div className="empty-state">No contacts found</div>
      )}

      {!loading && !error && contacts.length > 0 && (
        <table className="data-table">
          <thead>
            <tr>
              <th>Name</th>
              <th>Company</th>
              <th>Type</th>
              <th>Tier</th>
              <th>Layer</th>
              <th>Score</th>
              <th>Last Activity</th>
            </tr>
          </thead>
          <tbody>
            {contacts.map(c => (
              <tr key={c.id}>
                <td>
                  <span
                    className="contact-link"
                    onClick={() => { window.location.hash = "#contact/" + c.id; }}
                  >
                    {c.name || "Unknown"}
                  </span>
                </td>
                <td>{c.company || ""}</td>
                <td><span className="badge badge-pending" style={{ textTransform: "capitalize" }}>{c.type || ""}</span></td>
                <td>{c.tier && <span className={"tier-badge " + (tierColors[c.tier] || "tier-C")}>{c.tier}</span>}</td>
                <td style={{ textTransform: "capitalize" }}>{c.layer || ""}</td>
                <td style={{ fontFamily: "var(--font-mono)", fontSize: 13 }}>{c.total_score != null ? c.total_score + "/100" : ""}</td>
                <td style={{ fontSize: 12, color: "var(--text-muted)" }}>{c.last_activity ? relativeTime(c.last_activity) : ""}</td>
              </tr>
            ))}
          </tbody>
        </table>
      )}

      {!loading && totalPages > 1 && (
        <div className="pagination">
          <button className="filter-tab" disabled={page <= 1} onClick={() => setPage(p => Math.max(1, p - 1))}>Prev</button>
          <span className="pagination-info">Page {page} of {totalPages}</span>
          <button className="filter-tab" disabled={page >= totalPages} onClick={() => setPage(p => Math.min(totalPages, p + 1))}>Next</button>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// FreestyleCreatorPage — natural language content generation workspace
// ---------------------------------------------------------------------------

function FreestyleCreatorPage() {
  const [prompt, setPrompt] = React.useState("");
  const [format, setFormat] = React.useState("auto");
  const [tone, setTone] = React.useState("auto");
  const [imageFile, setImageFile] = React.useState(null);
  const [loading, setLoading] = React.useState(false);
  const [result, setResult] = React.useState(null);
  const [error, setError] = React.useState(null);
  const [recent, setRecent] = React.useState([]);
  const [scheduleStatus, setScheduleStatus] = React.useState({});

  React.useEffect(() => {
    salesApiFetch("/api/create/recent")
      .then(r => r.ok ? r.json() : { items: [] })
      .then(data => setRecent(data.items || []))
      .catch(() => {});
  }, []);

  function handleImageChange(e) {
    const file = e.target.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = (ev) => setImageFile(ev.target.result);
    reader.readAsDataURL(file);
  }

  async function handleGenerate() {
    if (!prompt.trim()) return;
    setLoading(true);
    setResult(null);
    setError(null);
    try {
      const body = { prompt, format: format !== "auto" ? format : undefined, tone: tone !== "auto" ? tone : undefined };
      if (imageFile) body.image_data = imageFile;
      const resp = await salesApiFetch("/api/create", {
        method: "POST",
        body: JSON.stringify(body)
      });
      if (!resp.ok) throw new Error(await resp.text());
      setResult(await resp.json());
    } catch (e) {
      setError(e.message);
    } finally {
      setLoading(false);
    }
  }

  async function handleSchedule(variantText, idx) {
    try {
      const resp = await salesApiFetch("/api/create/schedule", {
        method: "POST",
        body: JSON.stringify({ content: variantText, platform: result?.content_type || "linkedin_post" })
      });
      if (!resp.ok) throw new Error();
      setScheduleStatus(s => ({ ...s, [idx]: "scheduled" }));
    } catch {
      setScheduleStatus(s => ({ ...s, [idx]: "error" }));
    }
  }

  function handleCopy(text) {
    navigator.clipboard?.writeText(text).catch(() => {});
  }

  const FORMAT_OPTIONS = [
    { value: "auto", label: "Auto-detect" },
    { value: "linkedin_post", label: "LinkedIn Post" },
    { value: "linkedin_ad", label: "LinkedIn Ad" },
    { value: "substack_note", label: "Substack Note" },
    { value: "email_draft", label: "Email Draft" },
    { value: "blog_outline", label: "Blog Outline" },
    { value: "thread", label: "Thread" },
  ];

  const TONE_OPTIONS = [
    { value: "auto", label: "Auto-detect" },
    { value: "analytical", label: "Analytical" },
    { value: "provocative", label: "Provocative" },
    { value: "conversational", label: "Conversational" },
    { value: "urgent", label: "Urgent" },
  ];

  const variants = result ? [result.primary, ...(result.variations || [])].filter(Boolean) : [];
  const variantLabels = ["Variant A (recommended)", "Variant B", "Variant C"];

  return (
    <div style={{ maxWidth: 780, margin: "0 auto" }}>
      <div className="section-header" style={{ marginBottom: 24 }}>
        <h2 style={{ margin: 0 }}>Freestyle Creator</h2>
        <span style={{ color: "#6B7A8D", fontSize: 13 }}>Natural language → LinkedIn posts, ads, emails, Substack notes</span>
      </div>

      {/* Input card */}
      <div className="card" style={{ padding: 24, marginBottom: 20 }}>
        <textarea
          value={prompt}
          onChange={e => setPrompt(e.target.value)}
          placeholder={"e.g. \"Write a LinkedIn post about CMS's new prior auth transparency rule\" or \"Create 3 ad variants for our payer intelligence audit offer\""}
          style={{ width: "100%", minHeight: 80, background: "#1a1f2e", border: "1px solid #2a3040", borderRadius: 6, color: "#e2e8f0", padding: 12, fontSize: 14, resize: "vertical", boxSizing: "border-box" }}
          onKeyDown={e => { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) handleGenerate(); }}
        />

        <div style={{ display: "flex", alignItems: "center", gap: 12, marginTop: 12, flexWrap: "wrap" }}>
          <label style={{ cursor: "pointer", color: imageFile ? "#4CAF7D" : "#6B7A8D", fontSize: 13, display: "flex", alignItems: "center", gap: 6 }}>
            <input type="file" accept="image/*" onChange={handleImageChange} style={{ display: "none" }} />
            📎 {imageFile ? "Image attached" : "Attach image"}
            {imageFile && <span onClick={(e) => { e.preventDefault(); setImageFile(null); }} style={{ color: "#e74c3c", cursor: "pointer" }}>×</span>}
          </label>

          <select value={format} onChange={e => setFormat(e.target.value)}
            style={{ background: "#1a1f2e", border: "1px solid #2a3040", color: "#e2e8f0", borderRadius: 4, padding: "6px 10px", fontSize: 13 }}>
            {FORMAT_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
          </select>

          <select value={tone} onChange={e => setTone(e.target.value)}
            style={{ background: "#1a1f2e", border: "1px solid #2a3040", color: "#e2e8f0", borderRadius: 4, padding: "6px 10px", fontSize: 13 }}>
            {TONE_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
          </select>

          <div style={{ marginLeft: "auto" }}>
            <button className="btn" onClick={handleGenerate} disabled={loading || !prompt.trim()}
              style={{ opacity: loading || !prompt.trim() ? 0.6 : 1 }}>
              {loading ? "Generating..." : "Generate →"}
            </button>
          </div>
        </div>

        {error && <div style={{ marginTop: 12, color: "#e74c3c", fontSize: 13 }}>{error}</div>}
      </div>

      {/* Output variants */}
      {result && (
        <div style={{ marginBottom: 20 }}>
          <div style={{ fontSize: 11, color: "#6B7A8D", marginBottom: 10, display: "flex", gap: 16 }}>
            {result.pillar_tag && <span>Pillar: <strong style={{ color: "#4CAF7D" }}>{result.pillar_tag}</strong></span>}
            {result.content_type && <span>Format: <strong style={{ color: "#2D7DD2" }}>{result.content_type}</strong></span>}
            {result.estimated_cost_usd != null && <span>Cost: <strong>${result.estimated_cost_usd.toFixed(3)}</strong></span>}
            {result.suggested_schedule && <span>Schedule: <strong>{result.suggested_schedule}</strong></span>}
          </div>

          {variants.map((text, idx) => (
            <div key={idx} className="card" style={{ padding: 16, marginBottom: 12, borderLeft: idx === 0 ? "3px solid #4CAF7D" : "3px solid #2a3040" }}>
              <div style={{ fontSize: 12, color: idx === 0 ? "#4CAF7D" : "#6B7A8D", marginBottom: 8, fontWeight: 600 }}>
                {variantLabels[idx] || `Variant ${idx + 1}`}
              </div>
              <pre style={{ margin: 0, whiteSpace: "pre-wrap", fontFamily: "inherit", fontSize: 14, color: "#e2e8f0", lineHeight: 1.6 }}>{text}</pre>
              <div style={{ display: "flex", gap: 8, marginTop: 12 }}>
                <button className="btn" style={{ fontSize: 12, padding: "4px 12px", background: "#2a3040" }}
                  onClick={() => handleCopy(text)}>Copy</button>
                {idx === 0 && (
                  <button className="btn" style={{ fontSize: 12, padding: "4px 12px" }}
                    onClick={() => handleSchedule(text, idx)}
                    disabled={scheduleStatus[idx] === "scheduled"}>
                    {scheduleStatus[idx] === "scheduled" ? "Scheduled ✓" : scheduleStatus[idx] === "error" ? "Error" : "Schedule →"}
                  </button>
                )}
              </div>
            </div>
          ))}

          {result.subject_lines?.length > 0 && (
            <div className="card" style={{ padding: 16, marginBottom: 12 }}>
              <div style={{ fontSize: 12, color: "#6B7A8D", marginBottom: 8 }}>Subject Lines / Headlines</div>
              {result.subject_lines.map((s, i) => (
                <div key={i} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "6px 0", borderBottom: i < result.subject_lines.length - 1 ? "1px solid #2a3040" : "none" }}>
                  <span style={{ fontSize: 14, color: "#e2e8f0" }}>{s}</span>
                  <button className="btn" style={{ fontSize: 11, padding: "2px 8px", background: "#2a3040" }} onClick={() => handleCopy(s)}>Copy</button>
                </div>
              ))}
            </div>
          )}
        </div>
      )}

      {/* Recent Creations */}
      {recent.length > 0 && (
        <div>
          <div style={{ fontSize: 11, color: "#6B7A8D", marginBottom: 10, textTransform: "uppercase", letterSpacing: 1 }}>Recent Creations</div>
          {recent.slice(0, 5).map((item, i) => (
            <div key={i} className="card" style={{ padding: "10px 16px", marginBottom: 8, display: "flex", justifyContent: "space-between", alignItems: "center", cursor: "pointer" }}
              onClick={() => setPrompt(item.prompt || "")}>
              <div>
                <span style={{ fontSize: 13, color: "#e2e8f0" }}>{(item.prompt || "").slice(0, 60)}{(item.prompt || "").length > 60 ? "..." : ""}</span>
                <span style={{ fontSize: 11, color: "#6B7A8D", marginLeft: 12 }}>{item.content_type}</span>
              </div>
              <span style={{ fontSize: 11, color: "#6B7A8D" }}>{relativeTime(item.created_at)}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// SegmentsPage — predefined smart segments with filtered contact list
// ---------------------------------------------------------------------------

const SEGMENT_DEFS = [
  { key: "subscribers", label: "Subscribers", desc: "Newsletter subscribers from Ghost" },
  { key: "hot_leads", label: "Hot Leads", desc: "Fit score 80+ - high priority" },
  { key: "s_tier", label: "S-Tier", desc: "Top-tier prospects for relationship building" },
  { key: "active_sequences", label: "Active Sequences", desc: "Currently receiving outreach emails" },
  { key: "replied", label: "Replied", desc: "Contacts who have replied to outreach" },
  { key: "meeting_booked", label: "Meeting Booked", desc: "Meetings scheduled or completed" },
  { key: "paused", label: "Paused", desc: "Sequences on hold" },
];

function SegmentsPage() {
  const [activeSeg, setActiveSeg] = React.useState(null);
  const [segContacts, setSegContacts] = React.useState([]);
  const [segCount, setSegCount] = React.useState(0);
  const [segLoading, setSegLoading] = React.useState(false);
  const [counts, setCounts] = React.useState({});
  const [countsLoading, setCountsLoading] = React.useState(true);

  React.useEffect(() => {
    // Fetch counts for all segments in parallel
    setCountsLoading(true);
    Promise.all(
      SEGMENT_DEFS.map(seg =>
        salesApiFetch("/api/contacts/segments/" + seg.key)
          .then(r => r.ok ? r.json() : { count: 0 })
          .then(data => ({ key: seg.key, count: data.count || 0 }))
          .catch(() => ({ key: seg.key, count: 0 }))
      )
    ).then(results => {
      const countMap = {};
      results.forEach(r => { countMap[r.key] = r.count; });
      setCounts(countMap);
      setCountsLoading(false);
    });
  }, []);

  function loadSegment(segKey) {
    if (activeSeg === segKey) {
      setActiveSeg(null);
      setSegContacts([]);
      return;
    }
    setActiveSeg(segKey);
    setSegLoading(true);
    salesApiFetch("/api/contacts/segments/" + segKey)
      .then(r => {
        if (!r.ok) throw new Error("Failed to load segment");
        return r.json();
      })
      .then(data => {
        setSegContacts(data.contacts || []);
        setSegCount(data.count || 0);
        setSegLoading(false);
      })
      .catch(() => {
        setSegContacts([]);
        setSegLoading(false);
      });
  }

  const tierColors = { S: "tier-S", A: "tier-A", B: "tier-B", C: "tier-C" };

  return (
    <div className="page">
      <div className="page-header">
        <h2>Segments</h2>
        <p className="subtitle">Predefined smart segments for quick access to contact groups</p>
      </div>

      <div className="segments-grid">
        {SEGMENT_DEFS.map(seg => (
          <div
            key={seg.key}
            className={"segment-card" + (activeSeg === seg.key ? " active" : "")}
            onClick={() => loadSegment(seg.key)}
          >
            <div className="segment-name">
              {seg.label}
              <span className="segment-count">
                {countsLoading ? "..." : (counts[seg.key] || 0)}
              </span>
            </div>
            <div className="segment-desc">{seg.desc}</div>
          </div>
        ))}
      </div>

      {activeSeg && (
        <div>
          <div style={{ fontWeight: 600, fontSize: 14, marginBottom: 12 }}>
            {SEGMENT_DEFS.find(s => s.key === activeSeg)?.label || activeSeg}
            <span className="text-muted" style={{ fontWeight: 400, marginLeft: 8 }}>({segCount} contacts)</span>
          </div>

          {segLoading && <div className="loading">Loading segment...</div>}

          {!segLoading && segContacts.length === 0 && (
            <div className="empty-state">No contacts in this segment</div>
          )}

          {!segLoading && segContacts.length > 0 && (
            <table className="data-table">
              <thead>
                <tr>
                  <th>Name</th>
                  <th>Company</th>
                  <th>Type</th>
                  <th>Tier</th>
                  <th>Score</th>
                </tr>
              </thead>
              <tbody>
                {segContacts.map(c => (
                  <tr key={c.id}>
                    <td>
                      <span
                        className="contact-link"
                        onClick={() => { window.location.hash = "#contact/" + c.id; }}
                      >
                        {c.name || "Unknown"}
                      </span>
                    </td>
                    <td>{c.company || ""}</td>
                    <td style={{ textTransform: "capitalize" }}>{c.type || ""}</td>
                    <td>{c.tier && <span className={"tier-badge " + (tierColors[c.tier] || "tier-C")}>{c.tier}</span>}</td>
                    <td style={{ fontFamily: "var(--font-mono)", fontSize: 13 }}>{c.total_score != null ? c.total_score + "/100" : ""}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      )}
    </div>
  );
}
