// ABO Tracking — list & spreadsheet (split from abo.jsx).
// MobileAboList, FollowUpSheet, InactiveList, _jumpToSixW.

// ======================== Mobile card list ========================
// Mobile-friendly alternative to FollowUpSheet — the spreadsheet's tiny
// 28×30 checkboxes + vertical-text headers are unusable on a phone. Each
// person is a card; the หลัก (BM/BI/6W) checkboxes are exposed inline,
// other groups collapse behind an "ดูเพิ่ม" toggle to keep the card short.
// Quick navigation helper shared by the ABO list cards — open the 6W
// Tracking view focused on the matching customer.
function _jumpToSixW(name) {
  if (!name) return;
  const detail = { kind: '6w', name, prospectId: null };
  window.__emphasisPendingFocus = detail;
  window.dispatchEvent(new CustomEvent('emphasis:focus-followup', { detail }));
  // navigate by re-dispatching a window event the shell listens to. We don't
  // have direct access to navigate() here, so use a dedicated nav event.
  window.dispatchEvent(new CustomEvent('emphasis:navigate', { detail: { view: '6w' } }));
}

function MobileAboList({ people, onToggle, onMarkInactive, onEditPerson, onRestore, onDeletePerson, sixwCodes, mode = 'active' }) {
  const [expandedId, setExpandedId] = useState(null);

  if (people.length === 0) {
    return (
      <div className="text-center py-12 text-xs text-ink-400 bg-white rounded-xl border border-ink-100">
        ไม่มีรายชื่อตรงกับตัวกรอง
      </div>
    );
  }

  return (
    <div className="space-y-2.5">
      {people.map((p, idx) => {
        const stage = stageOf(p);
        const country = window.COUNTRIES?.find(c => c.id === p.country);
        const expanded = expandedId === p.id;
        const sixWEnrolled = p.filled.em6w === 'enrolled' || p.filled.em6w === true;
        const mfinityDone = !!p.filled.bt3;

        // Count progress for the chip on the right of each group toggle
        const groupProgress = FU_GROUPS.map(g => {
          const filled = g.cols.filter(c => {
            const v = p.filled[c.id];
            return c.id === 'em6w' ? (v === 'enrolled' || v === true) : !!v;
          }).length;
          return { id: g.id, filled, total: g.cols.length };
        });

        return (
          <div key={p.id} className="bg-white rounded-xl border border-ink-100 overflow-hidden">
            {/* Header */}
            <div className="flex items-center gap-2 p-3">
              <button
                onClick={() => onEditPerson?.(p)}
                disabled={!onEditPerson}
                className="flex items-center gap-2 flex-1 min-w-0 text-left">
                <Avatar user={{ avatar: p.name.charAt(0) || 'ค', color: p.source === 'EM6W' ? '#10B981' : '#2F5DE5' }} size={32} />
                <div className="flex-1 min-w-0">
                  <div className="flex items-center gap-1.5">
                    <span className="text-sm font-semibold text-ink-900 truncate">{p.name}</span>
                    {country && <span className="text-[12px] leading-none">{country.flag}</span>}
                  </div>
                  <div className="text-[10px] text-ink-500 leading-tight flex items-center gap-1.5 flex-wrap">
                    <span>{p.source === 'EM6W' ? '🥤 EM6W' : '💼 Sponsor'}</span>
                    {p.abo_code && <><span className="text-ink-300">·</span><span className="num tracking-wider">{p.abo_code}</span></>}
                  </div>
                </div>
              </button>
              {/* Stage badge only while still in EM Begin — keeps the card clean. */}
              {stage.id === 's4' && (
                <Pill color={stage.color} tint={stage.color + "20"} size="xs">{_stageLabel(stage, p)}</Pill>
              )}
              {/* Cross-link to 6W Tracking for ABO people also enrolled
                  in the weight program (matched by abo_code). */}
              {p.abo_code && sixwCodes && sixwCodes.has(p.abo_code) && (
                <button
                  onClick={() => _jumpToSixW(p.name)}
                  title="ดู 6W ของคนนี้"
                  className="inline-flex items-center gap-1 h-7 px-2 rounded text-[10px] font-semibold text-emerald-700 bg-emerald-50 hover:bg-emerald-100 border border-emerald-200 flex-shrink-0">
                  <span className="text-xs leading-none">🥤</span>
                  <span>6W</span>
                </button>
              )}
              {mode === 'active' && onMarkInactive && (
                <button
                  onClick={() => { if (confirm(`ย้าย "${p.name}" ไป Inactive?`)) onMarkInactive(p.id); }}
                  className="w-8 h-8 rounded-md text-ink-300 hover:bg-rose-50 hover:text-rose-500 flex items-center justify-center flex-shrink-0">
                  <UserOffIcon className="w-4 h-4" />
                </button>
              )}
              {mode === 'inactive' && onRestore && (
                <button
                  onClick={() => onRestore(p.id)}
                  className="px-2 h-7 rounded text-[10px] font-semibold text-brand-600 bg-brand-50 flex items-center flex-shrink-0">
                  ↻ Active
                </button>
              )}
              {onDeletePerson && (
                <button
                  onClick={() => onDeletePerson(p)}
                  title="ลบออกจากระบบถาวร"
                  className="w-8 h-8 rounded-md text-ink-300 hover:bg-rose-100 hover:text-rose-600 flex items-center justify-center flex-shrink-0">
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" className="w-4 h-4"><path d="M4 7h16M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13" strokeLinecap="round" strokeLinejoin="round" /></svg>
                </button>
              )}
            </div>

            {/* Key (หลัก) group — always visible: BM / BI / 6W */}
            <div className="px-3 pb-2 grid grid-cols-3 gap-1.5">
              {FU_GROUPS[0].cols.map(c => {
                const val = p.filled[c.id];
                const is6W = c.id === 'em6w';
                const enrolled = val === 'enrolled' || val === true;
                const noenroll = val === 'noenroll';
                const filled = is6W ? enrolled : !!val;
                const bg = is6W && noenroll
                  ? '#CBD5E1'
                  : filled ? FU_GROUPS[0].color : 'white';
                const text = filled || noenroll ? 'white' : '#445576';
                const label = c.label.split('·')[0].trim();
                return (
                  <button key={c.id}
                    onClick={() => onToggle(p.id, c.id)}
                    className="h-10 rounded-lg border-2 text-xs font-bold flex items-center justify-center gap-1 transition-all"
                    style={{
                      background: bg,
                      borderColor: filled || noenroll ? bg : '#E6EAF3',
                      color: text,
                    }}>
                    {(filled || noenroll) && (
                      <Icon name={noenroll ? 'x' : 'check'} className="w-3 h-3" strokeWidth={3} />
                    )}
                    <span>{label}</span>
                  </button>
                );
              })}
            </div>

            {/* Expand/collapse the other groups */}
            <button
              onClick={() => setExpandedId(expanded ? null : p.id)}
              className="w-full px-3 py-2 border-t border-ink-100 text-[11px] font-semibold text-brand-600 flex items-center justify-between hover:bg-ink-50">
              <span className="flex items-center gap-2">
                <Icon name={expanded ? 'chevD' : 'chevR'} className="w-3.5 h-3.5" />
                {expanded ? 'ซ่อน' : 'ดูเพิ่ม'} ({FU_GROUPS.length - 1} กลุ่ม)
              </span>
              <span className="text-[10px] text-ink-400 num">
                {groupProgress.slice(1).reduce((s, g) => s + g.filled, 0)} / {groupProgress.slice(1).reduce((s, g) => s + g.total, 0)}
              </span>
            </button>

            {expanded && (
              <div className="border-t border-ink-100 p-3 space-y-3 bg-ink-50/30">
                {FU_GROUPS.slice(1).map(g => {
                  const locked = (g.id === 'course' && !sixWEnrolled)
                              || (g.id === 'meeting' && mfinityDone);
                  const lockMsg = g.id === 'course'
                    ? '🔒 ต้องติ๊ก "6W เข้าคอร์ส" ก่อน'
                    : g.id === 'meeting' && mfinityDone
                    ? '🔒 ปิดเพราะติ๊ก MFinity แล้ว'
                    : null;
                  return (
                    <div key={g.id}>
                      <div className="flex items-center gap-1.5 mb-1.5">
                        <span className="text-[11px] font-bold uppercase tracking-wider" style={{ color: g.color }}>
                          {g.label}
                        </span>
                        {g.sub && <span className="text-[9px] text-rose-500 font-medium">* {g.sub}</span>}
                        {locked && lockMsg && (
                          <span className="text-[9px] text-ink-400 italic ml-auto">{lockMsg}</span>
                        )}
                      </div>
                      <div className="grid grid-cols-2 gap-1.5">
                        {g.cols.map(c => {
                          const val = p.filled[c.id];
                          const filled = !!val;
                          return (
                            <button key={c.id}
                              onClick={() => !locked && onToggle(p.id, c.id)}
                              disabled={locked}
                              className="flex items-center gap-2 px-2 py-2 rounded-lg border text-left transition-all"
                              style={{
                                background: filled ? g.color : locked ? '#F4F6FB' : 'white',
                                borderColor: filled ? g.color : '#E6EAF3',
                                opacity: locked ? 0.45 : 1,
                                cursor: locked ? 'not-allowed' : 'pointer',
                              }}>
                              <span className="w-5 h-5 rounded flex items-center justify-center flex-shrink-0"
                                    style={{ background: filled ? 'rgba(255,255,255,.25)' : 'white', border: filled ? 'none' : '1.5px solid #C9D2E3' }}>
                                {filled && <Icon name="check" className="w-3 h-3 text-white" strokeWidth={3} />}
                              </span>
                              <span className="text-[11px] font-medium leading-tight" style={{ color: filled ? 'white' : '#0F1E38' }}>
                                {c.label}
                              </span>
                            </button>
                          );
                        })}
                      </div>
                    </div>
                  );
                })}
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

// ======================== Spreadsheet ========================
function FollowUpSheet({ people, onToggle, onMarkInactive, onRestore, onEditPerson, onDeletePerson, onReorder, onPickSponsor, hoveredCol, onHoverCol, mode = 'active' }) {
  const NAME_W = 280;
  const CELL_W = 28;
  const CELL_H = 30;
  // Drag-to-reorder state: which row id is being dragged, and which row the
  // pointer is currently over (for the drop-indicator highlight).
  const [dragId, setDragId] = useState(null);
  const [overId, setOverId] = useState(null);
  // Collapsed sponsors (their DL subtree is hidden). Default = all expanded.
  const [collapsed, setCollapsed] = useState(() => new Set());
  const toggleCollapse = (id) => setCollapsed(prev => {
    const n = new Set(prev);
    n.has(id) ? n.delete(id) : n.add(id);
    return n;
  });

  // Quick lookup so a row can show its sponsor's name.
  const byId = useMemo(() => new Map(people.map(p => [p.id, p])), [people]);

  // Build the DL hierarchy: each person with a sponsorId nests under that
  // sponsor. Flatten depth-first so a DL renders right under its upline,
  // indented by depth. Roots = no sponsor (or sponsor not in this view).
  // Sibling order follows the incoming fu_position order. Collapsed nodes
  // keep their row but skip their subtree.
  const flatRows = useMemo(() => {
    const childrenOf = new Map();
    for (const p of people) {
      const par = p.sponsorId && byId.has(p.sponsorId) ? p.sponsorId : null;
      if (!childrenOf.has(par)) childrenOf.set(par, []);
      childrenOf.get(par).push(p);
    }
    const out = [];
    const seen = new Set();
    // `hidden` = we're inside a collapsed ancestor's subtree. We still recurse
    // (so every descendant is marked seen and excluded from the orphan
    // fallback below) but emit no rows for them — that's what "ซ่อน DL" means.
    const walk = (parentKey, depth, hidden) => {
      const kids = childrenOf.get(parentKey) || [];
      for (const p of kids) {
        if (seen.has(p.id)) continue; // cycle guard
        seen.add(p.id);
        const hasChildren = (childrenOf.get(p.id) || []).length > 0;
        const isCollapsed = collapsed.has(p.id);
        if (!hidden) out.push({ p, depth, hasChildren, isCollapsed });
        if (hasChildren) walk(p.id, depth + 1, hidden || isCollapsed);
      }
    };
    walk(null, 0, false);
    // Safety: append any orphan not reached (shouldn't happen).
    for (const p of people) if (!seen.has(p.id)) out.push({ p, depth: 0, hasChildren: false, isCollapsed: false });
    return out;
  }, [people, byId, collapsed]);

  // Every row that has at least one DL nested under it — drives the
  // "ซ่อน/แสดง DL ทั้งหมด" toggle.
  const parentIds = useMemo(() => {
    const s = new Set();
    for (const p of people) if (p.sponsorId && byId.has(p.sponsorId)) s.add(p.sponsorId);
    return s;
  }, [people, byId]);
  const allCollapsed = parentIds.size > 0 && [...parentIds].every(id => collapsed.has(id));
  const toggleAll = () => setCollapsed(allCollapsed ? new Set() : new Set(parentIds));

  return (
    <Card pad={false} className="overflow-hidden">
      <div className="overflow-x-auto overflow-y-visible scroll-thin">
        <div className="min-w-fit">
          {/* Group header */}
          <div className="flex sticky top-0 z-20 bg-white border-b-2 border-ink-200">
            <div className="flex-shrink-0 sticky left-0 z-10 bg-white border-r-2 border-ink-200" style={{ width: NAME_W }} />
            {FU_GROUPS.map(g => (
              <div key={g.id}
                className="flex items-center justify-center text-center border-r-2 border-ink-200 py-2"
                style={{ width: g.cols.length * CELL_W, background: g.tint }}>
                <div>
                  <div className="text-xs font-bold uppercase tracking-wider" style={{ color: g.color }}>{g.label}</div>
                  {g.sub && <div className="text-[9px] text-rose-500 font-medium">* {g.sub}</div>}
                </div>
              </div>
            ))}
          </div>

          {/* Sub-headers */}
          <div className="flex sticky top-[40px] z-20 bg-white border-b-2 border-ink-300">
            <div className="flex-shrink-0 sticky left-0 z-10 bg-white border-r-2 border-ink-200 flex items-end px-3 pb-2" style={{ width: NAME_W, height: 150 }}>
              <div className="flex items-center justify-between w-full gap-2">
                <span className="text-[10px] uppercase tracking-wider font-bold text-ink-400">⇅ · Name</span>
                {parentIds.size > 0 && (
                  <button onClick={toggleAll}
                    title={allCollapsed ? 'แสดง DL ทั้งหมด' : 'ซ่อน DL ทั้งหมด'}
                    className="inline-flex items-center gap-1 px-2 h-6 rounded-md text-[10px] font-semibold text-ink-500 bg-ink-50 hover:bg-ink-100 transition-colors normal-case tracking-normal">
                    <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="2" className="w-2.5 h-2.5"
                         style={{ transform: allCollapsed ? 'rotate(-90deg)' : 'none' }}>
                      <path d="M3 4.5l3 3 3-3" strokeLinecap="round" strokeLinejoin="round" />
                    </svg>
                    {allCollapsed ? 'แสดง DL' : 'ซ่อน DL'}
                  </button>
                )}
                <span className="text-[10px] uppercase tracking-wider font-bold text-ink-400">Stage</span>
              </div>
            </div>
            {FU_ALL_COLS.map(c => {
              const isHover = hoveredCol === c.id;
              return (
                <div key={c.id}
                  onMouseEnter={() => onHoverCol(c.id)}
                  onMouseLeave={() => onHoverCol(null)}
                  className="relative flex items-end justify-center border-r border-ink-100 transition-colors"
                  style={{ width: CELL_W, height: 150, background: isHover ? c.groupTint : 'white' }}>
                  <div className="text-[10px] leading-tight whitespace-nowrap pb-2"
                    style={{
                      writingMode: 'vertical-rl', transform: 'rotate(180deg)',
                      color: isHover ? c.groupColor : '#0F1E38',
                      fontWeight: isHover ? 700 : 500,
                    }}>{c.label}</div>
                </div>
              );
            })}
          </div>

          {/* Rows — DL hierarchy: each DL nests under its sponsor. */}
          {flatRows.map(({ p, depth, hasChildren, isCollapsed }, rowIdx) => {
            const stage = stageOf(p);
            const country = window.COUNTRIES?.find(c => c.id === p.country);
            const sponsor = p.sponsorId ? byId.get(p.sponsorId) : null;
            const isDragging = dragId === p.id;
            const isOver = overId === p.id && dragId && dragId !== p.id;
            return (
              <div key={p.id}
                onDragOver={onReorder ? (e) => { e.preventDefault(); if (overId !== p.id) setOverId(p.id); } : undefined}
                onDrop={onReorder ? (e) => { e.preventDefault(); if (dragId && dragId !== p.id) onReorder(dragId, p.id); setDragId(null); setOverId(null); } : undefined}
                className={`flex group hover:bg-brand-50/30 ${isDragging ? 'opacity-40' : ''}`}
                style={{ background: ROW_BG[Math.min(depth, 2)], ...(isOver ? { boxShadow: 'inset 0 2px 0 #2F5DE5' } : {}) }}>
                <div className="flex-shrink-0 sticky left-0 z-[5] border-r-2 border-ink-200 px-2 py-1 flex items-center gap-1.5 transition-colors"
                  style={{ width: NAME_W, background: NAME_BG[Math.min(depth, 2)], borderLeft: depth > 0 ? `3px solid ${DEPTH_ACCENT[Math.min(depth,2)]}` : undefined }}>
                  {/* Indent for DL depth + a connector glyph on child rows. */}
                  {depth > 0 && (
                    <span className="flex-shrink-0 flex items-center justify-end text-ink-300 text-[11px]"
                          style={{ width: depth * 14 }}>↳</span>
                  )}
                  {/* Collapse caret on rows that have DLs; otherwise a spacer
                      so names stay aligned. */}
                  {hasChildren ? (
                    <button onClick={() => toggleCollapse(p.id)}
                      title={isCollapsed ? 'แสดง DL' : 'ซ่อน DL'}
                      className="flex-shrink-0 w-4 h-4 flex items-center justify-center text-ink-400 hover:text-ink-800 transition-transform"
                      style={{ transform: isCollapsed ? 'rotate(-90deg)' : 'none' }}>
                      <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="2" className="w-2.5 h-2.5">
                        <path d="M3 4.5l3 3 3-3" strokeLinecap="round" strokeLinejoin="round" />
                      </svg>
                    </button>
                  ) : (
                    <span className="flex-shrink-0 w-4" />
                  )}
                  {onReorder && (
                    <div
                      draggable
                      onDragStart={(e) => { setDragId(p.id); e.dataTransfer.effectAllowed = 'move'; }}
                      onDragEnd={() => { setDragId(null); setOverId(null); }}
                      title="ลากเพื่อจัดลำดับ"
                      className="flex-shrink-0 w-4 flex items-center justify-center text-ink-300 hover:text-ink-600 cursor-grab active:cursor-grabbing opacity-0 group-hover:opacity-100 transition-opacity">
                      <svg viewBox="0 0 16 16" fill="currentColor" className="w-3.5 h-3.5">
                        <circle cx="6" cy="4" r="1.3" /><circle cx="10" cy="4" r="1.3" />
                        <circle cx="6" cy="8" r="1.3" /><circle cx="10" cy="8" r="1.3" />
                        <circle cx="6" cy="12" r="1.3" /><circle cx="10" cy="12" r="1.3" />
                      </svg>
                    </div>
                  )}
                  <button
                    onClick={() => onEditPerson?.(p)}
                    disabled={!onEditPerson}
                    title={onEditPerson ? 'คลิกเพื่อแก้ไขชื่อ / รหัส ABO' : ''}
                    className="flex items-center gap-2 flex-1 min-w-0 text-left rounded-md px-1 -mx-1 py-0.5 hover:bg-ink-100/60 transition-colors disabled:cursor-default disabled:hover:bg-transparent">
                    <Avatar user={{ avatar_url: p.photoUrl, avatar: p.name.charAt(p.name.indexOf(' ')+1) || p.name.charAt(0) || 'ค', color: p.source === 'EM6W' ? '#10B981' : '#2F5DE5' }} size={22} />
                    <div className="flex-1 min-w-0">
                      {/* Line 1 — NAME only, on its own line so it's always
                          fully visible (most important). */}
                      <div className="flex items-center gap-1.5">
                        <span className="text-[13px] font-semibold text-ink-900 truncate">{p.name}</span>
                        {country && <span className="text-[10px] leading-none flex-shrink-0">{country.flag}</span>}
                      </div>
                      {/* Line 2 — EM Begin progress (only while still in EM
                          Begin) + ABO code, under the name. */}
                      {(stage.id === 's4' || p.abo_code) && (
                        <div className="flex items-center gap-1.5 leading-tight">
                          {stage.id === 's4' && (
                            <Pill color={stage.color} tint={stage.color + "20"} size="xs">{_stageLabel(stage, p)}</Pill>
                          )}
                          {p.abo_code && <span className="text-[9px] text-ink-400 num tracking-wider truncate">{p.abo_code}</span>}
                        </div>
                      )}
                    </div>
                  </button>

                  {/* DL-of: icon-only button (the upline is already shown by the
                      row indentation, so no text chip). Amber when a sponsor
                      is set; otherwise reveals on hover. */}
                  {onPickSponsor && (
                    <button
                      onClick={() => onPickSponsor(p)}
                      title={sponsor ? `DL ของ ${sponsor.name} · คลิกเปลี่ยน` : 'กำหนดว่าเป็น DL ของใคร'}
                      className={`flex-shrink-0 w-6 h-6 rounded-md flex items-center justify-center transition-all ${
                        sponsor
                          ? 'text-amber-600 bg-amber-50 hover:bg-amber-100'
                          : 'text-ink-300 hover:text-brand-600 hover:bg-brand-50 opacity-0 group-hover:opacity-100'
                      }`}>
                      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" className="w-3.5 h-3.5">
                        <circle cx="9" cy="8" r="3" /><path d="M3 19c0-3 2.7-4.5 6-4.5" strokeLinecap="round" />
                        <path d="M15 11l3 3 4-5" strokeLinecap="round" strokeLinejoin="round" />
                      </svg>
                    </button>
                  )}

                  {mode === 'active' && onMarkInactive && (
                    <button
                      onClick={() => { if (confirm(`ย้าย "${p.name}" ไป Inactive?`)) onMarkInactive(p.id); }}
                      title="ย้ายไปแท็บ Inactive"
                      className="opacity-0 group-hover:opacity-100 w-6 h-6 rounded-md text-ink-300 hover:bg-rose-50 hover:text-rose-500 flex items-center justify-center transition-all flex-shrink-0">
                      <UserOffIcon className="w-4 h-4" />
                    </button>
                  )}
                  {mode === 'inactive' && onRestore && (
                    <button
                      onClick={() => onRestore(p.id)}
                      title="นำกลับมา Active"
                      className="opacity-60 group-hover:opacity-100 px-1.5 h-5 rounded text-[10px] font-semibold text-brand-600 bg-brand-50 hover:bg-brand-100 flex items-center transition-all flex-shrink-0">
                      ↻
                    </button>
                  )}
                  {onDeletePerson && (
                    <button
                      onClick={() => onDeletePerson(p)}
                      title="ลบออกจากระบบถาวร"
                      className="opacity-0 group-hover:opacity-100 w-6 h-6 rounded-md text-ink-300 hover:bg-rose-100 hover:text-rose-600 flex items-center justify-center transition-all flex-shrink-0">
                      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" className="w-3.5 h-3.5"><path d="M4 7h16M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13" strokeLinecap="round" strokeLinejoin="round" /></svg>
                    </button>
                  )}
                </div>

                {FU_GROUPS.map(g => g.cols.map((c, ci) => {
                  const val = p.filled[c.id];
                  const filled = !!val;
                  const isLast = ci === g.cols.length - 1;
                  const isHover = hoveredCol === c.id;
                  const is6W = c.id === 'em6w';
                  const enrolled = val === 'enrolled' || val === true;
                  const noenroll = val === 'noenroll';

                  const sixWEnrolled = p.filled.em6w === 'enrolled' || p.filled.em6w === true;
                  const mfinityDone = !!p.filled.bt3;
                  const lockReason = (g.id === 'course' && !sixWEnrolled) ? 'sixW'
                                   : (g.id === 'meeting' && mfinityDone)  ? 'mfinity'
                                   : null;
                  const isLocked = !!lockReason;

                  let cellBg = 'transparent';
                  if (is6W) {
                    if (enrolled) cellBg = '#10B981';
                    else if (noenroll) cellBg = '#CBD5E1';
                    else if (isHover) cellBg = g.tint;
                  } else if (isLocked) {
                    cellBg = 'repeating-linear-gradient(135deg, #F1F5F9 0 6px, #E2E8F0 6px 7px)';
                  } else {
                    cellBg = filled ? g.color : (isHover ? g.tint : 'transparent');
                  }
                  const lockedTitle = lockReason === 'sixW'
                    ? `${c.label} · ${p.name} · 🔒 ต้องติ๊ก "6W เข้าคอร์ส" ก่อน`
                    : lockReason === 'mfinity'
                    ? `${c.label} · ${p.name} · 🔒 ปิด EM Begin เพราะติ๊ก MFinity แล้ว`
                    : '';
                  return (
                    <button key={c.id}
                      onClick={() => !isLocked && onToggle(p.id, c.id)}
                      onMouseEnter={() => onHoverCol(c.id)}
                      onMouseLeave={() => onHoverCol(null)}
                      disabled={isLocked}
                      title={
                        isLocked
                          ? lockedTitle
                          : `${c.label} · ${p.name}${is6W && noenroll ? ' · ไม่เข้าคอร์ส' : is6W && enrolled ? ' · เข้าคอร์ส' : ''}`
                      }
                      className={`flex-shrink-0 flex items-center justify-center transition-all ${isLast ? 'border-r-2 border-ink-200' : 'border-r border-ink-100'} border-b border-ink-100 ${isLocked ? 'cursor-not-allowed' : 'hover:scale-110'}`}
                      style={{ width: CELL_W, height: CELL_H, background: cellBg }}>
                      {is6W ? (
                        enrolled ? (
                          <svg viewBox="0 0 16 16" fill="none" stroke="white" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" className="w-3.5 h-3.5">
                            <path d="M3 9h10a5 5 0 0 1-10 0z" />
                            <path d="M5 3v2M8 2v3M11 3v2" />
                          </svg>
                        ) : noenroll ? (
                          <svg viewBox="0 0 16 16" fill="none" stroke="#475569" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" className="w-3.5 h-3.5">
                            <path d="M3 9h10a5 5 0 0 1-10 0z" />
                            <path d="M5 3v2M8 2v3M11 3v2" />
                            <line x1="1.5" y1="14.5" x2="14.5" y2="1.5" />
                          </svg>
                        ) : null
                      ) : isLocked ? (
                        <svg viewBox="0 0 16 16" fill="none" stroke="#94A3B8" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" className="w-2.5 h-2.5 opacity-60">
                          <rect x="3.5" y="7" width="9" height="6.5" rx="1" />
                          <path d="M5 7V5a3 3 0 0 1 6 0v2" />
                        </svg>
                      ) : (
                        filled && (
                          <svg viewBox="0 0 16 16" fill="none" stroke="white" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" className="w-3 h-3">
                            <path d="M3 8l3.5 3.5L13 4" />
                          </svg>
                        )
                      )}
                    </button>
                  );
                }))}
              </div>
            );
          })}

          {people.length === 0 && (
            <div className="flex">
              <div className="flex-1 text-center py-12 text-xs text-ink-400">ไม่มีรายชื่อตรงกับตัวกรอง</div>
            </div>
          )}
        </div>
      </div>

      <div className="px-5 py-3 border-t border-ink-100 bg-ink-50/40 flex items-center justify-between text-[11px] text-ink-500">
        <div className="flex items-center gap-4">
          {mode === 'active'
            ? <span className="inline-flex items-center gap-1.5">คลิก cell เพื่อติ๊ก · hover แถวเพื่อหาปุ่ม <UserOffIcon className="w-3.5 h-3.5 text-rose-500" /> (ย้ายไป Inactive)</span>
            : <span>คลิก cell เพื่อติ๊ก · hover แถวเพื่อหาปุ่ม ↻ (นำกลับ Active)</span>
          }
        </div>
        <div className="num">{FU_ALL_COLS.length} steps · {people.length} คน</div>
      </div>
    </Card>
  );
}

function UserOffIcon({ className = 'w-4 h-4' }) {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" className={className}>
      <circle cx="10" cy="8" r="3.5" />
      <path d="M3 21c0-4 3.5-7 7-7 1.4 0 2.7.4 3.8 1" />
      <circle cx="18" cy="18" r="4" />
      <path d="M16 18h4" />
    </svg>
  );
}

// ======================== Inactive list ========================
function InactiveList({ people, onRestore, onToggle, onEditPerson, onDeletePerson, hoveredCol, onHoverCol }) {
  if (people.length === 0) {
    return (
      <Card className="text-center py-12">
        <div className="text-4xl mb-2">🌱</div>
        <div className="text-sm font-semibold text-ink-700">ยังไม่มีใครย้ายมาที่นี่</div>
        <div className="text-[11px] text-ink-400 mt-1">คน Inactive จะถูกย้ายมาที่นี่ (กดปุ่ม ✕ ในตารางหลัก)</div>
      </Card>
    );
  }

  const stageCounts = VISIBLE_STAGES.map(s => ({
    ...s,
    count: people.filter(p => stageOf(p).id === s.id).length,
  }));

  return (
    <div className="space-y-4">
      <Card className="bg-ink-50/60 border-ink-200" pad={false}>
        <div className="p-4 flex items-center gap-3 border-b border-ink-200/60">
          <div className="w-10 h-10 rounded-lg bg-ink-700 text-white flex items-center justify-center">
            <Icon name="info" className="w-5 h-5" />
          </div>
          <div className="flex-1">
            <div className="text-sm font-semibold text-ink-800">รายชื่อไม่ active · {people.length} คน</div>
            <div className="text-[11px] text-ink-500">เก็บประวัติ follow-up เดิมไว้ครบ · เผื่อ retarget ภายหลัง · กด ↻ เพื่อย้ายกลับ Active</div>
          </div>
        </div>
        <div className="p-4 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-2">
          {stageCounts.map(s => (
            <div key={s.id} className="rounded-lg p-2 text-center border" style={{ borderColor: s.color + '30', background: s.count > 0 ? s.color + '0F' : 'white' }}>
              <div className="text-[10px] font-bold uppercase tracking-wider" style={{ color: s.color }}>{s.short}</div>
              <div className="text-lg font-semibold num" style={{ color: s.count > 0 ? s.color : '#94A3B8' }}>{s.count}</div>
            </div>
          ))}
        </div>
      </Card>

      <div className="hidden md:block">
        <FollowUpSheet
          people={people}
          onToggle={onToggle}
          onRestore={onRestore}
          onEditPerson={onEditPerson}
          onDeletePerson={onDeletePerson}
          hoveredCol={hoveredCol}
          onHoverCol={onHoverCol}
          mode="inactive"
        />
      </div>
      <div className="md:hidden">
        <MobileAboList
          people={people}
          onToggle={onToggle}
          onRestore={onRestore}
          onEditPerson={onEditPerson}
          onDeletePerson={onDeletePerson}
          mode="inactive"
        />
      </div>
    </div>
  );
}
