// Memory Jogger — "คนรู้จัก" natural-market list (ported from the Memory Jogger
// design). A table of acquaintances with name + social link, age/job/faculty,
// four 0–10 scores (Active / Friendly / Money / Relation) and a note.
//
// Saved per month: a YYYY-MM period picker switches the whole list, and each
// month is persisted independently to db.memoryJogger (Supabase, scoped to the
// signed-in account) with a per-user localStorage mirror. Editing is NOT
// auto-saved — the user presses บันทึก to persist. Each person also has a
// "ทักแล้ว" checkbox to mark that they've been contacted.

const MJ_THAI_MONTHS = ['มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน','กรกฎาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'];

const mjUid = () => 'p' + Math.random().toString(36).slice(2, 9);
const mjBlankRow = () => ({ id: mjUid(), name: '', link: '', age: '', job: '', faculty: '', active: 0, friendly: 0, money: 0, relation: 0, note: '', contacted: false });

function mjPlatform(url) {
  const u = (url || '').toLowerCase();
  if (!u.trim()) return null;
  if (u.includes('instagram') || u.includes('ig.me') || /(^|\W)ig(\W|$)/.test(u)) return 'ig';
  if (u.includes('facebook') || u.includes('fb.com') || u.includes('fb.me') || u.includes('m.me')) return 'fb';
  if (u.includes('tiktok')) return 'tt';
  if (u.includes('line.me') || u.includes('lin.ee')) return 'line';
  return 'web';
}
function mjNormUrl(u) { u = (u || '').trim(); if (!u) return '#'; if (!/^https?:\/\//i.test(u)) return 'https://' + u; return u; }
function mjRowTotal(p) { return (+p.active || 0) + (+p.friendly || 0) + (+p.money || 0) + (+p.relation || 0); }
function mjScoreLevel(v) { v = +v || 0; if (v <= 0) return 'lv0'; if (v <= 3) return 'lv-lo'; if (v <= 6) return 'lv-mid'; return 'lv-hi'; }
function mjTotalClass(t) { return t >= 32 ? 't-hi' : t >= 20 ? 't-mid' : 't-lo'; }
function mjTotalLabel(t, any) { if (!any) return ''; return t >= 32 ? 'ตัวจริง' : t >= 20 ? 'น่าสน' : 'ทั่วไป'; }

const MJ_PLAT_SVG = {
  ig: <svg width="14" height="14" viewBox="0 0 24 24" fill="none"><rect x="3" y="3" width="18" height="18" rx="5.4" stroke="currentColor" strokeWidth="2"/><circle cx="12" cy="12" r="4" stroke="currentColor" strokeWidth="2"/><circle cx="17.4" cy="6.6" r="1.2" fill="currentColor"/></svg>,
  fb: <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M14 9V7c0-1 .3-1.5 1.6-1.5H17V2.3C16.5 2.2 15.4 2 14.2 2 11.6 2 10 3.6 10 6.4V9H7.5v3.2H10V22h3.4v-9.8H16l.5-3.2H13.4z"/></svg>,
  tt: <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M16.5 3c.3 2.1 1.6 3.6 3.5 3.9v2.7c-1.3.1-2.5-.3-3.6-1v5.9c0 3.4-2.6 5.9-5.9 5.9S4.6 17.9 4.6 14.6c0-3.1 2.4-5.7 5.6-5.8v2.8c-.4.1-.8.2-1.1.4-1 .5-1.7 1.5-1.7 2.7 0 1.7 1.3 2.9 2.9 2.9 1.6 0 2.9-1.3 2.9-3.1V3h3.3z"/></svg>,
  line: <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M12 3C6.8 3 2.5 6.4 2.5 10.6c0 3.8 3.4 7 8 7.6.3.1.7.2.8.5.1.3.1.7 0 1l-.1.8c-.1.3-.3 1.1 1 .6 1.3-.5 6.8-4 9.3-6.9 1.7-1.8 2-3.7 2-3.6C23.5 6.4 19.2 3 12 3z"/></svg>,
  web: <svg width="14" height="14" viewBox="0 0 24 24" fill="none"><path d="M9 15l6-6M10.5 7l1-1a3.5 3.5 0 015 5l-1 1M13.5 17l-1 1a3.5 3.5 0 01-5-5l1-1" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/></svg>,
};
const MJ_PLAT_BG = { ig: 'linear-gradient(135deg,var(--mj-ig1),var(--mj-ig2) 50%,var(--mj-ig3))', fb: 'var(--mj-fb)', tt: 'var(--mj-tiktok)', line: 'var(--mj-line-green)', web: '#64748B' };

function MemoryJoggerView({ currentUser }) {
  const now = new Date();
  const [month, setMonth] = useState(now.getMonth());
  const [year, setYear] = useState(now.getFullYear());
  const [rows, setRows] = useState([]);
  const [loading, setLoading] = useState(true);
  const [search, setSearch] = useState('');
  const [sort, setSort] = useState('manual');
  const [dirty, setDirty] = useState(false);
  const [saving, setSaving] = useState(false);
  const [saveLabel, setSaveLabel] = useState('');
  const period = `${year}-${String(month + 1).padStart(2, '0')}`;
  // localStorage is keyed per account so two users on the same browser never
  // share a list (Supabase is the source of truth; this is just the mirror).
  const uid = currentUser?.id || 'anon';
  const lsKey = `emphasis.memoryJogger.${uid}.${period}`;

  // Load the selected month — Supabase first (scoped to this account), then LS.
  useEffect(() => {
    let cancelled = false;
    (async () => {
      setLoading(true);
      let loaded = null, when = null;
      try {
        if (window.SB_READY && window.db?.memoryJogger) {
          const { data } = await window.db.memoryJogger.get(period);
          if (data) { loaded = data.data; when = data.updated_at ? new Date(data.updated_at).getTime() : null; }
        }
      } catch (e) { /* fall through to LS */ }
      if (!Array.isArray(loaded)) {
        try { const raw = localStorage.getItem(lsKey); if (raw) { const j = JSON.parse(raw); if (Array.isArray(j)) loaded = j; } } catch {}
      }
      if (cancelled) return;
      setRows(Array.isArray(loaded) ? loaded.map(r => ({ ...mjBlankRow(), ...r, id: r.id || mjUid() })) : []);
      setDirty(false);
      setSaveLabel(when ? 'บันทึกล่าสุด · ' + new Date(when).toLocaleString('th-TH', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }) : '');
      setLoading(false);
    })();
    return () => { cancelled = true; };
  }, [period, uid]); // eslint-disable-line

  // Explicit save — only runs when the user presses บันทึก.
  const saveNow = useCallback(async (override) => {
    const next = override || rows;
    setSaving(true);
    try { localStorage.setItem(lsKey, JSON.stringify(next)); } catch {}
    let ok = true;
    try {
      if (window.SB_READY && window.db?.memoryJogger) {
        const { error } = await window.db.memoryJogger.save(period, next);
        if (error) ok = false;
      }
    } catch (e) { ok = false; }
    setSaving(false);
    if (ok) { setDirty(false); setSaveLabel('บันทึกแล้ว · ' + new Date().toLocaleTimeString('th-TH', { hour: '2-digit', minute: '2-digit' })); }
    else { setSaveLabel('บันทึกขึ้นคลาวด์ไม่สำเร็จ — เก็บไว้ในเครื่องชั่วคราว'); }
    return ok;
  }, [rows, period, lsKey]);

  // Edits only update local state + mark dirty (no auto-save).
  const commit = (next) => { setRows(next); setDirty(true); };
  const updateRow = (id, patch) => commit(rows.map(r => r.id === id ? { ...r, ...patch } : r));
  const toggleContacted = (id) => commit(rows.map(r => r.id === id ? { ...r, contacted: !r.contacted } : r));
  const addRow = () => { setSort('manual'); commit([...rows, mjBlankRow()]); };
  const removeRow = (id) => commit(rows.filter(r => r.id !== id));
  const clearAll = () => { if (confirm('ลบรายชื่อทั้งหมดของเดือนนี้? อย่าลืมกดบันทึกเพื่อยืนยัน')) commit([]); };

  // Guard month switches when there are unsaved edits.
  const guardSwitch = () => !dirty || confirm('มีการแก้ไขที่ยังไม่ได้บันทึก — เปลี่ยนเดือนเลยไหม? การแก้ไขจะหาย');
  const prevMonth = () => { if (!guardSwitch()) return; let m = month - 1, y = year; if (m < 0) { m = 11; y--; } setMonth(m); setYear(y); };
  const nextMonth = () => { if (!guardSwitch()) return; let m = month + 1, y = year; if (m > 11) { m = 0; y++; } setMonth(m); setYear(y); };

  // Stats
  const total = rows.length;
  const scored = rows.filter(p => mjRowTotal(p) > 0);
  const avg = scored.length ? Math.round(scored.reduce((s, p) => s + mjRowTotal(p), 0) / scored.length) : 0;
  const contactedCount = rows.filter(p => p.contacted).length;

  // Sorted + filtered view
  const sortedRows = (() => {
    const arr = rows.slice();
    if (sort === 'score') arr.sort((a, b) => mjRowTotal(b) - mjRowTotal(a));
    else if (sort === 'name') arr.sort((a, b) => (a.name || '').localeCompare(b.name || '', 'th'));
    return arr;
  })();
  const q = search.trim().toLowerCase();
  const visibleRows = q
    ? sortedRows.filter(p => `${p.name} ${p.job} ${p.faculty} ${p.note}`.toLowerCase().includes(q))
    : sortedRows;

  const SCORES = [
    { f: 'active', label: 'Active' }, { f: 'friendly', label: 'Friendly' },
    { f: 'money', label: 'Money' }, { f: 'relation', label: 'Relation' },
  ];

  return (
    <div className="mj-root">
      <style>{`
        .mj-root{
          --mj-surface:#FFF; --mj-line:#EDF0F6; --mj-line-strong:#E2E8F0;
          --mj-ink:#0F172A; --mj-ink-2:#334155; --mj-muted:#64748B; --mj-muted-2:#94A3B8;
          --mj-blue:#2563EB; --mj-blue-deep:#1D4ED8; --mj-blue-soft:#EAF1FE;
          --mj-kraft:#B3A06B; --mj-kraft-deep:#9A8753; --mj-kraft-soft:#F4EFE0;
          --mj-pos:#059669; --mj-pos-soft:#E3F6EE; --mj-amber:#B45309; --mj-amber-soft:#FEF3C7;
          --mj-neg:#DC2626; --mj-neg-soft:#FDECEC;
          --mj-ig1:#F9CE34; --mj-ig2:#EE2A7B; --mj-ig3:#6228D7; --mj-fb:#1877F2; --mj-line-green:#06C755; --mj-tiktok:#010101;
          color:var(--mj-ink);
        }
        .mj-num{font-feature-settings:"tnum"}
        .mj-stats{display:grid;grid-template-columns:repeat(2,1fr);gap:14px;margin-bottom:18px}
        .mj-stat{background:var(--mj-surface);border:1px solid var(--mj-line);border-radius:15px;padding:15px 17px;display:flex;flex-direction:column;gap:7px;box-shadow:0 1px 2px rgba(15,23,42,0.04)}
        .mj-stat .k{font-size:12.5px;color:var(--mj-muted);font-weight:500;display:flex;align-items:center;gap:8px}
        .mj-stat .k .ic{width:26px;height:26px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
        .mj-stat .v{font-weight:800;font-size:26px;letter-spacing:-0.5px;line-height:1;color:var(--mj-ink)}
        .mj-stat .v .u{font-size:13px;font-weight:600;color:var(--mj-muted);margin-left:4px}

        .mj-toolbar{display:flex;align-items:center;gap:12px;margin-bottom:14px;flex-wrap:wrap}
        .mj-monthnav{display:flex;align-items:center;gap:2px;background:#fff;border:1px solid var(--mj-line-strong);border-radius:12px;padding:4px}
        .mj-monthnav button{width:32px;height:32px;border:none;background:transparent;border-radius:8px;color:var(--mj-muted);font-size:18px;line-height:1;cursor:pointer}
        .mj-monthnav button:hover{background:#F1F5F9;color:var(--mj-ink)}
        .mj-monthnav .lab{min-width:128px;text-align:center;font-size:13.5px;font-weight:700;color:var(--mj-ink)}
        .mj-search{position:relative;flex:1;min-width:200px;max-width:360px}
        .mj-search svg{position:absolute;left:13px;top:50%;transform:translateY(-50%);color:var(--mj-muted-2)}
        .mj-search input{width:100%;height:44px;border:1px solid var(--mj-line-strong);background:#fff;border-radius:12px;padding:0 14px 0 40px;font-size:14px;color:var(--mj-ink);outline:none}
        .mj-search input:focus{border-color:var(--mj-blue);box-shadow:0 0 0 3px var(--mj-blue-soft)}
        .mj-sel{height:44px;border:1px solid var(--mj-line-strong);background:#fff;border-radius:12px;padding:0 14px;font-size:13.5px;font-weight:600;color:var(--mj-ink-2);outline:none;cursor:pointer}
        .mj-btn{height:44px;padding:0 16px;border-radius:12px;background:#fff;border:1px solid var(--mj-line-strong);font-size:13.5px;font-weight:600;color:var(--mj-ink-2);display:inline-flex;align-items:center;gap:8px;cursor:pointer}
        .mj-btn:hover{background:#F8FAFC}
        .mj-btn.primary{background:var(--mj-blue);color:#fff;border-color:transparent;box-shadow:0 10px 22px -10px rgba(37,99,235,0.7)}
        .mj-btn.primary:hover{background:var(--mj-blue-deep)}
        .mj-btn.is-disabled{opacity:0.45;cursor:default;box-shadow:none}
        .mj-btn.is-disabled:hover{background:var(--mj-blue)}
        .mj-savelabel{font-size:11.5px;color:var(--mj-muted-2);font-weight:500}
        .mj-spacer{flex:1}

        .mj-panel{background:var(--mj-surface);border:1px solid var(--mj-line);border-radius:18px;box-shadow:0 1px 3px rgba(15,23,42,0.05);overflow:hidden}
        .mj-scroll{overflow-x:auto}
        .mj-table{border-collapse:separate;border-spacing:0;width:100%;min-width:1060px}
        .mj-table thead th{position:sticky;top:0;z-index:2;background:#F8FAFC;border-bottom:1px solid var(--mj-line-strong);font-size:12px;font-weight:700;color:var(--mj-ink-2);text-align:left;padding:12px 12px;white-space:nowrap}
        .mj-table thead th.center{text-align:center;padding:12px 4px}
        .mj-grp-head th{padding:7px 4px;font-size:11px;color:var(--mj-kraft-deep);background:var(--mj-kraft-soft);border-bottom:1px solid #E8DFC4;text-align:center;letter-spacing:0.4px}
        .mj-grp-head th.plain{background:#F8FAFC;border-bottom:none}
        .mj-table tbody tr{transition:background .12s}
        .mj-table tbody tr:hover{background:#FBFCFE}
        .mj-table tbody td{border-bottom:1px solid var(--mj-line);padding:7px 9px;vertical-align:middle}
        .mj-col-no{width:48px;text-align:center}
        .mj-rownum{font-weight:700;font-size:13px;color:var(--mj-muted-2)}

        /* ทักแล้ว checkbox */
        .mj-col-tick{width:64px;text-align:center}
        .mj-table thead th.mj-col-tick{font-size:11px}
        .mj-tick{display:inline-flex;align-items:center;justify-content:center;cursor:pointer}
        .mj-tick input{position:absolute;opacity:0;width:0;height:0}
        .mj-tick .box{width:22px;height:22px;border-radius:7px;border:1.5px solid var(--mj-line-strong);background:#fff;display:flex;align-items:center;justify-content:center;color:transparent;transition:all .12s}
        .mj-tick:hover .box{border-color:var(--mj-pos)}
        .mj-tick input:checked + .box{background:var(--mj-pos);border-color:var(--mj-pos);color:#fff}
        .mj-tick input:focus-visible + .box{box-shadow:0 0 0 3px var(--mj-pos-soft)}
        .mj-row-done{background:var(--mj-pos-soft) !important}
        .mj-row-done .mj-name-input{color:var(--mj-pos)}

        .mj-cell-input{width:100%;border:1px solid transparent;background:transparent;border-radius:8px;padding:8px 9px;font-size:13.5px;color:var(--mj-ink);outline:none}
        .mj-cell-input::placeholder{color:#CBD5E1}
        .mj-cell-input:hover{background:#F1F5F9}
        .mj-cell-input:focus{background:#fff;border-color:var(--mj-blue);box-shadow:0 0 0 3px var(--mj-blue-soft)}
        .mj-name-input{font-weight:600;font-size:14px}
        .mj-col-name{min-width:200px}
        .mj-col-job{min-width:130px}.mj-col-fac{min-width:150px}.mj-col-note{min-width:200px}
        .mj-col-age{width:64px}.mj-age-input{text-align:center}

        .mj-social{display:flex;align-items:center;gap:6px;border:1px solid transparent;border-radius:8px;padding:2px 4px 2px 6px}
        .mj-social:hover{background:#F1F5F9}
        .mj-social:focus-within{background:#fff;border-color:var(--mj-blue);box-shadow:0 0 0 3px var(--mj-blue-soft)}
        .mj-social .plat{width:24px;height:24px;border-radius:7px;flex-shrink:0;display:flex;align-items:center;justify-content:center;color:#fff;background:#CBD5E1}
        .mj-social input{flex:1;min-width:0;border:none;background:transparent;outline:none;font-size:12.5px;color:var(--mj-ink-2);padding:6px 2px}
        .mj-social input::placeholder{color:#CBD5E1}
        .mj-social .open{width:26px;height:26px;border-radius:7px;border:none;background:transparent;color:var(--mj-muted-2);display:flex;align-items:center;justify-content:center;cursor:pointer;flex-shrink:0}
        .mj-social .open:hover{background:#E2E8F0;color:var(--mj-ink)}

        .mj-score-cell{padding:6px 3px !important;text-align:center}
        .mj-score{width:44px;height:36px;border:1px solid var(--mj-line-strong);background:#fff;border-radius:9px;text-align:center;font-weight:700;font-size:14px;color:var(--mj-ink);outline:none;-moz-appearance:textfield}
        .mj-score::-webkit-outer-spin-button,.mj-score::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
        .mj-score:hover{border-color:var(--mj-muted-2)}
        .mj-score:focus{border-color:var(--mj-blue);box-shadow:0 0 0 3px var(--mj-blue-soft)}
        .mj-score.lv0{color:#CBD5E1}
        .mj-score.lv-lo{background:#FDECEC;border-color:#F8C9C9;color:#B91C1C}
        .mj-score.lv-mid{background:#FEF6E7;border-color:#F5E0AE;color:#B45309}
        .mj-score.lv-hi{background:#E7F7EF;border-color:#B9E6CE;color:#047857}

        .mj-total-cell{text-align:center;width:74px}
        .mj-total-chip{display:inline-flex;flex-direction:column;align-items:center;justify-content:center;min-width:52px;padding:5px 8px;border-radius:10px;background:#F1F5F9;line-height:1}
        .mj-total-chip .n{font-weight:800;font-size:16px;color:var(--mj-ink)}
        .mj-total-chip .n small{font-size:10px;color:var(--mj-muted-2);font-weight:600}
        .mj-total-chip .lab{font-size:9.5px;font-weight:700;margin-top:3px;letter-spacing:0.3px}
        .mj-total-chip.t-hi{background:var(--mj-pos-soft)}.mj-total-chip.t-hi .n{color:var(--mj-pos)}.mj-total-chip.t-hi .lab{color:var(--mj-pos)}
        .mj-total-chip.t-mid{background:var(--mj-amber-soft)}.mj-total-chip.t-mid .n{color:var(--mj-amber)}.mj-total-chip.t-mid .lab{color:var(--mj-amber)}
        .mj-total-chip.t-lo .lab{color:var(--mj-muted)}

        .mj-col-act{width:44px;text-align:center}
        .mj-del{width:30px;height:30px;border-radius:8px;border:none;background:transparent;color:var(--mj-muted-2);display:flex;align-items:center;justify-content:center;cursor:pointer;opacity:0;transition:opacity .12s}
        .mj-table tbody tr:hover .mj-del{opacity:1}
        .mj-del:hover{background:var(--mj-neg-soft);color:var(--mj-neg)}

        .mj-add-btn{width:100%;border:none;background:transparent;color:var(--mj-blue);font-weight:600;font-size:13.5px;padding:15px;display:flex;align-items:center;justify-content:center;gap:9px;cursor:pointer;border-top:1px dashed var(--mj-line-strong)}
        .mj-add-btn:hover{background:var(--mj-blue-soft)}
        .mj-add-btn .plus{width:24px;height:24px;border-radius:7px;background:var(--mj-blue);color:#fff;display:flex;align-items:center;justify-content:center}

        .mj-empty{padding:56px 20px;text-align:center;color:var(--mj-muted)}
        .mj-empty .ic{width:60px;height:60px;border-radius:16px;background:var(--mj-kraft-soft);color:var(--mj-kraft-deep);display:flex;align-items:center;justify-content:center;margin:0 auto 14px}
        .mj-empty h4{margin:0 0 5px;font-size:16px;color:var(--mj-ink-2)}
        .mj-empty p{margin:0;font-size:13.5px}

        .mj-foot-note{margin-top:14px;font-size:12px;color:var(--mj-muted-2);display:flex;align-items:center;gap:8px;justify-content:center}
        @media (max-width:720px){ .mj-stats{grid-template-columns:repeat(2,1fr)} }
      `}</style>

      <div className="mj-stats">
        <div className="mj-stat">
          <div className="k"><span className="ic" style={{ background: 'var(--mj-pos-soft)', color: 'var(--mj-pos)' }}><Icon name="star" className="w-3.5 h-3.5" /></span>คะแนนเฉลี่ย</div>
          <div className="v mj-num">{avg}<span className="u">/ 40</span></div>
        </div>
        <div className="mj-stat">
          <div className="k"><span className="ic" style={{ background: '#EDE9FE', color: '#7C3AED' }}><Icon name="check" className="w-3.5 h-3.5" /></span>ทักแล้ว</div>
          <div className="v mj-num">{contactedCount}<span className="u">/ {total} คน</span></div>
        </div>
      </div>

      <div className="mj-toolbar">
        <div className="mj-monthnav">
          <button onClick={prevMonth} aria-label="เดือนก่อนหน้า">‹</button>
          <div className="lab">{MJ_THAI_MONTHS[month]} {year + 543}</div>
          <button onClick={nextMonth} aria-label="เดือนถัดไป">›</button>
        </div>
        <div className="mj-search">
          <svg width="17" height="17" viewBox="0 0 24 24" fill="none"><circle cx="11" cy="11" r="7" stroke="currentColor" strokeWidth="2"/><path d="M21 21l-4-4" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/></svg>
          <input type="text" placeholder="ค้นหาชื่อ อาชีพ หรือมหาลัย…" value={search} onChange={e => setSearch(e.target.value)} />
        </div>
        <select className="mj-sel" value={sort} onChange={e => setSort(e.target.value)}>
          <option value="manual">เรียง: ลำดับที่เพิ่ม</option>
          <option value="score">เรียง: คะแนนมาก → น้อย</option>
          <option value="name">เรียง: ชื่อ ก → ฮ</option>
        </select>
        <div className="mj-spacer" />
        <span className="mj-savelabel">{dirty ? 'มีการแก้ไขที่ยังไม่ได้บันทึก' : saveLabel}</span>
        <button className="mj-btn" onClick={clearAll}><Icon name="x" className="w-3.5 h-3.5" />ล้างทั้งหมด</button>
        <button className="mj-btn" onClick={addRow}><Icon name="plus" className="w-4 h-4" />เพิ่มคนรู้จัก</button>
        <button className={`mj-btn primary ${(!dirty || saving) ? 'is-disabled' : ''}`} onClick={() => saveNow()} disabled={!dirty || saving}>
          <Icon name="check" className="w-4 h-4" />{saving ? 'กำลังบันทึก…' : 'บันทึก'}
        </button>
      </div>

      <div className="mj-panel">
        {loading ? (
          <div className="mj-empty"><h4>กำลังโหลด…</h4></div>
        ) : rows.length === 0 ? (
          <div className="mj-empty">
            <div className="ic"><Icon name="users" className="w-7 h-7" /></div>
            <h4>ยังไม่มีรายชื่อในเดือนนี้</h4>
            <p>กด “เพิ่มคนรู้จัก” เพื่อเริ่มจดคนแรกในเครือข่ายของคุณ</p>
          </div>
        ) : (
          <div className="mj-scroll">
            <table className="mj-table">
              <thead>
                <tr className="mj-grp-head">
                  <th className="plain" colSpan={7}></th>
                  <th colSpan={4}>10 คะแนน (ให้คะแนนละ 0–10)</th>
                  <th className="plain" colSpan={3}></th>
                </tr>
                <tr>
                  <th className="mj-col-no center">No.</th>
                  <th className="center mj-col-tick">ทักแล้ว</th>
                  <th>ชื่อ &amp; ลิงก์โซเชียล</th>
                  <th className="center">Age</th>
                  <th>อาชีพ</th>
                  <th>คณะ / มหาลัย</th>
                  <th className="center" style={{ width: 1 }}></th>
                  <th className="center">Active</th>
                  <th className="center">Friendly</th>
                  <th className="center">Money</th>
                  <th className="center">Relation</th>
                  <th className="center">รวม</th>
                  <th>หมายเหตุ</th>
                  <th className="center"></th>
                </tr>
              </thead>
              <tbody>
                {visibleRows.map((p, i) => {
                  const pf = mjPlatform(p.link);
                  const t = mjRowTotal(p);
                  const any = t > 0;
                  return (
                    <tr key={p.id} className={p.contacted ? 'mj-row-done' : ''}>
                      <td className="mj-col-no"><span className="mj-rownum mj-num">{i + 1}</span></td>
                      <td className="mj-col-tick">
                        <label className="mj-tick" title="ทักแล้ว">
                          <input type="checkbox" checked={!!p.contacted} onChange={() => toggleContacted(p.id)} />
                          <span className="box"><svg width="12" height="12" viewBox="0 0 24 24" fill="none"><path d="M5 12l4 4L19 6" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"/></svg></span>
                        </label>
                      </td>
                      <td className="mj-col-name">
                        <input className="mj-cell-input mj-name-input" placeholder="ชื่อ–สกุล / ชื่อเล่น" value={p.name} onChange={e => updateRow(p.id, { name: e.target.value })} />
                        <div className="mj-social">
                          <span className="plat" style={{ background: pf ? MJ_PLAT_BG[pf] : '#CBD5E1' }}>{MJ_PLAT_SVG[pf || 'web']}</span>
                          <input placeholder="วางลิงก์ IG หรือ Facebook…" value={p.link} onChange={e => updateRow(p.id, { link: e.target.value })} />
                          {p.link ? (
                            <button className="open" title="เปิดลิงก์" onClick={() => window.open(mjNormUrl(p.link), '_blank', 'noopener')}>
                              <svg width="14" height="14" viewBox="0 0 24 24" fill="none"><path d="M14 4h6v6M20 4l-9 9M19 13v6a1 1 0 01-1 1H5a1 1 0 01-1-1V6a1 1 0 011-1h6" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round"/></svg>
                            </button>
                          ) : null}
                        </div>
                      </td>
                      <td className="mj-col-age"><input className="mj-cell-input mj-age-input mj-num" inputMode="numeric" placeholder="–" value={p.age} onChange={e => updateRow(p.id, { age: e.target.value })} /></td>
                      <td className="mj-col-job"><input className="mj-cell-input" placeholder="อาชีพ" value={p.job} onChange={e => updateRow(p.id, { job: e.target.value })} /></td>
                      <td className="mj-col-fac"><input className="mj-cell-input" placeholder="คณะ / มหาลัย" value={p.faculty} onChange={e => updateRow(p.id, { faculty: e.target.value })} /></td>
                      <td style={{ padding: 0, width: 1, background: 'var(--mj-kraft-soft)' }}></td>
                      {SCORES.map((s, si) => (
                        <td key={s.f} className="mj-score-cell" style={si === SCORES.length - 1 ? { borderRight: '1px solid var(--mj-kraft-soft)' } : undefined}>
                          <input className={`mj-score mj-num ${mjScoreLevel(p[s.f])}`} type="number" min="0" max="10" value={p[s.f] || 0}
                            onChange={e => updateRow(p.id, { [s.f]: Math.max(0, Math.min(10, Math.round(+e.target.value || 0))) })} />
                        </td>
                      ))}
                      <td className="mj-total-cell">
                        <span className={`mj-total-chip ${mjTotalClass(t)}`}>
                          <span className="n mj-num">{any ? <>{t}<small>/40</small></> : <small style={{ fontSize: 13 }}>–</small>}</span>
                          <span className="lab">{mjTotalLabel(t, any)}</span>
                        </span>
                      </td>
                      <td className="mj-col-note"><input className="mj-cell-input" placeholder="หมายเหตุ…" value={p.note} onChange={e => updateRow(p.id, { note: e.target.value })} /></td>
                      <td className="mj-col-act">
                        <button className="mj-del" title="ลบ" onClick={() => removeRow(p.id)}>
                          <svg width="15" height="15" viewBox="0 0 24 24" fill="none"><path d="M4 7h16M9 7V5a2 2 0 012-2h2a2 2 0 012 2v2m-1 0l-.5 13h-7L7 7" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/></svg>
                        </button>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
            <button className="mj-add-btn" onClick={addRow}>
              <span className="plus"><Icon name="plus" className="w-3.5 h-3.5" /></span>
              เพิ่มคนรู้จักอีกคน
            </button>
          </div>
        )}
      </div>

      <div className="mj-foot-note">
        <Icon name="info" className="w-3.5 h-3.5" />
        เก็บแยกตามเดือนและแยกตามบัญชีผู้ใช้ — แก้ไขแล้วอย่าลืมกด “บันทึก” · ติ๊ก “ทักแล้ว” เมื่อทักคนนั้นเรียบร้อย
      </div>
    </div>
  );
}
