// Settings module — admin configuration center
// 7 categories: Matrices, Parámetros, Contratos, Flujos, Plantillas, Centros costo, Usuarios
const { useState: _cf_useState } = React;

// ─── Matrices por cargo ──────────────────────────────────

const ROLE_MATRICES_FULL = [
  {
    id: 'op-tostion', role: 'Operario de Clasificación',     active: 142, updated: '12/04/2026',
    counts: { dot: 4, epp: 6, cap: 6, exa: 3, doc: 5, onb: 12 },
  },
  {
    id: 'op-aprovechamiento', role: 'Op. Aprovechamiento',             active: 98,  updated: '08/04/2026',
    counts: { dot: 3, epp: 4, cap: 4, exa: 3, doc: 5, onb: 11 },
  },
  {
    id: 'tec-mant',   role: 'Téc. Mantenimiento',      active: 22,  updated: '15/04/2026',
    counts: { dot: 2, epp: 7, cap: 6, exa: 4, doc: 6, onb: 14 },
  },
  {
    id: 'conductor',  role: 'Conductor',                active: 18,  updated: '02/04/2026',
    counts: { dot: 2, epp: 3, cap: 4, exa: 3, doc: 5, onb: 10 },
  },
  {
    id: 'aux-cal',    role: 'Aux. Calidad',             active: 14,  updated: '20/03/2026',
    counts: { dot: 2, epp: 4, cap: 4, exa: 3, doc: 5, onb: 11 },
  },
  {
    id: 'lid-aprovechamiento',role: 'Líder de Aprovechamiento',         active: 6,   updated: '05/04/2026',
    counts: { dot: 3, epp: 4, cap: 7, exa: 3, doc: 6, onb: 13 },
  },
  {
    id: 'aux-rrhh',   role: 'Aux. Recursos Humanos',    active: 4,   updated: '15/02/2026',
    counts: { dot: 2, epp: 0, cap: 4, exa: 2, doc: 5, onb: 9 },
  },
  {
    id: 'jefe-rrhh',  role: 'Jefe de RRHH',             active: 1,   updated: '15/02/2026',
    counts: { dot: 2, epp: 0, cap: 6, exa: 2, doc: 5, onb: 9 },
  },
];

// Full matrix for Operario de Clasificación (used in editor)
const MATRIX_OP_TOSTION = {
  dotacion: [
    { name: 'Uniforme operario clasificación',  qty: 2, size: 'Talla', mandatory: true,  moment: 'ingreso',   freq: 'Anual' },
    { name: 'Pantalón industrial drill',  qty: 2, size: 'Talla', mandatory: true,  moment: 'ingreso',   freq: 'Anual' },
    { name: 'Camisa polo corporativa',    qty: 1, size: 'Talla', mandatory: false, moment: 'ingreso',   freq: 'Por desgaste' },
    { name: 'Cofia desechable',           qty: 30, size: 'Única', mandatory: true, moment: 'periodico', freq: 'Mensual' },
  ],
  epp: [
    { name: 'Guantes térmicos Kevlar 350°C', qty: 1, size: 'Talla', mandatory: true, moment: 'periodico', freq: 'Por desgaste' },
    { name: 'Botas dieléctricas con puntera', qty: 1, size: 'Talla', mandatory: true, moment: 'ingreso',   freq: 'Anual' },
    { name: 'Casco industrial clase E',       qty: 1, size: 'Única', mandatory: true, moment: 'ingreso',   freq: 'Por desgaste' },
    { name: 'Protector auditivo copa 25 dB',  qty: 1, size: 'Única', mandatory: true, moment: 'ingreso',   freq: 'Semestral' },
    { name: 'Gafas de seguridad',             qty: 1, size: 'Única', mandatory: false,moment: 'periodico', freq: 'Por desgaste' },
    { name: 'Faja lumbar ergonómica',         qty: 1, size: 'Talla', mandatory: false,moment: 'periodico', freq: 'Por desgaste' },
  ],
  capacitaciones: [
    { name: 'Manejo seguro de maquinaria de clasificación', mandatory: true,  delay: 7,   recur: 'Anual',     duration: '8 h' },
    { name: 'Buenas Prácticas de Manufactura (BPM)',   mandatory: true,  delay: 14,  recur: 'Anual',     duration: '4 h' },
    { name: 'Manipulación de alimentos',               mandatory: true,  delay: 21,  recur: 'Anual',     duration: '3 h' },
    { name: 'Reglamento Interno · RIT',                mandatory: true,  delay: 5,   recur: 'Por cambio',duration: '2 h' },
    { name: 'Clasificación avanzada de residuos',       mandatory: false, delay: 90,  recur: 'Una vez',   duration: '12 h' },
    { name: 'Brigada de emergencias',                  mandatory: false, delay: 180, recur: 'Anual',     duration: '16 h' },
  ],
  examenes: [
    { type: 'Examen médico de ingreso',           delay: 5,  freq: 'Una vez',  lab: 'IPS Megacentro · Cali' },
    { type: 'Examen médico periódico',            delay: 365,freq: 'Anual',    lab: 'IPS Megacentro · Cali' },
    { type: 'Audiometría · ruido ocupacional',     delay: 30, freq: 'Anual',    lab: 'IPS Audiocom' },
  ],
  documentos: [
    { type: 'Contrato laboral · indefinido',       moment: 'ingreso',  signers: ['Colaborador', 'Rep. Legal'] },
    { type: 'Reglamento Interno · constancia',     moment: 'ingreso',  signers: ['Colaborador'] },
    { type: 'Acuerdo de confidencialidad',         moment: 'ingreso',  signers: ['Colaborador', 'Rep. Legal'] },
    { type: 'Autorización tratamiento de datos',   moment: 'ingreso',  signers: ['Colaborador'] },
    { type: 'Paz y salvo',                         moment: 'retiro',   signers: ['Colaborador', 'RRHH'] },
  ],
  onboarding: [
    { task: 'Firmar contrato y documentos legales',  owner: 'Carolina Restrepo · RRHH',     days: 1, order: 1 },
    { task: 'Recibir dotación y EPP completos',      owner: 'Patricia Gómez · Bienestar',   days: 2, order: 2 },
    { task: 'Examen médico de ingreso',              owner: 'IPS Megacentro',                days: 5, order: 3 },
    { task: 'Inducción Atica (e-learning)',    owner: 'Plataforma',                    days: 3, order: 4 },
    { task: 'Tour de instalaciones · zona clasificación',  owner: 'Luis Miguel Marín · Líder',     days: 4, order: 5 },
    { task: 'Capacitación SST específica',           owner: 'C. F. Vélez · ARL Sura',        days: 7, order: 6 },
    { task: 'Pareja sombra · primer turno',          owner: 'Carlos Andrés Vélez · mentor',  days: 8, order: 7 },
    { task: 'Apertura cuenta nómina',                owner: 'Banco · Davivienda',            days: 10, order: 8 },
    { task: 'Asignación EPS y AFP',                  owner: 'Carolina Restrepo · RRHH',     days: 10, order: 9 },
    { task: 'Reunión 1:1 con jefe directo',          owner: 'Luis Miguel Marín',             days: 14, order: 10 },
    { task: 'Evaluación período de prueba',          owner: 'Luis Miguel Marín',             days: 60, order: 11 },
    { task: 'Cierre formal de onboarding',           owner: 'Carolina Restrepo · RRHH',     days: 90, order: 12 },
  ],
};

// ─── Flujos de aprobación ────────────────────────────────

const FLOWS = [
  {
    id: 'fl-vac', type: 'Vacaciones', active: true,
    steps: [
      { role: 'Jefe directo',      sla: 24,  escalation: 'RRHH' },
      { role: 'RRHH',              sla: 48,  escalation: 'Dirección' },
    ],
    description: 'Solicitud de vacaciones programadas. Requiere validación de operación antes de bloquear el calendario.',
  },
  {
    id: 'fl-perm', type: 'Permisos remunerados', active: true,
    steps: [
      { role: 'Jefe directo',      sla: 8,   escalation: 'RRHH' },
    ],
    description: 'Permisos cortos (citas, diligencias). Aprobación rápida del jefe.',
  },
  {
    id: 'fl-inca', type: 'Incapacidades', active: true,
    steps: [
      { role: 'RRHH',              sla: 12,  escalation: 'Dirección' },
      { role: 'ARL · si aplica',   sla: 72,  escalation: 'Notificación legal' },
    ],
    description: 'Reporte de incapacidad médica con soporte de IPS. Salta jefe directo, va directo a RRHH.',
  },
  {
    id: 'fl-nov', type: 'Novedades de nómina', active: true,
    steps: [
      { role: 'Jefe directo',      sla: 24,  escalation: 'RRHH' },
      { role: 'RRHH',              sla: 24,  escalation: 'Dirección' },
      { role: 'Contabilidad',      sla: 48,  escalation: 'CFO' },
    ],
    description: 'Cambios salariales, bonificaciones, descuentos. Triple validación obligatoria.',
  },
  {
    id: 'fl-cont', type: 'Contratación · nuevo ingreso', active: true,
    steps: [
      { role: 'Jefe del área',     sla: 48,  escalation: 'RRHH' },
      { role: 'RRHH',              sla: 24,  escalation: 'Dirección' },
      { role: 'Dirección',         sla: 24,  escalation: 'CEO' },
    ],
    description: 'Apertura formal de vacante hasta firma del contrato.',
  },
  {
    id: 'fl-ret', type: 'Retiros y liquidaciones', active: false,
    steps: [
      { role: 'Jefe directo',      sla: 24,  escalation: 'RRHH' },
      { role: 'RRHH',              sla: 48,  escalation: 'Dirección' },
      { role: 'Contabilidad',      sla: 72,  escalation: 'CFO' },
    ],
    description: 'Proceso de salida. Requiere paz y salvo de todas las áreas.',
  },
];

// ─── Tipos de contrato ───────────────────────────────────

const CONTRACT_TYPES = [
  { id: 'ind',  label: 'Indefinido',           prob: 60, ces: true,  acc: '4.350%',  used: 612, code: 'CTI', tone: 'navy'  },
  { id: 'fij',  label: 'Fijo · 1 año',         prob: 60, ces: true,  acc: '4.350%',  used: 142, code: 'CTF', tone: 'blue'  },
  { id: 'apr',  label: 'Aprendizaje SENA',     prob: 0,  ces: false, acc: '0.522%',  used: 38,  code: 'APR', tone: 'amber' },
  { id: 'obr',  label: 'Obra o labor',         prob: 0,  ces: true,  acc: '6.960%',  used: 32,  code: 'COL', tone: 'rose'  },
];

// ─── Centros de costo ────────────────────────────────────

const COST_CENTERS = [
  { code: 'CC-100', name: 'Operaciones · Clasificación',       site: 'Cali',   responsible: 'Luis Miguel Marín',  active: 142, budget: '$214M' },
  { code: 'CC-110', name: 'Operaciones · Aprovechamiento',       site: 'Cali',   responsible: 'Luis Miguel Marín',  active: 98,  budget: '$148M' },
  { code: 'CC-200', name: 'Calidad · Laboratorio',      site: 'Cali',   responsible: 'Patricia Gómez',     active: 14,  budget: '$28M' },
  { code: 'CC-210', name: 'Calidad · Barranquilla',        site: 'Barranquilla', responsible: 'Sandra M. Ortiz',    active: 8,   budget: '$15M' },
  { code: 'CC-300', name: 'Mantenimiento · Planta',     site: 'Cali',   responsible: 'Paula Valencia',     active: 22,  budget: '$48M' },
  { code: 'CC-400', name: 'Recolección · Vehículos',   site: 'Barranquilla', responsible: 'Jorge Iván Patiño',  active: 18,  budget: '$72M' },
  { code: 'CC-500', name: 'Administración · RRHH',      site: 'Cali',   responsible: 'Carolina Restrepo',  active: 5,   budget: '$32M' },
  { code: 'CC-510', name: 'Administración · Compras',   site: 'Bogotá',    responsible: 'Sandra M. Ortiz',    active: 4,   budget: '$28M' },
];

// ─── Parámetros legales ──────────────────────────────────

const LEGAL_PARAMS = [
  { key: 'smmlv',           label: 'Salario Mínimo Mensual Legal Vigente', value: '$1.423.500',           unit: 'COP/mes',  effective: '01/01/2026' },
  { key: 'aux-trans',       label: 'Auxilio de transporte',                value: '$200.000',             unit: 'COP/mes',  effective: '01/01/2026' },
  { key: 'jornada-max',     label: 'Jornada máxima legal',                 value: '48',                   unit: 'horas/sem',effective: '15/07/2025' },
  { key: 'horas-extras',    label: 'Recargo horas extras diurnas',         value: '25%',                  unit: 'sobre hora', effective: '01/01/2025' },
  { key: 'horas-nocturnas', label: 'Recargo trabajo nocturno',             value: '35%',                  unit: 'sobre hora', effective: '01/01/2025' },
  { key: 'ces',             label: 'Cesantías · % sobre salario',          value: '8.33%',                unit: 'mensual',  effective: '01/01/2025' },
  { key: 'int-ces',         label: 'Intereses sobre cesantías',            value: '12%',                  unit: 'anual',    effective: '01/01/2025' },
  { key: 'prima',           label: 'Prima de servicios',                   value: '8.33%',                unit: 'mensual',  effective: '01/01/2025' },
  { key: 'vac',             label: 'Días de vacaciones · año causado',     value: '15',                   unit: 'días hábiles', effective: '01/01/2025' },
];

// ─── Plantillas ──────────────────────────────────────────

const TEMPLATES_LINK = [
  { id: 't-01', name: 'Contrato laboral · indefinido', type: 'Contrato',    version: 'v3.2', uses: 247 },
  { id: 't-02', name: 'Contrato laboral · fijo',       type: 'Contrato',    version: 'v2.8', uses: 84 },
  { id: 't-03', name: 'Reglamento interno',            type: 'Reglamento',  version: 'v1.4', uses: 847 },
  { id: 't-04', name: 'Certificación laboral',         type: 'Certificación',version: 'v2.1', uses: 412 },
  { id: 't-05', name: 'Acuerdo de confidencialidad',   type: 'Acuerdo',     version: 'v1.2', uses: 156 },
  { id: 't-06', name: 'Paz y salvo',                   type: 'Paz y salvo', version: 'v1.0', uses: 38 },
];

// ─── Usuarios y roles ────────────────────────────────────
// La cuenta de acceso nace automáticamente al crear el empleado — por eso no
// existe alta manual aquí. Cada usuario referencia su empleado real en
// window.EMPLOYEES vía empleadoId (mismo helper getEmpleadoById de Sociedades).

const ROLE_META = {
  admin:      { label: 'Administrador',     tone: 'rose',  desc: 'Acceso total al sistema' },
  rrhh:       { label: 'RRHH',              tone: 'navy',  desc: 'Gestión de talento y nómina' },
  direccion:  { label: 'Dirección',         tone: 'amber', desc: 'Aprobaciones ejecutivas' },
  jefe:       { label: 'Jefe directo',      tone: 'blue',  desc: 'Equipo a cargo' },
  operativo:  { label: 'Operativo',         tone: 'green', desc: 'Acceso a su ficha y portal' },
};

// Solo 3 estados de cuenta — sin Bloqueado/Suspendido ni similares.
const STATE_USER = {
  activo:    { label: 'Activo',    pill: 'green',      dot: 'var(--green-600)' },
  pendiente: { label: 'Pendiente', pill: 'amber-soft', dot: '#854D0E' },
  inactivo:  { label: 'Inactivo',  pill: 'navy',       dot: 'var(--text-muted)' },
};

// Mismas 5 sociedades de SOCIEDADES_SEED (más abajo en este archivo) y las
// oficinas de venta ya usadas en el Dashboard (components/dashboard.jsx ·
// EP_GRUPOS), para que "sociedad" y "oficina de venta" signifiquen lo mismo
// en toda la plataforma. Se agrega Cartagena para ampliar la cobertura Caribe.
const USER_SOCIEDADES = ['ASEI', 'IA4 SAS', 'ECOENTORNO', 'ECOLOGISTICA', 'BYC'];

const OFICINAS_VENTA_SEED = [
  { codigo: '2201', sociedad: 'ASEI', ciudad: 'Cali' },
  { codigo: '2302', sociedad: 'ASEI', ciudad: 'Barranquilla' },
  { codigo: '2101', sociedad: 'ASEI', ciudad: 'Bogotá' },
  { codigo: '2401', sociedad: 'ECOENTORNO', ciudad: 'Cali' },
  { codigo: '2402', sociedad: 'ECOENTORNO', ciudad: 'Yumbo' },
  { codigo: '2403', sociedad: 'ECOENTORNO', ciudad: 'Bogotá' },
  { codigo: '2501', sociedad: 'ECOENTORNO', ciudad: 'Medellín' },
  { codigo: '2601', sociedad: 'ECOLOGISTICA', ciudad: 'Cali' },
  { codigo: '2602', sociedad: 'ECOLOGISTICA', ciudad: 'Barranquilla' },
  { codigo: '2603', sociedad: 'ECOLOGISTICA', ciudad: 'Cartagena' },
  { codigo: '2701', sociedad: 'IA4 SAS', ciudad: 'Bogotá' },
  { codigo: '2702', sociedad: 'IA4 SAS', ciudad: 'Medellín' },
  { codigo: '2801', sociedad: 'BYC', ciudad: 'Santo Domingo' },
];
const oficinaLabel = (codigo) => {
  const o = OFICINAS_VENTA_SEED.find(x => x.codigo === codigo);
  return o ? `${o.codigo} — ${o.sociedad} ${o.ciudad}` : codigo;
};

const PERM_MODULES = [
  { id: 'employees', label: 'Empleados',         icon: 'IconUsers' },
  { id: 'docs',      label: 'Documentos',        icon: 'IconDoc' },
  { id: 'training',  label: 'Capacitaciones',    icon: 'IconBook' },
  { id: 'sst',       label: 'SST',               icon: 'IconShield' },
  { id: 'epp',       label: 'Dotación y EPP',    icon: 'IconShirt' },
  { id: 'recruit',   label: 'Reclutamiento',     icon: 'IconSearch' },
  { id: 'perf',      label: 'Desempeño',         icon: 'IconStar' },
  { id: 'timeoff',   label: 'Vacaciones',        icon: 'IconCalendar' },
  { id: 'comms',     label: 'Comunicaciones',    icon: 'IconMegaphone' },
  { id: 'reports',   label: 'Reportes',          icon: 'IconBarChart' },
  { id: 'settings',  label: 'Configuración',     icon: 'IconSettings' },
];

const PERM_ACTIONS = ['Ver', 'Crear', 'Editar', 'Aprobar', 'Exportar'];

// Mock permission matrix per role
const PERM_MATRIX = {
  admin:     { all: [1,1,1,1,1] },
  rrhh:      {
    employees: [1,1,1,1,1], docs: [1,1,1,1,1], training: [1,1,1,1,1], sst: [1,1,1,1,1],
    epp: [1,1,1,1,1], recruit: [1,1,1,1,1], perf: [1,1,1,0,1], timeoff: [1,0,1,1,1],
    comms: [1,1,1,1,0], reports: [1,0,0,0,1], settings: [1,0,1,0,0],
  },
  direccion: {
    employees: [1,0,0,1,1], docs: [1,0,0,1,1], training: [1,0,0,0,1], sst: [1,0,0,1,1],
    epp: [1,0,0,0,0], recruit: [1,0,0,1,0], perf: [1,0,0,1,1], timeoff: [1,0,0,1,0],
    comms: [1,1,0,1,0], reports: [1,0,0,0,1], settings: [1,0,0,0,0],
  },
  jefe:      {
    employees: [1,0,0,0,0], docs: [1,0,0,0,0], training: [1,0,1,0,0], sst: [1,0,0,0,0],
    epp: [1,0,0,0,0], recruit: [0,0,0,0,0], perf: [1,1,1,1,0], timeoff: [1,0,0,1,0],
    comms: [1,0,0,0,0], reports: [1,0,0,0,1], settings: [0,0,0,0,0],
  },
  operativo: {
    employees: [0,0,0,0,0], docs: [1,0,0,0,0], training: [1,0,0,0,0], sst: [1,0,0,0,0],
    epp: [1,0,0,0,0], recruit: [0,0,0,0,0], perf: [1,0,0,0,0], timeoff: [1,1,0,0,0],
    comms: [1,0,0,0,0], reports: [0,0,0,0,0], settings: [0,0,0,0,0],
  },
};

const getPerms = (role, module) => {
  const m = PERM_MATRIX[role];
  if (m.all) return m.all;
  return m[module] || [0, 0, 0, 0, 0];
};

// ─── Usuarios y roles · helpers ───────────────────────────

const permModuleLabel = (moduleId) => (PERM_MODULES.find(m => m.id === moduleId) || {}).label || moduleId;
const permLabel = (moduleId, actionIndex) => `${permModuleLabel(moduleId)} · ${PERM_ACTIONS[actionIndex]}`;
const permIsGrantedByRole = (role, moduleId, actionIndex) => getPerms(role, moduleId)[actionIndex] === 1;

// Todas las (módulo, acción) que el rol ya otorga — lo "heredado".
const rolePermsList = (role) => {
  const out = [];
  PERM_MODULES.forEach(m => {
    getPerms(role, m.id).forEach((v, i) => { if (v === 1) out.push({ moduleId: m.id, actionIndex: i }); });
  });
  return out;
};

// Permisos extra "aditivos" — nunca deben solapar lo que el rol ya entrega.
// Si el rol cambia y algún extra queda cubierto por el nuevo rol, se filtra
// aquí para no duplicar ni mostrar un permiso extra que ya es heredado.
const effectiveExtraPerms = (user) => (user.permisosExtra || []).filter(
  p => !permIsGrantedByRole(user.rol, p.moduleId, p.actionIndex)
);

const formatAlcance = (user) => {
  if (user.todasSociedades) return 'Todas las sociedades';
  const nSoc = (user.sociedades || []).length;
  const nOfi = (user.oficinas || []).length;
  if (nSoc === 0) return 'Sin alcance asignado';
  return `${nSoc} sociedad${nSoc === 1 ? '' : 'es'} · ${nOfi} oficina${nOfi === 1 ? '' : 's'}`;
};

const maskPhone = (tel) => {
  if (!tel) return null;
  const parts = tel.split(' ');
  if (parts.length !== 4) return tel;
  return `${parts[0]} ••• ••• ${parts[3]}`;
};

const maskEmail = (email) => {
  if (!email) return null;
  const [user, domain] = email.split('@');
  if (!domain) return email;
  const visible = user.slice(0, 2);
  return `${visible}${'•'.repeat(Math.max(user.length - 2, 3))}@${domain}`;
};

// ─── Usuarios y roles · datos mock ────────────────────────
// Cada usuario referencia un colaborador real de window.EMPLOYEES
// (empleadoId) — nombre, tipo/número de documento y cargo se leen de ahí;
// aquí solo vive lo propio de la cuenta de acceso.

const USERS = [
  {
    id: 'USR-0001', empleadoId: 'E0023', initials: 'CR',
    telefono: '+57 315 442 8801', telefonoVerificado: true, fechaModTelefono: '10/01/2020', responsableModTelefono: 'Sistema · alta automática',
    whatsappAutorizado: true,
    correo: 'carolina.restrepo@atica.co', correoVerificado: true,
    rol: 'admin', permisosExtra: [],
    todasSociedades: true, sociedades: [], oficinas: [],
    fechaCreacion: '10/01/2020', fechaActivacion: '10/01/2020', ultimoAcceso: 'Hace 5 min', ultimoCambioPassword: '02/03/2026',
    canalActivacion: 'Correo corporativo',
    estado: 'activo',
    historial: [
      { fecha: '10/01/2020 08:02', accion: 'Cuenta creada', responsable: 'Sistema · HCM Atica', detalle: 'Generada automáticamente al crear el empleado' },
      { fecha: '10/01/2020 08:15', accion: 'Código enviado', responsable: 'Sistema · HCM Atica', detalle: 'Correo corporativo · entregado' },
      { fecha: '10/01/2020 08:20', accion: 'Cuenta activada', responsable: 'Carolina Restrepo Salazar', detalle: 'Vía correo corporativo' },
      { fecha: '02/03/2026 11:40', accion: 'Cambio de contraseña', responsable: 'Carolina Restrepo Salazar', detalle: 'Autogestión' },
    ],
  },
  {
    id: 'USR-0002', empleadoId: 'E0094', initials: 'MT',
    telefono: '+57 300 512 7734', telefonoVerificado: true, fechaModTelefono: '17/08/2022', responsableModTelefono: 'Sistema · alta automática',
    whatsappAutorizado: true,
    correo: 'maria.trujillo@atica.co', correoVerificado: true,
    rol: 'rrhh',
    permisosExtra: [{ moduleId: 'reports', actionIndex: 4 }, { moduleId: 'recruit', actionIndex: 1 }],
    todasSociedades: false, sociedades: ['ASEI', 'ECOENTORNO'], oficinas: ['2201', '2101', '2401', '2402'],
    fechaCreacion: '17/08/2022', fechaActivacion: '18/08/2022', ultimoAcceso: 'Hace 1 hora', ultimoCambioPassword: '14/02/2026',
    canalActivacion: 'Correo corporativo',
    estado: 'activo',
    historial: [
      { fecha: '17/08/2022 09:00', accion: 'Cuenta creada', responsable: 'Sistema · HCM Atica', detalle: 'Generada automáticamente al crear el empleado' },
      { fecha: '18/08/2022 07:50', accion: 'Cuenta activada', responsable: 'María Trujillo Henao', detalle: 'Vía correo corporativo' },
      { fecha: '03/11/2025 15:12', accion: 'Permiso extra agregado', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: permLabel('reports', 4) },
      { fecha: '20/01/2026 10:05', accion: 'Permiso extra agregado', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: permLabel('recruit', 1) },
      { fecha: '14/02/2026 08:30', accion: 'Cambio de contraseña', responsable: 'María Trujillo Henao', detalle: 'Autogestión' },
    ],
  },
  {
    id: 'USR-0003', empleadoId: 'E0067', initials: 'LM',
    telefono: '+57 318 774 2201', telefonoVerificado: false, fechaModTelefono: '28/04/2026', responsableModTelefono: 'Luis Miguel Marín (autogestión)',
    whatsappAutorizado: false,
    correo: 'luis.marin@atica.co', correoVerificado: true,
    rol: 'jefe', permisosExtra: [],
    todasSociedades: false, sociedades: ['ECOENTORNO'], oficinas: ['2401', '2402'],
    fechaCreacion: '11/04/2021', fechaActivacion: '12/04/2021', ultimoAcceso: 'Ayer 18:42', ultimoCambioPassword: '30/01/2026',
    canalActivacion: 'Correo corporativo',
    estado: 'activo',
    historial: [
      { fecha: '11/04/2021 08:00', accion: 'Cuenta creada', responsable: 'Sistema · HCM Atica', detalle: 'Generada automáticamente al crear el empleado' },
      { fecha: '12/04/2021 09:10', accion: 'Cuenta activada', responsable: 'Luis Miguel Marín', detalle: 'Vía correo corporativo' },
      { fecha: '28/04/2026 16:20', accion: 'Cambio de teléfono', responsable: 'Luis Miguel Marín (autogestión)', detalle: 'Nuevo número pendiente de verificación' },
      { fecha: '28/04/2026 16:21', accion: 'Código enviado', responsable: 'Sistema · HCM Atica', detalle: 'SMS al nuevo número · entregado' },
    ],
  },
  {
    id: 'USR-0004', empleadoId: 'E0244', initials: 'SO',
    telefono: '+57 311 998 4420', telefonoVerificado: true, fechaModTelefono: '21/04/2026', responsableModTelefono: 'Sandra Milena Ortiz (autogestión)',
    whatsappAutorizado: true,
    correo: null, correoVerificado: false,
    rol: 'jefe', permisosExtra: [{ moduleId: 'comms', actionIndex: 1 }],
    todasSociedades: false, sociedades: ['ASEI'], oficinas: ['2101'],
    fechaCreacion: '21/04/2020', fechaActivacion: '22/04/2020', ultimoAcceso: 'Hace 4 horas', ultimoCambioPassword: '05/12/2025',
    canalActivacion: 'SMS',
    estado: 'activo',
    historial: [
      { fecha: '21/04/2020 08:00', accion: 'Cuenta creada', responsable: 'Sistema · HCM Atica', detalle: 'Generada automáticamente al crear el empleado' },
      { fecha: '22/04/2020 10:44', accion: 'Cuenta activada', responsable: 'Sandra Milena Ortiz', detalle: 'Vía SMS' },
      { fecha: '19/09/2025 09:00', accion: 'Permiso extra agregado', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: permLabel('comms', 1) },
    ],
  },
  {
    id: 'USR-0005', empleadoId: 'E0247', initials: 'AM',
    telefono: '+57 311 456 7821', telefonoVerificado: false, fechaModTelefono: '12/05/2026', responsableModTelefono: 'Sistema · alta automática',
    whatsappAutorizado: true,
    correo: null, correoVerificado: false,
    rol: 'operativo', permisosExtra: [],
    todasSociedades: false, sociedades: ['ASEI'], oficinas: ['2201'],
    fechaCreacion: '12/05/2026', fechaActivacion: null, ultimoAcceso: 'Nunca ha ingresado', ultimoCambioPassword: null,
    canalActivacion: null,
    estado: 'pendiente',
    historial: [
      { fecha: '12/05/2026 07:30', accion: 'Cuenta creada', responsable: 'Sistema · HCM Atica', detalle: 'Generada automáticamente al crear el empleado' },
      { fecha: '12/05/2026 07:31', accion: 'Código enviado', responsable: 'Sistema · HCM Atica', detalle: 'SMS · entregado, pendiente de confirmación' },
    ],
  },
  {
    id: 'USR-0006', empleadoId: 'E0298', initials: 'AR',
    telefono: '+57 320 887 1245', telefonoVerificado: false, fechaModTelefono: '01/02/2026', responsableModTelefono: 'Sistema · alta automática',
    whatsappAutorizado: true,
    correo: null, correoVerificado: false,
    rol: 'operativo', permisosExtra: [],
    todasSociedades: false, sociedades: ['ECOENTORNO'], oficinas: ['2401'],
    fechaCreacion: '01/02/2026', fechaActivacion: null, ultimoAcceso: 'Nunca ha ingresado', ultimoCambioPassword: null,
    canalActivacion: null,
    estado: 'pendiente',
    historial: [
      { fecha: '01/02/2026 08:10', accion: 'Cuenta creada', responsable: 'Sistema · HCM Atica', detalle: 'Generada automáticamente al crear el empleado' },
      { fecha: '15/04/2026 09:00', accion: 'Código enviado', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: 'WhatsApp · entregado, pendiente de confirmación' },
    ],
  },
  {
    id: 'USR-0007', empleadoId: 'E0177', initials: 'JP',
    telefono: '+57 313 220 9987', telefonoVerificado: true, fechaModTelefono: '11/06/2023', responsableModTelefono: 'Sistema · alta automática',
    whatsappAutorizado: true,
    correo: null, correoVerificado: false,
    rol: 'operativo', permisosExtra: [],
    todasSociedades: false, sociedades: ['ECOLOGISTICA'], oficinas: ['2602'],
    fechaCreacion: '11/06/2023', fechaActivacion: '12/06/2023', ultimoAcceso: 'Hace 2 días', ultimoCambioPassword: '11/06/2023',
    canalActivacion: 'SMS',
    estado: 'activo',
    historial: [
      { fecha: '11/06/2023 08:00', accion: 'Cuenta creada', responsable: 'Sistema · HCM Atica', detalle: 'Generada automáticamente al crear el empleado' },
      { fecha: '12/06/2023 07:15', accion: 'Cuenta activada', responsable: 'Jorge Iván Patiño', detalle: 'Vía SMS' },
    ],
  },
  {
    id: 'USR-0008', empleadoId: 'E0156', initials: 'PV',
    telefono: '+57 317 556 2290', telefonoVerificado: true, fechaModTelefono: '03/02/2025', responsableModTelefono: 'Sistema · alta automática',
    whatsappAutorizado: false,
    correo: null, correoVerificado: false,
    rol: 'operativo', permisosExtra: [],
    todasSociedades: false, sociedades: ['ECOLOGISTICA'], oficinas: ['2601'],
    fechaCreacion: '03/02/2025', fechaActivacion: '04/02/2025', ultimoAcceso: 'Hace 6 días', ultimoCambioPassword: '04/02/2025',
    canalActivacion: 'SMS',
    estado: 'activo',
    historial: [
      { fecha: '03/02/2025 08:00', accion: 'Cuenta creada', responsable: 'Sistema · HCM Atica', detalle: 'Generada automáticamente al crear el empleado' },
      { fecha: '04/02/2025 07:40', accion: 'Cuenta activada', responsable: 'Paula Valencia Ríos', detalle: 'Vía SMS' },
    ],
  },
  {
    id: 'USR-0009', empleadoId: 'E0011', initials: 'FH',
    telefono: '+57 300 221 7743', telefonoVerificado: true, fechaModTelefono: '14/07/2018', responsableModTelefono: 'Sistema · alta automática',
    whatsappAutorizado: false,
    correo: null, correoVerificado: false,
    rol: 'operativo', permisosExtra: [],
    todasSociedades: false, sociedades: ['ECOENTORNO'], oficinas: ['2401'],
    fechaCreacion: '14/07/2018', fechaActivacion: '15/07/2018', ultimoAcceso: 'Hace 8 meses', ultimoCambioPassword: '02/06/2024',
    canalActivacion: 'SMS',
    estado: 'inactivo',
    historial: [
      { fecha: '14/07/2018 08:00', accion: 'Cuenta creada', responsable: 'Sistema · HCM Atica', detalle: 'Generada automáticamente al crear el empleado' },
      { fecha: '15/07/2018 07:55', accion: 'Cuenta activada', responsable: 'Fernando Henao', detalle: 'Vía SMS' },
      { fecha: '20/12/2025 14:00', accion: 'Usuario inactivado', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: 'Retiro del colaborador' },
    ],
  },
  {
    id: 'USR-0010', empleadoId: 'E0205', initials: 'CV',
    telefono: '+57 314 552 8890', telefonoVerificado: true, fechaModTelefono: '14/03/2024', responsableModTelefono: 'Sistema · alta automática',
    whatsappAutorizado: true,
    correo: 'carlos.velez@atica.co', correoVerificado: true,
    rol: 'operativo', permisosExtra: [{ moduleId: 'docs', actionIndex: 3 }],
    todasSociedades: false, sociedades: ['ASEI'], oficinas: ['2201'],
    fechaCreacion: '14/03/2024', fechaActivacion: '15/03/2024', ultimoAcceso: 'Hace 30 min', ultimoCambioPassword: '11/01/2026',
    canalActivacion: 'Correo corporativo',
    estado: 'activo',
    historial: [
      { fecha: '14/03/2024 08:00', accion: 'Cuenta creada', responsable: 'Sistema · HCM Atica', detalle: 'Generada automáticamente al crear el empleado' },
      { fecha: '15/03/2024 08:20', accion: 'Cuenta activada', responsable: 'Carlos Andrés Vélez', detalle: 'Vía correo corporativo' },
      { fecha: '02/01/2026 11:00', accion: 'Permiso extra agregado', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: permLabel('docs', 3) },
      { fecha: '11/01/2026 09:12', accion: 'Cambio de contraseña', responsable: 'Carlos Andrés Vélez', detalle: 'Autogestión' },
    ],
  },
];

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

const Settings = () => {
  const [section, setSection]       = _cf_useState('matrices');
  const [matrixOpen, setMatrixOpen] = _cf_useState(null);
  const [flowOpen, setFlowOpen]     = _cf_useState(null);

  const NAV = [
    ['cargos',      'Cargos',                   'IconSitemap'],
    ['sociedades',  'Sociedades',               'IconBuilding'],
    ['bandas',      'Bandas salariales',        'IconWallet'],
    ['matrices',  'Matrices por cargo',         'IconUsers'],
    ['competencias', 'Competencias y versiones', 'IconStar'],
    ['legales',   'Parámetros legales',         'IconShield'],
    ['contratos', 'Tipos de contrato',          'IconDoc'],
    ['flujos',    'Flujos de aprobación',       'IconZap'],
    ['plantillas','Plantillas de documentos',   'IconBook'],
    ['plantillas-solicitudes', 'Plantillas de solicitudes', 'IconDoc'],
    ['centros',   'Centros de costo',           'IconBarChart'],
    ['usuarios',  'Usuarios y roles',           'IconSettings'],
  ];

  return (
    <div className="main" data-screen-label="Configuración">
      <div className="page-head">
        <div>
          <h1 className="page-title">Configuración del sistema</h1>
          <div className="page-subtitle">
            <b>Atica S.A.S.</b> · ajustes que aplican a toda la operación · cambios auditables
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button className="btn"><IconExternal size={14} /> Bitácora de cambios</button>
        </div>
      </div>

      <div className="cf-layout">
        <aside className="cf-sidebar">
          {NAV.map(([id, label, ico]) => {
            const I = window[ico];
            return (
              <button key={id} className={`cf-nav-item ${section === id ? 'active' : ''}`} onClick={() => setSection(id)}>
                <I size={15} />
                <span>{label}</span>
              </button>
            );
          })}
        </aside>

        <div className="cf-content">
          {section === 'cargos'      && <CargosSection />}
          {section === 'sociedades'  && <SociedadesSection />}
          {section === 'bandas'      && <BandasSalarialesSection />}
          {section === 'matrices'    && <MatricesSection onEdit={(m) => setMatrixOpen(m)} />}
          {section === 'competencias'&& <CompetenciasEditorSection />}
          {section === 'legales'     && <LegalSection />}
          {section === 'contratos' && <ContractsSection />}
          {section === 'flujos'    && <FlowsSection onEdit={(f) => setFlowOpen(f)} />}
          {section === 'plantillas'&& <TemplatesSection />}
          {section === 'plantillas-solicitudes' && <PlantillasSolicitudesSection />}
          {section === 'centros'   && <CostCentersSection />}
          {section === 'usuarios'  && <UsersSection />}
        </div>
      </div>

      {matrixOpen && <MatrixEditor matrix={matrixOpen} onClose={() => setMatrixOpen(null)} />}
      {flowOpen   && <FlowEditor flow={flowOpen} onClose={() => setFlowOpen(null)} />}
    </div>
  );
};

// ─── Section: Cargos ──────────────────────────────────────
// Catálogo maestro de cargos: perfil, jerarquía, documentos y pruebas.
// Reutiliza los mismos nombres de cargo que window.CARGOS (data-providers.jsx)
// para no romper consistencia con Capacitaciones/Matrices/SST.

const AREAS_CARGO = ['Operaciones / Clasificación', 'Aprovechamiento', 'Recolección', 'Calidad y Laboratorio', 'Mantenimiento', 'Administración', 'Comercial', 'Compras y Logística'];

const NIVELES_CARGO = [
  { id: 'operativo',  label: 'Operativo' },
  { id: 'tecnico',    label: 'Técnico' },
  { id: 'liderazgo',  label: 'Liderazgo' },
  { id: 'directivo',  label: 'Directivo' },
  { id: 'voluntario', label: 'Voluntario' },
];

const STATE_CARGO = {
  activo:   { label: 'Activo',   pill: 'green', dot: 'var(--green-600)' },
  inactivo: { label: 'Inactivo', pill: 'navy',  dot: 'var(--text-muted)' },
};

const DOCUMENTOS_CARGO_OPTS = [
  'Cédula de ciudadanía', 'Hoja de vida', 'Certificado EPS', 'Certificado AFP', 'Certificado ARL',
  'Antecedentes judiciales (Policía)', 'Antecedentes disciplinarios (Procuraduría)', 'Certificado bancario',
  'Examen médico ocupacional de ingreso', 'Libreta militar', 'Diploma de bachiller', 'Diploma técnico/tecnólogo',
  'Certificados laborales', 'Referencias personales', 'Licencia de conducción',
];

const PRUEBAS_GO_OPTS = ['16PF · Personalidad', 'G-O · Inteligencia general', 'G-O · Valores organizacionales', 'Cleaver · Perfil comportamental (DISC)'];
const PRUEBAS_JIRO_OPTS = ['Jiro · Razonamiento lógico', 'Jiro · Atención y concentración', 'Jiro · Habilidad numérica', 'Jiro · Habilidad verbal'];
const PRUEBAS_ADICIONALES_OPTS = ['Prueba técnica del cargo', 'Assessment center', 'Entrevista por competencias', 'Prueba de manejo defensivo (conductores)', 'Prueba de alturas (Res. 4272)'];

const HABILIDADES_CARGO_OPTS = [
  'Manejo fluido de software de oficina (Word, Excel básico, plataformas o herramientas digitales de análisis)',
  'Archivo y control documental',
  'Diseño y seguimiento de indicadores de gestión (KPIs)',
  'Trabajo en equipo y comunicación asertiva',
  'Orientación al detalle y calidad',
  'Manejo de maquinaria y equipo industrial',
  'Liderazgo de equipos operativos',
  'Resolución de problemas bajo presión',
  'Conocimiento normativo SST',
  'Manejo defensivo y normas de tránsito',
];

const CARGOS_CATALOG_SEED = [
  {
    id: 'CGO-001', nombre: 'Operario de Clasificación', codigo: 'CGO-OPC-01',
    proceso: 'Operaciones', subproceso: 'Clasificación de residuos', nivel: 'operativo',
    area: 'Operaciones / Clasificación', headcount: 38, estado: 'activo',
    jefeInmediato: 'Líder de Aprovechamiento', cargosQueReportan: [],
    documentosObligatorios: ['Cédula de ciudadanía', 'Hoja de vida', 'Certificado EPS', 'Certificado AFP', 'Certificado ARL', 'Examen médico ocupacional de ingreso'],
    documentosComplementarios: ['Diploma de bachiller', 'Certificados laborales'],
    mision: 'Clasificar y separar los residuos recibidos en planta según su categoría, cumpliendo los estándares de calidad, seguridad y productividad definidos por Atica.',
    indicadores: ['Cumplimiento de meta de clasificación diaria (kg/turno)', 'Índice de accidentalidad = 0', '% de material mal clasificado < 2%'],
    perfilOculto: 'Se valora tolerancia a jornadas de pie y disposición para rotar entre líneas de clasificación según demanda operativa.',
    fechaActualizacion: '02/05/2026',
    pruebasGO: ['16PF · Personalidad', 'Cleaver · Perfil comportamental (DISC)'],
    pruebasJiro: ['Jiro · Atención y concentración'],
    pruebasAdicionales: ['Prueba técnica del cargo'],
    competencias: 'Trabajo en equipo, atención al detalle, seguimiento de instrucciones, adaptabilidad a cambios de línea.',
    funcionesEspecificas: 'Recibir, inspeccionar y clasificar residuos según categoría (orgánico, reciclable, no aprovechable). Registrar novedades de calidad del material en el sistema.',
    funcionesSST: 'Usar de forma permanente los EPP asignados. Reportar actos y condiciones inseguras. Participar en las inspecciones y simulacros programados.',
    funcionesSGA: 'Segregar correctamente los residuos generados en su puesto de trabajo. Contribuir al cumplimiento de las metas de aprovechamiento de la sede.',
    funcionesCalidad: 'Verificar que el material clasificado cumpla los criterios del instructivo de calidad vigente antes de enviarlo a la siguiente etapa.',
    habilidades: ['Trabajo en equipo y comunicación asertiva', 'Orientación al detalle y calidad'],
  },
  {
    id: 'CGO-003', nombre: 'Op. Aprovechamiento', codigo: 'CGO-OAP-01',
    proceso: 'Aprovechamiento', subproceso: 'Recuperación de material', nivel: 'operativo',
    area: 'Aprovechamiento', headcount: 86, estado: 'activo',
    jefeInmediato: 'Líder de Aprovechamiento', cargosQueReportan: [],
    documentosObligatorios: ['Cédula de ciudadanía', 'Hoja de vida', 'Certificado EPS', 'Certificado ARL'],
    documentosComplementarios: ['Certificados laborales', 'Referencias personales'],
    mision: 'Ejecutar los procesos de recuperación y preparación de material aprovechable garantizando su correcta disposición para comercialización.',
    indicadores: ['Kg de material recuperado por turno', 'Cumplimiento de plan de aprovechamiento mensual'],
    perfilOculto: '',
    fechaActualizacion: '28/04/2026',
    pruebasGO: ['16PF · Personalidad'],
    pruebasJiro: ['Jiro · Habilidad numérica'],
    pruebasAdicionales: [],
    competencias: 'Trabajo en equipo, resistencia física, manejo responsable de residuos biológicos.',
    funcionesEspecificas: 'Separar, limpiar y empacar material aprovechable según especificación comercial.',
    funcionesSST: 'Aplicar protocolo de bioseguridad en manejo de residuos. Uso obligatorio de guantes y tapabocas.',
    funcionesSGA: 'Maximizar el porcentaje de material recuperado, minimizando el envío a relleno sanitario.',
    funcionesCalidad: 'Garantizar que el material empacado cumpla el estándar de pureza exigido por el comprador.',
    habilidades: ['Orientación al detalle y calidad', 'Trabajo en equipo y comunicación asertiva'],
  },
  {
    id: 'CGO-004', nombre: 'Líder de Aprovechamiento', codigo: 'CGO-LAP-01',
    proceso: 'Aprovechamiento', subproceso: 'Coordinación de línea', nivel: 'liderazgo',
    area: 'Aprovechamiento', headcount: 6, estado: 'activo',
    jefeInmediato: 'Jefe de RRHH', cargosQueReportan: ['Op. Aprovechamiento', 'Operario de Clasificación'],
    documentosObligatorios: ['Cédula de ciudadanía', 'Hoja de vida', 'Certificado EPS', 'Certificado AFP', 'Certificado ARL', 'Diploma técnico/tecnólogo'],
    documentosComplementarios: ['Certificados laborales', 'Referencias personales'],
    mision: 'Liderar el equipo operativo de aprovechamiento, garantizando el cumplimiento de metas de producción, calidad y seguridad de la línea.',
    indicadores: ['Cumplimiento de meta de producción de la línea', 'Rotación de personal a cargo', 'Cierre de hallazgos SST en plazo'],
    perfilOculto: 'Requiere disponibilidad para turnos rotativos y manejo de equipos de más de 10 personas.',
    fechaActualizacion: '05/04/2026',
    pruebasGO: ['G-O · Inteligencia general', 'Cleaver · Perfil comportamental (DISC)'],
    pruebasJiro: ['Jiro · Razonamiento lógico', 'Jiro · Habilidad verbal'],
    pruebasAdicionales: ['Assessment center', 'Entrevista por competencias'],
    competencias: 'Liderazgo de equipos, resolución de conflictos, planificación operativa, comunicación asertiva.',
    funcionesEspecificas: 'Distribuir tareas del turno, hacer seguimiento a metas de producción y reportar novedades a la Jefatura de RRHH/Operaciones.',
    funcionesSST: 'Liderar las inspecciones de seguridad de su línea. Garantizar el uso correcto de EPP por parte del equipo a cargo.',
    funcionesSGA: 'Verificar cumplimiento de metas de aprovechamiento de la línea y proponer mejoras al proceso.',
    funcionesCalidad: 'Aprobar el material clasificado antes de despacho y gestionar no conformidades detectadas.',
    habilidades: ['Diseño y seguimiento de indicadores de gestión (KPIs)', 'Liderazgo de equipos operativos', 'Resolución de problemas bajo presión'],
  },
  {
    id: 'CGO-006', nombre: 'Téc. Mantenimiento', codigo: 'CGO-TMT-01',
    proceso: 'Mantenimiento', subproceso: 'Mantenimiento industrial', nivel: 'tecnico',
    area: 'Mantenimiento', headcount: 8, estado: 'activo',
    jefeInmediato: 'Jefe de RRHH', cargosQueReportan: [],
    documentosObligatorios: ['Cédula de ciudadanía', 'Hoja de vida', 'Certificado EPS', 'Certificado ARL', 'Diploma técnico/tecnólogo', 'Examen médico ocupacional de ingreso'],
    documentosComplementarios: ['Certificados laborales'],
    mision: 'Ejecutar el mantenimiento preventivo y correctivo de la maquinaria industrial de planta, minimizando tiempos de parada.',
    indicadores: ['Cumplimiento de plan de mantenimiento preventivo', 'Tiempo medio de reparación (MTTR)'],
    perfilOculto: 'Debe contar con certificación vigente de trabajo en alturas y trabajo en espacios confinados.',
    fechaActualizacion: '15/04/2026',
    pruebasGO: ['16PF · Personalidad'],
    pruebasJiro: ['Jiro · Razonamiento lógico'],
    pruebasAdicionales: ['Prueba técnica del cargo', 'Prueba de alturas (Res. 4272)'],
    competencias: 'Diagnóstico técnico, trabajo bajo presión, autonomía, cumplimiento de protocolos LOTO.',
    funcionesEspecificas: 'Ejecutar rutinas de mantenimiento preventivo. Diagnosticar y reparar fallas de maquinaria de clasificación y trituración.',
    funcionesSST: 'Aplicar el procedimiento de bloqueo y etiquetado (LOTO) en toda intervención. Uso de arnés certificado en trabajo en alturas.',
    funcionesSGA: 'Gestionar adecuadamente residuos peligrosos generados por mantenimiento (aceites, grasas, repuestos).',
    funcionesCalidad: 'Registrar en el sistema cada intervención realizada, garantizando trazabilidad del mantenimiento.',
    habilidades: ['Manejo de maquinaria y equipo industrial', 'Resolución de problemas bajo presión'],
  },
  {
    id: 'CGO-009', nombre: 'Conductor', codigo: 'CGO-CND-01',
    proceso: 'Logística', subproceso: 'Recolección y transporte', nivel: 'operativo',
    area: 'Recolección', headcount: 4, estado: 'activo',
    jefeInmediato: 'Coord. Compras', cargosQueReportan: [],
    documentosObligatorios: ['Cédula de ciudadanía', 'Hoja de vida', 'Licencia de conducción', 'Certificado EPS', 'Certificado ARL', 'Examen médico ocupacional de ingreso'],
    documentosComplementarios: ['Certificados laborales', 'Referencias personales'],
    mision: 'Conducir los vehículos de recolección cumpliendo las rutas asignadas, la normativa de tránsito y los protocolos de seguridad vial de Atica.',
    indicadores: ['Cumplimiento de ruta asignada', 'Índice de siniestralidad vial = 0', 'Consumo de combustible vs. meta'],
    perfilOculto: 'Se valora experiencia previa en manejo de vehículos pesados y rutas urbanas.',
    fechaActualizacion: '21/04/2026',
    pruebasGO: ['Cleaver · Perfil comportamental (DISC)'],
    pruebasJiro: ['Jiro · Atención y concentración'],
    pruebasAdicionales: ['Prueba de manejo defensivo (conductores)'],
    competencias: 'Responsabilidad, atención sostenida, manejo defensivo, orientación al servicio.',
    funcionesEspecificas: 'Ejecutar la ruta de recolección asignada. Verificar el estado del vehículo antes y después de cada turno (preoperacional).',
    funcionesSST: 'Diligenciar el preoperacional diario del vehículo. Cumplir el reglamento interno de seguridad vial.',
    funcionesSGA: 'Evitar derrames y fugas durante el transporte de residuos. Reportar cualquier incidente ambiental en ruta.',
    funcionesCalidad: 'Garantizar la puntualidad y el cumplimiento del cronograma de recolección pactado con el cliente.',
    habilidades: ['Manejo defensivo y normas de tránsito', 'Orientación al detalle y calidad'],
  },
  {
    id: 'CGO-005', nombre: 'Aux. Calidad', codigo: 'CGO-AXC-01',
    proceso: 'Calidad', subproceso: 'Aseguramiento de calidad', nivel: 'operativo',
    area: 'Calidad y Laboratorio', headcount: 12, estado: 'inactivo',
    jefeInmediato: 'Jefe de RRHH', cargosQueReportan: [],
    documentosObligatorios: ['Cédula de ciudadanía', 'Hoja de vida', 'Certificado EPS', 'Certificado ARL', 'Diploma técnico/tecnólogo'],
    documentosComplementarios: ['Certificados laborales'],
    mision: 'Verificar el cumplimiento de los estándares de calidad del material clasificado y aprovechado en cada etapa del proceso.',
    indicadores: ['% de conformidad en auditorías internas', 'Tiempo de respuesta a no conformidades'],
    perfilOculto: '',
    fechaActualizacion: '20/03/2026',
    pruebasGO: ['16PF · Personalidad'],
    pruebasJiro: [],
    pruebasAdicionales: [],
    competencias: 'Atención al detalle, pensamiento analítico, manejo de indicadores.',
    funcionesEspecificas: 'Realizar inspecciones de calidad por muestreo. Documentar hallazgos y hacer seguimiento a planes de acción.',
    funcionesSST: 'Cumplir protocolo de bioseguridad al manipular muestras de residuos.',
    funcionesSGA: 'Verificar cumplimiento de criterios ambientales en el material certificado como aprovechable.',
    funcionesCalidad: 'Custodiar y actualizar el sistema documental del proceso de calidad.',
    habilidades: ['Archivo y control documental', 'Diseño y seguimiento de indicadores de gestión (KPIs)'],
  },
];

const CargosSection = () => {
  const [catalog, setCatalog] = _cf_useState(CARGOS_CATALOG_SEED);
  const [modal, setModal]     = _cf_useState(null); // null | 'new' | cargo object
  const [bulkOpen, setBulkOpen] = _cf_useState(false);

  const handleSave = (data) => {
    setCatalog(prev => {
      const exists = prev.some(c => c.id === data.id);
      return exists ? prev.map(c => c.id === data.id ? data : c) : [...prev, data];
    });
    setModal(null);
  };

  return (
    <>
      <div className="cf-section-head">
        <div>
          <h2 className="cf-section-title">Cargos</h2>
          <p className="cf-section-sub">
            Catálogo maestro de cargos de Atica: perfil, jerarquía, documentos y pruebas asociadas a cada posición.
          </p>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button className="btn" onClick={() => setBulkOpen(true)}><IconExternal size={14} /> Cargue masivo</button>
          <button className="btn primary" onClick={() => setModal('new')}><IconPlus size={14} /> Nuevo Cargo</button>
        </div>
      </div>

      <div className="doc-list-card">
        <table className="doc-table">
          <thead>
            <tr>
              <th>Nombre de cargo</th>
              <th>Código</th>
              <th style={{ textAlign: 'center' }}>Colaboradores</th>
              <th>Estado</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {catalog.map(c => {
              const s = STATE_CARGO[c.estado];
              return (
                <tr key={c.id} onClick={() => setModal(c)} style={{ cursor: 'pointer' }}>
                  <td style={{ fontWeight: 600, fontSize: 13 }}>{c.nombre}</td>
                  <td className="mono muted" style={{ fontSize: 12 }}>{c.codigo}</td>
                  <td style={{ textAlign: 'center', fontFamily: 'JetBrains Mono', fontSize: 13, fontWeight: 700 }}>{c.headcount}</td>
                  <td>
                    <span className={`pill ${s.pill}`}>
                      <span className="status-dot" style={{ background: s.dot }} /> {s.label}
                    </span>
                  </td>
                  <td>
                    <button className="icon-action" title="Editar" onClick={(e) => { e.stopPropagation(); setModal(c); }}><IconExternal size={14} /></button>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {modal && (
        <CargoFormModal
          cargo={modal === 'new' ? null : modal}
          allCargos={catalog}
          onClose={() => setModal(null)}
          onSave={handleSave}
        />
      )}
      {bulkOpen && <CargoBulkUploadModal onClose={() => setBulkOpen(false)} />}
    </>
  );
};

const CARGO_TABS_FORM = [
  ['general',   'Datos generales',          'IconSettings'],
  ['jerarquia', 'Jerarquía y documentos',   'IconSitemap'],
  ['perfil',    'Perfil del cargo',         'IconStar'],
  ['pruebas',   'Pruebas y evaluación',     'IconShield'],
  ['funciones', 'Funciones y competencias', 'IconBook'],
];

const CargoFormModal = ({ cargo, allCargos, onClose, onSave }) => {
  const [tab, setTab]   = _cf_useState('general');
  const [form, setForm] = _cf_useState(() => cargo ? { ...cargo } : {
    id: null, nombre: '', codigo: '', proceso: '', subproceso: '',
    nivel: 'operativo', area: AREAS_CARGO[0], estado: 'activo', headcount: 0,
    jefeInmediato: '', cargosQueReportan: [],
    documentosObligatorios: [], documentosComplementarios: [],
    mision: '', indicadores: [], perfilOculto: '', fechaActualizacion: '',
    pruebasGO: [], pruebasJiro: [], pruebasAdicionales: [],
    competencias: '', funcionesEspecificas: '', funcionesSST: '', funcionesSGA: '', funcionesCalidad: '',
    habilidades: [],
  });

  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 set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const toggleArr = (k, val) => setForm(f => ({ ...f, [k]: f[k].includes(val) ? f[k].filter(x => x !== val) : [...f[k], val] }));

  const otherCargos = allCargos.filter(c => c.id !== form.id).map(c => c.nombre);

  const addIndicador = () => set('indicadores', [...form.indicadores, '']);
  const updIndicador  = (i, val) => set('indicadores', form.indicadores.map((x, idx) => idx === i ? val : x));
  const delIndicador  = (i) => set('indicadores', form.indicadores.filter((_, idx) => idx !== i));

  const handleGuardar = () => {
    onSave({ ...form, id: form.id || `CGO-${Date.now()}`, fechaActualizacion: '05/05/2026' });
  };

  const MultiPick = ({ k, options }) => (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
      {options.map(o => {
        const sel = form[k].includes(o);
        return (
          <button
            key={o} type="button"
            className={`pill ${sel ? 'green' : 'navy-soft'}`}
            style={{ cursor: 'pointer', border: 'none', fontSize: 11.5, textAlign: 'left' }}
            onClick={() => toggleArr(k, o)}
          >
            {sel && <IconCheck size={10} />} {o}
          </button>
        );
      })}
    </div>
  );

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal cf-mx-modal" style={{ maxWidth: 900, height: 'calc(100vh - 64px)' }}>
        <div className="modal-head cf-mx-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>{form.id || 'NUEVO CARGO'}</div>
            <div className="modal-title">{cargo ? `Editar cargo: ${cargo.nombre}` : 'Nuevo cargo'}</div>
            <div className="modal-sub">Define el perfil completo del cargo: jerarquía, documentos, pruebas y funciones.</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>

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

        <div className="modal-body cf-mx-body">
          {tab === 'general' && (
            <div className="cf-cmp-fields">
              <div className="furat-grid-2">
                <div className="furat-row">
                  <label className="furat-label">Nombre del cargo</label>
                  <input type="text" value={form.nombre} onChange={e => set('nombre', e.target.value)} placeholder="Ej: Operario de Clasificación" />
                </div>
                <div className="furat-row">
                  <label className="furat-label">Código</label>
                  <input type="text" className="mono" value={form.codigo} onChange={e => set('codigo', e.target.value)} placeholder="Ej: CGO-OPC-02" />
                </div>
                <div className="furat-row">
                  <label className="furat-label">Proceso</label>
                  <input type="text" value={form.proceso} onChange={e => set('proceso', e.target.value)} placeholder="Ej: Operaciones" />
                </div>
                <div className="furat-row">
                  <label className="furat-label">Subproceso</label>
                  <input type="text" value={form.subproceso} onChange={e => set('subproceso', e.target.value)} placeholder="Ej: Clasificación de residuos" />
                </div>
                <div className="furat-row">
                  <label className="furat-label">Nivel de cargo</label>
                  <select value={form.nivel} onChange={e => set('nivel', e.target.value)}>
                    {NIVELES_CARGO.map(n => <option key={n.id} value={n.id}>{n.label}</option>)}
                  </select>
                </div>
                <div className="furat-row">
                  <label className="furat-label">Área</label>
                  <select value={form.area} onChange={e => set('area', e.target.value)}>
                    {AREAS_CARGO.map(a => <option key={a} value={a}>{a}</option>)}
                  </select>
                </div>
              </div>
              <div className="furat-row" style={{ marginTop: 4, flexDirection: 'row', alignItems: 'center' }}>
                <label className="furat-label" style={{ marginRight: 4 }}>Estado</label>
                <label className="epp-toggle">
                  <input type="checkbox" checked={form.estado === 'activo'} onChange={e => set('estado', e.target.checked ? 'activo' : 'inactivo')} />
                  <span className="epp-toggle-track" />
                </label>
                <span className="muted" style={{ fontSize: 12, marginLeft: 8 }}>{form.estado === 'activo' ? 'Activo' : 'Inactivo'}</span>
              </div>
            </div>
          )}

          {tab === 'jerarquia' && (
            <div className="cf-cmp-fields">
              <div className="furat-row">
                <label className="furat-label">Jefe inmediato</label>
                <select value={form.jefeInmediato} onChange={e => set('jefeInmediato', e.target.value)}>
                  <option value="">— Sin jefe directo (cargo máximo) —</option>
                  {otherCargos.map(n => <option key={n} value={n}>{n}</option>)}
                </select>
              </div>
              <div className="furat-row">
                <label className="furat-label">Cargos que le reportan</label>
                <MultiPick k="cargosQueReportan" options={otherCargos} />
              </div>
              <div className="furat-row">
                <label className="furat-label">Documentos obligatorios para ingresar</label>
                <MultiPick k="documentosObligatorios" options={DOCUMENTOS_CARGO_OPTS} />
              </div>
              <div className="furat-row">
                <label className="furat-label">Documentos complementarios</label>
                <MultiPick k="documentosComplementarios" options={DOCUMENTOS_CARGO_OPTS} />
              </div>
            </div>
          )}

          {tab === 'perfil' && (
            <div className="cf-cmp-fields">
              <div className="furat-row">
                <label className="furat-label">Misión del cargo</label>
                <textarea rows={3} value={form.mision} onChange={e => set('mision', e.target.value)} placeholder="Propósito principal del cargo dentro de la operación..." />
              </div>
              <div className="furat-row">
                <label className="furat-label">Indicadores de cargo</label>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                  {form.indicadores.map((ind, i) => (
                    <div key={i} style={{ display: 'flex', gap: 6 }}>
                      <input type="text" style={{ flex: 1 }} value={ind} onChange={e => updIndicador(i, e.target.value)} placeholder="Ej: Cumplimiento de meta mensual" />
                      <button className="icon-action danger" title="Quitar indicador" onClick={() => delIndicador(i)}><IconAlert size={13} /></button>
                    </div>
                  ))}
                  <button className="btn" style={{ alignSelf: 'flex-start' }} onClick={addIndicador}><IconPlus size={12} /> Agregar indicador</button>
                </div>
              </div>
              <div className="furat-row">
                <label className="furat-label">Perfil oculto</label>
                <textarea rows={2} value={form.perfilOculto} onChange={e => set('perfilOculto', e.target.value)} placeholder="Criterios adicionales no visibles en la convocatoria pública..." />
              </div>
              <div className="furat-row">
                <label className="furat-label">Fecha última actualización</label>
                <input type="text" value={form.fechaActualizacion || '— se registra al guardar —'} disabled className="mono" />
              </div>
            </div>
          )}

          {tab === 'pruebas' && (
            <div className="cf-cmp-fields">
              <div className="furat-row">
                <label className="furat-label">Pruebas psicotécnicas G.O.</label>
                <MultiPick k="pruebasGO" options={PRUEBAS_GO_OPTS} />
              </div>
              <div className="furat-row">
                <label className="furat-label">Pruebas psicotécnicas Jiro</label>
                <MultiPick k="pruebasJiro" options={PRUEBAS_JIRO_OPTS} />
              </div>
              <div className="furat-row">
                <label className="furat-label">Pruebas adicionales</label>
                <MultiPick k="pruebasAdicionales" options={PRUEBAS_ADICIONALES_OPTS} />
              </div>
            </div>
          )}

          {tab === 'funciones' && (
            <div className="cf-cmp-fields">
              <div className="furat-row">
                <label className="furat-label">Competencias</label>
                <textarea rows={2} value={form.competencias} onChange={e => set('competencias', e.target.value)} />
              </div>
              <div className="furat-row">
                <label className="furat-label">Funciones específicas del cargo</label>
                <textarea rows={3} value={form.funcionesEspecificas} onChange={e => set('funcionesEspecificas', e.target.value)} />
              </div>
              <div className="furat-row">
                <label className="furat-label">Funciones y Responsabilidades en SST (Seguridad y Salud en el Trabajo)</label>
                <textarea rows={3} value={form.funcionesSST} onChange={e => set('funcionesSST', e.target.value)} />
              </div>
              <div className="furat-row">
                <label className="furat-label">Funciones y Responsabilidades Frente al SGA (Sistema de Gestión Ambiental)</label>
                <textarea rows={3} value={form.funcionesSGA} onChange={e => set('funcionesSGA', e.target.value)} />
              </div>
              <div className="furat-row">
                <label className="furat-label">Funciones y Responsabilidades Frente al Sistema de Calidad</label>
                <textarea rows={3} value={form.funcionesCalidad} onChange={e => set('funcionesCalidad', e.target.value)} />
              </div>
              <div className="furat-row">
                <label className="furat-label">Habilidades</label>
                <MultiPick k="habilidades" options={HABILIDADES_CARGO_OPTS} />
              </div>
            </div>
          )}
        </div>

        <div className="modal-foot">
          <span className="muted" style={{ fontSize: 12, marginRight: 'auto' }}>
            Última actualización: <b style={{ color: 'var(--text)' }}>{form.fechaActualizacion || '— aún no guardado —'}</b>
          </span>
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" onClick={handleGuardar} disabled={!form.nombre || !form.codigo}>
            <IconCheck size={14} /> Guardar cargo
          </button>
        </div>
      </div>
    </div>
  );
};

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

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 520 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">Cargue masivo de cargos</div>
            <div className="modal-sub">Sube un archivo con el catálogo de cargos para crearlos o actualizarlos en lote.</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <button className="link-btn" style={{ display: 'inline-flex', alignItems: 'center', gap: 6, marginBottom: 14 }}>
            <IconExternal size={13} /> Descargar plantilla .xlsx
          </button>
          <div style={{ border: '2px dashed var(--border)', borderRadius: 12, padding: '36px 20px', textAlign: 'center', color: 'var(--text-muted)' }}>
            <IconDoc size={26} style={{ marginBottom: 8, opacity: 0.5 }} />
            <div style={{ fontWeight: 600, fontSize: 13.5, color: 'var(--text)' }}>Arrastra el archivo aquí</div>
            <div style={{ fontSize: 12, marginTop: 4 }}>o haz clic para buscarlo · formatos .xlsx, .csv</div>
          </div>
          <div className="muted" style={{ fontSize: 11.5, marginTop: 12, lineHeight: 1.5 }}>
            <IconShield size={11} /> Los cargos con código existente se actualizarán; los códigos nuevos se crearán como nuevos cargos.
          </div>
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" disabled><IconCheck size={14} /> Cargar archivo</button>
        </div>
      </div>
    </div>
  );
};

// ─── Section: Sociedades ──────────────────────────────────
// Empresas/razones sociales que agrupan a los colaboradores por área.
// Los empleados referenciados por id vienen de window.EMPLOYEES
// (employee-list.jsx) — no se inventan personas nuevas.

const getEmpleadoById = (id) => (window.EMPLOYEES || []).find(e => e.id === id);

const SOCIEDADES_SEED = [
  {
    id: 'SOC-ASEI', nombre: 'ASEI', prefijo: 'ASEI',
    nit: '900.234.567-1', centroCosto: 'CC-ASEI-ADM', direccion: 'Calle 15 #24-56, Cali, Valle del Cauca',
    descripcion: 'Sociedad matriz — administración general y presidencia del grupo.',
    logo: null, representantesLegales: ['Ricardo Andrés Fajardo Uribe'],
    areas: [
      { id: 'AREA-ASEI-01', nombre: 'Admon Cali',            empleadosIds: ['E0094', 'E0023'] },
      { id: 'AREA-ASEI-02', nombre: 'Operativa Cali',        empleadosIds: ['E0247', 'E0246', 'E0205'] },
      { id: 'AREA-ASEI-03', nombre: 'Operativa Barranquilla', empleadosIds: ['E0245'] },
    ],
  },
  {
    id: 'SOC-IA4', nombre: 'IA4 SAS', prefijo: 'IA4',
    nit: '900.345.678-2', centroCosto: 'CC-IA4-ADM', direccion: 'Carrera 43A #5-15, Cali, Valle del Cauca',
    descripcion: 'Administración de compras, servicios generales y soporte administrativo.',
    logo: null, representantesLegales: ['Jorge Eduardo Villamizar Peña'],
    areas: [
      { id: 'AREA-IA4-01', nombre: 'Admon Bogotá',   empleadosIds: ['E0244'] },
      { id: 'AREA-IA4-02', nombre: 'Admon Medellín', empleadosIds: ['E0298'] },
    ],
  },
  {
    id: 'SOC-ECOENTORNO', nombre: 'ECOENTORNO', prefijo: 'ECO',
    nit: '900.456.789-3', centroCosto: 'CC-ECO-ADM', direccion: 'Avenida 6 Norte #23-12, Cali, Valle del Cauca',
    descripcion: 'Aprovechamiento y gestión comercial de residuos aprovechables.',
    logo: null, representantesLegales: ['Daniela Alejandra Montoya Salcedo', 'Valentina Sofía Cortés Lara'],
    areas: [
      { id: 'AREA-ECOENT-01', nombre: 'Aprovechamiento Cali', empleadosIds: ['E0198', 'E0142', 'E0067'] },
      { id: 'AREA-ECOENT-02', nombre: 'Calidad Cali',         empleadosIds: ['E0011'] },
    ],
  },
  {
    id: 'SOC-ECOLOGISTICA', nombre: 'ECOLOGISTICA', prefijo: 'ECL',
    nit: '900.567.890-4', centroCosto: 'CC-ECL-ADM', direccion: 'Calle 30 #45-20, Barranquilla, Atlántico',
    descripcion: 'Recolección, transporte y logística de residuos en la costa Caribe.',
    logo: null, representantesLegales: ['Luis Fernando Cárdenas Ospina'],
    areas: [
      { id: 'AREA-ECOLOG-01', nombre: 'Recolección Barranquilla', empleadosIds: ['E0177', 'E0128'] },
      { id: 'AREA-ECOLOG-02', nombre: 'Mantenimiento Cali',       empleadosIds: ['E0156'] },
    ],
  },
  {
    id: 'SOC-BYC', nombre: 'BYC', prefijo: 'BYC',
    nit: '900.678.901-5', centroCosto: 'CC-BYC-ADM', direccion: 'Zona Franca Las Américas, Santo Domingo, Rep. Dominicana',
    descripcion: 'Operación internacional — República Dominicana y Guatemala.',
    logo: null, representantesLegales: ['María Camila Duarte Rincón'],
    areas: [
      { id: 'AREA-BYC-01', nombre: 'Operación Santo Domingo', empleadosIds: ['E0301', 'E0302', 'E0303', 'E0304', 'E0305', 'E0306'] },
      { id: 'AREA-BYC-02', nombre: 'Operación Guatemala',     empleadosIds: ['E0311', 'E0312', 'E0313', 'E0314', 'E0315', 'E0316'] },
    ],
  },
];

const EmpleadoRow = ({ id, subtitle }) => {
  const e = getEmpleadoById(id);
  if (!e) return null;
  const s = window.STATUS_META ? window.STATUS_META[e.status] : null;
  return (
    <div className="doc-cell-emp" style={{ padding: '10px 0', borderBottom: '1px solid var(--border)' }}>
      <div className="doc-avatar">{e.initials}</div>
      <div style={{ minWidth: 0, flex: 1 }}>
        <div style={{ fontWeight: 600, fontSize: 13 }}>{e.name}</div>
        <div className="muted" style={{ fontSize: 11.5, marginTop: 1 }}>{e.role} · {subtitle || e.site}</div>
      </div>
      {s && <span className={`pill ${s.pill}`} style={{ fontSize: 10.5 }}>{s.label}</span>}
    </div>
  );
};

const SociedadesSection = () => {
  const [sociedades, setSociedades]         = _cf_useState(SOCIEDADES_SEED);
  const [openSociedadId, setOpenSociedadId] = _cf_useState(null);
  const [openArea, setOpenArea]             = _cf_useState(null); // { sociedadId, areaId }
  const [nuevaAreaFor, setNuevaAreaFor]      = _cf_useState(null); // sociedadId
  const [viewMode, setViewMode]             = _cf_useState('cards'); // 'cards' | 'table'
  const [nuevaEmpresaOpen, setNuevaEmpresaOpen] = _cf_useState(false);

  const openSociedad = sociedades.find(s => s.id === openSociedadId) || null;
  const openAreaSociedad = openArea ? sociedades.find(s => s.id === openArea.sociedadId) : null;
  const openAreaObj = openAreaSociedad ? openAreaSociedad.areas.find(a => a.id === openArea.areaId) : null;
  const nuevaAreaSociedad = sociedades.find(s => s.id === nuevaAreaFor) || null;

  const handleAddArea = (sociedadId, nombre) => {
    setSociedades(prev => prev.map(s => s.id === sociedadId
      ? { ...s, areas: [...s.areas, { id: `AREA-${Date.now()}`, nombre, empleadosIds: [] }] }
      : s));
    setNuevaAreaFor(null);
  };

  const handleAddSociedad = (form) => {
    setSociedades(prev => [...prev, {
      id: form.codigo.trim() || `SOC-${Date.now()}`,
      nombre: form.nombre.trim(), prefijo: form.prefijo.trim(),
      nit: form.nit.trim(), centroCosto: form.centroCosto.trim(), direccion: form.direccion.trim(),
      descripcion: form.descripcion.trim(), logo: form.logo || null,
      representantesLegales: [], areas: [],
    }]);
    setNuevaEmpresaOpen(false);
  };

  return (
    <>
      <div className="cf-section-head">
        <div>
          <h2 className="cf-section-title">Sociedades</h2>
          <p className="cf-section-sub">
            Razones sociales de Atica. Cada sociedad agrupa sus áreas, sus representantes legales y los colaboradores vinculados a cada una.
          </p>
        </div>
        <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
          <div className="view-toggle">
            <button className={viewMode === 'cards' ? 'active' : ''} onClick={() => setViewMode('cards')} title="Tarjetas">
              <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="3" width="7" height="7" rx="1" /><rect x="14" y="3" width="7" height="7" rx="1" /><rect x="3" y="14" width="7" height="7" rx="1" /><rect x="14" y="14" width="7" height="7" rx="1" /></svg>
            </button>
            <button className={viewMode === 'table' ? 'active' : ''} onClick={() => setViewMode('table')} title="Tabla">
              <IconMenu size={15} />
            </button>
          </div>
          <button className="btn primary" onClick={() => setNuevaEmpresaOpen(true)}>
            <IconPlus size={14} /> Nueva empresa
          </button>
        </div>
      </div>

      {viewMode === 'cards' ? (
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: 16 }}>
          {sociedades.map(soc => {
            const total = soc.areas.reduce((sum, a) => sum + a.empleadosIds.length, 0);
            return (
              <div key={soc.id} className="doc-list-card" style={{ padding: 18 }}>
                <div
                  onClick={() => setOpenSociedadId(soc.id)}
                  style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, cursor: 'pointer' }}
                >
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                    <IconBuilding size={16} style={{ color: 'var(--navy-800)' }} />
                    <h3 style={{ margin: 0, fontSize: 15 }}>{soc.nombre}</h3>
                  </div>
                  <span className="pill navy">{total} colaborador{total === 1 ? '' : 'es'}</span>
                </div>

                <div style={{ marginBottom: 14 }}>
                  <div className="muted-xs" style={{ marginBottom: 4 }}>
                    Representante{(soc.representantesLegales || []).length === 1 ? '' : 's'} legal{(soc.representantesLegales || []).length === 1 ? '' : 'es'}
                  </div>
                  {(soc.representantesLegales || []).length > 0 ? (
                    <div className="signer-chips">
                      {soc.representantesLegales.map((rl, i) => <span key={i} className="signer-chip">{rl}</span>)}
                    </div>
                  ) : (
                    <div className="muted" style={{ fontSize: 12 }}>Sin representante legal asignado</div>
                  )}
                </div>

                <div>
                  {soc.areas.map(a => (
                    <div
                      key={a.id}
                      className="list-row"
                      style={{ cursor: 'pointer' }}
                      onClick={() => setOpenArea({ sociedadId: soc.id, areaId: a.id })}
                    >
                      <span className="ttl">{a.nombre}</span>
                      <span className="right mono" style={{ fontWeight: 700 }}>{a.empleadosIds.length}</span>
                    </div>
                  ))}
                </div>
              </div>
            );
          })}
        </div>
      ) : (
        <div className="doc-list-card">
          <table className="data-table">
            <thead>
              <tr>
                <th>Código</th><th>Nombre</th><th>NIT</th><th>Centro de costo</th>
                <th>Representantes legales</th><th style={{ textAlign: 'center' }}>Colaboradores</th><th></th>
              </tr>
            </thead>
            <tbody>
              {sociedades.map(soc => {
                const total = soc.areas.reduce((sum, a) => sum + a.empleadosIds.length, 0);
                return (
                  <tr key={soc.id}>
                    <td className="mono muted">{soc.id}</td>
                    <td style={{ fontWeight: 600 }}>{soc.nombre}</td>
                    <td className="mono muted">{soc.nit || '—'}</td>
                    <td className="mono muted">{soc.centroCosto || '—'}</td>
                    <td>
                      {(soc.representantesLegales || []).length > 0 ? (
                        <div className="signer-chips">
                          {soc.representantesLegales.map((rl, i) => <span key={i} className="signer-chip">{rl}</span>)}
                        </div>
                      ) : <span className="muted" style={{ fontSize: 12 }}>Sin asignar</span>}
                    </td>
                    <td style={{ textAlign: 'center', fontWeight: 700 }} className="mono">{total}</td>
                    <td style={{ textAlign: 'right' }}>
                      <button className="btn" style={{ padding: '4px 10px', fontSize: 12 }} onClick={() => setOpenSociedadId(soc.id)}>Ver</button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}

      {openSociedad && (
        <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) setOpenSociedadId(null); }}>
          <div className="modal" style={{ maxWidth: 640, height: 'calc(100vh - 64px)' }}>
            <div className="modal-head">
              <div>
                <div className="muted mono" style={{ fontSize: 11 }}>{openSociedad.id}</div>
                <div className="modal-title">{openSociedad.nombre}</div>
                <div className="modal-sub">
                  {openSociedad.areas.reduce((sum, a) => sum + a.empleadosIds.length, 0)} colaboradores en {openSociedad.areas.length} área{openSociedad.areas.length === 1 ? '' : 's'}
                </div>
              </div>
              <button className="icon-btn" onClick={() => setOpenSociedadId(null)} title="Cerrar">
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
              </button>
            </div>
            <div className="modal-body">
              <div className="furat-grid-2" style={{ marginBottom: 16 }}>
                <div className="furat-row">
                  <label className="furat-label">Prefijo</label>
                  <div className="mono" style={{ fontSize: 13 }}>{openSociedad.prefijo || '—'}</div>
                </div>
                <div className="furat-row">
                  <label className="furat-label">NIT</label>
                  <div className="mono" style={{ fontSize: 13 }}>{openSociedad.nit || '—'}</div>
                </div>
                <div className="furat-row">
                  <label className="furat-label">Centro de costo</label>
                  <div className="mono" style={{ fontSize: 13 }}>{openSociedad.centroCosto || '—'}</div>
                </div>
                <div className="furat-row">
                  <label className="furat-label">Dirección</label>
                  <div style={{ fontSize: 13 }}>{openSociedad.direccion || '—'}</div>
                </div>
              </div>
              {openSociedad.descripcion && (
                <p className="muted" style={{ fontSize: 12.5, margin: '0 0 16px', lineHeight: 1.55 }}>{openSociedad.descripcion}</p>
              )}
              <div style={{ marginBottom: 18 }}>
                <div className="muted-xs" style={{ marginBottom: 6 }}>
                  Representante{(openSociedad.representantesLegales || []).length === 1 ? '' : 's'} legal{(openSociedad.representantesLegales || []).length === 1 ? '' : 'es'}
                </div>
                {(openSociedad.representantesLegales || []).length > 0 ? (
                  <div className="signer-chips">
                    {openSociedad.representantesLegales.map((rl, i) => <span key={i} className="signer-chip">{rl}</span>)}
                  </div>
                ) : (
                  <div className="muted" style={{ fontSize: 12 }}>Sin representante legal asignado</div>
                )}
              </div>
              <button className="btn primary" style={{ marginBottom: 16 }} onClick={() => setNuevaAreaFor(openSociedad.id)}>
                <IconPlus size={14} /> Nueva área
              </button>
              {openSociedad.areas.map(a => (
                <div key={a.id} style={{ marginBottom: 18 }}>
                  <div className="muted-xs" style={{ marginBottom: 4, display: 'flex', justifyContent: 'space-between' }}>
                    <span>{a.nombre.toUpperCase()}</span>
                    <span>{a.empleadosIds.length}</span>
                  </div>
                  {a.empleadosIds.length === 0
                    ? <div className="muted" style={{ fontSize: 12, padding: '8px 0' }}>Sin colaboradores asignados todavía.</div>
                    : a.empleadosIds.map(id => <EmpleadoRow key={id} id={id} />)}
                </div>
              ))}
            </div>
            <div className="modal-foot">
              <button className="btn" onClick={() => setOpenSociedadId(null)}>Cerrar</button>
            </div>
          </div>
        </div>
      )}

      {openAreaObj && (
        <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) setOpenArea(null); }}>
          <div className="modal" style={{ maxWidth: 560, height: 'calc(100vh - 64px)' }}>
            <div className="modal-head">
              <div>
                <div className="muted mono" style={{ fontSize: 11 }}>{openAreaSociedad.nombre}</div>
                <div className="modal-title">{openAreaObj.nombre}</div>
                <div className="modal-sub">{openAreaObj.empleadosIds.length} colaboradores en esta área</div>
              </div>
              <button className="icon-btn" onClick={() => setOpenArea(null)} title="Cerrar">
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
              </button>
            </div>
            <div className="modal-body">
              {openAreaObj.empleadosIds.length === 0
                ? <div className="muted" style={{ fontSize: 12, padding: '8px 0' }}>Sin colaboradores asignados todavía.</div>
                : openAreaObj.empleadosIds.map(id => <EmpleadoRow key={id} id={id} />)}
            </div>
            <div className="modal-foot">
              <button className="btn" onClick={() => setOpenArea(null)}>Cerrar</button>
            </div>
          </div>
        </div>
      )}

      {nuevaAreaSociedad && (
        <NuevaAreaModal
          sociedad={nuevaAreaSociedad}
          onClose={() => setNuevaAreaFor(null)}
          onSave={(nombre) => handleAddArea(nuevaAreaSociedad.id, nombre)}
        />
      )}

      {nuevaEmpresaOpen && (
        <NuevaEmpresaModal
          onClose={() => setNuevaEmpresaOpen(false)}
          onSave={handleAddSociedad}
        />
      )}
    </>
  );
};

const NuevaAreaModal = ({ sociedad, onClose, onSave }) => {
  const [nombre, setNombre] = _cf_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); };
  }, []);

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 420 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">Nueva área</div>
            <div className="modal-sub">Se creará dentro de <b>{sociedad.nombre}</b> con 0 colaboradores.</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <div className="furat-row">
            <label className="furat-label">Nombre del área</label>
            <input type="text" autoFocus value={nombre} onChange={e => setNombre(e.target.value)} placeholder="Ej: Admon Cartagena" />
          </div>
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" disabled={!nombre.trim()} onClick={() => onSave(nombre.trim())}>
            <IconCheck size={14} /> Guardar área
          </button>
        </div>
      </div>
    </div>
  );
};

const NuevaEmpresaModal = ({ onClose, onSave }) => {
  const [form, setForm] = _cf_useState({
    codigo: '', prefijo: '', centroCosto: '', nit: '', nombre: '', direccion: '', logo: '', descripcion: '',
  });

  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 set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const canSave = form.codigo.trim() && form.nombre.trim() && form.nit.trim();

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 640 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">Nueva empresa</div>
            <div className="modal-sub">Crea una nueva sociedad dentro del grupo Atica.</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <div className="form-grid">
            <FormField label="Código" span={3}>
              <input className="form-input" value={form.codigo} onChange={e => set('codigo', e.target.value)} placeholder="Ej: SOC-NUEVA" />
            </FormField>
            <FormField label="Prefijo" span={3}>
              <input className="form-input" value={form.prefijo} onChange={e => set('prefijo', e.target.value)} placeholder="Ej: NVA" />
            </FormField>
            <FormField label="Centro de costo" span={3}>
              <input className="form-input" value={form.centroCosto} onChange={e => set('centroCosto', e.target.value)} placeholder="Ej: CC-NVA-ADM" />
            </FormField>
            <FormField label="NIT" span={3}>
              <input className="form-input" value={form.nit} onChange={e => set('nit', e.target.value)} placeholder="Ej: 900.111.222-3" />
            </FormField>
            <FormField label="Nombre" span={6}>
              <input className="form-input" value={form.nombre} onChange={e => set('nombre', e.target.value)} placeholder="Ej: Nueva Sociedad SAS" />
            </FormField>
            <FormField label="Dirección" span={6}>
              <input className="form-input" value={form.direccion} onChange={e => set('direccion', e.target.value)} placeholder="Ej: Calle 10 #20-30, Cali, Valle del Cauca" />
            </FormField>
            <FormField label="Logo" span={6}>
              <input className="form-input" type="file" accept="image/*" onChange={e => set('logo', e.target.files[0]?.name || '')} />
              {form.logo && <div className="muted mono" style={{ fontSize: 11.5, marginTop: 4 }}>{form.logo}</div>}
            </FormField>
            <FormField label="Descripción" span={6}>
              <textarea className="form-input" rows={3} value={form.descripcion} onChange={e => set('descripcion', e.target.value)} placeholder="¿A qué se dedica esta sociedad dentro del grupo?" />
            </FormField>
          </div>
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" disabled={!canSave} onClick={() => onSave(form)}>
            <IconCheck size={14} /> Guardar empresa
          </button>
        </div>
      </div>
    </div>
  );
};

// ─── Section: Bandas salariales ───────────────────────────
// Cada banda se vincula a un cargo de CARGOS_CATALOG_SEED (sección Cargos, arriba).
// Un cargo activo solo puede tener una banda vigente a la vez.

const getCargoById = (id) => CARGOS_CATALOG_SEED.find(c => c.id === id);

const formatCOP = (n) => (n === '' || n === null || n === undefined) ? '' : '$ ' + Number(n).toLocaleString('es-CO');

const CurrencyInput = ({ value, onChange, placeholder }) => (
  <input
    type="text"
    inputMode="numeric"
    value={formatCOP(value)}
    onChange={e => {
      const digits = e.target.value.replace(/\D/g, '');
      onChange(digits === '' ? '' : Number(digits));
    }}
    placeholder={placeholder}
  />
);

const BANDAS_SEED = [
  { id: 'BND-001', nombre: 'Banda Operario Nivel 1',         cargoId: 'CGO-001', estado: 'activo',   salarioMinimo: 1300000, salarioMedio: 1450000, salarioMaximo: 1600000 },
  { id: 'BND-002', nombre: 'Banda Operario Aprovechamiento', cargoId: 'CGO-003', estado: 'activo',   salarioMinimo: 1300000, salarioMedio: 1475000, salarioMaximo: 1650000 },
  { id: 'BND-003', nombre: 'Banda Liderazgo Operativo',      cargoId: 'CGO-004', estado: 'activo',   salarioMinimo: 2200000, salarioMedio: 2550000, salarioMaximo: 2900000 },
  { id: 'BND-004', nombre: 'Banda Técnico Mantenimiento',    cargoId: 'CGO-006', estado: 'inactivo', salarioMinimo: 1800000, salarioMedio: 2100000, salarioMaximo: 2400000 },
];

const BandasSalarialesSection = () => {
  const [bandas, setBandas]     = _cf_useState(BANDAS_SEED);
  const [modal, setModal]       = _cf_useState(null); // null | 'new' | banda
  const [bulkOpen, setBulkOpen] = _cf_useState(false);

  const handleSave = (data) => {
    setBandas(prev => {
      const exists = prev.some(b => b.id === data.id);
      return exists ? prev.map(b => b.id === data.id ? data : b) : [...prev, data];
    });
    setModal(null);
  };

  const handleDelete = (b) => {
    if (!confirm(`¿Eliminar la banda salarial "${b.nombre}"?`)) return;
    setBandas(prev => prev.filter(x => x.id !== b.id));
  };

  return (
    <>
      <div className="cf-section-head">
        <div>
          <h2 className="cf-section-title">Bandas salariales</h2>
          <p className="cf-section-sub">
            Rangos salariales definidos por cargo. Cada cargo activo puede tener una única banda vigente.
          </p>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button className="btn" onClick={() => setBulkOpen(true)}><IconExternal size={14} /> Cargar bandas masivas</button>
          <button className="btn primary" onClick={() => setModal('new')}><IconPlus size={14} /> Nueva banda salarial</button>
        </div>
      </div>

      <div className="doc-list-card">
        <table className="doc-table">
          <thead>
            <tr>
              <th>Nombre de banda salarial</th>
              <th>Cargo asociado</th>
              <th>Código del cargo</th>
              <th>Estado</th>
              <th>Mínimo de banda</th>
              <th>Máximo de banda</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {bandas.map(b => {
              const cargo = getCargoById(b.cargoId);
              const s = STATE_CARGO[b.estado];
              return (
                <tr key={b.id}>
                  <td style={{ fontWeight: 600, fontSize: 13 }}>{b.nombre}</td>
                  <td style={{ fontSize: 13 }}>{cargo ? cargo.nombre : '—'}</td>
                  <td className="mono muted" style={{ fontSize: 12 }}>{cargo ? cargo.codigo : '—'}</td>
                  <td>
                    <span className={`pill ${s.pill}`}>
                      <span className="status-dot" style={{ background: s.dot }} /> {s.label}
                    </span>
                  </td>
                  <td className="mono" style={{ fontSize: 12.5, fontWeight: 700 }}>{formatCOP(b.salarioMinimo)}</td>
                  <td className="mono" style={{ fontSize: 12.5, fontWeight: 700 }}>{formatCOP(b.salarioMaximo)}</td>
                  <td>
                    <div className="doc-actions">
                      <button className="icon-action" title="Modificar" onClick={() => setModal(b)}><IconExternal size={14} /></button>
                      <button className="icon-action danger" title="Eliminar" onClick={() => handleDelete(b)}><IconTrash size={14} /></button>
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      {modal && (
        <BandaFormModal
          banda={modal === 'new' ? null : modal}
          allBandas={bandas}
          onClose={() => setModal(null)}
          onSave={handleSave}
        />
      )}
      {bulkOpen && <BandaBulkUploadModal onClose={() => setBulkOpen(false)} />}
    </>
  );
};

const BandaFormModal = ({ banda, allBandas, onClose, onSave }) => {
  const [form, setForm] = _cf_useState(() => banda ? { ...banda } : {
    id: null, nombre: '', cargoId: '', estado: 'activo',
    salarioMedio: '', salarioMinimo: '', salarioMaximo: '',
  });

  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 set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const cargosDisponibles = CARGOS_CATALOG_SEED.filter(c =>
    c.estado === 'activo' &&
    (c.id === form.cargoId || !allBandas.some(b => b.cargoId === c.id && b.id !== form.id))
  );

  const handleGuardar = () => {
    onSave({
      ...form,
      id: form.id || `BND-${Date.now()}`,
      salarioMinimo: Number(form.salarioMinimo) || 0,
      salarioMedio: Number(form.salarioMedio) || 0,
      salarioMaximo: Number(form.salarioMaximo) || 0,
    });
  };

  const canSave = form.nombre.trim() && form.cargoId && form.salarioMinimo !== '' && form.salarioMaximo !== '';

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 520 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">{banda ? 'Editar banda salarial' : 'Nueva banda salarial'}</div>
            <div className="modal-sub">Define el rango salarial asociado a un cargo activo.</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <div className="furat-row">
            <label className="furat-label">Nombre de banda</label>
            <input type="text" value={form.nombre} onChange={e => set('nombre', e.target.value)} placeholder="Ej: Banda Operario Nivel 1" />
          </div>
          <div className="furat-row">
            <label className="furat-label">Cargo de banda</label>
            <select value={form.cargoId} onChange={e => set('cargoId', e.target.value)}>
              <option value="">— Selecciona un cargo —</option>
              {cargosDisponibles.map(c => <option key={c.id} value={c.id}>{c.nombre} ({c.codigo})</option>)}
            </select>
            {cargosDisponibles.length === 0 && (
              <div className="muted" style={{ fontSize: 11.5, marginTop: 2 }}>Todos los cargos activos ya tienen una banda asignada.</div>
            )}
          </div>
          <div className="furat-grid-2">
            <div className="furat-row">
              <label className="furat-label">Salario mínimo</label>
              <CurrencyInput value={form.salarioMinimo} onChange={v => set('salarioMinimo', v)} placeholder="$ 0" />
            </div>
            <div className="furat-row">
              <label className="furat-label">Salario medio</label>
              <CurrencyInput value={form.salarioMedio} onChange={v => set('salarioMedio', v)} placeholder="$ 0" />
            </div>
            <div className="furat-row">
              <label className="furat-label">Salario máximo</label>
              <CurrencyInput value={form.salarioMaximo} onChange={v => set('salarioMaximo', v)} placeholder="$ 0" />
            </div>
          </div>
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" onClick={handleGuardar} disabled={!canSave}>
            <IconCheck size={14} /> Guardar banda
          </button>
        </div>
      </div>
    </div>
  );
};

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

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 520 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">Cargue masivo de bandas salariales</div>
            <div className="modal-sub">Sube un archivo Excel con las bandas salariales por cargo.</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <button className="link-btn" style={{ display: 'inline-flex', alignItems: 'center', gap: 6, marginBottom: 14 }}>
            <IconExternal size={13} /> Descargar plantilla .xlsx
          </button>
          <div style={{ border: '2px dashed var(--border)', borderRadius: 12, padding: '36px 20px', textAlign: 'center', color: 'var(--text-muted)' }}>
            <IconDoc size={26} style={{ marginBottom: 8, opacity: 0.5 }} />
            <div style={{ fontWeight: 600, fontSize: 13.5, color: 'var(--text)' }}>Arrastra el archivo Excel aquí</div>
            <div style={{ fontSize: 12, marginTop: 4 }}>o haz clic para buscarlo · formato .xlsx</div>
          </div>
          <div className="muted" style={{ fontSize: 11.5, marginTop: 12, lineHeight: 1.5 }}>
            <IconShield size={11} /> Las bandas con cargo existente se actualizarán; los cargos sin banda previa crearán una nueva.
          </div>
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" disabled><IconCheck size={14} /> Cargar archivo</button>
        </div>
      </div>
    </div>
  );
};

// ─── Section: Matrices ───────────────────────────────────

const MatricesSection = ({ onEdit }) => {
  return (
    <>
      <div className="cf-section-head">
        <div>
          <h2 className="cf-section-title">Matrices por cargo</h2>
          <p className="cf-section-sub">
            Configura qué dotación, EPP, capacitaciones, exámenes, documentos y tareas de onboarding aplican a cada cargo.
            Es el corazón del motor de automatización: al crear un colaborador se aplica la matriz de su cargo.
          </p>
        </div>
        <button className="btn primary"><IconPlus size={14} /> Nueva matriz</button>
      </div>

      <div className="doc-list-card">
        <table className="doc-table">
          <thead>
            <tr>
              <th>Cargo</th>
              <th style={{ textAlign: 'center' }}>Activos</th>
              <th>Composición</th>
              <th>Última actualización</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {ROLE_MATRICES_FULL.map(m => (
              <tr key={m.id}>
                <td>
                  <div style={{ fontWeight: 700, fontSize: 13.5 }}>{m.role}</div>
                  <div className="muted mono" style={{ fontSize: 11 }}>{m.id.toUpperCase()}</div>
                </td>
                <td style={{ textAlign: 'center', fontFamily: 'JetBrains Mono', fontSize: 14, fontWeight: 700 }}>
                  {m.active}
                </td>
                <td>
                  <div className="cf-comp-stats">
                    <span><IconShirt size={11} /> Dot <b>{m.counts.dot}</b></span>
                    <span><IconShield size={11} /> EPP <b>{m.counts.epp}</b></span>
                    <span><IconBook size={11} /> Cap <b>{m.counts.cap}</b></span>
                    <span><IconStar size={11} /> Exá <b>{m.counts.exa}</b></span>
                    <span><IconDoc size={11} /> Doc <b>{m.counts.doc}</b></span>
                    <span><IconRocket size={11} /> Onb <b>{m.counts.onb}</b></span>
                  </div>
                </td>
                <td className="mono muted" style={{ fontSize: 12 }}>{m.updated}</td>
                <td>
                  <button className="btn primary" style={{ padding: '5px 12px', fontSize: 12 }} onClick={() => onEdit(m)}>
                    <IconExternal size={13} /> Editar matriz
                  </button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </>
  );
};

// ─── Matrix editor (6 tabs) ──────────────────────────────

const MatrixEditor = ({ matrix, onClose }) => {
  const [tab, setTab]   = _cf_useState('dotacion');
  const [recalc, setRC] = _cf_useState(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); };
  }, []);

  const TABS = [
    ['dotacion',       'Dotación',        'IconShirt',  matrix.counts.dot],
    ['epp',            'EPP',             'IconShield', matrix.counts.epp],
    ['capacitaciones', 'Capacitaciones',  'IconBook',   matrix.counts.cap],
    ['examenes',       'Exámenes SST',    'IconStar',   matrix.counts.exa],
    ['documentos',     'Documentos',      'IconDoc',    matrix.counts.doc],
    ['onboarding',     'Onboarding',      'IconRocket', matrix.counts.onb],
  ];

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal cf-mx-modal" style={{ maxWidth: 1200, height: 'calc(100vh - 64px)' }}>
        <div className="modal-head cf-mx-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>{matrix.id.toUpperCase()}</div>
            <div className="modal-title">Matriz del cargo: {matrix.role}</div>
            <div className="modal-sub">
              <b>{matrix.active} colaboradores activos</b> con este cargo · última actualización {matrix.updated}
            </div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>

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

        <div className="modal-body cf-mx-body">
          {tab === 'dotacion'       && <DotacionEppTable rows={MATRIX_OP_TOSTION.dotacion} />}
          {tab === 'epp'            && <DotacionEppTable rows={MATRIX_OP_TOSTION.epp} />}
          {tab === 'capacitaciones' && <CapacitacionesTable rows={MATRIX_OP_TOSTION.capacitaciones} />}
          {tab === 'examenes'       && <ExamenesTable rows={MATRIX_OP_TOSTION.examenes} />}
          {tab === 'documentos'     && <DocumentosTable rows={MATRIX_OP_TOSTION.documentos} />}
          {tab === 'onboarding'     && <OnboardingTable rows={MATRIX_OP_TOSTION.onboarding} />}

          <div className="cf-mx-warning">
            <IconAlert size={14} />
            <span>
              Esta configuración se aplicará a <b>todos los empleados con este cargo que ingresen de ahora en adelante.</b>
              Para aplicar a empleados existentes, usa el botón <b>Recalcular obligaciones</b>.
            </span>
            <label className="cf-mx-recalc">
              <input type="checkbox" checked={recalc} onChange={(e) => setRC(e.target.checked)} />
              <span>Recalcular obligaciones para los {matrix.active} empleados existentes con este cargo</span>
            </label>
          </div>
        </div>

        <div className="modal-foot">
          <span className="muted" style={{ fontSize: 12, marginRight: 'auto' }}>
            <IconCheck size={12} style={{ color: 'var(--green-600)' }} /> Cambios guardados localmente
          </span>
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn">Guardar borrador</button>
          <button className="btn primary"><IconCheck size={14} /> Guardar y aplicar</button>
        </div>
      </div>
    </div>
  );
};

// ─── Tables for matrix editor ────────────────────────────

const DotacionEppTable = ({ rows }) => (
  <div className="doc-list-card">
    <table className="doc-table">
      <thead>
        <tr>
          <th>Ítem</th>
          <th style={{ textAlign: 'center' }}>Cantidad</th>
          <th>Talla</th>
          <th style={{ textAlign: 'center' }}>Obligatorio</th>
          <th>Momento</th>
          <th>Frecuencia</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        {rows.map((r, i) => (
          <tr key={i}>
            <td style={{ fontWeight: 600, fontSize: 13 }}>{r.name}</td>
            <td style={{ textAlign: 'center', fontFamily: 'JetBrains Mono', fontSize: 13 }}>{r.qty}</td>
            <td className="muted" style={{ fontSize: 12 }}>{r.size}</td>
            <td style={{ textAlign: 'center' }}>
              <label className="epp-toggle">
                <input type="checkbox" defaultChecked={r.mandatory} />
                <span className="epp-toggle-track" />
              </label>
            </td>
            <td>
              <span className={`pill ${r.moment === 'ingreso' ? 'navy' : 'amber-soft'}`} style={{ fontSize: 11 }}>
                {r.moment === 'ingreso' ? 'Al ingreso' : 'Periódico'}
              </span>
            </td>
            <td className="muted" style={{ fontSize: 12 }}>{r.freq}</td>
            <td>
              <button className="icon-action danger" title="Eliminar"><IconAlert size={13} /></button>
            </td>
          </tr>
        ))}
        <tr>
          <td colSpan={7} style={{ padding: 0 }}>
            <button className="cf-add-row"><IconPlus size={13} /> Agregar ítem desde catálogo</button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
);

const CapacitacionesTable = ({ rows }) => (
  <div className="doc-list-card">
    <table className="doc-table">
      <thead>
        <tr>
          <th>Curso</th>
          <th>Duración</th>
          <th style={{ textAlign: 'center' }}>Obligatorio</th>
          <th>Plazo desde ingreso</th>
          <th>Recurrencia</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        {rows.map((r, i) => (
          <tr key={i}>
            <td style={{ fontWeight: 600, fontSize: 13 }}>{r.name}</td>
            <td className="muted" style={{ fontSize: 12 }}>{r.duration}</td>
            <td style={{ textAlign: 'center' }}>
              <label className="epp-toggle">
                <input type="checkbox" defaultChecked={r.mandatory} />
                <span className="epp-toggle-track" />
              </label>
            </td>
            <td><span className="cf-num-badge">{r.delay}</span> <span className="muted" style={{ fontSize: 11 }}>días</span></td>
            <td><span className={`pill ${r.recur === 'Anual' ? 'amber-soft' : 'green'}`} style={{ fontSize: 11 }}>{r.recur}</span></td>
            <td><button className="icon-action danger"><IconAlert size={13} /></button></td>
          </tr>
        ))}
        <tr><td colSpan={6} style={{ padding: 0 }}>
          <button className="cf-add-row"><IconPlus size={13} /> Agregar curso desde catálogo</button>
        </td></tr>
      </tbody>
    </table>
  </div>
);

const ExamenesTable = ({ rows }) => (
  <div className="doc-list-card">
    <table className="doc-table">
      <thead>
        <tr>
          <th>Tipo de examen</th>
          <th>Plazo desde ingreso</th>
          <th>Frecuencia</th>
          <th>Laboratorio sugerido</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        {rows.map((r, i) => (
          <tr key={i}>
            <td style={{ fontWeight: 600, fontSize: 13 }}>{r.type}</td>
            <td><span className="cf-num-badge">{r.delay}</span> <span className="muted" style={{ fontSize: 11 }}>días</span></td>
            <td><span className={`pill ${r.freq === 'Anual' ? 'amber-soft' : 'green'}`} style={{ fontSize: 11 }}>{r.freq}</span></td>
            <td className="muted" style={{ fontSize: 12 }}>{r.lab}</td>
            <td><button className="icon-action danger"><IconAlert size={13} /></button></td>
          </tr>
        ))}
        <tr><td colSpan={5} style={{ padding: 0 }}>
          <button className="cf-add-row"><IconPlus size={13} /> Agregar tipo de examen</button>
        </td></tr>
      </tbody>
    </table>
  </div>
);

const DocumentosTable = ({ rows }) => (
  <div className="doc-list-card">
    <table className="doc-table">
      <thead>
        <tr>
          <th>Tipo de documento</th>
          <th>Momento de generación</th>
          <th>Firmantes requeridos</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        {rows.map((r, i) => (
          <tr key={i}>
            <td style={{ fontWeight: 600, fontSize: 13 }}>{r.type}</td>
            <td>
              <span className={`pill ${r.moment === 'ingreso' ? 'navy' : r.moment === 'retiro' ? 'rose' : 'amber-soft'}`} style={{ fontSize: 11 }}>
                {r.moment === 'ingreso' ? 'Al ingreso' : r.moment === 'retiro' ? 'Al retiro' : 'Periódico'}
              </span>
            </td>
            <td>
              <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap' }}>
                {r.signers.map((s, j) => (
                  <span key={j} className="signer-chip">{s}</span>
                ))}
              </div>
            </td>
            <td><button className="icon-action danger"><IconAlert size={13} /></button></td>
          </tr>
        ))}
        <tr><td colSpan={4} style={{ padding: 0 }}>
          <button className="cf-add-row"><IconPlus size={13} /> Agregar documento desde plantillas</button>
        </td></tr>
      </tbody>
    </table>
  </div>
);

const OnboardingTable = ({ rows }) => (
  <div className="doc-list-card">
    <table className="doc-table">
      <thead>
        <tr>
          <th style={{ width: 60, textAlign: 'center' }}>#</th>
          <th>Tarea</th>
          <th>Responsable</th>
          <th>Plazo</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        {rows.map((r, i) => (
          <tr key={i}>
            <td style={{ textAlign: 'center' }}>
              <span className="cf-order-num">{r.order}</span>
            </td>
            <td style={{ fontWeight: 600, fontSize: 13 }}>{r.task}</td>
            <td className="muted" style={{ fontSize: 12 }}>{r.owner}</td>
            <td><span className="cf-num-badge">{r.days}d</span></td>
            <td>
              <div style={{ display: 'flex', gap: 4 }}>
                <button className="icon-action" title="Mover arriba"><IconChevronLeft size={13} style={{ transform: 'rotate(90deg)' }} /></button>
                <button className="icon-action" title="Mover abajo"><IconChevronRight size={13} style={{ transform: 'rotate(90deg)' }} /></button>
                <button className="icon-action danger"><IconAlert size={13} /></button>
              </div>
            </td>
          </tr>
        ))}
        <tr><td colSpan={5} style={{ padding: 0 }}>
          <button className="cf-add-row"><IconPlus size={13} /> Agregar tarea de onboarding</button>
        </td></tr>
      </tbody>
    </table>
  </div>
);

// ─── Section: Flujos ─────────────────────────────────────

const FlowsSection = ({ onEdit }) => {
  return (
    <>
      <div className="cf-section-head">
        <div>
          <h2 className="cf-section-title">Flujos de aprobación</h2>
          <p className="cf-section-sub">
            Define el camino de aprobación para cada tipo de solicitud. Cada paso tiene un SLA y un escalamiento automático si no se responde a tiempo.
          </p>
        </div>
        <button className="btn primary"><IconPlus size={14} /> Nuevo flujo</button>
      </div>

      <div className="cf-flows-list">
        {FLOWS.map(f => (
          <div key={f.id} className={`cf-flow-card ${!f.active ? 'inactive' : ''}`}>
            <div className="cf-flow-head">
              <div>
                <div className="muted mono" style={{ fontSize: 11 }}>{f.id.toUpperCase()}</div>
                <h3 className="cf-flow-title">{f.type}</h3>
                <div className="muted" style={{ fontSize: 12.5, marginTop: 4 }}>{f.description}</div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <span className={`pill ${f.active ? 'green' : 'navy'}`}>{f.active ? 'Activo' : 'Inactivo'}</span>
                <label className="epp-toggle">
                  <input type="checkbox" defaultChecked={f.active} />
                  <span className="epp-toggle-track" />
                </label>
              </div>
            </div>

            <div className="cf-flow-pipe">
              <div className="cf-flow-step start">
                <span className="cf-flow-step-icon"><IconRocket size={13} /></span>
                <div>
                  <div className="muted-xs">Inicio</div>
                  <div className="cf-flow-step-name">Solicitud</div>
                </div>
              </div>
              {f.steps.map((s, i) => (
                <React.Fragment key={i}>
                  <div className="cf-flow-arrow">→</div>
                  <div className="cf-flow-step">
                    <span className="cf-flow-step-num">{i + 1}</span>
                    <div>
                      <div className="cf-flow-step-name">{s.role}</div>
                      <div className="cf-flow-sla">
                        <IconClock size={10} /> SLA {s.sla} h
                      </div>
                      <div className="cf-flow-esc">
                        <span className="muted">si vence →</span> <b>{s.escalation}</b>
                      </div>
                    </div>
                  </div>
                </React.Fragment>
              ))}
              <div className="cf-flow-arrow">→</div>
              <div className="cf-flow-step end">
                <span className="cf-flow-step-icon"><IconCheck size={13} /></span>
                <div>
                  <div className="muted-xs">Fin</div>
                  <div className="cf-flow-step-name">Aprobada</div>
                </div>
              </div>
            </div>

            <div className="cf-flow-foot">
              <span className="muted" style={{ fontSize: 11.5 }}>
                Total {f.steps.length} {f.steps.length === 1 ? 'paso' : 'pasos'} · SLA total {f.steps.reduce((a, s) => a + s.sla, 0)} horas
              </span>
              <div style={{ flex: 1 }} />
              <button className="btn" style={{ padding: '5px 11px', fontSize: 12 }} onClick={() => onEdit(f)}>
                <IconExternal size={13} /> Editar flujo
              </button>
            </div>
          </div>
        ))}
      </div>
    </>
  );
};

// ─── Flow editor (drag & drop visual mock) ───────────────

const FlowEditor = ({ flow, onClose }) => {
  const [steps, setSteps] = _cf_useState(flow.steps);

  const move = (i, dir) => {
    const j = i + dir;
    if (j < 0 || j >= steps.length) return;
    const next = [...steps];
    [next[i], next[j]] = [next[j], next[i]];
    setSteps(next);
  };
  const remove = (i) => setSteps(s => s.filter((_, x) => x !== i));

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

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 980 }}>
        <div className="modal-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>{flow.id.toUpperCase()}</div>
            <div className="modal-title">Editor de flujo · {flow.type}</div>
            <div className="modal-sub">Reordena los pasos arrastrando con las flechas. Define rol aprobador, SLA y acción de escalamiento si no responde.</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>

        <div className="modal-body">
          <div className="cf-fe-canvas">
            <div className="cf-fe-step start">
              <span className="cf-flow-step-icon"><IconRocket size={14} /></span>
              <div>
                <div className="muted-xs">Inicio</div>
                <div style={{ fontWeight: 700, fontSize: 13 }}>Solicitud creada</div>
              </div>
            </div>

            {steps.map((s, i) => (
              <div key={i} className="cf-fe-step">
                <div className="cf-fe-step-grip">
                  <button className="icon-action" onClick={() => move(i, -1)} disabled={i === 0} title="Arriba">
                    <IconChevronLeft size={13} style={{ transform: 'rotate(90deg)' }} />
                  </button>
                  <span className="cf-flow-step-num">{i + 1}</span>
                  <button className="icon-action" onClick={() => move(i, 1)} disabled={i === steps.length - 1} title="Abajo">
                    <IconChevronRight size={13} style={{ transform: 'rotate(90deg)' }} />
                  </button>
                </div>
                <div className="cf-fe-step-fields">
                  <div>
                    <label className="muted-xs">Rol aprobador</label>
                    <select defaultValue={s.role}>
                      <option>Jefe directo</option>
                      <option>RRHH</option>
                      <option>Dirección</option>
                      <option>Contabilidad</option>
                      <option>Jefe del área</option>
                      <option>ARL · si aplica</option>
                    </select>
                  </div>
                  <div>
                    <label className="muted-xs">SLA (horas)</label>
                    <input type="number" defaultValue={s.sla} min="1" />
                  </div>
                  <div>
                    <label className="muted-xs">Si vence el SLA</label>
                    <select defaultValue={s.escalation}>
                      <option>RRHH</option>
                      <option>Dirección</option>
                      <option>CFO</option>
                      <option>CEO</option>
                      <option>Notificación legal</option>
                    </select>
                  </div>
                </div>
                <button className="icon-action danger" onClick={() => remove(i)} title="Quitar paso">
                  <IconAlert size={14} />
                </button>
              </div>
            ))}

            <button className="cf-fe-add" onClick={() => setSteps([...steps, { role: 'Jefe directo', sla: 24, escalation: 'RRHH' }])}>
              <IconPlus size={13} /> Agregar paso
            </button>

            <div className="cf-fe-step end">
              <span className="cf-flow-step-icon"><IconCheck size={14} /></span>
              <div>
                <div className="muted-xs">Fin</div>
                <div style={{ fontWeight: 700, fontSize: 13 }}>Solicitud aprobada · notificación al solicitante</div>
              </div>
            </div>
          </div>
        </div>

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

// ─── Section: Usuarios ───────────────────────────────────

// La cuenta de acceso "propia" del prototipo — mismo usuario que sidebar.jsx
// muestra como sesión activa (Carolina Restrepo · Admin RRHH). Se usa para
// bloquear la auto-inactivación.
const CURRENT_USER_ID = 'USR-0001';

// ¿Puede inactivarse este usuario? No si es la cuenta propia, y no si es el
// último administrador activo del sistema.
const puedeInactivar = (user, allUsers) => {
  if (user.estado === 'inactivo') return false;
  if (user.id === CURRENT_USER_ID) return false;
  if (user.rol === 'admin') {
    const otrosAdminsActivos = allUsers.filter(u => u.id !== user.id && u.rol === 'admin' && u.estado === 'activo').length;
    if (otrosAdminsActivos === 0) return false;
  }
  return true;
};
const motivoNoInactivar = (user, allUsers) => {
  if (user.id === CURRENT_USER_ID) return 'No puedes inactivar tu propia cuenta.';
  if (user.rol === 'admin') {
    const otrosAdminsActivos = allUsers.filter(u => u.id !== user.id && u.rol === 'admin' && u.estado === 'activo').length;
    if (otrosAdminsActivos === 0) return 'Debe existir al menos un administrador activo.';
  }
  return '';
};

const activacionDisplay = (u) => (u.estado === 'pendiente' ? 'Sin activar' : (u.fechaActivacion || 'Sin activar'));

const UserEstadoPill = ({ estado }) => {
  const s = STATE_USER[estado];
  return <span className={`pill ${s.pill}`}><span className="status-dot" style={{ background: s.dot }} /> {s.label}</span>;
};

// Badge/link de permisos extra — clic abre un popover con el resumen
// (además del hover vía title, para que funcione igual con teclado y touch).
const ExtraPermsCell = ({ user }) => {
  const [open, setOpen] = _cf_useState(false);
  const extras = effectiveExtraPerms(user);
  React.useEffect(() => {
    if (!open) return;
    const close = (e) => { if (!e.target.closest('.cf-user-permpop-wrap')) setOpen(false); };
    const t = setTimeout(() => document.addEventListener('click', close), 0);
    return () => { clearTimeout(t); document.removeEventListener('click', close); };
  }, [open]);

  if (extras.length === 0) return <span className="muted" style={{ fontSize: 12 }}>Sin permisos extra</span>;

  return (
    <div className="cf-user-permpop-wrap">
      <button
        type="button" className="cf-user-extra-badge"
        title={extras.map(p => permLabel(p.moduleId, p.actionIndex)).join(' · ')}
        onClick={() => setOpen(o => !o)}
      >
        {extras.length} permiso{extras.length === 1 ? '' : 's'} extra
      </button>
      {open && (
        <div className="cf-user-menu cf-user-permpop" onClick={(e) => e.stopPropagation()}>
          <div className="cf-user-permpop-head">Permisos extra</div>
          {extras.map((p, i) => <div key={i} className="cf-user-permpop-item">{permLabel(p.moduleId, p.actionIndex)}</div>)}
        </div>
      )}
    </div>
  );
};

const CanalUpdatedBadge = ({ user }) => {
  const pendientes = [];
  if (user.telefono && !user.telefonoVerificado) pendientes.push('Teléfono actualizado · Pendiente de verificar');
  if (user.correo && !user.correoVerificado) pendientes.push('Correo actualizado · Pendiente de verificar');
  if (pendientes.length === 0) return <span className="muted" style={{ fontSize: 12 }}>—</span>;
  return (
    <span className="pill amber-soft" title={pendientes.join(' · ')}>
      <IconAlert size={11} /> {pendientes.length > 1 ? `${pendientes.length} canales pendientes` : 'Pendiente de verificar'}
    </span>
  );
};

const UserRowMenu = ({ user, allUsers, onView, onEdit, onResend, onToggleEstado }) => {
  const [open, setOpen] = _cf_useState(false);
  React.useEffect(() => {
    if (!open) return;
    const close = (e) => { if (!e.target.closest('.cf-user-menu-wrap')) setOpen(false); };
    const t = setTimeout(() => document.addEventListener('click', close), 0);
    return () => { clearTimeout(t); document.removeEventListener('click', close); };
  }, [open]);

  const esInactivo = user.estado === 'inactivo';
  const puedeInact = puedeInactivar(user, allUsers);
  const motivo = motivoNoInactivar(user, allUsers);

  return (
    <div className="cf-user-menu-wrap">
      <button className="icon-action" title="Más acciones" onClick={() => setOpen(o => !o)}>
        <span aria-hidden="true">⋯</span>
      </button>
      {open && (
        <div className="cf-user-menu" onClick={(e) => e.stopPropagation()}>
          <button className="cf-user-menu-item" onClick={() => { setOpen(false); onView(user); }}>
            <IconExternal size={13} /> Ver usuario
          </button>
          <button className="cf-user-menu-item" onClick={() => { setOpen(false); onEdit(user); }}>
            <IconDoc size={13} /> Editar usuario
          </button>
          {!esInactivo && (
            <button className="cf-user-menu-item" onClick={() => { setOpen(false); onResend(user); }}>
              <IconMegaphone size={13} /> {user.estado === 'pendiente' ? 'Reenviar código de activación' : 'Enviar código de recuperación'}
            </button>
          )}
          {esInactivo ? (
            <button className="cf-user-menu-item" onClick={() => { setOpen(false); onToggleEstado(user, 'activo'); }}>
              <IconCheck size={13} /> Activar usuario
            </button>
          ) : (
            <button
              className="cf-user-menu-item danger" disabled={!puedeInact}
              title={motivo || undefined}
              onClick={() => { setOpen(false); onToggleEstado(user, 'inactivo'); }}
            >
              <IconAlert size={13} /> Inactivar usuario
            </button>
          )}
        </div>
      )}
    </div>
  );
};

// ─── Filtros ───────────────────────────────────────────────

const USERS_FILTROS_VACIOS = { rol: 'todos', estado: 'todos', sociedad: 'todas', oficina: 'todas', conExtra: false, pendientesActivacion: false };

const UserFiltersPanel = ({ filtros, setFiltro, limpiar, q, setQ, oficinasVisibles }) => (
  <div className="cf-user-filters-fields">
    <input
      className="form-input" placeholder="Buscar por nombre o documento"
      value={q} onChange={e => setQ(e.target.value)}
    />
    <select value={filtros.rol} onChange={e => setFiltro('rol', e.target.value)}>
      <option value="todos">Todos los roles</option>
      {Object.entries(ROLE_META).map(([k, m]) => <option key={k} value={k}>{m.label}</option>)}
    </select>
    <select value={filtros.estado} onChange={e => setFiltro('estado', e.target.value)}>
      <option value="todos">Todos los estados</option>
      {Object.entries(STATE_USER).map(([k, m]) => <option key={k} value={k}>{m.label}</option>)}
    </select>
    <select value={filtros.sociedad} onChange={e => setFiltro('sociedad', e.target.value)}>
      <option value="todas">Todas las sociedades</option>
      {USER_SOCIEDADES.map(s => <option key={s} value={s}>{s}</option>)}
    </select>
    <select value={filtros.oficina} onChange={e => setFiltro('oficina', e.target.value)}>
      <option value="todas">Todas las oficinas</option>
      {oficinasVisibles.map(o => <option key={o.codigo} value={o.codigo}>{oficinaLabel(o.codigo)}</option>)}
    </select>
    <label className="cf-user-filter-check">
      <input type="checkbox" checked={filtros.conExtra} onChange={e => setFiltro('conExtra', e.target.checked)} /> Con permisos extra
    </label>
    <label className="cf-user-filter-check">
      <input type="checkbox" checked={filtros.pendientesActivacion} onChange={e => setFiltro('pendientesActivacion', e.target.checked)} /> Pendientes de activación
    </label>
    <button className="ep-clear-filters" onClick={limpiar}>Limpiar filtros</button>
  </div>
);

// ─── Modal: reenviar código ─────────────────────────────────

const ResendCodeModal = ({ user, onClose, onSent }) => {
  const [canal, setCanal] = _cf_useState(null);
  const [fase, setFase] = _cf_useState('elegir'); // elegir | confirmar | enviando | enviado | entregado | fallido
  const [cooldown, setCooldown] = _cf_useState(0);

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

  React.useEffect(() => {
    if (cooldown <= 0) return;
    const t = setTimeout(() => setCooldown(c => Math.max(0, c - 6)), 500);
    return () => clearTimeout(t);
  }, [cooldown]);

  const titulo = user.estado === 'pendiente' ? 'Reenviar código de activación' : 'Enviar código de recuperación';

  const smsDisponible = !!user.telefono;
  const waDisponible = !!user.telefono && user.whatsappAutorizado;
  const correoDisponible = !!user.correo && user.correoVerificado;

  const enviar = () => {
    setFase('enviando');
    setTimeout(() => {
      const falla = Math.random() < 0.15;
      if (falla) { setFase('fallido'); return; }
      setFase('enviado');
      setTimeout(() => {
        setFase('entregado');
        setCooldown(60);
        onSent(user, canal);
      }, 900);
    }, 900);
  };

  const destinoEnmascarado = canal === 'sms' || canal === 'whatsapp' ? maskPhone(user.telefono) : canal === 'correo' ? maskEmail(user.correo) : '';

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 460 }}>
        <div className="modal-head">
          <div>
            <div className="modal-title">{titulo}</div>
            <div className="modal-sub">{getEmpleadoUsuarioNombre(user)}</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          {(fase === 'elegir' || fase === 'confirmar') && (
            <>
              <div className="muted-xs" style={{ marginBottom: 8 }}>Elige un canal de envío</div>
              <div className="range-list">
                <label className={`range-row ${!smsDisponible ? 'disabled' : ''} ${canal === 'sms' ? 'active' : ''}`}>
                  <input type="radio" name="canal-codigo" disabled={!smsDisponible} checked={canal === 'sms'} onChange={() => setCanal('sms')} />
                  <div>
                    <div style={{ fontSize: 13, fontWeight: 600 }}>SMS</div>
                    <div className="muted" style={{ fontSize: 11.5 }}>{smsDisponible ? maskPhone(user.telefono) : 'Sin número de teléfono registrado'}</div>
                  </div>
                </label>
                <label className={`range-row ${!waDisponible ? 'disabled' : ''} ${canal === 'whatsapp' ? 'active' : ''}`}>
                  <input type="radio" name="canal-codigo" disabled={!waDisponible} checked={canal === 'whatsapp'} onChange={() => setCanal('whatsapp')} />
                  <div>
                    <div style={{ fontSize: 13, fontWeight: 600 }}>WhatsApp</div>
                    <div className="muted" style={{ fontSize: 11.5 }}>
                      {!user.telefono ? 'Sin número de teléfono registrado' : !user.whatsappAutorizado ? 'El colaborador no ha autorizado WhatsApp' : maskPhone(user.telefono)}
                    </div>
                  </div>
                </label>
                <label className={`range-row ${!correoDisponible ? 'disabled' : ''} ${canal === 'correo' ? 'active' : ''}`}>
                  <input type="radio" name="canal-codigo" disabled={!correoDisponible} checked={canal === 'correo'} onChange={() => setCanal('correo')} />
                  <div>
                    <div style={{ fontSize: 13, fontWeight: 600 }}>Correo</div>
                    <div className="muted" style={{ fontSize: 11.5 }}>
                      {!user.correo ? 'Sin correo registrado' : !user.correoVerificado ? 'Correo pendiente de verificación' : maskEmail(user.correo)}
                    </div>
                  </div>
                </label>
              </div>
              {fase === 'confirmar' && canal && (
                <div className="ne-callout" style={{ marginTop: 14 }}>
                  <IconAlert size={16} />
                  <div>¿Confirmas el envío del código a <b>{destinoEnmascarado}</b>? Gestión Humana no podrá ver el código en ningún momento.</div>
                </div>
              )}
            </>
          )}
          {fase === 'enviando' && (
            <div className="cf-user-send-state">
              <div className="cf-user-send-spinner" /> Enviando código a <b>{destinoEnmascarado}</b>…
            </div>
          )}
          {(fase === 'enviado' || fase === 'entregado') && (
            <div className="cf-user-send-state ok">
              <IconCheck size={18} />
              <div>
                <div style={{ fontWeight: 700 }}>{fase === 'entregado' ? 'Código entregado' : 'Código enviado'}</div>
                <div className="muted" style={{ fontSize: 12.5 }}>Enviado a {destinoEnmascarado} por {canal === 'sms' ? 'SMS' : canal === 'whatsapp' ? 'WhatsApp' : 'correo'}.</div>
              </div>
            </div>
          )}
          {fase === 'fallido' && (
            <div className="cf-user-send-state fail">
              <IconAlert size={18} />
              <div>
                <div style={{ fontWeight: 700 }}>No se pudo entregar el código</div>
                <div className="muted" style={{ fontSize: 12.5 }}>Intenta de nuevo o elige otro canal.</div>
              </div>
            </div>
          )}
        </div>
        <div className="modal-foot">
          {cooldown > 0 && fase === 'entregado' && (
            <span className="muted" style={{ fontSize: 12, marginRight: 'auto' }}>Podrás reenviar en {cooldown} segundos</span>
          )}
          <button className="btn" onClick={onClose}>{fase === 'entregado' ? 'Cerrar' : 'Cancelar'}</button>
          {fase === 'elegir' && <button className="btn primary" disabled={!canal} onClick={() => setFase('confirmar')}>Continuar</button>}
          {fase === 'confirmar' && <button className="btn primary" onClick={enviar}>Confirmar envío</button>}
          {fase === 'fallido' && <button className="btn primary" onClick={enviar}>Reintentar</button>}
        </div>
      </div>
    </div>
  );
};

// ─── Drawer: ver usuario ─────────────────────────────────────

const getEmpleadoUsuarioNombre = (user) => {
  const e = getEmpleadoById(user.empleadoId);
  return e ? e.name : 'Empleado no encontrado';
};

const UserViewDrawer = ({ user, allUsers, onClose, onEdit, onResend, onToggleEstado }) => {
  const emp = getEmpleadoById(user.empleadoId);
  const rolMeta = ROLE_META[user.rol];
  const heredados = rolePermsList(user.rol);
  const extras = effectiveExtraPerms(user);
  const esInactivo = user.estado === 'inactivo';
  const puedeInact = puedeInactivar(user, allUsers);
  const motivo = motivoNoInactivar(user, allUsers);

  React.useEffect(() => {
    document.body.style.overflow = 'hidden';
    return () => { document.body.style.overflow = ''; };
  }, []);

  if (!emp) return null;

  return (
    <div className="tr-side-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="tr-side-panel" style={{ width: 560 }}>
        <div className="tr-side-head">
          <div style={{ display: 'flex', gap: 12, minWidth: 0 }}>
            <div className="doc-avatar" style={{ width: 44, height: 44, fontSize: 14 }}>{emp.initials}</div>
            <div style={{ minWidth: 0 }}>
              <div className="tr-side-title">{emp.name}</div>
              <div className="muted" style={{ fontSize: 12, marginTop: 4 }}>
                <span className={`cf-role-badge ${rolMeta.tone}`} style={{ marginRight: 6 }}>{rolMeta.label}</span>
                <span className="mono">{user.id}</span>
              </div>
            </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="tr-side-body">
          <section className="tr-side-section">
            <div className="muted-xs">Identificación</div>
            <div className="tr-side-row">
              <div><div className="muted-xs">Nombre completo</div><div className="tr-side-val">{emp.name}</div></div>
              <div><div className="muted-xs">Documento</div><div className="tr-side-val mono">{emp.doc}</div></div>
              <div><div className="muted-xs">ID de usuario</div><div className="tr-side-val mono">{user.id}</div></div>
              <div><div className="muted-xs">ID de empleado</div><div className="tr-side-val mono">{user.empleadoId}</div></div>
            </div>
          </section>

          <section className="tr-side-section">
            <div className="muted-xs">Cuenta</div>
            <div className="tr-side-row">
              <div><div className="muted-xs">Estado</div><div className="tr-side-val"><UserEstadoPill estado={user.estado} /></div></div>
              <div><div className="muted-xs">Fecha de creación</div><div className="tr-side-val mono">{user.fechaCreacion}</div></div>
              <div><div className="muted-xs">Fecha de activación</div><div className="tr-side-val mono">{activacionDisplay(user)}</div></div>
              <div><div className="muted-xs">Último acceso</div><div className="tr-side-val">{user.ultimoAcceso}</div></div>
              <div><div className="muted-xs">Último cambio de contraseña</div><div className="tr-side-val mono">{user.ultimoCambioPassword || 'Sin registro'}</div></div>
              <div><div className="muted-xs">Canal de activación</div><div className="tr-side-val">{user.canalActivacion || '—'}</div></div>
            </div>
          </section>

          <section className="tr-side-section">
            <div className="muted-xs">Canales de verificación</div>
            <div className="tr-side-row">
              <div>
                <div className="muted-xs">Teléfono</div>
                <div className="tr-side-val mono">{user.telefono || 'Sin registrar'}</div>
              </div>
              <div>
                <div className="muted-xs">Estado del teléfono</div>
                <div className="tr-side-val">{user.telefono ? (user.telefonoVerificado ? <span className="pill green">Verificado</span> : <span className="pill amber-soft">Pendiente de verificación</span>) : '—'}</div>
              </div>
              <div><div className="muted-xs">Última modificación</div><div className="tr-side-val mono">{user.fechaModTelefono || '—'}</div></div>
              <div><div className="muted-xs">Responsable de la modificación</div><div className="tr-side-val">{user.responsableModTelefono || '—'}</div></div>
              <div><div className="muted-xs">WhatsApp autorizado</div><div className="tr-side-val">{user.whatsappAutorizado ? 'Sí' : 'No'}</div></div>
              <div>
                <div className="muted-xs">Correo registrado</div>
                <div className="tr-side-val">{user.correo || 'No tiene correo registrado'}</div>
              </div>
              {user.correo && (
                <div><div className="muted-xs">Estado del correo</div><div className="tr-side-val">{user.correoVerificado ? <span className="pill green">Verificado</span> : <span className="pill amber-soft">Pendiente de verificación</span>}</div></div>
              )}
            </div>
          </section>

          <section className="tr-side-section">
            <div className="muted-xs">Rol y permisos</div>
            <div style={{ marginTop: 6 }}>
              <span className={`cf-role-badge ${rolMeta.tone}`}>{rolMeta.label}</span>
              <span className="muted" style={{ fontSize: 12, marginLeft: 8 }}>{rolMeta.desc}</span>
            </div>
            <div className="muted-xs" style={{ marginTop: 12 }}>Permisos heredados del rol ({heredados.length})</div>
            <div className="cf-user-permlist">
              {heredados.slice(0, 8).map((p, i) => <span key={i} className="pill navy-soft">{permLabel(p.moduleId, p.actionIndex)}</span>)}
              {heredados.length > 8 && <span className="muted-xs">+ {heredados.length - 8} más</span>}
            </div>
            <div className="muted-xs" style={{ marginTop: 12 }}>Permisos extra ({extras.length})</div>
            {extras.length === 0 ? (
              <div className="muted" style={{ fontSize: 12.5 }}>Sin permisos extra — solo tiene lo que otorga su rol.</div>
            ) : (
              <div className="cf-user-permlist">
                {extras.map((p, i) => <span key={i} className="pill green">{permLabel(p.moduleId, p.actionIndex)}</span>)}
              </div>
            )}
            <div className="muted-xs" style={{ marginTop: 10 }}>Total de permisos efectivos: <b style={{ color: 'var(--text)' }}>{heredados.length + extras.length}</b></div>
          </section>

          <section className="tr-side-section">
            <div className="muted-xs">Alcance organizacional</div>
            {user.todasSociedades ? (
              <div className="muted" style={{ fontSize: 12.5, marginTop: 4 }}>Todas las sociedades y oficinas de venta.</div>
            ) : (
              <>
                <div className="signer-chips" style={{ marginTop: 6 }}>
                  {user.sociedades.map(s => <span key={s} className="signer-chip">{s}</span>)}
                </div>
                <div className="muted-xs" style={{ marginTop: 10 }}>Oficinas de venta</div>
                <div className="signer-chips" style={{ marginTop: 6 }}>
                  {user.oficinas.map(o => <span key={o} className="signer-chip mono">{oficinaLabel(o)}</span>)}
                </div>
              </>
            )}
          </section>

          <section className="tr-side-section">
            <div className="muted-xs">Historial</div>
            <div className="cf-user-history">
              {user.historial.slice().reverse().map((h, i) => (
                <div key={i} className="cf-user-history-item">
                  <div className="cf-user-history-dot" />
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div style={{ fontSize: 12.5, fontWeight: 600 }}>{h.accion}</div>
                    <div className="muted" style={{ fontSize: 11.5, marginTop: 1 }}>{h.detalle}</div>
                    <div className="muted-xs" style={{ marginTop: 2 }}>{h.fecha} · {h.responsable}</div>
                  </div>
                </div>
              ))}
            </div>
          </section>
        </div>

        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cerrar</button>
          {!esInactivo && <button className="btn" onClick={() => onResend(user)}><IconMegaphone size={13} /> {user.estado === 'pendiente' ? 'Reenviar código' : 'Enviar recuperación'}</button>}
          {esInactivo ? (
            <button className="btn" onClick={() => onToggleEstado(user, 'activo')}><IconCheck size={13} /> Activar usuario</button>
          ) : (
            <button className="btn" disabled={!puedeInact} title={motivo || undefined} onClick={() => onToggleEstado(user, 'inactivo')}><IconAlert size={13} /> Inactivar usuario</button>
          )}
          <button className="btn primary" onClick={() => onEdit(user)}><IconDoc size={13} /> Editar usuario</button>
        </div>
      </div>
    </div>
  );
};

// ─── Modal: editar usuario ────────────────────────────────────

const UserEditModal = ({ user, allUsers, onClose, onSave }) => {
  const emp = getEmpleadoById(user.empleadoId);
  const [form, setForm] = _cf_useState({ ...user, sociedades: [...user.sociedades], oficinas: [...user.oficinas], permisosExtra: user.permisosExtra.map(p => ({ ...p })) });
  const [telefonoOriginal] = _cf_useState(user.telefono);
  const [correoOriginal] = _cf_useState(user.correo);

  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 set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const setRol = (rol) => {
    setForm(f => ({ ...f, rol, permisosExtra: f.permisosExtra.filter(p => !permIsGrantedByRole(rol, p.moduleId, p.actionIndex)) }));
  };

  const toggleExtra = (moduleId, actionIndex) => {
    setForm(f => {
      const existe = f.permisosExtra.some(p => p.moduleId === moduleId && p.actionIndex === actionIndex);
      return { ...f, permisosExtra: existe ? f.permisosExtra.filter(p => !(p.moduleId === moduleId && p.actionIndex === actionIndex)) : [...f.permisosExtra, { moduleId, actionIndex }] };
    });
  };

  const toggleSociedad = (soc) => {
    setForm(f => {
      const yaEsta = f.sociedades.includes(soc);
      const sociedades = yaEsta ? f.sociedades.filter(s => s !== soc) : [...f.sociedades, soc];
      // si se retira una sociedad, sus oficinas dejan de ser válidas
      const oficinas = f.oficinas.filter(o => sociedades.includes((OFICINAS_VENTA_SEED.find(x => x.codigo === o) || {}).sociedad));
      return { ...f, sociedades, oficinas };
    });
  };

  const toggleOficina = (codigo) => {
    setForm(f => ({ ...f, oficinas: f.oficinas.includes(codigo) ? f.oficinas.filter(o => o !== codigo) : [...f.oficinas, codigo] }));
  };

  const oficinasDisponibles = OFICINAS_VENTA_SEED.filter(o => form.sociedades.includes(o.sociedad));
  const telefonoCambio = form.telefono.trim() !== telefonoOriginal;
  const correoCambio = (form.correo || '').trim() !== (correoOriginal || '');
  const bloquearInactivo = !puedeInactivar(user, allUsers) && user.estado !== 'inactivo';

  const guardar = () => {
    const ahora = '05/05/2026';
    const nuevoHistorial = [...user.historial];
    if (form.rol !== user.rol) nuevoHistorial.push({ fecha: `${ahora} 00:00`, accion: 'Cambio de rol', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: `${ROLE_META[user.rol].label} → ${ROLE_META[form.rol].label}` });
    const extrasNuevos = form.permisosExtra.filter(p => !user.permisosExtra.some(o => o.moduleId === p.moduleId && o.actionIndex === p.actionIndex));
    extrasNuevos.forEach(p => nuevoHistorial.push({ fecha: `${ahora} 00:00`, accion: 'Permiso extra agregado', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: permLabel(p.moduleId, p.actionIndex) }));

    const next = { ...form };
    if (telefonoCambio) {
      next.telefonoVerificado = false;
      next.fechaModTelefono = ahora;
      next.responsableModTelefono = 'Carolina Restrepo S. · Jefe de RRHH (edición)';
      nuevoHistorial.push({ fecha: `${ahora} 00:00`, accion: 'Cambio de teléfono', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: 'Nuevo número pendiente de verificación' });
      // El estado de la cuenta (next.estado, ya copiado de form.estado más
      // abajo) nunca se deriva del cambio de teléfono — solo de la selección
      // explícita en el campo Estado.
    }
    if (correoCambio) {
      next.correoVerificado = false;
      nuevoHistorial.push({ fecha: `${ahora} 00:00`, accion: 'Cambio de correo', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: 'Nuevo correo pendiente de verificación' });
    }
    next.historial = nuevoHistorial;
    onSave(next, { telefonoCambio, correoCambio });
  };

  if (!emp) return null;

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 720, height: 'calc(100vh - 64px)' }}>
        <div className="modal-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>{user.id}</div>
            <div className="modal-title">Editar usuario</div>
            <div className="modal-sub">{emp.name}</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <div className="cf-user-readonly">
            <div><span className="muted-xs">Nombre</span><div style={{ fontWeight: 600, fontSize: 13 }}>{emp.name}</div></div>
            <div><span className="muted-xs">Tipo de documento</span><div style={{ fontWeight: 600, fontSize: 13 }}>{emp.doc.split(' ')[0]}</div></div>
            <div><span className="muted-xs">Número de documento</span><div className="mono" style={{ fontWeight: 600, fontSize: 13 }}>{emp.doc.split(' ').slice(1).join(' ')}</div></div>
            <div className="muted-xs" style={{ gridColumn: '1 / -1' }}>Estos datos provienen de la ficha del empleado y no se editan aquí.</div>
          </div>

          <div className="cf-user-form-subhead">Rol y permisos</div>
          <div className="furat-row">
            <label className="furat-label">Rol principal</label>
            <select value={form.rol} onChange={e => setRol(e.target.value)}>
              {Object.entries(ROLE_META).map(([k, m]) => <option key={k} value={k}>{m.label}</option>)}
            </select>
          </div>
          <div className="furat-row">
            <label className="furat-label">Permisos heredados del rol ({rolePermsList(form.rol).length})</label>
            <div className="cf-user-permlist">
              {rolePermsList(form.rol).map((p, i) => <span key={i} className="pill navy-soft">{permLabel(p.moduleId, p.actionIndex)}</span>)}
            </div>
          </div>
          <div className="furat-row">
            <label className="furat-label">Permisos extra (aditivos — nunca retiran lo heredado)</label>
            {PERM_MODULES.every(m => PERM_ACTIONS.every((a, i) => permIsGrantedByRole(form.rol, m.id, i))) && (
              <div className="muted" style={{ fontSize: 12.5 }}>Este rol ya incluye todos los permisos disponibles — no hay nada extra que agregar.</div>
            )}
            {PERM_MODULES.map(m => {
              const acciones = PERM_ACTIONS.map((a, i) => ({ a, i })).filter(({ i }) => !permIsGrantedByRole(form.rol, m.id, i));
              if (acciones.length === 0) return null;
              return (
                <div key={m.id} className="cf-user-perm-modrow">
                  <span className="muted-xs" style={{ minWidth: 110 }}>{m.label}</span>
                  <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                    {acciones.map(({ a, i }) => {
                      const sel = form.permisosExtra.some(p => p.moduleId === m.id && p.actionIndex === i);
                      return (
                        <button key={i} type="button" className={`pill ${sel ? 'green' : 'navy-soft'}`} style={{ cursor: 'pointer', border: 'none' }} onClick={() => toggleExtra(m.id, i)}>
                          {sel && <IconCheck size={10} />} {a}
                        </button>
                      );
                    })}
                  </div>
                </div>
              );
            })}
          </div>

          <div className="cf-user-form-subhead">Alcance organizacional</div>
          <div className="furat-row">
            <label className="epp-toggle">
              <input type="checkbox" checked={form.todasSociedades} onChange={e => set('todasSociedades', e.target.checked)} />
              <span className="epp-toggle-track" />
            </label>
            <span style={{ fontSize: 12.5, marginLeft: 8 }}>Todas las sociedades</span>
          </div>
          {!form.todasSociedades && (
            <>
              <div className="furat-row">
                <label className="furat-label">Sociedades asignadas</label>
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                  {USER_SOCIEDADES.map(s => {
                    const sel = form.sociedades.includes(s);
                    return (
                      <button key={s} type="button" className={`pill ${sel ? 'green' : 'navy-soft'}`} style={{ cursor: 'pointer', border: 'none' }} onClick={() => toggleSociedad(s)}>
                        {sel && <IconCheck size={10} />} {s}
                      </button>
                    );
                  })}
                </div>
              </div>
              <div className="furat-row">
                <label className="furat-label">Oficinas de venta {form.sociedades.length === 0 && '(elige una sociedad primero)'}</label>
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
                  {oficinasDisponibles.map(o => {
                    const sel = form.oficinas.includes(o.codigo);
                    return (
                      <button key={o.codigo} type="button" className={`pill ${sel ? 'green' : 'navy-soft'}`} style={{ cursor: 'pointer', border: 'none', fontSize: 11.5 }} onClick={() => toggleOficina(o.codigo)}>
                        {sel && <IconCheck size={10} />} {oficinaLabel(o.codigo)}
                      </button>
                    );
                  })}
                </div>
              </div>
            </>
          )}

          <div className="cf-user-form-subhead">Canales y cuenta</div>
          <div className="furat-grid-2">
            <div className="furat-row">
              <label className="furat-label">Número de teléfono</label>
              <input type="text" value={form.telefono} onChange={e => set('telefono', e.target.value)} />
            </div>
            <div className="furat-row">
              <label className="furat-label">Correo</label>
              <input type="text" placeholder="Sin correo" value={form.correo || ''} onChange={e => set('correo', e.target.value)} />
            </div>
          </div>
          {telefonoCambio && (
            <div className="ne-callout"><IconAlert size={16} /><div>El teléfono cambió — quedará <b>pendiente de verificación</b> al guardar. El estado de la cuenta no se modifica.</div></div>
          )}
          {correoCambio && (
            <div className="ne-callout"><IconAlert size={16} /><div>El correo cambió — quedará <b>pendiente de verificación</b> al guardar.</div></div>
          )}
          <div className="furat-row" style={{ marginTop: 4, flexDirection: 'row', alignItems: 'center' }}>
            <label className="epp-toggle">
              <input type="checkbox" checked={form.whatsappAutorizado} onChange={e => set('whatsappAutorizado', e.target.checked)} />
              <span className="epp-toggle-track" />
            </label>
            <span style={{ fontSize: 12.5, marginLeft: 8 }}>WhatsApp autorizado</span>
          </div>
          <div className="furat-row">
            <label className="furat-label">Estado</label>
            <select value={form.estado} onChange={e => set('estado', e.target.value)}>
              <option value="activo">Activo</option>
              <option value="pendiente">Pendiente</option>
              <option value="inactivo" disabled={bloquearInactivo}>Inactivo{bloquearInactivo ? ' (no disponible)' : ''}</option>
            </select>
            {bloquearInactivo && <div className="muted-xs" style={{ marginTop: 4 }}>{motivoNoInactivar(user, allUsers)}</div>}
          </div>
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" onClick={guardar}><IconCheck size={14} /> Guardar cambios</button>
        </div>
      </div>
    </div>
  );
};

// ─── Root: Usuarios y roles ───────────────────────────────

const UsersSection = () => {
  const [users, setUsers] = _cf_useState(USERS);
  const [expanded, setExpanded] = _cf_useState(null);
  const [q, setQ] = _cf_useState('');
  const [filtros, setFiltros] = _cf_useState(USERS_FILTROS_VACIOS);
  const [mobileFiltersOpen, setMobileFiltersOpen] = _cf_useState(false);
  const [viewUser, setViewUser] = _cf_useState(null);
  const [editUser, setEditUser] = _cf_useState(null);
  const [resendUser, setResendUser] = _cf_useState(null);
  const [verifyPrompt, setVerifyPrompt] = _cf_useState(null); // { user, canal }

  const setFiltro = (k, v) => setFiltros(f => {
    const next = { ...f, [k]: v };
    if (k === 'sociedad') next.oficina = 'todas'; // la oficina depende de la sociedad elegida
    return next;
  });
  const limpiarFiltros = () => { setFiltros(USERS_FILTROS_VACIOS); setQ(''); };

  const oficinasVisibles = filtros.sociedad === 'todas' ? OFICINAS_VENTA_SEED : OFICINAS_VENTA_SEED.filter(o => o.sociedad === filtros.sociedad);

  const usersConEmpleado = users.map(u => ({ u, emp: getEmpleadoById(u.empleadoId) })).filter(x => x.emp);

  const filtrados = usersConEmpleado
    .filter(({ emp }) => !q || emp.name.toLowerCase().includes(q.toLowerCase()) || emp.doc.toLowerCase().includes(q.toLowerCase()))
    .filter(({ u }) => filtros.rol === 'todos' || u.rol === filtros.rol)
    .filter(({ u }) => filtros.estado === 'todos' || u.estado === filtros.estado)
    .filter(({ u }) => filtros.sociedad === 'todas' || u.todasSociedades || u.sociedades.includes(filtros.sociedad))
    .filter(({ u }) => filtros.oficina === 'todas' || u.todasSociedades || u.oficinas.includes(filtros.oficina))
    .filter(({ u }) => !filtros.conExtra || effectiveExtraPerms(u).length > 0)
    .filter(({ u }) => !filtros.pendientesActivacion || u.estado === 'pendiente');

  const updateUser = (updated) => setUsers(list => list.map(u => u.id === updated.id ? updated : u));

  const handleToggleEstado = (user, nuevoEstado) => {
    if (nuevoEstado === 'inactivo') {
      const motivo = motivoNoInactivar(user, users);
      if (motivo) { alert(motivo); return; }
      const emp = getEmpleadoById(user.empleadoId);
      const ok = confirm(`¿Inactivar a ${emp ? emp.name : user.id}?\n\nPerderá inmediatamente el acceso al sistema. Se conservan su rol, permisos, asignaciones e historial — puede reactivarse más adelante.`);
      if (!ok) return;
      updateUser({
        ...user, estado: 'inactivo',
        historial: [...user.historial, { fecha: '05/05/2026 00:00', accion: 'Usuario inactivado', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: 'Acción manual desde Usuarios y roles' }],
      });
    } else {
      const emp = getEmpleadoById(user.empleadoId);
      const ok = confirm(`¿Activar a ${emp ? emp.name : user.id}?\n\nRecupera el acceso al sistema con su rol y permisos actuales. No se genera ni se cambia ninguna contraseña automáticamente.`);
      if (!ok) return;
      updateUser({
        ...user, estado: 'activo',
        historial: [...user.historial, { fecha: '05/05/2026 00:00', accion: 'Usuario activado', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: 'Acción manual desde Usuarios y roles' }],
      });
    }
    setViewUser(v => v && v.id === user.id ? null : v);
  };

  const handleSaveEdit = (updated, { telefonoCambio, correoCambio }) => {
    updateUser(updated);
    setEditUser(null);
    if (telefonoCambio || correoCambio) setVerifyPrompt({ user: updated, canal: telefonoCambio ? 'sms' : 'correo' });
  };

  const handleResendSent = (user, canal) => {
    const updated = {
      ...user,
      historial: [...user.historial, { fecha: '05/05/2026 00:00', accion: 'Código enviado', responsable: 'Carolina Restrepo S. · Jefe de RRHH', detalle: `${canal === 'sms' ? 'SMS' : canal === 'whatsapp' ? 'WhatsApp' : 'Correo'} · entregado` }],
    };
    updateUser(updated);
  };

  const activosCount = filtrados.length;
  const filtrosActivos = q || Object.entries(filtros).some(([k, v]) => v !== USERS_FILTROS_VACIOS[k]);

  return (
    <>
      <div className="cf-section-head">
        <div>
          <h2 className="cf-section-title">Usuarios y roles</h2>
          <p className="cf-section-sub">
            Administra las cuentas de acceso, roles, permisos adicionales y alcance organizacional de los colaboradores.
          </p>
        </div>
        <span className="muted mono" style={{ fontSize: 12 }}>{activosCount} usuario{activosCount === 1 ? '' : 's'} encontrado{activosCount === 1 ? '' : 's'}</span>
      </div>

      {verifyPrompt && (
        <div className="ne-callout" style={{ marginBottom: 14 }}>
          <IconAlert size={16} />
          <div style={{ flex: 1 }}>
            {verifyPrompt.canal === 'sms' ? 'El teléfono' : 'El correo'} de <b>{getEmpleadoUsuarioNombre(verifyPrompt.user)}</b> quedó pendiente de verificación. ¿Enviar el código ahora?
          </div>
          <div style={{ display: 'flex', gap: 8 }}>
            <button className="btn primary" style={{ padding: '5px 11px', fontSize: 12 }} onClick={() => { setResendUser(verifyPrompt.user); setVerifyPrompt(null); }}>Enviar código</button>
            <button className="btn" style={{ padding: '5px 11px', fontSize: 12 }} onClick={() => setVerifyPrompt(null)}>Ahora no</button>
          </div>
        </div>
      )}

      <div className="cf-user-toolbar">
        <div className="cf-user-toolbar-desktop">
          <UserFiltersPanel filtros={filtros} setFiltro={setFiltro} limpiar={limpiarFiltros} q={q} setQ={setQ} oficinasVisibles={oficinasVisibles} />
        </div>
        <button className="btn cf-user-toolbar-mobile-btn" onClick={() => setMobileFiltersOpen(true)}>
          <IconFilter size={14} /> Filtros {filtrosActivos && <span className="cf-user-filter-dot" />}
        </button>
      </div>

      {mobileFiltersOpen && (
        <div className="tr-side-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) setMobileFiltersOpen(false); }}>
          <div className="tr-side-panel" style={{ width: 340 }}>
            <div className="tr-side-head">
              <div className="tr-side-title">Filtros</div>
              <button className="icon-btn" onClick={() => setMobileFiltersOpen(false)} 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="tr-side-body">
              <UserFiltersPanel filtros={filtros} setFiltro={setFiltro} limpiar={limpiarFiltros} q={q} setQ={setQ} oficinasVisibles={oficinasVisibles} />
            </div>
            <div className="modal-foot">
              <button className="btn primary" onClick={() => setMobileFiltersOpen(false)}>Ver {activosCount} resultado{activosCount === 1 ? '' : 's'}</button>
            </div>
          </div>
        </div>
      )}

      <div className="doc-list-card cf-user-table-wrap">
        <table className="doc-table">
          <thead>
            <tr>
              <th>Usuario</th>
              <th>Rol</th>
              <th>Permisos extra</th>
              <th>Alcance</th>
              <th>Último acceso</th>
              <th>Activación</th>
              <th>Estado</th>
              <th>Canal</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {filtrados.map(({ u, emp }) => {
              const r = ROLE_META[u.rol];
              return (
                <tr key={u.id}>
                  <td>
                    <div className="doc-cell-emp">
                      <div className="doc-avatar">{emp.initials}</div>
                      <div style={{ minWidth: 0 }}>
                        <div style={{ fontWeight: 600, fontSize: 13 }}>{emp.name}</div>
                        <div className="muted mono" style={{ fontSize: 11 }}>{emp.doc}</div>
                      </div>
                    </div>
                  </td>
                  <td><span className={`cf-role-badge ${r.tone}`}>{r.label}</span></td>
                  <td><ExtraPermsCell user={u} /></td>
                  <td className="muted" style={{ fontSize: 12 }}>{formatAlcance(u)}</td>
                  <td className="muted" style={{ fontSize: 12 }}>{u.ultimoAcceso}</td>
                  <td className="mono muted" style={{ fontSize: 12 }}>{activacionDisplay(u)}</td>
                  <td><UserEstadoPill estado={u.estado} /></td>
                  <td><CanalUpdatedBadge user={u} /></td>
                  <td>
                    <UserRowMenu
                      user={u} allUsers={users}
                      onView={setViewUser} onEdit={setEditUser} onResend={setResendUser}
                      onToggleEstado={handleToggleEstado}
                    />
                  </td>
                </tr>
              );
            })}
            {filtrados.length === 0 && (
              <tr><td colSpan={9} className="muted" style={{ textAlign: 'center', padding: 24, fontSize: 12.5 }}>Ningún usuario coincide con la búsqueda o los filtros.</td></tr>
            )}
          </tbody>
        </table>
      </div>

      <div className="cf-user-cards">
        {filtrados.map(({ u, emp }) => {
          const r = ROLE_META[u.rol];
          return (
            <div key={u.id} className="cf-user-card" onClick={() => setViewUser(u)}>
              <div className="doc-cell-emp">
                <div className="doc-avatar">{emp.initials}</div>
                <div style={{ minWidth: 0, flex: 1 }}>
                  <div style={{ fontWeight: 600, fontSize: 13 }}>{emp.name}</div>
                  <div className="muted mono" style={{ fontSize: 11 }}>{emp.doc}</div>
                </div>
                <div onClick={(e) => e.stopPropagation()}>
                  <UserRowMenu user={u} allUsers={users} onView={setViewUser} onEdit={setEditUser} onResend={setResendUser} onToggleEstado={handleToggleEstado} />
                </div>
              </div>
              <div className="cf-user-card-row">
                <span className={`cf-role-badge ${r.tone}`}>{r.label}</span>
                <UserEstadoPill estado={u.estado} />
              </div>
              <div className="cf-user-card-meta">{formatAlcance(u)} · Último acceso: {u.ultimoAcceso}</div>
            </div>
          );
        })}
        {filtrados.length === 0 && (
          <div className="muted" style={{ textAlign: 'center', padding: 24, fontSize: 12.5 }}>Ningún usuario coincide con la búsqueda o los filtros.</div>
        )}
      </div>

      <div className="cf-section-head" style={{ marginTop: 24 }}>
        <div>
          <h2 className="cf-section-title">Matriz de permisos por rol</h2>
          <p className="cf-section-sub">Selecciona un rol para ver y ajustar qué acciones puede hacer en cada módulo del sistema.</p>
        </div>
      </div>

      <div className="cf-perm-matrix">
        <div className="cf-perm-roles">
          {Object.entries(ROLE_META).map(([k, m]) => (
            <button
              key={k}
              className={`cf-perm-role ${m.tone} ${expanded === k ? 'active' : ''}`}
              onClick={() => setExpanded(expanded === k ? null : k)}
            >
              <div className={`cf-perm-role-tag ${m.tone}`}>{m.label}</div>
              <div className="muted" style={{ fontSize: 11.5, marginTop: 3 }}>{m.desc}</div>
              <div className="muted mono" style={{ fontSize: 10.5, marginTop: 6 }}>
                {users.filter(u => u.rol === k).length} usuario{users.filter(u => u.rol === k).length === 1 ? '' : 's'}
              </div>
            </button>
          ))}
        </div>

        {expanded && (
          <div className="cf-perm-grid-wrap">
            <div className="cf-perm-grid-head">
              <span className={`cf-role-badge ${ROLE_META[expanded].tone}`}>{ROLE_META[expanded].label}</span>
              <span className="muted" style={{ fontSize: 12 }}>{ROLE_META[expanded].desc}</span>
              <button className="link-btn" style={{ marginLeft: 'auto' }}>Restablecer a defaults</button>
            </div>
            <div style={{ overflowX: 'auto' }}>
              <table className="cf-perm-table">
                <thead>
                  <tr>
                    <th>Módulo</th>
                    {PERM_ACTIONS.map(a => <th key={a} style={{ textAlign: 'center' }}>{a}</th>)}
                  </tr>
                </thead>
                <tbody>
                  {PERM_MODULES.map(m => {
                    const I = window[m.icon];
                    const perms = getPerms(expanded, m.id);
                    return (
                      <tr key={m.id}>
                        <td>
                          <div style={{ display: 'flex', alignItems: 'center', gap: 8, whiteSpace: 'nowrap' }}>
                            <I size={14} />
                            <span style={{ fontWeight: 600, fontSize: 12.5 }}>{m.label}</span>
                          </div>
                        </td>
                        {perms.map((p, i) => (
                          <td key={i} style={{ textAlign: 'center' }}>
                            <label className="cf-perm-cell">
                              <input type="checkbox" defaultChecked={p === 1} />
                              <span className={`cf-perm-mark ${p ? 'on' : ''}`}>
                                {p ? <IconCheck size={10} /> : ''}
                              </span>
                            </label>
                          </td>
                        ))}
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
            <div style={{ display: 'flex', justifyContent: 'flex-end', padding: '12px 16px', borderTop: '1px solid var(--border)' }}>
              <button className="btn primary" style={{ padding: '6px 14px' }}><IconCheck size={13} /> Guardar permisos</button>
            </div>
          </div>
        )}
      </div>

      {viewUser && (
        <UserViewDrawer
          user={viewUser} allUsers={users}
          onClose={() => setViewUser(null)}
          onEdit={(u) => { setViewUser(null); setEditUser(u); }}
          onResend={(u) => setResendUser(u)}
          onToggleEstado={handleToggleEstado}
        />
      )}
      {editUser && (
        <UserEditModal
          user={editUser} allUsers={users}
          onClose={() => setEditUser(null)}
          onSave={handleSaveEdit}
        />
      )}
      {resendUser && (
        <ResendCodeModal
          user={resendUser}
          onClose={() => setResendUser(null)}
          onSent={(u, canal) => { handleResendSent(u, canal); }}
        />
      )}
    </>
  );
};

// ─── Section: Legal params ───────────────────────────────

const LegalSection = () => (
  <>
    <div className="cf-section-head">
      <div>
        <h2 className="cf-section-title">Parámetros legales colombianos</h2>
        <p className="cf-section-sub">
          Valores legales que el sistema usa para cálculos de nómina, contratos y prestaciones. Se actualizan al cambiar la normativa o por decreto anual.
        </p>
      </div>
    </div>
    <div className="doc-list-card">
      <table className="doc-table">
        <thead>
          <tr>
            <th>Parámetro</th>
            <th>Valor actual</th>
            <th>Unidad</th>
            <th>Vigente desde</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          {LEGAL_PARAMS.map(p => (
            <tr key={p.key}>
              <td>
                <div style={{ fontWeight: 600, fontSize: 13 }}>{p.label}</div>
                <div className="muted mono" style={{ fontSize: 11 }}>{p.key.toUpperCase()}</div>
              </td>
              <td className="mono" style={{ fontSize: 14, fontWeight: 700, color: 'var(--navy-800)' }}>{p.value}</td>
              <td className="muted" style={{ fontSize: 12 }}>{p.unit}</td>
              <td className="mono" style={{ fontSize: 12 }}>{p.effective}</td>
              <td>
                <button className="icon-action" title="Editar"><IconExternal size={14} /></button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  </>
);

// ─── Section: Tipos de contrato ──────────────────────────

const ContractsSection = () => (
  <>
    <div className="cf-section-head">
      <div>
        <h2 className="cf-section-title">Tipos de contrato</h2>
        <p className="cf-section-sub">
          Modalidades disponibles al vincular un colaborador. Cada tipo determina las prestaciones, el período de prueba y el porcentaje de cotización.
        </p>
      </div>
      <button className="btn"><IconPlus size={13} /> Nuevo tipo</button>
    </div>
    <div className="cf-contracts-grid">
      {CONTRACT_TYPES.map(c => (
        <div key={c.id} className={`cf-contract-card ${c.tone}`}>
          <div className="cf-contract-head">
            <div>
              <div className="muted mono" style={{ fontSize: 11 }}>{c.code}</div>
              <h3 className="cf-contract-name">{c.label}</h3>
            </div>
            <div className="cf-contract-uses">
              <div className="mono" style={{ fontSize: 18, fontWeight: 800 }}>{c.used}</div>
              <div className="muted" style={{ fontSize: 10.5 }}>activos</div>
            </div>
          </div>
          <div className="cf-contract-rows">
            <div className="cf-contract-row">
              <span className="muted-xs">Período de prueba</span>
              <span className="mono" style={{ fontWeight: 700 }}>{c.prob ? `${c.prob} días` : 'N/A'}</span>
            </div>
            <div className="cf-contract-row">
              <span className="muted-xs">Cesantías</span>
              <span style={{ fontWeight: 700, color: c.ces ? 'var(--green-600)' : 'var(--text-muted)' }}>
                {c.ces ? '✓ Aplica' : '✗ No aplica'}
              </span>
            </div>
            <div className="cf-contract-row">
              <span className="muted-xs">% Riesgo ARL</span>
              <span className="mono" style={{ fontWeight: 700 }}>{c.acc}</span>
            </div>
          </div>
          <button className="btn" style={{ width: '100%' }}><IconExternal size={13} /> Configurar</button>
        </div>
      ))}
    </div>
  </>
);

// ─── Section: Centros de costo ───────────────────────────

const CostCentersSection = () => (
  <>
    <div className="cf-section-head">
      <div>
        <h2 className="cf-section-title">Centros de costo</h2>
        <p className="cf-section-sub">
          Estructura financiera de la operación. Cada colaborador se asigna a un centro de costo para los reportes contables y de presupuesto.
        </p>
      </div>
      <button className="btn primary"><IconPlus size={14} /> Nuevo centro</button>
    </div>
    <div className="doc-list-card">
      <table className="doc-table">
        <thead>
          <tr>
            <th>Código</th>
            <th>Nombre</th>
            <th>Sede</th>
            <th>Responsable</th>
            <th style={{ textAlign: 'center' }}>Activos</th>
            <th>Presupuesto mensual</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          {COST_CENTERS.map(c => (
            <tr key={c.code}>
              <td className="mono" style={{ fontWeight: 700, fontSize: 12.5, color: 'var(--navy-800)' }}>{c.code}</td>
              <td style={{ fontWeight: 600, fontSize: 13 }}>{c.name}</td>
              <td className="muted" style={{ fontSize: 12 }}>{c.site}</td>
              <td className="muted" style={{ fontSize: 12 }}>{c.responsible}</td>
              <td style={{ textAlign: 'center', fontFamily: 'JetBrains Mono', fontSize: 13, fontWeight: 700 }}>{c.active}</td>
              <td className="mono" style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--text)' }}>{c.budget}</td>
              <td>
                <button className="icon-action" title="Editar"><IconExternal size={14} /></button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  </>
);

// ─── Section: Plantillas de solicitudes (Creador de flujos) ──────────
// Modelo: Plantilla → Etapas → cada Etapa usa un Bloque funcional → cada Bloque define Atributos configurables.

const BLOQUES_FUNCIONALES_SEED = [
  { id: 'BLQ-001', nombre: 'Formulario', descripcion: 'Captura de datos estructurados mediante un formulario dinámico.', atributos: ['Campos del formulario', 'Validaciones', 'Documentos requeridos'], estado: 'activo' },
  { id: 'BLQ-002', nombre: 'Revisión', descripcion: 'Revisión manual de la información o documentos de la etapa anterior.', atributos: ['Responsable de revisión', 'Checklist de revisión', 'Tiempo límite (días)'], estado: 'activo' },
  { id: 'BLQ-003', nombre: 'Aprobación', descripcion: 'Punto de decisión que requiere aprobación de uno o varios responsables.', atributos: ['Aprobadores', 'Tipo de aprobación (uno / todos)', 'Tiempo límite (días)'], estado: 'activo' },
  { id: 'BLQ-004', nombre: 'Firma electrónica', descripcion: 'Solicita firma electrónica de uno o varios firmantes sobre un documento generado.', atributos: ['Firmantes', 'Documento a firmar', 'Orden de firma'], estado: 'activo' },
  { id: 'BLQ-005', nombre: 'Entrevista', descripcion: 'Agenda y registra el resultado de una entrevista dentro del proceso.', atributos: ['Entrevistador', 'Modalidad', 'Formato de evaluación'], estado: 'activo' },
  { id: 'BLQ-006', nombre: 'Prueba técnica', descripcion: 'Aplicación de una prueba técnica o psicotécnica al candidato o al cargo.', atributos: ['Tipo de prueba', 'Puntaje mínimo', 'Proveedor'], estado: 'activo' },
  { id: 'BLQ-007', nombre: 'Notificación', descripcion: 'Envía una notificación automática a uno o varios roles o correos.', atributos: ['Destinatarios', 'Canal', 'Plantilla de mensaje'], estado: 'activo' },
  { id: 'BLQ-008', nombre: 'Validación de documentos', descripcion: 'Verifica que los documentos cargados cumplan los requisitos definidos.', atributos: ['Documentos requeridos', 'Formato permitido', 'Responsable'], estado: 'inactivo' },
  { id: 'BLQ-009', nombre: 'Resultado final', descripcion: 'Acción automática del sistema que ejecuta el resultado del flujo (crea o actualiza un registro) al completarse la última etapa.', atributos: ['Acción a ejecutar', 'Módulo destino', 'Estado inicial del registro'], estado: 'activo' },
];

const PLANTILLAS_SOLICITUD_SEED = [
  {
    id: 'PLT-001', nombre: 'Solicitud de Remplazo por Vacante', estado: 'activa',
    etapas: [
      {
        nombre: 'Solicitud de Remplazo por Vacante', bloqueId: 'BLQ-001',
        valores: {
          'Campos del formulario': [
            { nombre: 'Cargo', tipo: 'Selección única' },
            { nombre: 'Motivo de la solicitud', tipo: 'Texto largo' },
            { nombre: 'Fecha límite', tipo: 'Fecha' },
            { nombre: 'Adjuntar soporte', tipo: 'Archivo adjunto' },
          ],
          'Validaciones': 'Iniciada por todos los usuarios con empleo activo. Debe existir un cargo activo asociado al solicitante.',
          'Documentos requeridos': 'Ninguno obligatorio en esta etapa',
        },
      },
      {
        nombre: 'Revisar la solicitud de Remplazo por Vacante', bloqueId: 'BLQ-002',
        valores: {
          'Responsable de revisión': 'Usuario elegido en la etapa anterior (jefe directo del cargo)',
          'Checklist de revisión': 'Verificar vacante real, presupuesto disponible y justificación del reemplazo',
          'Tiempo límite (días)': '2',
        },
      },
      {
        nombre: 'Se informa a Sistemas: Nueva Solicitud de Remplazo por Vacante', bloqueId: 'BLQ-007',
        valores: {
          'Destinatarios': 'Equipo de Sistemas · Administrador de accesos',
          'Canal': 'Correo electrónico interno',
          'Plantilla de mensaje': 'Se aprobó una nueva solicitud de reemplazo por vacante. Cargo: {{cargo}} · Sede: {{sede}}.',
        },
      },
      {
        nombre: 'Creación de una vacante en estado pendiente en el módulo de Reclutamiento', bloqueId: 'BLQ-009',
        valores: {
          'Acción a ejecutar': 'Crear vacante',
          'Módulo destino': 'Reclutamiento y Selección',
          'Estado inicial del registro': 'Pendiente',
        },
      },
    ],
  },
  {
    id: 'PLT-002', nombre: 'Reemplazo por incapacidad', estado: 'inactiva',
    etapas: [
      { nombre: 'Solicitud de reemplazo', bloqueId: 'BLQ-001' },
      { nombre: 'Validación de incapacidad', bloqueId: 'BLQ-008' },
      { nombre: 'Aprobación de RRHH', bloqueId: 'BLQ-003' },
    ],
  },
  {
    id: 'PLT-003', nombre: 'Reemplazo por vacaciones', estado: 'inactiva',
    etapas: [
      { nombre: 'Solicitud de reemplazo', bloqueId: 'BLQ-001' },
      { nombre: 'Revisión de jefe directo', bloqueId: 'BLQ-002' },
      { nombre: 'Aprobación de RRHH', bloqueId: 'BLQ-003' },
    ],
  },
  {
    id: 'PLT-004', nombre: 'Traslado', estado: 'inactiva',
    etapas: [
      { nombre: 'Solicitud de traslado', bloqueId: 'BLQ-001' },
      { nombre: 'Aprobación de jefe receptor', bloqueId: 'BLQ-003' },
      { nombre: 'Aprobación de RRHH', bloqueId: 'BLQ-003' },
      { nombre: 'Notificación a nómina', bloqueId: 'BLQ-007' },
    ],
  },
  {
    id: 'PLT-005', nombre: 'Ampliación de nómina — Cargo existente', estado: 'activa',
    etapas: [
      {
        nombre: 'Solicitud de personal', bloqueId: 'BLQ-001',
        valores: {
          'Campos del formulario': [
            { nombre: 'Cargo existente', tipo: 'Selección única' },
            { nombre: 'Cantidad de posiciones', tipo: 'Número' },
            { nombre: 'Sociedad', tipo: 'Selección única' },
            { nombre: 'Línea de negocio', tipo: 'Selección única' },
            { nombre: 'Sede o regional', tipo: 'Selección única' },
            { nombre: 'Centro de costo', tipo: 'Texto corto' },
            { nombre: 'Posición jefe', tipo: 'Selección única' },
            { nombre: 'Fecha requerida', tipo: 'Fecha' },
          ],
          'Validaciones': 'Responsable: todos los colaboradores. El cargo se toma tal cual está configurado en el Maestro de cargos — no se puede editar desde la solicitud.',
          'Documentos requeridos': 'Archivo de soporte opcional (proyecto, contrato u operación relacionada)',
        },
      },
      {
        nombre: 'Revisar escala salarial', bloqueId: 'BLQ-002',
        valores: {
          'Responsable de revisión': 'Directora de Gestión Humana',
          'Checklist de revisión': 'Confirma o asigna la línea de negocio y valida que la ampliación no afecte incorrectamente la escala salarial del cargo',
          'Tiempo límite (días)': '2',
        },
      },
      {
        nombre: 'Autorización del director del proceso', bloqueId: 'BLQ-003',
        valores: {
          'Aprobadores': 'Director del proceso — responsable dinámico según la línea de negocio de la solicitud',
          'Tipo de aprobación (uno / todos)': 'Uno',
          'Tiempo límite (días)': '3',
        },
      },
      {
        nombre: 'Autorización del director nacional', bloqueId: 'BLQ-003',
        valores: {
          'Aprobadores': 'Director nacional — responsable dinámico según la línea de negocio de la solicitud',
          'Tipo de aprobación (uno / todos)': 'Uno',
          'Tiempo límite (días)': '3',
        },
      },
      {
        nombre: 'Autorización de la gerencia del proceso', bloqueId: 'BLQ-003',
        valores: {
          'Aprobadores': 'Gerente del proceso — responsable dinámico según la línea de negocio de la solicitud',
          'Tipo de aprobación (uno / todos)': 'Uno',
          'Tiempo límite (días)': '3',
        },
      },
      {
        nombre: 'Autorización del CEO', bloqueId: 'BLQ-003',
        valores: {
          'Aprobadores': 'Diego · CEO',
          'Tipo de aprobación (uno / todos)': 'Uno',
          'Tiempo límite (días)': '1',
        },
      },
      {
        nombre: 'Creación de la posición aprobada', bloqueId: 'BLQ-009',
        valores: {
          'Acción a ejecutar': 'Crear una posición individual activa y vacante, asociada al cargo existente. No crea un cargo nuevo.',
          'Módulo destino': 'Organigrama aprobado',
          'Estado inicial del registro': 'Activa · Vacante',
        },
      },
      {
        nombre: 'Apertura', bloqueId: 'BLQ-002',
        valores: {
          'Responsable de revisión': 'Reclutadores',
          'Checklist de revisión': 'Revisa la información de la posición creada y envía la solicitud a las temporales',
          'Tiempo límite (días)': '1',
        },
      },
      {
        nombre: 'RQ Temporales', bloqueId: 'BLQ-001',
        valores: {
          'Campos del formulario': [
            { nombre: 'Código RQ', tipo: 'Texto corto' },
          ],
          'Validaciones': 'No permite cerrar la etapa sin registrar el código RQ entregado por la temporal',
          'Documentos requeridos': 'Ninguno obligatorio en esta etapa',
        },
      },
      {
        nombre: 'Actualizar HCM', bloqueId: 'BLQ-009',
        valores: {
          'Acción a ejecutar': 'Actualizar el control de planta y confirmar la vinculación entre solicitud, posición y requisición',
          'Módulo destino': 'HCM · Headcount',
          'Estado inicial del registro': 'Confirmado',
        },
      },
      {
        nombre: 'Alerta a Sistemas', bloqueId: 'BLQ-007',
        valores: {
          'Destinatarios': 'Coordinador Nacional de Tecnología',
          'Canal': 'Correo electrónico interno',
          'Plantilla de mensaje': 'Se aprobó una ampliación de nómina para un cargo existente. Esta notificación no modifica el estado de la posición ni de la vacante.',
        },
      },
    ],
  },
];

const getBloqueById = (id) => BLOQUES_FUNCIONALES_SEED.find(b => b.id === id);

const PlantillasSolicitudesSection = () => {
  const [tab, setTab] = _cf_useState('plantillas');
  const [plantillas, setPlantillas] = _cf_useState(PLANTILLAS_SOLICITUD_SEED);
  const [bloques, setBloques] = _cf_useState(BLOQUES_FUNCIONALES_SEED);
  const [viewingPlantilla, setViewingPlantilla] = _cf_useState(null);
  const [editingPlantilla, setEditingPlantilla] = _cf_useState(null);
  const [viewingBloque, setViewingBloque] = _cf_useState(null);
  const [editingBloque, setEditingBloque] = _cf_useState(null);

  const togglePlantillaEstado = (id) => {
    setPlantillas(list => list.map(p => p.id === id ? { ...p, estado: p.estado === 'activa' ? 'inactiva' : 'activa' } : p));
  };
  const saveBloques = (list) => setBloques(list);
  const saveBloque = (bloque) => {
    setBloques(list => list.some(b => b.id === bloque.id)
      ? list.map(b => b.id === bloque.id ? bloque : b)
      : [...list, bloque]);
    setEditingBloque(null);
  };
  const savePlantilla = (plantilla) => {
    setPlantillas(list => list.map(p => p.id === plantilla.id ? plantilla : p));
    setEditingPlantilla(null);
  };

  return (
    <>
      <div className="cf-section-head">
        <div>
          <h2 className="cf-section-title">Plantillas de solicitudes · Creador de flujos</h2>
          <p className="cf-section-sub">
            Cada <b>plantilla</b> define el proceso de selección y contratación para un tipo de solicitud: una secuencia de <b>etapas</b>, y cada etapa usa un <b>bloque funcional</b> reutilizable con sus propios atributos configurables.
          </p>
        </div>
      </div>

      <div className="doc-tabs">
        <button className={`doc-tab ${tab === 'plantillas' ? 'active' : ''}`} onClick={() => setTab('plantillas')}>Plantillas</button>
        <button className={`doc-tab ${tab === 'bloques' ? 'active' : ''}`} onClick={() => setTab('bloques')}>Bloques funcionales</button>
      </div>

      {tab === 'plantillas' && (
        <div className="doc-list-card" style={{ marginTop: 16 }}>
          <table className="doc-table">
            <thead>
              <tr>
                <th>Código</th>
                <th>Nombre de la plantilla</th>
                <th style={{ textAlign: 'center' }}>N.º de etapas</th>
                <th>Estado</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {plantillas.map(p => (
                <tr key={p.id}>
                  <td className="mono" style={{ fontSize: 12 }}>{p.id}</td>
                  <td style={{ fontWeight: 600, fontSize: 13 }}>{p.nombre}</td>
                  <td style={{ textAlign: 'center' }}><span className="cf-num-badge">{p.etapas.length}</span></td>
                  <td><span className={`pill ${p.estado === 'activa' ? 'green' : 'navy'}`}>{p.estado === 'activa' ? 'Activa' : 'Inactiva'}</span></td>
                  <td>
                    <div style={{ display: 'flex', gap: 4, justifyContent: 'flex-end' }}>
                      <button className="icon-action" title="Ver plantilla" onClick={() => setViewingPlantilla(p)}><IconExternal size={14} /></button>
                      <button className="icon-action" title="Editar plantilla" onClick={() => setEditingPlantilla(p)}><IconDoc size={14} /></button>
                      <button
                        className={`icon-action ${p.estado === 'activa' ? 'danger' : ''}`}
                        title={p.estado === 'activa' ? 'Inactivar plantilla' : 'Activar plantilla'}
                        onClick={() => togglePlantillaEstado(p.id)}
                      >
                        {p.estado === 'activa' ? <IconAlert size={14} /> : <IconCheck size={14} />}
                      </button>
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {tab === 'bloques' && (
        <div className="doc-list-card" style={{ marginTop: 16 }}>
          <table className="doc-table">
            <thead>
              <tr>
                <th>Código</th>
                <th>Nombre del bloque</th>
                <th>Descripción</th>
                <th style={{ textAlign: 'center' }}>Atributos</th>
                <th>Estado</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {bloques.map(b => (
                <tr key={b.id}>
                  <td className="mono" style={{ fontSize: 12 }}>{b.id}</td>
                  <td style={{ fontWeight: 600, fontSize: 13 }}>{b.nombre}</td>
                  <td className="muted" style={{ fontSize: 12.5, maxWidth: 320 }}>{b.descripcion}</td>
                  <td style={{ textAlign: 'center' }}><span className="cf-num-badge">{b.atributos.length}</span></td>
                  <td><span className={`pill ${b.estado === 'activo' ? 'green' : 'navy'}`}>{b.estado === 'activo' ? 'Activo' : 'Inactivo'}</span></td>
                  <td>
                    <div style={{ display: 'flex', gap: 4, justifyContent: 'flex-end' }}>
                      <button className="icon-action" title="Ver bloque" onClick={() => setViewingBloque(b)}><IconExternal size={14} /></button>
                      <button className="icon-action" title="Editar bloque" onClick={() => setEditingBloque(b)}><IconDoc size={14} /></button>
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {viewingPlantilla && <PlantillaViewModal plantilla={viewingPlantilla} onClose={() => setViewingPlantilla(null)} />}
      {editingPlantilla && <PlantillaFormModal plantilla={editingPlantilla} bloques={bloques} onClose={() => setEditingPlantilla(null)} onSave={savePlantilla} />}
      {viewingBloque && <BloqueViewModal bloque={viewingBloque} onClose={() => setViewingBloque(null)} />}
      {editingBloque && <BloqueFormModal bloque={editingBloque} onClose={() => setEditingBloque(null)} onSave={saveBloque} />}
    </>
  );
};

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

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 720 }}>
        <div className="modal-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>{plantilla.id}</div>
            <div className="modal-title">{plantilla.nombre}</div>
            <div className="modal-sub">Flujo de {plantilla.etapas.length} etapas · <span className={plantilla.estado === 'activa' ? 'muted' : 'muted'}>{plantilla.estado === 'activa' ? 'Plantilla activa' : 'Plantilla inactiva'}</span></div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <div className="cf-fe-canvas">
            <div className="cf-fe-step start">
              <span className="cf-flow-step-icon"><IconRocket size={14} /></span>
              <div>
                <div className="muted-xs">Inicio</div>
                <div style={{ fontWeight: 700, fontSize: 13 }}>Solicitud creada</div>
              </div>
            </div>
            {plantilla.etapas.map((e, i) => {
              const bloque = getBloqueById(e.bloqueId);
              return (
                <div key={i} className="cf-fe-step">
                  <span className="cf-flow-step-num">{i + 1}</span>
                  <div className="cf-fe-step-fields" style={{ gridTemplateColumns: '1fr' }}>
                    <div>
                      <div style={{ fontWeight: 700, fontSize: 13 }}>{e.nombre}</div>
                      <div className="muted" style={{ fontSize: 11.5, marginTop: 2 }}>
                        Bloque: <span className="pill navy" style={{ fontSize: 10.5 }}>{bloque ? bloque.nombre : '—'}</span>
                      </div>
                      {bloque && (
                        <div className="muted" style={{ fontSize: 11, marginTop: 4 }}>
                          Atributos: {bloque.atributos.join(' · ')}
                        </div>
                      )}
                    </div>
                  </div>
                </div>
              );
            })}
            <div className="cf-fe-step end">
              <span className="cf-flow-step-icon"><IconCheck size={14} /></span>
              <div>
                <div className="muted-xs">Fin</div>
                <div style={{ fontWeight: 700, fontSize: 13 }}>Solicitud finalizada</div>
              </div>
            </div>
          </div>
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cerrar</button>
        </div>
      </div>
    </div>
  );
};

const PlantillaFormModal = ({ plantilla, bloques, onClose, onSave }) => {
  const [nombre, setNombre] = _cf_useState(plantilla.nombre);
  const [etapas, setEtapas] = _cf_useState(plantilla.etapas.map(e => ({ ...e })));

  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 move = (i, dir) => {
    const j = i + dir;
    if (j < 0 || j >= etapas.length) return;
    const next = [...etapas];
    [next[i], next[j]] = [next[j], next[i]];
    setEtapas(next);
  };
  const remove = (i) => setEtapas(list => list.filter((_, x) => x !== i));
  const updateEtapa = (i, field, value) => setEtapas(list => list.map((e, x) => x === i ? { ...e, [field]: value } : e));
  const updateEtapaValores = (i, valores) => setEtapas(list => list.map((e, x) => x === i ? { ...e, valores } : e));

  const [managingIndex, setManagingIndex] = _cf_useState(null);

  const canSave = nombre.trim().length > 0 && etapas.length > 0 && etapas.every(e => e.nombre.trim().length > 0);

  const handleGuardar = () => {
    onSave({ ...plantilla, nombre: nombre.trim(), etapas });
  };

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 980 }}>
        <div className="modal-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>{plantilla.id}</div>
            <div className="modal-title">Editar plantilla</div>
            <div className="modal-sub">Ajusta el nombre y la secuencia de etapas. Cada etapa usa un bloque funcional del catálogo.</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <div className="furat-row" style={{ marginBottom: 16 }}>
            <label className="furat-label">Nombre de la plantilla</label>
            <input type="text" value={nombre} onChange={e => setNombre(e.target.value)} placeholder="Ej: Reemplazo por vacante" />
          </div>

          <div className="cf-fe-canvas">
            <div className="cf-fe-step start">
              <span className="cf-flow-step-icon"><IconRocket size={14} /></span>
              <div>
                <div className="muted-xs">Inicio</div>
                <div style={{ fontWeight: 700, fontSize: 13 }}>Solicitud creada</div>
              </div>
            </div>

            {etapas.map((e, i) => (
              <div key={i} className="cf-fe-step">
                <div className="cf-fe-step-grip">
                  <button className="icon-action" onClick={() => move(i, -1)} disabled={i === 0} title="Arriba">
                    <IconChevronLeft size={13} style={{ transform: 'rotate(90deg)' }} />
                  </button>
                  <span className="cf-flow-step-num">{i + 1}</span>
                  <button className="icon-action" onClick={() => move(i, 1)} disabled={i === etapas.length - 1} title="Abajo">
                    <IconChevronRight size={13} style={{ transform: 'rotate(90deg)' }} />
                  </button>
                </div>
                <div className="cf-fe-step-fields">
                  <div>
                    <label className="muted-xs">Nombre de la etapa</label>
                    <input type="text" value={e.nombre} onChange={ev => updateEtapa(i, 'nombre', ev.target.value)} placeholder="Ej: Aprobación de RRHH" />
                  </div>
                  <div>
                    <label className="muted-xs">Bloque funcional</label>
                    <select value={e.bloqueId} onChange={ev => updateEtapa(i, 'bloqueId', ev.target.value)}>
                      {bloques.map(b => <option key={b.id} value={b.id}>{b.nombre}</option>)}
                    </select>
                  </div>
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                  <button className="icon-action" onClick={() => setManagingIndex(i)} title="Gestionar etapa">
                    <IconSettings size={14} />
                  </button>
                  <button className="icon-action danger" onClick={() => remove(i)} title="Quitar etapa">
                    <IconAlert size={14} />
                  </button>
                </div>
              </div>
            ))}

            <button className="cf-fe-add" onClick={() => setEtapas([...etapas, { nombre: '', bloqueId: bloques[0] ? bloques[0].id : '' }])}>
              <IconPlus size={13} /> Agregar etapa
            </button>

            <div className="cf-fe-step end">
              <span className="cf-flow-step-icon"><IconCheck size={14} /></span>
              <div>
                <div className="muted-xs">Fin</div>
                <div style={{ fontWeight: 700, fontSize: 13 }}>Solicitud finalizada</div>
              </div>
            </div>
          </div>
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" onClick={handleGuardar} disabled={!canSave}>
            <IconCheck size={14} /> Guardar plantilla
          </button>
        </div>
      </div>

      {managingIndex !== null && etapas[managingIndex] && (
        <EtapaGestionModal
          etapa={etapas[managingIndex]}
          bloque={getBloqueById(etapas[managingIndex].bloqueId)}
          onClose={() => setManagingIndex(null)}
          onSave={(valores) => { updateEtapaValores(managingIndex, valores); setManagingIndex(null); }}
        />
      )}
    </div>
  );
};

const FORM_FIELD_TYPES = ['Texto corto', 'Texto largo', 'Número', 'Fecha', 'Selección única', 'Selección múltiple', 'Casilla de verificación', 'Archivo adjunto'];

const FORM_FIELD_CATALOG = [
  { nombre: 'Nombre completo', tipo: 'Texto corto' },
  { nombre: 'Documento de identidad', tipo: 'Texto corto' },
  { nombre: 'Cargo', tipo: 'Selección única' },
  { nombre: 'Sede', tipo: 'Selección única' },
  { nombre: 'Centro de costo', tipo: 'Selección única' },
  { nombre: 'Fecha de solicitud', tipo: 'Fecha' },
  { nombre: 'Fecha límite', tipo: 'Fecha' },
  { nombre: 'Motivo de la solicitud', tipo: 'Texto largo' },
  { nombre: 'Observaciones', tipo: 'Texto largo' },
  { nombre: 'Adjuntar soporte', tipo: 'Archivo adjunto' },
];

const CamposFormularioSelector = ({ campos, onChange }) => {
  const [showCustom, setShowCustom] = _cf_useState(false);
  const [customNombre, setCustomNombre] = _cf_useState('');
  const [customTipo, setCustomTipo] = _cf_useState(FORM_FIELD_TYPES[0]);

  const disponibles = FORM_FIELD_CATALOG.filter(f => !campos.some(c => c.nombre === f.nombre));
  const addCampo = (campo) => onChange([...campos, campo]);
  const removeCampo = (nombre) => onChange(campos.filter(c => c.nombre !== nombre));

  const crearPersonalizado = () => {
    if (!customNombre.trim()) return;
    addCampo({ nombre: customNombre.trim(), tipo: customTipo, personalizado: true });
    setCustomNombre('');
    setCustomTipo(FORM_FIELD_TYPES[0]);
    setShowCustom(false);
  };

  return (
    <div>
      <div className="signer-chips" style={{ marginBottom: 10, minHeight: 24 }}>
        {campos.length === 0 && <span className="muted" style={{ fontSize: 12 }}>Ningún campo agregado todavía.</span>}
        {campos.map((c, i) => (
          <span key={i} className="signer-chip">
            {c.nombre} <span className="muted" style={{ fontSize: 10 }}>· {c.tipo}</span>
            <button
              type="button" onClick={() => removeCampo(c.nombre)} title={`Quitar ${c.nombre}`}
              style={{ background: 'none', border: 'none', cursor: 'pointer', display: 'flex', color: 'inherit', padding: 0, marginLeft: 2 }}
            >
              <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
            </button>
          </span>
        ))}
      </div>

      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
        <select
          value=""
          onChange={e => { const f = disponibles.find(x => x.nombre === e.target.value); if (f) addCampo(f); }}
          disabled={disponibles.length === 0}
          style={{ maxWidth: 260 }}
        >
          <option value="">{disponibles.length ? '+ Agregar campo del catálogo' : 'Todos los campos agregados'}</option>
          {disponibles.map(f => <option key={f.nombre} value={f.nombre}>{f.nombre} ({f.tipo})</option>)}
        </select>
        <button type="button" className="btn" onClick={() => setShowCustom(true)}>
          <IconPlus size={13} /> Crear campo personalizado
        </button>
      </div>

      {showCustom && (
        <div style={{ marginTop: 10, padding: 12, background: 'var(--surface)', borderRadius: 8, border: '1px solid var(--border)' }}>
          <div className="furat-grid-2">
            <div className="furat-row">
              <label className="furat-label">Nombre del campo</label>
              <input type="text" value={customNombre} onChange={e => setCustomNombre(e.target.value)} placeholder="Ej: Número de contrato" autoFocus />
            </div>
            <div className="furat-row">
              <label className="furat-label">Tipo de campo</label>
              <select value={customTipo} onChange={e => setCustomTipo(e.target.value)}>
                {FORM_FIELD_TYPES.map(t => <option key={t} value={t}>{t}</option>)}
              </select>
            </div>
          </div>
          <div style={{ display: 'flex', gap: 8, marginTop: 10 }}>
            <button type="button" className="btn" onClick={() => { setShowCustom(false); setCustomNombre(''); }}>Cancelar</button>
            <button type="button" className="btn primary" onClick={crearPersonalizado} disabled={!customNombre.trim()}>
              <IconCheck size={14} /> Agregar campo
            </button>
          </div>
        </div>
      )}
    </div>
  );
};

const EtapaGestionModal = ({ etapa, bloque, onClose, onSave }) => {
  const isFormulario = bloque && bloque.nombre === 'Formulario';
  const [valores, setValores] = _cf_useState(() => {
    const base = {};
    (bloque ? bloque.atributos : []).forEach(a => {
      const prev = etapa.valores && etapa.valores[a];
      if (isFormulario && a === 'Campos del formulario') {
        base[a] = Array.isArray(prev) ? prev : [];
      } else {
        base[a] = prev || '';
      }
    });
    return base;
  });

  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 setValor = (attr, v) => setValores(prev => ({ ...prev, [attr]: v }));

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 560 }}>
        <div className="modal-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>{bloque ? bloque.id : '—'}</div>
            <div className="modal-title">Gestionar etapa · {etapa.nombre || 'Sin nombre'}</div>
            <div className="modal-sub">
              Configura los atributos del bloque <b>{bloque ? bloque.nombre : '—'}</b> para esta etapa específica.
            </div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          {bloque && bloque.atributos.length > 0 ? (
            bloque.atributos.map((a, i) => (
              <div key={i} className="furat-row">
                <label className="furat-label">{a}</label>
                {isFormulario && a === 'Campos del formulario' ? (
                  <CamposFormularioSelector campos={valores[a] || []} onChange={(campos) => setValor(a, campos)} />
                ) : (
                  <input type="text" value={valores[a] || ''} onChange={e => setValor(a, e.target.value)} placeholder={`Valor de "${a}"`} />
                )}
              </div>
            ))
          ) : (
            <p className="muted" style={{ fontSize: 13 }}>Este bloque no tiene atributos configurables.</p>
          )}
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" onClick={() => onSave(valores)}>
            <IconCheck size={14} /> Guardar configuración
          </button>
        </div>
      </div>
    </div>
  );
};

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

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 560 }}>
        <div className="modal-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>{bloque.id}</div>
            <div className="modal-title">{bloque.nombre}</div>
            <div className="modal-sub">{bloque.estado === 'activo' ? 'Bloque activo' : 'Bloque inactivo'}</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <p className="muted" style={{ fontSize: 13, marginTop: 0 }}>{bloque.descripcion}</p>
          <label className="furat-label">Atributos configurables</label>
          <ul style={{ margin: '6px 0 0', paddingLeft: 18 }}>
            {bloque.atributos.map((a, i) => (
              <li key={i} style={{ fontSize: 13, marginBottom: 4 }}>{a}</li>
            ))}
          </ul>
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cerrar</button>
        </div>
      </div>
    </div>
  );
};

const BloqueFormModal = ({ bloque, onClose, onSave }) => {
  const [nombre, setNombre] = _cf_useState(bloque.nombre);
  const [descripcion, setDescripcion] = _cf_useState(bloque.descripcion);
  const [estado, setEstado] = _cf_useState(bloque.estado);
  const [atributos, setAtributos] = _cf_useState([...bloque.atributos]);

  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 updateAtributo = (i, value) => setAtributos(list => list.map((a, x) => x === i ? value : a));
  const removeAtributo = (i) => setAtributos(list => list.filter((_, x) => x !== i));

  const canSave = nombre.trim().length > 0 && atributos.every(a => a.trim().length > 0);

  const handleGuardar = () => {
    onSave({ ...bloque, nombre: nombre.trim(), descripcion: descripcion.trim(), estado, atributos });
  };

  return (
    <div className="modal-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 620 }}>
        <div className="modal-head">
          <div>
            <div className="muted mono" style={{ fontSize: 11 }}>{bloque.id}</div>
            <div className="modal-title">Editar bloque funcional</div>
            <div className="modal-sub">Define el nombre, la descripción y los atributos configurables de este bloque.</div>
          </div>
          <button className="icon-btn" onClick={onClose} title="Cerrar">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
          </button>
        </div>
        <div className="modal-body">
          <div className="furat-row">
            <label className="furat-label">Nombre del bloque</label>
            <input type="text" value={nombre} onChange={e => setNombre(e.target.value)} placeholder="Ej: Aprobación" />
          </div>
          <div className="furat-row">
            <label className="furat-label">Descripción</label>
            <textarea rows={2} value={descripcion} onChange={e => setDescripcion(e.target.value)} placeholder="¿Qué hace este bloque dentro de una etapa?" />
          </div>
          <div className="furat-row">
            <label className="furat-label">Estado</label>
            <select value={estado} onChange={e => setEstado(e.target.value)}>
              <option value="activo">Activo</option>
              <option value="inactivo">Inactivo</option>
            </select>
          </div>
          <div className="furat-row">
            <label className="furat-label">Atributos configurables</label>
            {atributos.map((a, i) => (
              <div key={i} style={{ display: 'flex', gap: 6, marginBottom: 6 }}>
                <input type="text" value={a} onChange={e => updateAtributo(i, e.target.value)} placeholder="Ej: Aprobadores" style={{ flex: 1 }} />
                <button type="button" className="icon-action danger" onClick={() => removeAtributo(i)} title="Quitar atributo">
                  <IconAlert size={14} />
                </button>
              </div>
            ))}
            <button type="button" className="btn" style={{ marginTop: 2 }} onClick={() => setAtributos([...atributos, ''])}>
              <IconPlus size={13} /> Agregar atributo
            </button>
          </div>
        </div>
        <div className="modal-foot">
          <button className="btn" onClick={onClose}>Cancelar</button>
          <button className="btn primary" onClick={handleGuardar} disabled={!canSave}>
            <IconCheck size={14} /> Guardar bloque
          </button>
        </div>
      </div>
    </div>
  );
};

const TemplatesSection = () => (
  <>
    <div className="cf-section-head">
      <div>
        <h2 className="cf-section-title">Plantillas de documentos</h2>
        <p className="cf-section-sub">
          Los contratos, certificaciones y reglamentos que el sistema genera automáticamente. La edición full está en el módulo de Documentos.
        </p>
      </div>
      <button className="btn"><IconExternal size={14} /> Ir a Documentos · Plantillas</button>
    </div>
    <div className="doc-list-card">
      <table className="doc-table">
        <thead>
          <tr>
            <th>Plantilla</th>
            <th>Tipo</th>
            <th>Versión</th>
            <th style={{ textAlign: 'center' }}>Usos</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          {TEMPLATES_LINK.map(t => (
            <tr key={t.id}>
              <td style={{ fontWeight: 600, fontSize: 13 }}>{t.name}</td>
              <td><span className="pill navy" style={{ fontSize: 11 }}>{t.type}</span></td>
              <td><span className="pill navy mono" style={{ fontSize: 11 }}>{t.version}</span></td>
              <td style={{ textAlign: 'center', fontFamily: 'JetBrains Mono', fontSize: 12.5, fontWeight: 700 }}>{t.uses.toLocaleString()}</td>
              <td>
                <button className="icon-action" title="Editar"><IconExternal size={14} /></button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  </>
);

// ─── Section: Competencias y versiones ───────────────────

const CMP_VERSION_HISTORY = {
  'CMP-01': [
    { v: 'v3.2', date: '12/04/2026', author: 'Carlos F. Vélez',  current: true,  changes: ['Actualizada sección LOTO con bloqueo eléctrico', 'Agregado caso real accidente Q1 2026'], appliedSessions: 1, certCount: 142 },
    { v: 'v3.1', date: '03/02/2026', author: 'Carlos F. Vélez',  current: false, changes: ['Inclusión protocolo nueva trituradora industrial'], appliedSessions: 3, certCount: 47 },
    { v: 'v3.0', date: '15/12/2025', author: 'Carolina Restrepo', current: false, changes: ['Reescritura completa post Reforma Laboral 2025'], appliedSessions: 8, certCount: 168 },
    { v: 'v2.5', date: '04/08/2025', author: 'Carlos F. Vélez',  current: false, changes: ['Ajuste módulo EPP categoría III'], appliedSessions: 12, certCount: 224 },
  ],
  'CMP-02': [
    { v: 'v1.4', date: '10/03/2026', author: 'Patricia Gómez', current: true,  changes: ['Actualización Resolución 2674/2013'], appliedSessions: 0, certCount: 0 },
    { v: 'v1.3', date: '15/01/2026', author: 'Patricia Gómez', current: false, changes: ['Inclusión control de plagas extendido'], appliedSessions: 2, certCount: 64 },
    { v: 'v1.2', date: '02/09/2025', author: 'Patricia Gómez', current: false, changes: ['Versión inicial INVIMA actualizada'], appliedSessions: 6, certCount: 187 },
  ],
};

const CMP_ROLES_COVERAGE = {
  'CMP-01': [
    { role: 'Operario de Clasificación', total: 142, vigentes: 138, vencidos: 3, sinFormar: 1 },
    { role: 'Líder de Aprovechamiento',     total: 6,   vigentes: 6,   vencidos: 0, sinFormar: 0 },
    { role: 'Téc. Mantenimiento',   total: 22,  vigentes: 18,  vencidos: 3, sinFormar: 1 },
  ],
  'CMP-02': [
    { role: 'Operario de Clasificación', total: 142, vigentes: 130, vencidos: 8,  sinFormar: 4 },
    { role: 'Op. Aprovechamiento',          total: 98,  vigentes: 92,  vencidos: 4,  sinFormar: 2 },
    { role: 'Aux. Calidad',         total: 14,  vigentes: 14,  vencidos: 0,  sinFormar: 0 },
    { role: 'Líder de Aprovechamiento',     total: 6,   vigentes: 6,   vencidos: 0,  sinFormar: 0 },
  ],
};

const CompetenciasEditorSection = () => {
  const [editing, setEditing] = _cf_useState(null);  // competencia abierta en editor
  const [filterCat, setFilterCat] = _cf_useState('todas');

  const list = COMPETENCIAS_MAESTRAS.filter(c =>
    filterCat === 'todas' || c.cat === filterCat
  );

  if (editing) return <CompetenciaEditor cmp={editing} onBack={() => setEditing(null)} />;

  const altas = COMPETENCIAS_MAESTRAS.filter(c => c.criticality === 'alta').length;

  return (
    <>
      <div className="cf-section-head">
        <div>
          <h2 className="cf-section-title">Competencias y versiones de contenido</h2>
          <p className="cf-section-sub">
            Catálogo maestro de competencias auditables. Cada competencia se cubre con uno o más cursos y mantiene <b>historial inmutable de versiones</b> de contenido. La versión activa es la que se ancla a las próximas sesiones.
          </p>
        </div>
        <button className="btn primary"><IconPlus size={14} /> Nueva competencia</button>
      </div>

      <div className="ic-cmp-banner">
        <div className="ic-cmp-banner-icon"><IconShield size={18} /></div>
        <div style={{ flex: 1 }}>
          <div className="ic-cmp-banner-title">Reglas de versionado · ICONTEC</div>
          <div className="ic-cmp-banner-sub">
            Las versiones <b>nunca se editan</b>: se publica una nueva con changelog. Los certificados emitidos quedan anclados a la versión vigente al momento de la sesión, aunque el contenido cambie después.
          </div>
        </div>
        <div className="ic-cmp-banner-stat">
          <div className="ic-cmp-banner-num">{COMPETENCIAS_MAESTRAS.length}</div>
          <div className="muted" style={{ fontSize: 11 }}>competencias · {altas} críticas</div>
        </div>
      </div>

      <div className="sst-quickfilter">
        <button className={`sst-chip ${filterCat === 'todas' ? 'active' : ''}`} onClick={() => setFilterCat('todas')}>Todas</button>
        {Object.entries(CMP_CAT).map(([k, v]) => (
          <button key={k} className={`sst-chip ${filterCat === k ? 'active' : ''}`} onClick={() => setFilterCat(k)}>{v.label}</button>
        ))}
        <div style={{ flex: 1 }} />
        <button className="btn"><IconExternal size={14} /> Exportar catálogo</button>
      </div>

      <div className="doc-list-card">
        <table className="doc-table">
          <thead>
            <tr>
              <th>Competencia</th>
              <th>Categoría</th>
              <th>Criticidad</th>
              <th style={{ textAlign: 'center' }}>Versiones</th>
              <th>Versión vigente</th>
              <th>Norma vinculada</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {list.map(c => {
              const cat = CMP_CAT[c.cat];
              const crit = CRITICALITY[c.criticality];
              const versions = CMP_VERSION_HISTORY[c.id] || [];
              const current = versions.find(v => v.current);
              return (
                <tr key={c.id}>
                  <td data-label="Competencia">
                    <div style={{ fontWeight: 700, fontSize: 13.5 }}>{c.name}</div>
                    <div className="muted mono" style={{ fontSize: 11 }}>{c.id}</div>
                  </td>
                  <td data-label="Categoría">
                    <span className={`tr-cat-badge ${cat.tone}`}>{cat.label}</span>
                  </td>
                  <td data-label="Criticidad">
                    <span className={`pill ${crit.pill}`}>
                      <span className="status-dot" style={{ background: crit.dot }} /> {crit.label}
                    </span>
                  </td>
                  <td data-label="Versiones" style={{ textAlign: 'center' }}>
                    <span className="cf-num-badge">{versions.length || 1}</span>
                  </td>
                  <td data-label="Vigente">
                    {current ? (
                      <>
                        <div className="mono" style={{ fontWeight: 700, fontSize: 12.5, color: 'var(--navy-800)' }}>{current.v}</div>
                        <div className="muted mono" style={{ fontSize: 10.5 }}>{current.date} · {current.author}</div>
                      </>
                    ) : (
                      <span className="muted" style={{ fontSize: 11.5 }}>v1.0 (única)</span>
                    )}
                  </td>
                  <td data-label="Norma" className="muted" style={{ fontSize: 11.5, maxWidth: 240 }}>{c.norma}</td>
                  <td>
                    <button className="btn primary" style={{ padding: '5px 11px', fontSize: 12 }} onClick={() => setEditing(c)}>
                      <IconExternal size={13} /> Editar
                    </button>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </>
  );
};

// ─── Editor de competencia individual ────────────────────

const CompetenciaEditor = ({ cmp, onBack }) => {
  const [tab, setTab] = _cf_useState('versiones');
  const [showNewVersion, setShowNewVersion] = _cf_useState(false);
  const [newVersionChanges, setNewVersionChanges] = _cf_useState('');
  const versions = CMP_VERSION_HISTORY[cmp.id] || [];
  const current = versions.find(v => v.current);
  const coverage = CMP_ROLES_COVERAGE[cmp.id] || [];

  const cat = CMP_CAT[cmp.cat];
  const crit = CRITICALITY[cmp.criticality];

  return (
    <>
      <button className="btn" onClick={onBack} style={{ marginBottom: 14 }}>
        <IconChevronLeft size={14} /> Volver al catálogo
      </button>

      <div className="cf-cmp-edit-head">
        <div style={{ flex: 1, minWidth: 0 }}>
          <div className="muted mono" style={{ fontSize: 11 }}>{cmp.id}</div>
          <h2 className="cf-cmp-edit-name">{cmp.name}</h2>
          <div style={{ display: 'flex', gap: 8, marginTop: 8, flexWrap: 'wrap', alignItems: 'center' }}>
            <span className={`tr-cat-badge ${cat.tone}`}>{cat.label}</span>
            <span className={`pill ${crit.pill}`}><span className="status-dot" style={{ background: crit.dot }} /> Crit. {crit.label}</span>
            <span className="muted" style={{ fontSize: 12 }}>· Recurrencia: <b style={{ color: 'var(--text)' }}>{cmp.recur}</b></span>
            <span className="muted" style={{ fontSize: 12 }}>· {cmp.rolesCount} cargos la exigen</span>
          </div>
          <div className="cf-cmp-edit-norma">
            <IconShield size={12} /> Norma vinculada: <b style={{ marginLeft: 4 }}>{cmp.norma}</b>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button className="btn"><IconBarChart size={14} /> Ver cobertura</button>
          <button className="btn"><IconExternal size={14} /> Exportar histórico</button>
        </div>
      </div>

      <div className="doc-tabs" style={{ marginTop: 18 }}>
        <button className={`doc-tab ${tab === 'versiones' ? 'active' : ''}`} onClick={() => setTab('versiones')}>
          <IconBook size={14} /> Versiones de contenido <span className="epp-tab-pill">{versions.length}</span>
        </button>
        <button className={`doc-tab ${tab === 'cobertura' ? 'active' : ''}`} onClick={() => setTab('cobertura')}>
          <IconUsers size={14} /> Cobertura por cargo
        </button>
        <button className={`doc-tab ${tab === 'datos' ? 'active' : ''}`} onClick={() => setTab('datos')}>
          <IconSettings size={14} /> Datos básicos
        </button>
      </div>

      {tab === 'versiones' && (
        <>
          <div className="cf-vers-banner">
            <div className="cf-vers-current">
              <div className="muted-xs">Versión vigente · activa</div>
              <div className="cf-vers-current-num mono">{current?.v}</div>
              <div className="muted" style={{ fontSize: 11.5 }}>{current?.date} · {current?.author}</div>
            </div>
            <div style={{ flex: 1 }} />
            {!showNewVersion ? (
              <button className="btn primary" onClick={() => setShowNewVersion(true)}>
                <IconPlus size={14} /> Publicar nueva versión
              </button>
            ) : (
              <div className="cf-vers-new">
                <div className="muted-xs" style={{ marginBottom: 6 }}>Cambios respecto a {current?.v}</div>
                <textarea
                  className="cf-vers-new-input"
                  rows={2}
                  value={newVersionChanges}
                  onChange={e => setNewVersionChanges(e.target.value)}
                  placeholder='Ej: "Actualizada sección LOTO con caso real Q1"  (cada línea es un cambio)'
                />
                <div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
                  <button className="btn" onClick={() => { setShowNewVersion(false); setNewVersionChanges(''); }}>Cancelar</button>
                  <button className="btn primary" disabled={newVersionChanges.trim().length < 8}>
                    <IconShield size={13} /> Publicar v{current ? (parseFloat(current.v.slice(1)) + 0.1).toFixed(1) : '1.0'}
                  </button>
                </div>
              </div>
            )}
          </div>

          <div className="cf-vers-list">
            {versions.map((v, i) => (
              <div key={v.v} className={`cf-vers-card ${v.current ? 'current' : ''}`}>
                <div className="cf-vers-rail">
                  <div className="cf-vers-dot">
                    {v.current ? <IconCheck size={11} /> : v.v.charAt(1)}
                  </div>
                  {i < versions.length - 1 && <div className="cf-vers-line" />}
                </div>
                <div className="cf-vers-body">
                  <div className="cf-vers-head">
                    <div>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                        <span className="cf-vers-num mono">{v.v}</span>
                        {v.current && <span className="pill green" style={{ fontSize: 10.5 }}><span className="status-dot" style={{ background: 'var(--green-600)' }} /> Activa</span>}
                        {!v.current && <span className="pill navy" style={{ fontSize: 10.5 }}>Histórica</span>}
                      </div>
                      <div className="muted" style={{ fontSize: 12, marginTop: 4 }}>
                        Publicada <b style={{ color: 'var(--text)' }}>{v.date}</b> por {v.author}
                      </div>
                    </div>
                    <div className="cf-vers-stats">
                      <div><div className="muted-xs">Sesiones aplicadas</div><div className="cf-vers-stat-val mono">{v.appliedSessions}</div></div>
                      <div><div className="muted-xs">Certificados con esta v.</div><div className="cf-vers-stat-val mono">{v.certCount}</div></div>
                    </div>
                  </div>
                  <div className="cf-vers-changes">
                    <div className="muted-xs" style={{ marginBottom: 6 }}>Changelog</div>
                    <ul className="cf-vers-changelog">
                      {v.changes.map((c, j) => <li key={j}><IconCheck size={11} /> {c}</li>)}
                    </ul>
                  </div>
                  {!v.current && (
                    <div style={{ display: 'flex', gap: 6, marginTop: 12 }}>
                      <button className="btn" style={{ padding: '5px 11px', fontSize: 12 }}><IconExternal size={13} /> Ver contenido</button>
                      <button className="btn" style={{ padding: '5px 11px', fontSize: 12 }}><IconDoc size={13} /> Certificados con esta versión</button>
                    </div>
                  )}
                </div>
              </div>
            ))}
          </div>

          <div className="cf-vers-immut">
            <IconShield size={14} />
            <div>
              <div style={{ fontWeight: 700, fontSize: 12.5 }}>Inmutabilidad de versiones</div>
              <div className="muted" style={{ fontSize: 11.5, marginTop: 2, lineHeight: 1.45 }}>
                Las versiones publicadas no se editan ni se eliminan. Los {versions.reduce((a, v) => a + v.certCount, 0)} certificados emitidos con versiones anteriores conservan el contenido al que aplicaron, conforme a normativa ICONTEC.
              </div>
            </div>
          </div>
        </>
      )}

      {tab === 'cobertura' && (
        <>
          <div className="muted" style={{ fontSize: 12.5, marginBottom: 12 }}>
            <IconUsers size={11} /> Cobertura actual de la competencia <b style={{ color: 'var(--text)' }}>{cmp.name}</b> en cada cargo que la exige.
          </div>
          <div className="doc-list-card">
            <table className="doc-table">
              <thead>
                <tr>
                  <th>Cargo</th>
                  <th style={{ textAlign: 'center' }}>Total</th>
                  <th style={{ textAlign: 'center' }}>Vigentes</th>
                  <th style={{ textAlign: 'center' }}>Vencidos</th>
                  <th style={{ textAlign: 'center' }}>Sin formar</th>
                  <th>Cumplimiento</th>
                </tr>
              </thead>
              <tbody>
                {coverage.map((r, i) => {
                  const pct = Math.round((r.vigentes / r.total) * 100);
                  const tone = pct >= 90 ? 'green' : pct >= 70 ? 'amber' : 'rose';
                  return (
                    <tr key={i}>
                      <td data-label="Cargo" style={{ fontWeight: 600, fontSize: 13 }}>{r.role}</td>
                      <td data-label="Total" className="mono" style={{ textAlign: 'center', fontWeight: 700 }}>{r.total}</td>
                      <td data-label="Vigentes" style={{ textAlign: 'center' }} className="mono"><span style={{ color: 'var(--green-600)', fontWeight: 700 }}>{r.vigentes}</span></td>
                      <td data-label="Vencidos" style={{ textAlign: 'center' }} className="mono">{r.vencidos > 0 ? <span style={{ color: 'var(--rose-600)', fontWeight: 700 }}>{r.vencidos}</span> : <span className="muted">0</span>}</td>
                      <td data-label="Sin formar" style={{ textAlign: 'center' }} className="mono">{r.sinFormar > 0 ? <span style={{ color: 'var(--amber-600)', fontWeight: 700 }}>{r.sinFormar}</span> : <span className="muted">0</span>}</td>
                      <td data-label="Cumplimiento">
                        <div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 200 }}>
                          <div className="tr-prog-track" style={{ flex: 1 }}>
                            <div className={`tr-prog-fill ${tone}`} style={{ width: `${pct}%` }} />
                          </div>
                          <span className={`mono`} style={{ fontWeight: 800, fontSize: 13, color: tone === 'green' ? 'var(--green-600)' : tone === 'amber' ? 'var(--amber-600)' : 'var(--rose-600)' }}>{pct}%</span>
                        </div>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </>
      )}

      {tab === 'datos' && (
        <div className="doc-list-card" style={{ padding: 22 }}>
          <div className="cf-cmp-fields">
            <div className="furat-row">
              <label className="furat-label">Nombre de la competencia</label>
              <input type="text" defaultValue={cmp.name} />
            </div>
            <div className="furat-row">
              <label className="furat-label">Descripción</label>
              <textarea rows={3} defaultValue={cmp.description} />
            </div>
            <div className="furat-grid-2">
              <div className="furat-row">
                <label className="furat-label">Categoría</label>
                <select defaultValue={cmp.cat}>
                  {Object.entries(CMP_CAT).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
                </select>
              </div>
              <div className="furat-row">
                <label className="furat-label">Criticidad</label>
                <select defaultValue={cmp.criticality}>
                  <option value="alta">Alta · ICONTEC</option>
                  <option value="media">Media</option>
                  <option value="baja">Baja</option>
                </select>
              </div>
              <div className="furat-row">
                <label className="furat-label">Recurrencia</label>
                <select defaultValue={cmp.recur}>
                  <option>Anual</option>
                  <option>Semestral</option>
                  <option>Trianual</option>
                  <option>Una vez</option>
                  <option>Una vez · ingreso</option>
                  <option>Por cambio</option>
                </select>
              </div>
              <div className="furat-row">
                <label className="furat-label">Norma legal vinculada</label>
                <input type="text" defaultValue={cmp.norma} />
              </div>
            </div>
          </div>
          <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, marginTop: 16, paddingTop: 14, borderTop: '1px solid var(--border)' }}>
            <button className="btn">Cancelar</button>
            <button className="btn primary"><IconCheck size={14} /> Guardar cambios en datos básicos</button>
          </div>
          <div className="muted" style={{ fontSize: 11.5, marginTop: 12, lineHeight: 1.5 }}>
            <IconShield size={11} /> Cambios en datos básicos quedan registrados en bitácora pero no generan nueva versión de contenido. Para versionar el contenido, ve a la pestaña <b>Versiones</b>.
          </div>
        </div>
      )}
    </>
  );
};

window.Settings = Settings;
