// ════════════ PEOPLE · CRM cluster ════════════
const { Icon, Spark, Pex, Avatar, Card, Btn, Pill, Label, Num, Spark2, Tabs, money, Field, Select } = window;

window.PEOPLE = [
  { id: 'marc', name: 'Marc Lefèvre', co: 'Café Bleu', role: 'Owner', tags: ['wholesale', 'overdue'], deal: 4200, last: '11d', tone: 'rose', signal: 'Overdue nudge sent', email: 'marc@cafebleu.nyc', ltv: 28420, rel: 92 },
  { id: 'jenna', name: 'Jenna Ruiz', co: 'Pastry Guild NYC', role: 'Director', tags: ['press', 'pastry'], deal: 0, last: '3d', tone: 'sage', signal: 'Coffee scheduled', email: 'jenna@pastryguild.org', ltv: 0, rel: 70 },
  { id: 'lila', name: 'Lila Okamoto', co: 'Lila Events', role: 'Founder', tags: ['caterer', 'repeat'], deal: 1850, last: '1w', tone: 'amber', signal: 'Quote sent', email: 'lila@lilaevents.nyc', ltv: 9200, rel: 88 },
  { id: 'marcus', name: 'Marcus Chen', co: 'Slate & Stone', role: 'Owner', tags: ['wholesale', 'new'], deal: 800, last: 'Today', tone: 'sky', signal: 'Proposal drafted', email: 'marcus@slatestone.co', ltv: 800, rel: 60 },
  { id: 'noor', name: 'Noor Hassan', co: 'Greenpoint Market', role: 'Buyer', tags: ['wholesale'], deal: 2400, last: '2w', tone: 'neutral', signal: 'Going quiet', email: 'noor@gpmarket.com', ltv: 6400, rel: 75 },
  { id: 'david', name: 'David Park', co: 'Park Bros. Hotel', role: 'F&B Director', tags: ['wholesale', 'vip'], deal: 12000, last: '1d', tone: 'sage', signal: 'Contract signed', email: 'david@parkbros.com', ltv: 24000, rel: 95 },
  { id: 'sofia', name: 'Sofia Martins', co: '—', role: 'Regular', tags: ['class', 'repeat'], deal: 0, last: '4d', tone: 'neutral', signal: '3rd class this year', email: 'sofia.m@gmail.com', ltv: 960, rel: 80 },
  { id: 'ahmad', name: 'Ahmad Saleh', co: 'BK Food Co-op', role: 'Manager', tags: ['wholesale', 'new'], deal: 3600, last: '2d', tone: 'amber', signal: 'Awaiting samples', email: 'ahmad@bkcoop.org', ltv: 3600, rel: 65 },
];

// Reactive wrapper so an added contact shows up in the list without a reload.
// window.PEOPLE stays pointed at the live array for the many places that read
// it directly (invoice recipient picker, contact detail, segment badges).
window.PXPeople = window.makeStore({ people: window.PEOPLE });
window.PXPeople.subscribe(() => { window.PEOPLE = window.PXPeople.get().people; });
window.PXPeople.addContact = (c) => window.PXPeople.set(s => ({ ...s, people: [c, ...s.people] }));
window.PXPeople.patchContact = (id, patch) => window.PXPeople.set(s => ({ ...s, people: s.people.map(p => p.id === id ? { ...p, ...patch } : p) }));
window.PXPeople.removeContact = (id) => window.PXPeople.set(s => ({ ...s, people: s.people.filter(p => p.id !== id) }));

// Canonical deal records shared by Pipeline + Deals + the deal detail drawer
window.DEALS = [
  { id: 'd-lead1', name: 'Wedding cake inquiry · Instagram', stage: 'Lead', value: 0, contactId: null, notes: '', winLossReason: null, activity: [{ ic: 'sparkles', t: 'Deal created from Instagram DM', s: '2d ago', tone: 'spark' }] },
  { id: 'd-lead2', name: 'Cold email · hotel chain', stage: 'Lead', value: 0, contactId: null, notes: '', winLossReason: null, activity: [{ ic: 'mail', t: 'Cold outreach email sent', s: '4d ago', tone: 'sky' }] },
  { id: 'd-q1', name: 'Marcus Chen · wholesale trial', stage: 'Qualified', value: 800, contactId: 'marcus', notes: '', winLossReason: null, activity: [{ ic: 'fileText', t: 'Proposal drafted', s: 'Today', tone: 'spark' }] },
  { id: 'd-q2', name: 'Ahmad Saleh · BK Co-op', stage: 'Qualified', value: 3600, contactId: 'ahmad', notes: '', winLossReason: null, activity: [{ ic: 'package', t: 'Awaiting samples', s: '2d ago', tone: 'amber' }] },
  { id: 'd-q3', name: 'Noor · Greenpoint Market', stage: 'Qualified', value: 2400, contactId: 'noor', notes: '', winLossReason: null, activity: [{ ic: 'clock', t: 'Going quiet — no reply in 2 weeks', s: '2w ago', tone: 'amber' }] },
  { id: 'd-p1', name: 'Lila · summer catering', stage: 'Proposal', value: 1850, contactId: 'lila', notes: '', winLossReason: null, activity: [{ ic: 'send', t: 'Quote sent', s: '1w ago', tone: 'spark' }] },
  { id: 'd-p2', name: 'Corner Coffee', stage: 'Proposal', value: 1200, contactId: null, notes: '', winLossReason: null, activity: [{ ic: 'fileText', t: 'Proposal sent', s: '5d ago', tone: 'spark' }] },
  { id: 'd-n1', name: 'Marc · Café Bleu renewal', stage: 'Negotiation', value: 4200, contactId: 'marc', notes: 'Wants to bump to 15 loaves/wk.', winLossReason: null, activity: [{ ic: 'reply', t: 'Replied: wants to bump to 15 loaves', s: 'Today', tone: 'sky' }] },
  { id: 'd-n2', name: 'Park Bros. Hotel · Q2 contract', stage: 'Negotiation', value: 12000, contactId: 'david', notes: '', winLossReason: null, activity: [{ ic: 'phone', t: 'Call · discussed contract terms', s: '1d ago', tone: 'sky' }] },
  { id: 'd-w1', name: 'Park Bros. Hotel · signed', stage: 'Won', value: 12000, contactId: 'david', notes: '', winLossReason: null, activity: [{ ic: 'check', t: 'Contract signed', s: '1d ago', tone: 'sage' }] },
  { id: 'd-w2', name: 'Slate & Stone · first order', stage: 'Won', value: 800, contactId: 'marcus', notes: '', winLossReason: null, activity: [{ ic: 'check', t: 'First order placed', s: 'Today', tone: 'sage' }] },
  { id: 'd-w3', name: 'Lila Events · Feb order', stage: 'Won', value: 2100, contactId: 'lila', notes: '', winLossReason: null, activity: [{ ic: 'check', t: 'Order completed', s: 'Feb', tone: 'sage' }] },
];

// Default segments — now backed by real criteria instead of decorative pills
window.SEGMENTS_DEFAULT = [
  { id: 'seg-wholesale', icon: 'truck', name: 'Wholesale', criteria: [{ field: 'tag', op: 'is', value: 'wholesale' }] },
  { id: 'seg-class', icon: 'gift', name: 'Class regulars', criteria: [{ field: 'tag', op: 'is', value: 'class' }] },
  { id: 'seg-stale', icon: 'clock', name: 'Going quiet', tone: 'amber', criteria: [{ field: 'last-activity', op: 'over', value: '7' }] },
  { id: 'seg-new', icon: 'user', name: 'Recently added', tone: 'sky', criteria: [{ field: 'tag', op: 'is', value: 'new' }] },
];

// ── shared helpers ─────────────────────────────────────────────
function parseLastDays(s) {
  if (!s) return 0;
  if (/today/i.test(s)) return 0;
  const m = String(s).match(/(\d+)\s*(d|w)/i);
  if (!m) return 0;
  return m[2].toLowerCase() === 'w' ? Number(m[1]) * 7 : Number(m[1]);
}

function matchesCriteria(c, criteria) {
  return (criteria || []).every(cr => {
    const val = (cr.value || '').toString().toLowerCase().trim();
    if (!val) return true;
    if (cr.field === 'tag') {
      const has = c.tags.some(t => t.toLowerCase() === val || t.toLowerCase().includes(val));
      return cr.op === 'is not' ? !has : has;
    }
    if (cr.field === 'company') {
      const has = (c.co || '').toLowerCase().includes(val);
      return cr.op === 'is not' ? !has : has;
    }
    if (cr.field === 'deal-stage') {
      const stages = crmFor(c).deals.map(d => d.stage.toLowerCase());
      const has = stages.includes(val);
      return cr.op === 'is not' ? !has : has;
    }
    if (cr.field === 'last-activity') {
      const days = parseLastDays(c.last);
      const n = Number(cr.value) || 0;
      return cr.op === 'under' ? days <= n : days >= n;
    }
    return true;
  });
}

// Compact chip-row selector — used in place of a native <select> throughout this file
function Chips({ options, value, onChange, toneFor }) {
  const P = window.PX;
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
      {options.map(o => {
        const on = value === o;
        const rawTone = toneFor ? toneFor(o) : null;
        const tone = rawTone && rawTone !== 'neutral' ? rawTone : null;
        return (
          <div key={o} onClick={() => onChange(o)} style={{ padding: '6px 12px', borderRadius: 8, fontSize: 12.5, fontWeight: on ? 600 : 500, cursor: 'pointer', whiteSpace: 'nowrap',
            background: on ? (tone ? P[tone + 'Tint'] : P.ink) : P.sunk,
            color: on ? (tone ? P[tone] : '#fff') : P.ink2,
            border: `1px solid ${on && tone ? P[tone] : 'transparent'}` }}>{o}</div>
        );
      })}
    </div>
  );
}

window.SCREENS['people'] = function People({ sub }) {
  const P = window.PX; const { go } = window.useApp();
  const seg = (sub || '').split('/');
  const raw = seg[0] || 'contacts';
  const contact = window.PEOPLE.find(p => p.id === raw);
  const isSeg = raw.startsWith('seg');
  const active = contact ? 'contacts' : raw;

  const [segments, setSegments] = React.useState(() => window.SEGMENTS_DEFAULT.map(s => ({ ...s })));
  const [showSegBuilder, setShowSegBuilder] = React.useState(false);
  const [deals, setDeals] = React.useState(() => window.DEALS.map(d => ({ ...d, activity: [...d.activity] })));
  const [openDealId, setOpenDealId] = React.useState(null);

  const activeSegment = segments.find(s => s.id === raw);

  const nav = [
    { items: [
      { k: 'contacts', icon: 'users', label: 'Contacts', badge: 428 },
      { k: 'pipeline', icon: 'layout', label: 'Pipeline', badge: deals.filter(d => d.stage !== 'Won' && d.stage !== 'Lost').length },
      { k: 'tasks', icon: 'check', label: 'Tasks', badge: 5, tone: 'spark' },
      { k: 'companies', icon: 'building', label: 'Companies', badge: 96 },
      { k: 'deals', icon: 'dollar', label: 'Deals' },
      { k: 'duplicates', icon: 'copy', label: 'Duplicates', badge: 4, tone: 'amber' },
    ]},
    { label: 'Segments', items: [
      ...segments.map(s => ({ k: s.id, icon: s.icon, label: s.name, badge: window.PEOPLE.filter(c => matchesCriteria(c, s.criteria)).length, tone: s.tone })),
      { k: 'new-segment', icon: 'plus', label: 'New segment', tone: 'spark' },
    ]},
  ];
  const onNav = (k) => {
    if (k === 'new-segment') { setShowSegBuilder(true); return; }
    go('people' + (k === 'contacts' ? '' : '/' + k));
  };

  return (
    <>
      <window.SubLayout title="People" nav={nav} active={active} onNav={onNav}>
        {(active === 'contacts' || isSeg) && (contact ? <ContactDetail id={raw}/> : <ContactList segment={activeSegment}/>)}
        {active === 'pipeline' && <Pipeline deals={deals} setDeals={setDeals} onOpen={setOpenDealId}/>}
        {active === 'tasks' && <CRMTasks/>}
        {active === 'companies' && <Companies/>}
        {active === 'deals' && <Deals deals={deals} onOpen={setOpenDealId}/>}
        {active === 'duplicates' && <Duplicates/>}
      </window.SubLayout>
      {showSegBuilder && (
        <SegmentBuilder
          onClose={() => setShowSegBuilder(false)}
          onSave={(newSeg) => { setSegments(s => [...s, newSeg]); setShowSegBuilder(false); go('people/' + newSeg.id); }}
        />
      )}
      {openDealId && (
        <DealDetail id={openDealId} deals={deals} setDeals={setDeals} onClose={() => setOpenDealId(null)}/>
      )}
    </>
  );
};

const COL_TEMPLATE = '30px 2.2fr 2fr 1fr 0.8fr 30px';

function ContactList({ segment }) {
  const P = window.PX; const { go, openOverlay, toast } = window.useApp();
  const [q, setQ] = React.useState('');
  const [sel, setSel] = React.useState(() => new Set());
  const people = window.useStore(window.PXPeople).people;
  const base = segment ? people.filter(c => matchesCriteria(c, segment.criteria)) : people;
  const ql = q.trim().toLowerCase();
  const list = ql ? base.filter(c => (c.name + ' ' + (c.co || '') + ' ' + c.email + ' ' + (c.tags || []).join(' ')).toLowerCase().includes(ql)) : base;
  const title = segment ? segment.name : 'Contacts';
  const subtitle = segment ? `${list.length} match${list.length === 1 ? '' : 'es'} · live segment` : `${people.length} people · 11 open deals · 23 going quiet`;

  const toggleSel = (id) => setSel(s => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });
  const allOn = list.length > 0 && list.every(c => sel.has(c.id));
  const toggleAll = () => setSel(s => { if (allOn) { const n = new Set(s); list.forEach(c => n.delete(c.id)); return n; } return new Set([...s, ...list.map(c => c.id)]); });
  const selCount = list.filter(c => sel.has(c.id)).length;
  const clearSel = () => setSel(new Set());
  const bulkTag = (tag) => { const ids = list.filter(c => sel.has(c.id)).map(c => c.id); ids.forEach(id => { const c = people.find(p => p.id === id); if (c && !c.tags.includes(tag)) window.PXPeople.patchContact(id, { tags: [...c.tags, tag] }); }); toast(`Tagged ${ids.length} contact${ids.length === 1 ? '' : 's'} #${tag}.`, { tone: 'sage', icon: 'check' }); };
  const bulkDelete = () => { const ids = list.filter(c => sel.has(c.id)).map(c => c.id); ids.forEach(id => window.PXPeople.removeContact(id)); toast(`Deleted ${ids.length} contact${ids.length === 1 ? '' : 's'}.`, { icon: 'trash' }); clearSel(); };

  return (
    <div style={{ fontFamily: P.sans }}>
      <div style={{ padding: '18px 22px', borderBottom: `1px solid ${P.line}`, display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{ flex: 1 }}><div style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 26, color: P.ink }}>{title}</div><div style={{ fontSize: 12.5, color: P.ink3 }}>{subtitle}</div></div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '7px 11px', background: P.card, border: `1px solid ${P.line}`, borderRadius: 9, fontSize: 12.5, color: P.ink3, width: 240 }}>
          <Icon name="search" size={15}/>
          <input value={q} onChange={e => setQ(e.target.value)} placeholder="Search people, companies, tags…" style={{ flex: 1, border: 'none', outline: 'none', background: 'transparent', fontSize: 12.5, color: P.ink, fontFamily: P.sans, minWidth: 0 }}/>
        </div>
        <Btn kind="primary" size="sm" icon="plus" onClick={() => openOverlay('addContact')}>Add</Btn>
      </div>

      {selCount > 0 && (
        <div style={{ padding: '10px 22px', borderBottom: `1px solid ${P.line}`, background: P.sparkWash, display: 'flex', alignItems: 'center', gap: 10 }}>
          <span style={{ fontSize: 12.5, color: P.ink, fontWeight: 600 }}>{selCount} selected</span>
          <div style={{ flex: 1 }}/>
          <Btn kind="default" size="sm" icon="mail" onClick={() => { openOverlay('compose'); }}>Email</Btn>
          <Btn kind="default" size="sm" icon="plus" onClick={() => bulkTag('wholesale')}>Tag #wholesale</Btn>
          <Btn kind="default" size="sm" icon="download" onClick={() => toast(`Exported ${selCount} contact${selCount === 1 ? '' : 's'} to CSV.`, { tone: 'sage', icon: 'check' })}>Export</Btn>
          <Btn kind="danger" size="sm" icon="trash" onClick={bulkDelete}>Delete</Btn>
          <Btn kind="ghost" size="sm" onClick={clearSel}>Clear</Btn>
        </div>
      )}

      <div style={{ padding: '0 22px' }}>
        <div style={{ display: 'grid', gridTemplateColumns: COL_TEMPLATE, gap: 14, padding: '12px 4px', borderBottom: `1px solid ${P.line}`, alignItems: 'center' }}>
          <window.Check on={allOn} onClick={toggleAll}/>
          {['Name', 'Company · Signal', 'Open deal', 'Last', ''].map((h, i) => <Label key={i}>{h}</Label>)}
        </div>
        {list.map((c, i) => {
          const on = sel.has(c.id);
          return (
          <div key={c.id} onClick={() => go('people/' + c.id)} style={{ display: 'grid', gridTemplateColumns: COL_TEMPLATE, gap: 14, padding: '12px 4px', borderBottom: `1px solid ${P.line}`, alignItems: 'center', cursor: 'pointer', background: on ? P.sparkWash : 'transparent' }}
            onMouseEnter={e => { if (!on) e.currentTarget.style.background = P.hover; }} onMouseLeave={e => { if (!on) e.currentTarget.style.background = 'transparent'; }}>
            <span onClick={e => { e.stopPropagation(); toggleSel(c.id); }}><window.Check on={on} onClick={() => {}}/></span>
            <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
              <Avatar name={c.name} size={32}/>
              <div><div style={{ fontSize: 13.5, color: P.ink, fontWeight: 500 }}>{c.name}</div><div style={{ display: 'flex', gap: 4, marginTop: 3 }}>{c.tags.map(t => <span key={t} style={{ fontSize: 9.5, color: P.ink3, background: P.sunk, padding: '1px 6px', borderRadius: 4 }}>#{t}</span>)}</div></div>
            </div>
            <div><div style={{ fontSize: 13, color: P.ink2 }}>{c.co}</div><div style={{ fontSize: 11.5, color: c.tone === 'neutral' ? P.ink3 : P[c.tone], marginTop: 2, display: 'flex', alignItems: 'center', gap: 4 }}>{c.tone === 'spark' && <Spark size={10}/>}{c.signal}</div></div>
            <span style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 16, color: P.ink }}>{c.deal ? money(c.deal).replace('.00', '') : '—'}</span>
            <span style={{ fontSize: 12, color: P.ink3 }}>{c.last}</span>
            <Icon name="chevR" size={15} color={P.ink4}/>
          </div>
          );
        })}
        {!list.length && <Empty label="contacts in this segment"/>}
      </div>
    </div>
  );
}

// Per-contact CRM record — deals, invoices, notes, tasks, files, activity
function crmFor(c) {
  const fname = c.name.split(' ')[0];
  if (c.id === 'marc') return {
    deals: [
      { name: 'Wholesale renewal · 15 loaves/wk', stage: 'Negotiation', value: 4200, tone: 'spark' },
      { name: 'Spring catering trial', stage: 'Lead', value: 1800, tone: 'sky' },
      { name: '2024 wholesale contract', stage: 'Won', value: 16800, tone: 'sage' },
    ],
    invoices: [
      { no: '#1024', status: 'Overdue 11d', amt: 1420, tone: 'rose' },
      { no: '#1018', status: 'Paid Feb 14', amt: 1280, tone: 'sage' },
      { no: '#1009', status: 'Paid Jan 30', amt: 1280, tone: 'sage' },
    ],
    notes: [
      { t: 'Prefers Sunday deliveries before 9am. Still sensitive about the Feb mix-up — wasn’t his fault.', by: 'Amara · Feb 22' },
      { t: 'Hinted at opening a second café location this summer.', by: 'Amara · Jan 14' },
    ],
    tasks: [
      { t: 'Send the 15-loaf price sheet ($1,820/mo)', due: 'Today', done: false },
      { t: 'Confirm Friday payment landed', due: 'Fri', done: false },
      { t: 'Q2 wholesale check-in call', due: 'Apr 2', done: false },
    ],
    files: [{ n: 'cafebleu-wholesale-2024.pdf', type: 'PDF' }, { n: 'delivery-preferences.txt', type: 'Note' }],
    activity: [
      { ic: 'eye', t: 'Opened payment reminder', s: 'Today 7:14am · by Pex', tone: 'spark', type: 'email' },
      { ic: 'reply', t: 'Replied: "paying Friday, want to bump to 15 loaves"', s: 'Today 7:41am', tone: 'sky', type: 'email' },
      { ic: 'send', t: 'Reminder sent: Invoice #1024', s: 'Today 7:12am · by Pex', tone: 'spark', type: 'email' },
      { ic: 'dollar', t: 'Invoice #1024 issued · $1,420', s: 'Mar 1', tone: 'amber', type: 'note' },
      { ic: 'phone', t: '45-min call · discussed catering', s: 'Feb 22', tone: 'sky', type: 'call' },
      { ic: 'check', t: 'Invoice #1018 paid · $1,280', s: 'Feb 14', tone: 'sage', type: 'note' },
    ],
  };
  const toneFix = c.tone === 'neutral' ? 'sky' : c.tone;
  const stageByTone = { rose: 'Negotiation', sky: 'Qualified', amber: 'Proposal', sage: 'Won', neutral: 'Lead' };
  const deals = [];
  if (c.deal) deals.push({ name: `${c.co !== '—' ? c.co : fname} · ${c.tags[0]}`, stage: stageByTone[c.tone] || 'Qualified', value: c.deal, tone: toneFix });
  if (c.ltv > c.deal) deals.push({ name: 'Past orders', stage: 'Won', value: c.ltv - c.deal, tone: 'sage' });
  const invoices = [];
  if (c.tone === 'rose') invoices.push({ no: '#1024', status: 'Overdue', amt: c.deal, tone: 'rose' });
  if (c.ltv > 0) { invoices.push({ no: '#1018', status: 'Paid', amt: Math.max(80, Math.round(c.ltv * 0.18)), tone: 'sage' }); if (c.ltv > 2000) invoices.push({ no: '#1004', status: 'Paid', amt: Math.round(c.ltv * 0.12), tone: 'sage' }); }
  const notes = [
    { t: `${c.signal}.`, by: 'Pex · today' },
    { t: `${fname}${c.tags.includes('repeat') ? ' is a repeat customer' : ' is a newer relationship'}${c.tags.includes('vip') ? ' — treat as VIP' : ''}.`, by: 'Amara · recent' },
  ];
  const tasks = [];
  if (c.tone === 'rose') tasks.push({ t: `Confirm ${fname}’s payment`, due: 'Fri', done: false });
  if (c.deal) tasks.push({ t: `Move the ${c.co !== '—' ? c.co : fname} deal forward`, due: 'This week', done: false });
  tasks.push({ t: `Quarterly check-in with ${fname}`, due: 'Apr 2', done: false });
  const files = [{ n: `${c.co !== '—' ? c.co.replace(/[^a-z]/gi, '').toLowerCase() : fname.toLowerCase()}-notes.pdf`, type: 'PDF' }];
  const activity = [
    { ic: 'eye', t: 'Opened your last email', s: 'Today · tracked by Pex', tone: 'spark', type: 'email' },
    { ic: 'send', t: c.signal, s: 'Today · by Pex', tone: 'spark', type: /coffee|meet/i.test(c.signal) ? 'meeting' : 'note' },
    ...invoices.slice(0, 2).map(iv => ({ ic: 'dollar', t: `Invoice ${iv.no} · ${window.money(iv.amt)}`, s: iv.status, tone: iv.tone === 'rose' ? 'rose' : 'sage', type: 'note' })),
    { ic: 'phone', t: 'Call logged · discussed next order', s: c.last + ' ago', tone: 'sky', type: 'call' },
  ];
  return { deals, invoices, notes, tasks, files, activity };
}

const ACTIVITY_FILTERS = [
  { k: 'all', label: 'All' },
  { k: 'call', label: 'Calls' },
  { k: 'email', label: 'Emails' },
  { k: 'meeting', label: 'Meetings' },
  { k: 'note', label: 'Notes' },
];

function ContactDetail({ id }) {
  const P = window.PX; const { go, toast, openOverlay } = window.useApp();
  const c = window.PEOPLE.find(p => p.id === id);
  if (!c) return <div style={{ padding: 22 }}><Btn kind="ghost" size="sm" icon="chevL" onClick={() => go('people')}>All contacts</Btn><Empty label="contact — it may have been deleted"/></div>;
  const d = crmFor(c);
  const fname = c.name.split(' ')[0];
  const [tab, setTab] = React.useState('activity');
  const [notes, setNotes] = React.useState(d.notes);
  const [draft, setDraft] = React.useState('');
  const [tasks, setTasks] = React.useState(d.tasks);
  const [taskDraft, setTaskDraft] = React.useState('');
  const [activity, setActivity] = React.useState(d.activity);
  const [files, setFiles] = React.useState(d.files);
  const [actFilter, setActFilter] = React.useState('all');
  const [editDetails, setEditDetails] = React.useState(false);
  const [confirmDel, setConfirmDel] = React.useState(false);
  const [form, setForm] = React.useState({ name: c.name, email: c.email, phone: c.phone || '+1 (718) 555-0142', co: c.co, tags: c.tags, owner: 'Amara', source: 'Referral' });
  const fileInputRef = React.useRef(null);
  React.useEffect(() => {
    setNotes(d.notes); setTasks(d.tasks); setActivity(d.activity); setFiles(d.files);
    setForm({ name: c.name, email: c.email, phone: c.phone || '+1 (718) 555-0142', co: c.co, tags: c.tags, owner: 'Amara', source: 'Referral' });
    setTab('activity'); setActFilter('all'); setEditDetails(false); setDraft(''); setTaskDraft('');
  }, [id]);

  const logActivity = (entry) => setActivity(a => [{ s: 'Just now', ...entry }, ...a]);
  const addNote = () => { if (!draft.trim()) return; setNotes(n => [{ t: draft.trim(), by: 'Amara · just now' }, ...n]); setDraft(''); toast('Note saved to ' + fname + '’s record.', { icon: 'check' }); };
  const toggleTask = (i) => setTasks(ts => ts.map((t, j) => j === i ? { ...t, done: !t.done } : t));
  const addTask = () => { if (!taskDraft.trim()) return; setTasks(ts => [...ts, { t: taskDraft.trim(), due: 'This week', done: false }]); setTaskDraft(''); toast('Task added.', { tone: 'sage', icon: 'check' }); };
  const quickLog = (label, ic, type) => { logActivity({ ic, t: `${label} logged with ${fname}`, tone: 'sky', type }); toast(`${label} logged to ${fname}’s timeline.`, { tone: 'sage', icon: 'check' }); };
  const scheduleFollowUp = () => { logActivity({ ic: 'clock', t: 'Follow-up scheduled for next week', tone: 'spark', type: 'note' }); toast('Follow-up scheduled for next week.', { tone: 'sage', icon: 'check' }); };
  const draftProposal = () => { logActivity({ ic: 'fileText', t: 'Pex drafted a proposal', tone: 'spark', type: 'note' }); toast('Drafting a proposal…', { icon: 'sparkles' }); };
  const uploadFile = (e) => { const f = e.target.files && e.target.files[0]; const n = f ? f.name : `upload-${files.length + 1}.pdf`; const ext = (n.split('.').pop() || 'FILE').toUpperCase(); setFiles(fs => [{ n, type: ext }, ...fs]); logActivity({ ic: 'fileText', t: `File added · ${n}`, tone: 'sky', type: 'note' }); toast('File uploaded.', { tone: 'sage', icon: 'check' }); if (e.target) e.target.value = ''; };
  const removeFile = (i) => { setFiles(fs => fs.filter((_, j) => j !== i)); toast('File removed.', { icon: 'trash' }); };
  const toggleTag = (t) => setForm(f => ({ ...f, tags: f.tags.includes(t) ? f.tags.filter(x => x !== t) : [...f.tags, t] }));
  const saveDetails = () => {
    if (!form.name.trim()) { toast('Name can’t be empty.', { tone: 'rose', icon: 'alert' }); return; }
    window.PXPeople.patchContact(c.id, { name: form.name.trim(), email: form.email.trim(), phone: form.phone.trim(), co: form.co.trim() || '—', tags: form.tags });
    setEditDetails(false); toast('Contact updated.', { tone: 'sage', icon: 'check' });
  };
  const deleteContact = () => { window.PXPeople.removeContact(c.id); setConfirmDel(false); toast(`${c.name} deleted.`, { icon: 'trash' }); go('people'); };

  const stTone = { Won: 'sage', Negotiation: 'spark', Proposal: 'amber', Qualified: 'sky', Lead: 'neutral' };
  const openTasks = tasks.filter(t => !t.done).length;
  const tabs = [{ k: 'activity', label: 'Activity' }, { k: 'deals', label: 'Deals', count: d.deals.length }, { k: 'invoices', label: 'Invoices', count: d.invoices.length }, { k: 'notes', label: 'Notes', count: notes.length }, { k: 'tasks', label: 'Tasks', count: openTasks }, { k: 'files', label: 'Files', count: files.length }];
  const filteredActivity = actFilter === 'all' ? activity : activity.filter(e => e.type === actFilter);
  const ALL_TAGS = ['wholesale', 'class', 'press', 'vip', 'repeat', 'new', 'caterer', 'pastry'];

  return (
    <div style={{ fontFamily: P.sans }}>
      <div style={{ padding: '16px 22px 0' }}>
        <Btn kind="ghost" size="sm" icon="chevL" onClick={() => go('people')}>All contacts</Btn>
      </div>
      <div style={{ padding: '12px 22px 16px', display: 'flex', gap: 16, alignItems: 'center', borderBottom: `1px solid ${P.line}` }}>
        <Avatar name={c.name} size={56}/>
        <div style={{ flex: 1 }}>
          <div style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 28, color: P.ink, letterSpacing: -0.4, lineHeight: 1 }}>{c.name}</div>
          <div style={{ fontSize: 12.5, color: P.ink3, marginTop: 5 }}>{c.role} · <b style={{ color: P.ink2 }}>{c.co}</b> · {c.email}</div>
          <div style={{ display: 'flex', gap: 5, marginTop: 7 }}>{c.tags.map(t => <span key={t} style={{ fontSize: 10, color: P.ink3, background: P.sunk, padding: '2px 7px', borderRadius: 5 }}>#{t}</span>)}</div>
        </div>
        {c.tone === 'rose' && <Pill tone="rose">11d overdue</Pill>}
        <Btn kind="default" size="sm" icon="mail" onClick={() => openOverlay('compose')}>Email</Btn>
        <Btn kind="default" size="sm" icon="phone" onClick={() => { logActivity({ ic: 'phone', t: `Call logged with ${fname}`, tone: 'sky', type: 'call' }); toast(`Calling ${fname}…`, { icon: 'phone' }); }}>Call</Btn>
        <Btn kind="spark" size="sm" icon="dollar" onClick={() => go('money/invoices/new')}>Invoice</Btn>
        <Btn kind="ghost" size="sm" icon="pencil" onClick={() => setEditDetails(true)}>Edit</Btn>
        <Btn kind="ghost" size="sm" icon="trash" onClick={() => setConfirmDel(true)}/>
      </div>

      {/* quick log bar */}
      <div style={{ padding: '10px 22px', borderBottom: `1px solid ${P.line}`, display: 'flex', alignItems: 'center', gap: 8, background: P.canvas }}>
        <span style={{ fontSize: 11.5, color: P.ink3, fontWeight: 600 }}>Log:</span>
        {[['phone', 'Call', 'call'], ['mail', 'Email', 'email'], ['message', 'Meeting', 'meeting'], ['check', 'Task', 'task']].map((a, i) => (
          <div key={i} onClick={() => a[1] === 'Task' ? setTab('tasks') : quickLog(a[1], a[0], a[2])} style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '5px 11px', border: `1px solid ${P.line}`, borderRadius: 8, fontSize: 12, color: P.ink2, cursor: 'pointer', background: P.card }}>
            <Icon name={a[0]} size={13} color={P.ink3}/>{a[1]}
          </div>
        ))}
        <div style={{ flex: 1 }}/>
        <span style={{ fontSize: 11.5, color: P.ink3 }}>Owner <b style={{ color: P.ink2 }}>{form.owner}</b> · Source {form.source}</span>
      </div>

      {/* next step */}
      <div style={{ padding: '11px 22px', borderBottom: `1px solid ${P.line}`, display: 'flex', alignItems: 'center', gap: 12, background: P.sparkWash }}>
        <Pex size={20}/>
        <span style={{ fontSize: 12.5, color: P.ink2, flex: 1 }}><b style={{ color: P.ink }}>Next step:</b> {c.tone === 'rose' ? 'Invoice #1024 is 11 days overdue — send a reminder.' : c.deal ? `Open deal worth ${window.money(c.deal).replace('.00', '')} — move it forward.` : 'No open deal — log a follow-up or send a quote.'}</span>
        <Btn kind="default" size="sm" onClick={() => c.tone === 'rose' ? go('money/invoices/1024') : scheduleFollowUp()}>{c.tone === 'rose' ? 'View invoice' : 'Schedule follow-up'}</Btn>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 320px', gap: 0 }}>
        <div style={{ padding: 22, borderRight: `1px solid ${P.line}`, minWidth: 0 }}>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 12, marginBottom: 18 }}>
            {[['Lifetime', window.money(c.ltv).replace('.00', '')], ['Open deal', c.deal ? window.money(c.deal).replace('.00', '') : '—'], ['Reliability', c.rel + '%'], ['Last contact', c.last]].map((s, i) => (
              <Card key={i} pad={12}><Label>{s[0]}</Label><Num size={18} style={{ marginTop: 4 }}>{s[1]}</Num></Card>
            ))}
          </div>
          <Tabs tabs={tabs} active={tab} onChange={setTab} style={{ marginBottom: 16 }}/>

          {tab === 'activity' && (
            <>
              <div style={{ display: 'flex', gap: 6, marginBottom: 14 }}>
                {ACTIVITY_FILTERS.map(f => {
                  const on = actFilter === f.k;
                  return (
                    <div key={f.k} onClick={() => setActFilter(f.k)} style={{ padding: '5px 12px', borderRadius: 999, fontSize: 12, fontWeight: on ? 600 : 500, cursor: 'pointer', background: on ? P.ink : P.sunk, color: on ? '#fff' : P.ink2 }}>{f.label}</div>
                  );
                })}
              </div>
              {filteredActivity.length ? filteredActivity.map((e, i) => (
                <div key={i} style={{ display: 'flex', gap: 12, padding: '11px 0', borderBottom: i < filteredActivity.length - 1 ? `1px solid ${P.line}` : 'none' }}>
                  <div style={{ width: 30, height: 30, borderRadius: 8, background: P[e.tone + 'Tint'], color: P[e.tone], display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name={e.ic} size={14}/></div>
                  <div style={{ flex: 1 }}><div style={{ fontSize: 13, color: P.ink, lineHeight: 1.4 }}>{e.t}</div><div style={{ fontSize: 11, color: P.ink3, marginTop: 2 }}>{e.s}</div></div>
                </div>
              )) : <Empty label={actFilter === 'all' ? 'activity' : ACTIVITY_FILTERS.find(f => f.k === actFilter).label.toLowerCase()}/>}
            </>
          )}

          {tab === 'deals' && (d.deals.length ? d.deals.map((dl, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 0', borderBottom: i < d.deals.length - 1 ? `1px solid ${P.line}` : 'none' }}>
              <div style={{ width: 3, alignSelf: 'stretch', minHeight: 28, background: P[dl.tone], borderRadius: 3 }}/>
              <div style={{ flex: 1 }}><div style={{ fontSize: 13.5, color: P.ink, fontWeight: 500 }}>{dl.name}</div><div style={{ fontSize: 11, color: P.ink3 }}>{dl.stage}</div></div>
              <Pill tone={stTone[dl.stage] || 'neutral'}>{dl.stage}</Pill>
              <Num size={17}>{window.money(dl.value).replace('.00', '')}</Num>
            </div>
          )) : <Empty label="deals"/>)}

          {tab === 'invoices' && (d.invoices.length ? d.invoices.map((iv, i) => (
            <div key={i} onClick={() => go('money/invoices')} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 0', borderBottom: i < d.invoices.length - 1 ? `1px solid ${P.line}` : 'none', cursor: 'pointer' }}>
              <span style={{ fontFamily: P.mono, fontSize: 12.5, color: P.ink2, width: 50 }}>{iv.no}</span>
              <span style={{ flex: 1 }}><Pill tone={iv.tone}>{iv.status}</Pill></span>
              <Num size={17} color={iv.tone === 'rose' ? P.rose : P.ink}>{window.money(iv.amt).replace('.00', '')}</Num>
            </div>
          )) : <Empty label="invoices"/>)}

          {tab === 'notes' && (
            <div>
              <div style={{ display: 'flex', gap: 8, marginBottom: 14 }}>
                <input value={draft} onChange={e => setDraft(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') addNote(); }} placeholder={`Add a note about ${c.name.split(' ')[0]}…`} style={{ flex: 1, border: `1px solid ${P.lineStrong}`, borderRadius: 9, padding: '9px 12px', fontSize: 13, color: P.ink, fontFamily: P.sans, outline: 'none' }}/>
                <Btn kind="spark" size="md" onClick={addNote}>Add</Btn>
              </div>
              {notes.map((n, i) => (
                <div key={i} style={{ padding: '11px 0', borderBottom: i < notes.length - 1 ? `1px solid ${P.line}` : 'none' }}>
                  <div style={{ fontSize: 13, color: P.ink, lineHeight: 1.5 }}>{n.t}</div>
                  <div style={{ fontSize: 11, color: P.ink3, marginTop: 3 }}>{n.by}</div>
                </div>
              ))}
            </div>
          )}

          {tab === 'tasks' && (
            <div>
              {tasks.map((t, i) => (
                <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '11px 0', borderBottom: i < tasks.length - 1 ? `1px solid ${P.line}` : 'none' }}>
                  <span onClick={() => toggleTask(i)} style={{ width: 18, height: 18, borderRadius: 5, border: `1.5px solid ${t.done ? P.sage : P.lineStrong}`, background: t.done ? P.sage : 'transparent', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, cursor: 'pointer' }}>{t.done && <Icon name="check" size={11} color="#fff" stroke={3}/>}</span>
                  <span style={{ flex: 1, fontSize: 13, color: t.done ? P.ink3 : P.ink, textDecoration: t.done ? 'line-through' : 'none' }}>{t.t}</span>
                  <Pill tone={t.due === 'Today' ? 'rose' : t.due === 'Fri' || t.due === 'This week' ? 'amber' : 'neutral'}>{t.due}</Pill>
                </div>
              ))}
              <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
                <input value={taskDraft} onChange={e => setTaskDraft(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') addTask(); }} placeholder={`Add a task for ${fname}…`} style={{ flex: 1, border: `1px solid ${P.lineStrong}`, borderRadius: 9, padding: '9px 12px', fontSize: 13, color: P.ink, fontFamily: P.sans, outline: 'none' }}/>
                <Btn kind="spark" size="md" icon="plus" onClick={addTask}>Add</Btn>
              </div>
            </div>
          )}

          {tab === 'files' && (
            <div>
              <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 8 }}>
                <input ref={fileInputRef} type="file" style={{ display: 'none' }} onChange={uploadFile}/>
                <Btn kind="default" size="sm" icon="upload" onClick={() => fileInputRef.current && fileInputRef.current.click()}>Upload file</Btn>
              </div>
              {files.length ? files.map((f, i) => (
                <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 11, padding: '11px 0', borderBottom: i < files.length - 1 ? `1px solid ${P.line}` : 'none' }}>
                  <div style={{ width: 30, height: 30, borderRadius: 8, background: P.sunk, color: P.ink2, display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name="fileText" size={15}/></div>
                  <span style={{ flex: 1, fontSize: 13, color: P.ink }}>{f.n}</span>
                  <span style={{ fontSize: 11, color: P.ink3 }}>{f.type}</span>
                  <span onClick={() => toast(`Downloading ${f.n}…`, { icon: 'download' })} style={{ cursor: 'pointer', display: 'inline-flex' }}><Icon name="download" size={15} color={P.ink3}/></span>
                  <span onClick={() => removeFile(i)} style={{ cursor: 'pointer', display: 'inline-flex' }}><Icon name="trash" size={15} color={P.ink3}/></span>
                </div>
              )) : <Empty label="files"/>}
            </div>
          )}
        </div>

        <div style={{ padding: 18 }}>
          <Card pad={14} style={{ marginBottom: 14, background: P.sparkWash, border: `1px solid ${P.sparkTint}` }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 7, marginBottom: 7 }}><Pex size={18}/><span style={{ fontSize: 13, fontWeight: 600, color: P.ink }}>Opportunity</span></div>
            <div style={{ fontSize: 12.5, color: P.ink2, lineHeight: 1.5 }}>{c.id === 'marc' ? <>Marc has been a 2× client since 2022 and never late before. His reply mentions wanting <b>15 loaves</b> (up from 10) — that’s <b style={{ color: P.sage }}>+$728/mo</b>.</> : <>{c.name.split(' ')[0]} {c.tags.includes('repeat') ? 'orders regularly' : 'is worth nurturing'} — reliability {c.rel}%. {c.deal ? `An open ${window.money(c.deal).replace('.00','')} deal is on the table.` : 'No open deal yet — good time to send a quote.'}</>}</div>
            <Btn kind="default" size="sm" full style={{ marginTop: 10 }} onClick={draftProposal}>Pex: draft a proposal · 2 ⚡</Btn>
          </Card>
          <Card pad={14}>
            <div style={{ display: 'flex', alignItems: 'center', marginBottom: 8 }}>
              <Label style={{ flex: 1 }}>Details</Label>
              {!editDetails && <span onClick={() => setEditDetails(true)} style={{ fontSize: 11.5, color: P.spark, cursor: 'pointer', fontWeight: 600 }}>Edit</span>}
            </div>
            {editDetails ? (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                <Field label="Name" value={form.name} onChange={v => setForm(f => ({ ...f, name: v }))}/>
                <Field label="Email" value={form.email} onChange={v => setForm(f => ({ ...f, email: v }))} icon="mail"/>
                <Field label="Phone" value={form.phone} onChange={v => setForm(f => ({ ...f, phone: v }))} icon="phone"/>
                <Field label="Company" value={form.co} onChange={v => setForm(f => ({ ...f, co: v }))} icon="building"/>
                <Field label="Owner" value={form.owner} onChange={v => setForm(f => ({ ...f, owner: v }))}/>
                <Field label="Source" value={form.source} onChange={v => setForm(f => ({ ...f, source: v }))}/>
                <div>
                  <div style={{ fontSize: 12, color: P.ink3, marginBottom: 6, fontWeight: 500 }}>Tags</div>
                  <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>{ALL_TAGS.map(t => <Pill key={t} tone="neutral" on={form.tags.includes(t)} onClick={() => toggleTag(t)} style={{ padding: '3px 9px' }}>#{t}</Pill>)}</div>
                </div>
                <div style={{ display: 'flex', gap: 8, marginTop: 4 }}>
                  <Btn kind="ghost" size="sm" onClick={() => { setEditDetails(false); setForm({ name: c.name, email: c.email, phone: c.phone || '+1 (718) 555-0142', co: c.co, tags: c.tags, owner: form.owner, source: form.source }); }}>Cancel</Btn>
                  <div style={{ flex: 1 }}/>
                  <Btn kind="primary" size="sm" icon="check" onClick={saveDetails}>Save</Btn>
                </div>
              </div>
            ) : (
              [['Email', form.email], ['Phone', form.phone], ['Company', form.co], ['Owner', form.owner], ['Source', form.source], ['Created', 'Jan 2023']].map((dt, i) => (
                <div key={i} style={{ display: 'flex', padding: '6px 0', fontSize: 12.5, borderBottom: i < 5 ? `1px solid ${P.line}` : 'none' }}><span style={{ width: 74, color: P.ink3 }}>{dt[0]}</span><span style={{ flex: 1, color: P.ink, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis' }}>{dt[1]}</span></div>
              ))
            )}
          </Card>
        </div>
      </div>
      {confirmDel && (
        <window.Modal title="Delete contact?" sub={`${c.name} will be removed from People. This can’t be undone.`} w={440} onClose={() => setConfirmDel(false)}
          foot={<><Btn kind="ghost" onClick={() => setConfirmDel(false)}>Cancel</Btn><div style={{ flex: 1 }}/><Btn kind="danger" icon="trash" onClick={deleteContact}>Delete contact</Btn></>}>
          <div style={{ fontSize: 13, color: P.ink2, lineHeight: 1.5 }}>Deleting <b style={{ color: P.ink }}>{c.name}</b> removes their timeline, notes, and tasks from this prototype session.</div>
        </window.Modal>
      )}
    </div>
  );
}

function Empty({ label }) { const P = window.PX; return <div style={{ padding: '36px 0', textAlign: 'center', color: P.ink3, fontSize: 13 }}>No {label} yet.</div>; }

// ── TASKS · follow-ups across the CRM ─────────────────────────
function CRMTasks() {
  const P = window.PX; const { go, toast } = window.useApp();
  const [tasks, setTasks] = React.useState([
    { who: 'marc', name: 'Marc Lefèvre', t: 'Send the 15-loaf price sheet', due: 'Today', group: 'Today', done: false },
    { who: 'ahmad', name: 'Ahmad Saleh', t: 'Follow up on sample delivery', due: 'Today', group: 'Today', done: false },
    { who: 'marcus', name: 'Marcus Chen', t: 'Send wholesale proposal', due: 'Tomorrow', group: 'This week', done: false },
    { who: 'noor', name: 'Noor Hassan', t: 'Re-engage — going quiet 2 weeks', due: 'Wed', group: 'This week', done: false },
    { who: 'jenna', name: 'Jenna Ruiz', t: 'Confirm podcast recording date', due: 'Fri', group: 'This week', done: false },
    { who: 'sofia', name: 'Sofia Martins', t: 'Invite to April class', due: 'Apr 11', group: 'Later', done: true },
    { who: 'david', name: 'David Park', t: 'Send Q2 wholesale agreement', due: 'Apr 1', group: 'Later', done: false },
  ]);
  const [showNew, setShowNew] = React.useState(false);
  const toggle = (i) => setTasks(ts => ts.map((t, j) => j === i ? { ...t, done: !t.done } : t));
  const addTask = (t) => setTasks(ts => [...ts, t]);
  const queuePex = () => {
    const quiet = [
      { who: 'noor', name: 'Noor Hassan', t: 'Re-engage — no reply in 2 weeks', due: 'Today', group: 'Today', done: false },
      { who: 'sofia', name: 'Sofia Martins', t: 'Invite back for a spring class', due: 'Wed', group: 'This week', done: false },
      { who: 'jenna', name: 'Jenna Ruiz', t: 'Nudge on the coffee reschedule', due: 'Fri', group: 'This week', done: false },
    ];
    setTasks(ts => [...ts, ...quiet]);
    toast('Pex queued 3 follow-ups for quiet contacts.', { tone: 'sage', icon: 'check' });
  };
  const groups = ['Today', 'This week', 'Later'];
  const open = tasks.filter(t => !t.done).length;
  return (
    <div style={{ fontFamily: P.sans, padding: 22 }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', marginBottom: 18 }}>
        <div style={{ flex: 1 }}><div style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 26, color: P.ink }}>Tasks &amp; follow-ups</div><div style={{ fontSize: 12.5, color: P.ink3 }}>{open} open · across your pipeline</div></div>
        <Btn kind="default" size="sm" icon="sparkles" onClick={queuePex}>Let Pex queue follow-ups</Btn>
        <Btn kind="spark" size="sm" icon="plus" style={{ marginLeft: 8 }} onClick={() => setShowNew(true)}>New task</Btn>
      </div>
      {showNew && <NewTaskModal onClose={() => setShowNew(false)} onSave={(t) => { addTask(t); setShowNew(false); toast('Task added.', { tone: 'sage', icon: 'check' }); }}/>}
      {groups.map(g => {
        const items = tasks.map((t, i) => ({ ...t, i })).filter(t => t.group === g);
        if (!items.length) return null;
        return (
          <div key={g} style={{ marginBottom: 18 }}>
            <Label style={{ marginBottom: 8 }}>{g} · {items.filter(t => !t.done).length}</Label>
            <Card pad={0}>
              {items.map((t, j) => (
                <div key={t.i} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 16px', borderBottom: j < items.length - 1 ? `1px solid ${P.line}` : 'none' }}>
                  <span onClick={() => toggle(t.i)} style={{ width: 18, height: 18, borderRadius: 5, border: `1.5px solid ${t.done ? P.sage : P.lineStrong}`, background: t.done ? P.sage : 'transparent', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, cursor: 'pointer' }}>{t.done && <Icon name="check" size={11} color="#fff" stroke={3}/>}</span>
                  <div onClick={() => go('people/' + t.who)} style={{ flex: 1, cursor: 'pointer' }}>
                    <div style={{ fontSize: 13.5, color: t.done ? P.ink3 : P.ink, fontWeight: 500, textDecoration: t.done ? 'line-through' : 'none' }}>{t.t}</div>
                    <div style={{ fontSize: 11.5, color: P.ink3, display: 'flex', alignItems: 'center', gap: 5, marginTop: 2 }}><Avatar name={t.name} size={15}/>{t.name}</div>
                  </div>
                  <Pill tone={t.group === 'Today' ? 'rose' : t.group === 'This week' ? 'amber' : 'neutral'}>{t.due}</Pill>
                </div>
              ))}
            </Card>
          </div>
        );
      })}
    </div>
  );
}

// ── New task modal — pick a contact, write the task, set when ──
function NewTaskModal({ onClose, onSave }) {
  const P = window.PX;
  const people = window.PEOPLE;
  const [who, setWho] = React.useState(people[0] ? people[0].id : '');
  const [text, setText] = React.useState('');
  const [group, setGroup] = React.useState('Today');
  const dueFor = { Today: 'Today', 'This week': 'This week', Later: 'Next month' };
  const save = () => {
    if (!text.trim()) return;
    const p = people.find(x => x.id === who);
    onSave({ who, name: p ? p.name : 'Unassigned', t: text.trim(), due: dueFor[group], group, done: false });
  };
  return (
    <window.Modal title="New task" sub="Add a follow-up to your CRM" w={520} onClose={onClose}
      foot={<><Btn kind="ghost" onClick={onClose}>Cancel</Btn><div style={{ flex: 1 }}/><Btn kind="primary" icon="check" disabled={!text.trim()} onClick={save}>Add task</Btn></>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <Field label="Task" placeholder="e.g. Send the wholesale price sheet" value={text} onChange={setText}/>
        <Select label="Contact" value={who} onChange={setWho} options={people.map(p => ({ v: p.id, label: p.name + (p.co && p.co !== '—' ? ' · ' + p.co : '') }))}/>
        <div>
          <div style={{ fontSize: 12, color: P.ink3, marginBottom: 6, fontWeight: 500 }}>When</div>
          <Chips options={['Today', 'This week', 'Later']} value={group} onChange={setGroup}/>
        </div>
      </div>
    </window.Modal>
  );
}

// ── PIPELINE · draggable kanban ─────────────────────────────────
const PIPELINE_STAGES = ['Lead', 'Qualified', 'Proposal', 'Negotiation', 'Won'];

function Pipeline({ deals, setDeals, onOpen }) {
  const P = window.PX; const { toast } = window.useApp();
  const stageColor = { Lead: P.ink4, Qualified: P.sky, Proposal: P.amber, Negotiation: P.spark, Won: P.sage };
  const [dragOver, setDragOver] = React.useState(null);
  const [newStage, setNewStage] = React.useState(null);
  const openDeals = deals.filter(d => d.stage !== 'Won' && d.stage !== 'Lost');
  const openTotal = openDeals.reduce((a, d) => a + d.value, 0);

  const addDeal = (deal) => { setDeals(ds => [deal, ...ds]); setNewStage(null); toast(`Deal added to ${deal.stage}.`, { tone: 'sage', icon: 'check' }); };

  const moveDeal = (dealId, stage) => {
    setDeals(ds => ds.map(d => {
      if (d.id !== dealId || d.stage === stage) return d;
      return { ...d, stage, activity: [{ ic: 'layout', t: `Moved to ${stage}`, s: 'Just now', tone: 'spark' }, ...d.activity] };
    }));
  };
  const onDrop = (e, stage) => { e.preventDefault(); setDragOver(null); const id = e.dataTransfer.getData('text/plain'); if (id) moveDeal(id, stage); };

  return (
    <div style={{ fontFamily: P.sans, padding: 22, height: '100%' }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', marginBottom: 18 }}>
        <div style={{ flex: 1 }}><div style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 26, color: P.ink }}>Pipeline</div><div style={{ fontSize: 12.5, color: P.ink3 }}>{window.money(openTotal).replace('.00', '')} open across {openDeals.length} deals · drag a card to change its stage</div></div>
        <Btn kind="primary" size="sm" icon="plus" onClick={() => setNewStage('Lead')}>New deal</Btn>
      </div>
      {newStage && <NewDealModal stage={newStage} onClose={() => setNewStage(null)} onSave={addDeal}/>}
      <div style={{ display: 'flex', gap: 12, overflowX: 'auto', paddingBottom: 8 }}>
        {PIPELINE_STAGES.map(stage => {
          const items = deals.filter(d => d.stage === stage);
          const total = items.reduce((a, d) => a + d.value, 0);
          const isOver = dragOver === stage;
          return (
            <div key={stage}
              onDragOver={e => { e.preventDefault(); if (dragOver !== stage) setDragOver(stage); }}
              onDragLeave={() => setDragOver(o => o === stage ? null : o)}
              onDrop={e => onDrop(e, stage)}
              style={{ width: 230, flexShrink: 0, borderRadius: 12, background: isOver ? P.sparkWash : 'transparent', outline: isOver ? `1.5px dashed ${P.spark}` : 'none', transition: 'background .12s' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4, padding: '0 2px' }}>
                <span style={{ width: 8, height: 8, borderRadius: 8, background: stageColor[stage] }}/>
                <span style={{ fontSize: 12.5, fontWeight: 600, color: P.ink, flex: 1 }}>{stage}</span>
                <span style={{ fontSize: 11, color: P.ink3 }}>{items.length}</span>
              </div>
              <div style={{ fontFamily: P.mono, fontSize: 11.5, color: P.ink3, padding: '0 2px', marginBottom: 10 }}>{total ? window.money(total).replace('.00', '') : '—'}</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8, minHeight: 44 }}>
                {items.map(d => (
                  <div key={d.id} draggable
                    onDragStart={e => { e.dataTransfer.setData('text/plain', d.id); e.dataTransfer.effectAllowed = 'move'; }}
                    onClick={() => onOpen(d.id)}
                    onMouseEnter={e => e.currentTarget.style.boxShadow = P.shMd} onMouseLeave={e => e.currentTarget.style.boxShadow = P.shSm}
                    style={{ background: P.card, border: `1px solid ${P.line}`, borderLeft: `3px solid ${stageColor[stage]}`, borderRadius: P.rCard, boxShadow: P.shSm, padding: 11, cursor: 'grab', transition: 'box-shadow .15s' }}>
                    <div style={{ fontSize: 12.5, color: P.ink, fontWeight: 500, lineHeight: 1.3 }}>{d.name}</div>
                    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 7 }}>
                      <span style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 14, color: P.ink }}>{d.value ? window.money(d.value).replace('.00', '') : '—'}</span>
                      {d.contactId && <Avatar name={window.PEOPLE.find(p => p.id === d.contactId).name} size={18}/>}
                    </div>
                  </div>
                ))}
                <div onClick={() => setNewStage(stage)} style={{ padding: 9, border: `1px dashed ${P.lineStrong}`, borderRadius: 9, fontSize: 11.5, color: P.ink3, textAlign: 'center', cursor: 'pointer' }}>+ Add</div>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ── New deal modal — name, value, stage, optional linked contact ──
function NewDealModal({ stage, onClose, onSave }) {
  const P = window.PX;
  const people = window.PEOPLE;
  const [name, setName] = React.useState('');
  const [value, setValue] = React.useState('');
  const [st, setSt] = React.useState(stage || 'Lead');
  const [contactId, setContactId] = React.useState('');
  const save = () => {
    if (!name.trim()) return;
    const num = Math.max(0, Math.round(Number(String(value).replace(/[^0-9.]/g, '')) || 0));
    onSave({ id: window.pxid('d'), name: name.trim(), stage: st, value: num, contactId: contactId || null, notes: '', winLossReason: null,
      activity: [{ ic: 'sparkles', t: 'Deal created', s: 'Just now', tone: 'spark' }] });
  };
  return (
    <window.Modal title="New deal" sub="Add an opportunity to your pipeline" w={520} onClose={onClose}
      foot={<><Btn kind="ghost" onClick={onClose}>Cancel</Btn><div style={{ flex: 1 }}/><Btn kind="primary" icon="check" disabled={!name.trim()} onClick={save}>Add deal</Btn></>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <Field label="Deal name" placeholder="e.g. Café Bleu · wholesale renewal" value={name} onChange={setName}/>
        <Field label="Value" placeholder="0" icon="dollar" mono value={value} onChange={setValue}/>
        <div>
          <div style={{ fontSize: 12, color: P.ink3, marginBottom: 6, fontWeight: 500 }}>Stage</div>
          <Chips options={PIPELINE_STAGES} value={st} onChange={setSt}/>
        </div>
        <Select label="Linked contact (optional)" value={contactId} onChange={setContactId} placeholder="No contact" options={people.map(p => ({ v: p.id, label: p.name + (p.co && p.co !== '—' ? ' · ' + p.co : '') }))}/>
      </div>
    </window.Modal>
  );
}

const COMPANIES_SEED = [
  { id: 'co-cafebleu', name: 'Café Bleu', kind: 'Wholesale', contacts: 3, value: 28420 },
  { id: 'co-parkbros', name: 'Park Bros. Hotel', kind: 'Hospitality', contacts: 5, value: 24000 },
  { id: 'co-lila', name: 'Lila Events', kind: 'Catering', contacts: 2, value: 9200 },
  { id: 'co-greenpoint', name: 'Greenpoint Market', kind: 'Retail', contacts: 1, value: 6400 },
  { id: 'co-bkcoop', name: 'BK Food Co-op', kind: 'Retail', contacts: 2, value: 3600 },
];
const COMPANY_KINDS = ['Wholesale', 'Hospitality', 'Catering', 'Retail', 'Other'];

function Companies() {
  const P = window.PX; const { toast } = window.useApp();
  const [cos, setCos] = React.useState(COMPANIES_SEED);
  const [openId, setOpenId] = React.useState(null);
  const [showNew, setShowNew] = React.useState(false);
  const open = cos.find(c => c.id === openId);
  const total = cos.reduce((a, c) => a + c.value, 0);
  const addCompany = (co) => { setCos(cs => [{ ...co, id: window.pxid('co') }, ...cs]); setShowNew(false); toast(`${co.name} added.`, { tone: 'sage', icon: 'check' }); };
  const patchCompany = (id, patch) => setCos(cs => cs.map(c => c.id === id ? { ...c, ...patch } : c));
  const removeCompany = (id) => { setCos(cs => cs.filter(c => c.id !== id)); setOpenId(null); toast('Company removed.', { icon: 'trash' }); };
  return (
    <div style={{ fontFamily: P.sans, padding: 22 }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', marginBottom: 16 }}>
        <div style={{ flex: 1 }}><div style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 26, color: P.ink }}>Companies</div><div style={{ fontSize: 12.5, color: P.ink3 }}>{cos.length} companies · {window.money(total).replace('.00', '')} lifetime value</div></div>
        <Btn kind="primary" size="sm" icon="plus" onClick={() => setShowNew(true)}>Add company</Btn>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3,1fr)', gap: 14 }}>
        {cos.map((c) => (
          <Card key={c.id} pad={16} hover onClick={() => setOpenId(c.id)}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 11, marginBottom: 12 }}>
              <div style={{ width: 40, height: 40, borderRadius: 10, background: P.sunk, display: 'flex', alignItems: 'center', justifyContent: 'center', color: P.ink2 }}><Icon name="building" size={19}/></div>
              <div><div style={{ fontSize: 14, fontWeight: 600, color: P.ink }}>{c.name}</div><div style={{ fontSize: 11.5, color: P.ink3 }}>{c.kind}</div></div>
            </div>
            <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12, color: P.ink3 }}><span>{c.contacts} contact{c.contacts === 1 ? '' : 's'}</span><span style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 16, color: P.ink }}>{window.money(c.value).replace('.00', '')}</span></div>
          </Card>
        ))}
      </div>
      {open && <CompanyDrawer company={open} onClose={() => setOpenId(null)} onSave={patchCompany} onRemove={removeCompany}/>}
      {showNew && <CompanyModal onClose={() => setShowNew(false)} onSave={addCompany}/>}
    </div>
  );
}

function CompanyDrawer({ company, onClose, onSave, onRemove }) {
  const P = window.PX; const { go, toast } = window.useApp();
  const [edit, setEdit] = React.useState(false);
  const [form, setForm] = React.useState({ name: company.name, kind: company.kind, value: String(company.value) });
  React.useEffect(() => { setForm({ name: company.name, kind: company.kind, value: String(company.value) }); setEdit(false); }, [company.id]);
  const linked = window.PEOPLE.filter(p => (p.co || '').toLowerCase() === company.name.toLowerCase());
  const save = () => { onSave(company.id, { name: form.name.trim() || company.name, kind: form.kind, value: Math.max(0, Math.round(Number(form.value.replace(/[^0-9.]/g, '')) || 0)) }); setEdit(false); toast('Company updated.', { tone: 'sage', icon: 'check' }); };
  return (
    <window.Drawer title={company.name} sub={`${company.kind} · ${company.contacts} contact${company.contacts === 1 ? '' : 's'}`} tag={<Pill tone="plum">Company</Pill>} onClose={onClose}
      foot={<><Btn kind="danger" size="sm" icon="trash" onClick={() => onRemove(company.id)}>Remove</Btn><div style={{ flex: 1 }}/>{edit ? <><Btn kind="ghost" size="sm" onClick={() => setEdit(false)}>Cancel</Btn><Btn kind="primary" size="sm" icon="check" onClick={save}>Save</Btn></> : <Btn kind="default" size="sm" icon="pencil" onClick={() => setEdit(true)}>Edit</Btn>}</>}>
      <Num size={28} style={{ marginBottom: 18 }}>{window.money(company.value).replace('.00', '')}</Num>
      {edit ? (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14, marginBottom: 18 }}>
          <Field label="Company name" value={form.name} onChange={v => setForm(f => ({ ...f, name: v }))}/>
          <Select label="Type" value={form.kind} onChange={v => setForm(f => ({ ...f, kind: v }))} options={COMPANY_KINDS}/>
          <Field label="Lifetime value" icon="dollar" mono value={form.value} onChange={v => setForm(f => ({ ...f, value: v }))}/>
        </div>
      ) : (
        <Card pad={14} style={{ marginBottom: 16 }}>
          {[['Type', company.kind], ['Contacts', String(company.contacts)], ['Lifetime value', window.money(company.value).replace('.00', '')]].map((r, i) => (
            <div key={i} style={{ display: 'flex', padding: '6px 0', fontSize: 12.5, borderBottom: i < 2 ? `1px solid ${P.line}` : 'none' }}><span style={{ width: 100, color: P.ink3 }}>{r[0]}</span><span style={{ flex: 1, color: P.ink }}>{r[1]}</span></div>
          ))}
        </Card>
      )}
      <Label style={{ marginBottom: 8 }}>People at {company.name}</Label>
      {linked.length ? linked.map(p => (
        <Card key={p.id} pad={12} hover onClick={() => { onClose(); go('people/' + p.id); }} style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
          <Avatar name={p.name} size={30}/>
          <div style={{ flex: 1 }}><div style={{ fontSize: 13, fontWeight: 500, color: P.ink }}>{p.name}</div><div style={{ fontSize: 11.5, color: P.ink3 }}>{p.role}</div></div>
          <Icon name="chevR" size={15} color={P.ink4}/>
        </Card>
      )) : <div style={{ fontSize: 12.5, color: P.ink3 }}>No contacts linked to this company yet.</div>}
    </window.Drawer>
  );
}

function CompanyModal({ onClose, onSave }) {
  const P = window.PX;
  const [name, setName] = React.useState('');
  const [kind, setKind] = React.useState('Wholesale');
  const [value, setValue] = React.useState('');
  const save = () => { if (!name.trim()) return; onSave({ name: name.trim(), kind, contacts: 0, value: Math.max(0, Math.round(Number(String(value).replace(/[^0-9.]/g, '')) || 0)) }); };
  return (
    <window.Modal title="Add a company" w={500} onClose={onClose}
      foot={<><Btn kind="ghost" onClick={onClose}>Cancel</Btn><div style={{ flex: 1 }}/><Btn kind="primary" icon="check" disabled={!name.trim()} onClick={save}>Add company</Btn></>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        <Field label="Company name" placeholder="e.g. Corner Coffee" icon="building" value={name} onChange={setName}/>
        <Select label="Type" value={kind} onChange={setKind} options={COMPANY_KINDS}/>
        <Field label="Lifetime value (optional)" placeholder="0" icon="dollar" mono value={value} onChange={setValue}/>
      </div>
    </window.Modal>
  );
}

// ── DEALS · list view, opens the shared deal detail drawer ─────
function Deals({ deals, onOpen }) {
  const P = window.PX;
  const stTone = { Lead: 'neutral', Qualified: 'sky', Proposal: 'amber', Negotiation: 'spark', Won: 'sage', Lost: 'rose' };
  const barColor = { Lead: P.ink4, Qualified: P.sky, Proposal: P.amber, Negotiation: P.spark, Won: P.sage, Lost: P.rose };
  const open = deals.filter(d => d.stage !== 'Won' && d.stage !== 'Lost');
  const openTotal = open.reduce((a, d) => a + d.value, 0);
  return (
    <div style={{ fontFamily: P.sans, padding: 22 }}>
      <div style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 26, color: P.ink, marginBottom: 4 }}>Deals</div>
      <div style={{ fontSize: 12.5, color: P.ink3, marginBottom: 16 }}>{deals.length} deals · {window.money(openTotal).replace('.00', '')} open across {open.length}</div>
      <Card>
        {deals.map((d, i) => (
          <div key={d.id} onClick={() => onOpen(d.id)} style={{ padding: '14px 18px', display: 'flex', alignItems: 'center', gap: 14, borderBottom: i < deals.length - 1 ? `1px solid ${P.line}` : 'none', cursor: 'pointer' }}
            onMouseEnter={e => e.currentTarget.style.background = P.hover} onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
            <div style={{ width: 3, height: 30, background: barColor[d.stage], borderRadius: 3 }}/>
            <span style={{ flex: 1, fontSize: 13.5, color: P.ink, fontWeight: 500 }}>{d.name}</span>
            <Pill tone={stTone[d.stage]}>{d.stage}</Pill>
            <Num size={18}>{money(d.value).replace('.00', '')}</Num>
            <Icon name="chevR" size={15} color={P.ink4}/>
          </div>
        ))}
      </Card>
    </div>
  );
}

// ── Deal detail drawer — value/stage, linked contact, notes, history, win/loss reason ──
const DEAL_STAGES_ALL = ['Lead', 'Qualified', 'Proposal', 'Negotiation', 'Won', 'Lost'];
const WIN_LOSS_REASONS = ['Price', 'Timing', 'Competitor', 'No budget', 'Other'];

function DealDetail({ id, deals, setDeals, onClose }) {
  const P = window.PX; const { go, toast } = window.useApp();
  const deal = deals.find(d => d.id === id);
  const [notesDraft, setNotesDraft] = React.useState(deal ? deal.notes : '');
  React.useEffect(() => { setNotesDraft(deal ? deal.notes : ''); }, [id]);
  if (!deal) return null;
  const contact = deal.contactId ? window.PEOPLE.find(p => p.id === deal.contactId) : null;
  const stTone = { Lead: 'neutral', Qualified: 'sky', Proposal: 'amber', Negotiation: 'spark', Won: 'sage', Lost: 'rose' };

  const log = (text, tone) => setDeals(ds => ds.map(d => d.id === id ? { ...d, activity: [{ ic: 'check', t: text, s: 'Just now', tone: tone || 'spark' }, ...d.activity] } : d));

  const setStage = (s) => {
    if (s === deal.stage) return;
    setDeals(ds => ds.map(d => d.id === id ? { ...d, stage: s, winLossReason: (s === 'Won' || s === 'Lost') ? d.winLossReason : null } : d));
    log(`Stage changed to ${s}`, s === 'Won' ? 'sage' : s === 'Lost' ? 'rose' : 'spark');
    toast(`Deal moved to ${s}.`, { icon: 'check', tone: s === 'Won' ? 'sage' : undefined });
  };
  const setReason = (r) => {
    setDeals(ds => ds.map(d => d.id === id ? { ...d, winLossReason: r } : d));
    log(`${deal.stage} reason: ${r}`, deal.stage === 'Won' ? 'sage' : 'rose');
    toast(`Marked ${deal.stage.toLowerCase()} · ${r}`, { tone: deal.stage === 'Won' ? 'sage' : 'rose', icon: deal.stage === 'Won' ? 'check' : 'x' });
  };
  const saveNotes = () => {
    if (notesDraft === deal.notes) return;
    setDeals(ds => ds.map(d => d.id === id ? { ...d, notes: notesDraft } : d));
    toast('Notes saved.', { icon: 'check' });
  };

  return (
    <window.Drawer title={deal.name} sub={contact ? `${contact.name} · ${contact.co}` : 'No linked contact'} tag={<Pill tone={stTone[deal.stage]}>{deal.stage}</Pill>} onClose={onClose}>
      <Num size={30} style={{ marginBottom: 18 }}>{window.money(deal.value).replace('.00', '')}</Num>

      {contact ? (
        <Card pad={12} hover onClick={() => { onClose(); go('people/' + contact.id); }} style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 18 }}>
          <Avatar name={contact.name} size={32}/>
          <div style={{ flex: 1 }}><div style={{ fontSize: 13, fontWeight: 500, color: P.ink }}>{contact.name}</div><div style={{ fontSize: 11.5, color: P.ink3 }}>{contact.role} · {contact.co}</div></div>
          <Icon name="chevR" size={15} color={P.ink4}/>
        </Card>
      ) : (
        <div style={{ fontSize: 12.5, color: P.ink3, marginBottom: 18 }}>No contact linked to this deal yet.</div>
      )}

      <Label style={{ marginBottom: 8 }}>Stage</Label>
      <div style={{ marginBottom: 18 }}><Chips options={DEAL_STAGES_ALL} value={deal.stage} onChange={setStage} toneFor={s => stTone[s]}/></div>

      {(deal.stage === 'Won' || deal.stage === 'Lost') && (
        <div style={{ marginBottom: 18 }}>
          <Label style={{ marginBottom: 8 }}>{deal.stage} reason</Label>
          <Chips options={WIN_LOSS_REASONS} value={deal.winLossReason} onChange={setReason}/>
        </div>
      )}

      <Label style={{ marginBottom: 8 }}>Notes</Label>
      <textarea value={notesDraft} onChange={e => setNotesDraft(e.target.value)} onBlur={saveNotes} rows={4} placeholder="Add notes about this deal…"
        style={{ width: '100%', border: `1px solid ${P.lineStrong}`, borderRadius: 9, padding: '9px 12px', fontSize: 13, color: P.ink, fontFamily: P.sans, outline: 'none', resize: 'vertical', marginBottom: 18, boxSizing: 'border-box' }}/>

      <Label style={{ marginBottom: 8 }}>History</Label>
      {deal.activity.map((e, i) => (
        <div key={i} style={{ display: 'flex', gap: 12, padding: '9px 0', borderBottom: i < deal.activity.length - 1 ? `1px solid ${P.line}` : 'none' }}>
          <div style={{ width: 26, height: 26, borderRadius: 7, background: P[e.tone + 'Tint'], color: P[e.tone], display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name={e.ic} size={12}/></div>
          <div style={{ flex: 1 }}><div style={{ fontSize: 12.5, color: P.ink }}>{e.t}</div><div style={{ fontSize: 10.5, color: P.ink3, marginTop: 2 }}>{e.s}</div></div>
        </div>
      ))}
    </window.Drawer>
  );
}

// ── Segment builder — live criteria-based contact filter ────────
const SEGMENT_FIELDS = ['tag', 'company', 'last-activity', 'deal-stage'];
const SEGMENT_STAGE_VALUES = ['Lead', 'Qualified', 'Proposal', 'Negotiation', 'Won'];
const segmentOpsFor = f => f === 'last-activity' ? ['over', 'under'] : ['is', 'is not'];

function SegmentBuilder({ onClose, onSave }) {
  const P = window.PX;
  const [name, setName] = React.useState('');
  const [rows, setRows] = React.useState([{ field: 'tag', op: 'is', value: '' }]);

  const updateRow = (i, patch) => setRows(rs => rs.map((r, j) => j === i ? { ...r, ...patch } : r));
  const addRow = () => setRows(rs => [...rs, { field: 'tag', op: 'is', value: '' }]);
  const removeRow = (i) => setRows(rs => rs.filter((_, j) => j !== i));

  const activeRows = rows.filter(r => r.value);
  const matches = activeRows.length ? window.PEOPLE.filter(c => matchesCriteria(c, activeRows)) : window.PEOPLE;

  const save = () => {
    if (!name.trim() || !activeRows.length) return;
    onSave({ id: 'seg-' + name.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-') || ('seg-' + Date.now()), name: name.trim(), icon: 'layers', tone: 'plum', criteria: activeRows });
  };

  return (
    <window.Modal title="New segment" sub="Combine criteria to build a live contact list" w={580} onClose={onClose}
      foot={<>
        <Btn kind="ghost" onClick={onClose}>Cancel</Btn>
        <Btn kind="primary" disabled={!name.trim() || !activeRows.length} onClick={save}>Save segment · {matches.length} match{matches.length === 1 ? '' : 'es'}</Btn>
      </>}>
      <div style={{ marginBottom: 18 }}>
        <div style={{ fontSize: 12, color: P.ink3, marginBottom: 5, fontWeight: 500 }}>Segment name</div>
        <input value={name} onChange={e => setName(e.target.value)} placeholder="e.g. High-value wholesale" style={{ width: '100%', border: `1px solid ${P.lineStrong}`, borderRadius: 9, padding: '9px 12px', fontSize: 13.5, color: P.ink, fontFamily: P.sans, outline: 'none', boxSizing: 'border-box' }}/>
      </div>

      <Label style={{ marginBottom: 8 }}>Criteria</Label>
      {rows.map((r, i) => (
        <Card key={i} pad={12} style={{ marginBottom: 10 }}>
          <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 10.5, color: P.ink3, marginBottom: 5 }}>Field</div>
              <Chips options={SEGMENT_FIELDS} value={r.field} onChange={v => updateRow(i, { field: v, op: segmentOpsFor(v)[0], value: '' })}/>
            </div>
            {rows.length > 1 && <Icon name="x" size={15} color={P.ink3} style={{ cursor: 'pointer', marginTop: 4 }} onClick={() => removeRow(i)}/>}
          </div>
          <div style={{ display: 'flex', gap: 16, marginTop: 12, alignItems: 'flex-start' }}>
            <div>
              <div style={{ fontSize: 10.5, color: P.ink3, marginBottom: 5 }}>Operator</div>
              <Chips options={segmentOpsFor(r.field)} value={r.op} onChange={v => updateRow(i, { op: v })}/>
            </div>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 10.5, color: P.ink3, marginBottom: 5 }}>Value</div>
              {r.field === 'deal-stage' ? (
                <Chips options={SEGMENT_STAGE_VALUES} value={r.value} onChange={v => updateRow(i, { value: v })}/>
              ) : (
                <input value={r.value} onChange={e => updateRow(i, { value: e.target.value })}
                  placeholder={r.field === 'tag' ? 'wholesale' : r.field === 'company' ? 'Café Bleu' : 'days, e.g. 7'}
                  style={{ width: '100%', border: `1px solid ${P.lineStrong}`, borderRadius: 8, padding: '7px 10px', fontSize: 12.5, color: P.ink, fontFamily: P.sans, outline: 'none', boxSizing: 'border-box' }}/>
              )}
            </div>
          </div>
        </Card>
      ))}
      <div onClick={addRow} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '9px 0', fontSize: 12.5, color: P.spark, cursor: 'pointer', marginBottom: 18 }}><Icon name="plus" size={14}/>Add criteria</div>

      <Card pad={12} style={{ background: P.sunk }}>
        <Label style={{ marginBottom: 8 }}>Live preview · {matches.length} of {window.PEOPLE.length}</Label>
        {matches.slice(0, 5).map(c => (
          <div key={c.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 0' }}>
            <Avatar name={c.name} size={20}/><span style={{ fontSize: 12.5, color: P.ink2 }}>{c.name}</span><span style={{ fontSize: 11, color: P.ink3 }}>· {c.co}</span>
          </div>
        ))}
        {matches.length > 5 && <div style={{ fontSize: 11.5, color: P.ink3, marginTop: 4 }}>+{matches.length - 5} more</div>}
        {!matches.length && <div style={{ fontSize: 12, color: P.ink3 }}>No contacts match yet.</div>}
      </Card>
    </window.Modal>
  );
}

// ── Duplicate detection — merge or dismiss flagged contact pairs ──
function Duplicates() {
  const P = window.PX; const { toast } = window.useApp();
  const seed = [
    { id: 'dup1', a: window.PEOPLE.find(p => p.id === 'marc'), b: { name: 'Marc LeFevre', co: 'Cafe Bleu', role: 'Owner', email: 'm.lefevre@cafebleu.nyc' }, reason: 'Near-identical name & matching company domain' },
    { id: 'dup2', a: window.PEOPLE.find(p => p.id === 'marcus'), b: { name: 'Marc Chen', co: 'Slate & Stone', role: 'Owner', email: 'marc.chen@slatestone.co' }, reason: 'Same first name, same company & role' },
    { id: 'dup3', a: window.PEOPLE.find(p => p.id === 'lila'), b: { name: 'Lila Okamoto-Reyes', co: 'Lila Events LLC', role: 'Founder', email: 'lila@lilaevents.co' }, reason: 'Matching first/last name, near-identical email domain' },
    { id: 'dup4', a: window.PEOPLE.find(p => p.id === 'ahmad'), b: { name: 'Ahmed Saleh', co: 'BK Food Co-op', role: 'Manager', email: 'ahmad.saleh@bkcoop.org' }, reason: 'Same company & role, alternate spelling of first name' },
  ];
  const [pairs, setPairs] = React.useState(seed);
  const [mergePair, setMergePair] = React.useState(null);
  const applyMerge = (pr, chosen) => {
    // Reconcile onto the survivor (pr.a, a real PEOPLE record) and drop the duplicate.
    window.PXPeople.patchContact(pr.a.id, chosen);
    if (pr.b.id) window.PXPeople.removeContact(pr.b.id);
    setPairs(ps => ps.filter(p => p.id !== pr.id));
    setMergePair(null);
    toast(`Merged ${pr.b.name} into ${chosen.name || pr.a.name}.`, { tone: 'sage', icon: 'check' });
  };
  const dismiss = (id) => { setPairs(ps => ps.filter(p => p.id !== id)); toast('Marked as not a duplicate.', { icon: 'x' }); };

  return (
    <div style={{ fontFamily: P.sans, padding: 22 }}>
      <div style={{ fontFamily: P.serif, fontStyle: 'italic', fontSize: 26, color: P.ink, marginBottom: 4 }}>Possible duplicates</div>
      <div style={{ fontSize: 12.5, color: P.ink3, marginBottom: 18 }}>{pairs.length} pair{pairs.length === 1 ? '' : 's'} flagged · review and merge or dismiss</div>
      {!pairs.length && <Empty label="duplicates"/>}
      {pairs.map(pr => (
        <Card key={pr.id} pad={16} style={{ marginBottom: 12 }}>
          <div style={{ display: 'flex', gap: 16, alignItems: 'center' }}>
            <div style={{ flex: 1, display: 'flex', gap: 10, alignItems: 'center', minWidth: 0 }}>
              <Avatar name={pr.a.name} size={36}/>
              <div style={{ minWidth: 0 }}><div style={{ fontSize: 13.5, fontWeight: 500, color: P.ink }}>{pr.a.name}</div><div style={{ fontSize: 11.5, color: P.ink3, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{pr.a.co} · {pr.a.email}</div></div>
            </div>
            <Icon name="arrowRight" size={16} color={P.ink4}/>
            <div style={{ flex: 1, display: 'flex', gap: 10, alignItems: 'center', minWidth: 0 }}>
              <Avatar name={pr.b.name} size={36}/>
              <div style={{ minWidth: 0 }}><div style={{ fontSize: 13.5, fontWeight: 500, color: P.ink }}>{pr.b.name}</div><div style={{ fontSize: 11.5, color: P.ink3, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{pr.b.co} · {pr.b.email}</div></div>
            </div>
          </div>
          <div style={{ fontSize: 11.5, color: P.ink3, marginTop: 10, display: 'flex', alignItems: 'center', gap: 6 }}><Icon name="alert" size={13} color={P.amber}/>{pr.reason}</div>
          <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
            <Btn kind="primary" size="sm" icon="check" onClick={() => setMergePair(pr)}>Merge</Btn>
            <Btn kind="ghost" size="sm" onClick={() => dismiss(pr.id)}>Not a duplicate</Btn>
          </div>
        </Card>
      ))}
      {mergePair && <MergeModal pair={mergePair} onClose={() => setMergePair(null)} onMerge={applyMerge}/>}
    </div>
  );
}

// ── Merge field chooser — pick which value survives for each conflict ──
function MergeModal({ pair, onClose, onMerge }) {
  const P = window.PX;
  const fields = [['name', 'Name'], ['co', 'Company'], ['email', 'Email']];
  // Default to the survivor (a) side for each field.
  const [pick, setPick] = React.useState(() => ({ name: 'a', co: 'a', email: 'a' }));
  const valFor = (key, side) => (side === 'a' ? pair.a : pair.b)[key] || '—';
  const confirm = () => {
    const chosen = {};
    fields.forEach(([key]) => { chosen[key] = valFor(key, pick[key]); });
    onMerge(pair, chosen);
  };
  return (
    <window.Modal title="Merge contacts" sub="Choose which value to keep for each field — the rest is discarded." w={560} onClose={onClose}
      foot={<><Btn kind="ghost" onClick={onClose}>Cancel</Btn><div style={{ flex: 1 }}/><Btn kind="primary" icon="check" onClick={confirm}>Merge into one contact</Btn></>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {fields.map(([key, label]) => (
          <div key={key}>
            <Label style={{ marginBottom: 6 }}>{label}</Label>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
              {['a', 'b'].map(side => {
                const on = pick[key] === side;
                return (
                  <div key={side} onClick={() => setPick(p => ({ ...p, [key]: side }))}
                    style={{ padding: '10px 12px', borderRadius: 10, cursor: 'pointer', border: `1.5px solid ${on ? P.spark : P.line}`, background: on ? P.sparkWash : P.card }}>
                    <div style={{ fontSize: 10, color: P.ink3, marginBottom: 3, display: 'flex', alignItems: 'center', gap: 5 }}>{on && <Icon name="check" size={11} color={P.spark} stroke={3}/>}{side === 'a' ? 'Record A' : 'Record B'}</div>
                    <div style={{ fontSize: 13, color: P.ink, wordBreak: 'break-word' }}>{valFor(key, side)}</div>
                  </div>
                );
              })}
            </div>
          </div>
        ))}
      </div>
    </window.Modal>
  );
}
