/* Lead Card — role-aware, read-only states, inline edit, lifecycle actions. */
const { useState: useStateLC, useEffect: useEffectLC } = React;

// Lead current time — derived local wall-clock from Country/City (Contact Info, sidebar-and-edit-rules
// §Секція 1). Separate from the global Server Time in the topbar. Ticks live; falls back to "—" for an
// unknown timezone. Reuses LEAD_TZ / leadTzOffset from LeadsList (shared top-level binding).
function LeadClock({ lead }) {
  const off = (typeof leadTzOffset === 'function') ? leadTzOffset(lead) : null;
  const [, tick] = useStateLC(0);
  useEffectLC(() => { const id = setInterval(() => tick(n => n + 1), 1000); return () => clearInterval(id); }, []);
  if (off == null) return <span style={{ color: 'var(--text-3)' }} title="Timezone unknown — set Country/City">—</span>;
  const now = new Date();
  const d = new Date(now.getTime() + now.getTimezoneOffset() * 60000 + off * 3600000);
  const p2 = (n) => String(n).padStart(2, '0');
  const H = Math.floor(Math.abs(off)), M = Math.round((Math.abs(off) - H) * 60);
  const tz = 'UTC' + (off >= 0 ? '+' : '−') + H + (M ? ':' + p2(M) : '');
  return <span><span className="mn-mono" style={{ color: 'var(--text-1)' }}>{p2(d.getHours())}:{p2(d.getMinutes())}</span> <span className="mn-muted" style={{ fontSize: 11 }}>· {tz}</span></span>;
}

// Lead Details (sidebar §Секція 3) — metadata + SLA. Source Type/Name live here (not Contact),
// plus Lead Age, Last Activity, current_owner_since and overdue_days/overdue_count (MUST-HAVE SLA
// per lead-sla-and-overdue). Fields absent from seed data are derived from createdAt / nextStep /
// updatedAt (labelled proxies) so the SLA state is always visible on the card.
function LeadDetailsCard({ lead, converted, linkedClient }) {
  const now = window.MonolitData.NOW;
  const fmtDate = (d) => new Date(d).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' });
  const ageDays = Math.max(0, Math.floor((now - new Date(lead.createdAt)) / 86400000));
  const due = lead.nextStep ? new Date(lead.nextStep.due) : null;
  const overdue = lead.status !== 'disqualified' && due && due < now;
  const overdueDays = overdue ? Math.floor((now - due) / 86400000) : 0;
  const overdueCount = lead.overdueCount != null ? lead.overdueCount : (overdue ? Math.max(1, Math.ceil(overdueDays / 7)) : 0);
  const ownerSince = lead.owner ? (lead.ownerSince || lead.createdAt) : null;
  const lastActivity = lead.lastActivity || lead.updatedAt;
  return (
    <Card title="Lead details" eyebrow="Metadata & SLA" padding="md">
      <dl className="mn-kv">
        <dt>Public ID</dt><dd className="mono">{window.MonolitData.publicId(lead.id)}</dd>
        <dt>Source type</dt><dd><span className="mn-mono" style={{ color: 'var(--text-2)', fontSize: 12 }}>{lead.source.type}</span></dd>
        <dt>Source name</dt><dd>{lead.source.name}</dd>
        <dt>Created</dt><dd>{fmtDate(lead.createdAt)}</dd>
        <dt>Lead age</dt><dd>{ageDays} day{ageDays === 1 ? '' : 's'}</dd>
        <dt>Last activity</dt><dd>{fmtDate(lastActivity)}</dd>
        <dt>Activities</dt><dd>{lead.activities}</dd>
        <dt>Owner since</dt><dd>{ownerSince ? fmtDate(ownerSince) : <span style={{ color: 'var(--text-3)' }}>—</span>}</dd>
        <dt>Overdue</dt><dd>
          <span className="mn-row" style={{ gap: 6, flexWrap: 'wrap' }}>
            {overdue
              ? <span className="mn-chip mn-chip--problem" style={{ gap: 4 }}><Icon name="alarm-clock" size="xs" stroke="2" />{overdueDays}d overdue</span>
              : <span style={{ color: 'var(--success-main)', font: 'var(--font-weight-medium) 12px/16px var(--font-sans)' }}>On track</span>}
            {overdueCount > 0 ? <span className="mn-muted" style={{ fontSize: 11 }}>· entered {overdueCount}×</span> : null}
          </span>
        </dd>
        {converted && linkedClient ? <React.Fragment><dt>Converted to</dt><dd className="mono">{linkedClient.id}</dd></React.Fragment> : null}
        <dt>Tenant TZ</dt><dd className="mono">UTC+3</dd>
      </dl>
    </Card>
  );
}

// tel:/mailto: are external protocol links. The preview sandbox blocks all non-localhost navigation
// (and it can't be feature-detected — not an iframe here, no webdriver flag), so the prototype
// SIMULATES the dial/compose with a toast instead of navigating. Flip to false for real tel:/mailto:
// links in a production build (a real browser hands off to the dialer / mail client).
const SIMULATE_CHANNELS = true;

const LEAD_TRANSITIONS = {
  new: ['in_progress', 'qualified', 'disqualified'],
  in_progress: ['qualified', 'disqualified'],
  qualified: ['in_progress', 'disqualified'],
  disqualified: ['in_progress'],
  converted: [],
  archived: [],
};

function LeadCard({ lead, activity, role, initialTab, clients, onBack, onConvert, onAssign, onUnassign, onLifecycle, onUpdate, onRestore, onAddActivity, onEditDetails, onNewDeal, onOpenClient, onOpenLead, duplicates, onToast }) {
  const RB = window.MonolitRBAC;
  // Deep link can open the card at a specific tab (AC-LC-008); fall back to Overview.
  const [tab, setTab] = useStateLC(['overview', 'activity', 'comments', 'deals', 'files', 'audit'].includes(initialTab) ? initialTab : 'overview');
  const status = lead.status;

  const converted = status === 'converted';
  const archived = !!lead.is_archived; // separate layer from status (lead-lifecycle §2.1)
  const isViewer = role === 'Viewer';
  const readOnly = converted || archived || isViewer;
  const canConvert = status === 'qualified' && !readOnly && RB.can(role, 'leads.convert');
  const canSeeAudit = RB.can(role, 'audit.view');
  // Disqualified → reopen is Admin / Ops Admin / Manager only (lead-lifecycle §2.2).
  const allowedTransitions = (LEAD_TRANSITIONS[status] || []).filter(() => status !== 'disqualified' || ['Admin', 'Ops Admin', 'Manager'].includes(role));
  // Resolve the converted client from the live store (App clients) by convertedTo first, then fall back.
  const linkedClient = converted ? ((clients || []).find(c => c.id === lead.convertedTo) || (clients || []).find(c => c.originalLeadId === lead.id) || window.MonolitData.clients.find(c => c.originalLeadId === lead.id)) : null;

  // Lifecycle / ownership actions live in the sidebar Actions Zone only (layout-and-tabs spec).
  // The header keeps two canonical surfaces: Quick Actions Bar (Call/Email/Add/Schedule/Convert)
  // and the standalone Edit Details control — no third "Actions ▾" dropdown, no Permanent Delete (POST-MVP).
  const canEditDetails = !readOnly && RB.can(role, 'leads.update');

  // Reachable-channel actions. tel:/mailto: are external protocol handlers — an anchor click hands
  // off to the OS (dialer / mail client) without navigating the page, so it works inside the preview too.
  const reach = (href) => { if (SIMULATE_CHANNELS) return; const a = document.createElement('a'); a.href = href; a.rel = 'noopener'; a.style.display = 'none'; document.body.appendChild(a); a.click(); a.remove(); };
  const telHref = lead.phone ? 'tel:' + lead.phone.replace(/[^\d+]/g, '') : null;
  const mailHref = lead.email ? 'mailto:' + lead.email : null;
  // Quick Action Call/Email (layout-and-tabs §1.1): initiate the call/email AND open the activity
  // composer so the rep logs the outcome (spec: "ініціює дзвінок … автоматично створює Activity").
  const startCall = () => { if (telHref) { reach(telHref); onToast('Calling ' + lead.phone + '…'); } else { onToast('No phone number on file'); } onAddActivity('call'); };
  const startEmail = () => { if (mailHref) { reach(mailHref); onToast('Composing email to ' + lead.email + '…'); } else { onToast('No email on file'); } onAddActivity('email'); };

  const tabs = [
    { id: 'overview', label: 'Overview' },
    { id: 'activity', label: 'Activity', count: activity.length },
    { id: 'comments', label: 'Comments', count: 3 },
    { id: 'deals',    label: 'Deals',    count: (window.MonolitData.deals || []).filter(d => d.leadId === lead.id && dealIsActive(d)).length },
    { id: 'files',    label: 'Files',    count: 4 },
    ...(canSeeAudit ? [{ id: 'audit', label: 'Audit' }] : []),
  ];

  return (
    <React.Fragment>
      <div className="mn-page-h" style={{ paddingBottom: 0 }}>
        <button className="mn-drawer-back" onClick={onBack} type="button"><Icon name="arrow-left" size="xs" /> Back to leads</button>
        <div className="mn-page-actions">
          <Button variant="quiet" size="md" icon="copy" title="Copy link" onClick={() => { const url = window.location.origin + window.location.pathname + '?screen=lead-card&id=' + lead.id; try { if (navigator.clipboard) navigator.clipboard.writeText(url); } catch (e) {} onToast('Link copied to clipboard'); }}>Copy link</Button>
          {canEditDetails ? <Button variant="ghost" size="md" icon="pencil" title="Edit fields not editable inline" onClick={onEditDetails}>Edit details</Button> : null}
          {converted ? <Button variant="secondary" size="md" icon="arrow-up-right" onClick={() => onOpenClient(linkedClient ? linkedClient.id : (lead.convertedTo || 'mon-c-00064'))}>Go to client</Button> :
           archived && RB.can(role, 'leads.archive') ? <Button variant="secondary" size="md" icon="archive-restore" onClick={() => onRestore && onRestore()}>Restore</Button> : null}
        </div>
      </div>

      <div className="mn-leadcard">
        <div className="mn-leadcard-l">
          <header className="mn-lead-header">
            <div className="mn-lead-id-row">
              <span className="mn-lead-id">{window.MonolitData.publicId(lead.id)}</span>
              <span className="mn-mono mn-muted" style={{ fontSize: 12 }}>·</span>
              <span className="mn-mono mn-muted" style={{ fontSize: 12 }}>created {new Date(lead.createdAt).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' })}</span>
              {window.MonolitData.isProblemLead(lead) ? <span className="mn-chip mn-chip--problem" style={{ marginLeft: 6 }}><Icon name="alert-triangle" size="xs" stroke="2" />Problem lead</span> : null}
              {archived ? <span className="mn-chip mn-chip--sys-archived" style={{ marginLeft: 6 }}><Icon name="archive" size="xs" stroke="2" />Archived</span> : null}
            </div>
            <div className="mn-lead-title-row">
              <ScoreRing value={lead.score} size={56} />
              <div style={{ flex: 1 }}>
                <h1 className="mn-lead-title">{lead.name}</h1>
                <div className="mn-lead-co">{lead.company} · {lead.city}, {lead.country}</div>
              </div>
              {!readOnly && RB.can(role, 'leads.update') ? (
                <Dropdown align="right" width={220} trigger={({ toggle }) => <span onClick={toggle}><StatusBadge status={status} size="lg" onClick={() => {}} /></span>}>
                  {({ close }) => (
                    <React.Fragment>
                      <div className="mn-dd-h">Change status</div>
                      <div className="mn-dd-list">
                        {allowedTransitions.map(s => (
                          <button key={s} className="mn-dd-item" onClick={() => { close(); if (s === 'disqualified') onLifecycle('disqualify'); else { onUpdate(lead.id, { status: s }); onToast('Status → ' + (STATUS_CFG[s] ? STATUS_CFG[s].label : s)); } }}>
                            <StatusBadge status={s} /><span style={{ flex: 1 }} />
                          </button>
                        ))}
                        {!allowedTransitions.length ? <div style={{ padding: 12, color: 'var(--text-3)', font: 'var(--font-weight-medium) 12px/16px var(--font-sans)' }}>No transitions available.</div> : null}
                      </div>
                    </React.Fragment>
                  )}
                </Dropdown>
              ) : <StatusBadge status={status} size="lg" />}
            </div>
            <div className="mn-lead-meta-row">
              <div className="mn-row">
                <span className="mn-eyebrow" style={{ margin: 0 }}>Next step</span>
                <NextStepCell nextStep={lead.nextStep} now={window.MonolitData.NOW} />
              </div>
              <div className="mn-row" style={{ marginLeft: 'auto' }}>
                <span className="mn-eyebrow" style={{ margin: 0 }}>Owner</span>
                {!readOnly && RB.can(role, 'leads.assign') ? (
                  <Dropdown align="right" width={240} trigger={({ toggle }) => (
                    <span onClick={toggle} style={{ cursor: 'pointer' }} title="Assign / reassign owner">
                      {lead.owner
                        ? <span className="mn-row" style={{ gap: 6 }}><Avatar user={lead.owner} size={22} /><span style={{ font: 'var(--font-weight-medium) 13px/16px var(--font-sans)' }}>{lead.owner.name}</span><Icon name="chevron-down" size="xs" color="text-3" /></span>
                        : <span className="mn-chip mn-chip--noowner"><Icon name="user-x" size="xs" stroke="2" />No owner<Icon name="chevron-down" size="xs" /></span>}
                    </span>
                  )}>
                    {({ close }) => (
                      <React.Fragment>
                        <div className="mn-dd-h">{lead.owner ? 'Reassign owner' : 'Assign owner'}</div>
                        <div className="mn-dd-list">
                          {window.MonolitData.owners.filter(o => role !== 'Manager' || RB.TEAM_IDS.includes(o.id)).map(o => (
                            <button key={o.id} className="mn-dd-item" style={{ alignItems: 'center' }} onClick={() => { close(); onUpdate(lead.id, { owner: o }); onToast('Owner → ' + o.name); }}>
                              <Avatar user={o} size={20} /><span className="mn-dd-item-tt">{o.name}</span>{lead.owner && lead.owner.id === o.id ? <Icon name="check" size="sm" color="primary" /> : null}
                            </button>
                          ))}
                        </div>
                        <div style={{ font: 'var(--font-weight-medium) 11px/15px var(--font-sans)', color: 'var(--text-3)', padding: '6px 12px 2px' }}>Removing an owner uses “Unassign owner” in Actions (needs a reason).</div>
                      </React.Fragment>
                    )}
                  </Dropdown>
                ) : (
                  lead.owner ? <span className="mn-row" style={{ gap: 6 }}><Avatar user={lead.owner} size={22} /><span style={{ font: 'var(--font-weight-medium) 13px/16px var(--font-sans)' }}>{lead.owner.name}</span></span>
                    : <span className="mn-chip mn-chip--noowner"><Icon name="user-x" size="xs" stroke="2" />No owner</span>
                )}
              </div>
            </div>
            <div className="mn-lead-quick">
              <Button variant="ghost" size="md" icon="phone" disabled={readOnly || !RB.can(role, 'activities.create')} onClick={startCall}>Call</Button>
              <Button variant="ghost" size="md" icon="mail" disabled={readOnly || !RB.can(role, 'activities.create')} onClick={startEmail}>Email</Button>
              <Button variant="ghost" size="md" icon="plus-square" disabled={readOnly || !RB.can(role, 'activities.create')} onClick={() => onAddActivity()}>Add activity</Button>
              <Button variant="ghost" size="md" icon="calendar-plus" disabled={readOnly || !RB.can(role, 'activities.create')} onClick={() => onAddActivity('meeting')}>Schedule</Button>
              {!converted && !archived && RB.can(role, 'leads.convert') ? <Button variant="secondary" size="md" icon="check-check" disabled={!canConvert} title={canConvert ? 'Convert to client' : 'Available once the lead is Qualified'} onClick={onConvert}>Convert</Button> : null}
            </div>
          </header>

          {converted ? (
            <div className="mn-robanner" style={{ marginTop: 12, background: 'var(--success-low)', color: 'var(--success-low-on)', borderColor: 'color-mix(in srgb, var(--success-main) 30%, transparent)' }}>
              <Icon name="check-check" size="sm" />Converted {linkedClient ? 'to ' + linkedClient.name : 'to Client'} on {new Date(lead.updatedAt).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' })} — this lead is read-only.
              <button type="button" className="mn-login-link" style={{ marginLeft: 'auto' }} onClick={() => onOpenClient(linkedClient ? linkedClient.id : (lead.convertedTo || 'mon-c-00064'))}>Open client →</button>
            </div>
          ) : archived ? (
            <div className="mn-robanner" style={{ marginTop: 12 }}><Icon name="archive" size="sm" />This lead is archived — read-only. Restore to resume work.</div>
          ) : isViewer ? (
            <div className="mn-robanner" style={{ marginTop: 12 }}><Icon name="eye" size="sm" />Read-only access — your role is Viewer.</div>
          ) : null}

          {duplicates && duplicates.length && !converted ? (
            <div className="mn-robanner" style={{ marginTop: 12, background: 'var(--warning-low)', color: 'var(--warning-low-on)', borderColor: 'color-mix(in srgb, var(--warning-main) 30%, transparent)' }}>
              <Icon name="copy" size="sm" />Possible duplicate — {duplicates.length} other lead{duplicates.length > 1 ? 's' : ''} share this email or phone.
              {onOpenLead ? <button type="button" className="mn-login-link" style={{ marginLeft: 'auto' }} onClick={() => onOpenLead(duplicates[0].id)}>Open match →</button> : null}
            </div>
          ) : null}

          <Tabs items={tabs} value={tab} onChange={setTab} />

          {tab === 'overview' ? <OverviewTab lead={lead} activity={activity} canSeeAudit={canSeeAudit} onGoTab={setTab} /> :
           tab === 'activity' ? <ActivityTab activity={activity} readOnly={readOnly} canCreate={RB.can(role, 'activities.create')} onAddActivity={onAddActivity} /> :
           tab === 'comments' ? <CommentsTab readOnly={readOnly} onToast={onToast} /> :
           tab === 'deals' ?    <DealsTab lead={lead} readOnly={readOnly} canCreate={RB.can(role, 'deals.create')} onNewDeal={onNewDeal} /> :
           tab === 'files' ?    <FilesTab readOnly={readOnly} role={role} onToast={onToast} /> :
           <AuditTab activity={activity} />}
        </div>

        <aside className="mn-leadcard-r">
          <Card title="Contact" eyebrow="Reachable channels" padding="md">
            <dl className="mn-kv">
              <dt>Email</dt><dd>{mailHref ? <a href={mailHref} title="Compose email" onClick={(e) => { if (SIMULATE_CHANNELS) { e.preventDefault(); onToast('Opening email to ' + lead.email + '…'); } }} style={{ color: 'var(--secondary-main)', textDecoration: 'none' }}>{lead.email}</a> : <span style={{ color: 'var(--text-3)' }}>—</span>}</dd>
              <dt>Phone</dt><dd>{telHref ? <a href={telHref} title="Call" onClick={(e) => { if (SIMULATE_CHANNELS) { e.preventDefault(); onToast('Calling ' + lead.phone + '…'); } }} className="mn-mono" style={{ color: 'var(--text-1)', textDecoration: 'none' }}>{lead.phone}</a> : <span style={{ color: 'var(--text-3)' }}>—</span>}</dd>
              <dt>Location</dt><dd>{lead.city}, {lead.country}</dd>
              <dt>Lead current time</dt><dd><LeadClock lead={lead} /></dd>
            </dl>
          </Card>

          <BantCard lead={lead} role={role} readOnly={readOnly} onUpdate={onUpdate} onToast={onToast} />

          <TagsCard lead={lead} role={role} readOnly={readOnly} onUpdate={onUpdate} />

          <LeadDetailsCard lead={lead} converted={converted} linkedClient={linkedClient} />

          {!isViewer && !converted ? (
            <Card title="Actions" eyebrow="Ownership & lifecycle" padding="md">
              <div className="mn-stack">
                {canConvert ? <Button variant="secondary" size="md" icon="check-check" fullWidth onClick={onConvert}>Convert lead</Button> : null}
                {RB.can(role, 'leads.unassign') && lead.owner && !archived ? <Button variant="ghost" size="md" icon="user-minus" fullWidth onClick={onUnassign}>Unassign owner</Button> : null}
                {RB.can(role, 'leads.archive') ? (archived
                  ? <Button variant="secondary" size="md" icon="archive-restore" fullWidth onClick={() => onRestore && onRestore()}>Restore lead</Button>
                  : <Button variant="ghost" size="md" icon="archive" fullWidth onClick={() => onLifecycle('archive')}>Archive lead</Button>) : null}
              </div>
              {role === 'Sales Rep' || role === 'Manager' ? <div style={{ font: 'var(--font-weight-medium) 11px/15px var(--font-sans)', color: 'var(--text-3)', marginTop: 8 }}>Unassign owner is Admin / Ops Admin only.</div> : null}
            </Card>
          ) : null}
        </aside>
      </div>
    </React.Fragment>
  );
}

/* BANT scoring — lead-scoring-bant.md (weighted_bant_v1). Budget 25 · Authority 25 · Need 20 ·
   Timeline 20 · Engagement 0–10 (= 100). Budget/Authority/Need/Timeline use Yes / No / Unknown —
   Unknown means "not evaluated": it is excluded from the sum and NEVER subtracts. Engagement is a
   4-level scale (No response 0 / Responded 5 / Active communication 8 / Initiates 10) or unevaluated.
   Score = sum of points over *known* criteria; with zero known criteria the Score is `null` (not 0).
   Score Confidence reflects how many of the 5 criteria are known.
   `lead.bant` = { B,A,N,T: 'yes'|'no'|'unknown', E: 'none'|'responded'|'active'|'initiates'|'unknown' }. */
const BANT4 = [['B', 'Budget', 25], ['A', 'Authority', 25], ['N', 'Need', 20], ['T', 'Timeline', 20]];
const BANT_TRI = [['no', 'No'], ['unknown', 'Unknown'], ['yes', 'Yes']];
const ENGAGE_LEVELS = [
  { value: 'none', label: 'No response', points: 0 },
  { value: 'responded', label: 'Responded', points: 5 },
  { value: 'active', label: 'Active communication', points: 8 },
  { value: 'initiates', label: 'Initiates', points: 10 },
];
function engagePoints(v) { const e = ENGAGE_LEVELS.find(x => x.value === v); return e ? e.points : null; }
function bantKnownCount(b) {
  let n = 0;
  BANT4.forEach(([L]) => { if (b[L] === 'yes' || b[L] === 'no') n++; });
  if (b.E && b.E !== 'unknown') n++;
  return n;
}
// Score = sum of points over known criteria. Unknown/unevaluated never subtract. All-unknown → null.
function bantScore(b) {
  if (bantKnownCount(b) === 0) return null;
  let s = 0;
  BANT4.forEach(([L, , cap]) => { if (b[L] === 'yes') s += cap; });
  const ep = engagePoints(b.E);
  if (ep != null) s += ep;
  return s;
}
const BANT_CONF = (n) =>
  n === 0 ? { label: 'Not scored', bg: 'var(--bg-3)', fg: 'var(--text-3)' } :
  n <= 2 ? { label: 'Low confidence', bg: 'var(--warning-low)', fg: 'var(--warning-low-on)' } :
  n <= 4 ? { label: 'Medium confidence', bg: 'var(--secondary-low)', fg: 'var(--secondary-low-on)' } :
  { label: 'High confidence', bg: 'var(--success-low)', fg: 'var(--success-low-on)' };
// Seeded leads carry only a numeric score (no per-criterion breakdown). Derive a deterministic,
// fully-known split so the headline and the rows always agree (discrete caps may shift it a few points).
function deriveBant(score) {
  let rem = typeof score === 'number' ? score : 0;
  const b = {};
  BANT4.forEach(([L, , cap]) => { if (rem >= cap) { b[L] = 'yes'; rem -= cap; } else { b[L] = 'no'; } });
  let best = ENGAGE_LEVELS[0];
  ENGAGE_LEVELS.forEach(l => { if (Math.abs(l.points - rem) < Math.abs(best.points - rem)) best = l; });
  b.E = best.value;
  return b;
}
function bantOf(lead) { return lead.bant && lead.bant.B ? lead.bant : deriveBant(lead.score); }
function bantReadRows(b) {
  const rows = BANT4.map(([letter, label, cap]) => {
    const st = b[letter] || 'unknown';
    return { letter, label, cap, unknown: st === 'unknown', points: st === 'yes' ? cap : 0 };
  });
  const e = b.E || 'unknown';
  const el = ENGAGE_LEVELS.find(x => x.value === e);
  rows.push({ letter: 'E', label: 'Engagement', cap: 10, unknown: e === 'unknown', points: el ? el.points : 0, sub: el ? el.label : null });
  return rows;
}

function BantRow({ letter, label, sub, cap, points, unknown }) {
  const pct = unknown ? 0 : (points / cap) * 100;
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 0' }}>
      <span className="mn-feed-icon" style={{ width: 24, height: 24, flex: 'none', fontSize: 11, fontWeight: 700, background: unknown ? 'var(--bg-3)' : 'var(--primary-low)', color: unknown ? 'var(--text-3)' : 'var(--primary-low-on)' }}>{letter}</span>
      <span style={{ width: 96, flex: 'none' }}>
        <span style={{ display: 'block', font: 'var(--font-weight-strong) 12px/15px var(--font-sans)', color: unknown ? 'var(--text-3)' : 'var(--text-1)' }}>{label}</span>
        {sub ? <span style={{ display: 'block', font: 'var(--font-weight-medium) 10px/13px var(--font-sans)', color: 'var(--text-3)' }}>{sub}</span> : null}
      </span>
      <span style={{ flex: 1, height: 6, borderRadius: 'var(--radi-full)', position: 'relative', overflow: 'hidden', background: unknown ? 'transparent' : 'var(--bg-3)', border: unknown ? '1px dashed var(--border-1)' : 'none' }}>
        <span style={{ position: 'absolute', left: 0, top: 0, height: '100%', width: pct + '%', borderRadius: 'var(--radi-full)', background: 'var(--primary-main)' }} />
      </span>
      <span style={{ flex: 'none', minWidth: 28, textAlign: 'right', fontFamily: 'var(--font-mono)', fontSize: 12, color: unknown ? 'var(--text-3)' : 'var(--text-2)' }} title={unknown ? 'Not evaluated' : undefined}>{unknown ? '—' : (points > 0 ? '+' + points : '0')}</span>
    </div>
  );
}

function BantTriRow({ letter, label, value, onSet }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 0' }}>
      <span className="mn-feed-icon" style={{ width: 24, height: 24, flex: 'none', fontSize: 11, fontWeight: 700, background: 'var(--primary-low)', color: 'var(--primary-low-on)' }}>{letter}</span>
      <span style={{ flex: 1, font: 'var(--font-weight-strong) 12px/16px var(--font-sans)', color: 'var(--text-1)' }}>{label}</span>
      <span style={{ display: 'inline-flex', flex: 'none', border: '1px solid var(--border-1)', borderRadius: 'var(--radi-full)', overflow: 'hidden' }}>
        {BANT_TRI.map(([v, lbl]) => {
          const on = value === v, unk = v === 'unknown';
          return <button key={v} type="button" onClick={() => onSet(v)} title={unk ? 'Not evaluated — left out of the score' : lbl}
            style={{ border: 0, cursor: 'pointer', padding: '4px 10px', font: 'var(--font-weight-medium) 11px/16px var(--font-sans)',
                     background: on ? (unk ? 'var(--bg-3)' : 'var(--primary-main)') : 'var(--bg-1)', color: on ? (unk ? 'var(--text-1)' : 'var(--primary-on)') : 'var(--text-3)' }}>{lbl}</button>;
        })}
      </span>
    </div>
  );
}

function BantEngageRow({ value, onSet }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 0' }}>
      <span className="mn-feed-icon" style={{ width: 24, height: 24, flex: 'none', fontSize: 11, fontWeight: 700, background: 'var(--primary-low)', color: 'var(--primary-low-on)' }}>E</span>
      <span style={{ width: 96, flex: 'none', font: 'var(--font-weight-strong) 12px/16px var(--font-sans)', color: 'var(--text-1)' }}>Engagement</span>
      <span style={{ flex: 1 }}>
        <Select size="sm" value={value || 'unknown'} onChange={(v) => onSet(v)}
          options={[{ value: 'unknown', label: 'Not evaluated' }].concat(ENGAGE_LEVELS.map(l => ({ value: l.value, label: l.label + ' · +' + l.points })))} />
      </span>
    </div>
  );
}

// BANT panel — read-only breakdown + Score Confidence, or an inline per-criterion editor
// (lead-scoring-bant.md §Lead Card Integration). Saving recomputes Score from the criteria.
function BantCard({ lead, role, readOnly, onUpdate, onToast }) {
  const RB = window.MonolitRBAC;
  const canEdit = !readOnly && RB.can(role, 'leads.update');
  const current = bantOf(lead);
  const [editing, setEditing] = useStateLC(false);
  const [draft, setDraft] = useStateLC({});
  function start() { setDraft({ ...current }); setEditing(true); }
  function set(letter, v) { setDraft(d => ({ ...d, [letter]: v })); }
  function save() {
    const score = bantScore(draft);
    onUpdate && onUpdate(lead.id, { bant: { ...draft }, score });
    onToast && onToast(score == null ? 'BANT updated — not scored yet' : 'BANT updated — score ' + score + '/100');
    setEditing(false);
  }
  const shown = editing ? draft : current;
  const score = bantScore(shown);
  const known = bantKnownCount(shown);
  const conf = BANT_CONF(known);
  const action = canEdit ? (editing
    ? <span style={{ display: 'inline-flex', gap: 6 }}>
        <Button variant="quiet" size="sm" onClick={() => setEditing(false)}>Cancel</Button>
        <Button variant="secondary" size="sm" onClick={save}>Save</Button>
      </span>
    : <IconButton icon="pencil" size="sm" title="Edit BANT" onClick={start} />) : null;
  return (
    <Card title="BANT Score" eyebrow={score == null ? 'Not scored' : ('Total ' + score + '/100')} padding="md" action={action}>
      <div className="mn-row" style={{ gap: 8, marginBottom: 8 }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', padding: '2px 8px', borderRadius: 'var(--radi-full)', background: conf.bg, color: conf.fg, font: 'var(--font-weight-medium) 11px/16px var(--font-sans)' }}>{conf.label}</span>
        <span className="mn-mono mn-muted" style={{ fontSize: 11 }}>{known}/5 known</span>
      </div>
      {score == null && !editing ? <div style={{ font: 'var(--font-weight-medium) 12px/18px var(--font-sans)', color: 'var(--text-3)', marginBottom: 6 }}>Unknown — fill the BANT criteria to score this lead.</div> : null}
      <div className="mn-stack" style={{ gap: 0 }}>
        {editing
          ? <React.Fragment>
              {BANT4.map(([letter, label]) => <BantTriRow key={letter} letter={letter} label={label} value={draft[letter] || 'unknown'} onSet={(v) => set(letter, v)} />)}
              <BantEngageRow value={draft.E || 'unknown'} onSet={(v) => set('E', v)} />
            </React.Fragment>
          : bantReadRows(shown).map(r => <BantRow key={r.letter} {...r} />)}
      </div>
      {editing ? <div style={{ font: 'var(--font-weight-medium) 11px/15px var(--font-sans)', color: 'var(--text-3)', marginTop: 8 }}>Unknown ≠ No — it means “not evaluated” and is left out of the Score (never lowers it).</div> : null}
    </Card>
  );
}

// Tags panel — read-only chips, or an inline add/remove editor (sidebar-and-edit-rules.md hot field).
function TagsCard({ lead, role, readOnly, onUpdate }) {
  const RB = window.MonolitRBAC;
  const canEdit = !readOnly && RB.can(role, 'leads.update');
  const [adding, setAdding] = useStateLC(false);
  const [val, setVal] = useStateLC('');
  const tags = lead.tags || [];
  function add() { const t = val.trim(); if (t && !tags.includes(t)) onUpdate && onUpdate(lead.id, { tags: [...tags, t] }); setVal(''); }
  function remove(t) { onUpdate && onUpdate(lead.id, { tags: tags.filter(x => x !== t) }); }
  return (
    <Card title="Tags" eyebrow="Classification" padding="md"
          action={canEdit ? <IconButton icon={adding ? 'check' : 'plus'} size="sm" title={adding ? 'Done' : 'Add tag'} onClick={() => setAdding(a => !a)} /> : null}>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
        {tags.map((t) => (
          <span key={t} className="mn-chip mn-chip--tag" style={{ gap: 4 }}>{t}
            {canEdit && adding ? <span onClick={() => remove(t)} style={{ cursor: 'pointer', display: 'inline-flex' }} title="Remove"><Icon name="x" size="xs" stroke="2" /></span> : null}
          </span>
        ))}
        {!tags.length && !adding ? <span style={{ color: 'var(--text-3)', font: 'var(--font-weight-medium) 12px/16px var(--font-sans)' }}>No tags</span> : null}
      </div>
      {canEdit && adding ? (
        <div style={{ display: 'flex', gap: 6, marginTop: 8 }}>
          <input value={val} onChange={(e) => setVal(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') add(); }} placeholder="Add tag…"
            style={{ flex: 1, padding: '6px 10px', border: '1px solid var(--border-1)', borderRadius: 'var(--radi-sm)', font: 'var(--font-weight-medium) 13px/16px var(--font-sans)', color: 'var(--text-1)', background: 'var(--bg-1)', boxSizing: 'border-box' }} />
          <Button variant="secondary" size="sm" onClick={add}>Add</Button>
        </div>
      ) : null}
    </Card>
  );
}

// Overview = navigation hub (no own CRUD) — lead-card-overview.md §Overview Tab:
// Next Step + SLA, condensed summary, Last Activity & Last Comment summaries with jumps,
// and View Activity / Comments / Audit shortcuts.
function OverviewTab({ lead, activity, canSeeAudit, onGoTab }) {
  const now = window.MonolitData.NOW;
  const acts = activity || [];
  const lastAct = acts[0];
  const due = lead.nextStep ? new Date(lead.nextStep.due) : null;
  const overdue = lead.status !== 'disqualified' && due && due < now;
  const overdueDays = overdue ? Math.floor((now - due) / 86400000) : 0;
  // Last comment summary mirrors the most recent note in the Comments tab (demo data).
  const lastComment = { who: window.MonolitData.owners[1], at: '2 h ago', text: 'Asked about data import from Salesforce — sent the import wizard doc.' };
  return (
    <div className="mn-stack-lg" style={{ paddingTop: 16 }}>
      <Card title="Next step" eyebrow="Follow-up & SLA">
        {lead.nextStep ? (
          <div className="mn-row" style={{ justifyContent: 'space-between', alignItems: 'center', gap: 8 }}>
            <NextStepCell nextStep={lead.nextStep} now={now} />
            {overdue ? <span className="mn-chip mn-chip--problem" style={{ gap: 4 }}><Icon name="alarm-clock" size="xs" stroke="2" />{overdueDays} day{overdueDays === 1 ? '' : 's'} overdue</span> : null}
          </div>
        ) : <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, color: 'var(--text-3)', font: 'var(--font-weight-medium) 13px/16px var(--font-sans)' }}><Icon name="circle-dashed" size="sm" />No next step set.</span>}
      </Card>

      <Card title="Summary" eyebrow="What we know">
        <p style={{ font: 'var(--font-weight-default) 14px/22px var(--font-sans)', color: 'var(--text-1)', margin: 0 }}>
          {lead.company} is evaluating Monolit alongside Salesforce for their {lead.tags.join(' / ')} operations.
          Budget range identified during discovery; decision expected in Q3. Primary contact prefers email after 14:00 UTC+3.
        </p>
      </Card>

      <Card title="Last activity" eyebrow="Most recent" action={<Button variant="quiet" size="sm" iconRight="arrow-right" onClick={() => onGoTab('activity')}>View activity</Button>}>
        {lastAct ? <div className="mn-feed"><FeedItem a={lastAct} /></div> : <div className="mn-empty" style={{ padding: 16 }}><Icon name="activity" size="lg" /><div className="mn-empty-msg">No activity yet.</div></div>}
      </Card>

      <Card title="Last comment" eyebrow="Team-internal" action={<Button variant="quiet" size="sm" iconRight="arrow-right" onClick={() => onGoTab('comments')}>View comments</Button>}>
        <div className="mn-row" style={{ alignItems: 'flex-start', gap: 10 }}>
          <Avatar user={lastComment.who} size={28} />
          <div style={{ flex: 1 }}>
            <div className="mn-feed-h"><span className="mn-feed-who">{lastComment.who.name}</span><span className="mn-feed-at">· {lastComment.at}</span></div>
            <div className="mn-feed-body">{lastComment.text}</div>
          </div>
        </div>
      </Card>

      <div className="mn-row" style={{ gap: 8, flexWrap: 'wrap' }}>
        <Button variant="ghost" size="md" icon="activity" onClick={() => onGoTab('activity')}>View activity</Button>
        <Button variant="ghost" size="md" icon="message-square" onClick={() => onGoTab('comments')}>View comments</Button>
        {canSeeAudit ? <Button variant="ghost" size="md" icon="history" onClick={() => onGoTab('audit')}>View audit</Button> : null}
      </div>
    </div>
  );
}

const ACT_FILTERS = [
  { value: 'all', label: 'All types', icon: 'filter' },
  { value: 'call', label: 'Calls', icon: 'phone' },
  { value: 'email', label: 'Emails', icon: 'mail' },
  { value: 'meeting', label: 'Meetings', icon: 'calendar' },
  { value: 'note', label: 'Notes', icon: 'sticky-note' },
  { value: 'task', label: 'Tasks', icon: 'check-square' },
];
function ActivityTab({ activity, readOnly, canCreate, onAddActivity }) {
  const [ftype, setFtype] = useStateLC('all');
  const cur = ACT_FILTERS.find(t => t.value === ftype) || ACT_FILTERS[0];
  const shown = ftype === 'all' ? activity : activity.filter(a => a.type === ftype);
  return (
    <div style={{ paddingTop: 16 }}>
      <Card title="Activity timeline" eyebrow={ftype === 'all' ? `${activity.length} events` : `${shown.length} of ${activity.length} events`}
            action={<div className="mn-row" style={{ gap: 8 }}>
              <Dropdown align="right" width={200} trigger={({ toggle }) => <Button variant={ftype === 'all' ? 'ghost' : 'secondary'} size="sm" icon="filter" iconRight="chevron-down" onClick={toggle}>{cur.label}</Button>}>
                {({ close }) => (
                  <div className="mn-dd-list">
                    {ACT_FILTERS.map(t => (
                      <button key={t.value} className="mn-dd-item" style={{ alignItems: 'center' }} onClick={() => { setFtype(t.value); close(); }}>
                        <Icon name={t.icon} size="sm" color="text-2" /><span className="mn-dd-item-tt">{t.label}</span>{ftype === t.value ? <Icon name="check" size="sm" color="primary" /> : null}
                      </button>
                    ))}
                  </div>
                )}
              </Dropdown>
              {!readOnly && canCreate ? <Button variant="primary" size="sm" icon="plus" onClick={() => onAddActivity()}>Add activity</Button> : null}
            </div>}>
        {shown.length
          ? <div className="mn-feed">{shown.map((a) => <FeedItem key={a.id} a={a} />)}</div>
          : <div className="mn-empty" style={{ padding: 24 }}><Icon name={cur.icon} size="lg" /><div className="mn-empty-msg">No {cur.label.toLowerCase()} in this timeline.</div></div>}
      </Card>
    </div>
  );
}

const COMMENT_MAX = 2000;
function CommentsTab({ readOnly, onToast }) {
  const seed = [
    { id: 'c1', who: window.MonolitData.owners[1], at: '2 h ago', body: 'Asked about data import from Salesforce — sent the import wizard doc.' },
    { id: 'c2', who: window.MonolitData.owners[2], at: 'yesterday', body: "Procurement team CC'd. Their preferred billing cycle is annual prepaid." },
    { id: 'c3', who: window.MonolitData.owners[0], at: '3 d ago', body: 'Original referral came from @Lukas Berger at Alpenbau. Worth thanking him.' },
  ];
  const [comments, setComments] = useStateLC(seed);
  const [val, setVal] = useStateLC('');
  const me = { name: 'Maria Lis', initials: 'ML', color: 'teal' };
  function send() {
    const t = val.trim(); if (!t) return;
    setComments(cs => [{ id: 'c' + Date.now(), who: me, at: 'just now', body: t }, ...cs]);
    setVal(''); onToast && onToast('Comment added');
  }
  return (
    <div style={{ paddingTop: 16 }}>
      <Card title="Comments" eyebrow={comments.length + ' team-internal note' + (comments.length === 1 ? '' : 's')}>
        {!readOnly ? (
          <div style={{ marginBottom: 16, paddingBottom: 14, borderBottom: '1px solid var(--border-1)' }}>
            <Textarea fullWidth value={val} onChange={setVal} rows={2} maxLength={COMMENT_MAX} placeholder="Add a comment… @ to mention" />
            <div className="mn-row" style={{ justifyContent: 'space-between', alignItems: 'center', marginTop: 8 }}>
              <span className="mn-mono mn-muted" style={{ fontSize: 11 }}>{val.length}/{COMMENT_MAX}</span>
              <Button variant="primary" size="sm" icon="message-square" disabled={!val.trim()} onClick={send}>Comment</Button>
            </div>
          </div>
        ) : null}
        {comments.length
          ? <div className="mn-stack-lg">{comments.map(c => <Comment key={c.id} who={c.who} at={c.at} body={c.body} />)}</div>
          : <div className="mn-empty" style={{ padding: 24 }}><Icon name="message-square" size="lg" /><div className="mn-empty-msg">No comments yet — start the thread.</div></div>}
      </Card>
    </div>
  );
}

function Comment({ who, at, body }) {
  return (
    <div className="mn-row" style={{ alignItems: 'flex-start', gap: 10 }}>
      <Avatar user={who} size={28} />
      <div style={{ flex: 1 }}>
        <div className="mn-feed-h"><span className="mn-feed-who">{who.name}</span><span className="mn-feed-at">· {at}</span></div>
        <div className="mn-feed-body">{body}</div>
      </div>
    </div>
  );
}

function DealsTab({ lead, readOnly, canCreate, onNewDeal }) {
  const deals = (window.MonolitData.deals || []).filter(d => d.leadId === lead.id);
  return (
    <div style={{ paddingTop: 16 }}>
      <Card title="Pre-sales deals" eyebrow="Linked to this lead"
            action={!readOnly && canCreate ? <Button variant="primary" size="sm" icon="plus" onClick={onNewDeal}>New deal</Button> : null}>
        {deals.length ? deals.map(d => (
          <div key={d.id} className="mn-row" style={{ padding: '8px 4px', borderBottom: '1px dashed var(--border-1)', justifyContent: 'space-between' }}>
            <div className="mn-row" style={{ gap: 10 }}>
              <span className="mn-feed-icon"><Icon name="briefcase" size="sm" /></span>
              <div>
                <div style={{ font: 'var(--font-weight-strong) 13px/18px var(--font-sans)' }}>{d.name}</div>
                <div style={{ font: 'var(--font-weight-medium) 12px/16px var(--font-sans)', color: 'var(--text-3)' }}>{window.MonolitData.publicId(d.id)} · {d.owner ? d.owner.name : 'no owner'}{!readOnly && dealIsActive(d) ? ' · Won blocked until convert' : ''}</div>
              </div>
            </div>
            <div className="mn-row" style={{ gap: 8 }}><span className="mn-mono" style={{ fontSize: 13, color: 'var(--text-1)' }}>{fmtMoney(d) || '—'}</span><DealStageChip stage={d.stage} /></div>
          </div>
        )) : (
          <div className="mn-empty" style={{ padding: 24 }}><Icon name="briefcase" size="lg" /><div className="mn-empty-msg">No deals yet. Pre-sales deals can’t reach Won until the lead is converted.</div>{!readOnly && canCreate ? <Button variant="primary" size="sm" icon="plus" onClick={onNewDeal}>New pre-sales deal</Button> : null}</div>
        )}
      </Card>
    </div>
  );
}

// Files tab — upload/download/delete with MVP rules: formats PDF/DOCX/XLSX/PNG/JPG, ≤15 MB,
// ≤50 files; soft delete via confirmation modal; delete restricted to own files (Manager/Sales Rep)
// vs any (Admin/Ops Admin) per files-and-document-verification.md File Delete Rules.
const FILE_OK = /\.(pdf|docx|xlsx|png|jpe?g)$/i;
function FilesTab({ readOnly, role, onToast }) {
  const seed = [
    { id: 'f1', name: 'NDA — countersigned.pdf', size: '184 KB', who: 'Maria Lis', at: 'yesterday', type: 'doc' },
    { id: 'f2', name: 'Discovery notes 24-04.docx', size: '12 KB', who: 'Maria Lis', at: '3 d ago', type: 'doc' },
    { id: 'f3', name: 'Northwind org chart.png', size: '420 KB', who: 'Daniyar K.', at: '5 d ago', type: 'image' },
    { id: 'f4', name: 'Budget approval.pdf', size: '28 KB', who: 'Anna Voronova', at: 'a week ago', type: 'doc' },
  ];
  const [files, setFiles] = useStateLC(seed);
  const [pending, setPending] = useStateLC(null);
  const canDeleteAny = role === 'Admin' || role === 'Ops Admin';
  const canDelete = (f) => !readOnly && (canDeleteAny || f.who === 'Maria Lis');
  function pickUpload() {
    if (files.length >= 50) { onToast && onToast('Limit reached — max 50 files per lead'); return; }
    const input = document.createElement('input');
    input.type = 'file'; input.accept = '.pdf,.docx,.xlsx,.png,.jpg,.jpeg';
    input.onchange = () => {
      const fl = input.files && input.files[0]; if (!fl) return;
      if (!FILE_OK.test(fl.name)) { onToast && onToast('Unsupported format — PDF/DOCX/XLSX/PNG/JPG only'); return; }
      if (fl.size > 15 * 1024 * 1024) { onToast && onToast('Too large — 15 MB max per file'); return; }
      const kb = Math.max(1, Math.round(fl.size / 1024));
      const sz = kb >= 1024 ? (kb / 1024).toFixed(1) + ' MB' : kb + ' KB';
      setFiles(fs => [{ id: 'f' + Date.now(), name: fl.name, size: sz, who: 'Maria Lis', at: 'just now', type: /\.(png|jpe?g)$/i.test(fl.name) ? 'image' : 'doc' }, ...fs]);
      onToast && onToast('File uploaded · ' + fl.name);
    };
    input.click();
  }
  return (
    <div style={{ paddingTop: 16 }}>
      <Card title="Files" eyebrow={files.length + ' attached'} action={!readOnly ? <Button variant="primary" size="sm" icon="paperclip" onClick={pickUpload}>Upload</Button> : null}>
        {files.length ? (
          <div className="mn-stack">
            {files.map((f) => (
              <div key={f.id} className="mn-row" style={{ padding: '10px 4px', borderBottom: '1px dashed var(--border-1)', gap: 10 }}>
                <span className="mn-feed-icon"><Icon name={f.type === 'image' ? 'image' : 'file-text'} size="sm" /></span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ font: 'var(--font-weight-strong) 13px/18px var(--font-sans)' }}>{f.name}</div>
                  <div style={{ font: 'var(--font-weight-medium) 12px/16px var(--font-sans)', color: 'var(--text-3)' }}>{f.size} · {f.who} · {f.at}</div>
                </div>
                <IconButton icon="download" size="sm" title="Download" onClick={() => onToast && onToast('Preparing secure download…')} />
                {canDelete(f) ? <IconButton icon="trash-2" size="sm" title="Delete" danger onClick={() => setPending(f)} /> : null}
              </div>
            ))}
          </div>
        ) : (
          <div className="mn-empty" style={{ padding: 24 }}><Icon name="paperclip" size="lg" /><div className="mn-empty-msg">No files attached yet.</div>{!readOnly ? <Button variant="primary" size="sm" icon="paperclip" onClick={pickUpload}>Upload file</Button> : null}</div>
        )}
        <div style={{ font: 'var(--font-weight-medium) 11px/15px var(--font-sans)', color: 'var(--text-3)', marginTop: 10 }}>PDF · DOCX · XLSX · PNG · JPG · max 15 MB · up to 50 files</div>
      </Card>
      {pending ? (
        <Modal open onClose={() => setPending(null)} eyebrow="Files" title="Delete file?" size="sm" footer={
          <React.Fragment>
            <Button variant="ghost" size="md" onClick={() => setPending(null)}>Cancel</Button>
            <Button variant="destructive" size="md" icon="trash-2" onClick={() => { const n = pending.name; setFiles(fs => fs.filter(x => x.id !== pending.id)); setPending(null); onToast && onToast('“' + n + '” deleted'); }}>Delete file</Button>
          </React.Fragment>}>
          <p style={{ font: 'var(--font-weight-medium) 13px/20px var(--font-sans)', color: 'var(--text-1)', margin: 0 }}>Delete <b>{pending.name}</b>? It’s removed from the lead — soft delete, metadata kept for audit.</p>
        </Modal>
      ) : null}
    </div>
  );
}

function AuditTab({ activity }) {
  const audit = [
    { who: 'Maria Lis', at: 'today, 09:14', evt: 'lead.status_changed', detail: 'In progress → Qualified' },
    { who: 'Maria Lis', at: 'today, 09:13', evt: 'lead.field_updated', detail: 'next_step_due_at: null → 2026-05-30' },
    { who: 'system', at: 'today, 08:02', evt: 'lead.score_recomputed', detail: '67 → 82 (BANT update)' },
    { who: 'Anna Voronova', at: '3 d ago, 16:40', evt: 'lead.owner_assigned', detail: 'null → Maria Lis' },
    { who: 'system', at: '11 d ago, 10:02', evt: 'lead.created', detail: 'source=web_form/landing_1' },
  ];
  return (
    <div style={{ paddingTop: 16 }}>
      <Card title="Audit log" eyebrow="All events for this lead">
        <table className="mn-table" style={{ marginTop: -8 }}>
          <thead><tr><th>Time</th><th>Event</th><th>Detail</th><th>By</th></tr></thead>
          <tbody>{audit.map((a, i) => (
            <tr key={i}>
              <td><span className="mn-mono" style={{ fontSize: 12, color: 'var(--text-3)' }}>{a.at}</span></td>
              <td><span className="mn-mono" style={{ fontSize: 12, color: 'var(--text-2)' }}>{a.evt}</span></td>
              <td>{a.detail}</td><td>{a.who}</td>
            </tr>
          ))}</tbody>
        </table>
      </Card>
    </div>
  );
}

Object.assign(window, { LeadCard });
