// Training module — plans + catalog + course detail + certificate
const { useState: _tr_useState, useMemo: _tr_useMemo } = React;

// ─── Mock data ────────────────────────────────────────────────

const TR_CATS = {
  sst:        { label: 'SST',         tone: 'rose',  icon: 'IconShield' },
  tecnico:    { label: 'Técnico',     tone: 'blue',  icon: 'IconZap' },
  normativo:  { label: 'Normativo',   tone: 'navy',  icon: 'IconBook' },
  liderazgo:  { label: 'Liderazgo',   tone: 'amber', icon: 'IconStar' },
};

const TR_MODES = {
  presencial:        { label: 'Presencial',          icon: 'IconUsers' },
  virtual:           { label: 'Virtual',             icon: 'IconExternal' },
  elearning:         { label: 'E-learning interno',  icon: 'IconBook' },
  'elearning-externo': { label: 'E-learning externo (proveedor)', icon: 'IconExternal' },
};

// Plataformas e-learning de terceros soportadas (Fase E.3)
const PLATAFORMAS_ELEARNING = [
  { id: 'sena-sofia',     label: 'SENA · SOFIA Plus',          web: 'https://oferta.senasofiaplus.edu.co' },
  { id: 'arl-sura',       label: 'ARL Sura · Aula virtual',    web: 'https://www.arlsura.com' },
  { id: 'coursera',       label: 'Coursera Business',          web: 'https://www.coursera.org' },
  { id: 'udemy',          label: 'Udemy Business',             web: 'https://business.udemy.com' },
  { id: 'lms-proveedor',  label: 'Plataforma propia del proveedor', web: '' },
];

// Hidratación · garantiza campos status/version/edicionData (Fase E.1)
const hydrateCourse = (c) => ({
  status: 'publicado',
  version: 'v1.0',
  changelog: 'Versión inicial publicada',
  publicadoEn: '01/01/2026',
  publicadoPor: 'Carolina Restrepo · Jefe RRHH',
  modulos: c.modulos || (c.syllabus || []).map((s, i) => ({
    id: `mod-${c.id}-${i}`,
    nombre: s.split(' · ')[0] || s,
    duracion: s.split(' · ')[1] || '',
    materiales: [],
  })),
  ...c,
});

const COURSES = [
  {
    id: 'c-01', name: 'Manejo seguro de maquinaria de clasificación',
    cat: 'sst', mode: 'presencial', duration: '8 h', mandatory: true,
    provider: 'ARL Sura · Carlos Fernando Vélez', minScore: 80,
    competenciaId: 'CMP-01', normaOrigen: 'Resolución 0312 de 2019 · SG-SST', proveedorId: 'PRV-001',
    enrolled: 142, completed: 118, rating: 4.7,
    forRoles: ['Operario de Clasificación', 'Líder de Aprovechamiento', 'Téc. Mantenimiento'],
    description: 'Curso obligatorio para personal que opera o supervisa máquinas trituradoras. Cubre identificación de peligros mecánicos y térmicos, bloqueo y etiquetado (LOTO), uso correcto de EPP térmico y procedimiento de parada de emergencia.',
    syllabus: [
      'Anatomía de la trituradora industrial · 1.5 h',
      'Identificación de riesgos mecánicos y térmicos · 1.5 h',
      'Procedimiento LOTO (Lock-out Tag-out) · 2 h',
      'EPP específico para zona de clasificación · 1 h',
      'Simulacro de parada de emergencia · 2 h',
    ],
    sessions: [
      { date: '12/04/2026', site: 'Cali · Aula 2', instructor: 'C. F. Vélez', enrolled: 18, passed: 17, status: 'completada' },
      { date: '08/03/2026', site: 'Barranquilla',        instructor: 'C. F. Vélez', enrolled: 12, passed: 12, status: 'completada' },
      { date: '14/02/2026', site: 'Cali · Aula 1', instructor: 'C. F. Vélez', enrolled: 22, passed: 20, status: 'completada' },
    ],
    upcoming: [
      { name: 'Andrés Felipe Mejía', initials: 'AM', role: 'Operario de Clasificación',   site: 'Cali',  scheduled: '14/05/2026' },
      { name: 'Carlos Andrés Vélez', initials: 'CV', role: 'Operario de Clasificación',   site: 'Cali',  scheduled: '14/05/2026' },
      { name: 'Paula Valencia Ríos', initials: 'PV', role: 'Téc. Mantenimiento',    site: 'Cali',  scheduled: '14/05/2026' },
      { name: 'Luis Miguel Marín',   initials: 'LM', role: 'Líder de Aprovechamiento',      site: 'Cali',  scheduled: '21/05/2026' },
    ],
  },
  {
    id: 'c-02', name: 'Buenas Prácticas de Manufactura (BPM)',
    cat: 'normativo', mode: 'elearning', duration: '4 h', mandatory: true,
    provider: 'INVIMA · Plataforma e-learning interna', minScore: 75,
    competenciaId: 'CMP-02', normaOrigen: 'Resolución 2674 de 2013 · INVIMA', proveedorId: 'PRV-005',
    enrolled: 847, completed: 712, rating: 4.4,
    forRoles: ['Operario de Clasificación', 'Op. Aprovechamiento', 'Aux. Calidad', 'Líder de Aprovechamiento'],
    description: 'Curso normativo INVIMA obligatorio para todo personal que tiene contacto con producto. Higiene personal, manipulación, control de plagas, trazabilidad.',
    syllabus: [
      'Marco normativo Resolución 2674 de 2013 · 0.5 h',
      'Higiene personal y uniforme · 0.5 h',
      'Buenas prácticas en zona de proceso · 1 h',
      'Limpieza y desinfección · 1 h',
      'Evaluación final · 1 h',
    ],
    sessions: [
      { date: '01/05/2026', site: 'E-learning', instructor: 'Plataforma', enrolled: 28, passed: 26, status: 'en-curso' },
      { date: '01/04/2026', site: 'E-learning', instructor: 'Plataforma', enrolled: 64, passed: 61, status: 'completada' },
    ],
    upcoming: [
      { name: 'María Fernanda López', initials: 'ML', role: 'Op. Aprovechamiento',      site: 'Cali',   scheduled: 'En curso' },
      { name: 'Laura Gómez Restrepo', initials: 'LG', role: 'Operaria de Planta', site: 'Cali', scheduled: 'En curso' },
      { name: 'Juan David Ruiz',      initials: 'JR', role: 'Aux. Calidad',     site: 'Barranquilla', scheduled: 'En curso' },
    ],
  },
  {
    id: 'c-03', name: 'Brigada de emergencias y primeros auxilios',
    cat: 'sst', mode: 'presencial', duration: '16 h', mandatory: false,
    provider: 'ARL Sura · Defensa Civil', minScore: 80,
    competenciaId: 'CMP-05', normaOrigen: 'Decreto 1072 · Brigada SG-SST', proveedorId: 'PRV-001',
    enrolled: 38, completed: 32, rating: 4.9,
    forRoles: ['Brigadistas voluntarios'],
    description: 'Formación de brigadistas internos en evacuación, primeros auxilios básicos, control de incendios incipientes y rescate.',
    syllabus: [
      'Plan de emergencias de la planta · 2 h',
      'Primeros auxilios · 6 h',
      'Control de fuego incipiente · 4 h',
      'Evacuación y rescate · 4 h',
    ],
    sessions: [
      { date: '20/03/2026', site: 'Cali', instructor: 'Defensa Civil', enrolled: 14, passed: 14, status: 'completada' },
    ],
    upcoming: [],
  },
  {
    id: 'c-04', name: 'Clasificación avanzada de residuos',
    cat: 'tecnico', mode: 'presencial', duration: '12 h', mandatory: false,
    provider: 'Consultor ambiental · Gabriel Alejandro Marín (Gestor ambiental)', minScore: 70,
    competenciaId: 'CMP-07', normaOrigen: 'Estándar ambiental Gestor ambiental', proveedorId: 'PRV-003',
    enrolled: 24, completed: 19, rating: 4.8,
    forRoles: ['Operario de Clasificación', 'Líder de Aprovechamiento'],
    description: 'Curso técnico de caracterización de residuos, curva del proceso, control de olores y análisis de laboratorio profesional.',
    syllabus: [
      'Química del material entrante y proceso de clasificación · 3 h',
      'Lectura de perfil en software de trituradora · 3 h',
      'Cupping protocolar ISO 14001 · 4 h',
      'Defectos de clasificación y corrección · 2 h',
    ],
    sessions: [
      { date: '15/04/2026', site: 'Cali', instructor: 'G. Marín', enrolled: 8, passed: 7, status: 'completada' },
    ],
    upcoming: [
      { name: 'Carlos Andrés Vélez', initials: 'CV', role: 'Operario de Clasificación', site: 'Cali', scheduled: '28/05/2026' },
    ],
  },
  {
    id: 'c-05', name: 'Reglamento Interno de Trabajo · Reforma Laboral 2025',
    cat: 'normativo', mode: 'elearning', duration: '2 h', mandatory: true,
    provider: 'Carolina Restrepo · RRHH interno', minScore: 70,
    competenciaId: 'CMP-06', normaOrigen: 'CST · Reforma Laboral Ley 2466 de 2025', proveedorId: 'PRV-008',
    enrolled: 847, completed: 768, rating: 4.1,
    forRoles: ['Todos los cargos'],
    description: 'Recorrido por el RIT actualizado conforme a la Reforma Laboral 2025. Conducta, jornada, sanciones, conducto regular.',
    syllabus: [
      'Estructura del RIT · 0.25 h',
      'Cambios por Reforma Laboral 2025 · 0.75 h',
      'Conducto regular y sanciones · 0.5 h',
      'Evaluación · 0.5 h',
    ],
    sessions: [
      { date: '10/02/2026', site: 'E-learning', instructor: 'C. Restrepo', enrolled: 847, passed: 768, status: 'completada' },
    ],
    upcoming: [],
  },
  {
    id: 'c-06', name: 'Liderazgo de equipos operativos',
    cat: 'liderazgo', mode: 'virtual', duration: '20 h', mandatory: false,
    provider: 'Universidad EAFIT · Diplomado virtual', minScore: 75,
    competenciaId: 'CMP-08', normaOrigen: 'Diplomado EAFIT', proveedorId: 'PRV-004',
    enrolled: 8, completed: 5, rating: 4.6,
    forRoles: ['Líder de Aprovechamiento', 'Coord. Compras', 'Jefe de RRHH'],
    description: 'Diplomado virtual sobre liderazgo situacional, manejo de conflictos, retroalimentación efectiva y liderazgo en piso de planta.',
    syllabus: [
      'Liderazgo situacional · 5 h',
      'Comunicación asertiva · 5 h',
      'Manejo de conflictos · 5 h',
      'Coaching de desempeño · 5 h',
    ],
    sessions: [
      { date: '01/03/2026', site: 'Virtual · Zoom + LMS', instructor: 'EAFIT', enrolled: 8, passed: 5, status: 'en-curso' },
    ],
    upcoming: [],
  },
  {
    id: 'c-07', name: 'Manipulación de alimentos',
    cat: 'sst', mode: 'elearning', duration: '3 h', mandatory: true,
    provider: 'Secretaría de Salud Valle del Cauca', minScore: 70,
    competenciaId: 'CMP-03', normaOrigen: 'Resolución 2674 · Sec. Salud Valle del Cauca', proveedorId: 'PRV-006',
    enrolled: 412, completed: 389, rating: 4.3,
    forRoles: ['Op. Aprovechamiento', 'Aux. Calidad', 'Aux. Calidad'],
    description: 'Curso obligatorio para personal en contacto con producto. Certificación municipal con vigencia anual.',
    syllabus: [
      'Microbiología básica · 0.5 h',
      'ETAs y prevención · 1 h',
      'Higiene personal y locativa · 1 h',
      'Evaluación · 0.5 h',
    ],
    sessions: [
      { date: '10/01/2026', site: 'E-learning', instructor: 'Sec. Salud', enrolled: 412, passed: 389, status: 'completada' },
    ],
    upcoming: [],
  },
  {
    id: 'c-08', name: 'Trabajo en alturas',
    cat: 'sst', mode: 'presencial', duration: '40 h', mandatory: false,
    provider: 'CCS · Consejo Colombiano de Seguridad', minScore: 85,
    competenciaId: 'CMP-04', normaOrigen: 'Resolución 1409 de 2012 · CCS', proveedorId: 'PRV-003',
    enrolled: 12, completed: 9, rating: 4.8,
    forRoles: ['Téc. Mantenimiento'],
    description: 'Curso avanzado certificable para trabajos sobre 1.5 m. Resolución 1409 de 2012.',
    syllabus: [
      'Marco normativo · 4 h',
      'Equipos de protección anticaídas · 8 h',
      'Sistemas de acceso y posicionamiento · 14 h',
      'Práctica en torre · 12 h',
      'Evaluación · 2 h',
    ],
    sessions: [
      { date: '14/03/2026', site: 'Cali · Centro CCS', instructor: 'CCS', enrolled: 5, passed: 4, status: 'completada' },
    ],
    upcoming: [
      { name: 'Paula Valencia Ríos', initials: 'PV', role: 'Téc. Mantenimiento', site: 'Cali', scheduled: '04/06/2026' },
    ],
  },
];

// Per-employee plan rows
const PLANS = [
  {
    id: 'E0247', initials: 'AM', name: 'Andrés Felipe Mejía',  role: 'Operario de Clasificación', area: 'Operaciones',     site: 'Cali',
    assigned: 6, completed: 1, inProgress: 2, pending: 3,
    nextDue: { course: 'BPM',                     date: '14/05/2026', urgent: true,  daysLeft: 9 },
  },
  {
    id: 'E0246', initials: 'LG', name: 'Laura Gómez Restrepo', role: 'Operaria de Planta',  area: 'Operaciones',     site: 'Cali',
    assigned: 5, completed: 0, inProgress: 3, pending: 2,
    nextDue: { course: 'Manipulación de alimentos', date: '12/05/2026', urgent: true, daysLeft: 7 },
  },
  {
    id: 'E0205', initials: 'CV', name: 'Carlos Andrés Vélez',  role: 'Operario de Clasificación', area: 'Operaciones',     site: 'Cali',
    assigned: 8, completed: 5, inProgress: 1, pending: 2,
    nextDue: { course: 'Manejo seguro de maquinaria', date: '14/05/2026', urgent: true, daysLeft: 9 },
  },
  {
    id: 'E0198', initials: 'MF', name: 'María Fernanda López', role: 'Op. Aprovechamiento',          area: 'Aprovechamiento',        site: 'Cali',
    assigned: 5, completed: 4, inProgress: 1, pending: 0,
    nextDue: { course: 'BPM (en curso)',            date: '15/05/2026', urgent: false, daysLeft: 10 },
  },
  {
    id: 'E0177', initials: 'JP', name: 'Jorge Iván Patiño',     role: 'Conductor',           area: 'Recolección',   site: 'Barranquilla',
    assigned: 4, completed: 4, inProgress: 0, pending: 0,
    nextDue: { course: 'Renovación licencia categoría', date: '12/08/2026', urgent: false, daysLeft: 99 },
  },
  {
    id: 'E0156', initials: 'PV', name: 'Paula Valencia Ríos',   role: 'Téc. Mantenimiento',  area: 'Mantenimiento',  site: 'Cali',
    assigned: 7, completed: 5, inProgress: 1, pending: 1,
    nextDue: { course: 'Trabajo en alturas',         date: '04/06/2026', urgent: false, daysLeft: 30 },
  },
  {
    id: 'E0142', initials: 'DT', name: 'Diego Andrés Toro',     role: 'Aux. Aprovechamiento',        area: 'Aprovechamiento',        site: 'Cali',
    assigned: 5, completed: 3, inProgress: 0, pending: 2,
    nextDue: { course: 'BPM',                       date: '20/05/2026', urgent: false, daysLeft: 15 },
  },
  {
    id: 'E0128', initials: 'NC', name: 'Nicolás Cárdenas',      role: 'Conductor',           area: 'Recolección',   site: 'Barranquilla',
    assigned: 4, completed: 4, inProgress: 0, pending: 0,
    nextDue: null,
  },
  {
    id: 'E0094', initials: 'MT', name: 'María Trujillo Henao',  role: 'Aux. RRHH',           area: 'Administración', site: 'Cali',
    assigned: 3, completed: 3, inProgress: 0, pending: 0,
    nextDue: null,
  },
  {
    id: 'E0067', initials: 'LM', name: 'Luis Miguel Marín',     role: 'Líder de Aprovechamiento',    area: 'Aprovechamiento',        site: 'Cali',
    assigned: 9, completed: 6, inProgress: 2, pending: 1,
    nextDue: { course: 'Liderazgo de equipos',       date: '01/06/2026', urgent: false, daysLeft: 27 },
  },
  {
    id: 'E0023', initials: 'CR', name: 'Carolina Restrepo S.',  role: 'Jefe de RRHH',        area: 'Administración', site: 'Cali',
    assigned: 6, completed: 6, inProgress: 0, pending: 0,
    nextDue: null,
  },
];

// ─── Root component ─────────────────────────────────────────

// Arquitectura de información aprobada — 6 dominios, navegación secundaria
// dentro de cada uno. Resumen no tiene subnav (es una portada). Configuración
// no se muestra para jefe/nuevo — ver Training() más abajo.
const TR_DOMAINS = [
  { id: 'resumen', label: 'Resumen' },
  { id: 'induccion', label: 'Inducción' },
  { id: 'cargo', label: 'Entrenamiento al cargo' },
  { id: 'interna', label: 'Capacitación interna' },
  { id: 'externa', label: 'Capacitación externa' },
  { id: 'config', label: 'Configuración' },
];
const TR_SUBNAV = {
  induccion: [{ id: 'seguimiento', label: 'Seguimiento de inducción' }, { id: 'reinduccion', label: 'Reinducción' }],
  cargo: [
    { id: 'matriz-cargo', label: 'Matriz por cargo' },
    { id: 'ejecutados', label: 'Entrenamientos ejecutados' },
    { id: 'reentrenamientos', label: 'Reentrenamientos' },
    { id: 'ghfo24', label: 'Formato GH-FO-24 V7' },
    { id: 'plataformas', label: 'Plataformas digitales actuales' },
  ],
  interna: [
    { id: 'programa', label: 'Programa anual' },
    { id: 'seguimiento-personas', label: 'Seguimiento por personas' },
    { id: 'cursos-sesiones', label: 'Cursos y sesiones actuales' },
  ],
  externa: [{ id: 'solicitudes', label: 'Solicitudes' }, { id: 'seguimiento-costos', label: 'Seguimiento y costos' }],
  config: [
    { id: 'capacitograma', label: 'Capacitograma' },
    { id: 'catalogo', label: 'Catálogo actual' },
    { id: 'matriz-competencias', label: 'Matriz de competencias actual' },
    { id: 'competencias', label: 'Competencias' },
    { id: 'proveedores', label: 'Proveedores' },
    { id: 'bitacora', label: 'Bitácora' },
  ],
};

// Feedback simulado no bloqueante — reemplaza alert() en todo el módulo.
const TrToast = ({ message }) => !message ? null : (
  <div className="tr-toast" role="status" aria-live="polite"><IconCheck size={14} /> {message}</div>
);

const Training = ({ currentRole = 'admin' }) => {
  const [domain, setDomain] = _tr_useState('resumen');
  const [subTab, setSubTab] = _tr_useState('seguimiento');
  const [toastMsg, setToastMsg] = _tr_useState(null);
  const toastTimerRef = React.useRef(null);
  const toast = (msg) => {
    setToastMsg(msg);
    clearTimeout(toastTimerRef.current);
    toastTimerRef.current = setTimeout(() => setToastMsg(null), 3200);
  };
  React.useEffect(() => () => clearTimeout(toastTimerRef.current), []);

  const [course, setCourse] = _tr_useState(null);
  const [certFor, setCertFor] = _tr_useState(null);
  const [captureFor, setCaptureFor] = _tr_useState(null);
  const [auditOpen, setAuditOpen] = _tr_useState(false);
  const [planModalOpen, setPlanModalOpen] = _tr_useState(false);
  const [sessionModalOpen, setSessionModalOpen] = _tr_useState(false);
  const [sessionsTick, setSessionsTick] = _tr_useState(0);
  const [editingCourse, setEditingCourse] = _tr_useState(null);
  const [coursesState, setCoursesState] = _tr_useState(() => COURSES.map(hydrateCourse));
  const [cursosSesionesView, setCursosSesionesView] = _tr_useState('sesiones');
  const [programaView, setProgramaView] = _tr_useState('programa'); // 'programa' | 'validacion' (solo admin)

  // Mantener window.COURSES sincronizado para el resto de módulos
  React.useEffect(() => { window.COURSES = coursesState; }, [coursesState]);

  const saveCourse = (data) => {
    const updated = data.id && coursesState.some(c => c.id === data.id);
    if (updated) {
      setCoursesState(coursesState.map(c => c.id === data.id ? { ...c, ...data } : c));
    } else {
      const nextId = data.id || `c-${String(coursesState.length + 1).padStart(2, '0')}`;
      setCoursesState([...coursesState, { ...data, id: nextId }]);
    }
    setEditingCourse(null);
  };

  const goTo = (d, s) => { setDomain(d); setSubTab(s || ((TR_SUBNAV[d] || [{ id: null }])[0].id)); };

  // Colaborador ('nuevo'): vista personal simple — sin dominios, sin
  // configuración, sin información financiera. Ver TrPersonalView.
  if (currentRole === 'nuevo') {
    return (
      <div className="main" data-screen-label="Formación y desarrollo">
        <TrPersonalView empId="E0247" />
        <TrToast message={toastMsg} />
      </div>
    );
  }

  const domains = currentRole === 'admin' ? TR_DOMAINS : TR_DOMAINS.filter(d => d.id !== 'config');
  const subnavActual = TR_SUBNAV[domain] || [];

  return (
    <div className="main" data-screen-label="Formación y desarrollo">
      <div className="page-head">
        <div>
          <h1 className="page-title">Formación y desarrollo</h1>
          <div className="page-subtitle">
            {currentRole === 'jefe'
              ? <b>Formación de tu equipo · vista de Jefe</b>
              : <><b>Plan formativo Atica</b> · prototipo navegable para validación con Gestión Humana</>}
          </div>
        </div>
        {currentRole === 'admin' && (
          <button className="btn" onClick={() => setAuditOpen(true)}><IconShield size={14} /> Modo Auditoría</button>
        )}
      </div>

      <div className="doc-tabs">
        {domains.map(d => (
          <button key={d.id} className={`doc-tab ${domain === d.id ? 'active' : ''}`} onClick={() => goTo(d.id)}>{d.label}</button>
        ))}
      </div>

      {subnavActual.length > 0 && (
        <div className="seg-pill tr-subnav" role="tablist" aria-label={(TR_DOMAINS.find(d => d.id === domain) || {}).label}>
          {subnavActual.map(s => (
            <button key={s.id} role="tab" aria-selected={subTab === s.id} className={`seg-pill-btn ${subTab === s.id ? 'active' : ''}`} onClick={() => setSubTab(s.id)}>{s.label}</button>
          ))}
        </div>
      )}

      {domain === 'resumen' && <TrOverviewTab onNavigate={goTo} currentRole={currentRole} />}

      {domain === 'induccion' && subTab === 'seguimiento' && <TrInductionTracking currentRole={currentRole} toast={toast} />}
      {domain === 'induccion' && subTab === 'reinduccion' && <TrReinduction currentRole={currentRole} toast={toast} />}

      {domain === 'cargo' && subTab === 'matriz-cargo' && <TrJobMatrix toast={toast} />}
      {domain === 'cargo' && subTab === 'ejecutados' && <TrJobExecuted currentRole={currentRole} toast={toast} />}
      {domain === 'cargo' && subTab === 'reentrenamientos' && <TrRetraining currentRole={currentRole} toast={toast} />}
      {domain === 'cargo' && subTab === 'ghfo24' && <TrGhFo24 currentRole={currentRole} toast={toast} />}
      {domain === 'cargo' && subTab === 'plataformas' && <EntrenamientoTab currentRole={currentRole} />}

      {domain === 'interna' && subTab === 'programa' && (
        <div>
          {currentRole === 'admin' && (
            <div className="seg-pill" style={{ marginBottom: 14 }}>
              <button className={`seg-pill-btn ${programaView === 'programa' ? 'active' : ''}`} onClick={() => setProgramaView('programa')}>Programa anual</button>
              <button className={`seg-pill-btn ${programaView === 'validacion' ? 'active' : ''}`} onClick={() => setProgramaView('validacion')}>Validación GH</button>
            </div>
          )}
          {(currentRole !== 'admin' || programaView === 'programa')
            ? <TrAnnualProgram currentRole={currentRole} toast={toast} />
            : <TrInternalValidation toast={toast} />}
        </div>
      )}
      {domain === 'interna' && subTab === 'seguimiento-personas' && <TrInternalTracking currentRole={currentRole} toast={toast} />}
      {domain === 'interna' && subTab === 'cursos-sesiones' && (
        <div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, justifyContent: 'space-between', marginBottom: 14 }}>
            <div className="seg-pill">
              <button className={`seg-pill-btn ${cursosSesionesView === 'sesiones' ? 'active' : ''}`} onClick={() => setCursosSesionesView('sesiones')}>
                Sesiones <span className="epp-tab-pill rose" style={{ marginLeft: 4 }}>{(window.SESSIONS_SCHED || []).filter(s => s.state === 'programada').length}</span>
              </button>
              <button className={`seg-pill-btn ${cursosSesionesView === 'planes' ? 'active' : ''}`} onClick={() => setCursosSesionesView('planes')}>
                Planes <span className="epp-tab-pill" style={{ marginLeft: 4 }}>{(window.PLANES_FORMATIVOS || []).filter(p => p.estado === 'activo').length}</span>
              </button>
            </div>
            <div style={{ display: 'flex', gap: 8 }}>
              <button className="btn" onClick={() => setSessionModalOpen(true)}><IconRocket size={14} /> Programar sesión</button>
              <button className="btn primary" onClick={() => setPlanModalOpen(true)}><IconPlus size={14} /> Nuevo plan formativo</button>
            </div>
          </div>
          {cursosSesionesView === 'sesiones'
            ? <SesionesTab key={sessionsTick} onCapture={(s) => setCaptureFor(s)} onProgramar={() => setSessionModalOpen(true)} />
            : <PlanesTab onProgramarSesion={(planId) => setSessionModalOpen(planId || true)} onNuevoPlan={() => setPlanModalOpen(true)} />}
        </div>
      )}

      {domain === 'externa' && subTab === 'solicitudes' && <TrExternalRequests currentRole={currentRole} toast={toast} />}
      {domain === 'externa' && subTab === 'seguimiento-costos' && <TrExternalTracking currentRole={currentRole} toast={toast} />}

      {domain === 'config' && subTab === 'capacitograma' && <TrCapacitogram toast={toast} />}
      {domain === 'config' && subTab === 'catalogo' && (
        <CatalogTab
          courses={coursesState}
          onOpen={(c) => setCourse(c)}
          onEdit={(c) => setEditingCourse(c)}
          onNew={() => setEditingCourse('nuevo')}
          onNewExterno={() => setEditingCourse('externo')}
        />
      )}
      {domain === 'config' && subTab === 'matriz-competencias' && <MatrizTab />}
      {domain === 'config' && subTab === 'competencias' && <CompetenciasTab />}
      {domain === 'config' && subTab === 'proveedores' && <ProveedoresTab />}
      {domain === 'config' && subTab === 'bitacora' && <BitacoraTab currentRole={currentRole} />}

      {course     && <CourseDetailPanel course={course} onClose={() => setCourse(null)} onCert={() => { setCertFor(course); }} onEdit={() => { setEditingCourse(course); setCourse(null); }} />}
      {certFor    && <CertificateModal course={certFor} onClose={() => setCertFor(null)} />}
      {captureFor && <SessionCapture session={captureFor} onClose={() => setCaptureFor(null)} />}
      {auditOpen  && <AuditoriaModal onClose={() => setAuditOpen(false)} />}
      {editingCourse && (
        <CursoEditorModal
          course={editingCourse === 'nuevo' ? null : editingCourse}
          onClose={() => setEditingCourse(null)}
          onSave={saveCourse}
        />
      )}
      {planModalOpen && (
        <NuevoPlanModal
          onClose={() => setPlanModalOpen(false)}
          onCreated={(plan) => {
            window.PLANES_FORMATIVOS = [...(window.PLANES_FORMATIVOS || []), plan];
            setPlanModalOpen(false);
            goTo('interna', 'cursos-sesiones');
            setCursosSesionesView('planes');
            toast('Plan formativo creado');
          }}
        />
      )}
      {sessionModalOpen && (
        <NuevaSesionModal
          presetPlanId={typeof sessionModalOpen === 'string' ? sessionModalOpen : null}
          onClose={() => setSessionModalOpen(false)}
          onCreated={(sesion) => {
            window.SESSIONS_SCHED = [...(window.SESSIONS_SCHED || []), sesion];
            setSessionsTick(t => t + 1);
            setSessionModalOpen(false);
            goTo('interna', 'cursos-sesiones');
            setCursosSesionesView('sesiones');
            toast('Sesión programada');
          }}
        />
      )}

      <TrToast message={toastMsg} />
    </div>
  );
};

// ─── Tab 1: Plans ──────────────────────────────────────────

const PlansTab = ({ onCertSample = () => {} }) => {
  const [filterArea, setFilterArea]       = _tr_useState('todas');
  const [filterRole, setFilterRole]       = _tr_useState('todos');
  const [filterCompl, setFilterCompl]     = _tr_useState('todos');
  const [filterStatus, setFilterStatus]   = _tr_useState('todos');

  const areas = _tr_useMemo(() => Array.from(new Set(PLANS.map(p => p.area))), []);
  const roles = _tr_useMemo(() => Array.from(new Set(PLANS.map(p => p.role))), []);

  const rows = PLANS.filter(p => {
    if (filterArea !== 'todas' && p.area !== filterArea) return false;
    if (filterRole !== 'todos' && p.role !== filterRole) return false;
    const pct = p.assigned ? Math.round((p.completed / p.assigned) * 100) : 0;
    if (filterCompl === 'low'    && pct >= 50)            return false;
    if (filterCompl === 'medium' && (pct < 50 || pct > 80)) return false;
    if (filterCompl === 'high'   && pct <= 80)            return false;
    if (filterStatus === 'urgent' && !(p.nextDue && p.nextDue.urgent)) return false;
    if (filterStatus === 'complete' && p.pending !== 0)   return false;
    return true;
  });

  return (
    <>
      <div className="ob-toolbar" style={{ marginBottom: 14 }}>
        <div className="ob-search">
          <IconSearch size={15} />
          <input placeholder="Buscar por colaborador o cargo…" />
        </div>
        <select value={filterArea} onChange={e => setFilterArea(e.target.value)}>
          <option value="todas">Todas las áreas</option>
          {areas.map(a => <option key={a}>{a}</option>)}
        </select>
        <select value={filterRole} onChange={e => setFilterRole(e.target.value)}>
          <option value="todos">Todos los cargos</option>
          {roles.map(r => <option key={r}>{r}</option>)}
        </select>
        <select value={filterCompl} onChange={e => setFilterCompl(e.target.value)}>
          <option value="todos">Cumplimiento: cualquiera</option>
          <option value="low">&lt; 50%</option>
          <option value="medium">50% – 80%</option>
          <option value="high">&gt; 80%</option>
        </select>
        <select value={filterStatus} onChange={e => setFilterStatus(e.target.value)}>
          <option value="todos">Estado del plan</option>
          <option value="urgent">Con vencimiento urgente</option>
          <option value="complete">Plan al día</option>
        </select>
      </div>

      <div className="doc-list-card">
        <table className="doc-table tr-plan-table">
          <thead>
            <tr>
              <th>Colaborador</th>
              <th>Cargo</th>
              <th style={{ textAlign: 'center' }}>Asignados</th>
              <th>Estado del plan</th>
              <th>Cumplimiento</th>
              <th>Próximo vencimiento</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {rows.map(p => {
              const pct = p.assigned ? Math.round((p.completed / p.assigned) * 100) : 0;
              const tone = pct >= 80 ? 'green' : pct >= 50 ? 'amber' : 'rose';
              return (
                <tr key={p.id}>
                  <td>
                    <div className="doc-cell-emp">
                      <div className="doc-avatar">{p.initials}</div>
                      <div>
                        <div style={{ fontWeight: 600, fontSize: 13 }}>{p.name}</div>
                        <div className="muted mono" style={{ fontSize: 11 }}>{p.id} · {p.site}</div>
                      </div>
                    </div>
                  </td>
                  <td className="muted" style={{ fontSize: 12.5 }}>{p.role}</td>
                  <td style={{ textAlign: 'center', fontWeight: 700, fontSize: 14 }}>{p.assigned}</td>
                  <td>
                    <div className="tr-plan-stats">
                      <span className="tr-plan-stat green" title="Completados"><IconCheck size={10} /> {p.completed}</span>
                      <span className="tr-plan-stat blue"  title="En progreso"><IconClock size={10} /> {p.inProgress}</span>
                      <span className="tr-plan-stat muted" title="Pendientes"><IconDot size={10} /> {p.pending}</span>
                    </div>
                  </td>
                  <td>
                    <div className="tr-prog-cell">
                      <div className="tr-prog-track">
                        <div className={`tr-prog-fill ${tone}`} style={{ width: `${pct}%` }} />
                      </div>
                      <span className={`tr-prog-pct ${tone}`}>{pct}%</span>
                    </div>
                  </td>
                  <td>
                    {p.nextDue ? (
                      <div>
                        <div style={{ fontSize: 12.5, fontWeight: 500 }}>{p.nextDue.course}</div>
                        <div className={`tr-due ${p.nextDue.urgent ? 'urgent' : 'muted'}`}>
                          {p.nextDue.urgent && <IconAlert size={11} />}
                          {p.nextDue.date} · en {p.nextDue.daysLeft} días
                        </div>
                      </div>
                    ) : <span className="muted" style={{ fontSize: 12 }}>—</span>}
                  </td>
                  <td>
                    <div className="doc-actions">
                      <button className="icon-action" title="Ver plan completo" onClick={() => onCertSample(COURSES[0])}>
                        <IconExternal size={14} />
                      </button>
                      <button className="icon-action" title="Agregar curso">
                        <IconPlus size={14} />
                      </button>
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
        <div className="doc-table-foot">
          <span className="muted" style={{ fontSize: 12 }}>Mostrando {rows.length} de 824 colaboradores con plan</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 / 75</span>
            <button className="btn" style={{ padding: '5px 9px' }}><IconChevronRight size={13} /></button>
          </div>
        </div>
      </div>
    </>
  );
};

// ─── Tab 2: Catalog ────────────────────────────────────────

const CatalogTab = ({ onOpen, onEdit, onNew, onNewExterno, courses, statusFilter = 'todos' }) => {
  const [filterCat, setFilterCat]   = _tr_useState('todas');
  const [filterMode, setFilterMode] = _tr_useState('todas');
  const [filterStatus, setFilterStatus] = _tr_useState(statusFilter);
  const [search, setSearch] = _tr_useState('');

  const list = (courses || COURSES).filter(c =>
    (filterCat === 'todas'  || c.cat  === filterCat) &&
    (filterMode === 'todas' || c.mode === filterMode) &&
    (filterStatus === 'todos' || c.status === filterStatus) &&
    (!search || c.name.toLowerCase().includes(search.toLowerCase()) || (c.provider || '').toLowerCase().includes(search.toLowerCase()))
  );

  const STATUS_META_C = {
    borrador:  { label: 'Borrador',  pill: 'amber-soft' },
    publicado: { label: 'Publicado', pill: 'green' },
    retirado:  { label: 'Retirado',  pill: 'rose' },
  };

  return (
    <>
      <div className="ob-toolbar" style={{ marginBottom: 14 }}>
        <div className="ob-search">
          <IconSearch size={15} />
          <input
            placeholder="Buscar curso por nombre o proveedor…"
            value={search}
            onChange={e => setSearch(e.target.value)}
          />
        </div>
        <select value={filterCat} onChange={e => setFilterCat(e.target.value)}>
          <option value="todas">Todas las categorías</option>
          {Object.entries(TR_CATS).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
        </select>
        <select value={filterMode} onChange={e => setFilterMode(e.target.value)}>
          <option value="todas">Todas las modalidades</option>
          {Object.entries(TR_MODES).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
        </select>
        <select value={filterStatus} onChange={e => setFilterStatus(e.target.value)}>
          <option value="todos">Todos los estados</option>
          <option value="publicado">Publicados</option>
          <option value="borrador">Borradores</option>
          <option value="retirado">Retirados</option>
        </select>
        <span className="muted" style={{ fontSize: 12, alignSelf: 'center' }}>{list.length} cursos</span>
        <div style={{ flex: 1 }} />
        {onNewExterno && (
          <button className="btn" onClick={onNewExterno} title="Vincular curso de proveedor externo (solo URL)">
            <IconExternal size={13} /> Curso de tercero
          </button>
        )}
        {onNew && (
          <button className="btn primary" onClick={onNew}>
            <IconPlus size={14} /> Nuevo curso
          </button>
        )}
      </div>

      <div className="tr-catalog">
        {list.map(c => {
          const cat = TR_CATS[c.cat];
          const mode = TR_MODES[c.mode];
          const ModeIco = window[mode.icon];
          const CatIco  = window[cat.icon];
          const statusMeta = STATUS_META_C[c.status] || STATUS_META_C.publicado;
          const pct = Math.round((c.completed / c.enrolled) * 100);
          return (
            <div key={c.id} className="tr-card" onClick={() => onOpen(c)}>
              <div className="tr-card-head">
                <span className={`tr-cat-badge ${cat.tone}`}>
                  <CatIco size={11} /> {cat.label}
                </span>
                <span className="tr-mode">
                  <ModeIco size={12} /> {mode.label}
                </span>
              </div>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 6 }}>
                <span className={`pill ${statusMeta.pill}`} style={{ fontSize: 10 }}>{statusMeta.label} · {c.version || 'v1.0'}</span>
                {onEdit && (
                  <button
                    className="icon-btn"
                    title="Editar curso"
                    onClick={(e) => { e.stopPropagation(); onEdit(c); }}
                    style={{ padding: 4 }}
                  >
                    <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M12 20h9M16.5 3.5a2.121 2.121 0 1 1 3 3L7 19l-4 1 1-4 12.5-12.5z" /></svg>
                  </button>
                )}
              </div>
              <div className="tr-card-name">{c.name}</div>
              <div className="tr-card-meta">
                <div><div className="muted-xs">Duración</div><div className="tr-card-val">{c.duration}</div></div>
                <div><div className="muted-xs">Aprobación</div><div className="tr-card-val">≥ {c.minScore}</div></div>
                <div><div className="muted-xs">Rating</div><div className="tr-card-val">★ {c.rating}</div></div>
              </div>
              <div className="tr-card-progress">
                <div className="tr-prog-track">
                  <div className="tr-prog-fill green" style={{ width: `${pct}%` }} />
                </div>
                <div className="tr-card-prog-meta">
                  <span><b>{c.completed}</b> de {c.enrolled} completados</span>
                  <span className="muted">{pct}%</span>
                </div>
              </div>
              <div className="tr-card-roles">
                <div className="muted-xs">{c.mandatory ? 'Obligatorio para' : 'Recomendado para'}</div>
                <div className="tr-role-chips">
                  {c.forRoles.slice(0, 3).map((r, i) => (
                    <span key={i} className={`tr-role-chip ${c.mandatory ? 'mand' : ''}`}>{r}</span>
                  ))}
                  {c.forRoles.length > 3 && <span className="muted" style={{ fontSize: 11 }}>+{c.forRoles.length - 3}</span>}
                </div>
              </div>
              <button className="btn" style={{ width: '100%' }}>
                <IconExternal size={13} /> Ver detalle
              </button>
            </div>
          );
        })}
      </div>
    </>
  );
};

// ─── Course detail (slide-in side panel) ───────────────────

const CourseDetailPanel = ({ course, onClose, onCert, onEdit }) => {
  const cat  = TR_CATS[course.cat];
  const mode = TR_MODES[course.mode];
  const ModeIco = window[mode.icon];

  return (
    <div className="tr-side-overlay" onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="tr-side-panel">
        <div className="tr-side-head">
          <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start', minWidth: 0 }}>
            <span className={`tr-cat-badge ${cat.tone}`} style={{ marginTop: 2 }}>{cat.label}</span>
            <div style={{ minWidth: 0 }}>
              <div className="tr-side-title">{course.name}</div>
              <div className="muted" style={{ fontSize: 12, marginTop: 4 }}>
                <ModeIco size={12} /> {mode.label} · {course.duration} · Aprobación ≥ {course.minScore}
              </div>
              <div style={{ display: 'flex', gap: 6, marginTop: 6, flexWrap: 'wrap' }}>
                <span className={`pill ${course.status === 'borrador' ? 'amber-soft' : course.status === 'retirado' ? 'rose' : 'green'}`} style={{ fontSize: 10.5 }}>
                  {course.status === 'borrador' ? 'Borrador' : course.status === 'retirado' ? 'Retirado' : 'Publicado'} · {course.version || 'v1.0'}
                </span>
                {course.competenciaId && <span className="pill navy-soft mono" style={{ fontSize: 10 }}>{course.competenciaId}</span>}
              </div>
            </div>
          </div>
          <div style={{ display: 'flex', gap: 6 }}>
            {onEdit && <button className="btn" onClick={onEdit}><IconPlus size={12} /> Editar</button>}
            <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>

        <div className="tr-side-body">

          <section className="tr-side-section">
            <div className="muted-xs">Descripción</div>
            <p style={{ margin: '6px 0 0', fontSize: 13, lineHeight: 1.55 }}>{course.description}</p>
          </section>

          <section className="tr-side-section">
            <div className="tr-side-row">
              <div><div className="muted-xs">Proveedor</div><div className="tr-side-val">{course.provider}</div></div>
              <div><div className="muted-xs">Modalidad</div><div className="tr-side-val">{mode.label}</div></div>
              <div><div className="muted-xs">Duración</div><div className="tr-side-val">{course.duration}</div></div>
              <div><div className="muted-xs">Evaluación</div><div className="tr-side-val">Sí · nota mínima {course.minScore}</div></div>
            </div>
          </section>

          <section className="tr-side-section">
            <div className="muted-xs">Temario</div>
            <ol className="tr-syllabus">
              {course.syllabus.map((s, i) => (
                <li key={i}><span className="tr-syllabus-num">{i + 1}</span><span>{s}</span></li>
              ))}
            </ol>
          </section>

          <section className="tr-side-section">
            <div className="muted-xs">Cargos {course.mandatory ? 'obligatorios' : 'recomendados'}</div>
            <div className="tr-role-chips" style={{ marginTop: 6 }}>
              {course.forRoles.map((r, i) => <span key={i} className={`tr-role-chip ${course.mandatory ? 'mand' : ''}`}>{r}</span>)}
            </div>
          </section>

          <section className="tr-side-section">
            <div className="muted-xs">Sesiones pasadas</div>
            <table className="tr-mini-table">
              <thead>
                <tr><th>Fecha</th><th>Sede</th><th>Instructor</th><th style={{ textAlign: 'right' }}>Aprobaron</th><th></th></tr>
              </thead>
              <tbody>
                {course.sessions.map((s, i) => (
                  <tr key={i}>
                    <td className="mono" style={{ fontSize: 11.5 }}>{s.date}</td>
                    <td style={{ fontSize: 12 }}>{s.site}</td>
                    <td className="muted" style={{ fontSize: 12 }}>{s.instructor}</td>
                    <td style={{ textAlign: 'right', fontSize: 12 }}><b>{s.passed}</b><span className="muted">/{s.enrolled}</span></td>
                    <td style={{ textAlign: 'right' }}>
                      <span className={`pill ${s.status === 'completada' ? 'green' : 'amber'}`} style={{ fontSize: 10.5 }}>
                        {s.status === 'completada' ? 'Completada' : 'En curso'}
                      </span>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </section>

          <section className="tr-side-section">
            <div className="muted-xs">Próximos inscritos · {course.upcoming.length}</div>
            {course.upcoming.length === 0
              ? <div className="muted" style={{ fontSize: 12.5, marginTop: 6 }}>Sin inscripciones programadas. Crea una sesión para empezar.</div>
              : (
                <div className="tr-upcoming">
                  {course.upcoming.map((u, i) => (
                    <div key={i} className="tr-upcoming-row">
                      <div className="doc-avatar">{u.initials}</div>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontWeight: 600, fontSize: 12.5 }}>{u.name}</div>
                        <div className="muted" style={{ fontSize: 11 }}>{u.role} · {u.site}</div>
                      </div>
                      <span className="mono" style={{ fontSize: 11 }}>{u.scheduled}</span>
                    </div>
                  ))}
                </div>
              )}
          </section>
        </div>

        <div className="tr-side-foot">
          <button className="btn" onClick={onCert}>
            <IconStar size={14} /> Ver certificado de muestra
          </button>
          <button className="btn primary" style={{ marginLeft: 'auto' }}>
            <IconPlus size={14} /> Crear nueva sesión
          </button>
        </div>
      </div>
    </div>
  );
};

// ─── Mock QR (CSS pixel grid) ──────────────────────────────

const MockQR = ({ size = 96 }) => {
  // 21x21 pseudo-random pattern with corner finder squares
  const grid = _tr_useMemo(() => {
    const N = 21;
    const cells = Array.from({ length: N * N }, (_, i) => {
      const r = Math.floor(i / N), c = i % N;
      // finder squares (top-left, top-right, bottom-left)
      const inFinder = (r, c, x, y) => r >= y && r < y + 7 && c >= x && c < x + 7;
      const ring = (r, c, x, y) => inFinder(r, c, x, y) && (r === y || r === y + 6 || c === x || c === x + 6 || (r >= y + 2 && r <= y + 4 && c >= x + 2 && c <= x + 4));
      if (inFinder(r, c, 0, 0))    return ring(r, c, 0, 0)    ? 1 : 0;
      if (inFinder(r, c, 14, 0))   return ring(r, c, 14, 0)   ? 1 : 0;
      if (inFinder(r, c, 0, 14))   return ring(r, c, 0, 14)   ? 1 : 0;
      // pseudo-random body
      return ((r * 31 + c * 17 + r * c) % 5) < 2 ? 1 : 0;
    });
    return cells;
  }, []);

  return (
    <div className="cert-qr" style={{ width: size, height: size, gridTemplateColumns: 'repeat(21, 1fr)', gridTemplateRows: 'repeat(21, 1fr)' }}>
      {grid.map((v, i) => <span key={i} className={v ? 'on' : ''} />)}
    </div>
  );
};

// ─── Certificate modal ─────────────────────────────────────

const CertificateModal = ({ course, onClose }) => {
  const sample = {
    name: 'Andrés Felipe Mejía Restrepo',
    doc:  'CC 1.087.456.231',
    date: '12 de abril de 2026',
    score: 92,
    code: `CERT-2026-${course.id.toUpperCase()}-04821`,
    hash: 'a4f2c1e89b7d3f5e26c8d4b1a9f3e7c5d8b2a4f6e9c1d3b5a7f8e0c2d4b6a9f1',
    issuer: 'Carolina Restrepo Salazar',
    issuerRole: 'Jefe de Recursos Humanos · Atica S.A.S.',
  };

  return (
    <div className="modal-overlay" onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal cert-modal" style={{ maxWidth: 980 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">Vista previa del certificado</div>
            <div className="modal-sub">Se genera automáticamente al aprobar el curso. Verificable en línea por código y hash.</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="cert-stage">
          <div className="cert-sheet">
            <div className="cert-watermark">a</div>

            <div className="cert-head">
              <div className="cert-logo">
                <div className="cert-logo-mark">i</div>
                <div>
                  <div style={{ fontWeight: 700, fontSize: 12, letterSpacing: '0.04em' }}>ATICA SOMOS</div>
                  <div className="cert-logo-sub">Plataforma de gestión humana</div>
                </div>
              </div>
              <div className="cert-divider" />
              <div className="cert-logo cert-logo-client">
                <div className="cert-logo-mark client">a</div>
                <div>
                  <div style={{ fontWeight: 700, fontSize: 12, letterSpacing: '0.04em' }}>ATICA</div>
                  <div className="cert-logo-sub">NIT 900.123.456-7 · Cali</div>
                </div>
              </div>
            </div>

            <div className="cert-body">
              <div className="cert-eyebrow">Certificado de capacitación</div>
              <div className="cert-pre">Hace constar que</div>
              <h1 className="cert-name">{sample.name}</h1>
              <div className="cert-doc">identificado(a) con {sample.doc}</div>
              <div className="cert-pre">completó satisfactoriamente el curso</div>
              <h2 className="cert-course">«{course.name}»</h2>
              <div className="cert-meta">
                <div><div className="cert-meta-lbl">Duración</div><div className="cert-meta-val">{course.duration}</div></div>
                <div><div className="cert-meta-lbl">Calificación</div><div className="cert-meta-val">{sample.score} / 100</div></div>
                <div><div className="cert-meta-lbl">Modalidad</div><div className="cert-meta-val">{TR_MODES[course.mode].label}</div></div>
                <div><div className="cert-meta-lbl">Proveedor</div><div className="cert-meta-val" style={{ fontSize: 11 }}>{course.provider.split(' · ')[0]}</div></div>
              </div>

              <div className="cert-foot">
                <div className="cert-sign">
                  <div className="cert-sign-line">
                    <span className="cert-sign-mark">Carolina Restrepo</span>
                  </div>
                  <div className="cert-sign-name">{sample.issuer}</div>
                  <div className="cert-sign-role">{sample.issuerRole}</div>
                </div>
                <div className="cert-meta-side">
                  <div className="cert-date">Cali, {sample.date}</div>
                  <div className="cert-code mono">{sample.code}</div>
                  <div className="cert-hash mono">SHA-256 · {sample.hash.slice(0, 16)}…{sample.hash.slice(-8)}</div>
                </div>
                <div className="cert-qr-wrap">
                  <MockQR size={88} />
                  <div className="cert-qr-cap mono">verifica.atica.co/{sample.code.slice(-8)}</div>
                </div>
              </div>
            </div>
          </div>
        </div>

        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cerrar</button>
          <a className="btn" href="HCM%20Atica%20Verificar%20Certificado.html" target="_blank" rel="noopener" style={{ textDecoration: 'none' }}>
            <IconShield size={14} /> Vista pública del verificador
          </a>
          <button className="btn"><IconExternal size={14} /> Descargar PDF</button>
          <button className="btn primary"><IconMegaphone size={14} /> Enviar al colaborador</button>
        </div>
      </div>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════
// Modo Auditoría · Fase D
// Filtra certificados emitidos (interno + externo) por cargo / norma /
// colaborador / período. Devuelve el expediente listo para auditoría
// INVIMA / MinTrabajo / ICONTEC.
// ═══════════════════════════════════════════════════════════

const AuditoriaModal = ({ onClose }) => {
  const [cargo, setCargo]     = _tr_useState('todos');
  const [norma, setNorma]     = _tr_useState('todas');
  const [search, setSearch]   = _tr_useState('');
  const [origen, setOrigen]   = _tr_useState('todos');
  const [from, setFrom]       = _tr_useState('');
  const [to, setTo]           = _tr_useState('');
  const [expanded, setExpanded] = _tr_useState({});

  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 certs = window.CERTIFICATES || [];

  // Catálogos para filtros
  const cargos = Array.from(new Set(certs.map(c => c.emp?.cargo).filter(Boolean))).sort();
  const normas = Array.from(new Set(certs.map(c => c.competencia?.norma).filter(Boolean))).sort();

  const parseFecha = (s) => {
    if (!s) return null;
    const [d, m, y] = s.split('/').map(Number);
    if (!d) return null;
    return new Date(y, m - 1, d);
  };

  const filtered = certs.filter(c => {
    if (cargo !== 'todos' && c.emp?.cargo !== cargo) return false;
    if (norma !== 'todas' && c.competencia?.norma !== norma) return false;
    if (origen !== 'todos' && c.origen !== origen) return false;
    if (search) {
      const s = search.toLowerCase();
      if (!(c.emp?.name?.toLowerCase().includes(s) || c.code.toLowerCase().includes(s))) return false;
    }
    if (from || to) {
      const fEmit = parseFecha(c.session?.date);
      if (from) {
        const fFrom = parseFecha(from);
        if (fFrom && fEmit && fEmit < fFrom) return false;
      }
      if (to) {
        const fTo = parseFecha(to);
        if (fTo && fEmit && fEmit > fTo) return false;
      }
    }
    return true;
  });

  const toggle = (code) => setExpanded(s => ({ ...s, [code]: !s[code] }));

  // Totales
  const totalInternos = filtered.filter(c => c.origen !== 'externo').length;
  const totalExternos = filtered.filter(c => c.origen === 'externo').length;

  const exportar = () => {
    alert(`Exportación simulada · ${filtered.length} certificados\n\nEn operaciones esto descargará un ZIP con: PDFs + lista por sesión + metadata CSV + soportes de idoneidad de proveedores.`);
  };

  const verPublico = (code) => {
    // Abre el verificador público en nueva pestaña con el código preseleccionado
    window.open(`HCM Atica Verificar Certificado.html?codigo=${encodeURIComponent(code)}`, '_blank');
  };

  return (
    <div className="modal-overlay" onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 1100, height: 'calc(100vh - 64px)' }}>
        <div className="modal-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>Modo Auditoría · INVIMA · MinTrabajo · ICONTEC</div>
            <div className="modal-title">Expediente para auditoría</div>
            <div className="modal-sub">
              Filtra los certificados emitidos por cargo, norma, colaborador o período. El export contiene PDFs + evidencias + soportes de idoneidad listos para entregar al auditor.
            </div>
          </div>
          <button className="icon-btn" onClick={onClose}><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 tr-audit-modal-body">
          <div className="tr-audit-filters">
            <label>
              Cargo
              <select value={cargo} onChange={e => setCargo(e.target.value)}>
                <option value="todos">Todos</option>
                {cargos.map(c => <option key={c}>{c}</option>)}
              </select>
            </label>
            <label>
              Norma origen
              <select value={norma} onChange={e => setNorma(e.target.value)}>
                <option value="todas">Todas</option>
                {normas.map(n => <option key={n}>{n}</option>)}
              </select>
            </label>
            <label>
              Origen
              <select value={origen} onChange={e => setOrigen(e.target.value)}>
                <option value="todos">Todos</option>
                <option value="interno">Interno (Atica)</option>
                <option value="externo">Externo (proveedor)</option>
              </select>
            </label>
            <label>
              Colaborador / Código
              <input type="text" placeholder="Nombre o CERT-…" value={search} onChange={e => setSearch(e.target.value)} />
            </label>
            <label>
              Desde (DD/MM/AAAA)
              <input type="text" placeholder="01/01/2026" value={from} onChange={e => setFrom(e.target.value)} />
            </label>
            <label>
              Hasta (DD/MM/AAAA)
              <input type="text" placeholder="06/05/2026" value={to} onChange={e => setTo(e.target.value)} />
            </label>
          </div>

          {/* Resumen */}
          <div style={{ display: 'flex', gap: 14, alignItems: 'center', flexWrap: 'wrap' }}>
            <div>
              <span style={{ fontSize: 22, fontWeight: 700 }}>{filtered.length}</span>
              <span className="muted" style={{ fontSize: 12.5, marginLeft: 6 }}>certificados encontrados</span>
            </div>
            <span className="pill green">{totalInternos} internos</span>
            <span className="pill navy">{totalExternos} externos</span>
            <div style={{ flex: 1 }} />
            <button className="btn primary" onClick={exportar}>
              <IconDoc size={13} /> Exportar expediente · ZIP
            </button>
          </div>

          {/* Lista */}
          {filtered.length === 0 && (
            <div className="muted" style={{ fontSize: 13, padding: 22, textAlign: 'center', background: 'var(--surface)', borderRadius: 10 }}>
              No hay certificados que cumplan los filtros. Ajusta los criterios o cierra una sesión nueva en <b>Sesiones</b> para verla aquí.
            </div>
          )}

          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            {filtered.map(c => {
              const exp = !!expanded[c.code];
              return (
                <div key={c.code} className={`tr-audit-row ${exp ? 'expanded' : ''}`} onClick={() => toggle(c.code)}>
                  {!exp ? (
                    <>
                      <span className="mono" style={{ fontSize: 11.5, fontWeight: 600 }}>{c.code}</span>
                      <div>
                        <div style={{ fontWeight: 600, fontSize: 12.5 }}>{c.emp?.name}</div>
                        <div className="muted" style={{ fontSize: 11.5 }}>{c.emp?.cargo}</div>
                      </div>
                      <div>
                        <div style={{ fontSize: 12 }}>{c.competencia?.name}</div>
                        <div className="muted" style={{ fontSize: 10.5 }}>{c.competencia?.norma}</div>
                      </div>
                      <span className={`pill ${c.origen === 'externo' ? 'navy' : 'green'}`} style={{ fontSize: 10.5 }}>
                        {c.origen === 'externo' ? 'Externo' : 'Interno'}
                      </span>
                      <span className="mono" style={{ fontSize: 11.5 }}>{c.session?.date}</span>
                      <span className="muted mono" style={{ fontSize: 10.5 }}>← detalle</span>
                    </>
                  ) : (
                    <div>
                      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12 }}>
                        <div>
                          <div className="mono" style={{ fontSize: 11.5, fontWeight: 600 }}>{c.code}</div>
                          <div style={{ fontSize: 14, fontWeight: 700, marginTop: 4 }}>{c.emp?.name} · {c.competencia?.name}</div>
                          <div className="muted" style={{ fontSize: 11.5 }}>{c.competencia?.norma}</div>
                        </div>
                        <div style={{ display: 'flex', gap: 6 }}>
                          <button className="btn" onClick={(e) => { e.stopPropagation(); verPublico(c.code); }}>
                            <IconExternal size={13} /> Ver verificador público
                          </button>
                          <span className={`pill ${c.origen === 'externo' ? 'navy' : 'green'}`} style={{ fontSize: 10.5 }}>
                            {c.origen === 'externo' ? 'Emitido por proveedor externo' : 'Emitido internamente'}
                          </span>
                        </div>
                      </div>

                      <div className="tr-audit-detail">
                        <div>
                          <div className="muted-xs">Sesión</div>
                          <div className="mono" style={{ fontSize: 12 }}>{c.session?.id} · {c.session?.date}</div>
                          <div className="muted" style={{ fontSize: 11 }}>{c.session?.site}</div>
                        </div>
                        <div>
                          <div className="muted-xs">Instructor</div>
                          <div style={{ fontSize: 12 }}>{c.session?.instructor}</div>
                          <div className="muted" style={{ fontSize: 11 }}>{c.session?.instructorOrg}</div>
                        </div>
                        <div>
                          <div className="muted-xs">Vigencia</div>
                          <div className="mono" style={{ fontSize: 12 }}>{c.vigencia?.from} → {c.vigencia?.to}</div>
                        </div>
                        <div>
                          <div className="muted-xs">Resultado</div>
                          <div className="mono" style={{ fontSize: 12 }}>
                            {c.result?.score !== null ? `${c.result?.score}/100 (mín. ${c.result?.minScore})` : 'Aprobado por proveedor'}
                          </div>
                        </div>
                      </div>

                      <div style={{ marginTop: 10 }}>
                        <div className="muted-xs" style={{ marginBottom: 6 }}>Cadena de evidencia</div>
                        <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                          <div className={`tr-audit-evidence-row ${c.evidence?.attendanceSigned || c.origen === 'externo' ? 'ok' : 'miss'}`}>
                            <IconCheck size={12} /> Asistencia: {c.evidence?.attendanceMethod}
                          </div>
                          <div className={`tr-audit-evidence-row ${c.evidence?.evaluationApplied ? 'ok' : 'miss'}`}>
                            <IconCheck size={12} /> Evaluación: {c.evidence?.evaluationApplied ? `aplicada (${c.evidence?.evaluationQuestions || '—'} preguntas)` : 'pendiente'}
                          </div>
                          <div className="tr-audit-evidence-row ok">
                            <IconDoc size={12} /> Evidencias adjuntas: {c.evidence?.evidencesCount} · {(c.evidence?.evidencesList || []).join(' · ')}
                          </div>
                          {c.hash && (
                            <div className="tr-audit-evidence-row ok">
                              <IconShield size={12} /> Hash SHA-256: <span className="mono" style={{ fontSize: 10 }}>{c.hash.slice(0, 32)}…</span>
                            </div>
                          )}
                          {!c.hash && c.origen === 'externo' && (
                            <div className="tr-audit-evidence-row ok">
                              <IconShield size={12} /> PDF original del proveedor archivado
                            </div>
                          )}
                        </div>
                      </div>
                    </div>
                  )}
                </div>
              );
            })}
          </div>

          <div className="ic-cap-info">
            <IconShield size={13} />
            <span>
              El expediente cumple con los requisitos probatorios de Resolución 0312 / Decreto 1072 (SST), Resolución 2674 (BPM INVIMA) e ICONTEC ISO 9001 cap. 7.2.
              Soporta firma electrónica Ley 527 de 1999 para certificados internos.
            </span>
          </div>
        </div>
      </div>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════
// Nuevo plan formativo · stepper de 4 pasos
// Crea una sesión real (visible en pestaña Sesiones) con inscritos
// determinados por audiencia (cargo · área · selección manual).
// ═══════════════════════════════════════════════════════════

const NuevoPlanModal = ({ onClose, onCreated }) => {
  const [step, setStep] = _tr_useState(1);
  // Step 1 · qué (multi-curso)
  const [nombre, setNombre] = _tr_useState('');
  const [descripcion, setDescripcion] = _tr_useState('');
  const [cursosIds, setCursosIds] = _tr_useState([]);
  // Step 2 · a quién
  const [audMode, setAudMode]   = _tr_useState('cargo');
  const [audCargos, setAudCargos] = _tr_useState([]);
  const [audAreas, setAudAreas]   = _tr_useState([]);
  const [audManual, setAudManual] = _tr_useState([]);
  // Step 3 · período + recurrencia
  const [vigenciaFrom, setVigenciaFrom] = _tr_useState('');
  const [vigenciaTo, setVigenciaTo] = _tr_useState('');
  const [tipoPlan, setTipoPlan] = _tr_useState('puntual');
  const [frecuencia, setFrecuencia] = _tr_useState('una-vez');

  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 courses = (window.COURSES || COURSES).filter(c => !c.status || c.status === 'publicado');
  const cargos  = (window.CARGOS || []);
  const cargosNombres = cargos.map(c => c.nombre);
  const areas   = Array.from(new Set(cargos.map(c => c.area)));
  const empleadosPool = PLANS;

  const cursosSeleccionados = courses.filter(c => cursosIds.includes(c.id));

  // Resolución de la audiencia (preview · cuántos colaboradores quedan en el plan)
  const empleadosResueltos = (() => {
    if (audMode === 'cargo')  return empleadosPool.filter(e => audCargos.includes(e.role));
    if (audMode === 'area')   return empleadosPool.filter(e => audAreas.includes(e.area));
    if (audMode === 'manual') return empleadosPool.filter(e => audManual.includes(e.id));
    return [];
  })();

  // Cálculo de proximaRecurrencia según vigenciaTo + frecuencia
  const calcularProximaRecurrencia = () => {
    if (tipoPlan !== 'ciclico' || frecuencia === 'una-vez' || !vigenciaTo) return null;
    const meses = (window.FREQ_PLAN || {})[frecuencia]?.meses;
    if (!meses) return null;
    const [d, m, y] = vigenciaTo.split('/').map(Number);
    if (!d) return null;
    const next = new Date(y, m - 1, d);
    next.setDate(next.getDate() + 1);
    return `${String(next.getDate()).padStart(2,'0')}/${String(next.getMonth()+1).padStart(2,'0')}/${next.getFullYear()}`;
  };
  const proximaRecurrencia = calcularProximaRecurrencia();

  const stepsMeta = [
    { n: 1, label: '¿Qué?',     icon: 'IconBook' },
    { n: 2, label: '¿A quién?', icon: 'IconUsers' },
    { n: 3, label: '¿Período?', icon: 'IconClock' },
    { n: 4, label: 'Confirmar', icon: 'IconCheck' },
  ];

  const canAdvance = {
    1: !!nombre && cursosIds.length > 0,
    2: empleadosResueltos.length > 0,
    3: !!vigenciaFrom && !!vigenciaTo,
    4: true,
  };

  const toggleArr = (arr, setArr, val) => {
    setArr(arr.includes(val) ? arr.filter(x => x !== val) : [...arr, val]);
  };

  const buildAudiencia = () => {
    if (audMode === 'cargo')  return { tipo: 'cargo',      cargosNombres: audCargos };
    if (audMode === 'area')   return { tipo: 'area',       areas: audAreas };
    if (audMode === 'manual') return { tipo: 'individual', empleadosIds: audManual };
    return { tipo: 'cargo', cargosNombres: [] };
  };

  const crearPlan = () => {
    const newId = `PLAN-${new Date().getFullYear()}-${Math.floor(Math.random() * 9000) + 1000}`;
    const nuevoPlan = {
      id: newId,
      nombre,
      descripcion,
      tipo: tipoPlan,
      frecuencia: tipoPlan === 'ciclico' ? frecuencia : 'una-vez',
      vigenciaFrom,
      vigenciaTo,
      proximaRecurrencia,
      cursosIds,
      audiencia: buildAudiencia(),
      estado: 'activo',
      creadoPor: 'Carolina Restrepo · Jefe RRHH',
      creadoEn: new Date().toLocaleDateString('es-CO'),
    };
    onCreated(nuevoPlan);
  };

  return (
    <div className="modal-overlay" onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 920, height: 'calc(100vh - 80px)' }}>
        <div className="modal-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>Plan formativo · creación manual</div>
            <div className="modal-title">Nuevo plan formativo</div>
            <div className="modal-sub">Programa una capacitación: elige el curso, define la audiencia y agenda la sesión. Se creará una entrada en <b>Sesiones</b> lista para captura el día acordado.</div>
          </div>
          <button className="icon-btn" onClick={onClose}><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="ic-cap-stepper">
          {stepsMeta.map(s => {
            const Ico = window[s.icon] || IconCheck;
            const done = step > s.n;
            const current = step === s.n;
            const cls = done ? 'done' : current ? 'current' : 'pending';
            return (
              <React.Fragment key={s.n}>
                <button className={`ic-cap-step ${cls}`} onClick={() => s.n <= step && setStep(s.n)} disabled={s.n > step}>
                  <span className="ic-cap-step-num">{done ? <IconCheck size={11} /> : s.n}</span>
                  <span className="ic-cap-step-label"><Ico size={11} /> {s.label}</span>
                </button>
                {s.n < stepsMeta.length && <div className={`ic-cap-step-line ${done ? 'done' : ''}`} />}
              </React.Fragment>
            );
          })}
        </div>

        <div className="modal-body" style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>

          {/* Step 1: ¿Qué? · nombre del plan + cursos que lo componen */}
          {step === 1 && (
            <div className="ic-cap-section">
              <h3 className="ic-cap-h3">¿Qué cursos contiene este plan?</h3>
              <p className="muted" style={{ fontSize: 13, marginTop: -4 }}>
                Un plan agrupa uno o varios cursos bajo un objetivo común. Por ejemplo, el <b>Plan Anual SG-SST</b> incluye varias capacitaciones de SST a lo largo del año.
              </p>

              <div className="ic-cap-setup-grid" style={{ marginTop: 12 }}>
                <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                  <div className="muted-xs">Nombre del plan *</div>
                  <input className="ic-cap-version" type="text" value={nombre} onChange={e => setNombre(e.target.value)} placeholder="Plan Anual SG-SST 2026" />
                </div>
                <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                  <div className="muted-xs">Descripción / objetivo</div>
                  <textarea className="ic-cap-version" rows={2} value={descripcion} onChange={e => setDescripcion(e.target.value)} placeholder="Plan obligatorio Decreto 1072 · mínimo 4 sesiones SST/año…" />
                </div>
              </div>

              <div className="muted-xs" style={{ marginTop: 14, marginBottom: 6 }}>
                Cursos del plan · {cursosIds.length} seleccionados
              </div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 10 }}>
                {courses.map(c => {
                  const cmp = (window.COMPETENCIAS_MAESTRAS || []).find(cm => cm.id === c.competenciaId);
                  const sel = cursosIds.includes(c.id);
                  return (
                    <button key={c.id} className={`ic-cap-origen-tab ${sel ? 'active' : ''}`} onClick={() => toggleArr(cursosIds, setCursosIds, c.id)} style={{ flexDirection: 'column', alignItems: 'flex-start' }}>
                      <div style={{ display: 'flex', justifyContent: 'space-between', width: '100%', alignItems: 'center' }}>
                        <span className="mono" style={{ fontSize: 10.5, opacity: 0.7 }}>{c.id} · {c.duration}</span>
                        {sel && <IconCheck size={13} />}
                      </div>
                      <div style={{ fontWeight: 700, fontSize: 13.5, marginTop: 4 }}>{c.name}</div>
                      {cmp && (
                        <div className="muted" style={{ fontSize: 11, marginTop: 2 }}>
                          {cmp.id} · {cmp.norma}
                        </div>
                      )}
                    </button>
                  );
                })}
              </div>
            </div>
          )}

          {/* Step 2: A quién */}
          {step === 2 && (
            <div className="ic-cap-section">
              <h3 className="ic-cap-h3">Define la audiencia</h3>
              <p className="muted" style={{ fontSize: 13, marginTop: -4 }}>Selecciona empleados por cargo, por área o uno a uno. Los seleccionados quedarán inscritos en la sesión.</p>

              <div style={{ display: 'flex', gap: 6, marginTop: 8, marginBottom: 14 }}>
                {[['cargo', 'Por cargo'], ['area', 'Por área'], ['manual', 'Selección manual']].map(([k, l]) => (
                  <button key={k} className={`btn ${audMode === k ? 'primary' : ''}`} onClick={() => setAudMode(k)}>{l}</button>
                ))}
              </div>

              {audMode === 'cargo' && (
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                  {cargosNombres.map(n => (
                    <button key={n} className={`pill ${audCargos.includes(n) ? 'green' : 'navy-soft'}`} style={{ cursor: 'pointer', border: 'none', fontSize: 12 }} onClick={() => toggleArr(audCargos, setAudCargos, n)}>
                      {audCargos.includes(n) && <IconCheck size={11} />} {n}
                    </button>
                  ))}
                </div>
              )}

              {audMode === 'area' && (
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                  {areas.map(a => (
                    <button key={a} className={`pill ${audAreas.includes(a) ? 'green' : 'navy-soft'}`} style={{ cursor: 'pointer', border: 'none', fontSize: 12 }} onClick={() => toggleArr(audAreas, setAudAreas, a)}>
                      {audAreas.includes(a) && <IconCheck size={11} />} {a}
                    </button>
                  ))}
                </div>
              )}

              {audMode === 'manual' && (
                <div style={{ maxHeight: 280, overflow: 'auto', border: '1px solid var(--border)', borderRadius: 8 }}>
                  {empleadosPool.map(e => {
                    const sel = audManual.includes(e.id);
                    return (
                      <label key={e.id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 12px', borderBottom: '1px solid var(--border)', cursor: 'pointer', background: sel ? '#F0FDF4' : 'white' }}>
                        <input type="checkbox" checked={sel} onChange={() => toggleArr(audManual, setAudManual, e.id)} />
                        <div className="doc-avatar" style={{ width: 28, height: 28, fontSize: 11 }}>{e.initials}</div>
                        <div style={{ flex: 1 }}>
                          <div style={{ fontWeight: 600, fontSize: 12.5 }}>{e.name}</div>
                          <div className="muted" style={{ fontSize: 11 }}>{e.role} · {e.area} · {e.site}</div>
                        </div>
                        <span className="mono muted" style={{ fontSize: 10.5 }}>{e.id}</span>
                      </label>
                    );
                  })}
                </div>
              )}

              <div className="ic-cap-info" style={{ marginTop: 14 }}>
                <IconUsers size={13} />
                <span><b>{empleadosResueltos.length}</b> colaborador{empleadosResueltos.length === 1 ? '' : 'es'} quedará{empleadosResueltos.length === 1 ? '' : 'n'} inscrito{empleadosResueltos.length === 1 ? '' : 's'} en esta sesión.</span>
              </div>
            </div>
          )}

          {/* Step 3: ¿Período? · vigencia + recurrencia */}
          {step === 3 && (
            <div className="ic-cap-section">
              <h3 className="ic-cap-h3">¿En qué período aplica el plan?</h3>
              <p className="muted" style={{ fontSize: 13, marginTop: -4 }}>
                Define la vigencia del plan y si se repite. Las sesiones concretas (fechas exactas, sede, instructor) se programan después dentro del plan, desde la pestaña <b>Sesiones</b>.
              </p>

              <div className="ic-cap-setup-grid" style={{ marginTop: 12 }}>
                <div className="ic-cap-field">
                  <div className="muted-xs">Vigente desde *</div>
                  <window.DatePickerCO
                    value={vigenciaFrom}
                    onChange={setVigenciaFrom}
                    presets={[
                      { label: 'Hoy',                compute: (t) => new Date(t) },
                      { label: 'Próx. lunes',        compute: (t) => { const d = new Date(t); const dow = d.getDay(); d.setDate(d.getDate() + (((1 - dow + 7) % 7) || 7)); return d; } },
                      { label: 'Inicio próximo mes', compute: (t) => new Date(t.getFullYear(), t.getMonth() + 1, 1) },
                    ]}
                  />
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Vigente hasta *</div>
                  <window.DatePickerCO
                    value={vigenciaTo}
                    onChange={setVigenciaTo}
                    min={vigenciaFrom}
                    presets={[
                      { label: 'Fin de mes',  compute: (t) => new Date(t.getFullYear(), t.getMonth() + 1, 0) },
                      { label: 'Fin del año', compute: (t) => new Date(t.getFullYear(), 11, 31) },
                      { label: 'En 1 año',    compute: (t) => { const d = new Date(t); d.setFullYear(d.getFullYear() + 1); return d; } },
                    ]}
                  />
                </div>
              </div>

              <h4 className="ic-cap-h3" style={{ fontSize: 13, marginTop: 18, marginBottom: 8 }}>Tipo de plan</h4>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(220px, 1fr))', gap: 8 }}>
                {Object.entries(window.TIPO_PLAN || {}).map(([k, v]) => (
                  <button key={k} className={`ic-cap-origen-tab ${tipoPlan === k ? 'active' : ''}`} onClick={() => setTipoPlan(k)} style={{ flexDirection: 'column', alignItems: 'flex-start' }}>
                    <div style={{ fontWeight: 700, fontSize: 13 }}>{v.label}</div>
                    <div className="muted" style={{ fontSize: 11.5, marginTop: 2 }}>{v.desc}</div>
                  </button>
                ))}
              </div>

              {tipoPlan === 'ciclico' && (
                <div className="ic-cap-setup-grid" style={{ marginTop: 14 }}>
                  <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                    <div className="muted-xs">Frecuencia de renovación</div>
                    <select className="ic-cap-version" value={frecuencia} onChange={e => setFrecuencia(e.target.value)}>
                      {Object.entries(window.FREQ_PLAN || {}).filter(([k]) => k !== 'una-vez').map(([k, v]) => (
                        <option key={k} value={k}>{v.label} (cada {v.meses} meses)</option>
                      ))}
                    </select>
                    {proximaRecurrencia && (
                      <div className="muted" style={{ fontSize: 11.5, marginTop: 6 }}>
                        Al cumplirse <b>{vigenciaTo}</b>, el plan se renueva automáticamente para el período que inicia el <b>{proximaRecurrencia}</b>.
                      </div>
                    )}
                  </div>
                </div>
              )}
            </div>
          )}

          {/* Step 4: Confirmar */}
          {step === 4 && (
            <div className="ic-cap-section">
              <h3 className="ic-cap-h3">Resumen del plan formativo</h3>
              <p className="muted" style={{ fontSize: 13, marginTop: -4 }}>
                Al confirmar se creará el plan. Después podrás programar sesiones concretas dentro de él (fechas, sedes, instructores) desde la vista del plan o desde la pestaña Sesiones.
              </p>

              <div className="ic-cap-ext-summary">
                <div className="ic-cap-ext-summary-grid">
                  <div><div className="muted-xs">Nombre</div><div style={{ fontWeight: 700 }}>{nombre}</div></div>
                  <div><div className="muted-xs">Cursos del plan</div><div>{cursosIds.length} cursos</div></div>
                  <div><div className="muted-xs">Vigencia</div><div className="mono">{vigenciaFrom} → {vigenciaTo}</div></div>
                  <div><div className="muted-xs">Tipo</div><div>{(window.TIPO_PLAN || {})[tipoPlan]?.label || tipoPlan}{tipoPlan === 'ciclico' && ` · ${(window.FREQ_PLAN || {})[frecuencia]?.label}`}</div></div>
                  {proximaRecurrencia && (
                    <div style={{ gridColumn: '1 / -1' }}><div className="muted-xs">Próxima renovación automática</div><div className="mono">{proximaRecurrencia}</div></div>
                  )}
                  <div style={{ gridColumn: '1 / -1' }}><div className="muted-xs">Audiencia</div><div>{empleadosResueltos.length} colaboradores · {audMode === 'cargo' ? `por cargo (${audCargos.length})` : audMode === 'area' ? `por área (${audAreas.length})` : `selección manual (${audManual.length})`}</div></div>
                </div>
              </div>

              <h4 className="ic-cap-h3" style={{ fontSize: 13, marginTop: 18, marginBottom: 8 }}>Cursos incluidos · {cursosSeleccionados.length}</h4>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                {cursosSeleccionados.map(c => {
                  const cmp = (window.COMPETENCIAS_MAESTRAS || []).find(cm => cm.id === c.competenciaId);
                  return (
                    <div key={c.id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 12px', background: 'white', border: '1px solid var(--border)', borderRadius: 6 }}>
                      <span className="mono" style={{ fontSize: 10.5, color: 'var(--text-muted)' }}>{c.id}</span>
                      <div style={{ flex: 1 }}>
                        <div style={{ fontWeight: 600, fontSize: 12.5 }}>{c.name}</div>
                        <div className="muted" style={{ fontSize: 11 }}>{cmp?.id} · {cmp?.norma}</div>
                      </div>
                      <span className="muted mono" style={{ fontSize: 10.5 }}>{c.duration}</span>
                    </div>
                  );
                })}
              </div>
            </div>
          )}
        </div>

        <div className="modal-foot">
          <span className="muted" style={{ fontSize: 11.5, alignSelf: 'center' }}>
            Paso {step} de 4
          </span>
          <div style={{ flex: 1 }} />
          {step > 1 && (
            <button className="btn" onClick={() => setStep(step - 1)}>
              <IconChevronLeft size={13} /> Atrás
            </button>
          )}
          {step < 4 && (
            <button className="btn primary" onClick={() => setStep(step + 1)} disabled={!canAdvance[step]}>
              Continuar <IconChevronRight size={13} />
            </button>
          )}
          {step === 4 && (
            <button className="btn primary" onClick={crearPlan}>
              <IconCheck size={13} /> Crear plan formativo
            </button>
          )}
        </div>
      </div>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════
// NuevaSesionModal · programar una sesión concreta (no un plan)
// Sesión opcional dentro de un plan formativo · multi-día · instructor con
// lógica de proveedor preferente / override (Fase B).
// ═══════════════════════════════════════════════════════════

const NuevaSesionModal = ({ presetPlanId, onClose, onCreated }) => {
  // Plan al que pertenece la sesión (opcional · sesión suelta sin plan también es válida)
  const [planId, setPlanId] = _tr_useState(presetPlanId || '');
  const [courseId, setCourseId] = _tr_useState('');
  const [dateStart, setDateStart] = _tr_useState('');
  const [dateEnd, setDateEnd] = _tr_useState('');
  const [hora, setHora] = _tr_useState('08:00 - 12:00');
  const [sede, setSede] = _tr_useState('Cali · Aula 2');
  const [instructorId, setInstructorId] = _tr_useState('');
  const [ampliarInstructores, setAmpliarInstructores] = _tr_useState(false);
  const [audMode, setAudMode] = _tr_useState('plan'); // plan (heredar audiencia) | manual
  const [audManual, setAudManual] = _tr_useState([]);

  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 planes = (window.PLANES_FORMATIVOS || []).filter(p => p.estado === 'activo');
  const planSeleccionado = planes.find(p => p.id === planId);

  // Cursos: si hay plan, solo los del plan; si no, todos los publicados
  const allCourses = (window.COURSES || COURSES).filter(c => !c.status || c.status === 'publicado');
  const courses = planSeleccionado
    ? allCourses.filter(c => planSeleccionado.cursosIds.includes(c.id))
    : allCourses;

  const course = courses.find(c => c.id === courseId);
  const competencia = course && (window.COMPETENCIAS_MAESTRAS || []).find(cm => cm.id === course.competenciaId);
  const proveedorCurso = course && course.proveedorId && window.getProveedor ? window.getProveedor(course.proveedorId) : null;

  // Instructores: lógica de proveedor preferente con toggle ampliar (Fase B)
  const instructoresPorCompetencia = competencia
    ? (window.INSTRUCTORES || []).filter(i => i.competencias.includes(competencia.id))
    : (window.INSTRUCTORES || []);
  const instructoresDelProveedor = proveedorCurso
    ? instructoresPorCompetencia.filter(i => i.proveedorId === proveedorCurso.id)
    : [];
  const instructoresElegibles = (proveedorCurso && !ampliarInstructores)
    ? instructoresDelProveedor
    : instructoresPorCompetencia;

  const instructor = (window.INSTRUCTORES || []).find(i => i.id === instructorId);
  const proveedor = instructor && window.getProveedor ? window.getProveedor(instructor.proveedorId) : null;
  const instructorEsOverride = !!(proveedorCurso && instructor && instructor.proveedorId !== proveedorCurso.id);

  // Audiencia · si hay plan y modo=plan, hereda; si manual, lista propia
  const empleadosPool = PLANS;
  const empleadosResueltos = (() => {
    if (audMode === 'plan' && planSeleccionado && window.resolverAudienciaPlan) {
      return window.resolverAudienciaPlan(planSeleccionado, empleadosPool);
    }
    return empleadosPool.filter(e => audManual.includes(e.id));
  })();

  const dias = (() => {
    if (!dateStart) return 1;
    if (!dateEnd || dateEnd === dateStart) return 1;
    const [d1, m1, y1] = dateStart.split('/').map(Number);
    const [d2, m2, y2] = dateEnd.split('/').map(Number);
    if (!d1 || !d2) return 1;
    return Math.round((new Date(y2, m2-1, d2) - new Date(y1, m1-1, d1)) / 86400000) + 1;
  })();

  const canCreate = !!(courseId && dateStart && instructorId && empleadosResueltos.length > 0);

  const crear = () => {
    if (!canCreate) return;
    const newId = `SES-${new Date().getFullYear()}-${Math.floor(Math.random() * 9000) + 1000}`;
    const enrolled = empleadosResueltos.map(e => ({
      empId: e.id, initials: e.initials, name: e.name, role: e.role,
    }));
    const finalDateEnd = dateEnd || dateStart;
    const nuevaSesion = {
      id: newId,
      planId: planId || null,
      courseId: course.id,
      courseName: course.name,
      competenciaId: course.competenciaId,
      cat: course.cat,
      criticality: 'alta',
      dateStart,
      dateEnd: finalDateEnd,
      date: dateStart, // back-compat
      time: hora,
      site: sede,
      instructor: instructor.nombre,
      instructorOrg: proveedor ? proveedor.razonSocial : '—',
      proveedorIdContratado: proveedorCurso?.id || null,
      proveedorIdOperativo: instructor.proveedorId,
      override: instructorEsOverride,
      contentVersion: 'v1.0',
      minScore: course.minScore,
      state: 'programada',
      enrolled,
      origenCertificado: proveedor && (proveedor.tipo === 'SENA' || proveedor.tipo === 'consultor' || proveedor.tipo === 'universidad') ? 'externo' : 'interno',
    };
    onCreated(nuevaSesion);
  };

  const toggleArr = (arr, setArr, val) => setArr(arr.includes(val) ? arr.filter(x => x !== val) : [...arr, val]);

  return (
    <div className="modal-overlay" onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 820 }}>
        <div className="modal-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>Programar sesión · ejecución concreta</div>
            <div className="modal-title">Nueva sesión</div>
            <div className="modal-sub">Una sesión es la ejecución concreta de un curso en una fecha. Puede pertenecer a un plan formativo o ser una sesión suelta.</div>
          </div>
          <button className="icon-btn" onClick={onClose}><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" style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>

          {/* Plan al que pertenece (opcional) */}
          <div className="ic-cap-field">
            <div className="muted-xs">Plan formativo (opcional)</div>
            <select className="ic-cap-version" value={planId} onChange={e => { setPlanId(e.target.value); setCourseId(''); }}>
              <option value="">— Sesión suelta sin plan —</option>
              {planes.map(p => <option key={p.id} value={p.id}>{p.nombre}</option>)}
            </select>
            {planSeleccionado && (
              <div className="muted" style={{ fontSize: 11.5, marginTop: 4 }}>
                Audiencia del plan: <b>{planSeleccionado.audiencia.tipo === 'cargo' ? planSeleccionado.audiencia.cargosNombres.join(', ') : planSeleccionado.audiencia.tipo === 'area' ? planSeleccionado.audiencia.areas.join(', ') : `${planSeleccionado.audiencia.empleadosIds.length} colaboradores específicos`}</b>
              </div>
            )}
          </div>

          {/* Curso */}
          <div className="ic-cap-field">
            <div className="muted-xs">Curso *</div>
            <select className="ic-cap-version" value={courseId} onChange={e => setCourseId(e.target.value)}>
              <option value="">— Selecciona —</option>
              {courses.map(c => {
                const cmp = (window.COMPETENCIAS_MAESTRAS || []).find(cm => cm.id === c.competenciaId);
                return <option key={c.id} value={c.id}>{c.name} · {cmp?.id || '—'} · {c.duration}</option>;
              })}
            </select>
            {planSeleccionado && courses.length === 0 && (
              <div className="muted" style={{ fontSize: 11.5, marginTop: 4 }}>El plan seleccionado no tiene cursos publicados.</div>
            )}
          </div>

          {/* Fechas multi-día */}
          <div className="ic-cap-setup-grid">
            <div className="ic-cap-field">
              <div className="muted-xs">Fecha inicio *</div>
              <window.DatePickerCO
                value={dateStart}
                onChange={setDateStart}
                presets={[
                  { label: 'Mañana',       compute: (t) => { const d = new Date(t); d.setDate(d.getDate() + 1); return d; } },
                  { label: 'Próx. lunes',  compute: (t) => { const d = new Date(t); const dow = d.getDay(); d.setDate(d.getDate() + (((1 - dow + 7) % 7) || 7)); return d; } },
                  { label: 'Próx. viernes',compute: (t) => { const d = new Date(t); const dow = d.getDay(); d.setDate(d.getDate() + (((5 - dow + 7) % 7) || 7)); return d; } },
                ]}
              />
            </div>
            <div className="ic-cap-field">
              <div className="muted-xs">Fecha fin (vacío = un día)</div>
              <window.DatePickerCO
                value={dateEnd}
                onChange={setDateEnd}
                min={dateStart}
                placeholder="Mismo día que el inicio"
              />
              {dateStart && (
                <div className="muted" style={{ fontSize: 11, marginTop: 4 }}>{dias} {dias === 1 ? 'día' : 'días'} de duración</div>
              )}
            </div>
            <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
              <div className="muted-xs">Horario diario</div>
              <window.TimeRangeChipsCO value={hora} onChange={setHora} />
            </div>
            <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
              <div className="muted-xs">Sede</div>
              <input className="ic-cap-version" type="text" value={sede} onChange={e => setSede(e.target.value)} placeholder="Cali · Aula 2" />
            </div>
          </div>

          {/* Instructor con lógica Fase B */}
          <div className="ic-cap-field">
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 }}>
              <div className="muted-xs">Instructor *</div>
              {proveedorCurso && (
                <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, fontWeight: 500, cursor: 'pointer' }}>
                  <input type="checkbox" checked={ampliarInstructores} onChange={e => { setAmpliarInstructores(e.target.checked); setInstructorId(''); }} />
                  Ampliar a otros proveedores
                </label>
              )}
            </div>
            <select className="ic-cap-version" value={instructorId} onChange={e => setInstructorId(e.target.value)}>
              <option value="">— Selecciona instructor —</option>
              {instructoresElegibles.map(i => {
                const v = i.licenciaSST && window.parseDateCO ? window.parseDateCO(i.licenciaSST.vence) : null;
                const vencida = v && v < new Date();
                const prov = window.getProveedor ? window.getProveedor(i.proveedorId) : null;
                const esDelProveedor = proveedorCurso && i.proveedorId === proveedorCurso.id;
                const prefix = esDelProveedor ? '✓ ' : (proveedorCurso ? '⚠ Override · ' : '');
                return (
                  <option key={i.id} value={i.id} disabled={vencida}>
                    {prefix}{i.nombre} · {prov?.razonSocial || i.proveedorId}{vencida ? ' · LICENCIA VENCIDA' : ''}
                  </option>
                );
              })}
            </select>
            {instructorEsOverride && (
              <div className="muted" style={{ fontSize: 11.5, marginTop: 4, color: '#854D0E', fontWeight: 600 }}>
                ⚠ Override · curso contratado con {proveedorCurso?.razonSocial}, instructor de otro proveedor.
              </div>
            )}
          </div>

          {/* Audiencia · heredar del plan o seleccionar manual */}
          <div className="ic-cap-field">
            <div className="muted-xs">Audiencia de esta sesión</div>
            <div style={{ display: 'flex', gap: 6, marginTop: 4, marginBottom: 6 }}>
              {planSeleccionado && (
                <button className={`btn ${audMode === 'plan' ? 'primary' : ''}`} onClick={() => setAudMode('plan')}>Heredar audiencia del plan</button>
              )}
              <button className={`btn ${audMode === 'manual' ? 'primary' : ''}`} onClick={() => setAudMode('manual')}>Selección manual</button>
            </div>
            {audMode === 'plan' && planSeleccionado && (
              <div className="muted" style={{ fontSize: 11.5 }}>
                {empleadosResueltos.length} colaboradores quedan inscritos automáticamente desde el plan.
              </div>
            )}
            {audMode === 'manual' && (
              <div style={{ maxHeight: 240, overflow: 'auto', border: '1px solid var(--border)', borderRadius: 8 }}>
                {empleadosPool.map(e => {
                  const sel = audManual.includes(e.id);
                  return (
                    <label key={e.id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 10px', borderBottom: '1px solid var(--border)', cursor: 'pointer', background: sel ? '#F0FDF4' : 'white' }}>
                      <input type="checkbox" checked={sel} onChange={() => toggleArr(audManual, setAudManual, e.id)} />
                      <div className="doc-avatar" style={{ width: 24, height: 24, fontSize: 10 }}>{e.initials}</div>
                      <div style={{ flex: 1 }}>
                        <span style={{ fontWeight: 600, fontSize: 12 }}>{e.name}</span>
                        <span className="muted" style={{ fontSize: 11, marginLeft: 8 }}>{e.role}</span>
                      </div>
                      <span className="mono muted" style={{ fontSize: 10.5 }}>{e.id}</span>
                    </label>
                  );
                })}
              </div>
            )}
            <div className="muted" style={{ fontSize: 11.5, marginTop: 6 }}>
              <b>{empleadosResueltos.length}</b> colaborador{empleadosResueltos.length === 1 ? '' : 'es'} en esta sesión.
            </div>
          </div>
        </div>

        <div className="modal-foot">
          <div style={{ flex: 1 }} />
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" onClick={crear} disabled={!canCreate}>
            <IconCheck size={13} /> Programar sesión
          </button>
        </div>
      </div>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════
// EntrenamientoTab · guías de plataformas digitales por cargo
// Idea de prototipo: cuando alguien ingresa a un cargo, aquí encuentra
// cómo usar las herramientas digitales que necesita para ese cargo
// (nuestra propia plataforma HCM Atica SOMOS + sistemas externos del
// día a día operativo). Sujeto a ajustes.
// ═══════════════════════════════════════════════════════════

// Semilla plana — cada registro es "un entrenamiento" ligado a un cargo y una plataforma.
// Separamos nombre del entrenamiento (qué vas a aprender a hacer) de la plataforma
// (en qué sistema lo haces), para que el admin pueda gestionarlos como catálogo.
const DIGITAL_TRAININGS_SEED = [
  { id: 'dp-01', cargoId: 'CGO-001', name: 'Registro de lotes en báscula digital',        platform: 'App de Báscula y Clasificación',            icon: 'IconBarChart', desc: 'Registro digital de lotes, pesaje y trazabilidad de material en la línea de clasificación.', duration: '25 min', mode: 'App móvil', status: 'completado' },
  { id: 'dp-02', cargoId: 'CGO-001', name: 'Marcar asistencia y consultar tu nómina',      platform: 'HCM Atica SOMOS · Portal del colaborador',  icon: 'IconRocket',   desc: 'Marcar asistencia, consultar tu nómina y solicitar vacaciones desde el celular.', duration: '15 min', mode: 'App móvil', status: 'pendiente' },

  { id: 'dp-03', cargoId: 'CGO-003', name: 'Registro de material aprovechable por turno',  platform: 'App de Trazabilidad de Aprovechamiento',    icon: 'IconSearch',   desc: 'Registro de material recuperado por categoría, peso y turno.', duration: '20 min', mode: 'App móvil', status: 'completado' },
  { id: 'dp-04', cargoId: 'CGO-003', name: 'Consultar dotación y capacitaciones',           platform: 'HCM Atica SOMOS · Portal del colaborador',  icon: 'IconRocket',   desc: 'Consultar tu dotación asignada y tus capacitaciones pendientes.', duration: '15 min', mode: 'App móvil', status: 'pendiente' },

  { id: 'dp-15', cargoId: 'CGO-004', name: 'Aprobar solicitudes de tu equipo',              platform: 'HCM Atica SOMOS · Panel de líder',          icon: 'IconRocket',   desc: 'Aprobar vacaciones, permisos y turnos de las personas a tu cargo.', duration: '25 min', mode: 'Web', status: 'pendiente' },
  { id: 'dp-16', cargoId: 'CGO-004', name: 'Seguimiento de metas de productividad',         platform: 'App de Trazabilidad de Aprovechamiento',    icon: 'IconSearch',   desc: 'Supervisar metas de productividad y calidad de tu línea por turno.', duration: '20 min', mode: 'App móvil', status: 'completado' },

  { id: 'dp-17', cargoId: 'CGO-005', name: 'Registro de muestreos y no conformidades',      platform: 'Portal de Calidad HACCP Digital',           icon: 'IconShield',   desc: 'Registro de muestreos, checklist HACCP y no conformidades desde el punto de control.', duration: '30 min', mode: 'App móvil', status: 'pendiente' },
  { id: 'dp-18', cargoId: 'CGO-005', name: 'Consultar certificados y capacitaciones',        platform: 'HCM Atica SOMOS · Portal del colaborador',  icon: 'IconRocket',   desc: 'Consultar tus capacitaciones obligatorias y certificados vigentes.', duration: '15 min', mode: 'App móvil', status: 'completado' },

  { id: 'dp-05', cargoId: 'CGO-006', name: 'Crear y cerrar órdenes de trabajo',              platform: 'Sistema de Órdenes de Mantenimiento (CMMS)', icon: 'IconSettings', desc: 'Crear, cerrar y hacer seguimiento a órdenes de trabajo de mantenimiento.', duration: '30 min', mode: 'Web + App', status: 'completado' },
  { id: 'dp-06', cargoId: 'CGO-006', name: 'Consultar dotación EPP y exámenes',              platform: 'HCM Atica SOMOS · Portal del colaborador',  icon: 'IconRocket',   desc: 'Consultar tu dotación EPP y tus exámenes médicos ocupacionales.', duration: '15 min', mode: 'App móvil', status: 'completado' },

  { id: 'dp-07', cargoId: 'CGO-007', name: 'Crear órdenes de compra y aprobar cotizaciones', platform: 'ERP de Compras y Proveedores',              icon: 'IconExternal', desc: 'Crear órdenes de compra, aprobar cotizaciones y gestionar proveedores.', duration: '40 min', mode: 'Web', status: 'pendiente' },
  { id: 'dp-08', cargoId: 'CGO-007', name: 'Gestionar tu correo y calendario',                platform: 'Correo corporativo y Google Workspace',     icon: 'IconMegaphone', desc: 'Uso de Gmail, Drive y Calendar con tu cuenta corporativa Atica.', duration: '20 min', mode: 'Web', status: 'completado' },
  { id: 'dp-09', cargoId: 'CGO-007', name: 'Aprobaciones y centros de costo',                 platform: 'HCM Atica SOMOS · Panel administrativo',    icon: 'IconRocket',   desc: 'Gestión de centros de costo y aprobaciones de tu equipo.', duration: '25 min', mode: 'Web', status: 'pendiente' },

  { id: 'dp-10', cargoId: 'CGO-008', name: 'Gestión completa de RRHH',                        platform: 'HCM Atica SOMOS · Panel administrativo completo', icon: 'IconRocket', desc: 'Empleados, nómina, SST, reportes y motor de automatización.', duration: '45 min', mode: 'Web', status: 'completado' },
  { id: 'dp-11', cargoId: 'CGO-008', name: 'Enviar documentos para firma',                    platform: 'Firma electrónica de documentos',           icon: 'IconDoc',      desc: 'Envío, seguimiento y validez legal de documentos firmados electrónicamente.', duration: '15 min', mode: 'Web', status: 'completado' },
  { id: 'dp-12', cargoId: 'CGO-008', name: 'Gestionar tu correo y calendario',                platform: 'Correo corporativo y Google Workspace',     icon: 'IconMegaphone', desc: 'Uso de Gmail, Drive y Calendar con tu cuenta corporativa Atica.', duration: '20 min', mode: 'Web', status: 'completado' },

  { id: 'dp-13', cargoId: 'CGO-009', name: 'Navegar tu ruta de recolección',                  platform: 'App de Ruta y Recolección',                 icon: 'IconZap',      desc: 'Navegación GPS, checklist de vehículo y registro de puntos de recolección.', duration: '20 min', mode: 'App móvil', status: 'pendiente' },
  { id: 'dp-14', cargoId: 'CGO-009', name: 'Consultar tus turnos y tu nómina',                platform: 'HCM Atica SOMOS · Portal del colaborador',  icon: 'IconRocket',   desc: 'Consultar tus turnos, tu nómina y solicitar permisos.', duration: '15 min', mode: 'App móvil', status: 'pendiente' },
];

const TRAINING_FORMATOS = ['App móvil', 'Web', 'Web + App', 'Presencial'];

const ENTR_STATUS_META = {
  completado: { label: 'Completado', pill: 'green' },
  pendiente:  { label: 'Pendiente',  pill: 'amber' },
};

// ─── Modal única: crear / editar / ver un entrenamiento ────
const TrainingFormModal = ({ mode, item, onClose, onSave }) => {
  const [form, setForm] = React.useState(null);
  const cargos = window.CARGOS || [];

  React.useEffect(() => {
    if (!mode) return;
    setForm(item ? { ...item } : {
      name: '', cargoId: cargos[0]?.id || '', platform: '', duration: '',
      mode: TRAINING_FORMATOS[0], desc: '', status: 'pendiente', icon: 'IconZap',
    });
  }, [mode, item]);

  if (!mode || !form) return null;
  const readOnly = mode === 'ver';
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const title = mode === 'crear' ? 'Crear entrenamiento' : mode === 'editar' ? 'Editar entrenamiento' : 'Detalle del entrenamiento';

  return (
    <Modal open onClose={onClose}
      title={title}
      subtitle={readOnly ? undefined : 'Nombre, cargo, plataforma y formato del entrenamiento'}
      width={600}
      footer={
        readOnly ? (
          <button className="btn" onClick={onClose}>Cerrar</button>
        ) : (
          <>
            <button className="btn" onClick={onClose}>Cancelar</button>
            <button className="btn primary" disabled={!form.name.trim() || !form.platform.trim()} onClick={() => onSave(form)}>
              {mode === 'crear' ? 'Crear entrenamiento' : 'Guardar cambios'}
            </button>
          </>
        )
      }>
      <div className="form-grid">
        <FormField label="Nombre de entrenamiento" span={6}>
          <input className="form-input" disabled={readOnly} placeholder='Ej. "Registro de lotes en báscula digital"' value={form.name} onChange={e => set('name', e.target.value)} />
        </FormField>
        <FormField label="Cargo" span={3}>
          <select className="form-input" disabled={readOnly} value={form.cargoId} onChange={e => set('cargoId', e.target.value)}>
            {cargos.map(c => <option key={c.id} value={c.id}>{c.nombre}</option>)}
          </select>
        </FormField>
        <FormField label="Plataforma" span={3}>
          <input className="form-input" disabled={readOnly} placeholder='Ej. "App de Báscula y Clasificación"' value={form.platform} onChange={e => set('platform', e.target.value)} />
        </FormField>
        <FormField label="Duración" span={3}>
          <input className="form-input" disabled={readOnly} placeholder="Ej. 20 min" value={form.duration} onChange={e => set('duration', e.target.value)} />
        </FormField>
        <FormField label="Formato" span={3}>
          <select className="form-input" disabled={readOnly} value={form.mode} onChange={e => set('mode', e.target.value)}>
            {TRAINING_FORMATOS.map(f => <option key={f} value={f}>{f}</option>)}
          </select>
        </FormField>
        <FormField label="Estado" span={6}>
          <select className="form-input" disabled={readOnly} value={form.status} onChange={e => set('status', e.target.value)}>
            <option value="pendiente">Pendiente</option>
            <option value="completado">Completado</option>
          </select>
        </FormField>
        <FormField label="Descripción" span={6}>
          <textarea className="form-input" rows={3} disabled={readOnly} placeholder="¿Qué va a aprender a hacer el colaborador?" value={form.desc} onChange={e => set('desc', e.target.value)} />
        </FormField>
      </div>
    </Modal>
  );
};

// ─── Modal grande: administrador de entrenamientos (solo Admin) ────
const TrainingAdminModal = ({ trainings, onClose, onCreate, onUpdate, onDelete, onView }) => {
  const cargoName = (id) => (window.CARGOS || []).find(c => c.id === id)?.nombre || id;

  return (
    <Modal open onClose={onClose}
      title="Administrador de entrenamientos"
      subtitle="Catálogo completo de entrenamientos de plataformas digitales, por cargo"
      width={980}
      noPad
      footer={<button className="btn" onClick={onClose}>Cerrar</button>}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '16px 20px' }}>
        <span className="muted" style={{ fontSize: 12.5 }}>{trainings.length} entrenamientos registrados</span>
        <button className="btn primary" onClick={() => onCreate()}>
          <IconPlus size={14} /> Crear entrenamiento
        </button>
      </div>
      <table className="data-table">
        <thead>
          <tr><th>Nombre de Entrenamiento</th><th>Cargo</th><th>Plataforma</th><th>Duración</th><th style={{ textAlign: 'right' }}>Funciones</th></tr>
        </thead>
        <tbody>
          {trainings.map(t => (
            <tr key={t.id}>
              <td style={{ fontWeight: 500 }}>{t.name}</td>
              <td>{cargoName(t.cargoId)}</td>
              <td className="muted">{t.platform}</td>
              <td className="mono muted">{t.duration}</td>
              <td style={{ textAlign: 'right' }}>
                <div style={{ display: 'inline-flex', gap: 6 }}>
                  <button className="btn" style={{ padding: '4px 10px', fontSize: 12 }} onClick={() => onView(t)}>Ver</button>
                  <button className="btn" style={{ padding: '4px 10px', fontSize: 12 }} onClick={() => onUpdate(t)}>Editar</button>
                  <button className="btn danger" style={{ padding: '4px 10px', fontSize: 12 }} onClick={() => onDelete(t)}>Eliminar</button>
                </div>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </Modal>
  );
};

const EntrenamientoTab = ({ currentRole }) => {
  const [trainings, setTrainings] = React.useState(DIGITAL_TRAININGS_SEED);
  const isAdmin = currentRole === 'admin';
  const isConductor = currentRole === 'conductor';

  const cargosConGuia = React.useMemo(() => {
    const ids = [...new Set(trainings.map(t => t.cargoId))];
    return (window.CARGOS || []).filter(c => ids.includes(c.id));
  }, [trainings]);

  const visibleCargos = isConductor ? cargosConGuia.filter(c => c.id === 'CGO-009') : cargosConGuia;

  const [cargoId, setCargoId] = React.useState(null);
  React.useEffect(() => {
    if (!visibleCargos.find(c => c.id === cargoId)) setCargoId(visibleCargos[0]?.id || null);
  }, [currentRole, visibleCargos.map(c => c.id).join(',')]);

  const [adminModalOpen, setAdminModalOpen] = React.useState(false);
  const [formMode, setFormMode] = React.useState(null); // null | 'crear' | 'editar' | 'ver'
  const [formItem, setFormItem] = React.useState(null);

  const cargo = cargosConGuia.find(c => c.id === cargoId);
  const items = trainings.filter(t => t.cargoId === cargoId);
  const completados = items.filter(i => i.status === 'completado').length;

  const closeForm = () => { setFormMode(null); setFormItem(null); };
  const saveForm = (data) => {
    if (data.id) {
      setTrainings(list => list.map(t => t.id === data.id ? { ...data } : t));
    } else {
      setTrainings(list => [...list, { ...data, id: `dp-${Date.now()}` }]);
    }
    closeForm();
  };
  const deleteTraining = (t) => {
    if (!confirm(`¿Eliminar el entrenamiento "${t.name}"?`)) return;
    setTrainings(list => list.filter(x => x.id !== t.id));
  };

  return (
    <div>
      <div className="card" style={{ marginBottom: 16, padding: '14px 18px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div className="tr-kpi-icon navy" style={{ width: 34, height: 34 }}><IconZap size={16} /></div>
          <div style={{ flex: 1 }}>
            <div style={{ fontWeight: 600, fontSize: 13.5 }}>Entrenamiento en plataformas digitales</div>
            <div className="muted" style={{ fontSize: 12 }}>
              {isConductor
                ? 'Estás viendo el entrenamiento de tu propio cargo: Conductor.'
                : 'Cuando un colaborador ingresa a un cargo, aquí encuentra cómo usar las herramientas digitales de Atica que necesita para cumplir sus funciones.'}
            </div>
          </div>
          {isAdmin && (
            <button className="btn" onClick={() => setAdminModalOpen(true)}>
              <IconSettings size={14} /> Administrador de entrenamientos
            </button>
          )}
        </div>
      </div>

      {isConductor ? (
        <>
          <div className="cf-section-head">
            <div>
              <div className="cf-section-title">{cargo ? cargo.nombre : 'Conductor'}</div>
              <div className="muted" style={{ fontSize: 12.5, marginTop: 2 }}>
                {completados} de {items.length} plataformas completadas
              </div>
            </div>
          </div>
          <div className="tr-catalog">
            {items.map(it => <EntrTrainingCard key={it.id} it={it} />)}
          </div>
        </>
      ) : (
        <div className="cf-layout">
          <aside className="cf-sidebar">
            {visibleCargos.map(c => {
              const its = trainings.filter(t => t.cargoId === c.id);
              const done = its.filter(i => i.status === 'completado').length;
              return (
                <button key={c.id} className={`cf-nav-item ${cargoId === c.id ? 'active' : ''}`} onClick={() => setCargoId(c.id)}>
                  <IconUsers size={15} />
                  <span style={{ flex: 1, textAlign: 'left' }}>{c.nombre}</span>
                  <span className="muted-xs" style={{ color: cargoId === c.id ? 'rgba(255,255,255,0.7)' : undefined }}>{done}/{its.length}</span>
                </button>
              );
            })}
          </aside>

          <div className="cf-content">
            {cargo && (
              <>
                <div className="cf-section-head">
                  <div>
                    <div className="cf-section-title">{cargo.nombre}</div>
                    <div className="muted" style={{ fontSize: 12.5, marginTop: 2 }}>
                      {cargo.area} · {completados} de {items.length} plataformas completadas · {cargo.headcount} colaboradores en este cargo
                    </div>
                  </div>
                </div>
                <div className="tr-catalog">
                  {items.map(it => <EntrTrainingCard key={it.id} it={it} />)}
                </div>
              </>
            )}
          </div>
        </div>
      )}

      {adminModalOpen && (
        <TrainingAdminModal
          trainings={trainings}
          onClose={() => setAdminModalOpen(false)}
          onCreate={() => { setFormItem(null); setFormMode('crear'); }}
          onUpdate={(t) => { setFormItem(t); setFormMode('editar'); }}
          onView={(t) => { setFormItem(t); setFormMode('ver'); }}
          onDelete={deleteTraining}
        />
      )}
      <TrainingFormModal mode={formMode} item={formItem} onClose={closeForm} onSave={saveForm} />
    </div>
  );
};

const EntrTrainingCard = ({ it }) => {
  const Ico = window[it.icon] || IconZap;
  const st = ENTR_STATUS_META[it.status];
  return (
    <div className="tr-card">
      <div className="tr-card-head">
        <span className="tr-cat-badge navy"><Ico size={11} /> {it.mode}</span>
        <span className={`pill ${st.pill}`} style={{ fontSize: 10 }}>{st.label}</span>
      </div>
      <div className="tr-card-name">{it.name}</div>
      <div className="muted-xs" style={{ marginTop: 2 }}>{it.platform}</div>
      <div className="muted" style={{ fontSize: 12, lineHeight: 1.5, marginTop: 6, marginBottom: 10 }}>{it.desc}</div>
      <div className="tr-card-meta">
        <div><div className="muted-xs">Duración</div><div className="tr-card-val">{it.duration}</div></div>
        <div><div className="muted-xs">Formato</div><div className="tr-card-val">{it.mode}</div></div>
      </div>
      <button className="btn" style={{ width: '100%', justifyContent: 'center', marginTop: 12 }}>
        {it.status === 'completado' ? 'Ver de nuevo' : 'Iniciar guía'}
      </button>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════
// PlanesTab · vista principal de planes formativos
// ═══════════════════════════════════════════════════════════

const PlanesTab = ({ onProgramarSesion, onNuevoPlan }) => {
  const [view, setView] = _tr_useState('por-plan'); // por-plan | por-colaborador
  const [picked, setPicked] = _tr_useState(null);

  const planes = window.PLANES_FORMATIVOS || [];
  const sesiones = window.SESSIONS_SCHED || [];

  // Métricas por plan
  const planConMetricas = (p) => {
    const ses = sesiones.filter(s => s.planId === p.id);
    const programadas = ses.filter(s => s.state === 'programada').length;
    const cerradas = ses.filter(s => s.state === 'cerrada').length;
    const total = ses.length;
    const cumplimiento = total > 0 ? Math.round((cerradas / total) * 100) : 0;
    return { ...p, sesionesProgramadas: programadas, sesionesCerradas: cerradas, sesionesTotal: total, cumplimiento };
  };

  return (
    <>
      <div className="ob-toolbar" style={{ marginBottom: 14 }}>
        <div style={{ display: 'flex', gap: 4 }}>
          <button className={`btn ${view === 'por-plan' ? 'primary' : ''}`} onClick={() => setView('por-plan')}>
            <IconBarChart size={13} /> Vista por plan
          </button>
          <button className={`btn ${view === 'por-colaborador' ? 'primary' : ''}`} onClick={() => setView('por-colaborador')}>
            <IconUsers size={13} /> Vista por colaborador
          </button>
        </div>
        <div style={{ flex: 1 }} />
        <button className="btn primary" onClick={onNuevoPlan}><IconPlus size={14} /> Nuevo plan formativo</button>
      </div>

      {view === 'por-plan' && (
        <>
          <div className="ic-cmp-kpis" style={{ marginBottom: 14 }}>
            <div className="ic-cmp-kpi">
              <div className="muted-xs">Planes activos</div>
              <div className="ic-cmp-kpi-num">{planes.filter(p => p.estado === 'activo').length}</div>
              <div className="muted" style={{ fontSize: 11 }}>Cíclicos · puntuales · por evento</div>
            </div>
            <div className="ic-cmp-kpi">
              <div className="muted-xs">Sesiones programadas</div>
              <div className="ic-cmp-kpi-num">{sesiones.filter(s => s.state === 'programada').length}</div>
              <div className="muted" style={{ fontSize: 11 }}>en planes activos</div>
            </div>
            <div className="ic-cmp-kpi">
              <div className="muted-xs">Sesiones cerradas</div>
              <div className="ic-cmp-kpi-num" style={{ color: 'var(--green-600)' }}>{sesiones.filter(s => s.state === 'cerrada').length}</div>
              <div className="muted" style={{ fontSize: 11 }}>certificados emitidos</div>
            </div>
            <div className="ic-cmp-kpi">
              <div className="muted-xs">Próxima recurrencia</div>
              <div className="ic-cmp-kpi-num" style={{ fontSize: 18 }}>{planes.filter(p => p.proximaRecurrencia).map(p => p.proximaRecurrencia).sort()[0] || '—'}</div>
              <div className="muted" style={{ fontSize: 11 }}>renovación automática</div>
            </div>
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(340px, 1fr))', gap: 14 }}>
            {planes.map(p => {
              const m = planConMetricas(p);
              const tipo = (window.TIPO_PLAN || {})[p.tipo];
              const freq = (window.FREQ_PLAN || {})[p.frecuencia];
              return (
                <button key={p.id} onClick={() => setPicked(m)} style={{ textAlign: 'left', background: 'white', border: '1px solid var(--border)', borderRadius: 14, padding: 16, cursor: 'pointer' }} className="tr-card">
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                    <span className={`pill ${p.tipo === 'ciclico' ? 'navy' : p.tipo === 'puntual' ? 'green' : 'amber'}`} style={{ fontSize: 10.5 }}>
                      {tipo?.label || p.tipo}{p.tipo === 'ciclico' && ` · ${freq?.label}`}
                    </span>
                    <span className="muted mono" style={{ fontSize: 10.5 }}>{p.id}</span>
                  </div>
                  <div style={{ fontWeight: 700, fontSize: 14, marginTop: 8 }}>{p.nombre}</div>
                  <div className="muted" style={{ fontSize: 12, marginTop: 4, lineHeight: 1.4 }}>{p.descripcion}</div>
                  <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginTop: 10 }}>
                    <div style={{ padding: '6px 8px', background: 'var(--surface)', borderRadius: 6 }}>
                      <div className="muted-xs">Vigencia</div>
                      <div className="mono" style={{ fontSize: 11.5 }}>{p.vigenciaFrom} → {p.vigenciaTo}</div>
                    </div>
                    <div style={{ padding: '6px 8px', background: 'var(--surface)', borderRadius: 6 }}>
                      <div className="muted-xs">Cursos</div>
                      <div style={{ fontSize: 12, fontWeight: 600 }}>{p.cursosIds.length} cursos</div>
                    </div>
                  </div>
                  <div className="tr-prog-track" style={{ marginTop: 10 }}>
                    <div className="tr-prog-fill green" style={{ width: `${m.cumplimiento}%` }} />
                  </div>
                  <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 4 }}>
                    <span className="muted" style={{ fontSize: 11 }}>{m.sesionesCerradas} de {m.sesionesTotal || 'sin sesiones'} cerradas</span>
                    <span className="mono" style={{ fontSize: 11, fontWeight: 700, color: 'var(--green-600)' }}>{m.cumplimiento}%</span>
                  </div>
                  {p.proximaRecurrencia && (
                    <div className="muted" style={{ fontSize: 11, marginTop: 6, fontStyle: 'italic' }}>
                      ↻ Próxima renovación: <b>{p.proximaRecurrencia}</b>
                    </div>
                  )}
                </button>
              );
            })}
          </div>

          {picked && <PlanDetailPanel plan={picked} onClose={() => setPicked(null)} onProgramarSesion={() => { onProgramarSesion(picked.id); setPicked(null); }} />}
        </>
      )}

      {view === 'por-colaborador' && <PlansTab />}
    </>
  );
};

const PlanDetailPanel = ({ plan, onClose, onProgramarSesion }) => {
  React.useEffect(() => {
    const onEsc = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onEsc);
    return () => window.removeEventListener('keydown', onEsc);
  }, []);

  const sesiones = (window.SESSIONS_SCHED || []).filter(s => s.planId === plan.id);
  const cursos = (window.COURSES || []).filter(c => plan.cursosIds.includes(c.id));
  const tipo = (window.TIPO_PLAN || {})[plan.tipo];
  const freq = (window.FREQ_PLAN || {})[plan.frecuencia];

  return (
    <div className="tr-side-overlay" onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="tr-side-panel" style={{ width: 720 }}>
        <div className="tr-side-head">
          <div style={{ minWidth: 0 }}>
            <div className="muted mono" style={{ fontSize: 11 }}>{plan.id}</div>
            <div className="tr-side-title" style={{ marginTop: 4 }}>{plan.nombre}</div>
            <div className="muted" style={{ fontSize: 12, marginTop: 4 }}>{plan.descripcion}</div>
          </div>
          <div style={{ display: 'flex', gap: 6 }}>
            <button className="btn primary" onClick={onProgramarSesion}><IconPlus size={12} /> Programar sesión</button>
            <button className="icon-btn" onClick={onClose}><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>
        <div className="tr-side-body">
          <section className="ic-prov-section">
            <h4 className="ic-cap-h3">Datos del plan</h4>
            <div className="ic-prov-info">
              <div><div className="muted-xs">Tipo</div><div>{tipo?.label}</div></div>
              <div><div className="muted-xs">Frecuencia</div><div>{plan.tipo === 'ciclico' ? freq?.label : '—'}</div></div>
              <div><div className="muted-xs">Vigencia</div><div className="mono">{plan.vigenciaFrom} → {plan.vigenciaTo}</div></div>
              <div><div className="muted-xs">Próxima renovación</div><div className="mono">{plan.proximaRecurrencia || '—'}</div></div>
              <div><div className="muted-xs">Creado por</div><div style={{ fontSize: 12 }}>{plan.creadoPor}</div></div>
              <div><div className="muted-xs">Estado</div><div><span className="pill green" style={{ fontSize: 10.5 }}>{plan.estado}</span></div></div>
            </div>
          </section>

          <section className="ic-prov-section">
            <h4 className="ic-cap-h3">Cursos del plan · {cursos.length}</h4>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {cursos.map(c => {
                const cmp = (window.COMPETENCIAS_MAESTRAS || []).find(cm => cm.id === c.competenciaId);
                return (
                  <div key={c.id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: 10, background: 'var(--surface)', borderRadius: 8 }}>
                    <span className="mono" style={{ fontSize: 10.5, color: 'var(--text-muted)' }}>{c.id}</span>
                    <div style={{ flex: 1 }}>
                      <div style={{ fontWeight: 600, fontSize: 12.5 }}>{c.name}</div>
                      <div className="muted" style={{ fontSize: 11 }}>{cmp?.id} · {cmp?.norma}</div>
                    </div>
                    <span className="mono muted" style={{ fontSize: 10.5 }}>{c.duration}</span>
                  </div>
                );
              })}
            </div>
          </section>

          <section className="ic-prov-section">
            <h4 className="ic-cap-h3">Sesiones del plan · {sesiones.length}</h4>
            {sesiones.length === 0 && (
              <div className="muted" style={{ fontSize: 12.5, padding: 16, textAlign: 'center', background: 'var(--surface)', borderRadius: 8 }}>
                Aún no se han programado sesiones para este plan. Click en <b>"+ Programar sesión"</b> arriba.
              </div>
            )}
            {sesiones.map(s => {
              const dateLabel = window.sessionDateLabel ? window.sessionDateLabel(s) : s.dateStart || s.date;
              return (
                <div key={s.id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: 10, background: 'white', border: '1px solid var(--border)', borderRadius: 8, marginBottom: 6 }}>
                  <span className={`pill ${s.state === 'cerrada' ? 'green' : s.state === 'programada' ? 'amber-soft' : 'rose'}`} style={{ fontSize: 10.5 }}>{s.state}</span>
                  <div style={{ flex: 1 }}>
                    <div style={{ fontWeight: 600, fontSize: 12.5 }}>{s.courseName}</div>
                    <div className="muted" style={{ fontSize: 11 }}>{dateLabel} · {s.site} · {(s.enrolled || []).length} inscritos</div>
                  </div>
                  <span className="mono muted" style={{ fontSize: 10.5 }}>{s.id}</span>
                </div>
              );
            })}
          </section>
        </div>
      </div>
    </div>
  );
};

// ═══════════════════════════════════════════════════════════
// MaterialEditor · selector de tipo + entrada según tipo
// Tipos: pdf · video · texto (rich text) · enlace
// ═══════════════════════════════════════════════════════════

const MAT_TIPOS = [
  { id: 'pdf',    label: 'PDF',    iconPath: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6zM14 2v6h6M9 13h6M9 17h6' },
  { id: 'video',  label: 'Video',  iconPath: 'm22 8-6 4 6 4V8zM2 6h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2z' },
  { id: 'texto',  label: 'Texto',  iconPath: 'M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2M9 20h6M12 4v16' },
  { id: 'enlace', label: 'Enlace', iconPath: 'M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71' },
];

const MaterialTipoIcon = ({ path, size = 13 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
    <path d={path} />
  </svg>
);

// Editor de texto enriquecido · contentEditable + toolbar (B / I / U / lista / link)
const RichTextEditor = ({ value = '', onChange, placeholder = 'Escribe el contenido del material…' }) => {
  const ref = React.useRef(null);
  const [focused, setFocused] = React.useState(false);

  // Sincronizar valor externo en mount sin perder el caret
  React.useEffect(() => {
    if (ref.current && ref.current.innerHTML !== (value || '')) {
      ref.current.innerHTML = value || '';
    }
  }, []);

  const exec = (cmd, arg = null) => {
    document.execCommand(cmd, false, arg);
    if (ref.current) onChange && onChange(ref.current.innerHTML);
    ref.current?.focus();
  };

  const tools = [
    { cmd: 'bold',          label: 'B',   title: 'Negrita',     style: { fontWeight: 800 } },
    { cmd: 'italic',        label: 'I',   title: 'Cursiva',     style: { fontStyle: 'italic' } },
    { cmd: 'underline',     label: 'U',   title: 'Subrayado',   style: { textDecoration: 'underline' } },
    { cmd: 'insertUnorderedList', label: '•', title: 'Lista', style: { fontWeight: 700 } },
    { cmd: 'insertOrderedList',   label: '1.', title: 'Lista numerada', style: { fontWeight: 700, fontSize: 11 } },
    { cmd: 'createLink',          label: '🔗', title: 'Insertar enlace', special: 'link' },
    { cmd: 'removeFormat',        label: '⌫', title: 'Quitar formato' },
  ];

  return (
    <div className={`rt-editor ${focused ? 'focused' : ''}`}>
      <div className="rt-toolbar">
        {tools.map(t => (
          <button
            key={t.cmd}
            type="button"
            className="rt-tool"
            title={t.title}
            onMouseDown={(e) => { e.preventDefault(); }}
            onClick={() => {
              if (t.special === 'link') {
                const url = prompt('URL del enlace:');
                if (url) exec('createLink', url);
              } else {
                exec(t.cmd);
              }
            }}
            style={t.style}
          >
            {t.label}
          </button>
        ))}
        <div style={{ flex: 1 }} />
        <span className="muted mono" style={{ fontSize: 10 }}>texto enriquecido</span>
      </div>
      <div
        ref={ref}
        className="rt-content"
        contentEditable
        suppressContentEditableWarning
        onFocus={() => setFocused(true)}
        onBlur={() => setFocused(false)}
        onInput={(e) => onChange && onChange(e.currentTarget.innerHTML)}
        data-placeholder={placeholder}
      />
    </div>
  );
};

const MaterialEditor = ({ material, onUpdate, onDelete }) => {
  const tipo = MAT_TIPOS.find(t => t.id === material.tipo) || MAT_TIPOS[0];
  const isText = material.tipo === 'texto';
  const isLink = material.tipo === 'enlace';

  return (
    <div className="mat-editor">
      <div className="mat-editor-head">
        <div className="mat-tipo-chips">
          {MAT_TIPOS.map(t => (
            <button
              key={t.id}
              type="button"
              className={`mat-tipo-chip ${material.tipo === t.id ? 'active' : ''}`}
              onClick={() => onUpdate({ tipo: t.id, nombre: t.id === 'texto' ? 'Contenido del módulo' : t.id === 'enlace' ? 'https://' : `material.${t.id === 'video' ? 'mp4' : 'pdf'}` })}
              title={t.label}
            >
              <MaterialTipoIcon path={t.iconPath} size={12} />
              {t.label}
            </button>
          ))}
        </div>
        <button className="icon-btn" onClick={onDelete} title="Quitar material">
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
        </button>
      </div>

      <input
        className="ic-cap-version"
        type="text"
        value={material.nombre || ''}
        onChange={e => onUpdate({ nombre: e.target.value })}
        placeholder={
          isText ? 'Título del contenido (visible al colaborador)' :
          isLink ? 'https://...' :
          tipo.id === 'video' ? 'video.mp4' : 'archivo.pdf'
        }
      />

      {isText && (
        <RichTextEditor
          value={material.contenido || ''}
          onChange={(html) => onUpdate({ contenido: html })}
          placeholder="Escribe el contenido del módulo… puedes dar formato con la barra superior."
        />
      )}
    </div>
  );
};

// ═══════════════════════════════════════════════════════════
// CursoEditorModal · Fase E (E.1 + E.2 + E.3)
// Tabs: Datos · Sílabo · Evaluación · E-learning externo
// ═══════════════════════════════════════════════════════════

const CursoEditorModal = ({ course, onClose, onSave }) => {
  // course puede ser:
  //   - null (nuevo curso interno completo)
  //   - 'externo' (atajo · pre-rellena modalidad e-learning externo)
  //   - object (editar existente)
  const externoExpress = course === 'externo';
  const isNew = !course || externoExpress;
  // Para curso de tercero express, abrir directo en la pestaña "Plataforma del proveedor" (donde vive la URL)
  const [editTab, setEditTab] = _tr_useState(externoExpress ? 'elearning' : 'datos');
  const [form, setForm] = _tr_useState(() => (course && course !== 'externo') ? { ...course } : {
    id: '',
    name: '',
    cat: 'sst',
    mode: externoExpress ? 'elearning-externo' : 'presencial',
    duration: '4 h',
    mandatory: false,
    minScore: 80,
    rating: 0,
    enrolled: 0,
    completed: 0,
    description: '',
    forRoles: [],
    syllabus: [],
    sessions: [],
    upcoming: [],
    competenciaId: '',
    normaOrigen: '',
    proveedorId: '',
    status: 'borrador',
    version: 'v1.0',
    changelog: '',
    publicadoEn: '',
    publicadoPor: '',
    modulos: [],
    // E.3 · campos para e-learning externo
    plataforma: '',
    urlAcceso: '',
    metodoSync: 'manual',
    webhookSecret: '',
  });

  // Evaluación asociada (E.2)
  const [evalForm, setEvalForm] = _tr_useState(() => {
    const existing = (window.EVALUACIONES || []).find(e => e.courseId === ((course && course !== 'externo' ? course.id : '') || ''));
    const c = (course && course !== 'externo') ? course : null;
    return existing ? { ...existing } : {
      id: '',
      courseId: c?.id || '',
      competenciaId: c?.competenciaId || '',
      modo: 'fija',
      preguntasFijas: [],
      poolPorDificultad: { facil: 1, media: 2, dificil: 1 },
      notaMinima: 75,
      tiempoMinutos: 30,
      intentos: 2,
      mostrarRespuestas: false,
    };
  });

  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); };
  }, []);

  // Auto-rellenar normaOrigen al elegir competencia
  const upd = (k, v) => {
    const next = { ...form, [k]: v };
    if (k === 'competenciaId') {
      const cmp = (window.COMPETENCIAS_MAESTRAS || []).find(c => c.id === v);
      if (cmp) next.normaOrigen = cmp.norma;
      setEvalForm(prev => ({ ...prev, competenciaId: v, preguntasFijas: [] }));
    }
    setForm(next);
  };

  const toggleRole = (role) => {
    upd('forRoles', form.forRoles.includes(role) ? form.forRoles.filter(r => r !== role) : [...form.forRoles, role]);
  };

  // Sílabo / módulos
  const addModulo = () => upd('modulos', [...(form.modulos || []), { id: `mod-${Date.now()}`, nombre: 'Nuevo módulo', duracion: '1 h', materiales: [] }]);
  const updModulo = (i, patch) => upd('modulos', form.modulos.map((m, idx) => idx === i ? { ...m, ...patch } : m));
  const delModulo = (i) => upd('modulos', form.modulos.filter((_, idx) => idx !== i));

  // Materiales por módulo
  const addMaterial = (mi) => updModulo(mi, { materiales: [...(form.modulos[mi].materiales || []), { tipo: 'pdf', nombre: 'material.pdf', url: '#', peso: '0 KB' }] });
  const updMaterial = (mi, mati, patch) => updModulo(mi, { materiales: form.modulos[mi].materiales.map((x, idx) => idx === mati ? { ...x, ...patch } : x) });
  const delMaterial = (mi, mati) => updModulo(mi, { materiales: form.modulos[mi].materiales.filter((_, idx) => idx !== mati) });

  // Preguntas (selector de banco existente)
  const banco = (window.BANCO_PREGUNTAS || []).filter(p => p.competenciaId === form.competenciaId);
  const togglePregunta = (id) => {
    setEvalForm(prev => ({
      ...prev,
      preguntasFijas: prev.preguntasFijas.includes(id)
        ? prev.preguntasFijas.filter(x => x !== id)
        : [...prev.preguntasFijas, id]
    }));
  };
  const updEval = (k, v) => setEvalForm({ ...evalForm, [k]: v });
  const updPool = (dif, n) => setEvalForm({ ...evalForm, poolPorDificultad: { ...evalForm.poolPorDificultad, [dif]: parseInt(n) || 0 } });

  // Provider list
  const proveedores = (window.PROVEEDORES || []);
  const cargosNombres = (window.CARGOS || []).map(c => c.nombre);

  const isExtMode = form.mode === 'elearning-externo';
  const canSave = !!(form.name && form.cat && form.mode && form.competenciaId);

  const submit = () => {
    // canSaveFinal cubre los dos flujos: interno (4 campos) y externo express (solo nombre + URL).
    if (!canSaveFinal) return;
    // Para cursos externos, marcar como publicado por defecto si el usuario no eligió otro estado
    const finalForm = (isExtMode && !form.status) ? { ...form, status: 'publicado' } : form;
    onSave(finalForm);

    // Persistir evaluación en el store global (E.2) · solo si el curso es interno y tiene competencia.
    // Los cursos externos no requieren evaluación interna (la hace el proveedor).
    if (!isExtMode && form.competenciaId) {
      const evaluaciones = window.EVALUACIONES || [];
      const idx = evaluaciones.findIndex(e => e.courseId === form.id);
      const evalFinal = { ...evalForm, courseId: form.id, competenciaId: form.competenciaId, id: evalForm.id || `EV-${String(evaluaciones.length + 1).padStart(3, '0')}` };
      if (idx >= 0) {
        window.EVALUACIONES = evaluaciones.map((e, i) => i === idx ? evalFinal : e);
      } else {
        window.EVALUACIONES = [...evaluaciones, evalFinal];
      }
    }
  };

  // Tabs · cuando es e-learning externo (curso de tercero) ocultamos Sílabo y Evaluación
  // porque ese contenido lo provee el proveedor en su plataforma.
  const tabs = [
    { k: 'datos',      l: 'Datos básicos',  ico: 'IconBook' },
    { k: 'silabo',     l: 'Sílabo',         ico: 'IconRocket', show: !isExtMode },
    { k: 'evaluacion', l: 'Evaluación',     ico: 'IconStar',   show: !isExtMode },
    { k: 'elearning',  l: 'Plataforma del proveedor', ico: 'IconExternal', show: isExtMode },
    { k: 'estado',     l: 'Estado · publicación', ico: 'IconShield' },
  ].filter(t => t.show !== false);

  // Si la tab activa quedó oculta (cambio de modalidad), volver a 'datos'
  React.useEffect(() => {
    if (!tabs.find(t => t.k === editTab)) setEditTab('datos');
  }, [isExtMode]);

  // Curso externo express · solo nombre + URL son obligatorios.
  // Plataforma, competencia, categoría son opcionales (se pueden completar luego al editar).
  const canSaveExt = !!(form.name && form.urlAcceso);
  const canSaveFinal = isExtMode ? canSaveExt : canSave;

  const titleSub = externoExpress
    ? 'Vincula un curso e-learning de un proveedor (SENA, ARL, Coursera, etc.). Solo necesitas la URL de acceso.'
    : isExtMode
      ? 'Curso de tercero · el contenido y la evaluación los provee el proveedor en su plataforma.'
      : 'Define el curso, su sílabo, la evaluación que aplica al cierre y, si es e-learning externo, la plataforma del proveedor.';

  return (
    <div className="modal-overlay" onMouseDown={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 980, height: 'calc(100vh - 64px)' }}>
        <div className="modal-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>
              {externoExpress ? 'Curso de tercero' : (isNew ? 'Nuevo curso' : `${form.id} · ${form.version}`)}
            </div>
            <div className="modal-title">
              {externoExpress
                ? 'Vincular curso de proveedor externo'
                : (isNew ? 'Crear curso del catálogo' : `Editar · ${course.name}`)}
            </div>
            <div className="modal-sub">{titleSub}</div>
          </div>
          <button className="icon-btn" onClick={onClose}><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="doc-tabs" style={{ margin: '0 24px', marginBottom: 0, borderBottom: '1px solid var(--border)' }}>
          {tabs.map(t => {
            const Ico = window[t.ico];
            return (
              <button key={t.k} className={`doc-tab ${editTab === t.k ? 'active' : ''}`} onClick={() => setEditTab(t.k)}>
                <Ico size={13} /> {t.l}
              </button>
            );
          })}
        </div>

        <div className="modal-body" style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>

          {/* TAB · Datos básicos */}
          {editTab === 'datos' && (
            <div className="ic-cap-section">
              <div className="ic-cap-setup-grid">
                <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                  <div className="muted-xs">Nombre del curso *</div>
                  <input className="ic-cap-version" type="text" value={form.name} onChange={e => upd('name', e.target.value)} placeholder="Manejo seguro de maquinaria de clasificación" />
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Categoría *</div>
                  <select className="ic-cap-version" value={form.cat} onChange={e => upd('cat', e.target.value)}>
                    {Object.entries(TR_CATS).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
                  </select>
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Modalidad *</div>
                  <select className="ic-cap-version" value={form.mode} onChange={e => upd('mode', e.target.value)}>
                    {Object.entries(TR_MODES).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
                  </select>
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Duración</div>
                  <input className="ic-cap-version" type="text" value={form.duration} onChange={e => upd('duration', e.target.value)} placeholder="8 h" />
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Nota mínima de aprobación</div>
                  <input className="ic-cap-version" type="number" min={0} max={100} value={form.minScore} onChange={e => upd('minScore', parseInt(e.target.value) || 0)} />
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Competencia que cubre {!isExtMode && '*'}{isExtMode && <span className="muted">(opcional · curso externo)</span>}</div>
                  <select className="ic-cap-version" value={form.competenciaId} onChange={e => upd('competenciaId', e.target.value)}>
                    <option value="">— {isExtMode ? 'Sin competencia vinculada' : 'Selecciona'} —</option>
                    {(window.COMPETENCIAS_MAESTRAS || []).map(c => <option key={c.id} value={c.id}>{c.id} · {c.name}</option>)}
                  </select>
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Norma origen (auto)</div>
                  <input className="ic-cap-version" type="text" value={form.normaOrigen} onChange={e => upd('normaOrigen', e.target.value)} placeholder="Resolución 0312 de 2019 · SG-SST" />
                </div>
                <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                  <div className="muted-xs">Proveedor preferente</div>
                  <select className="ic-cap-version" value={form.proveedorId} onChange={e => upd('proveedorId', e.target.value)}>
                    <option value="">— Sin proveedor preferente —</option>
                    {proveedores.map(p => <option key={p.id} value={p.id}>{p.razonSocial}</option>)}
                  </select>
                </div>
                <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                  <div className="muted-xs">Descripción</div>
                  <textarea className="ic-cap-version" rows={3} value={form.description} onChange={e => upd('description', e.target.value)} placeholder="Curso obligatorio para personal que opera o supervisa máquinas trituradoras…" />
                </div>
                <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                  <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13 }}>
                    <input type="checkbox" checked={form.mandatory} onChange={e => upd('mandatory', e.target.checked)} />
                    Curso obligatorio
                  </label>
                </div>
                <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                  <div className="muted-xs">Cargos a los que aplica</div>
                  <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 6 }}>
                    {cargosNombres.map(role => {
                      const sel = form.forRoles.includes(role);
                      return (
                        <button key={role} onClick={() => toggleRole(role)} className={`pill ${sel ? 'green' : 'navy-soft'}`} style={{ cursor: 'pointer', border: 'none', fontSize: 11 }}>
                          {sel && <IconCheck size={10} />} {role}
                        </button>
                      );
                    })}
                  </div>
                </div>
              </div>
            </div>
          )}

          {/* TAB · Sílabo */}
          {editTab === 'silabo' && (
            <div className="ic-cap-section">
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
                <h3 className="ic-cap-h3" style={{ margin: 0 }}>Módulos del curso · {(form.modulos || []).length}</h3>
                <button className="btn primary" onClick={addModulo}><IconPlus size={12} /> Agregar módulo</button>
              </div>

              {(form.modulos || []).length === 0 && (
                <div className="muted" style={{ fontSize: 13, padding: 22, textAlign: 'center', background: 'var(--surface)', borderRadius: 10 }}>
                  Agrega al menos un módulo. Cada módulo puede tener tópicos y materiales adjuntos.
                </div>
              )}

              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {(form.modulos || []).map((m, mi) => (
                  <div key={mi} style={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 10, padding: 12 }}>
                    <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
                      <span className="mono muted" style={{ fontSize: 10.5, width: 24 }}>{String(mi + 1).padStart(2, '0')}</span>
                      <input className="ic-cap-version" style={{ flex: 1 }} type="text" value={m.nombre} onChange={e => updModulo(mi, { nombre: e.target.value })} />
                      <input className="ic-cap-version" style={{ width: 80 }} type="text" value={m.duracion} onChange={e => updModulo(mi, { duracion: e.target.value })} placeholder="1.5 h" />
                      <button className="icon-btn" onClick={() => delModulo(mi)} title="Quitar módulo">
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2m3 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" /></svg>
                      </button>
                    </div>

                    {(m.materiales || []).length > 0 && (
                      <div style={{ marginTop: 10, marginLeft: 34, display: 'flex', flexDirection: 'column', gap: 8 }}>
                        {m.materiales.map((mat, mati) => (
                          <MaterialEditor
                            key={mati}
                            material={mat}
                            onUpdate={(patch) => updMaterial(mi, mati, patch)}
                            onDelete={() => delMaterial(mi, mati)}
                          />
                        ))}
                      </div>
                    )}
                    <button className="btn" onClick={() => addMaterial(mi)} style={{ marginTop: 10, marginLeft: 34, fontSize: 11.5 }}><IconPlus size={11} /> Material</button>
                  </div>
                ))}
              </div>
            </div>
          )}

          {/* TAB · Evaluación (E.2) */}
          {editTab === 'evaluacion' && (
            <div className="ic-cap-section">
              <h3 className="ic-cap-h3">Constructor de evaluación</h3>
              <p className="muted" style={{ fontSize: 13, marginTop: -4 }}>
                Define el examen que aplica al cierre de la sesión. Las preguntas vienen del banco asociado a la competencia <b>{form.competenciaId || '—'}</b>.
              </p>

              {!form.competenciaId && (
                <div className="ic-cap-info" style={{ marginTop: 8 }}>
                  <IconAlert size={13} />
                  <span>Primero selecciona una competencia en la pestaña <b>Datos básicos</b>.</span>
                </div>
              )}

              {form.competenciaId && (
                <>
                  <div className="ic-cap-setup-grid" style={{ marginTop: 10 }}>
                    <div className="ic-cap-field">
                      <div className="muted-xs">Modo</div>
                      <select className="ic-cap-version" value={evalForm.modo} onChange={e => updEval('modo', e.target.value)}>
                        <option value="fija">Preguntas fijas (todos ven las mismas)</option>
                        <option value="pool-aleatorio">Pool aleatorio por dificultad</option>
                      </select>
                    </div>
                    <div className="ic-cap-field">
                      <div className="muted-xs">Nota mínima</div>
                      <input className="ic-cap-version" type="number" min={0} max={100} value={evalForm.notaMinima} onChange={e => updEval('notaMinima', parseInt(e.target.value) || 0)} />
                    </div>
                    <div className="ic-cap-field">
                      <div className="muted-xs">Tiempo (minutos)</div>
                      <input className="ic-cap-version" type="number" min={1} value={evalForm.tiempoMinutos} onChange={e => updEval('tiempoMinutos', parseInt(e.target.value) || 0)} />
                    </div>
                    <div className="ic-cap-field">
                      <div className="muted-xs">Intentos</div>
                      <input className="ic-cap-version" type="number" min={1} max={10} value={evalForm.intentos} onChange={e => updEval('intentos', parseInt(e.target.value) || 1)} />
                    </div>
                    <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                      <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13 }}>
                        <input type="checkbox" checked={evalForm.mostrarRespuestas} onChange={e => updEval('mostrarRespuestas', e.target.checked)} />
                        Mostrar respuestas correctas al colaborador después del examen
                      </label>
                    </div>
                  </div>

                  {evalForm.modo === 'pool-aleatorio' && (
                    <div style={{ marginTop: 14, padding: 12, background: 'var(--surface)', borderRadius: 8 }}>
                      <div className="muted-xs" style={{ marginBottom: 8 }}>Configuración del pool aleatorio · cada asistente verá un set distinto</div>
                      <div style={{ display: 'flex', gap: 14 }}>
                        {['facil', 'media', 'dificil'].map(dif => (
                          <div key={dif} style={{ flex: 1 }}>
                            <div className="muted-xs">Preguntas {dif}</div>
                            <input
                              className="ic-cap-version"
                              type="number"
                              min={0}
                              value={evalForm.poolPorDificultad?.[dif] || 0}
                              onChange={e => updPool(dif, e.target.value)}
                            />
                            <div className="muted" style={{ fontSize: 10.5, marginTop: 2 }}>
                              {banco.filter(p => p.dificultad === dif).length} disponibles en banco
                            </div>
                          </div>
                        ))}
                      </div>
                      <div className="muted" style={{ fontSize: 11.5, marginTop: 8 }}>
                        Total por asistente: <b>{Object.values(evalForm.poolPorDificultad || {}).reduce((a, b) => a + b, 0)}</b> preguntas
                      </div>
                    </div>
                  )}

                  {evalForm.modo === 'fija' && (
                    <div style={{ marginTop: 14 }}>
                      <div className="muted-xs" style={{ marginBottom: 8 }}>
                        Preguntas seleccionadas · {evalForm.preguntasFijas.length} de {banco.length} en banco
                      </div>
                      <div style={{ maxHeight: 320, overflow: 'auto', border: '1px solid var(--border)', borderRadius: 8 }}>
                        {banco.length === 0 && (
                          <div className="muted" style={{ fontSize: 12, padding: 18, textAlign: 'center' }}>
                            No hay preguntas en el banco para esta competencia. (En esta versión del prototipo el banco viene precargado por seed; el editor de banco se abordará en una iteración posterior.)
                          </div>
                        )}
                        {banco.map(p => {
                          const sel = evalForm.preguntasFijas.includes(p.id);
                          return (
                            <label key={p.id} style={{ display: 'flex', alignItems: 'flex-start', gap: 10, padding: 10, borderBottom: '1px solid var(--border)', cursor: 'pointer', background: sel ? '#F0FDF4' : 'white' }}>
                              <input type="checkbox" checked={sel} onChange={() => togglePregunta(p.id)} style={{ marginTop: 3 }} />
                              <div style={{ flex: 1 }}>
                                <div style={{ display: 'flex', gap: 6, alignItems: 'center', marginBottom: 4 }}>
                                  <span className="mono" style={{ fontSize: 10.5, color: 'var(--text-muted)' }}>{p.id}</span>
                                  <span className={`pill ${p.dificultad === 'facil' ? 'green' : p.dificultad === 'media' ? 'amber-soft' : 'rose'}`} style={{ fontSize: 10 }}>{p.dificultad}</span>
                                  <span className="pill navy-soft" style={{ fontSize: 10 }}>{p.tipo}</span>
                                </div>
                                <div style={{ fontSize: 12.5, fontWeight: 500 }}>{p.enunciado}</div>
                                <div className="muted" style={{ fontSize: 11, marginTop: 2 }}>
                                  Correcta: <b>{String.fromCharCode(65 + p.respuestaCorrecta)})</b> {p.opciones[p.respuestaCorrecta]}
                                </div>
                              </div>
                            </label>
                          );
                        })}
                      </div>
                    </div>
                  )}
                </>
              )}
            </div>
          )}

          {/* TAB · E-learning externo (E.3) */}
          {editTab === 'elearning' && (
            <div className="ic-cap-section">
              <h3 className="ic-cap-h3">{externoExpress ? 'Vincular curso del proveedor' : 'Vinculación con plataforma externa'}</h3>
              <p className="muted" style={{ fontSize: 13, marginTop: -4 }}>
                {externoExpress
                  ? <>Solo necesitas <b>nombre del curso</b> y la <b>URL</b> donde el colaborador accederá. Lo demás (plataforma, sincronización, competencia) es opcional.</>
                  : <>El curso se imparte en la plataforma del proveedor. Atica archiva el resultado mediante carga manual o webhook simulado.</>}
              </p>

              <div className="ic-cap-setup-grid" style={{ marginTop: 10 }}>
                {/* Cuando es express, los campos críticos van arriba y a todo el ancho */}
                {externoExpress && (
                  <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                    <div className="muted-xs">Nombre del curso *</div>
                    <input className="ic-cap-version" type="text" value={form.name} onChange={e => upd('name', e.target.value)} placeholder="Ej. Manejo defensivo · SOFIA Plus" autoFocus />
                  </div>
                )}
                <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                  <div className="muted-xs">URL de acceso para el colaborador *</div>
                  <input className="ic-cap-version" type="url" value={form.urlAcceso} onChange={e => upd('urlAcceso', e.target.value)} placeholder="https://oferta.senasofiaplus.edu.co/curso/..." />
                  <div className="muted" style={{ fontSize: 11, marginTop: 3 }}>El colaborador la abrirá desde el portal con un botón "Ir a la plataforma".</div>
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Plataforma {externoExpress && <span className="muted">(opcional)</span>}</div>
                  <select className="ic-cap-version" value={form.plataforma} onChange={e => upd('plataforma', e.target.value)}>
                    <option value="">— Otro proveedor —</option>
                    {PLATAFORMAS_ELEARNING.map(p => <option key={p.id} value={p.id}>{p.label}</option>)}
                  </select>
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Método de sincronización</div>
                  <select className="ic-cap-version" value={form.metodoSync} onChange={e => upd('metodoSync', e.target.value)}>
                    <option value="manual">Manual · autocertificación del colaborador</option>
                    <option value="webhook-mock">Webhook · mock</option>
                    <option value="scorm-mock">SCORM · mock</option>
                  </select>
                </div>
                {form.metodoSync === 'webhook-mock' && (
                  <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                    <div className="muted-xs">Webhook secret (firma del proveedor)</div>
                    <input className="ic-cap-version mono" type="text" value={form.webhookSecret} onChange={e => upd('webhookSecret', e.target.value)} placeholder="whsec_..." />
                  </div>
                )}
                {externoExpress && (
                  <>
                    <div className="ic-cap-field">
                      <div className="muted-xs">Categoría {externoExpress && <span className="muted">(opcional)</span>}</div>
                      <select className="ic-cap-version" value={form.cat} onChange={e => upd('cat', e.target.value)}>
                        {Object.entries(TR_CATS).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
                      </select>
                    </div>
                    <div className="ic-cap-field">
                      <div className="muted-xs">Duración estimada {externoExpress && <span className="muted">(opcional)</span>}</div>
                      <input className="ic-cap-version" type="text" value={form.duration} onChange={e => upd('duration', e.target.value)} placeholder="6 h" />
                    </div>
                    <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                      <div className="muted-xs">Competencia que cubre <span className="muted">(opcional)</span></div>
                      <select className="ic-cap-version" value={form.competenciaId} onChange={e => upd('competenciaId', e.target.value)}>
                        <option value="">— Sin competencia vinculada —</option>
                        {(window.COMPETENCIAS_MAESTRAS || []).map(c => <option key={c.id} value={c.id}>{c.id} · {c.name}</option>)}
                      </select>
                      <div className="muted" style={{ fontSize: 11, marginTop: 3 }}>Si vinculas una competencia, el curso aparecerá como opción en planes formativos que la requieran.</div>
                    </div>
                  </>
                )}
              </div>

              <div className="ic-cap-info" style={{ marginTop: 14 }}>
                <IconShield size={13} />
                <span>
                  En el portal del colaborador este curso aparece con botón <b>"Ir a la plataforma"</b> y <b>"Marcar como completado"</b>. Al confirmar el completado el colaborador firma electrónicamente la declaración (Ley 527/1999) e Atica emite un certificado interno.
                </span>
              </div>
            </div>
          )}

          {/* TAB · Estado y publicación */}
          {editTab === 'estado' && (
            <div className="ic-cap-section">
              <div className="ic-cap-setup-grid">
                <div className="ic-cap-field">
                  <div className="muted-xs">Estado *</div>
                  <select className="ic-cap-version" value={form.status} onChange={e => upd('status', e.target.value)}>
                    <option value="borrador">Borrador (no aparece en plan formativo)</option>
                    <option value="publicado">Publicado (disponible para programar sesiones)</option>
                    <option value="retirado">Retirado (no se programa, historial intacto)</option>
                  </select>
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Versión</div>
                  <input className="ic-cap-version mono" type="text" value={form.version} onChange={e => upd('version', e.target.value)} placeholder="v1.0" />
                </div>
                <div className="ic-cap-field" style={{ gridColumn: '1 / -1' }}>
                  <div className="muted-xs">Changelog · qué cambió en esta versión</div>
                  <textarea className="ic-cap-version" rows={3} value={form.changelog} onChange={e => upd('changelog', e.target.value)} placeholder="Actualización LOTO · adición sección venteo·…" />
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Publicado en</div>
                  {window.DateInputCO
                    ? <window.DateInputCO className="ic-cap-version" value={form.publicadoEn} onChange={(v) => upd('publicadoEn', v)} />
                    : <input className="ic-cap-version" type="text" value={form.publicadoEn} onChange={e => upd('publicadoEn', e.target.value)} />}
                </div>
                <div className="ic-cap-field">
                  <div className="muted-xs">Publicado por</div>
                  <input className="ic-cap-version" type="text" value={form.publicadoPor} onChange={e => upd('publicadoPor', e.target.value)} placeholder="Carolina Restrepo · Jefe RRHH" />
                </div>
              </div>

              <div className="ic-cap-info" style={{ marginTop: 14 }}>
                <IconShield size={13} />
                <span>
                  Las sesiones cerradas conservan la versión del contenido que tenían anclada. Cambiar la versión solo afecta sesiones futuras.
                </span>
              </div>
            </div>
          )}
        </div>

        <div className="modal-foot">
          <span className="muted" style={{ fontSize: 11.5, alignSelf: 'center' }}>
            {form.status === 'publicado' ? '🟢 Publicado · disponible para sesiones' : form.status === 'retirado' ? '🔴 Retirado · solo histórico' : '🟡 Borrador · no se puede programar'}
          </span>
          <div style={{ flex: 1 }} />
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" onClick={submit} disabled={!canSaveFinal}>
            <IconCheck size={13} /> {isNew ? (externoExpress ? 'Vincular curso externo' : 'Crear curso') : 'Guardar cambios'}
          </button>
        </div>
      </div>
    </div>
  );
};

window.Training = Training;
window.COURSES = COURSES;
