// Salud ocupacional — matriz EPI, profesiograma, EMO y demás secciones de salud ocupacional
const { useState: _sst2_useState, useMemo: _sst2_useMemo } = React;

const SST2_SUBTABS = [
  { id: 'matriz-epi',       label: 'Matriz EPI' },
  { id: 'profesiograma',    label: 'Profesiograma' },
  { id: 'emo',              label: 'EMO' },
  { id: 'vacunacion',       label: 'Vacunación' },
  { id: 'casos-especiales', label: 'Casos especiales',   disabled: true },
  { id: 'sve',              label: 'SVE',                disabled: true },
  { id: 'semana-salud',     label: 'Semana de la Salud', disabled: true },
  { id: 'salud-publica',    label: 'Salud pública',      disabled: true },
];

// ─── Root ──────────────────────────────────────────────────

const SSTSaludOcupacional = () => {
  const [subTab, setSubTab] = _sst2_useState('matriz-epi');

  return (
    <div className="main" data-screen-label="Salud ocupacional">
      <div className="page-head">
        <div>
          <h1 className="page-title">Salud ocupacional</h1>
          <div className="page-subtitle">
            <b>SG-SST · Resolución 0312 de 2019</b> · ARL Sura · Plan vigente 2026
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button className="btn"><IconBarChart size={14} /> Reporte SG-SST</button>
        </div>
      </div>

      {/* KPIs */}
      <div className="tr-kpis">
        <div className="tr-kpi">
          <div className="tr-kpi-icon rose"><IconAlert size={18} /></div>
          <div>
            <div className="tr-kpi-num">3 <small>· 4 · 5</small></div>
            <div className="tr-kpi-lbl">Exámenes vencidos · por vencer · al día (k)</div>
            <div className="tr-kpi-foot down">3 vencidos requieren acción inmediata</div>
          </div>
        </div>
        <div className="tr-kpi">
          <div className="tr-kpi-icon amber"><IconShield size={18} /></div>
          <div>
            <div className="tr-kpi-num">6 <small>/ año</small></div>
            <div className="tr-kpi-lbl">Accidentes e incidentes 2026</div>
            <div className="tr-kpi-foot up">−40% vs. 2025</div>
          </div>
        </div>
        <div className="tr-kpi">
          <div className="tr-kpi-icon navy"><IconUsers size={18} /></div>
          <div>
            <div className="tr-kpi-num">38</div>
            <div className="tr-kpi-lbl">Colaboradores en riesgo alto/crítico</div>
            <div className="tr-kpi-foot muted">de 824 con plan</div>
          </div>
        </div>
        <div className="tr-kpi">
          <div className="tr-kpi-icon green"><IconCheck size={18} /></div>
          <div>
            <div className="tr-kpi-num">87<small>%</small></div>
            <div className="tr-kpi-lbl">Cumplimiento plan SG-SST</div>
            <div className="tr-kpi-foot up">+2 pts vs. abr</div>
          </div>
        </div>
      </div>

      <div className="doc-tabs">
        {SST2_SUBTABS.map(t => (
          <button
            key={t.id}
            className={`doc-tab ${subTab === t.id ? 'active' : ''}`}
            disabled={t.disabled}
            onClick={() => !t.disabled && setSubTab(t.id)}
          >
            {t.label}
            {t.disabled && <span className="nav-badge-v2" style={{ marginLeft: 5 }}>v2</span>}
          </button>
        ))}
      </div>
      {subTab === 'matriz-epi' ? (
        <MatrizEPISection2 />
      ) : subTab === 'profesiograma' ? (
        <ProfesiogramaSection2 />
      ) : subTab === 'emo' ? (
        <ExamsSectionSO />
      ) : subTab === 'vacunacion' ? (
        <VacunacionSection2 />
      ) : (
        <div className="card" style={{ marginBottom: 24 }}>
          <EmptyState
            icon="IconShield"
            title={(SST2_SUBTABS.find(t => t.id === subTab) || {}).label || 'Selecciona una sección'}
            description="Este contenido se define en una próxima iteración de este módulo."
          />
        </div>
      )}
    </div>
  );
};

// ─── Section: Matriz EPI ────────────────────────────────────
// Copiado de la pestaña "Matrices por cargo" de Dotación y EPP (components/epp.jsx),
// tal cual, para explorar cómo se vería aquí. El original en EPP no se modifica.
// Identificadores con sufijo "Epp2" para no chocar con los de epp.jsx (mismo scope global).

const ITEM_CATALOG_EPP2 = [
  { code: 'UNI-001', name: 'Uniforme operario clasificación',         cat: 'dotacion', sizes: ['S','M','L','XL'] },
  { code: 'UNI-002', name: 'Uniforme operaria aprovechamiento',         cat: 'dotacion', sizes: ['S','M','L','XL'] },
  { code: 'UNI-003', name: 'Camisa polo corporativa',           cat: 'dotacion', sizes: ['S','M','L','XL','XXL'] },
  { code: 'UNI-004', name: 'Pantalón industrial drill',         cat: 'dotacion', sizes: ['28','30','32','34','36','38'] },
  { code: 'UNI-005', name: 'Bata blanca laboratorio',           cat: 'dotacion', sizes: ['S','M','L','XL'] },
  { code: 'UNI-006', name: 'Cofia desechable',                  cat: 'dotacion', sizes: ['Única'] },
  { code: 'EPP-001', name: 'Guantes térmicos Kevlar 350°C',     cat: 'epp', sizes: ['M','L','XL'] },
  { code: 'EPP-002', name: 'Botas dieléctricas con puntera',    cat: 'epp', sizes: ['37','38','39','40','41','42','43','44'] },
  { code: 'EPP-003', name: 'Casco industrial clase E',          cat: 'epp', sizes: ['Única'] },
  { code: 'EPP-004', name: 'Protector auditivo copa 25 dB',     cat: 'epp', sizes: ['Única'] },
  { code: 'EPP-005', name: 'Gafas de seguridad transparentes',  cat: 'epp', sizes: ['Única'] },
  { code: 'EPP-006', name: 'Tapabocas N95 (caja x 20)',         cat: 'epp', sizes: ['Única'] },
  { code: 'EPP-007', name: 'Faja lumbar ergonómica',            cat: 'epp', sizes: ['M','L','XL'] },
  { code: 'EPP-008', name: 'Arnés de cuerpo entero c/4 anclajes', cat: 'epp', sizes: ['Única'] },
  { code: 'EPP-009', name: 'Guantes de nitrilo (caja x 100)',   cat: 'epp', sizes: ['M','L'] },
  { code: 'EPP-010', name: 'Delantal vinílico industrial',      cat: 'epp', sizes: ['Única'] },
];

const ROLE_MATRICES_EPP2 = [
  {
    role: 'Operario de Clasificación', count: 8, updated: '12/04/2026',
    items: [
      { code: 'UNI-001', mandatory: true,  moment: 'ingreso',   freq: 'Anual' },
      { code: 'UNI-004', mandatory: true,  moment: 'ingreso',   freq: 'Anual' },
      { code: 'EPP-001', mandatory: true,  moment: 'periodico', freq: 'Por desgaste' },
      { code: 'EPP-002', mandatory: true,  moment: 'ingreso',   freq: 'Anual' },
      { code: 'EPP-003', mandatory: true,  moment: 'ingreso',   freq: 'Por desgaste' },
      { code: 'EPP-004', mandatory: true,  moment: 'ingreso',   freq: 'Semestral' },
      { code: 'EPP-005', mandatory: false, moment: 'periodico', freq: 'Por desgaste' },
      { code: 'EPP-007', mandatory: false, moment: 'periodico', freq: 'Por desgaste' },
    ],
  },
  {
    role: 'Op. Aprovechamiento', count: 6, updated: '08/04/2026',
    items: [
      { code: 'UNI-002', mandatory: true, moment: 'ingreso',   freq: 'Anual' },
      { code: 'UNI-006', mandatory: true, moment: 'ingreso',   freq: 'Mensual' },
      { code: 'EPP-002', mandatory: true, moment: 'ingreso',   freq: 'Anual' },
      { code: 'EPP-006', mandatory: true, moment: 'periodico', freq: 'Mensual' },
      { code: 'EPP-007', mandatory: false, moment: 'periodico', freq: 'Por desgaste' },
      { code: 'EPP-009', mandatory: true, moment: 'periodico', freq: 'Por desgaste' },
    ],
  },
  {
    role: 'Téc. Mantenimiento', count: 9, updated: '15/04/2026',
    items: [
      { code: 'UNI-001', mandatory: true, moment: 'ingreso',   freq: 'Anual' },
      { code: 'EPP-002', mandatory: true, moment: 'ingreso',   freq: 'Anual' },
      { code: 'EPP-003', mandatory: true, moment: 'ingreso',   freq: 'Por desgaste' },
      { code: 'EPP-004', mandatory: true, moment: 'ingreso',   freq: 'Semestral' },
      { code: 'EPP-005', mandatory: true, moment: 'ingreso',   freq: 'Por desgaste' },
      { code: 'EPP-007', mandatory: true, moment: 'periodico', freq: 'Anual' },
      { code: 'EPP-008', mandatory: true, moment: 'ingreso',   freq: 'Por desgaste' },
      { code: 'EPP-001', mandatory: false, moment: 'periodico', freq: 'Por desgaste' },
      { code: 'UNI-004', mandatory: true, moment: 'ingreso',   freq: 'Anual' },
    ],
  },
  {
    role: 'Conductor', count: 4, updated: '02/04/2026',
    items: [
      { code: 'UNI-003', mandatory: true, moment: 'ingreso',   freq: 'Anual' },
      { code: 'UNI-004', mandatory: true, moment: 'ingreso',   freq: 'Anual' },
      { code: 'EPP-002', mandatory: true, moment: 'ingreso',   freq: 'Anual' },
      { code: 'EPP-007', mandatory: false, moment: 'periodico', freq: 'Por desgaste' },
    ],
  },
  {
    role: 'Aux. Calidad', count: 5, updated: '20/03/2026',
    items: [
      { code: 'UNI-005', mandatory: true, moment: 'ingreso',   freq: 'Anual' },
      { code: 'EPP-005', mandatory: true, moment: 'ingreso',   freq: 'Por desgaste' },
      { code: 'EPP-006', mandatory: true, moment: 'periodico', freq: 'Mensual' },
      { code: 'EPP-009', mandatory: true, moment: 'periodico', freq: 'Por desgaste' },
      { code: 'EPP-010', mandatory: false, moment: 'periodico', freq: 'Por desgaste' },
    ],
  },
];

const MOMENT_LABEL_EPP2 = {
  ingreso:    'Al ingreso',
  periodico:  'Periódico',
  retiro:     'Al retiro',
};

const FREQ_OPTIONS_EPP2 = ['Por desgaste', 'Mensual', 'Trimestral', 'Semestral', 'Anual'];

const getItemEpp2 = (code) => ITEM_CATALOG_EPP2.find(i => i.code === code);

// ─── Tab: Role matrices (copiado de MatricesTab en epp.jsx) ─

const MatricesTabEpp2 = ({ onEdit }) => {
  return (
    <>
      <div className="sst-quickfilter">
        <div className="ob-search" style={{ maxWidth: 320 }}>
          <IconSearch size={15} />
          <input placeholder="Buscar cargo…" />
        </div>
        <div style={{ flex: 1 }} />
        <button className="btn"><IconExternal size={13} /> Importar matriz</button>
        <button className="btn primary"><IconPlus size={13} /> Nueva matriz</button>
      </div>

      <div className="epp-matrix-grid">
        {ROLE_MATRICES_EPP2.map((m, i) => {
          const sample = m.items.slice(0, 4);
          const dot = m.items.filter(it => it.mandatory).length;
          return (
            <div key={i} className="epp-matrix-card" onClick={() => onEdit(m)}>
              <div className="epp-matrix-head">
                <div>
                  <div className="epp-matrix-name">{m.role}</div>
                  <div className="muted" style={{ fontSize: 11.5, marginTop: 3 }}>
                    {m.count} ítems · {dot} obligatorios · actualizado {m.updated}
                  </div>
                </div>
                <div className="epp-matrix-icon"><IconShirt size={18} /></div>
              </div>
              <div className="epp-matrix-preview">
                {sample.map((it, j) => {
                  const ci = getItemEpp2(it.code);
                  return (
                    <div key={j} className="epp-matrix-prev-row">
                      <span className={`epp-matrix-cat-dot ${ci.cat}`} />
                      <span style={{ flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', fontSize: 12 }}>{ci.name}</span>
                      <span className="muted mono" style={{ fontSize: 11 }}>{MOMENT_LABEL_EPP2[it.moment]}</span>
                      {it.mandatory && <IconCheck size={11} style={{ color: 'var(--rose-600)' }} />}
                    </div>
                  );
                })}
                {m.items.length > 4 && (
                  <div className="muted" style={{ fontSize: 11.5, padding: '4px 0 0' }}>+{m.items.length - 4} ítems más…</div>
                )}
              </div>
              <button className="btn primary" style={{ width: '100%' }} onClick={(e) => { e.stopPropagation(); onEdit(m); }}>
                <IconExternal size={13} /> Editar matriz
              </button>
            </div>
          );
        })}
      </div>
    </>
  );
};

// ─── Modal: editor de matriz (copiado de MatrixEditorModal en epp.jsx) ─

const MatrixEditorModalEpp2 = ({ matrix, onClose }) => {
  const [rows, setRows] = _sst2_useState(matrix.items.map(r => ({ ...r })));
  const [picker, setPicker] = _sst2_useState(false);

  const setRow = (idx, patch) => setRows(rs => rs.map((r, i) => i === idx ? { ...r, ...patch } : r));
  const removeRow = (idx) => setRows(rs => rs.filter((_, i) => i !== idx));
  const addRow = (code) => {
    setRows(rs => [...rs, { code, mandatory: false, moment: 'ingreso', freq: 'Anual' }]);
    setPicker(false);
  };

  const usedCodes = new Set(rows.map(r => r.code));

  React.useEffect(() => {
    document.body.style.overflow = 'hidden';
    const onEsc = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onEsc);
    return () => { document.body.style.overflow = ''; window.removeEventListener('keydown', onEsc); };
  }, []);

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 1080 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">Editor de matriz · {matrix.role}</div>
            <div className="modal-sub">
              Configura los ítems obligatorios, momento de entrega y frecuencia. Los cambios se aplicarán a {matrix.count} colaboradores con este cargo.
            </div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>

        <div className="modal-body">
          <div className="epp-edit-meta">
            <div>
              <div className="muted-xs">Ítems en la matriz</div>
              <div className="epp-edit-meta-val">{rows.length}</div>
            </div>
            <div>
              <div className="muted-xs">Obligatorios</div>
              <div className="epp-edit-meta-val rose">{rows.filter(r => r.mandatory).length}</div>
            </div>
            <div>
              <div className="muted-xs">Última modificación</div>
              <div className="epp-edit-meta-val">{matrix.updated}</div>
            </div>
            <div>
              <div className="muted-xs">Colaboradores afectados</div>
              <div className="epp-edit-meta-val">{matrix.count}</div>
            </div>
          </div>

          <div className="doc-list-card">
            <table className="doc-table epp-edit-table">
              <thead>
                <tr>
                  <th>Ítem</th>
                  <th>Categoría</th>
                  <th style={{ textAlign: 'center' }}>Obligatorio</th>
                  <th>Momento</th>
                  <th>Frecuencia</th>
                  <th></th>
                </tr>
              </thead>
              <tbody>
                {rows.map((r, i) => {
                  const ci = getItemEpp2(r.code);
                  return (
                    <tr key={i}>
                      <td>
                        <div style={{ fontWeight: 600, fontSize: 13 }}>{ci.name}</div>
                        <div className="muted mono" style={{ fontSize: 11 }}>{ci.code}</div>
                      </td>
                      <td>
                        <span className={`pill ${ci.cat === 'epp' ? 'navy' : 'green'}`} style={{ fontSize: 11 }}>
                          {ci.cat === 'epp' ? 'EPP' : 'Dotación'}
                        </span>
                      </td>
                      <td style={{ textAlign: 'center' }}>
                        <label className="epp-toggle">
                          <input type="checkbox" checked={r.mandatory} onChange={(e) => setRow(i, { mandatory: e.target.checked })} />
                          <span className="epp-toggle-track" />
                        </label>
                      </td>
                      <td>
                        <div className="epp-seg">
                          {['ingreso', 'periodico', 'retiro'].map(m => (
                            <button
                              key={m}
                              className={`epp-seg-btn ${r.moment === m ? 'active' : ''}`}
                              onClick={() => setRow(i, { moment: m })}
                            >
                              {MOMENT_LABEL_EPP2[m]}
                            </button>
                          ))}
                        </div>
                      </td>
                      <td>
                        <select value={r.freq} onChange={(e) => setRow(i, { freq: e.target.value })} className="epp-edit-select">
                          {FREQ_OPTIONS_EPP2.map(f => <option key={f}>{f}</option>)}
                        </select>
                      </td>
                      <td>
                        <button className="icon-action danger" title="Quitar ítem" onClick={() => removeRow(i)}>
                          <IconAlert size={14} />
                        </button>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
            <div className="doc-table-foot" style={{ justifyContent: 'flex-end' }}>
              {picker ? (
                <ItemPickerEpp2 exclude={usedCodes} onPick={addRow} onClose={() => setPicker(false)} />
              ) : (
                <button className="btn primary" onClick={() => setPicker(true)}>
                  <IconPlus size={13} /> Agregar ítem desde catálogo
                </button>
              )}
            </div>
          </div>

          <div className="epp-edit-warn">
            <IconAlert size={14} />
            <span>
              Los cambios afectarán a <b>{matrix.count} colaboradores</b> activos con cargo <b>{matrix.role}</b>.
              Se generarán automáticamente nuevas entregas pendientes para los ítems obligatorios que no se hayan entregado previamente.
            </span>
          </div>
        </div>

        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn">Guardar borrador</button>
          <button className="btn primary"><IconCheck size={14} /> Publicar matriz</button>
        </div>
      </div>
    </div>
  );
};

// ─── Item picker (autocomplete, copiado de ItemPicker en epp.jsx) ─

const ItemPickerEpp2 = ({ exclude, onPick, onClose }) => {
  const [q, setQ] = _sst2_useState('');
  const opts = ITEM_CATALOG_EPP2.filter(i =>
    !exclude.has(i.code) &&
    (q === '' || i.name.toLowerCase().includes(q.toLowerCase()) || i.code.toLowerCase().includes(q.toLowerCase()))
  );

  return (
    <div className="epp-picker">
      <div className="epp-picker-search">
        <IconSearch size={14} />
        <input autoFocus placeholder="Buscar ítem por nombre o código…" value={q} onChange={(e) => setQ(e.target.value)} />
        <button className="link-btn" onClick={onClose}>Cancelar</button>
      </div>
      <div className="epp-picker-list">
        {opts.length === 0
          ? <div className="muted" style={{ padding: 12, fontSize: 12.5 }}>Ningún ítem coincide</div>
          : opts.map(o => (
            <button key={o.code} className="epp-picker-row" onClick={() => onPick(o.code)}>
              <span className={`epp-matrix-cat-dot ${o.cat}`} />
              <div style={{ flex: 1, textAlign: 'left' }}>
                <div style={{ fontWeight: 600, fontSize: 12.5 }}>{o.name}</div>
                <div className="muted mono" style={{ fontSize: 11 }}>{o.code} · {o.cat === 'epp' ? 'EPP' : 'Dotación'}</div>
              </div>
              <IconPlus size={12} />
            </button>
          ))
        }
      </div>
    </div>
  );
};

const MatrizEPISection2 = () => {
  const [matrixOpen, setMatrixOpen] = _sst2_useState(null);
  return (
    <div style={{ marginBottom: 24 }}>
      <MatricesTabEpp2 onEdit={(m) => setMatrixOpen(m)} />
      {matrixOpen && <MatrixEditorModalEpp2 matrix={matrixOpen} onClose={() => setMatrixOpen(null)} />}
    </div>
  );
};

// ─── Section: EMO — Exámenes médicos ocupacionales ──────────
// Copiado de la pestaña "Exámenes médicos" de SST (components/sst.jsx),
// tal cual, para mostrarla dentro de Salud ocupacional. El original en SST
// no se modifica. Identificadores con sufijo "SO" para no chocar con los
// de sst.jsx (mismo scope global de scripts).

const EXAMS_SO = [
  { id: 'E0247', initials: 'AM', name: 'Andrés Felipe Mejía',  role: 'Operario de Clasificación',   site: 'Cali',    type: 'ingreso',   done: '02/05/2026', due: '02/05/2027', state: 'vigente', restrictions: null },
  { id: 'E0205', initials: 'CV', name: 'Carlos Andrés Vélez',  role: 'Operario de Clasificación',   site: 'Cali',    type: 'periodico', done: '14/03/2025', due: '14/03/2026', state: 'vencido',  restrictions: 'Hipoacusia leve · uso permanente de protector auditivo' },
  { id: 'E0198', initials: 'MF', name: 'María Fernanda López', role: 'Op. Aprovechamiento',           site: 'Cali',    type: 'periodico', done: '08/04/2025', due: '08/04/2026', state: 'vencido',  restrictions: null },
  { id: 'E0177', initials: 'JP', name: 'Jorge Iván Patiño',    role: 'Conductor',             site: 'Barranquilla',  type: 'periodico', done: '15/05/2025', due: '15/05/2026', state: 'porvencer', restrictions: 'Lumbalgia crónica · evitar carga > 15 kg' },
  { id: 'E0156', initials: 'PV', name: 'Paula Valencia Ríos',  role: 'Téc. Mantenimiento',    site: 'Cali',    type: 'periodico', done: '20/04/2025', due: '20/04/2026', state: 'vencido',  restrictions: null },
  { id: 'E0142', initials: 'DT', name: 'Diego Andrés Toro',    role: 'Aux. Aprovechamiento',          site: 'Cali',    type: 'periodico', done: '22/05/2025', due: '22/05/2026', state: 'porvencer', restrictions: null },
  { id: 'E0128', initials: 'NC', name: 'Nicolás Cárdenas',     role: 'Conductor',             site: 'Barranquilla',  type: 'periodico', done: '11/09/2025', due: '11/09/2026', state: 'vigente',  restrictions: null },
  { id: 'E0094', initials: 'MT', name: 'María Trujillo Henao', role: 'Aux. Recursos Humanos', site: 'Cali',    type: 'periodico', done: '04/02/2026', due: '04/02/2027', state: 'vigente',  restrictions: null },
  { id: 'E0067', initials: 'LM', name: 'Luis Miguel Marín',    role: 'Líder de Aprovechamiento',      site: 'Cali',    type: 'periodico', done: '18/06/2025', due: '18/06/2026', state: 'porvencer', restrictions: 'Síndrome de túnel carpiano · pausas activas cada 90 min' },
  { id: 'E0023', initials: 'CR', name: 'Carolina Restrepo S.', role: 'Jefe de RRHH',          site: 'Cali',    type: 'periodico', done: '12/02/2026', due: '12/02/2027', state: 'vigente',  restrictions: null },
  { id: 'E0011', initials: 'FH', name: 'Fernando Henao',       role: 'Operario Clasificación',      site: 'Cali',    type: 'egreso',    done: '28/04/2026', due: '—',          state: 'vigente',  restrictions: null },
  { id: 'E0246', initials: 'LG', name: 'Laura Gómez Restrepo', role: 'Operaria de Planta',    site: 'Cali',    type: 'ingreso',   done: '02/05/2026', due: '02/05/2027', state: 'vigente',  restrictions: null },
];

const STATE_EXAM_SO = {
  vigente:    { label: 'Vigente',    pill: 'green',      dot: 'var(--green-600)' },
  porvencer:  { label: 'Por vencer', pill: 'amber-soft', dot: '#854D0E' },
  vencido:    { label: 'Vencido',    pill: 'rose',       dot: 'var(--rose-600)' },
};

const TYPE_EXAM_SO = {
  ingreso:   { label: 'Ingreso' },
  periodico: { label: 'Periódico' },
  egreso:    { label: 'Egreso' },
};

const ExamsSectionSO = () => {
  const [filter, setFilter] = _sst2_useState('todos');
  const counts = _sst2_useMemo(() => ({
    todos:     EXAMS_SO.length,
    vigente:   EXAMS_SO.filter(e => e.state === 'vigente').length,
    porvencer: EXAMS_SO.filter(e => e.state === 'porvencer').length,
    vencido:   EXAMS_SO.filter(e => e.state === 'vencido').length,
  }), []);

  const rows = filter === 'todos' ? EXAMS_SO : EXAMS_SO.filter(e => e.state === filter);

  return (
    <>
      <div className="sst-quickfilter">
        {[
          { id: 'todos',     label: 'Todos',      tone: '' },
          { id: 'vigente',   label: 'Vigentes',   tone: 'green' },
          { id: 'porvencer', label: 'Por vencer', tone: 'amber' },
          { id: 'vencido',   label: 'Vencidos',   tone: 'rose' },
        ].map(o => (
          <button
            key={o.id}
            className={`sst-chip ${o.tone} ${filter === o.id ? 'active' : ''}`}
            onClick={() => setFilter(o.id)}
          >
            {o.label}
            <span className="sst-chip-count">{counts[o.id]}</span>
          </button>
        ))}
        <div style={{ flex: 1 }} />
        <button className="btn"><IconCalendar size={14} /> Programar lote</button>
      </div>

      <div className="doc-list-card">
        <table className="doc-table">
          <thead>
            <tr>
              <th>Colaborador</th>
              <th>Cargo</th>
              <th>Tipo</th>
              <th>Realizado</th>
              <th>Vence</th>
              <th>Estado</th>
              <th>Restricciones</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {rows.map(e => {
              const s = STATE_EXAM_SO[e.state];
              return (
                <tr key={e.id}>
                  <td>
                    <div className="doc-cell-emp">
                      <div className="doc-avatar">{e.initials}</div>
                      <div>
                        <div style={{ fontWeight: 600, fontSize: 13 }}>{e.name}</div>
                        <div className="muted mono" style={{ fontSize: 11 }}>{e.id} · {e.site}</div>
                      </div>
                    </div>
                  </td>
                  <td className="muted" style={{ fontSize: 12.5 }}>{e.role}</td>
                  <td><span className="pill navy" style={{ fontSize: 11 }}>{TYPE_EXAM_SO[e.type].label}</span></td>
                  <td className="mono" style={{ fontSize: 12 }}>{e.done}</td>
                  <td className={`mono ${e.state === 'vencido' ? 'sst-due-vencido' : e.state === 'porvencer' ? 'sst-due-porvencer' : ''}`} style={{ fontSize: 12 }}>{e.due}</td>
                  <td>
                    <span className={`pill ${s.pill}`}>
                      <span className="status-dot" style={{ background: s.dot }} /> {s.label}
                    </span>
                  </td>
                  <td>
                    {e.restrictions ? (
                      <div className="sst-restr" title={e.restrictions}>
                        <IconAlert size={12} />
                        <span>{e.restrictions}</span>
                      </div>
                    ) : <span className="muted" style={{ fontSize: 12 }}>—</span>}
                  </td>
                  <td>
                    <div className="doc-actions">
                      <button className="icon-action" title="Programar nuevo examen"><IconCalendar size={14} /></button>
                      <button className="icon-action" title="Ver historial"><IconExternal size={14} /></button>
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
        <div className="doc-table-foot">
          <span className="muted" style={{ fontSize: 12 }}>Mostrando {rows.length} de {EXAMS_SO.length} exámenes</span>
          <div className="pager">
            <button className="btn" style={{ padding: '5px 9px' }}><IconChevronLeft size={13} /></button>
            <span className="mono" style={{ fontSize: 12, padding: '0 8px' }}>1 / 4</span>
            <button className="btn" style={{ padding: '5px 9px' }}><IconChevronRight size={13} /></button>
          </div>
        </div>
      </div>
    </>
  );
};

// ─── Section: Vacunación ─────────────────────────────────────
// Control de esquemas de vacunación de colaboradores + admin de vacunas
// (catálogo, esquemas, registro por empleado, alertas). Por ahora solo el
// andamiaje (KPIs + 5 sub-pestañas con contenido placeholder) — el
// contenido de cada pestaña se define en una siguiente iteración.

const VAC_SUBTABS = [
  { id: 'panel',      label: 'Panel de vacunación',     icon: 'IconBarChart', desc: 'Vista general de cobertura, dosis aplicadas y alertas de vacunación.' },
  { id: 'gestion',    label: 'Gestión de vacunas',       icon: 'IconShield',   desc: 'Administra el catálogo de vacunas disponibles en el sistema: crear, editar y desactivar.' },
  { id: 'esquemas',   label: 'Esquemas de vacunación',   icon: 'IconDoc',      desc: 'Define los esquemas (series de dosis y refuerzos) asociados a cada vacuna.' },
  { id: 'empleado',   label: 'Vacunación por empleado',  icon: 'IconUsers',    desc: 'Consulta y registra las dosis aplicadas a cada colaborador.' },
  { id: 'alertas',    label: 'Alertas y reportes',       icon: 'IconAlert',    desc: 'Dosis vencidas, próximas a vencer, y reportes de cobertura por sede o cargo.' },
];

// Mismos pares bg/color que ya usa .pill por tono (styles.css) — navy es la
// excepción a la convención "-100/-600" (usa navy-50/navy-800), de ahí el mapa.
const VAC_TAG_TONE = {
  green: { bg: 'var(--green-100)', color: 'var(--green-600)' },
  rose:  { bg: 'var(--rose-100)',  color: 'var(--rose-600)' },
  amber: { bg: 'var(--amber-100)', color: 'var(--amber-600)' },
  navy:  { bg: 'var(--navy-50)',   color: 'var(--navy-800)' },
  blue:  { bg: 'var(--blue-100)',  color: 'var(--blue-600)' },
};

// Tarjeta grande de KPI — a propósito distinta de .tr-kpi (la de los KPIs
// generales de arriba de la página) para que no se lean como duplicadas.
const VacKpiCard = ({ tagIcon: TagIcon, tag, tagTone, status, statusTone, value, suffix, label, note }) => (
  <div style={{
    background: 'white', border: '1px solid var(--border)', borderRadius: 16,
    padding: '20px 22px', boxShadow: 'var(--shadow-1)',
    display: 'flex', flexDirection: 'column', gap: 16,
  }}>
    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 8 }}>
      <span style={{
        display: 'inline-flex', alignItems: 'center', gap: 6,
        background: VAC_TAG_TONE[tagTone].bg, color: VAC_TAG_TONE[tagTone].color,
        fontSize: 10.5, fontWeight: 700, letterSpacing: 0.04, textTransform: 'uppercase',
        padding: '5px 10px', borderRadius: 999, whiteSpace: 'nowrap',
      }}>
        <TagIcon size={12} /> {tag}
      </span>
      <span className={`pill ${statusTone}`} style={{ fontSize: 11, whiteSpace: 'nowrap' }}>{status}</span>
    </div>
    <div>
      <div style={{ fontSize: 32, fontWeight: 800, letterSpacing: '-0.02em', color: 'var(--text)', fontFeatureSettings: "'tnum'" }}>
        {value}{suffix && <small style={{ fontSize: 17, fontWeight: 600, color: 'var(--text-muted)' }}> {suffix}</small>}
      </div>
      <div style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--text)', marginTop: 4 }}>{label}</div>
    </div>
    <div style={{ background: 'var(--surface)', borderRadius: 10, padding: '10px 12px', fontSize: 12, color: 'var(--text-muted)', lineHeight: 1.5 }}>
      {note}
    </div>
  </div>
);

const VacunacionSection2 = () => {
  const [vacTab, setVacTab] = _sst2_useState('panel');
  const current = VAC_SUBTABS.find(t => t.id === vacTab) || VAC_SUBTABS[0];

  // Estado de vacunación por empleado — se comparte entre "Vacunación por
  // empleado" y "Alertas y reportes" para que ambas pestañas queden en sync.
  const [empVaccinations, setEmpVaccinations] = _sst2_useState(EMP_VACCINATIONS_INITIAL);
  const saveDoseRecord = (empId, vaccineId, key, record) => {
    setEmpVaccinations(list => list.map(emp => {
      if (emp.empId !== empId) return emp;
      return {
        ...emp,
        assignments: emp.assignments.map(a => a.vaccineId === vaccineId
          ? { ...a, records: { ...a.records, [key]: record } }
          : a),
      };
    }));
  };

  return (
    <div style={{ marginBottom: 24 }}>
      {/* KPIs — tarjetas grandes, formato distinto a los KPI generales de arriba */}
      <div className="tr-kpis">
        <VacKpiCard
          tagIcon={IconCheck} tag="Cobertura" tagTone="green"
          status="En buen ritmo" statusTone="green"
          value="612" suffix="/ 824"
          label="Empleados con esquema completo"
          note="74% de la plantilla · 212 colaboradores por completar su esquema."
        />
        <VacKpiCard
          tagIcon={IconAlert} tag="Vencimientos" tagTone="rose"
          status="Crítico" statusTone="rose"
          value="18"
          label="Dosis vencidas"
          note="Requieren refuerzo inmediato · notificar a colaborador y jefe directo."
        />
        <VacKpiCard
          tagIcon={IconClock} tag="Por vencer" tagTone="amber"
          status="Vigilar" statusTone="amber-soft"
          value="34"
          label="Dosis próximas a vencer"
          note="En los próximos 30 días · programar agenda con la IPS."
        />
        <VacKpiCard
          tagIcon={IconShield} tag="Catálogo" tagTone="navy"
          status="Activo" statusTone="navy"
          value="6"
          label="Vacunas en el sistema"
          note="Gestiona altas y bajas desde “Gestión de vacunas”."
        />
      </div>

      {/* Sub-secciones de Vacunación — botones separados (no barra de pestañas),
          para distinguirlos visualmente de las pestañas principales del módulo */}
      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 16 }}>
        {VAC_SUBTABS.map(t => {
          const TIco = window[t.icon];
          return (
            <button key={t.id} className={`sst-chip ${vacTab === t.id ? 'active' : ''}`} onClick={() => setVacTab(t.id)}>
              <TIco size={13} />
              {t.label}
            </button>
          );
        })}
      </div>

      {vacTab === 'panel' ? (
        <VacPanelSection />
      ) : vacTab === 'gestion' ? (
        <GestionVacunasSection2 />
      ) : vacTab === 'esquemas' ? (
        <EsquemasVacunacionSection2 />
      ) : vacTab === 'empleado' ? (
        <EmpleadoVacunacionSection2 employees={empVaccinations} onSaveDose={saveDoseRecord} />
      ) : vacTab === 'alertas' ? (
        <AlertasReportesSection2 employees={empVaccinations} onSaveDose={saveDoseRecord} />
      ) : (
        <div className="card" style={{ marginBottom: 24 }}>
          <EmptyState
            icon={current.icon}
            title={current.label}
            description={current.desc}
          />
        </div>
      )}
    </div>
  );
};

// ─── Panel de vacunación — medidores, gráficos y tablas ─────
// Todos los números parten de los mismos totales que ya muestran las
// tarjetas KPI de arriba (612/824 con esquema completo, 18 vencidas,
// 34 próximas a vencer, 6 vacunas activas) para que el panel no las
// contradiga.

// Mismos pares bg/color que .pill por tono — reservados para estado
// (bueno/atención/crítico), nunca para "serie 4".
const VAC_STATUS = {
  green: { fill: 'var(--green-600)', track: 'var(--green-100)', text: 'var(--green-600)' },
  amber: { fill: 'var(--amber-600)', track: 'var(--amber-100)', text: 'var(--amber-600)' },
  rose:  { fill: 'var(--rose-600)',  track: 'var(--rose-100)',  text: 'var(--rose-600)' },
  teal:  { fill: 'var(--teal-500)',  track: 'var(--sky-50)',    text: 'var(--teal-800)' },
};

// Empleados por estado del esquema — 612 + 158 + 54 = 824 (mismo total que el resto del módulo)
const VAC_SCHEME_STATE = [
  { id: 'completo',   label: 'Esquema completo',   value: 612, tone: 'green' },
  { id: 'incompleto', label: 'Esquema incompleto', value: 158, tone: 'amber' },
  { id: 'sin-registro', label: 'Sin registro',      value: 54,  tone: 'rose' },
];

// Cumplimiento por sede
const VAC_BY_SITE = [
  { label: 'Cali',         count: 520, pct: 82 },
  { label: 'Barranquilla', count: 210, pct: 65 },
  { label: 'Bogotá',       count: 94,  pct: 58 },
];

// Cumplimiento por área / cargo
const VAC_BY_AREA = [
  { label: 'Administración',  pct: 92 },
  { label: 'Calidad',         pct: 88 },
  { label: 'Operaciones',     pct: 80 },
  { label: 'Aprovechamiento', pct: 72 },
  { label: 'Mantenimiento',   pct: 68 },
  { label: 'Recolección',     pct: 55 },
];

// Vacunas con mayor cantidad de dosis pendientes
const VAC_PENDING_BY_VACCINE = [
  { label: 'Hepatitis B',               pending: 42 },
  { label: 'Tétanos y difteria (Td)',   pending: 35 },
  { label: 'Influenza estacional',      pending: 28 },
  { label: 'Fiebre tifoidea',           pending: 19 },
  { label: 'COVID-19 (refuerzo)',       pending: 14 },
  { label: 'Fiebre amarilla',           pending: 8 },
];

// Próximas dosis programadas
const VAC_UPCOMING = [
  { date: '08/05/2026', emp: 'Andrés Felipe Mejía',  vaccine: 'Influenza estacional',      site: 'Cali' },
  { date: '09/05/2026', emp: 'María Fernanda López', vaccine: 'Hepatitis B (dosis 3)',      site: 'Cali' },
  { date: '12/05/2026', emp: 'Jorge Iván Patiño',    vaccine: 'Fiebre amarilla',            site: 'Barranquilla' },
  { date: '14/05/2026', emp: 'Paula Valencia Ríos',  vaccine: 'Tétanos y difteria (Td)',    site: 'Cali' },
  { date: '15/05/2026', emp: 'Nicolás Cárdenas',     vaccine: 'Hepatitis B (dosis 2)',      site: 'Barranquilla' },
  { date: '20/05/2026', emp: 'Luis Miguel Marín',    vaccine: 'COVID-19 (refuerzo)',        site: 'Cali' },
];

const vacStatusForPct = (pct) => pct >= 80 ? 'green' : pct >= 60 ? 'amber' : 'rose';

// ── Medidor lineal (barra con pista) — para relaciones parte/total ──
const VacMeterLinear = ({ icon: Ico, label, value, total, tone, note }) => {
  const pct = Math.round((value / total) * 100);
  const t = VAC_STATUS[tone];
  return (
    <div className="card" style={{ padding: 16 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
        <span style={{ color: t.text, flexShrink: 0 }}><Ico size={16} /></span>
        <span style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--text)' }}>{label}</span>
      </div>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 6 }}>
        <span style={{ fontSize: 22, fontWeight: 800, color: 'var(--text)', fontFeatureSettings: "'tnum'" }}>
          {value}<small style={{ fontSize: 13, fontWeight: 600, color: 'var(--text-muted)' }}> / {total}</small>
        </span>
        <span style={{ fontSize: 15, fontWeight: 700, color: t.text }}>{pct}%</span>
      </div>
      <div style={{ height: 8, background: t.track, borderRadius: 999, overflow: 'hidden' }}>
        <div style={{ height: '100%', width: `${pct}%`, background: t.fill, borderRadius: 999 }} />
      </div>
      {note && <div className="muted-xs" style={{ marginTop: 8 }}>{note}</div>}
    </div>
  );
};

// ── Medidor radial (anillo SVG) — para una proporción dentro de un total relacionado ──
const VacMeterRadial = ({ icon: Ico, label, value, pct, tone, note }) => {
  const t = VAC_STATUS[tone];
  const R = 32, C = 2 * Math.PI * R;
  const dash = (pct / 100) * C;
  return (
    <div className="card" style={{ padding: 16, display: 'flex', gap: 14, alignItems: 'center' }}>
      <svg width="76" height="76" viewBox="0 0 76 76" style={{ flexShrink: 0 }}>
        <circle cx="38" cy="38" r={R} fill="none" stroke={t.track} strokeWidth="9" />
        <circle
          cx="38" cy="38" r={R} fill="none" stroke={t.fill} strokeWidth="9"
          strokeDasharray={`${dash} ${C - dash}`} strokeLinecap="round"
          transform="rotate(-90 38 38)"
        />
        <text x="38" y="42" textAnchor="middle" fontSize="18" fontWeight="800" fill="var(--text)" fontFamily="var(--font-body)">{value}</text>
      </svg>
      <div style={{ minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <span style={{ color: t.text }}><Ico size={14} /></span>
          <span style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--text)' }}>{label}</span>
        </div>
        {note && <div className="muted-xs" style={{ marginTop: 4 }}>{note}</div>}
      </div>
    </div>
  );
};

// ── Tarjeta simple (conteo sin relación parte/total) ──
const VacMeterStat = ({ icon: Ico, label, value, tone, note }) => {
  const t = VAC_STATUS[tone];
  return (
    <div className="card" style={{ padding: 16, display: 'flex', gap: 12, alignItems: 'center' }}>
      <div style={{ width: 40, height: 40, borderRadius: 10, background: t.track, color: t.text, display: 'grid', placeItems: 'center', flexShrink: 0 }}>
        <Ico size={18} />
      </div>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontSize: 22, fontWeight: 800, color: 'var(--text)', fontFeatureSettings: "'tnum'" }}>{value}</div>
        <div style={{ fontSize: 12, color: 'var(--text-muted)', fontWeight: 500 }}>{label}</div>
        {note && <div className="muted-xs" style={{ marginTop: 2 }}>{note}</div>}
      </div>
    </div>
  );
};

// Tarjeta de severidad — borde superior de color + ícono/etiqueta junto al
// número (a propósito distinta de VacKpiCard, usada arriba del módulo, para
// que esta escala de severidad no se lea como una repetición de esas).
const VacSeverityCard = ({ icon: Ico, severity, value, label, tone, note }) => {
  const t = VAC_STATUS[tone];
  return (
    <div style={{ background: 'white', border: '1px solid var(--border)', borderTop: `3px solid ${t.fill}`, borderRadius: 12, padding: '16px 18px' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, color: t.text, fontSize: 11.5, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.03 }}>
          <Ico size={14} /> {severity}
        </span>
        <span style={{ fontSize: 26, fontWeight: 800, color: 'var(--text)', fontFeatureSettings: "'tnum'" }}>{value}</span>
      </div>
      <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--text)' }}>{label}</div>
      {note && <div className="muted-xs" style={{ marginTop: 5, fontWeight: 400, textTransform: 'none', letterSpacing: 0 }}>{note}</div>}
    </div>
  );
};

// ── Donut — Empleados por estado del esquema ──
const VacDonut = ({ segments }) => {
  const total = segments.reduce((a, s) => a + s.value, 0);
  const R = 45, C = 2 * Math.PI * R;
  let acc = 0;
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 20, flexWrap: 'wrap' }}>
      <svg width="140" height="140" viewBox="0 0 100 100" style={{ flexShrink: 0 }}>
        {segments.map((s, i) => {
          const frac = s.value / total;
          const dash = frac * C;
          const offset = -(acc * C);
          acc += frac;
          const t = VAC_STATUS[s.tone];
          return (
            <circle
              key={i} cx="50" cy="50" r={R} fill="none" stroke={t.fill} strokeWidth="14"
              strokeDasharray={`${dash} ${C - dash}`} strokeDashoffset={offset}
              transform="rotate(-90 50 50)"
            />
          );
        })}
        <text x="50" y="47" textAnchor="middle" fontSize="17" fontWeight="800" fill="var(--text)" fontFamily="var(--font-body)">{total}</text>
        <text x="50" y="61" textAnchor="middle" fontSize="8" fill="var(--text-muted)" fontFamily="var(--font-body)">empleados</text>
      </svg>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8, flex: 1, minWidth: 160 }}>
        {segments.map((s, i) => {
          const t = VAC_STATUS[s.tone];
          const pct = Math.round((s.value / total) * 100);
          return (
            <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12.5 }}>
              <span style={{ width: 10, height: 10, borderRadius: 3, background: t.fill, flexShrink: 0 }} />
              <span style={{ flex: 1, color: 'var(--text)' }}>{s.label}</span>
              <span style={{ fontWeight: 700, color: 'var(--text)' }}>{s.value}</span>
              <span className="muted" style={{ fontSize: 11.5, width: 34, textAlign: 'right' }}>{pct}%</span>
            </div>
          );
        })}
      </div>
    </div>
  );
};

// ── Fila de barra horizontal (ranking / cumplimiento) ──
const VacBarRow = ({ label, value, pct, tone, valueLabel }) => {
  const t = VAC_STATUS[tone];
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '120px 1fr 44px', gap: 10, alignItems: 'center' }}>
      <span style={{ fontSize: 12, color: 'var(--text)', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={label}>{label}</span>
      <div style={{ height: 14, background: t.track, borderRadius: '0 7px 7px 0', overflow: 'hidden' }}>
        <div style={{ height: '100%', width: `${pct}%`, background: t.fill, borderRadius: '0 7px 7px 0' }} />
      </div>
      <span style={{ fontSize: 12, fontWeight: 700, color: t.text, textAlign: 'right' }}>{valueLabel != null ? valueLabel : `${value}%`}</span>
    </div>
  );
};

const VacChartCard = ({ title, sub, children }) => (
  <div className="card" style={{ padding: 18 }}>
    <div style={{ marginBottom: 14 }}>
      <div style={{ fontSize: 13.5, fontWeight: 700, color: 'var(--text)' }}>{title}</div>
      {sub && <div className="muted-xs" style={{ marginTop: 2 }}>{sub}</div>}
    </div>
    {children}
  </div>
);

const VacPanelSection = () => {
  const pendingMax = Math.max(...VAC_PENDING_BY_VACCINE.map(v => v.pending));

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20, marginBottom: 24 }}>
      {/* 6 medidores — estado general de vacunación */}
      <div>
        <div className="section-title" style={{ marginTop: 0 }}>Estado general de vacunación</div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12 }}>
          <VacMeterLinear icon={IconCheck} label="Esquema completo" value={612} total={824} tone="green" note="74% de la plantilla" />
          <VacMeterLinear icon={IconClock} label="Esquema incompleto" value={158} total={824} tone="amber" note="19% de la plantilla" />
          <VacMeterLinear icon={IconAlert} label="Sin registro de vacunación" value={54} total={824} tone="rose" note="6.5% de la plantilla" />
          <VacMeterRadial icon={IconAlert} label="Dosis vencidas" value={18} pct={Math.round(18 / (18 + 34) * 100)} tone="rose" note="34% de las dosis en riesgo" />
          <VacMeterRadial icon={IconClock} label="Dosis próximas a vencer" value={34} pct={Math.round(34 / (18 + 34) * 100)} tone="amber" note="66% de las dosis en riesgo" />
          <VacMeterStat icon={IconShield} label="Vacunas activas en el sistema" value={6} tone="teal" note="catálogo vigente" />
        </div>
      </div>

      {/* Estado del esquema + cumplimiento por sede */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        <VacChartCard title="Empleados por estado del esquema" sub="Distribución sobre 824 colaboradores">
          <VacDonut segments={VAC_SCHEME_STATE} />
        </VacChartCard>
        <VacChartCard title="Cumplimiento de vacunación por sede" sub="% de empleados con esquema completo">
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {VAC_BY_SITE.map((s, i) => (
              <VacBarRow key={i} label={s.label} value={s.pct} pct={s.pct} tone={vacStatusForPct(s.pct)} />
            ))}
          </div>
        </VacChartCard>
      </div>

      {/* Cumplimiento por área/cargo + vacunas con más pendientes */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        <VacChartCard title="Cumplimiento por área o cargo" sub="% de empleados con esquema completo">
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {VAC_BY_AREA.map((a, i) => (
              <VacBarRow key={i} label={a.label} value={a.pct} pct={a.pct} tone={vacStatusForPct(a.pct)} />
            ))}
          </div>
        </VacChartCard>
        <VacChartCard title="Vacunas con mayor cantidad de pendientes" sub="Dosis pendientes por tipo de vacuna">
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {VAC_PENDING_BY_VACCINE.map((v, i) => (
              <VacBarRow key={i} label={v.label} value={v.pending} pct={Math.round((v.pending / pendingMax) * 100)} tone="teal" valueLabel={v.pending} />
            ))}
          </div>
        </VacChartCard>
      </div>

      {/* Próximas dosis programadas */}
      <VacChartCard title="Próximas dosis programadas" sub="Agenda más cercana de aplicación">
        <div className="doc-list-card" style={{ boxShadow: 'none', border: '1px solid var(--border)' }}>
          <table className="doc-table">
            <thead>
              <tr>
                <th>Fecha</th>
                <th>Colaborador</th>
                <th>Vacuna</th>
                <th>Sede</th>
              </tr>
            </thead>
            <tbody>
              {VAC_UPCOMING.map((u, i) => (
                <tr key={i}>
                  <td className="mono" style={{ fontSize: 12 }}>{u.date}</td>
                  <td style={{ fontSize: 12.5, fontWeight: 600 }}>{u.emp}</td>
                  <td className="muted" style={{ fontSize: 12.5 }}>{u.vaccine}</td>
                  <td className="muted" style={{ fontSize: 12.5 }}>{u.site}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </VacChartCard>
    </div>
  );
};

// ─── Gestión de vacunas — catálogo, crear/editar/ver/activar ────

const VAC_TYPE_META = {
  ocupacional: { label: 'Ocupacional', pill: 'navy' },
  obligatoria: { label: 'Obligatoria', pill: 'rose' },
  recomendada: { label: 'Recomendada', pill: 'blue' },
  campana:     { label: 'Campaña',     pill: 'amber' },
  otro:        { label: 'Otro',        pill: '' },
};

const VAC_APPLICATION_META = {
  todos:   'Todos los empleados',
  cargos:  'Cargos específicos',
  areas:   'Áreas específicas',
  sedes:   'Sedes específicas',
  riesgos: 'Riesgos ocupacionales específicos',
};

const VACCINES_INITIAL = [
  { id: 'VAC-001', name: 'Influenza estacional',     type: 'campana',     doses: 1, requiresBooster: true,  boosters: 1, boosterFreq: 'Anual',          hasValidity: true,  minAge: '', maxAge: '',   application: 'todos',   state: 'activa',   esquemaId: 'ESQ-002', observations: 'Campaña anual · aplicación preferente marzo-abril.',                updated: '05/05/2026' },
  { id: 'VAC-002', name: 'Hepatitis B',               type: 'ocupacional', doses: 3, requiresBooster: false, boosters: 0, boosterFreq: '',                hasValidity: false, minAge: '', maxAge: '',   application: 'cargos',  state: 'activa',   esquemaId: 'ESQ-003', observations: 'Esquema 0-1-6 meses. Prioridad para cargos con riesgo biológico.',    updated: '30/04/2026' },
  { id: 'VAC-003', name: 'Tétanos y difteria (Td)',   type: 'obligatoria', doses: 3, requiresBooster: true,  boosters: 1, boosterFreq: 'Cada 10 años',    hasValidity: true,  minAge: '', maxAge: '',   application: 'todos',   state: 'activa',   esquemaId: 'ESQ-004', observations: 'Exigida por la Resolución 0312 de 2019.',                            updated: '12/04/2026' },
  { id: 'VAC-004', name: 'Fiebre amarilla',           type: 'obligatoria', doses: 1, requiresBooster: false, boosters: 0, boosterFreq: '',                hasValidity: false, minAge: '9', maxAge: '59', application: 'sedes',   state: 'activa',   esquemaId: 'ESQ-001', observations: 'Dosis única de por vida. Aplica a sedes en zona de riesgo.',          updated: '20/03/2026' },
  { id: 'VAC-005', name: 'COVID-19 (refuerzo)',       type: 'recomendada', doses: 2, requiresBooster: true,  boosters: 1, boosterFreq: 'Anual',          hasValidity: true,  minAge: '', maxAge: '',   application: 'todos',   state: 'activa',   esquemaId: 'ESQ-005', observations: 'Refuerzo anual recomendado por el Ministerio de Salud.',             updated: '03/05/2026' },
  { id: 'VAC-006', name: 'Fiebre tifoidea',           type: 'recomendada', doses: 1, requiresBooster: true,  boosters: 1, boosterFreq: 'Cada 3 años',     hasValidity: true,  minAge: '', maxAge: '',   application: 'riesgos', state: 'inactiva', esquemaId: 'ESQ-006', observations: 'Suspendida temporalmente · en revisión con ARL.',                    updated: '15/02/2026' },
];

// Esquema de vacunación de cada vacuna — referencia al catálogo reutilizable ESQUEMAS_INITIAL (más abajo)
const esquemaVacName = (id) => ESQUEMAS_INITIAL.find(e => e.id === id)?.name || 'Sin esquema asignado';

const parseDateVac = (d) => { const [dd, mm, yy] = d.split('/').map(Number); return new Date(yy, mm - 1, dd); };
const VAC_TODAY = new Date(2026, 4, 5); // 05/05/2026 — fecha de referencia del prototipo

const matchesVacDate = (dateStr, filter) => {
  if (filter === 'Cualquier fecha') return true;
  const diffDays = Math.round((VAC_TODAY - parseDateVac(dateStr)) / 86400000);
  if (filter === 'Hoy') return diffDays === 0;
  if (filter === 'Últimos 7 días') return diffDays >= 0 && diffDays <= 7;
  if (filter === 'Este mes') {
    const d = parseDateVac(dateStr);
    return d.getFullYear() === VAC_TODAY.getFullYear() && d.getMonth() === VAC_TODAY.getMonth();
  }
  return true;
};

const VAC_FORM_EMPTY = {
  name: '', type: 'ocupacional', state: 'activa', observations: '',
  doses: 1, requiresBooster: false, boosters: '', boosterFreq: '',
  hasValidity: false, minAge: '', maxAge: '', application: 'todos', esquemaId: '',
};

const vaccineToForm = (v) => ({
  name: v.name, type: v.type, state: v.state, observations: v.observations,
  doses: v.doses, requiresBooster: v.requiresBooster, boosters: v.boosters || '', boosterFreq: v.boosterFreq,
  hasValidity: v.hasValidity, minAge: v.minAge, maxAge: v.maxAge, application: v.application,
  esquemaId: v.esquemaId || '',
});

const GestionVacunasSection2 = () => {
  const [vaccines, setVaccines] = _sst2_useState(VACCINES_INITIAL);
  const [search, setSearch] = _sst2_useState('');
  const [fType, setFType] = _sst2_useState('Todos');
  const [fDoses, setFDoses] = _sst2_useState('Todos');
  const [fBoosters, setFBoosters] = _sst2_useState('Todos');
  const [fState, setFState] = _sst2_useState('Todos');
  const [fDate, setFDate] = _sst2_useState('Cualquier fecha');
  const [formOpen, setFormOpen] = _sst2_useState(null); // null | 'create' | vaccine (edit)
  const [viewing, setViewing] = _sst2_useState(null);   // vaccine | null

  const filtered = vaccines.filter(v =>
    (search === '' || v.name.toLowerCase().includes(search.toLowerCase())) &&
    (fType === 'Todos' || VAC_TYPE_META[v.type].label === fType) &&
    (fDoses === 'Todos' || String(v.doses) === fDoses) &&
    (fBoosters === 'Todos' || String(v.boosters) === fBoosters) &&
    (fState === 'Todos' || (fState === 'Activa' ? v.state === 'activa' : v.state === 'inactiva')) &&
    matchesVacDate(v.updated, fDate)
  );

  const toggleState = (id) => {
    setVaccines(prev => prev.map(v => v.id === id ? { ...v, state: v.state === 'activa' ? 'inactiva' : 'activa', updated: '05/05/2026' } : v));
  };

  const saveVaccine = (form, editingId) => {
    if (editingId) {
      setVaccines(prev => prev.map(v => v.id === editingId ? {
        ...v, ...form,
        boosters: form.requiresBooster ? Number(form.boosters) || 0 : 0,
        doses: Number(form.doses) || 1,
        updated: '05/05/2026',
      } : v));
    } else {
      const newVaccine = {
        id: `VAC-${String(vaccines.length + 1).padStart(3, '0')}`,
        ...form,
        doses: Number(form.doses) || 1,
        boosters: form.requiresBooster ? Number(form.boosters) || 0 : 0,
        updated: '05/05/2026',
      };
      setVaccines(prev => [newVaccine, ...prev]);
    }
    setFormOpen(null);
  };

  return (
    <div className="card" style={{ marginBottom: 24 }}>
      <div className="card-head">
        <div>
          <h3>Catálogo de vacunas</h3>
          <div className="sub">{vaccines.length} vacunas registradas en el sistema</div>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button className="btn"><IconExternal size={14} /> Exportar listado de vacunas</button>
          <button className="btn primary" onClick={() => setFormOpen('create')}><IconPlus size={14} /> Crear vacuna</button>
        </div>
      </div>

      <div className="ob-toolbar" style={{ margin: '14px 16px 0' }}>
        <div className="ob-search">
          <IconSearch size={15} />
          <input placeholder="Buscar por nombre…" value={search} onChange={(e) => setSearch(e.target.value)} />
        </div>
        <select value={fType} onChange={(e) => setFType(e.target.value)}>
          <option>Todos</option>
          {Object.values(VAC_TYPE_META).map(t => <option key={t.label}>{t.label}</option>)}
        </select>
        <select value={fDoses} onChange={(e) => setFDoses(e.target.value)}>
          <option value="Todos">Cualquier N.º de dosis</option>
          <option value="1">1 dosis</option>
          <option value="2">2 dosis</option>
          <option value="3">3 dosis</option>
        </select>
        <select value={fBoosters} onChange={(e) => setFBoosters(e.target.value)}>
          <option value="Todos">Cualquier N.º de refuerzos</option>
          <option value="0">Sin refuerzos</option>
          <option value="1">1 refuerzo</option>
        </select>
        <select value={fState} onChange={(e) => setFState(e.target.value)}>
          <option>Todos</option>
          <option>Activa</option>
          <option>Inactiva</option>
        </select>
        <select value={fDate} onChange={(e) => setFDate(e.target.value)}>
          <option>Cualquier fecha</option>
          <option>Hoy</option>
          <option>Últimos 7 días</option>
          <option>Este mes</option>
        </select>
      </div>

      <div className="doc-list-card" style={{ boxShadow: 'none', border: 'none', margin: '12px 16px 16px' }}>
        <table className="doc-table">
          <thead>
            <tr>
              <th>Nombre de la vacuna</th>
              <th>Tipo</th>
              <th>N.º dosis</th>
              <th>N.º refuerzos</th>
              <th>Esquema de vacunación</th>
              <th>Estado</th>
              <th>Última modificación</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {filtered.map(v => {
              const t = VAC_TYPE_META[v.type];
              return (
                <tr key={v.id}>
                  <td>
                    <div style={{ fontWeight: 600, fontSize: 13 }}>{v.name}</div>
                    <div className="muted mono" style={{ fontSize: 11 }}>{v.id}</div>
                  </td>
                  <td><span className={`pill ${t.pill}`} style={{ fontSize: 11 }}>{t.label}</span></td>
                  <td className="mono" style={{ fontSize: 12.5 }}>{v.doses}</td>
                  <td className="mono" style={{ fontSize: 12.5 }}>{v.boosters}</td>
                  <td style={{ fontSize: 12.5 }}>{esquemaVacName(v.esquemaId)}</td>
                  <td>
                    <span className={`pill ${v.state === 'activa' ? 'green' : ''}`} style={{ fontSize: 11 }}>
                      <span className="status-dot" style={{ background: v.state === 'activa' ? 'var(--green-600)' : 'var(--text-muted)' }} />
                      {v.state === 'activa' ? 'Activa' : 'Inactiva'}
                    </span>
                  </td>
                  <td className="mono muted" style={{ fontSize: 12 }}>{v.updated}</td>
                  <td>
                    <div className="doc-actions">
                      <button className="icon-action" title="Ver vacuna" onClick={() => setViewing(v)}><IconExternal size={14} /></button>
                      <button className="icon-action" title="Editar vacuna" onClick={() => setFormOpen(v)}><IconDoc size={14} /></button>
                      <button
                        className={`icon-action ${v.state === 'activa' ? 'danger' : ''}`}
                        title={v.state === 'activa' ? 'Inactivar vacuna' : 'Activar vacuna'}
                        onClick={() => toggleState(v.id)}
                      >
                        {v.state === 'activa' ? <IconAlert size={14} /> : <IconCheck size={14} />}
                      </button>
                    </div>
                  </td>
                </tr>
              );
            })}
            {filtered.length === 0 && (
              <tr><td colSpan={8} className="muted" style={{ textAlign: 'center', padding: 24, fontSize: 12.5 }}>Ningún resultado con estos filtros.</td></tr>
            )}
          </tbody>
        </table>
        <div className="doc-table-foot">
          <span className="muted" style={{ fontSize: 12 }}>Mostrando {filtered.length} de {vaccines.length} vacunas</span>
        </div>
      </div>

      {formOpen && (
        <VacVaccineFormModal
          vaccine={formOpen === 'create' ? null : formOpen}
          onClose={() => setFormOpen(null)}
          onSave={saveVaccine}
        />
      )}
      {viewing && <VacVaccineViewModal vaccine={viewing} onClose={() => setViewing(null)} />}
    </div>
  );
};

const VacVaccineFormModal = ({ vaccine, onClose, onSave }) => {
  const [form, setForm] = _sst2_useState(vaccine ? vaccineToForm(vaccine) : VAC_FORM_EMPTY);
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  React.useEffect(() => {
    document.body.style.overflow = 'hidden';
    const onEsc = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onEsc);
    return () => { document.body.style.overflow = ''; window.removeEventListener('keydown', onEsc); };
  }, []);

  const canSave = form.name.trim().length > 0;

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 940 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">{vaccine ? `Editar vacuna · ${vaccine.name}` : 'Crear vacuna'}</div>
            <div className="modal-sub">Define la información general y la configuración del esquema de aplicación.</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>

        <div className="modal-body">
          <div className="furat-grid">
            {/* Información general */}
            <div className="furat-col">
              <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--text)', textTransform: 'uppercase', letterSpacing: 0.03 }}>Información general</div>

              <div className="furat-row">
                <label className="furat-label">Nombre de vacuna</label>
                <input type="text" value={form.name} onChange={(e) => set('name', e.target.value)} placeholder="Ej. Influenza estacional" />
              </div>

              <div className="furat-row">
                <label className="furat-label">Tipo</label>
                <select value={form.type} onChange={(e) => set('type', e.target.value)}>
                  <option value="ocupacional">Ocupacional</option>
                  <option value="obligatoria">Obligatoria</option>
                  <option value="recomendada">Recomendada</option>
                  <option value="campana">Campaña</option>
                  <option value="otro">Otro</option>
                </select>
              </div>

              <div className="furat-row">
                <label className="furat-label">Estado</label>
                <div className="furat-segment compact">
                  <button className={`furat-seg ${form.state === 'activa' ? 'active green' : ''}`} onClick={() => set('state', 'activa')} type="button">Activa</button>
                  <button className={`furat-seg ${form.state === 'inactiva' ? 'active' : ''}`} onClick={() => set('state', 'inactiva')} type="button">Inactiva</button>
                </div>
              </div>

              <div className="furat-row">
                <label className="furat-label">Observaciones</label>
                <textarea rows={5} value={form.observations} onChange={(e) => set('observations', e.target.value)} placeholder="Notas adicionales sobre la vacuna, condiciones de aplicación, proveedor, etc." />
              </div>
            </div>

            {/* Configuración de vacuna */}
            <div className="furat-col">
              <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--text)', textTransform: 'uppercase', letterSpacing: 0.03 }}>Configuración de vacuna</div>

              <div className="furat-row">
                <label className="furat-label">Número de dosis requeridas</label>
                <input type="number" min="1" value={form.doses} onChange={(e) => set('doses', e.target.value)} />
              </div>

              <div className="furat-row">
                <label className="furat-label">¿Requiere refuerzos?</label>
                <div className="furat-segment compact">
                  <button className={`furat-seg ${form.requiresBooster ? 'active green' : ''}`} onClick={() => set('requiresBooster', true)} type="button">Sí</button>
                  <button className={`furat-seg ${!form.requiresBooster ? 'active' : ''}`} onClick={() => set('requiresBooster', false)} type="button">No</button>
                </div>
              </div>

              {form.requiresBooster && (
                <div className="furat-grid-2">
                  <div className="furat-row">
                    <label className="furat-label">N.º de refuerzos</label>
                    <input type="number" min="1" value={form.boosters} onChange={(e) => set('boosters', e.target.value)} placeholder="Ej. 1" />
                  </div>
                  <div className="furat-row">
                    <label className="furat-label">Periodicidad</label>
                    <input type="text" value={form.boosterFreq} onChange={(e) => set('boosterFreq', e.target.value)} placeholder="Ej. Anual, cada 3 años…" />
                  </div>
                </div>
              )}

              <div className="furat-row">
                <label className="furat-label">Tiene vigencia</label>
                <div className="furat-segment compact">
                  <button className={`furat-seg ${form.hasValidity ? 'active green' : ''}`} onClick={() => set('hasValidity', true)} type="button">Sí</button>
                  <button className={`furat-seg ${!form.hasValidity ? 'active' : ''}`} onClick={() => set('hasValidity', false)} type="button">No</button>
                </div>
              </div>

              <div className="furat-row">
                <label className="furat-label">Edad mínima y máxima <span className="muted" style={{ textTransform: 'none', fontWeight: 500 }}>(no obligatorio)</span></label>
                <div className="furat-grid-2">
                  <input type="number" min="0" value={form.minAge} onChange={(e) => set('minAge', e.target.value)} placeholder="Edad mínima" />
                  <input type="number" min="0" value={form.maxAge} onChange={(e) => set('maxAge', e.target.value)} placeholder="Edad máxima" />
                </div>
              </div>

              <div className="furat-row">
                <label className="furat-label">Aplicación</label>
                <select value={form.application} onChange={(e) => set('application', e.target.value)}>
                  <option value="todos">Todos los empleados</option>
                  <option value="cargos">Cargos específicos</option>
                  <option value="areas">Áreas específicas</option>
                  <option value="sedes">Sedes específicas</option>
                  <option value="riesgos">Riesgos ocupacionales específicos</option>
                </select>
              </div>

              <div className="furat-row">
                <label className="furat-label">Esquema de vacunación</label>
                <select value={form.esquemaId} onChange={(e) => set('esquemaId', e.target.value)}>
                  <option value="">Sin esquema asignado</option>
                  {ESQUEMAS_INITIAL.map(e => (
                    <option key={e.id} value={e.id}>{e.name}{e.state === 'inactivo' ? ' (inactivo)' : ''}</option>
                  ))}
                </select>
              </div>
            </div>
          </div>
        </div>

        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" disabled={!canSave} onClick={() => onSave(form, vaccine ? vaccine.id : null)}>
            <IconCheck size={14} /> {vaccine ? 'Guardar cambios' : 'Crear vacuna'}
          </button>
        </div>
      </div>
    </div>
  );
};

const VacVaccineViewModal = ({ vaccine: v, onClose }) => {
  React.useEffect(() => {
    document.body.style.overflow = 'hidden';
    const onEsc = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onEsc);
    return () => { document.body.style.overflow = ''; window.removeEventListener('keydown', onEsc); };
  }, []);

  const t = VAC_TYPE_META[v.type];
  const row = (label, value) => (
    <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, padding: '9px 0', borderBottom: '1px solid var(--border)', fontSize: 12.5 }}>
      <span className="muted">{label}</span>
      <span style={{ fontWeight: 600, color: 'var(--text)', textAlign: 'right' }}>{value}</span>
    </div>
  );

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 520 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">{v.name}</div>
            <div className="modal-sub mono">{v.id}</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>
            <span className={`pill ${t.pill}`}>{t.label}</span>
            <span className={`pill ${v.state === 'activa' ? 'green' : ''}`}>
              <span className="status-dot" style={{ background: v.state === 'activa' ? 'var(--green-600)' : 'var(--text-muted)' }} />
              {v.state === 'activa' ? 'Activa' : 'Inactiva'}
            </span>
          </div>
          {row('Dosis requeridas', v.doses)}
          {row('Requiere refuerzos', v.requiresBooster ? `Sí · ${v.boosters} (${v.boosterFreq || 'sin periodicidad definida'})` : 'No')}
          {row('Tiene vigencia', v.hasValidity ? 'Sí' : 'No')}
          {row('Edad mínima / máxima', (v.minAge || v.maxAge) ? `${v.minAge || '—'} / ${v.maxAge || '—'}` : 'No aplica')}
          {row('Aplicación', VAC_APPLICATION_META[v.application])}
          {row('Esquema de vacunación', esquemaVacName(v.esquemaId))}
          {row('Última modificación', v.updated)}
          {v.observations && (
            <div style={{ marginTop: 12 }}>
              <div className="muted-xs" style={{ marginBottom: 4 }}>Observaciones</div>
              <div style={{ fontSize: 12.5, lineHeight: 1.5 }}>{v.observations}</div>
            </div>
          )}
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cerrar</button>
        </div>
      </div>
    </div>
  );
};

// ─── Esquemas de vacunación — catálogo reutilizable por varias vacunas ──
// Un esquema (ej. "Dosis única", "Esquema 0-1-6 meses") define cuántas
// dosis y refuerzos tiene y su periodicidad; varias vacunas del catálogo
// pueden compartir el mismo esquema en vez de definir su propio calendario.

const VAC_PERIOD_UNIT_LABEL = { dias: 'día(s)', meses: 'mes(es)', anos: 'año(s)' };

const periodLabel = (p) => `${p.periodValue || 0} ${VAC_PERIOD_UNIT_LABEL[p.periodUnit]}`;

const ESQUEMAS_INITIAL = [
  {
    id: 'ESQ-001', name: 'Dosis única', state: 'activo',
    doses: [{ num: 1, periodValue: 0, periodUnit: 'dias', mandatory: true }],
    boosters: [],
    vaccines: ['Fiebre amarilla', 'Hepatitis A'],
  },
  {
    id: 'ESQ-002', name: 'Dosis única + refuerzo anual', state: 'activo',
    doses: [{ num: 1, periodValue: 0, periodUnit: 'dias', mandatory: true }],
    boosters: [{ num: 1, periodValue: 1, periodUnit: 'anos', mandatory: true }],
    vaccines: ['Influenza estacional'],
  },
  {
    id: 'ESQ-003', name: 'Esquema 0-1-6 meses', state: 'activo',
    doses: [
      { num: 1, periodValue: 0, periodUnit: 'dias',  mandatory: true },
      { num: 2, periodValue: 1, periodUnit: 'meses', mandatory: true },
      { num: 3, periodValue: 6, periodUnit: 'meses', mandatory: true },
    ],
    boosters: [],
    vaccines: ['Hepatitis B'],
  },
  {
    id: 'ESQ-004', name: '3 dosis + refuerzo decenal', state: 'activo',
    doses: [
      { num: 1, periodValue: 0, periodUnit: 'dias',  mandatory: true },
      { num: 2, periodValue: 1, periodUnit: 'meses', mandatory: true },
      { num: 3, periodValue: 6, periodUnit: 'meses', mandatory: true },
    ],
    boosters: [{ num: 1, periodValue: 10, periodUnit: 'anos', mandatory: true }],
    vaccines: ['Tétanos y difteria (Td)'],
  },
  {
    id: 'ESQ-005', name: '2 dosis + refuerzo anual', state: 'activo',
    doses: [
      { num: 1, periodValue: 0, periodUnit: 'dias',  mandatory: true },
      { num: 2, periodValue: 1, periodUnit: 'meses', mandatory: true },
    ],
    boosters: [{ num: 1, periodValue: 1, periodUnit: 'anos', mandatory: true }],
    vaccines: ['COVID-19 (refuerzo)'],
  },
  {
    id: 'ESQ-006', name: 'Dosis única + refuerzo trienal', state: 'inactivo',
    doses: [{ num: 1, periodValue: 0, periodUnit: 'dias', mandatory: true }],
    boosters: [{ num: 1, periodValue: 3, periodUnit: 'anos', mandatory: true }],
    vaccines: ['Fiebre tifoidea'],
  },
];

const ESQ_FORM_EMPTY = {
  name: '', state: 'activo',
  doses: [{ num: 1, periodValue: 0, periodUnit: 'dias', mandatory: true }],
  boosters: [],
};

const esquemaToForm = (e) => ({
  name: e.name, state: e.state,
  doses: e.doses.map(d => ({ ...d })),
  boosters: e.boosters.map(b => ({ ...b })),
});

const EsquemasVacunacionSection2 = () => {
  const [esquemas, setEsquemas] = _sst2_useState(ESQUEMAS_INITIAL);
  const [formOpen, setFormOpen] = _sst2_useState(null); // null | 'create' | esquema (edit)
  const [viewing, setViewing] = _sst2_useState(null);

  const toggleState = (id) => {
    setEsquemas(prev => prev.map(e => e.id === id ? { ...e, state: e.state === 'activo' ? 'inactivo' : 'activo' } : e));
  };

  const saveEsquema = (form, editingId) => {
    if (editingId) {
      setEsquemas(prev => prev.map(e => e.id === editingId ? { ...e, ...form } : e));
    } else {
      const newEsquema = { id: `ESQ-${String(esquemas.length + 1).padStart(3, '0')}`, ...form, vaccines: [] };
      setEsquemas(prev => [newEsquema, ...prev]);
    }
    setFormOpen(null);
  };

  return (
    <div className="card" style={{ marginBottom: 24 }}>
      <div className="card-head">
        <div>
          <h3>Esquemas de vacunación</h3>
          <div className="sub">{esquemas.length} esquemas · reutilizables entre varias vacunas</div>
        </div>
        <button className="btn primary" onClick={() => setFormOpen('create')}><IconPlus size={14} /> Crear esquema</button>
      </div>

      <div className="doc-list-card" style={{ boxShadow: 'none', border: 'none', margin: '12px 16px 16px' }}>
        <table className="doc-table">
          <thead>
            <tr>
              <th>Nombre de esquema</th>
              <th>N.º dosis</th>
              <th>N.º refuerzos</th>
              <th>Vacunas con este esquema</th>
              <th>Estado</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {esquemas.map(e => (
              <tr key={e.id}>
                <td>
                  <div style={{ fontWeight: 600, fontSize: 13 }}>{e.name}</div>
                  <div className="muted mono" style={{ fontSize: 11 }}>{e.id}</div>
                </td>
                <td className="mono" style={{ fontSize: 12.5 }}>{e.doses.length}</td>
                <td className="mono" style={{ fontSize: 12.5 }}>{e.boosters.length}</td>
                <td>
                  {e.vaccines.length === 0 ? (
                    <span className="muted" style={{ fontSize: 12 }}>Sin vacunas asignadas</span>
                  ) : (
                    <div className="signer-chips">
                      {e.vaccines.map((v, i) => <span key={i} className="signer-chip">{v}</span>)}
                    </div>
                  )}
                </td>
                <td>
                  <span className={`pill ${e.state === 'activo' ? 'green' : ''}`} style={{ fontSize: 11 }}>
                    <span className="status-dot" style={{ background: e.state === 'activo' ? 'var(--green-600)' : 'var(--text-muted)' }} />
                    {e.state === 'activo' ? 'Activo' : 'Inactivo'}
                  </span>
                </td>
                <td>
                  <div className="doc-actions">
                    <button className="icon-action" title="Ver esquema" onClick={() => setViewing(e)}><IconExternal size={14} /></button>
                    <button className="icon-action" title="Editar esquema" onClick={() => setFormOpen(e)}><IconDoc size={14} /></button>
                    <button
                      className={`icon-action ${e.state === 'activo' ? 'danger' : ''}`}
                      title={e.state === 'activo' ? 'Inactivar esquema' : 'Activar esquema'}
                      onClick={() => toggleState(e.id)}
                    >
                      {e.state === 'activo' ? <IconAlert size={14} /> : <IconCheck size={14} />}
                    </button>
                  </div>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {formOpen && (
        <EsquemaFormModal
          esquema={formOpen === 'create' ? null : formOpen}
          onClose={() => setFormOpen(null)}
          onSave={saveEsquema}
        />
      )}
      {viewing && <EsquemaViewModal esquema={viewing} onClose={() => setViewing(null)} />}
    </div>
  );
};

// ── Mini-formulario de dosis/refuerzos ──────────────────────
// hideFirst=true (Dosis): la dosis #1 es implícita — es la fecha de inicio
// del esquema, no tiene periodicidad propia — así que no se renderiza una
// tarjeta para ella. El contador visible arranca en la Dosis #2, y su
// periodicidad se cuenta "después de la fecha de la primera dosis".
// Refuerzos no tiene ese caso base implícito, así que se muestran todos.
const EsqDoseBuilder = ({ title, items, setItems, addLabel, hideFirst }) => {
  const singular = title === 'Dosis' ? 'Dosis' : 'Refuerzo';
  const mandatoryWord = singular === 'Dosis' ? 'obligatoria' : 'obligatorio';
  const update = (i, patch) => setItems(items.map((it, idx) => idx === i ? { ...it, ...patch } : it));
  const remove = (i) => setItems(items.filter((_, idx) => idx !== i).map((it, idx) => ({ ...it, num: idx + 1 })));
  const add = () => setItems([...items, { num: items.length + 1, periodValue: '', periodUnit: 'dias', mandatory: true }]);

  const periodPhrase = (it) => `${it.periodValue || 0} ${it.periodUnit === 'dias' ? 'días' : it.periodUnit === 'meses' ? 'meses' : 'años'}`;

  const sentenceFor = (it, isFirstVisible) => {
    if (singular === 'Dosis') {
      return <>Esta dosis debe aplicarse <b>{periodPhrase(it)}</b> después de la fecha de la primera dosis.</>;
    }
    return isFirstVisible
      ? <>Este refuerzo debe aplicarse <b>{periodPhrase(it)}</b> después de completar el esquema de dosis.</>
      : <>Este refuerzo debe aplicarse <b>{periodPhrase(it)}</b> después del refuerzo anterior.</>;
  };

  const helperFor = () => singular === 'Dosis'
    ? 'El empleado debe completar esta dosis para continuar con el esquema.'
    : 'El empleado debe completar este refuerzo para mantener vigente el esquema.';

  const visible = items.map((it, i) => ({ it, i })).filter(({ i }) => !hideFirst || i > 0);

  return (
    <div className="furat-row">
      <label className="furat-label">{title}</label>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        {visible.map(({ it, i }, vi) => (
          <div key={i} style={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 12, padding: 16 }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 }}>
              <span style={{
                display: 'inline-flex', alignItems: 'center', gap: 8,
                background: 'var(--sky-100)', color: 'var(--navy-800)',
                fontWeight: 700, fontSize: 13, padding: '7px 14px', borderRadius: 999,
              }}>
                <IconSyringe size={15} style={{ color: 'var(--teal-800)' }} /> {singular} {it.num}
              </span>
              <button type="button" className="icon-action danger" title={`Quitar ${singular.toLowerCase()} ${it.num}`} onClick={() => remove(i)}>
                <IconTrash size={15} />
              </button>
            </div>

            <div style={{ display: 'flex', gap: 20, flexWrap: 'wrap' }}>
              <div style={{ flex: 1, minWidth: 220 }}>
                <div style={{ display: 'flex', gap: 24, flexWrap: 'wrap', marginBottom: 14 }}>
                  <div>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 5, marginBottom: 6, fontSize: 12.5, color: 'var(--text)' }}>
                      Periodicidad <IconInfo size={13} style={{ color: 'var(--teal-500)' }} title="Tiempo transcurrido desde la referencia hasta esta aplicación" />
                    </div>
                    <input
                      type="number" min="0" value={it.periodValue}
                      onChange={(e) => update(i, { periodValue: e.target.value })}
                      style={{ width: 110, fontSize: 14, padding: '9px 12px' }}
                      placeholder="0"
                    />
                  </div>
                  <div>
                    <div className="muted-xs" style={{ marginBottom: 6 }}>Unidad de tiempo</div>
                    <div className="furat-segment compact">
                      {['dias', 'meses', 'anos'].map(u => (
                        <button
                          key={u} type="button"
                          className={`furat-seg ${it.periodUnit === u ? 'active navy' : ''}`}
                          onClick={() => update(i, { periodUnit: u })}
                        >
                          {u === 'dias' ? 'Días' : u === 'meses' ? 'Meses' : 'Años'}
                        </button>
                      ))}
                    </div>
                  </div>
                </div>

                <div style={{ display: 'flex', alignItems: 'center', gap: 10, borderTop: '1px solid var(--border)', paddingTop: 12 }}>
                  <div style={{ width: 30, height: 30, borderRadius: 8, background: 'var(--sky-50)', color: 'var(--teal-800)', display: 'grid', placeItems: 'center', flexShrink: 0 }}>
                    <IconCalendar size={14} />
                  </div>
                  <div style={{ fontSize: 12.5, color: 'var(--text)', lineHeight: 1.4 }}>
                    {sentenceFor(it, vi === 0)}
                  </div>
                </div>
              </div>

              <div style={{ borderLeft: '1px solid var(--border)', paddingLeft: 20, width: 210, flexShrink: 0 }}>
                <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, fontWeight: 600, color: 'var(--text)', cursor: 'pointer' }}>
                  <input
                    type="checkbox" checked={it.mandatory} onChange={(e) => update(i, { mandatory: e.target.checked })}
                    style={{ width: 17, height: 17, accentColor: 'var(--navy-800)', cursor: 'pointer' }}
                  />
                  {singular} {mandatoryWord}
                </label>
                <div className="muted" style={{ fontSize: 11.5, marginTop: 8, lineHeight: 1.5 }}>
                  {helperFor()}
                </div>
              </div>
            </div>
          </div>
        ))}
        <button type="button" className="btn" style={{ alignSelf: 'flex-start' }} onClick={add}>
          <IconPlus size={13} /> {addLabel}
        </button>
      </div>
    </div>
  );
};

const EsquemaFormModal = ({ esquema, onClose, onSave }) => {
  const [form, setForm] = _sst2_useState(esquema ? esquemaToForm(esquema) : ESQ_FORM_EMPTY);
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  React.useEffect(() => {
    document.body.style.overflow = 'hidden';
    const onEsc = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onEsc);
    return () => { document.body.style.overflow = ''; window.removeEventListener('keydown', onEsc); };
  }, []);

  const canSave = form.name.trim().length > 0;

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 680 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">{esquema ? `Editar esquema · ${esquema.name}` : 'Crear esquema'}</div>
            <div className="modal-sub">Define el calendario de dosis y, si aplica, de refuerzos. Este esquema podrá asignarse a varias vacunas.</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>

        <div className="modal-body">
          <div className="furat-col">
            <div className="furat-row">
              <label className="furat-label">Nombre de esquema</label>
              <input type="text" value={form.name} onChange={(e) => set('name', e.target.value)} placeholder="Ej. Dosis única, Esquema 0-1-6 meses…" />
            </div>

            <div className="furat-row">
              <label className="furat-label">Estado</label>
              <div className="furat-segment compact">
                <button type="button" className={`furat-seg ${form.state === 'activo' ? 'active green' : ''}`} onClick={() => set('state', 'activo')}>Activo</button>
                <button type="button" className={`furat-seg ${form.state === 'inactivo' ? 'active' : ''}`} onClick={() => set('state', 'inactivo')}>Inactivo</button>
              </div>
            </div>

            <EsqDoseBuilder title="Dosis" items={form.doses} setItems={(v) => set('doses', v)} addLabel="Agregar dosis" hideFirst />
            <EsqDoseBuilder title="Refuerzos" items={form.boosters} setItems={(v) => set('boosters', v)} addLabel="Agregar refuerzo" hideFirst={false} />
          </div>
        </div>

        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" disabled={!canSave} onClick={() => onSave(form, esquema ? esquema.id : null)}>
            <IconCheck size={14} /> {esquema ? 'Guardar cambios' : 'Crear esquema'}
          </button>
        </div>
      </div>
    </div>
  );
};

const EsquemaViewModal = ({ esquema: e, onClose }) => {
  React.useEffect(() => {
    document.body.style.overflow = 'hidden';
    const onEsc = (ev) => { if (ev.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onEsc);
    return () => { document.body.style.overflow = ''; window.removeEventListener('keydown', onEsc); };
  }, []);

  const renderList = (items, emptyLabel) => items.length === 0 ? (
    <div className="muted" style={{ fontSize: 12.5 }}>{emptyLabel}</div>
  ) : (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {items.map((it, i) => (
        <div key={i} style={{ display: 'flex', justifyContent: 'space-between', fontSize: 12.5, padding: '6px 0', borderBottom: i < items.length - 1 ? '1px solid var(--border)' : 'none' }}>
          <span>N.º {it.num}</span>
          <span className="muted">{periodLabel(it)}</span>
          <span className={`pill ${it.mandatory ? 'rose' : ''}`} style={{ fontSize: 10.5 }}>{it.mandatory ? 'Obligatoria' : 'Opcional'}</span>
        </div>
      ))}
    </div>
  );

  return (
    <div className="modal-overlay" onMouseDown={(ev) => { if (ev.target === ev.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 520 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">{e.name}</div>
            <div className="modal-sub mono">{e.id}</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <span className={`pill ${e.state === 'activo' ? 'green' : ''}`} style={{ marginBottom: 14, display: 'inline-flex' }}>
            <span className="status-dot" style={{ background: e.state === 'activo' ? 'var(--green-600)' : 'var(--text-muted)' }} />
            {e.state === 'activo' ? 'Activo' : 'Inactivo'}
          </span>

          <div className="muted-xs" style={{ marginBottom: 6 }}>Dosis ({e.doses.length})</div>
          {renderList(e.doses, 'Sin dosis definidas')}

          <div className="muted-xs" style={{ margin: '14px 0 6px' }}>Refuerzos ({e.boosters.length})</div>
          {renderList(e.boosters, 'Sin refuerzos')}

          <div className="muted-xs" style={{ margin: '14px 0 6px' }}>Vacunas con este esquema ({e.vaccines.length})</div>
          {e.vaccines.length === 0 ? (
            <div className="muted" style={{ fontSize: 12.5 }}>Sin vacunas asignadas</div>
          ) : (
            <div className="signer-chips">
              {e.vaccines.map((v, i) => <span key={i} className="signer-chip">{v}</span>)}
            </div>
          )}
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cerrar</button>
        </div>
      </div>
    </div>
  );
};

// ─── Vacunación por empleado ─────────────────────────────────
// Lista a los colaboradores con al menos una vacuna asignada (no
// necesariamente aplicada). "Ver vacunación" despliega, por cada vacuna
// asignada, las dosis/refuerzos que define su esquema — las ya aplicadas
// quedan bloqueadas, y las pendientes se pueden registrar. La fecha límite
// de cada dosis se calcula automáticamente a partir de la fecha en que se
// aplicó la dosis/refuerzo anterior (o de la fecha de asignación, para la 1ª).

const addPeriodVac = (date, value, unit) => {
  const d = new Date(date.getTime());
  const v = Number(value) || 0;
  if (unit === 'meses') d.setMonth(d.getMonth() + v);
  else if (unit === 'anos') d.setFullYear(d.getFullYear() + v);
  else d.setDate(d.getDate() + v); // 'dias' (o por defecto)
  return d;
};

const formatDateVac = (d) => `${String(d.getDate()).padStart(2, '0')}/${String(d.getMonth() + 1).padStart(2, '0')}/${d.getFullYear()}`;

// Construye la línea de tiempo dosis+refuerzos de una asignación, encadenando
// cada fecha límite a partir de la fecha real de aplicación anterior.
const buildVacSchedule = (assignment) => {
  const vaccine = VACCINES_INITIAL.find(v => v.id === assignment.vaccineId);
  const esquema = vaccine ? ESQUEMAS_INITIAL.find(e => e.id === vaccine.esquemaId) : null;
  if (!vaccine || !esquema) return { vaccine, esquema: null, items: [] };

  const sequence = [
    ...esquema.doses.map(d => ({ ...d, kind: 'dosis' })),
    ...esquema.boosters.map(b => ({ ...b, kind: 'refuerzo' })),
  ];

  let anchor = parseDateVac(assignment.assignedDate);
  const items = sequence.map(step => {
    const key = `${step.kind}-${step.num}`;
    const dueDate = addPeriodVac(anchor, step.periodValue, step.periodUnit);
    const rec = (assignment.records || {})[key] || {};
    anchor = rec.applied ? parseDateVac(rec.applied) : dueDate;
    return {
      key, kind: step.kind, num: step.num,
      dueDateStr: formatDateVac(dueDate),
      applied: rec.applied || null,
      cardPhoto: rec.cardPhoto || null,
      observations: rec.observations || '',
    };
  });
  return { vaccine, esquema, items };
};

const EMP_VACCINATIONS_INITIAL = [
  { empId: 'E0247', doc: 'CC 1.087.456.231', name: 'Andrés Felipe Mejía', cargo: 'Operario de Clasificación', ciudad: 'Cali',
    assignments: [
      { vaccineId: 'VAC-001', assignedDate: '20/04/2026', records: {} },
    ] },
  { empId: 'E0198', doc: 'CC 1.098.443.221', name: 'María Fernanda López', cargo: 'Op. Aprovechamiento', ciudad: 'Cali',
    assignments: [
      { vaccineId: 'VAC-002', assignedDate: '09/10/2025', records: {
        'dosis-1': { applied: '09/10/2025', cardPhoto: 'carnet-mfl-dosis1.jpg', observations: '' },
        'dosis-2': { applied: '09/11/2025', cardPhoto: 'carnet-mfl-dosis2.jpg', observations: '' },
      } },
    ] },
  { empId: 'E0177', doc: 'CC 75.221.487', name: 'Jorge Iván Patiño', cargo: 'Conductor', ciudad: 'Barranquilla',
    assignments: [
      { vaccineId: 'VAC-004', assignedDate: '12/05/2026', records: {} },
    ] },
  { empId: 'E0156', doc: 'CC 1.087.665.443', name: 'Paula Valencia Ríos', cargo: 'Téc. Mantenimiento', ciudad: 'Cali',
    assignments: [
      { vaccineId: 'VAC-003', assignedDate: '14/03/2016', records: {
        'dosis-1': { applied: '14/03/2016', cardPhoto: 'carnet-pv-dosis1.jpg', observations: '' },
        'dosis-2': { applied: '14/04/2016', cardPhoto: 'carnet-pv-dosis2.jpg', observations: '' },
        'dosis-3': { applied: '14/09/2016', cardPhoto: 'carnet-pv-dosis3.jpg', observations: '' },
      } },
    ] },
  { empId: 'E0128', doc: 'CC 1.067.443.221', name: 'Nicolás Cárdenas', cargo: 'Conductor', ciudad: 'Barranquilla',
    assignments: [
      { vaccineId: 'VAC-002', assignedDate: '15/03/2026', records: {
        'dosis-1': { applied: '15/03/2026', cardPhoto: 'carnet-nc-dosis1.jpg', observations: '' },
      } },
    ] },
  { empId: 'E0067', doc: 'CC 16.443.221', name: 'Luis Miguel Marín', cargo: 'Líder de Aprovechamiento', ciudad: 'Cali',
    assignments: [
      { vaccineId: 'VAC-005', assignedDate: '10/03/2025', records: {
        'dosis-1': { applied: '10/03/2025', cardPhoto: 'carnet-lm-dosis1.jpg', observations: '' },
        'dosis-2': { applied: '10/04/2025', cardPhoto: 'carnet-lm-dosis2.jpg', observations: '' },
      } },
    ] },
  { empId: 'E0023', doc: 'CC 42.221.087', name: 'Carolina Restrepo S.', cargo: 'Jefe de RRHH', ciudad: 'Cali',
    assignments: [
      { vaccineId: 'VAC-004', assignedDate: '02/02/2019', records: {
        'dosis-1': { applied: '05/02/2019', cardPhoto: 'carnet-cr-dosis1.jpg', observations: 'Aplicada en jornada de vacunación ARL Sura.' },
      } },
    ] },
  { empId: 'E0094', doc: 'CC 42.887.665', name: 'María Trujillo Henao', cargo: 'Aux. Recursos Humanos', ciudad: 'Cali',
    assignments: [
      { vaccineId: 'VAC-004', assignedDate: '05/01/2026', records: {} },
    ] },
  { empId: 'E0142', doc: 'CC 1.098.221.665', name: 'Diego Andrés Toro', cargo: 'Aux. Aprovechamiento', ciudad: 'Cali',
    assignments: [
      { vaccineId: 'VAC-001', assignedDate: '29/04/2026', records: {} },
    ] },
];

const EmpleadoVacunacionSection2 = ({ employees, onSaveDose }) => {
  const [viewingId, setViewingId] = _sst2_useState(null); // empId en el modal "Ver vacunación"
  const viewing = employees.find(e => e.empId === viewingId) || null;

  return (
    <div className="card" style={{ marginBottom: 24 }}>
      <div className="card-head">
        <div>
          <h3>Vacunación por empleado</h3>
          <div className="sub">{employees.length} colaboradores con al menos una vacuna asignada</div>
        </div>
      </div>
      <table className="data-table">
        <thead>
          <tr>
            <th>Documento</th>
            <th>Nombre completo</th>
            <th>Cargo</th>
            <th>Ciudad</th>
            <th>Vacunas asignadas</th>
            <th style={{ textAlign: 'right' }}>Funciones</th>
          </tr>
        </thead>
        <tbody>
          {employees.map(emp => (
            <tr key={emp.empId}>
              <td className="mono muted">{emp.doc}</td>
              <td style={{ fontWeight: 500 }}>{emp.name}</td>
              <td>{emp.cargo}</td>
              <td>{emp.ciudad}</td>
              <td>
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
                  {emp.assignments.map(a => {
                    const vac = VACCINES_INITIAL.find(v => v.id === a.vaccineId);
                    const t = vac ? VAC_TYPE_META[vac.type] : null;
                    return (
                      <span key={a.vaccineId} className={`pill ${t ? t.pill : ''}`} style={{ fontSize: 11 }}>
                        {vac ? vac.name : a.vaccineId}
                      </span>
                    );
                  })}
                </div>
              </td>
              <td style={{ textAlign: 'right' }}>
                <button className="btn" style={{ padding: '4px 10px', fontSize: 12 }} onClick={() => setViewingId(emp.empId)}>
                  Ver vacunación
                </button>
              </td>
            </tr>
          ))}
        </tbody>
        {employees.length === 0 && (
          <tbody>
            <tr><td colSpan={6} className="muted" style={{ textAlign: 'center', padding: 24, fontSize: 12.5 }}>Ningún colaborador tiene vacunas asignadas.</td></tr>
          </tbody>
        )}
      </table>
      <div className="doc-table-foot">
        <span className="muted" style={{ fontSize: 12 }}>Mostrando {employees.length} de {employees.length} colaboradores</span>
      </div>

      {viewing && (
        <EmpVacunacionViewModal
          employee={viewing}
          onClose={() => setViewingId(null)}
          onSaveDose={onSaveDose}
        />
      )}
    </div>
  );
};

const EmpVacunacionViewModal = ({ employee, onClose, onSaveDose }) => {
  const [capturing, setCapturing] = _sst2_useState(null); // { vaccineId, item }

  return (
    <Modal open onClose={onClose}
      title={employee.name}
      subtitle={`${employee.doc} · ${employee.cargo} · ${employee.ciudad}`}
      width={780}
      footer={<button className="btn" onClick={onClose}>Cerrar</button>}>
      {employee.assignments.map(a => {
        const { vaccine, esquema, items } = buildVacSchedule(a);
        return (
          <div key={a.vaccineId} style={{ marginBottom: 20 }}>
            <div style={{ marginBottom: 8 }}>
              <div style={{ fontWeight: 700, fontSize: 14 }}>{vaccine ? vaccine.name : a.vaccineId}</div>
              <div className="muted" style={{ fontSize: 12 }}>Esquema: {esquema ? esquema.name : 'Sin esquema asignado'}</div>
            </div>

            {!esquema ? (
              <div className="muted" style={{ fontSize: 12.5 }}>Esta vacuna no tiene un esquema de vacunación configurado, así que no hay dosis para registrar.</div>
            ) : (
              <table className="data-table">
                <thead>
                  <tr><th>Dosis / refuerzo</th><th>Fecha límite</th><th>Estado</th><th>Fecha aplicada</th><th style={{ textAlign: 'right' }}>Funciones</th></tr>
                </thead>
                <tbody>
                  {items.map(it => (
                    <tr key={it.key}>
                      <td>{it.kind === 'dosis' ? `Dosis ${it.num}` : `Refuerzo ${it.num}`}</td>
                      <td className="mono muted">{it.dueDateStr}</td>
                      <td>
                        <span className={`pill ${it.applied ? 'green' : 'amber'}`} style={{ fontSize: 11 }}>
                          {it.applied ? 'Aplicada' : 'Pendiente'}
                        </span>
                      </td>
                      <td className="mono muted">{it.applied || '—'}</td>
                      <td style={{ textAlign: 'right' }}>
                        {it.applied ? (
                          <button className="btn" disabled style={{ padding: '4px 10px', fontSize: 12 }}>Aplicada</button>
                        ) : (
                          <button
                            className="btn primary"
                            style={{ padding: '4px 10px', fontSize: 12 }}
                            onClick={() => setCapturing({ vaccineId: a.vaccineId, item: it })}
                          >
                            Registrar aplicación
                          </button>
                        )}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            )}
          </div>
        );
      })}

      {capturing && (
        <VacDoseCaptureModal
          item={capturing.item}
          onClose={() => setCapturing(null)}
          onSave={(record) => { onSaveDose(employee.empId, capturing.vaccineId, capturing.item.key, record); setCapturing(null); }}
        />
      )}
    </Modal>
  );
};

const VacDoseCaptureModal = ({ item, onClose, onSave }) => {
  const [applied, setApplied] = _sst2_useState('');
  const [cardPhoto, setCardPhoto] = _sst2_useState('');
  const [observations, setObservations] = _sst2_useState('');

  const todayStr = formatDateVac(VAC_TODAY);
  const canSave = applied.trim().length > 0;

  return (
    <Modal open onClose={onClose}
      title={`Registrar ${item.kind === 'dosis' ? `dosis ${item.num}` : `refuerzo ${item.num}`}`}
      subtitle="Registra la aplicación real de esta dosis o refuerzo."
      width={480}
      footer={
        <>
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" disabled={!canSave} onClick={() => onSave({ applied, cardPhoto, observations })}>
            <IconCheck size={14} /> Guardar aplicación
          </button>
        </>
      }>
      <div className="form-grid">
        <FormField label="Fecha límite de aplicación" span={6}>
          <input className="form-input" type="text" value={item.dueDateStr} disabled />
        </FormField>
        <FormField label="Fecha en que fue aplicada" span={6}>
          <window.DatePickerCO value={applied} onChange={setApplied} max={todayStr} placeholder="Seleccionar fecha" />
        </FormField>
        <FormField label="Foto del carnet de vacunación actualizado" span={6}>
          <input className="form-input" type="file" accept="image/*" onChange={(e) => setCardPhoto(e.target.files[0]?.name || '')} />
          {cardPhoto && <div className="muted mono" style={{ fontSize: 11.5, marginTop: 4 }}>{cardPhoto}</div>}
        </FormField>
        <FormField label="Observaciones" span={6}>
          <textarea className="form-input" rows={3} placeholder="Notas sobre la aplicación (lote, sede, reacciones, etc.)" value={observations} onChange={(e) => setObservations(e.target.value)} />
        </FormField>
      </div>
    </Modal>
  );
};

// ─── Alertas y reportes ──────────────────────────────────────
// Deriva las alertas directamente del mismo estado de "Vacunación por
// empleado": toda dosis/refuerzo pendiente que esté vencida o próxima a
// vencer (30 días) entra en la lista, clasificada por severidad según
// cuántos días de atraso lleva.

const VAC_ALERT_SEVERITY = {
  critico: { label: 'Crítico', pill: 'rose',       tagTone: 'rose'  },
  grave:   { label: 'Grave',   pill: 'amber-soft', tagTone: 'amber' },
  medio:   { label: 'Medio',   pill: 'amber',      tagTone: 'amber' },
  leve:    { label: 'Leve',    pill: 'blue',        tagTone: 'blue'  },
};

// Umbrales de días vencidos (>=). "leve" cubre lo próximo a vencer (aún no vencido, dentro de 30 días).
const vacAlertSeverity = (overdueDays) => {
  if (overdueDays >= 60) return 'critico';
  if (overdueDays >= 15) return 'grave';
  if (overdueDays > 0)   return 'medio';
  return 'leve';
};

const gatherVacAlerts = (employees) => {
  const alerts = [];
  employees.forEach(emp => {
    emp.assignments.forEach(a => {
      const { vaccine, esquema, items } = buildVacSchedule(a);
      if (!esquema) return;
      items.forEach(it => {
        if (it.applied) return; // solo pendientes
        const due = parseDateVac(it.dueDateStr);
        const diffDays = Math.round((due - VAC_TODAY) / 86400000); // + = faltan días, − = vencida
        if (diffDays > 30) return; // aún falta mucho, no es alertable todavía
        const overdueDays = Math.max(0, -diffDays);
        alerts.push({
          empId: emp.empId, empName: emp.name, doc: emp.doc, cargo: emp.cargo, ciudad: emp.ciudad,
          vaccineName: vaccine ? vaccine.name : a.vaccineId,
          itemLabel: it.kind === 'dosis' ? `Dosis ${it.num}` : `Refuerzo ${it.num}`,
          dueDateStr: it.dueDateStr, diffDays, overdueDays,
          severity: vacAlertSeverity(overdueDays),
        });
      });
    });
  });
  const order = { critico: 0, grave: 1, medio: 2, leve: 3 };
  alerts.sort((x, y) => order[x.severity] - order[y.severity] || y.overdueDays - x.overdueDays);
  return alerts;
};

const AlertasReportesSection2 = ({ employees, onSaveDose }) => {
  const alerts = _sst2_useMemo(() => gatherVacAlerts(employees), [employees]);
  const [viewingId, setViewingId] = _sst2_useState(null);
  const viewingEmp = employees.find(e => e.empId === viewingId) || null;

  const counts = _sst2_useMemo(() => ({
    critico: alerts.filter(a => a.severity === 'critico').length,
    grave: alerts.filter(a => a.severity === 'grave').length,
    medio: alerts.filter(a => a.severity === 'medio').length,
    leve: alerts.filter(a => a.severity === 'leve').length,
  }), [alerts]);

  return (
    <div>
      <div className="tr-kpis" style={{ marginBottom: 16 }}>
        <VacSeverityCard
          icon={IconAlert} severity="Crítico" tone="rose"
          value={counts.critico}
          label="Alertas críticas"
          note="Dosis vencidas hace 60 días o más · acción inmediata con ARL."
        />
        <VacSeverityCard
          icon={IconAlert} severity="Grave" tone="amber"
          value={counts.grave}
          label="Alertas graves"
          note="Vencidas entre 15 y 59 días · priorizar agenda con la IPS."
        />
        <VacSeverityCard
          icon={IconClock} severity="Medio" tone="amber"
          value={counts.medio}
          label="Alertas medias"
          note="Vencidas hace menos de 15 días."
        />
        <VacSeverityCard
          icon={IconClock} severity="Leve" tone="teal"
          value={counts.leve}
          label="Próximas a vencer"
          note="Dentro de los próximos 30 días · aún sin vencer."
        />
      </div>

      <div className="card" style={{ marginBottom: 24 }}>
        <div className="card-head">
          <div>
            <h3>Alertas de esquemas de vacunación</h3>
            <div className="sub">{alerts.length} dosis o refuerzos atrasados, vencidos o próximos a vencer</div>
          </div>
        </div>
        <table className="data-table">
          <thead>
            <tr>
              <th>Colaborador</th>
              <th>Cargo</th>
              <th>Ciudad</th>
              <th>Vacuna</th>
              <th>Dosis / refuerzo</th>
              <th>Fecha límite</th>
              <th>Severidad</th>
              <th style={{ textAlign: 'right' }}>Funciones</th>
            </tr>
          </thead>
          <tbody>
            {alerts.map((al, i) => {
              const sev = VAC_ALERT_SEVERITY[al.severity];
              return (
                <tr key={i}>
                  <td>
                    <div style={{ fontWeight: 500 }}>{al.empName}</div>
                    <div className="muted mono" style={{ fontSize: 11 }}>{al.doc}</div>
                  </td>
                  <td>{al.cargo}</td>
                  <td>{al.ciudad}</td>
                  <td>{al.vaccineName}</td>
                  <td>{al.itemLabel}</td>
                  <td className="mono muted">{al.dueDateStr}</td>
                  <td>
                    <span className={`pill ${sev.pill}`} style={{ fontSize: 11 }}>{sev.label}</span>
                    <div className="muted" style={{ fontSize: 11, marginTop: 3 }}>
                      {al.diffDays >= 0
                        ? `Vence en ${al.diffDays} día${al.diffDays === 1 ? '' : 's'}`
                        : `Vencida hace ${al.overdueDays} día${al.overdueDays === 1 ? '' : 's'}`}
                    </div>
                  </td>
                  <td style={{ textAlign: 'right' }}>
                    <button className="btn" style={{ padding: '4px 10px', fontSize: 12 }} onClick={() => setViewingId(al.empId)}>
                      Ver vacunación
                    </button>
                  </td>
                </tr>
              );
            })}
            {alerts.length === 0 && (
              <tr><td colSpan={8} className="muted" style={{ textAlign: 'center', padding: 24, fontSize: 12.5 }}>No hay alertas de vacunación en este momento.</td></tr>
            )}
          </tbody>
        </table>
      </div>

      {viewingEmp && (
        <EmpVacunacionViewModal employee={viewingEmp} onClose={() => setViewingId(null)} onSaveDose={onSaveDose} />
      )}
    </div>
  );
};

// ─── Section: Profesiograma ──────────────────────────────
// Borrador inicial construido a partir de la matriz IPVR ya cargada por
// cargo (window.CARGOS, componente Cargos en Configuración). Pendiente
// de validación por el equipo de SST: exámenes, vacunas y restricciones
// aquí son un punto de partida, no la versión oficial.

const IPVR_LABELS = {
  'térmico-alto':         { label: 'Temperaturas altas',              categoria: 'Físico',      tone: 'blue' },
  'ruido':                { label: 'Ruido',                           categoria: 'Físico',      tone: 'blue' },
  'gas-GLP':               { label: 'Gas GLP',                        categoria: 'Químico',     tone: 'amber' },
  'polvo-orgánico':        { label: 'Material particulado orgánico',  categoria: 'Químico',     tone: 'amber' },
  'químico':               { label: 'Sustancias químicas',            categoria: 'Químico',     tone: 'amber' },
  'biológico':             { label: 'Agentes biológicos',             categoria: 'Biológico',   tone: 'rose' },
  'ergonómico':            { label: 'Carga postural',                 categoria: 'Ergonómico',  tone: 'green' },
  'ergonómico-repetitivo': { label: 'Movimientos repetitivos',        categoria: 'Ergonómico',  tone: 'green' },
  'manipulación-cargas':   { label: 'Manipulación manual de cargas',  categoria: 'Ergonómico',  tone: 'green' },
  'administrativo':        { label: 'Carga mental administrativa',    categoria: 'Psicosocial', tone: 'navy-soft' },
  'datos-personales':      { label: 'Manejo de información sensible', categoria: 'Psicosocial', tone: 'navy-soft' },
  'liderazgo-equipos':     { label: 'Liderazgo de equipos',           categoria: 'Psicosocial', tone: 'navy-soft' },
  'fatiga':                { label: 'Fatiga por jornada extendida',   categoria: 'Psicosocial', tone: 'navy-soft' },
  'mecánico':              { label: 'Riesgo mecánico',                categoria: 'Seguridad',   tone: 'navy' },
  'alturas':               { label: 'Trabajo en alturas',             categoria: 'Seguridad',   tone: 'navy' },
  'eléctrico':             { label: 'Riesgo eléctrico',               categoria: 'Seguridad',   tone: 'navy' },
  'espacios-confinados':   { label: 'Espacios confinados',            categoria: 'Seguridad',   tone: 'navy' },
  'LOTO':                  { label: 'Bloqueo y etiquetado (LOTO)',    categoria: 'Seguridad',   tone: 'navy' },
  'vial':                  { label: 'Riesgo vial',                    categoria: 'Seguridad',   tone: 'navy' },
  'emergencias':           { label: 'Atención de emergencias',        categoria: 'Seguridad',   tone: 'navy' },
  'rescate':               { label: 'Rescate y salvamento',           categoria: 'Seguridad',   tone: 'navy' },
  'fuego-incipiente':      { label: 'Control de fuego incipiente',    categoria: 'Seguridad',   tone: 'navy' },
};

const NIVEL_LABEL_PROF = { operativo: 'Operativo', liderazgo: 'Liderazgo', técnico: 'Técnico', directivo: 'Directivo', voluntario: 'Voluntario' };

const PROFESIOGRAMAS_SEED = [
  {
    cargoId: 'CGO-001',
    descripcion: 'Recibe, inspecciona y clasifica los residuos que ingresan a la línea de producción según su categoría, en contacto directo con maquinaria de clasificación y bajo exposición a ruido y calor de planta.',
    exigenciasFisicas: ['Bipedestación prolongada', 'Movimientos repetitivos de manos y brazos', 'Manejo ocasional de cargas hasta 15 kg', 'Exposición sostenida a ruido y temperatura elevada'],
    examenes: [
      { nombre: 'Examen médico osteomuscular', periodicidad: 'Ingreso, periódico (anual) y egreso', origen: 'Base — Res. 2346/2007' },
      { nombre: 'Audiometría', periodicidad: 'Ingreso y anual', origen: 'Ruido' },
      { nombre: 'Espirometría', periodicidad: 'Ingreso y anual', origen: 'Material particulado / gas GLP' },
      { nombre: 'Optometría / visiometría', periodicidad: 'Ingreso y anual', origen: 'Base' },
      { nombre: 'Evaluación cardiovascular básica', periodicidad: 'Ingreso', origen: 'Temperaturas altas' },
    ],
    vacunas: ['Tétanos', 'Hepatitis B'],
    restricciones: 'No apto para personas con hipoacusia no compensada, asma o EPOC no controlada, ni patología osteomuscular lumbar activa.',
    eppAsociado: ['Guantes térmicos Kevlar 350°C', 'Botas dieléctricas con puntera', 'Casco industrial clase E', 'Protector auditivo copa 25 dB'],
  },
  {
    cargoId: 'CGO-002',
    descripcion: 'Opera equipos de planta y apoya el proceso productivo, con exposición a maquinaria en movimiento, ruido constante y contacto ocasional con material biológico.',
    exigenciasFisicas: ['Bipedestación prolongada', 'Movimientos repetitivos', 'Manejo de cargas hasta 12 kg', 'Coordinación motriz fina'],
    examenes: [
      { nombre: 'Examen médico osteomuscular', periodicidad: 'Ingreso, periódico y egreso', origen: 'Base' },
      { nombre: 'Audiometría', periodicidad: 'Ingreso y anual', origen: 'Ruido' },
      { nombre: 'Perfil serológico (Hepatitis B)', periodicidad: 'Ingreso', origen: 'Agentes biológicos' },
      { nombre: 'Evaluación osteomuscular de miembro superior', periodicidad: 'Anual', origen: 'Carga postural / repetitividad' },
    ],
    vacunas: ['Tétanos', 'Hepatitis B'],
    restricciones: 'No apta para personas con alteraciones auditivas severas no compensadas ni patologías osteomusculares activas de miembro superior.',
    eppAsociado: ['Guantes de nitrilo', 'Botas de seguridad', 'Protector auditivo tipo copa', 'Tapabocas quirúrgico'],
  },
  {
    cargoId: 'CGO-003',
    descripcion: 'Ejecuta labores de separación, limpieza y empaque de material aprovechable, con movimientos repetitivos y exposición a agentes biológicos propios del manejo de residuos.',
    exigenciasFisicas: ['Movimientos repetitivos de manos', 'Bipedestación prolongada', 'Manejo de cargas hasta 10 kg'],
    examenes: [
      { nombre: 'Examen médico osteomuscular', periodicidad: 'Ingreso, periódico y egreso', origen: 'Base' },
      { nombre: 'Perfil serológico (Hepatitis B)', periodicidad: 'Ingreso', origen: 'Agentes biológicos' },
      { nombre: 'Evaluación osteomuscular de miembro superior', periodicidad: 'Anual', origen: 'Movimientos repetitivos' },
    ],
    vacunas: ['Tétanos', 'Hepatitis B'],
    restricciones: 'No apto para personas con dermatitis crónica de manos ni síndrome de túnel carpiano activo.',
    eppAsociado: ['Guantes de nitrilo calibre reforzado', 'Tapabocas N95', 'Botas de seguridad', 'Delantal impermeable'],
  },
  {
    cargoId: 'CGO-004',
    descripcion: 'Lidera el equipo operativo de la línea de aprovechamiento, combinando supervisión en planta con exposición ocasional a los mismos riesgos biológicos y ergonómicos de su equipo a cargo.',
    exigenciasFisicas: ['Desplazamiento constante en planta', 'Manejo ocasional de cargas', 'Capacidad de gestión de equipos bajo presión'],
    examenes: [
      { nombre: 'Examen médico osteomuscular', periodicidad: 'Ingreso, periódico y egreso', origen: 'Base' },
      { nombre: 'Perfil serológico (Hepatitis B)', periodicidad: 'Ingreso', origen: 'Agentes biológicos' },
      { nombre: 'Evaluación de riesgo psicosocial', periodicidad: 'Anual', origen: 'Liderazgo de equipos' },
    ],
    vacunas: ['Tétanos', 'Hepatitis B'],
    restricciones: 'Sin restricciones específicas adicionales a las del cargo operativo que supervisa.',
    eppAsociado: ['Guantes de nitrilo', 'Botas de seguridad', 'Chaleco de identificación'],
  },
  {
    cargoId: 'CGO-005',
    descripcion: 'Realiza inspecciones de calidad por muestreo sobre el material clasificado y aprovechado, con manipulación de muestras y reactivos de laboratorio básico.',
    exigenciasFisicas: ['Bipedestación y sedestación alternada', 'Precisión manual y visual', 'Manejo ocasional de reactivos químicos'],
    examenes: [
      { nombre: 'Examen médico osteomuscular', periodicidad: 'Ingreso, periódico y egreso', origen: 'Base' },
      { nombre: 'Perfil serológico (Hepatitis B)', periodicidad: 'Ingreso', origen: 'Agentes biológicos' },
      { nombre: 'Espirometría', periodicidad: 'Ingreso y anual', origen: 'Sustancias químicas' },
      { nombre: 'Optometría', periodicidad: 'Ingreso y anual', origen: 'Base' },
    ],
    vacunas: ['Tétanos', 'Hepatitis B'],
    restricciones: 'No apto para personas con alergias respiratorias severas a compuestos químicos de laboratorio.',
    eppAsociado: ['Guantes de nitrilo', 'Gafas de seguridad', 'Bata de laboratorio', 'Tapabocas N95'],
  },
  {
    cargoId: 'CGO-006',
    descripcion: 'Ejecuta mantenimiento preventivo y correctivo de la maquinaria industrial, con exposición a trabajo en alturas, energías peligrosas y espacios confinados.',
    exigenciasFisicas: ['Aptitud para trabajo en alturas (Res. 4272)', 'Fuerza y destreza manual', 'Tolerancia a espacios reducidos', 'Buen equilibrio y coordinación'],
    examenes: [
      { nombre: 'Examen médico osteomuscular', periodicidad: 'Ingreso, periódico y egreso', origen: 'Base' },
      { nombre: 'Examen de aptitud para trabajo en alturas', periodicidad: 'Ingreso y anual', origen: 'Trabajo en alturas' },
      { nombre: 'Audiometría', periodicidad: 'Ingreso y anual', origen: 'Riesgo mecánico' },
      { nombre: 'Evaluación cardiovascular', periodicidad: 'Ingreso y anual', origen: 'Riesgo eléctrico / espacios confinados' },
      { nombre: 'Prueba vestibular (equilibrio)', periodicidad: 'Ingreso', origen: 'Trabajo en alturas' },
    ],
    vacunas: ['Tétanos'],
    restricciones: 'No apto para personas con vértigo, crisis convulsivas o patología cardiovascular no controlada. Contraindicado en espacios confinados para personas con claustrofobia diagnosticada.',
    eppAsociado: ['Arnés certificado de cuerpo entero', 'Casco con barbuquejo', 'Guantes dieléctricos', 'Detector de gases portátil'],
  },
  {
    cargoId: 'CGO-007',
    descripcion: 'Gestiona el proceso de compras y relacionamiento con proveedores desde labores administrativas de oficina, con manejo de información comercial sensible.',
    exigenciasFisicas: ['Trabajo prolongado frente a pantalla', 'Postura sedente prolongada'],
    examenes: [
      { nombre: 'Examen médico osteomuscular', periodicidad: 'Ingreso y periódico', origen: 'Base' },
      { nombre: 'Optometría', periodicidad: 'Ingreso y anual', origen: 'Trabajo prolongado en pantalla' },
      { nombre: 'Evaluación de riesgo psicosocial', periodicidad: 'Anual', origen: 'Carga mental administrativa' },
    ],
    vacunas: ['Tétanos'],
    restricciones: 'Sin restricciones específicas para el cargo.',
    eppAsociado: ['Ninguno — cargo administrativo sin exposición operativa directa'],
  },
  {
    cargoId: 'CGO-008',
    descripcion: 'Dirige la gestión humana de la organización, con manejo de información confidencial de colaboradores y responsabilidad de liderazgo sobre múltiples equipos.',
    exigenciasFisicas: ['Trabajo prolongado frente a pantalla', 'Alta exigencia de comunicación y gestión de conflictos'],
    examenes: [
      { nombre: 'Examen médico osteomuscular', periodicidad: 'Ingreso y periódico', origen: 'Base' },
      { nombre: 'Optometría', periodicidad: 'Ingreso y anual', origen: 'Trabajo prolongado en pantalla' },
      { nombre: 'Evaluación de riesgo psicosocial', periodicidad: 'Anual', origen: 'Liderazgo de equipos / información sensible' },
    ],
    vacunas: ['Tétanos'],
    restricciones: 'Sin restricciones específicas para el cargo.',
    eppAsociado: ['Ninguno — cargo administrativo sin exposición operativa directa'],
  },
  {
    cargoId: 'CGO-009',
    descripcion: 'Conduce los vehículos de recolección cumpliendo las rutas asignadas, con exposición a riesgo vial, jornadas extendidas y manipulación de cargas durante el cargue/descargue.',
    exigenciasFisicas: ['Agudeza visual y auditiva dentro de rango permitido', 'Tiempos de reacción adecuados', 'Manejo de cargas hasta 20 kg', 'Tolerancia a jornadas prolongadas al volante'],
    examenes: [
      { nombre: 'Examen médico osteomuscular', periodicidad: 'Ingreso, periódico y egreso', origen: 'Base' },
      { nombre: 'Optometría (visión y percepción de profundidad/color)', periodicidad: 'Ingreso y anual', origen: 'Riesgo vial' },
      { nombre: 'Audiometría', periodicidad: 'Ingreso y anual', origen: 'Riesgo vial' },
      { nombre: 'Prueba de aptitud psicofísica para conducción', periodicidad: 'Ingreso y anual', origen: 'Riesgo vial / fatiga' },
      { nombre: 'Prueba de alcoholimetría', periodicidad: 'Ingreso y aleatoria', origen: 'Riesgo vial' },
    ],
    vacunas: ['Tétanos'],
    restricciones: 'No apto para personas con epilepsia no controlada, alteraciones visuales no corregibles, o dependencia a sustancias psicoactivas.',
    eppAsociado: ['Chaleco reflectivo', 'Guantes de carga', 'Botas de seguridad', 'Botiquín y kit de carretera en el vehículo'],
  },
  {
    cargoId: 'CGO-010',
    descripcion: 'Rol voluntario adicional al cargo base: responde a emergencias, apoya labores de rescate y control de fuego incipiente durante simulacros y eventos reales.',
    exigenciasFisicas: ['Buena condición física y cardiovascular', 'Capacidad de esfuerzo físico intenso de corta duración', 'Tolerancia al estrés en situaciones de emergencia'],
    examenes: [
      { nombre: 'Examen médico osteomuscular', periodicidad: 'Ingreso y anual', origen: 'Base' },
      { nombre: 'Prueba de esfuerzo cardiovascular', periodicidad: 'Ingreso y anual', origen: 'Atención de emergencias / rescate' },
      { nombre: 'Evaluación de riesgo psicosocial', periodicidad: 'Anual', origen: 'Manejo de estrés agudo' },
    ],
    vacunas: ['Tétanos', 'Hepatitis B'],
    restricciones: 'No apto para personas con patología cardiovascular no controlada, asma severa o limitaciones físicas que impidan el uso de equipo de rescate.',
    eppAsociado: ['Traje de bombero estructural', 'Casco de bombero', 'Equipo de respiración autónoma (ERA)', 'Guantes ignífugos'],
  },
];

const getProfesiograma = (cargoId) => PROFESIOGRAMAS_SEED.find(p => p.cargoId === cargoId);

const PROFESIOGRAMA_TABS = [
  ['identificacion', 'Identificación',           'IconInfo'],
  ['riesgos',        'Factores de riesgo',       'IconAlert'],
  ['examenes',       'Exámenes y vacunación',    'IconShield'],
  ['restricciones',  'Restricciones y EPP',      'IconShirt'],
];

const ProfesiogramaModal = ({ cargo, perfil, onClose }) => {
  const [tab, setTab] = _sst2_useState('identificacion');

  React.useEffect(() => {
    document.body.style.overflow = 'hidden';
    const onEsc = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onEsc);
    return () => { document.body.style.overflow = ''; window.removeEventListener('keydown', onEsc); };
  }, []);

  const riesgosPorCategoria = _sst2_useMemo(() => {
    const groups = {};
    (cargo.riesgosIPVR || []).forEach(code => {
      const meta = IPVR_LABELS[code] || { label: code, categoria: 'Otro', tone: 'navy' };
      if (!groups[meta.categoria]) groups[meta.categoria] = [];
      groups[meta.categoria].push({ code, ...meta });
    });
    return groups;
  }, [cargo]);

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal cf-mx-modal" style={{ maxWidth: 780, height: 'calc(100vh - 64px)' }}>
        <div className="modal-head cf-mx-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>{cargo.id}</div>
            <div className="modal-title">Profesiograma · {cargo.nombre}</div>
            <div className="modal-sub">{cargo.area} · {cargo.headcount} colaboradores con este cargo</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>

        <div className="cf-mx-tabs">
          {PROFESIOGRAMA_TABS.map(([k, l, ic]) => {
            const I = window[ic];
            return (
              <button key={k} className={`cf-mx-tab ${tab === k ? 'active' : ''}`} onClick={() => setTab(k)}>
                <I size={14} /> {l}
              </button>
            );
          })}
        </div>

        <div className="modal-body cf-mx-body">
          {tab === 'identificacion' && (
            <div>
              <div className="furat-row" style={{ marginBottom: 16 }}>
                <label className="furat-label">Descripción general del cargo</label>
                <p style={{ fontSize: 13, lineHeight: 1.6, margin: 0 }}>{perfil.descripcion}</p>
              </div>
              <div className="furat-row">
                <label className="furat-label">Exigencias físicas del cargo</label>
                <ul style={{ margin: 0, paddingLeft: 18, fontSize: 13, lineHeight: 1.8 }}>
                  {perfil.exigenciasFisicas.map((x, i) => <li key={i}>{x}</li>)}
                </ul>
              </div>
            </div>
          )}

          {tab === 'riesgos' && (
            <div>
              <p className="muted" style={{ fontSize: 12.5, marginTop: 0, marginBottom: 14 }}>
                Factores de riesgo tomados de la matriz IPVR registrada para este cargo en el módulo <b>Cargos</b>.
              </p>
              {Object.keys(riesgosPorCategoria).length === 0
                ? <div className="muted" style={{ fontSize: 12.5 }}>Sin riesgos IPVR registrados para este cargo.</div>
                : Object.entries(riesgosPorCategoria).map(([categoria, items]) => (
                  <div key={categoria} style={{ marginBottom: 16 }}>
                    <div className="muted-xs" style={{ marginBottom: 6 }}>{categoria.toUpperCase()}</div>
                    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                      {items.map(item => (
                        <span key={item.code} className={`pill ${item.tone}`} style={{ fontSize: 11.5 }}>{item.label}</span>
                      ))}
                    </div>
                  </div>
                ))}
            </div>
          )}

          {tab === 'examenes' && (
            <div>
              <div className="doc-list-card" style={{ marginBottom: 18 }}>
                <table className="doc-table">
                  <thead>
                    <tr>
                      <th>Examen</th>
                      <th>Periodicidad</th>
                      <th>Motivado por</th>
                    </tr>
                  </thead>
                  <tbody>
                    {perfil.examenes.map((ex, i) => (
                      <tr key={i}>
                        <td style={{ fontWeight: 600, fontSize: 13 }}>{ex.nombre}</td>
                        <td className="muted" style={{ fontSize: 12.5 }}>{ex.periodicidad}</td>
                        <td><span className="pill navy-soft" style={{ fontSize: 11 }}>{ex.origen}</span></td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
              <div className="furat-row">
                <label className="furat-label">Esquema de vacunación requerido</label>
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                  {perfil.vacunas.map((v, i) => <span key={i} className="pill green" style={{ fontSize: 11.5 }}>{v}</span>)}
                </div>
              </div>
            </div>
          )}

          {tab === 'restricciones' && (
            <div>
              <div className="furat-row" style={{ marginBottom: 16 }}>
                <label className="furat-label">Restricciones y contraindicaciones médicas</label>
                <div className="sst-restr" style={{ background: 'var(--rose-100)' }}>
                  <IconAlert size={13} />
                  <span>{perfil.restricciones}</span>
                </div>
              </div>
              <div className="furat-row">
                <label className="furat-label">EPP asociado al cargo</label>
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                  {perfil.eppAsociado.map((e, i) => <span key={i} className="pill navy" style={{ fontSize: 11.5 }}>{e}</span>)}
                </div>
              </div>
            </div>
          )}
        </div>

        <div className="modal-foot">
          <span className="pill amber-soft" style={{ marginRight: 'auto' }}>Pendiente de validación por SST</span>
          <button className="btn" onClick={onClose}>Cerrar</button>
        </div>
      </div>
    </div>
  );
};

const ProfesiogramaSection2 = () => {
  const [openCargoId, setOpenCargoId] = _sst2_useState(null);
  const cargos = window.CARGOS || [];
  const open = openCargoId ? cargos.find(c => c.id === openCargoId) : null;
  const openPerfil = openCargoId ? getProfesiograma(openCargoId) : null;

  return (
    <>
      <div className="sst-restr" style={{ marginBottom: 16, background: '#FEF9C3', borderColor: 'transparent' }}>
        <IconInfo size={13} />
        <span>
          Contenido base generado a partir de la matriz IPVR por cargo (módulo <b>Cargos</b>, en Configuración). <b>Pendiente de validación por el equipo de SST</b> antes de publicarse como versión oficial.
        </span>
      </div>

      <div className="doc-list-card">
        <table className="doc-table">
          <thead>
            <tr>
              <th>Cargo</th>
              <th>Área</th>
              <th>Nivel</th>
              <th style={{ textAlign: 'center' }}>Riesgos IPVR</th>
              <th style={{ textAlign: 'center' }}>Exámenes requeridos</th>
              <th>Estado</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {cargos.map(c => {
              const perfil = getProfesiograma(c.id);
              if (!perfil) return null;
              return (
                <tr key={c.id}>
                  <td style={{ fontWeight: 600, fontSize: 13 }}>{c.nombre}</td>
                  <td className="muted" style={{ fontSize: 12.5 }}>{c.area}</td>
                  <td><span className="pill navy-soft" style={{ fontSize: 11 }}>{NIVEL_LABEL_PROF[c.nivel] || c.nivel}</span></td>
                  <td style={{ textAlign: 'center', fontFamily: 'JetBrains Mono', fontSize: 13, fontWeight: 700 }}>{(c.riesgosIPVR || []).length}</td>
                  <td style={{ textAlign: 'center', fontFamily: 'JetBrains Mono', fontSize: 13, fontWeight: 700 }}>{perfil.examenes.length}</td>
                  <td><span className="pill amber-soft">Pendiente validación SST</span></td>
                  <td>
                    <button className="icon-action" title="Ver profesiograma" onClick={() => setOpenCargoId(c.id)}><IconExternal size={14} /></button>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {open && openPerfil && (
        <ProfesiogramaModal cargo={open} perfil={openPerfil} onClose={() => setOpenCargoId(null)} />
      )}
    </>
  );
};

window.SSTSaludOcupacional = SSTSaludOcupacional;
