// Training.jsx — Owner-side Training management.
// Tabs:
//   Items       — table list of all training items, with category filter
//   Categories  — CRUD for category labels
//   By Staff    — each staff member's certification % by category
//   Coverage    — full staff × items matrix
//   Completions — chronological event log
//
// Data shape additions for category support:
//   - window.SAMPLE_TRAINING_CATEGORIES  → [{ id, name, color }]
//   - item.categoryId                    → string | null

const { useState: useTr, useMemo: useMemoTr, useEffect: useEffectTr } = React;

const TRAINING_ITEMS_KEY        = 'portal_training_items_v2';
const TRAINING_COMPLETIONS_KEY  = 'portal_training_completions_v1';
const TRAINING_CATEGORIES_KEY   = 'portal_training_categories_v1';

const portalIsAssigned   = window.isAssignedTraining;
const portalHasCompleted = window.hasCompletedTraining;

const seedItems       = (window.SAMPLE_TRAINING_ITEMS || []).slice();
const seedCategories  = (window.SAMPLE_TRAINING_CATEGORIES || []).slice();

// ------------------------------------------------------------------
// Local helpers
// ------------------------------------------------------------------
const PField = ({ label, subtitle, children }) => (
  <div style={{ marginBottom: 18 }}>
    <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--fg-1)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 4 }}>{label}</div>
    {subtitle && <div style={{ fontSize: 12, color: 'var(--fg-3)', marginBottom: 8, lineHeight: 1.4 }}>{subtitle}</div>}
    {children}
  </div>
);

// Tiny pill that shows a category label with its color dot.
const CategoryPill = ({ category, size = 'sm' }) => {
  if (!category) {
    return (
      <span style={{
        display: 'inline-flex', alignItems: 'center', gap: 6,
        padding: size === 'sm' ? '2px 8px' : '4px 10px',
        background: 'var(--bg-sunken)',
        borderRadius: 999,
        fontSize: size === 'sm' ? 11 : 12,
        color: 'var(--fg-3)',
        fontWeight: 500,
      }}>Uncategorized</span>
    );
  }
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: size === 'sm' ? '2px 8px' : '4px 10px',
      background: category.color + '14',
      borderRadius: 999,
      fontSize: size === 'sm' ? 11 : 12,
      color: category.color,
      fontWeight: 600,
    }}>
      <span style={{ width: 6, height: 6, borderRadius: 999, background: category.color }} />
      {category.name}
    </span>
  );
};

// ------------------------------------------------------------------
// Top-level
// ------------------------------------------------------------------
const Training = () => {
  const [tab, setTab] = useTr('items');
  const [items, setItems]             = usePersistent(TRAINING_ITEMS_KEY, seedItems);
  const [categories, setCategories]   = usePersistent(TRAINING_CATEGORIES_KEY, seedCategories);
  const [completions, setCompletions] = usePersistent(TRAINING_COMPLETIONS_KEY, window.SAMPLE_TRAINING_COMPLETIONS || {});

  const completionsCount = Object.values(completions).reduce((a, arr) => a + arr.length, 0);

  return (
    <div className="portal-page-wide" style={{ maxWidth: 1320 }}>
      <div className="portal-page-header" style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 24, flexWrap: 'wrap' }}>
        <div>
          <h1 className="portal-page-title">Training</h1>
          <div className="portal-page-sub">Library of training items, who's done them, and who can sign off.</div>
        </div>
      </div>

      <div style={{
        display: 'flex', gap: 0,
        borderBottom: '1px solid var(--border-2)',
        marginTop: 18, marginBottom: 24,
        overflowX: 'auto',
      }}>
        {[
          { id: 'items',       label: 'Items',       count: items.length },
          { id: 'categories',  label: 'Categories',  count: categories.length },
          { id: 'staff',       label: 'By Staff',    count: null },
          { id: 'coverage',    label: 'Coverage',    count: null },
          { id: 'completions', label: 'Completions', count: completionsCount },
        ].map(t => (
          <button key={t.id} onClick={() => setTab(t.id)} style={{
            padding: '10px 16px',
            background: 'transparent',
            border: 'none',
            borderBottom: '2px solid ' + (tab === t.id ? 'var(--fg-1)' : 'transparent'),
            marginBottom: -1,
            color: tab === t.id ? 'var(--fg-1)' : 'var(--fg-2)',
            fontSize: 14, fontWeight: tab === t.id ? 600 : 500,
            cursor: 'pointer',
            display: 'inline-flex', alignItems: 'center', gap: 8,
            whiteSpace: 'nowrap',
          }}>
            {t.label}
            {t.count !== null && (
              <span style={{
                fontSize: 11, fontWeight: 600,
                color: 'var(--fg-3)',
                background: 'var(--bg-sunken)',
                padding: '1px 7px', borderRadius: 999,
                fontFamily: 'var(--font-num)',
              }}>{t.count}</span>
            )}
          </button>
        ))}
      </div>

      {tab === 'items'       && <TrainingItems       items={items} setItems={setItems} categories={categories} completions={completions} />}
      {tab === 'categories'  && <TrainingCategories  categories={categories} setCategories={setCategories} items={items} setItems={setItems} />}
      {tab === 'staff'       && <TrainingByStaff     items={items} categories={categories} completions={completions} />}
      {tab === 'coverage'    && <TrainingCoverage    items={items} categories={categories} completions={completions} />}
      {tab === 'completions' && <TrainingCompletions items={items} completions={completions} setCompletions={setCompletions} />}
    </div>
  );
};

// ------------------------------------------------------------------
// Items — TABLE list (replaces the previous card grid)
// ------------------------------------------------------------------
const TrainingItems = ({ items, setItems, categories, completions }) => {
  const [editing, setEditing] = useTr(null);
  const [search, setSearch]   = useTr('');
  const [catFilter, setCatFilter] = useTr('all'); // 'all' | categoryId | 'none'
  const [sort, setSort]       = useTr({ key: 'title', dir: 'asc' });

  const catById = useMemoTr(() => Object.fromEntries(categories.map(c => [c.id, c])), [categories]);

  const filtered = useMemoTr(() => {
    const q = search.trim().toLowerCase();
    let out = items.filter(i => {
      if (q && !(i.title.toLowerCase().includes(q) || (i.summary || '').toLowerCase().includes(q))) return false;
      if (catFilter === 'all') return true;
      if (catFilter === 'none') return !i.categoryId;
      return i.categoryId === catFilter;
    });

    // Decorate with completion stats so we can sort by them.
    out = out.map(it => {
      const total = window.SAMPLE_STAFF.filter(s => portalIsAssigned(it, s)).length;
      const done  = window.SAMPLE_STAFF.filter(s => portalIsAssigned(it, s) && portalHasCompleted(it, s, completions)).length;
      const pct   = total === 0 ? 0 : Math.round((done / total) * 100);
      return { ...it, _total: total, _done: done, _pct: pct, _cat: catById[it.categoryId] };
    });

    const dir = sort.dir === 'asc' ? 1 : -1;
    out.sort((a, b) => {
      switch (sort.key) {
        case 'title':    return a.title.localeCompare(b.title) * dir;
        case 'category': return ((a._cat?.name || 'zzz').localeCompare(b._cat?.name || 'zzz')) * dir;
        case 'assigned': return (a._total - b._total) * dir;
        case 'done':     return (a._done - b._done) * dir;
        case 'pct':      return (a._pct - b._pct) * dir;
        case 'updated':  return ((a.createdAt || '').localeCompare(b.createdAt || '')) * dir;
        default:         return 0;
      }
    });
    return out;
  }, [items, search, catFilter, sort, completions, catById]);

  const addItem = () => {
    setEditing({
      id: 'new',
      categoryId: categories[0]?.id || null,
      title: '',
      summary: '',
      bodyHtml: '<p></p>',
      media: [],
      assignedRoles: ['Line', 'Front', 'Dish'],
      assignedStaffIds: null,
      trainerIds: ['ryan'],
      createdAt: new Date().toISOString(),
    });
  };

  const saveItem = (it) => {
    if (it.id === 'new') {
      const newId = 't-' + Date.now().toString(36);
      setItems(prev => [...prev, { ...it, id: newId }]);
    } else {
      setItems(prev => prev.map(p => p.id === it.id ? it : p));
    }
    setEditing(null);
  };

  const deleteItem = (id) => {
    if (!confirm('Delete this training item? Completion history is preserved.')) return;
    setItems(prev => prev.filter(p => p.id !== id));
    setEditing(null);
  };

  // Counts per category for filter chips
  const catCounts = useMemoTr(() => {
    const map = { all: items.length, none: 0 };
    categories.forEach(c => map[c.id] = 0);
    items.forEach(i => {
      if (!i.categoryId || !map.hasOwnProperty(i.categoryId)) map.none += !i.categoryId ? 1 : 0;
      else map[i.categoryId] += 1;
    });
    return map;
  }, [items, categories]);

  const setSortKey = (key) => {
    setSort(s => s.key === key ? { key, dir: s.dir === 'asc' ? 'desc' : 'asc' } : { key, dir: 'asc' });
  };

  return (
    <div>
      {/* Toolbar */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 12, flexWrap: 'wrap' }}>
        <div style={{
          flex: '0 0 auto', width: 280,
          display: 'flex', alignItems: 'center', gap: 8,
          padding: '8px 12px',
          background: 'var(--bg-sunken)',
          borderRadius: 8,
        }}>
          <PIcon name="search" size={14} color="var(--fg-3)" />
          <input
            value={search}
            onChange={e => setSearch(e.target.value)}
            placeholder="Search items"
            style={{ flex: 1, border: 'none', background: 'transparent', outline: 'none', fontSize: 13 }}
          />
        </div>
        <div style={{ flex: 1 }} />
        <PBtn variant="primary" onClick={addItem}>
          <PIcon name="plus" size={14} />
          New item
        </PBtn>
      </div>

      {/* Category filter chips */}
      <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 14 }}>
        <FilterChip active={catFilter === 'all'} onClick={() => setCatFilter('all')} count={catCounts.all}>All</FilterChip>
        {categories.map(c => (
          <FilterChip key={c.id} active={catFilter === c.id} onClick={() => setCatFilter(c.id)} color={c.color} count={catCounts[c.id] || 0}>
            {c.name}
          </FilterChip>
        ))}
        {catCounts.none > 0 && (
          <FilterChip active={catFilter === 'none'} onClick={() => setCatFilter('none')} count={catCounts.none}>Uncategorized</FilterChip>
        )}
      </div>

      {/* Table */}
      {filtered.length === 0 ? (
        <div className="portal-empty">
          <div style={{ fontSize: 14, color: 'var(--fg-2)' }}>
            {search || catFilter !== 'all' ? 'No items match.' : 'No training items yet.'}
          </div>
          {!search && catFilter === 'all' && (
            <PBtn variant="ghost" onClick={addItem} style={{ marginTop: 10 }}>
              <PIcon name="plus" size={14} />
              Add the first one
            </PBtn>
          )}
        </div>
      ) : (
        <div style={{
          background: '#FFFFFF',
          border: '1px solid var(--border-2)',
          borderRadius: 10,
          overflow: 'hidden',
        }}>
          <table style={{ borderCollapse: 'collapse', width: '100%' }}>
            <thead>
              <tr style={{ borderBottom: '1px solid var(--border-2)', background: '#FAFAF9' }}>
                <Th sortable onClick={() => setSortKey('title')}    sort={sort} k="title">Title</Th>
                <Th sortable onClick={() => setSortKey('category')} sort={sort} k="category" w={170}>Category</Th>
                <Th sortable onClick={() => setSortKey('assigned')} sort={sort} k="assigned" w={110} align="right">Assigned</Th>
                <Th                                                                       w={130}>Trainers</Th>
                <Th sortable onClick={() => setSortKey('pct')}      sort={sort} k="pct"      w={220}>Completion</Th>
                <Th w={36} />
              </tr>
            </thead>
            <tbody>
              {filtered.map(item => {
                const trainers = (item.trainerIds || []).map(id => window.SAMPLE_STAFF.find(s => s.id === id)).filter(Boolean);
                const pctColor = item._pct === 100 ? '#2D6A2A' : (item._pct >= 50 ? 'var(--fg-1)' : '#B45309');
                return (
                  <tr key={item.id}
                    onClick={() => setEditing(item)}
                    style={{ borderBottom: '1px solid var(--border-2)', cursor: 'pointer' }}
                    onMouseEnter={e => e.currentTarget.style.background = '#FBFAF8'}
                    onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
                  >
                    <td style={{ padding: '12px 14px' }}>
                      <div style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--fg-1)', lineHeight: 1.3, letterSpacing: '-0.005em' }}>
                        {item.title || <span style={{ color: 'var(--fg-3)', fontStyle: 'italic', fontWeight: 500 }}>Untitled</span>}
                      </div>
                      {item.summary && (
                        <div style={{ fontSize: 12, color: 'var(--fg-3)', marginTop: 2, lineHeight: 1.35, maxWidth: 480, textOverflow: 'ellipsis', whiteSpace: 'nowrap', overflow: 'hidden' }}>
                          {item.summary}
                        </div>
                      )}
                    </td>
                    <td style={{ padding: '12px 14px' }}>
                      <CategoryPill category={item._cat} />
                    </td>
                    <td style={{ padding: '12px 14px', textAlign: 'right' }}>
                      <div style={{ fontSize: 13, color: 'var(--fg-2)', fontFamily: 'var(--font-num)' }}>{item._total}</div>
                      <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 1 }}>
                        {item.assignedStaffIds && item.assignedStaffIds.length > 0
                          ? 'specific'
                          : (item.assignedRoles && item.assignedRoles.length > 0)
                            ? item.assignedRoles.join('·')
                            : 'everyone'}
                      </div>
                    </td>
                    <td style={{ padding: '12px 14px' }}>
                      <PAvatarStack ids={trainers.map(t => t.id)} size={20} max={4} />
                    </td>
                    <td style={{ padding: '12px 14px' }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                        <div style={{ flex: 1, height: 5, background: 'var(--bg-sunken)', borderRadius: 999, overflow: 'hidden' }}>
                          <div style={{ width: item._pct + '%', height: '100%', background: pctColor, transition: 'width 200ms ease' }} />
                        </div>
                        <span style={{ fontSize: 12, color: 'var(--fg-2)', fontWeight: 600, fontFamily: 'var(--font-num)', width: 36, textAlign: 'right' }}>{item._pct}%</span>
                        <span style={{ fontSize: 11, color: 'var(--fg-3)', fontFamily: 'var(--font-num)', width: 38, textAlign: 'right' }}>{item._done}/{item._total}</span>
                      </div>
                    </td>
                    <td style={{ padding: '12px 6px', textAlign: 'center' }}>
                      <PIcon name="chevronR" size={14} color="var(--fg-3)" />
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}

      {editing && (
        <TrainingEditor
          item={editing}
          categories={categories}
          onCancel={() => setEditing(null)}
          onSave={saveItem}
          onDelete={editing.id !== 'new' ? () => deleteItem(editing.id) : null}
          completions={completions}
        />
      )}
    </div>
  );
};

const Th = ({ children, sortable, onClick, sort, k, w, align = 'left' }) => {
  const active = sortable && sort && sort.key === k;
  return (
    <th style={{
      textAlign: align,
      padding: '10px 14px',
      fontSize: 11, fontWeight: 600,
      color: active ? 'var(--fg-1)' : 'var(--fg-2)',
      textTransform: 'uppercase', letterSpacing: '0.06em',
      width: w, cursor: sortable ? 'pointer' : 'default',
      userSelect: 'none',
      whiteSpace: 'nowrap',
    }} onClick={onClick}>
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, justifyContent: align === 'right' ? 'flex-end' : 'flex-start' }}>
        {children}
        {sortable && (
          <span style={{ fontSize: 10, opacity: active ? 1 : 0.3, fontFamily: 'var(--font-num)' }}>
            {active ? (sort.dir === 'asc' ? '↑' : '↓') : '↕'}
          </span>
        )}
      </span>
    </th>
  );
};

const FilterChip = ({ active, onClick, children, color, count }) => (
  <button onClick={onClick} style={{
    display: 'inline-flex', alignItems: 'center', gap: 6,
    padding: '5px 11px',
    background: active ? 'var(--fg-1)' : '#FFFFFF',
    color: active ? '#FFFFFF' : 'var(--fg-2)',
    border: '1px solid ' + (active ? 'var(--fg-1)' : 'var(--border-2)'),
    borderRadius: 999,
    fontSize: 12, fontWeight: 500,
    cursor: 'pointer',
  }}>
    {color && <span style={{ width: 7, height: 7, borderRadius: 999, background: color }} />}
    {children}
    {typeof count === 'number' && (
      <span style={{
        fontSize: 11, fontWeight: 600,
        color: active ? 'rgba(255,255,255,0.7)' : 'var(--fg-3)',
        fontFamily: 'var(--font-num)',
      }}>{count}</span>
    )}
  </button>
);

// ------------------------------------------------------------------
// Categories — CRUD list
// ------------------------------------------------------------------
const PALETTE = ['#2563EB', '#EA580C', '#059669', '#7C3AED', '#BE123C', '#0891B2', '#DB2777', '#CA8A04', '#475569'];

const TrainingCategories = ({ categories, setCategories, items, setItems }) => {
  const [draft, setDraft] = useTr(null);

  const addCategory = () => setDraft({ id: 'new', name: '', color: PALETTE[categories.length % PALETTE.length] });

  const saveCategory = () => {
    if (!draft.name.trim()) return;
    if (draft.id === 'new') {
      const newId = 'c-' + Date.now().toString(36);
      setCategories(prev => [...prev, { ...draft, id: newId }]);
    } else {
      setCategories(prev => prev.map(c => c.id === draft.id ? draft : c));
    }
    setDraft(null);
  };

  const deleteCategory = (id) => {
    const count = items.filter(i => i.categoryId === id).length;
    if (count > 0) {
      if (!confirm(`This category has ${count} item${count === 1 ? '' : 's'}. They will be set to uncategorized. Continue?`)) return;
      setItems(prev => prev.map(i => i.categoryId === id ? { ...i, categoryId: null } : i));
    }
    setCategories(prev => prev.filter(c => c.id !== id));
    if (draft && draft.id === id) setDraft(null);
  };

  const itemCount = (id) => items.filter(i => i.categoryId === id).length;

  return (
    <div style={{ maxWidth: 720 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 14 }}>
        <div style={{ fontSize: 13, color: 'var(--fg-2)', lineHeight: 1.5 }}>
          Categories group training items by area. Each staff member's certification % is tracked per category.
        </div>
        <PBtn variant="primary" onClick={addCategory}>
          <PIcon name="plus" size={14} />
          New category
        </PBtn>
      </div>

      <div style={{
        background: '#FFFFFF',
        border: '1px solid var(--border-2)',
        borderRadius: 10,
        overflow: 'hidden',
      }}>
        {categories.length === 0 ? (
          <div style={{ padding: 24, textAlign: 'center', fontSize: 13, color: 'var(--fg-3)' }}>
            No categories yet.
          </div>
        ) : categories.map((c, i) => (
          <div key={c.id} style={{
            display: 'flex', alignItems: 'center', gap: 12,
            padding: '12px 16px',
            borderTop: i === 0 ? 'none' : '1px solid var(--border-2)',
          }}>
            <span style={{ width: 14, height: 14, borderRadius: 4, background: c.color, flexShrink: 0 }} />
            <div style={{ flex: 1, fontSize: 14, fontWeight: 500, color: 'var(--fg-1)' }}>{c.name}</div>
            <div style={{ fontSize: 12, color: 'var(--fg-3)', fontFamily: 'var(--font-num)' }}>
              {itemCount(c.id)} item{itemCount(c.id) === 1 ? '' : 's'}
            </div>
            <div style={{ display: 'flex', gap: 4 }}>
              <button onClick={() => setDraft({ ...c })} style={{
                width: 28, height: 28, borderRadius: 6, background: 'transparent', border: 'none', cursor: 'pointer',
                display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              }}>
                <PIcon name="edit" size={13} color="var(--fg-2)" />
              </button>
              <button onClick={() => deleteCategory(c.id)} style={{
                width: 28, height: 28, borderRadius: 6, background: 'transparent', border: 'none', cursor: 'pointer',
                display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              }}>
                <PIcon name="trash" size={13} color="var(--fg-3)" />
              </button>
            </div>
          </div>
        ))}
      </div>

      {draft && (
        <PModal open={true} onClose={() => setDraft(null)} width={420}
          title={draft.id === 'new' ? 'New category' : 'Edit category'}>
          <div style={{ padding: '8px 24px 20px' }}>
            <PField label="Name">
              <input value={draft.name} onChange={e => setDraft(d => ({ ...d, name: e.target.value }))}
                placeholder="e.g. Front of House" className="portal-input" autoFocus />
            </PField>
            <PField label="Color">
              <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                {PALETTE.map(col => (
                  <button key={col} onClick={() => setDraft(d => ({ ...d, color: col }))} style={{
                    width: 30, height: 30, borderRadius: 8,
                    background: col, border: '2px solid ' + (draft.color === col ? 'var(--fg-1)' : 'transparent'),
                    cursor: 'pointer',
                  }} />
                ))}
              </div>
            </PField>
            <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, marginTop: 10 }}>
              <PBtn variant="ghost" onClick={() => setDraft(null)}>Cancel</PBtn>
              <PBtn variant="primary" onClick={saveCategory} disabled={!draft.name.trim()}>
                {draft.id === 'new' ? 'Create' : 'Save'}
              </PBtn>
            </div>
          </div>
        </PModal>
      )}
    </div>
  );
};

// ------------------------------------------------------------------
// By Staff — per-staff per-category certification breakdown
// ------------------------------------------------------------------
const TrainingByStaff = ({ items, categories, completions }) => {
  const [expanded, setExpanded] = useTr(null);

  // For each staff & category compute { assigned, done, pct }
  const rows = useMemoTr(() => {
    return window.SAMPLE_STAFF.map(staff => {
      const byCat = {};
      categories.forEach(c => byCat[c.id] = { assigned: 0, done: 0, items: [] });
      const uncat = { assigned: 0, done: 0, items: [] };

      items.forEach(it => {
        if (!portalIsAssigned(it, staff)) return;
        const target = it.categoryId && byCat[it.categoryId] ? byCat[it.categoryId] : uncat;
        target.assigned += 1;
        const done = portalHasCompleted(it, staff, completions);
        if (done) target.done += 1;
        target.items.push({ item: it, done });
      });

      const total = Object.values(byCat).reduce((a, b) => a + b.assigned, 0) + uncat.assigned;
      const doneTotal = Object.values(byCat).reduce((a, b) => a + b.done, 0) + uncat.done;
      const pct = total === 0 ? 0 : Math.round((doneTotal / total) * 100);

      return { staff, byCat, uncat, total, doneTotal, pct };
    });
  }, [items, categories, completions]);

  return (
    <div>
      <div style={{ fontSize: 13, color: 'var(--fg-2)', lineHeight: 1.5, marginBottom: 14 }}>
        Each staff member's certification progress, broken out by category. Click a row to see the items.
      </div>

      <div style={{
        background: '#FFFFFF',
        border: '1px solid var(--border-2)',
        borderRadius: 10,
        overflow: 'hidden',
      }}>
        {/* Header */}
        <div style={{
          display: 'grid',
          gridTemplateColumns: `260px repeat(${categories.length}, 1fr) 160px`,
          gap: 0,
          background: '#FAFAF9',
          borderBottom: '1px solid var(--border-2)',
          padding: '10px 0',
        }}>
          <div style={{ padding: '0 16px', fontSize: 11, fontWeight: 600, color: 'var(--fg-2)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Staff</div>
          {categories.map(c => (
            <div key={c.id} style={{ padding: '0 10px', textAlign: 'center' }}>
              <div style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 11, fontWeight: 600, color: 'var(--fg-2)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>
                <span style={{ width: 6, height: 6, borderRadius: 999, background: c.color }} />
                {c.name}
              </div>
            </div>
          ))}
          <div style={{ padding: '0 16px', textAlign: 'right', fontSize: 11, fontWeight: 600, color: 'var(--fg-2)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>Overall</div>
        </div>

        {/* Rows */}
        {rows.map(row => {
          const isOpen = expanded === row.staff.id;
          return (
            <div key={row.staff.id}>
              <div
                onClick={() => setExpanded(isOpen ? null : row.staff.id)}
                style={{
                  display: 'grid',
                  gridTemplateColumns: `260px repeat(${categories.length}, 1fr) 160px`,
                  gap: 0,
                  alignItems: 'center',
                  padding: '14px 0',
                  borderTop: '1px solid var(--border-2)',
                  cursor: 'pointer',
                  background: isOpen ? '#FBFAF8' : 'transparent',
                  transition: 'background 120ms ease',
                }}
                onMouseEnter={e => { if (!isOpen) e.currentTarget.style.background = '#FBFAF8'; }}
                onMouseLeave={e => { if (!isOpen) e.currentTarget.style.background = 'transparent'; }}
              >
                <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '0 16px' }}>
                  <PIcon name={isOpen ? 'chevronD' : 'chevronR'} size={13} color="var(--fg-3)" />
                  <PAvatar staff={row.staff} size={32} />
                  <div>
                    <div style={{ fontSize: 14, fontWeight: 600, color: 'var(--fg-1)' }}>{row.staff.name}</div>
                    <div style={{ fontSize: 11, color: 'var(--fg-3)' }}>{row.staff.role}</div>
                  </div>
                </div>

                {categories.map(c => {
                  const cell = row.byCat[c.id] || { assigned: 0, done: 0 };
                  return (
                    <div key={c.id} style={{ padding: '0 10px' }}>
                      <CatProgress assigned={cell.assigned} done={cell.done} color={c.color} />
                    </div>
                  );
                })}

                <div style={{ padding: '0 16px', textAlign: 'right' }}>
                  <div style={{ fontSize: 18, fontWeight: 700, color: row.pct === 100 ? '#2D6A2A' : 'var(--fg-1)', fontFamily: 'var(--font-num)', letterSpacing: '-0.02em' }}>
                    {row.pct}<span style={{ fontSize: 12, fontWeight: 500, color: 'var(--fg-3)', marginLeft: 1 }}>%</span>
                  </div>
                  <div style={{ fontSize: 11, color: 'var(--fg-3)', fontFamily: 'var(--font-num)' }}>{row.doneTotal} of {row.total}</div>
                </div>
              </div>

              {isOpen && (
                <div style={{
                  borderTop: '1px solid var(--border-2)',
                  background: '#FBFAF8',
                  padding: '14px 24px 18px',
                }}>
                  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(260px, 1fr))', gap: 14 }}>
                    {categories.map(c => {
                      const cell = row.byCat[c.id];
                      if (!cell || cell.assigned === 0) return null;
                      return (
                        <div key={c.id}>
                          <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 6 }}>
                            <span style={{ width: 8, height: 8, borderRadius: 999, background: c.color }} />
                            <span style={{ fontSize: 11, fontWeight: 700, color: 'var(--fg-1)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{c.name}</span>
                            <span style={{ fontSize: 11, color: 'var(--fg-3)', fontFamily: 'var(--font-num)', marginLeft: 'auto' }}>
                              {cell.done}/{cell.assigned}
                            </span>
                          </div>
                          <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                            {cell.items.map(({ item, done }) => (
                              <div key={item.id} style={{
                                display: 'flex', alignItems: 'center', gap: 8,
                                fontSize: 12.5,
                              }}>
                                <span style={{
                                  width: 14, height: 14, borderRadius: 999,
                                  background: done ? '#E7F0E0' : 'var(--bg-sunken)',
                                  display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                                  flexShrink: 0,
                                }}>
                                  {done ? <PIcon name="check" size={9} color="#2D6A2A" /> : null}
                                </span>
                                <span style={{ color: done ? 'var(--fg-1)' : 'var(--fg-3)', textDecoration: done ? 'none' : 'none' }}>
                                  {item.title}
                                </span>
                              </div>
                            ))}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
};

const CatProgress = ({ assigned, done, color }) => {
  if (assigned === 0) {
    return <div style={{ textAlign: 'center', fontSize: 12, color: 'var(--fg-3)' }}>—</div>;
  }
  const pct = Math.round((done / assigned) * 100);
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4 }}>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 4 }}>
        <span style={{ fontSize: 14, fontWeight: 700, color: pct === 100 ? '#2D6A2A' : 'var(--fg-1)', fontFamily: 'var(--font-num)' }}>{pct}%</span>
        <span style={{ fontSize: 10.5, color: 'var(--fg-3)', fontFamily: 'var(--font-num)' }}>{done}/{assigned}</span>
      </div>
      <div style={{ width: '100%', height: 4, background: 'var(--bg-sunken)', borderRadius: 999, overflow: 'hidden' }}>
        <div style={{ width: pct + '%', height: '100%', background: pct === 100 ? '#2D6A2A' : color }} />
      </div>
    </div>
  );
};

// ------------------------------------------------------------------
// Editor — full-form modal for a training item
// ------------------------------------------------------------------
const TrainingEditor = ({ item, categories, onCancel, onSave, onDelete, completions }) => {
  const [draft, setDraft] = useTr(item);
  const update = (patch) => setDraft(d => ({ ...d, ...patch }));

  const allStaff = window.SAMPLE_STAFF;
  const scopeMode = (draft.assignedStaffIds && draft.assignedStaffIds.length > 0)
    ? 'staff'
    : ((draft.assignedRoles || []).includes('Admin') ? 'everyone' : 'crew');

  const setScopeMode = (mode) => {
    if (mode === 'everyone') {
      update({ assignedStaffIds: null, assignedRoles: ['Admin', 'Crew'] });
    } else if (mode === 'crew') {
      update({ assignedStaffIds: null, assignedRoles: ['Crew'] });
    } else {
      update({ assignedStaffIds: allStaff.filter(s => (draft.assignedRoles || []).includes(s.role)).map(s => s.id) });
    }
  };

  const toggleStaff = (id) => {
    const list = draft.assignedStaffIds || [];
    const next = list.includes(id) ? list.filter(x => x !== id) : [...list, id];
    update({ assignedStaffIds: next });
  };

  const toggleTrainer = (id) => {
    const list = draft.trainerIds || [];
    const next = list.includes(id) ? list.filter(x => x !== id) : [...list, id];
    update({ trainerIds: next });
  };

  const addMedia = (type) => {
    const placeholder = type === 'video' ? 'New video · 0:00' : 'New image';
    update({ media: [...(draft.media || []), { type, alt: '', placeholder }] });
  };
  const updateMedia = (i, patch) => update({ media: draft.media.map((m, j) => j === i ? { ...m, ...patch } : m) });
  const removeMedia = (i) => update({ media: draft.media.filter((_, j) => j !== i) });

  return (
    <PModal open={true} onClose={onCancel} width={760}>
      <div style={{ display: 'flex', flexDirection: 'column', maxHeight: '85vh' }}>
        <div style={{
          padding: '18px 24px',
          borderBottom: '1px solid var(--border-2)',
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          flexShrink: 0,
        }}>
          <div style={{ fontSize: 16, fontWeight: 600, letterSpacing: '-0.01em' }}>
            {item.id === 'new' ? 'New training item' : 'Edit training item'}
          </div>
          <button onClick={onCancel} style={{
            width: 28, height: 28, borderRadius: 6, background: 'transparent', border: 'none',
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer',
          }}>
            <PIcon name="x" size={16} color="var(--fg-2)" />
          </button>
        </div>

        <div style={{ flex: 1, overflow: 'auto', padding: '20px 24px' }}>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 200px', gap: 14 }}>
            <PField label="Title">
              <input value={draft.title} onChange={e => update({ title: e.target.value })}
                placeholder="e.g. POS — Taking Orders" className="portal-input" />
            </PField>
            <PField label="Category">
              <select
                value={draft.categoryId || ''}
                onChange={e => update({ categoryId: e.target.value || null })}
                className="portal-input"
                style={{ paddingRight: 28 }}
              >
                <option value="">Uncategorized</option>
                {categories.map(c => (
                  <option key={c.id} value={c.id}>{c.name}</option>
                ))}
              </select>
            </PField>
          </div>

          <PField label="Summary" subtitle="One-line description shown in the staff app's list view.">
            <input value={draft.summary} onChange={e => update({ summary: e.target.value })}
              placeholder="What this trains" className="portal-input" />
          </PField>

          <PField label="Body" subtitle="HTML supported. Use <h3>, <ol>, <ul>, <p>, <b> as needed.">
            <textarea value={draft.bodyHtml} onChange={e => update({ bodyHtml: e.target.value })}
              rows={9}
              className="portal-input"
              style={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 12.5, lineHeight: 1.5 }}
            />
          </PField>

          <PField label="Attachments" subtitle="Photo & video placeholders shown in the iPad reader.">
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {(draft.media || []).map((m, i) => (
                <div key={i} style={{
                  display: 'flex', alignItems: 'center', gap: 10,
                  padding: '10px 12px',
                  background: 'var(--bg-sunken)',
                  borderRadius: 8,
                }}>
                  <span style={{
                    width: 22, height: 22, borderRadius: 4,
                    background: m.type === 'video' ? '#0F1115' : '#94A3B8',
                    color: '#fff', fontSize: 10, fontWeight: 700,
                    display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                    letterSpacing: '0.04em',
                  }}>{m.type === 'video' ? 'VID' : 'IMG'}</span>
                  <input value={m.placeholder}
                    onChange={e => updateMedia(i, { placeholder: e.target.value })}
                    placeholder="Caption / placeholder text"
                    style={{ flex: 1, border: 'none', background: 'transparent', outline: 'none', fontSize: 13 }}
                  />
                  <button onClick={() => removeMedia(i)} style={{
                    width: 24, height: 24, borderRadius: 4, background: 'transparent', border: 'none',
                    display: 'inline-flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer',
                  }}>
                    <PIcon name="trash" size={13} color="var(--fg-3)" />
                  </button>
                </div>
              ))}
              <div style={{ display: 'flex', gap: 8 }}>
                <PBtn variant="ghost" onClick={() => addMedia('image')}>
                  <PIcon name="plus" size={13} /> Add image
                </PBtn>
                <PBtn variant="ghost" onClick={() => addMedia('video')}>
                  <PIcon name="plus" size={13} /> Add video
                </PBtn>
              </div>
            </div>
          </PField>

          <PField label="Assigned to" subtitle="Pick who this training applies to.">
            <div style={{ display: 'inline-flex', background: 'var(--bg-sunken)', borderRadius: 8, padding: 3, marginBottom: 10 }}>
              {[
                { id: 'everyone', label: 'Everyone' },
                { id: 'crew', label: 'Crew only' },
                { id: 'staff', label: 'Specific staff' },
              ].map(opt => (
                <button key={opt.id} onClick={() => setScopeMode(opt.id)} style={{
                  padding: '6px 14px',
                  background: scopeMode === opt.id ? '#FFFFFF' : 'transparent',
                  border: 'none',
                  borderRadius: 6,
                  fontSize: 12.5,
                  fontWeight: scopeMode === opt.id ? 600 : 500,
                  color: scopeMode === opt.id ? 'var(--fg-1)' : 'var(--fg-2)',
                  cursor: 'pointer',
                  boxShadow: scopeMode === opt.id ? '0 1px 2px rgba(0,0,0,0.08)' : 'none',
                }}>{opt.label}</button>
              ))}
            </div>
            {scopeMode === 'staff' && (
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))', gap: 6 }}>
                {allStaff.map(s => {
                  const checked = (draft.assignedStaffIds || []).includes(s.id);
                  return (
                    <label key={s.id} style={{
                      display: 'flex', alignItems: 'center', gap: 8,
                      padding: '6px 10px',
                      background: checked ? '#EEF4FF' : 'var(--bg-sunken)',
                      borderRadius: 6, cursor: 'pointer',
                      border: '1px solid ' + (checked ? '#BFDBFE' : 'transparent'),
                    }}>
                      <input type="checkbox" checked={checked} onChange={() => toggleStaff(s.id)} />
                      <PAvatar staff={s} size={20} />
                      <span style={{ fontSize: 12.5, fontWeight: 500 }}>{s.name}</span>
                    </label>
                  );
                })}
              </div>
            )}
          </PField>

          <PField label="Certified trainers" subtitle="Who can sign off when staff complete this item. Owner can always sign off.">
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))', gap: 6 }}>
              {allStaff.map(s => {
                const checked = (draft.trainerIds || []).includes(s.id);
                const isOwner = s.id === 'ryan';
                return (
                  <label key={s.id} style={{
                    display: 'flex', alignItems: 'center', gap: 8,
                    padding: '6px 10px',
                    background: checked ? '#F0F7E8' : 'var(--bg-sunken)',
                    borderRadius: 6, cursor: isOwner ? 'not-allowed' : 'pointer',
                    border: '1px solid ' + (checked ? '#BBE0A1' : 'transparent'),
                    opacity: isOwner ? 0.85 : 1,
                  }}>
                    <input type="checkbox" checked={checked || isOwner} disabled={isOwner}
                      onChange={() => !isOwner && toggleTrainer(s.id)} />
                    <PAvatar staff={s} size={20} />
                    <span style={{ fontSize: 12.5, fontWeight: 500 }}>{s.name}</span>
                    {isOwner && <span style={{ fontSize: 10, color: 'var(--fg-3)', marginLeft: 'auto' }}>Owner</span>}
                  </label>
                );
              })}
            </div>
          </PField>

          {item.id !== 'new' && (
            <PField label="Completion history">
              <CompletionHistory itemId={item.id} completions={completions} />
            </PField>
          )}
        </div>

        <div style={{
          padding: '14px 24px',
          borderTop: '1px solid var(--border-2)',
          display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10,
          flexShrink: 0,
          background: '#FFFFFF',
        }}>
          {onDelete ? (
            <PBtn variant="ghost" onClick={onDelete} style={{ color: 'var(--danger)' }}>
              <PIcon name="trash" size={13} /> Delete
            </PBtn>
          ) : <div />}
          <div style={{ display: 'flex', gap: 8 }}>
            <PBtn variant="ghost" onClick={onCancel}>Cancel</PBtn>
            <PBtn variant="primary" onClick={() => onSave(draft)}
              disabled={!draft.title.trim()}>
              {item.id === 'new' ? 'Create' : 'Save'}
            </PBtn>
          </div>
        </div>
      </div>
    </PModal>
  );
};

const CompletionHistory = ({ itemId, completions }) => {
  const log = (completions[itemId] || []).slice().sort((a, b) => b.completedAt.localeCompare(a.completedAt));
  if (log.length === 0) {
    return <div style={{ fontSize: 12.5, color: 'var(--fg-3)' }}>No completions yet.</div>;
  }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 4, maxHeight: 180, overflow: 'auto' }}>
      {log.map((c, i) => {
        const staff = window.SAMPLE_STAFF.find(s => s.id === c.staffId);
        const approver = window.SAMPLE_STAFF.find(s => s.id === c.approvedBy);
        const dt = new Date(c.completedAt);
        if (!staff) return null;
        return (
          <div key={i} style={{
            display: 'flex', alignItems: 'center', gap: 10,
            padding: '6px 10px',
            background: 'var(--bg-sunken)',
            borderRadius: 6,
            fontSize: 12.5,
          }}>
            <PAvatar staff={staff} size={20} />
            <span style={{ fontWeight: 500 }}>{staff.name}</span>
            <span style={{ color: 'var(--fg-3)' }}>completed</span>
            <span style={{ flex: 1 }} />
            <span style={{ color: 'var(--fg-2)' }}>
              {dt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}
            </span>
            {approver && (
              <span style={{ color: 'var(--fg-3)', fontSize: 11 }}>
                · by {approver.name}
              </span>
            )}
          </div>
        );
      })}
    </div>
  );
};

// ------------------------------------------------------------------
// Coverage — staff × items matrix, grouped by category
// ------------------------------------------------------------------
const TrainingCoverage = ({ items, categories, completions }) => {
  if (items.length === 0) {
    return <div className="portal-empty"><div style={{ fontSize: 14, color: 'var(--fg-2)' }}>No training items yet.</div></div>;
  }

  // Group items by category for visual separation.
  const groups = useMemoTr(() => {
    const map = {};
    categories.forEach(c => map[c.id] = { cat: c, items: [] });
    map['__none'] = { cat: null, items: [] };
    items.forEach(it => {
      const key = (it.categoryId && map[it.categoryId]) ? it.categoryId : '__none';
      map[key].items.push(it);
    });
    return Object.values(map).filter(g => g.items.length > 0);
  }, [items, categories]);

  return (
    <div style={{
      background: '#FFFFFF',
      border: '1px solid var(--border-2)',
      borderRadius: 10,
      overflow: 'auto',
    }}>
      <table style={{ borderCollapse: 'collapse', width: '100%', minWidth: 720 }}>
        <thead>
          <tr style={{ borderBottom: '1px solid var(--border-2)', background: '#FAFAF9' }}>
            <th style={{ position: 'sticky', left: 0, background: '#FAFAF9', textAlign: 'left', padding: '10px 14px', fontSize: 11, fontWeight: 600, color: 'var(--fg-2)', textTransform: 'uppercase', letterSpacing: '0.06em', minWidth: 240, zIndex: 1 }}>
              Item
            </th>
            {window.SAMPLE_STAFF.map(s => (
              <th key={s.id} style={{ padding: '10px 6px', minWidth: 64 }}>
                <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4 }}>
                  <PAvatar staff={s} size={26} />
                  <span style={{ fontSize: 10.5, color: 'var(--fg-2)', fontWeight: 500 }}>{s.name}</span>
                </div>
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {groups.map(group => (
            <React.Fragment key={group.cat?.id || '__none'}>
              <tr>
                <td colSpan={1 + window.SAMPLE_STAFF.length} style={{
                  position: 'sticky', left: 0,
                  background: '#F4F2EE', padding: '6px 14px',
                  fontSize: 10.5, fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase',
                  color: 'var(--fg-2)',
                  borderTop: '1px solid var(--border-2)',
                  borderBottom: '1px solid var(--border-2)',
                }}>
                  <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                    {group.cat && <span style={{ width: 8, height: 8, borderRadius: 999, background: group.cat.color }} />}
                    {group.cat ? group.cat.name : 'Uncategorized'}
                  </span>
                </td>
              </tr>
              {group.items.map(item => (
                <tr key={item.id} style={{ borderBottom: '1px solid var(--border-2)' }}>
                  <td style={{ position: 'sticky', left: 0, background: '#FFFFFF', padding: '10px 14px', fontSize: 13, fontWeight: 500, color: 'var(--fg-1)', zIndex: 1 }}>
                    <div style={{ lineHeight: 1.3 }}>{item.title}</div>
                    <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 2 }}>
                      {item.assignedStaffIds && item.assignedStaffIds.length > 0
                        ? `${item.assignedStaffIds.length} staff`
                        : (item.assignedRoles && item.assignedRoles.length > 0)
                          ? item.assignedRoles.join(' · ')
                          : 'Everyone'}
                    </div>
                  </td>
                  {window.SAMPLE_STAFF.map(s => {
                    const assigned = portalIsAssigned(item, s);
                    const done = portalHasCompleted(item, s, completions);
                    return (
                      <td key={s.id} style={{ textAlign: 'center', padding: '10px 6px' }}>
                        {!assigned ? (
                          <span style={{ color: 'var(--fg-3)', fontSize: 14, opacity: 0.4 }}>—</span>
                        ) : done ? (
                          <span style={{
                            width: 22, height: 22, borderRadius: 999,
                            background: '#E7F0E0',
                            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                          }}>
                            <PIcon name="check" size={13} color="#2D6A2A" />
                          </span>
                        ) : (
                          <span style={{
                            width: 22, height: 22, borderRadius: 999,
                            background: 'var(--bg-sunken)',
                            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                            fontSize: 11, color: 'var(--fg-3)',
                          }}>·</span>
                        )}
                      </td>
                    );
                  })}
                </tr>
              ))}
            </React.Fragment>
          ))}
        </tbody>
      </table>
    </div>
  );
};

// ------------------------------------------------------------------
// Completions — chronological event log
// ------------------------------------------------------------------
const TrainingCompletions = ({ items, completions, setCompletions }) => {
  const log = useMemoTr(() => {
    const out = [];
    Object.entries(completions || {}).forEach(([itemId, arr]) => {
      arr.forEach(c => out.push({ itemId, ...c }));
    });
    out.sort((a, b) => b.completedAt.localeCompare(a.completedAt));
    return out;
  }, [completions]);

  if (log.length === 0) {
    return <div className="portal-empty"><div style={{ fontSize: 14, color: 'var(--fg-2)' }}>No completions logged yet.</div></div>;
  }

  const fmtDate = (iso) => new Date(iso).toLocaleString('en-US', {
    month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit',
  });

  return (
    <div style={{
      background: '#FFFFFF',
      border: '1px solid var(--border-2)',
      borderRadius: 10,
      overflow: 'hidden',
    }}>
      <table style={{ borderCollapse: 'collapse', width: '100%' }}>
        <thead>
          <tr style={{ borderBottom: '1px solid var(--border-2)', background: '#FAFAF9' }}>
            {['When', 'Who', 'Item', 'Approved by'].map(h => (
              <th key={h} style={{ textAlign: 'left', padding: '10px 14px', fontSize: 11, fontWeight: 600, color: 'var(--fg-2)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{h}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {log.map((c, i) => {
            const item = items.find(it => it.id === c.itemId);
            const staff = window.SAMPLE_STAFF.find(s => s.id === c.staffId);
            const approver = window.SAMPLE_STAFF.find(s => s.id === c.approvedBy);
            return (
              <tr key={i} style={{ borderBottom: '1px solid var(--border-2)' }}>
                <td style={{ padding: '10px 14px', fontSize: 12.5, color: 'var(--fg-2)', fontFamily: 'var(--font-num)', whiteSpace: 'nowrap' }}>{fmtDate(c.completedAt)}</td>
                <td style={{ padding: '10px 14px', fontSize: 13 }}>
                  {staff ? (
                    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                      <PAvatar staff={staff} size={22} />
                      <span style={{ fontWeight: 500 }}>{staff.name}</span>
                    </div>
                  ) : <span style={{ color: 'var(--fg-3)' }}>{c.staffId}</span>}
                </td>
                <td style={{ padding: '10px 14px', fontSize: 13, color: 'var(--fg-1)', fontWeight: 500 }}>
                  {item?.title || <span style={{ color: 'var(--fg-3)' }}>(deleted item)</span>}
                </td>
                <td style={{ padding: '10px 14px', fontSize: 13 }}>
                  {approver ? (
                    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                      <PAvatar staff={approver} size={20} />
                      <span style={{ color: 'var(--fg-2)' }}>{approver.name}</span>
                    </div>
                  ) : <span style={{ color: 'var(--fg-3)' }}>—</span>}
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
};

Object.assign(window, { Training });
