// src/screen-personas.jsx — Catálogo de PERSONAS (clientes) rediseñado.
// Anatomía de ficha: header con identidad + highlights fijos + tabs
// (Pólizas por relación / Documentos Art. 492) + listas relacionadas.
// La prima sólo se muestra contra quien está OBLIGADO a pagarla; un
// beneficiario nunca la carga. Incluye el consolidador de fichas duplicadas.

function ClientsScreen() {
  const { match } = useHashRoute();
  if (match('/clientes/duplicados')) return <ConsolidadorScreen/>;
  const detail = match('/clientes/:id');
  if (detail && detail.params.id !== 'duplicados') return <PersonaDetail id={detail.params.id}/>;
  return <PersonaList/>;
}

// ─────────────────────────────────────────────────────────────
// Piezas compartidas (también las usa el catálogo de pólizas)
// ─────────────────────────────────────────────────────────────

// Vigencia en lenguaje humano: "Vence en 12 días", no una fecha pelona.
function AxVigenciaHumana({ iso, prefijo }) {
  const d = AdmixPersonas.daysUntil(iso);
  if (d == null) return <span style={{ color: 'var(--ax-fg-faint)' }}>—</span>;
  let texto, color;
  if (d < 0)       { texto = 'Venció hace ' + Math.abs(d) + (Math.abs(d) === 1 ? ' día' : ' días'); color = 'var(--ax-fg-faint)'; }
  else if (d === 0){ texto = 'Vence hoy';                    color = 'var(--ax-warm)'; }
  else if (d <= 30){ texto = 'Vence en ' + d + (d === 1 ? ' día' : ' días'); color = 'var(--ax-warm)'; }
  else             { texto = (prefijo || 'Vence el ') + AdmixData.formatDateES(iso); color = 'var(--ax-fg-muted)'; }
  return (
    <span style={{ display: 'inline-flex', flexDirection: 'column', lineHeight: 1.3 }}>
      <span style={{ fontSize: 12, color }}>{texto}</span>
      {d >= 0 && d <= 30 ? <span className="ax-mono" style={{ fontSize: 10, color: 'var(--ax-fg-faint)' }}>{AdmixData.formatDateES(iso)}</span> : null}
    </span>
  );
}

// Pill de rol — el vocabulario que el asistente aprende una sola vez.
function AxRolPill({ rol, obligadoPago }) {
  const tone = rol === 'CONTRATANTE' ? 'accent' : rol === 'BENEFICIARIO' ? 'info' : 'neutral';
  return <AxPill tone={tone}>{AdmixPersonas.rolLabel(rol)}</AxPill>;
}

// Pill de identificación (KYC) — semáforo simple.
function AxKycPill({ kyc }) {
  if (!kyc) return null;
  const tone = kyc.estado === 'ok' ? 'accent' : kyc.estado === 'atencion' ? 'warm' : 'danger';
  return <AxPill tone={tone}>{kyc.etiqueta}</AxPill>;
}

// Chips de filtro SIEMPRE visibles (patrón Applied Epic): el usuario ve las
// opciones, no las descubre dentro de un dropdown.
function AxChipRow({ value, onChange, options }) {
  return (
    <div style={{ display: 'flex', gap: 6 }}>
      {options.map((o) => {
        const active = value === o.v;
        return (
          <button key={o.v} onClick={() => onChange(o.v)} style={{
            appearance: 'none', cursor: 'default',
            background: active ? 'var(--ax-bg-4)' : 'transparent',
            border: '1px solid ' + (active ? 'var(--ax-border-strong)' : 'var(--ax-border)'),
            color: active ? 'var(--ax-fg-strong)' : 'var(--ax-fg-muted)',
            height: 32, padding: '0 12px', borderRadius: 16, fontSize: 12,
            display: 'inline-flex', alignItems: 'center', gap: 6,
            transition: 'all 120ms', whiteSpace: 'nowrap',
          }}>
            {o.label}
            {o.n != null ? <span className="ax-mono" style={{ fontSize: 10, color: active ? 'var(--ax-fg-muted)' : 'var(--ax-fg-faint)' }}>{o.n}</span> : null}
          </button>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// LISTA DE PERSONAS
// ─────────────────────────────────────────────────────────────
function PersonaList() {
  const { navigate } = useHashRoute();
  const [search, setSearch] = useState('');
  const [rolF, setRolF] = useState('all');
  const [kycF, setKycF] = useState('all');
  const [sortKey, setSortKey] = useState('prima');

  const todas = useMemo(() => AdmixPersonas.personasConCartera(), []);
  const nDup = AdmixPersonas.DUP_CLUSTERS.length;

  const rows = useMemo(() => {
    let list = todas.slice();
    if (rolF === 'pagan')         list = list.filter((r) => r.prima > 0);
    if (rolF === 'asegurados')    list = list.filter((r) => r.roles.includes('ASEGURADO'));
    if (rolF === 'beneficiarios') list = list.filter((r) => r.roles.includes('BENEFICIARIO'));
    if (rolF === 'empresas')      list = list.filter((r) => r.persona.tipo === 'moral');
    if (kycF !== 'all')           list = list.filter((r) => r.kyc && r.kyc.estado === kycF);
    if (search) {
      const s = search.toLowerCase();
      list = list.filter((r) => ((r.persona.nombre || '') + ' ' + (r.persona.rfc || '') + ' ' + (r.persona.email || '')).toLowerCase().includes(s));
    }
    list.sort((a, b) => {
      if (sortKey === 'prima')   return b.prima - a.prima || (a.persona.nombre || '').localeCompare(b.persona.nombre || '');
      if (sortKey === 'nombre')  return (a.persona.nombre || '').localeCompare(b.persona.nombre || '');
      if (sortKey === 'polizas') return b.policyCount - a.policyCount;
      return 0;
    });
    return list;
  }, [todas, search, rolF, kycF, sortKey]);

  const counts = useMemo(() => ({
    todas: todas.length,
    pagan: todas.filter((r) => r.prima > 0).length,
    asegurados: todas.filter((r) => r.roles.includes('ASEGURADO')).length,
    beneficiarios: todas.filter((r) => r.roles.includes('BENEFICIARIO')).length,
  }), [todas]);

  return (
    <div style={{ flex: 1, overflow: 'auto', display: 'flex', flexDirection: 'column' }}>
      <AxPageHeader
        eyebrow="Cartera"
        title="Clientes"
        subtitle={`${counts.todas} personas en tu cartera — ${counts.pagan} pagan primas, el resto son asegurados y beneficiarios.`}
        actions={nDup > 0 ? (
          <AxButton variant="secondary" icon="copy" onClick={() => navigate('/clientes/duplicados')}>
            Revisar fichas repetidas ({nDup})
          </AxButton>
        ) : null}
      />

      {nDup > 0 ? (
        <div style={{ padding: '12px 32px 0' }}>
          <button onClick={() => navigate('/clientes/duplicados')} style={{
            appearance: 'none', width: '100%', textAlign: 'left', cursor: 'default', color: 'inherit',
            background: 'var(--ax-warm-soft)', border: '1px solid var(--ax-warm-line)',
            borderRadius: 8, padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 10,
          }}>
            <AxIcon name="copy" size={15} style={{ color: 'var(--ax-warm)' }}/>
            <span style={{ flex: 1, fontSize: 13, color: 'var(--ax-fg)' }}>
              Encontré <strong style={{ color: 'var(--ax-fg-strong)' }}>{AdmixPersonas.DUP_CLUSTERS.reduce((s, c) => s + c.personaIds.length, 0)} fichas</strong> que
              parecen ser <strong style={{ color: 'var(--ax-fg-strong)' }}>{nDup} personas</strong> repetidas. Únelas para ver su cartera completa.
            </span>
            <span style={{ fontSize: 12, color: 'var(--ax-warm)', display: 'inline-flex', alignItems: 'center', gap: 6 }}>
              Revisar <AxIcon name="arrow-right" size={12}/>
            </span>
          </button>
        </div>
      ) : null}

      <div style={{
        padding: '14px 32px', display: 'flex', gap: 10, alignItems: 'center', flexWrap: 'wrap',
        borderBottom: '1px solid var(--ax-border)', background: 'var(--ax-bg-1)',
      }}>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 8,
          background: 'var(--ax-bg-4)', border: '1px solid var(--ax-border)',
          padding: '0 10px', height: 32, borderRadius: 6, flex: '0 0 260px',
        }}>
          <AxIcon name="search" size={13} style={{ color: 'var(--ax-fg-faint)' }}/>
          <input value={search} onChange={(e) => setSearch(e.target.value)} placeholder="Nombre, RFC, correo…"
            style={{ flex: 1, background: 'transparent', border: 0, outline: 'none', color: 'var(--ax-fg)', fontSize: 13 }}/>
        </div>
        <AxChipRow value={rolF} onChange={setRolF} options={[
          { v: 'all',           label: 'Todos',         n: counts.todas },
          { v: 'pagan',         label: 'Pagan primas',  n: counts.pagan },
          { v: 'asegurados',    label: 'Asegurados',    n: counts.asegurados },
          { v: 'beneficiarios', label: 'Beneficiarios', n: counts.beneficiarios },
          { v: 'empresas',      label: 'Empresas' },
        ]}/>
        <div style={{ flex: 1 }}/>
        <FilterChip2 label="Identificación" value={kycF} onChange={setKycF} options={[
          { v: 'all',      label: 'Todas' },
          { v: 'ok',       label: 'Completa' },
          { v: 'atencion', label: 'En proceso' },
          { v: 'falta',    label: 'Faltan datos' },
        ]}/>
        <FilterChip2 label="Orden" value={sortKey} onChange={setSortKey} options={[
          { v: 'prima',   label: 'Prima (mayor)' },
          { v: 'nombre',  label: 'Nombre (A→Z)' },
          { v: 'polizas', label: 'Pólizas' },
        ]}/>
        <span style={{ fontSize: 11, color: 'var(--ax-fg-faint)', fontFamily: 'var(--font-mono)' }}>
          {rows.length} de {todas.length}
        </span>
      </div>

      <div style={{ flex: 1, overflow: 'auto' }}>
        <table className="ax-table">
          <thead>
            <tr>
              <th>Persona</th>
              <th style={{ width: 210 }}>Contacto</th>
              <th style={{ width: 190 }}>Pólizas</th>
              <th style={{ width: 170 }}>Identificación</th>
              <th style={{ width: 150, textAlign: 'right' }}>Prima anual a su cargo</th>
              <th style={{ width: 40 }}/>
            </tr>
          </thead>
          <tbody>
            {rows.map((r) => {
              const p = r.persona;
              const esMoral = p.tipo === 'moral';
              return (
                <tr key={p.id} onClick={() => navigate('/clientes/' + p.id)}>
                  <td>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                      <AxAvatar name={p.nombre} size={30}/>
                      <div style={{ minWidth: 0 }}>
                        <div style={{ fontSize: 13, color: 'var(--ax-fg-strong)', fontWeight: 500, display: 'flex', alignItems: 'center', gap: 8 }}>
                          <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.nombre}</span>
                          {esMoral ? <AxPill tone="neutral">Empresa</AxPill> : null}
                          {r.dup ? (
                            <span title="Esta ficha parece estar repetida" style={{ color: 'var(--ax-warm)', display: 'inline-flex' }}>
                              <AxIcon name="copy" size={12}/>
                            </span>
                          ) : null}
                        </div>
                        <div className="ax-mono" style={{ fontSize: 10, color: 'var(--ax-fg-faint)' }}>
                          {p.rfc || 'Sin RFC'}
                        </div>
                      </div>
                    </div>
                  </td>
                  <td>
                    {p.email || p.telefono ? (
                      <>
                        <div style={{ fontSize: 12, color: 'var(--ax-fg)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.email || '—'}</div>
                        <div className="ax-mono" style={{ fontSize: 11, color: 'var(--ax-fg-muted)' }}>{p.telefono || ''}</div>
                      </>
                    ) : (
                      <span style={{ fontSize: 12, color: 'var(--ax-fg-faint)' }}>Sin datos de contacto</span>
                    )}
                  </td>
                  <td>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                      <span className="ax-mono" style={{ fontSize: 13, color: 'var(--ax-fg-strong)' }}>{r.policyCount}</span>
                      <span style={{ display: 'flex', gap: 4, flexWrap: 'wrap' }}>
                        {r.roles.map((rol) => <AxRolPill key={rol} rol={rol}/>)}
                      </span>
                    </div>
                  </td>
                  <td><AxKycPill kyc={r.kyc}/></td>
                  <td style={{ textAlign: 'right' }}>
                    {r.prima > 0 ? (
                      <span className="ax-mono" style={{ fontSize: 13, color: 'var(--ax-fg-strong)' }}>{AdmixData.formatMoney(r.prima)}</span>
                    ) : (
                      <span style={{ fontSize: 13, color: 'var(--ax-fg-faint)' }}>—</span>
                    )}
                  </td>
                  <td><AxIcon name="chevron-right" size={13} style={{ color: 'var(--ax-fg-faint)' }}/></td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// DETALLE DE PERSONA
// ─────────────────────────────────────────────────────────────
function PersonaDetail({ id }) {
  const { navigate, query } = useHashRoute();
  const p = AdmixPersonas.personaById(id);
  const [tab, setTab] = useState('polizas');
  useEffect(() => { setTab('polizas'); }, [id]);

  if (!p) {
    return <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
      <AxEmpty icon="user" title="Persona no encontrada" action={<AxButton variant="secondary" onClick={() => navigate('/clientes')}>Volver</AxButton>}/>
    </div>;
  }

  const origen = AdmixPersonas.origenDe(query);
  const rels = AdmixPersonas.policiesOfPersona(id);
  const vigentes = rels.filter((r) => AdmixPersonas.esVigente(r.policy));
  const prima = AdmixPersonas.primaACargo(id);
  const kyc = AdmixPersonas.kycDe(id);
  const dup = AdmixPersonas.DUP_INDEX[id];
  const esMoral = p.tipo === 'moral';
  const anios = AdmixPersonas.edad(p.fechaNacimiento);
  const roles = AdmixPersonas.rolesDe(id);
  const renovacion = vigentes
    .filter((r) => r.policy.status === 'RENEWAL_PENDING')
    .sort((a, b) => a.policy.finVigencia.localeCompare(b.policy.finVigencia))[0] || null;

  const grupos = [
    { id: 'paga',    titulo: 'Paga y contrata',   rels: rels.filter((r) => r.obligadoPago) },
    { id: 'aseg',    titulo: esMoral ? 'Asegurada en' : 'Está asegurado(a) en', rels: rels.filter((r) => !r.obligadoPago && r.roles.includes('ASEGURADO')) },
    { id: 'benef',   titulo: 'Es beneficiario(a) de', rels: rels.filter((r) => !r.obligadoPago && !r.roles.includes('ASEGURADO') && r.roles.includes('BENEFICIARIO')) },
  ].filter((g) => g.rels.length > 0);

  return (
    <div style={{ flex: 1, overflow: 'auto' }}>
      <AxPageHeader
        breadcrumb={
          <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
            {origen ? (
              <button onClick={() => navigate(origen.path)} style={{
                appearance: 'none', cursor: 'default',
                background: 'var(--ax-bg-3)', border: '1px solid var(--ax-border-strong)',
                color: 'var(--ax-fg)', borderRadius: 14, height: 26, padding: '0 12px',
                fontSize: 12, display: 'inline-flex', alignItems: 'center', gap: 6,
              }}
                onMouseEnter={(e) => e.currentTarget.style.background = 'var(--ax-bg-4)'}
                onMouseLeave={(e) => e.currentTarget.style.background = 'var(--ax-bg-3)'}
              >
                <AxIcon name="arrow-left" size={12}/> Volver a {origen.label}
              </button>
            ) : null}
            <AxCrumb items={[{ label: 'Clientes', to: '/clientes' }, { label: p.nombre }]}/>
          </div>
        }
        eyebrow={(esMoral ? 'Persona moral' : 'Persona física') + (roles.length ? ' · ' + roles.map(AdmixPersonas.rolLabel).join(' · ') : '')}
        title={p.nombre}
        subtitle={
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 10 }}>
            <span className="ax-mono" style={{ color: 'var(--ax-fg-muted)' }}>{p.rfc || 'Sin RFC'}</span>
            {anios != null ? <span style={{ color: 'var(--ax-fg-muted)' }}>· {anios} años</span> : null}
            {esMoral && p.fechaConstitucion ? <span style={{ color: 'var(--ax-fg-muted)' }}>· constituida en {p.fechaConstitucion.slice(0, 4)}</span> : null}
          </span>
        }
        actions={
          <>
            <AxButton variant="secondary" icon="mail" disabled={!p.email}>Escribir</AxButton>
            <AxButton variant="secondary" icon="phone" disabled={!p.telefono}>Llamar</AxButton>
            <AxButton variant="secondary" icon="dots"/>
          </>
        }
      />

      <div style={{ padding: '20px 32px 48px', maxWidth: 1240 }}>
        {dup ? (
          <div style={{
            marginBottom: 16, background: 'var(--ax-warm-soft)', border: '1px solid var(--ax-warm-line)',
            borderRadius: 8, padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 10,
          }}>
            <AxIcon name="copy" size={15} style={{ color: 'var(--ax-warm)' }}/>
            <span style={{ flex: 1, fontSize: 13, color: 'var(--ax-fg)' }}>
              Esta ficha parece estar repetida con {dup.personaIds.length - 1} más ({dup.evidencia.toLowerCase()}).
              Su cartera podría verse incompleta hasta que las unas.
            </span>
            <AxButton size="sm" variant="secondary" onClick={() => navigate('/clientes/duplicados')}>Revisar y unir</AxButton>
          </div>
        ) : null}

        {/* Highlights: lo que el agente mira SIEMPRE, a golpe de vista */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12, marginBottom: 18 }}>
          <HighlightTile label="Pólizas vigentes" value={vigentes.length} sub={rels.length > vigentes.length ? (rels.length - vigentes.length) + ' históricas' : 'en tu libro'}/>
          <HighlightTile
            label="Prima anual a su cargo"
            value={prima > 0 ? AdmixData.formatMoney(prima) : '—'}
            mono={prima > 0}
            sub={prima > 0 ? 'sólo pólizas que paga' : ''}
          />
          <HighlightTile
            label="Identificación (Art. 492)"
            value={<AxKycPill kyc={kyc}/>}
            sub={kyc && kyc.copias ? 'copias ' + kyc.copias.done + ' de ' + kyc.copias.total : (kyc && kyc.minimos ? 'datos mínimos ✓' : 'faltan datos')}
            onClick={() => setTab('documentos')}
          />
          <HighlightTile
            label="Próxima renovación"
            value={renovacion ? <AxVigenciaHumana iso={renovacion.policy.finVigencia}/> : 'Sin renovaciones'}
            sub={renovacion ? renovacion.policy.producto : 'en los próximos 30 días'}
            onClick={renovacion ? () => navigate(AdmixPersonas.conOrigen('/polizas/' + renovacion.policy.id, '/clientes/' + p.id, primerNombre(p.nombre))) : undefined}
          />
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '330px 1fr', gap: 18, alignItems: 'start' }}>
          {/* Columna izquierda: los DATOS de la persona */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
            <div className="ax-card" style={{ padding: 20 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12, paddingBottom: 14, borderBottom: '1px solid var(--ax-border)', marginBottom: 14 }}>
                <AxAvatar name={p.nombre} size={44}/>
                <div style={{ minWidth: 0 }}>
                  <div style={{ fontSize: 14, color: 'var(--ax-fg-strong)', fontWeight: 600 }}>{p.nombre}</div>
                  <div style={{ fontSize: 11, color: 'var(--ax-fg-faint)' }}>
                    Ficha creada desde {p.origen === 'gnp' ? 'el portal GNP' : p.origen === 'manual' ? 'captura manual' : 'un PDF de póliza'}
                  </div>
                </div>
              </div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
                <DatoRow icon="mail"  label="Correo"   value={p.email}/>
                <DatoRow icon="phone" label="Teléfono" value={p.telefono}/>
                {esMoral ? (
                  <>
                    <DatoRow icon="cal"  label="Fecha de constitución" value={p.fechaConstitucion ? AdmixData.formatDateES(p.fechaConstitucion) : null}/>
                    <DatoRow icon="user" label="Representante legal"   value={p.repLegal}/>
                  </>
                ) : (
                  <>
                    <DatoRow icon="cal" label="Fecha de nacimiento" value={p.fechaNacimiento ? AdmixData.formatDateES(p.fechaNacimiento) + (anios != null ? ' · ' + anios + ' años' : '') : null}/>
                    <DatoRow icon="tag" label="CURP" value={p.curp} mono/>
                  </>
                )}
                <DatoRow icon="map" label="Domicilio" value={p.direccion ? (
                  <span>{p.direccion.calle}<br/>{p.direccion.colonia}, {p.direccion.ciudad}<br/>CP {p.direccion.cp}, {p.direccion.estado}</span>
                ) : null}/>
              </div>
              {(!p.email && !p.telefono) || !p.direccion || (!esMoral && !p.curp) ? (
                <div style={{ marginTop: 14, paddingTop: 12, borderTop: '1px solid var(--ax-border)', fontSize: 12, color: 'var(--ax-fg-muted)', display: 'flex', gap: 8, alignItems: 'flex-start' }}>
                  <span style={{ color: 'var(--ax-warm)', flexShrink: 0, marginTop: 1, display: 'inline-flex' }}><AxIcon name="info" size={13}/></span>
                  <span>Los datos que faltan aquí también cuentan para su identificación — ve al tab <button onClick={() => setTab('documentos')} style={{ appearance: 'none', border: 0, background: 'transparent', color: 'var(--ax-accent)', padding: 0, cursor: 'default', fontSize: 12 }}>Documentos</button>.</span>
                </div>
              ) : null}
            </div>

            <div className="ax-card" style={{ padding: 20 }}>
              <h3 style={{ margin: '0 0 10px', fontSize: 14, fontWeight: 500, color: 'var(--ax-fg-strong)' }}>Notas</h3>
              <textarea className="ax-textarea" placeholder="Nota privada: preferencias, hábitos de pago, próximas conversaciones…" style={{ minHeight: 80, resize: 'vertical' }}/>
            </div>
          </div>

          {/* Columna derecha: tabs Pólizas / Documentos */}
          <div className="ax-card" style={{ overflow: 'hidden' }}>
            <div style={{ display: 'flex', borderBottom: '1px solid var(--ax-border)', background: 'var(--ax-bg-1)' }}>
              <TabButton active={tab === 'polizas'} onClick={() => setTab('polizas')}>
                Pólizas <span className="ax-mono" style={{ fontSize: 10, color: 'var(--ax-fg-faint)' }}>{rels.length}</span>
              </TabButton>
              <TabButton active={tab === 'documentos'} onClick={() => setTab('documentos')} attention={kyc && kyc.estado !== 'ok'}>
                Documentos
              </TabButton>
            </div>
            <div style={{ padding: 20 }}>
              {tab === 'polizas'
                ? <PersonaPolizasTab persona={p} grupos={grupos}/>
                : <PersonaDocumentosTab persona={p} kyc={kyc}/>}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function primerNombre(nombre) { return (nombre || '').split(/\s+/)[0]; }

function HighlightTile({ label, value, sub, mono, onClick }) {
  const clickable = !!onClick;
  return (
    <button onClick={onClick} disabled={!clickable} style={{
      appearance: 'none', textAlign: 'left', color: 'inherit', cursor: 'default',
      background: 'var(--ax-bg-2)', border: '1px solid var(--ax-border)',
      borderRadius: 10, padding: '14px 16px', opacity: 1,
    }}
      onMouseEnter={(e) => { if (clickable) e.currentTarget.style.background = 'var(--ax-bg-3)'; }}
      onMouseLeave={(e) => { e.currentTarget.style.background = 'var(--ax-bg-2)'; }}
    >
      <AxEyebrow>{label}</AxEyebrow>
      <div className={mono ? 'ax-mono' : undefined} style={{ marginTop: 8, fontSize: mono ? 18 : 16, fontWeight: 600, color: 'var(--ax-fg-strong)', minHeight: 24, display: 'flex', alignItems: 'center' }}>
        {value}
      </div>
      <div style={{ fontSize: 11, color: 'var(--ax-fg-muted)', marginTop: 3 }}>{sub}</div>
    </button>
  );
}

function DatoRow({ icon, label, value, mono }) {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>
      <span style={{ color: 'var(--ax-fg-faint)', marginTop: 1 }}><AxIcon name={icon} size={14}/></span>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 10, color: 'var(--ax-fg-faint)', fontFamily: 'var(--font-mono)', textTransform: 'uppercase', letterSpacing: '0.12em' }}>{label}</div>
        <div className={mono ? 'ax-mono' : undefined} style={{ fontSize: 13, color: value ? 'var(--ax-fg-strong)' : 'var(--ax-fg-faint)', marginTop: 2, wordBreak: 'break-word' }}>
          {value || 'Sin registrar'}
        </div>
      </div>
    </div>
  );
}

function TabButton({ active, onClick, attention, children }) {
  return (
    <button onClick={onClick} style={{
      appearance: 'none', border: 0, cursor: 'default',
      background: 'transparent',
      color: active ? 'var(--ax-fg-strong)' : 'var(--ax-fg-muted)',
      padding: '12px 18px', fontSize: 13, fontWeight: active ? 600 : 400,
      display: 'inline-flex', alignItems: 'center', gap: 8,
      borderBottom: '2px solid ' + (active ? 'var(--ax-accent)' : 'transparent'),
      marginBottom: -1, position: 'relative',
    }}>
      {children}
      {attention && !active ? <span style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--ax-warm)' }}/> : null}
    </button>
  );
}

// ─── Tab: PÓLIZAS por relación ───────────────────────────────
function PersonaPolizasTab({ persona, grupos }) {
  const { navigate } = useHashRoute();
  if (grupos.length === 0) {
    return <AxEmpty icon="book" title="Sin pólizas ligadas" body="Cuando importes una póliza que la mencione, aparecerá aquí."/>;
  }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
      {grupos.map((g) => (
        <div key={g.id}>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginBottom: 8 }}>
            <h4 style={{ margin: 0, fontSize: 13, fontWeight: 600, color: 'var(--ax-fg-strong)' }}>{g.titulo}</h4>
            <span className="ax-mono" style={{ fontSize: 11, color: 'var(--ax-fg-faint)' }}>{g.rels.length}</span>
            {g.id === 'benef' ? (
              <span style={{ fontSize: 11, color: 'var(--ax-fg-faint)' }}>— no paga la prima de estas pólizas</span>
            ) : null}
          </div>
          <div style={{ border: '1px solid var(--ax-border)', borderRadius: 8, overflow: 'hidden' }}>
            {g.rels.map((r, i) => {
              const pol = r.policy;
              const c = AdmixData.carrierById(pol.carrier);
              return (
                <button key={pol.id}
                  onClick={() => navigate(AdmixPersonas.conOrigen('/polizas/' + pol.id, '/clientes/' + persona.id, primerNombre(persona.nombre)))}
                  style={{
                    appearance: 'none', background: 'transparent', border: 0, color: 'inherit',
                    width: '100%', textAlign: 'left', cursor: 'default',
                    padding: '12px 14px', borderTop: i > 0 ? '1px solid var(--ax-border)' : 'none',
                    display: 'grid', gridTemplateColumns: '24px 1.5fr 90px 130px auto', gap: 12, alignItems: 'center',
                  }}
                  onMouseEnter={(e) => e.currentTarget.style.background = 'var(--ax-bg-3)'}
                  onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
                >
                  <AxCarrierAvatar id={pol.carrier} size={22}/>
                  <div style={{ minWidth: 0 }}>
                    <div style={{ fontSize: 13, color: 'var(--ax-fg-strong)' }}>
                      {pol.producto}
                      {r.porcentaje != null ? <span style={{ color: 'var(--ax-info)', fontSize: 12 }}> · {r.porcentaje} %</span> : null}
                      {r.parentesco ? <span style={{ color: 'var(--ax-fg-muted)', fontSize: 12 }}> · {r.parentesco}</span> : null}
                    </div>
                    <div className="ax-mono" style={{ fontSize: 10, color: 'var(--ax-fg-faint)' }}>
                      {c ? c.name : ''} · {pol.polizaNumero}
                    </div>
                  </div>
                  <AxRamoTag code={pol.ramo}/>
                  <AxVigenciaHumana iso={pol.finVigencia}/>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 10, justifyContent: 'flex-end' }}>
                    {g.id === 'paga'
                      ? <span className="ax-mono" style={{ fontSize: 12, color: 'var(--ax-fg-strong)' }}>{AdmixData.formatMoney(pol.primaTotal)}</span>
                      : null}
                    <AxStatusPill code={pol.status}/>
                  </div>
                </button>
              );
            })}
          </div>
        </div>
      ))}
    </div>
  );
}

// ─── Tab: DOCUMENTOS (Art. 492) ──────────────────────────────
function PersonaDocumentosTab({ persona, kyc }) {
  const { pushToast } = useAxStore();
  const [reglas, setReglas] = useState(false);
  if (!kyc) return null;
  const perfil = kyc.perfil;
  const esMoral = persona.tipo === 'moral';

  const porQue = perfil.requiereCopias
    ? (esMoral
        ? 'Por ser la empresa contratante obligada a pagar la prima, la ley (Art. 492) pide identificarla con el expediente completo de persona moral.'
        : perfil.esObligado
          ? 'Por ser quien contrata y paga la prima, la ley (Art. 492) pide su expediente de identificación completo.'
          : 'Por ser asegurado(a) titular distinto de quien contrata, la ley pide identificar a ambos.')
    : 'Como beneficiario(a), por ahora la ley sólo pide sus datos mínimos. Las copias de documentos se piden hasta el momento de un pago.';

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
      <div style={{ fontSize: 13, color: 'var(--ax-fg-muted)', lineHeight: 1.5, display: 'flex', gap: 10 }}>
        <span style={{ color: 'var(--ax-fg-faint)', flexShrink: 0, marginTop: 2, display: 'inline-flex' }}><AxIcon name="shield" size={15}/></span>
        <span>{porQue}</span>
      </div>

      {/* Peldaños de identificación: mínimos → completos → copias */}
      <div style={{ display: 'grid', gridTemplateColumns: perfil.requiereCopias ? 'repeat(3, 1fr)' : 'repeat(2, 1fr)', gap: 10 }}>
        <Peldano n={1} titulo="Datos mínimos" done={kyc.minimos}
          detalle={kyc.minimos ? 'Capturados' : 'Falta: ' + kyc.faltanMin.join(', ')}/>
        <Peldano n={2} titulo="Datos completos" done={kyc.completos} locked={!kyc.minimos}
          detalle={kyc.completos ? 'Capturados' : (kyc.faltanComp.length ? 'Falta: ' + kyc.faltanComp.join(', ') : 'Pendiente')}/>
        {perfil.requiereCopias ? (
          <Peldano n={3} titulo="Copias de documentos" done={kyc.copias && kyc.copias.completo} locked={!kyc.minimos}
            detalle={kyc.copias ? (kyc.copias.completo ? 'Expediente completo' : kyc.copias.done + ' de ' + kyc.copias.total + ' en regla') : '—'}/>
        ) : null}
      </div>

      {/* Datos mínimos / completos con palomas por dato */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
        <DatosCheckCard titulo="Datos mínimos" items={esMoral ? [
          ['Razón social', !!persona.nombre],
          ['Fecha de constitución', !!persona.fechaConstitucion],
          ['Domicilio completo', !!persona.direccion],
        ] : [
          ['Nombre completo', !!persona.nombre],
          ['Fecha de nacimiento', !!persona.fechaNacimiento],
          ['CURP', !!persona.curp],
          ['Domicilio completo', !!persona.direccion],
        ]}/>
        <DatosCheckCard titulo="Datos completos" items={[
          ['RFC', !!persona.rfc],
          ['Correo o teléfono', !!(persona.email || persona.telefono)],
        ]}/>
      </div>

      {/* Checklist de copias de documentos */}
      {perfil.requiereCopias ? (
        <div>
          <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 8 }}>
            <h4 style={{ margin: 0, fontSize: 13, fontWeight: 600, color: 'var(--ax-fg-strong)' }}>
              Copias de documentos
              {esMoral ? <span style={{ fontWeight: 400, color: 'var(--ax-fg-muted)' }}> · persona moral mexicana</span>
                       : <span style={{ fontWeight: 400, color: 'var(--ax-fg-muted)' }}> · persona física mexicana</span>}
            </h4>
            <button onClick={() => setReglas(!reglas)} style={{ appearance: 'none', border: 0, background: 'transparent', color: 'var(--ax-fg-muted)', fontSize: 12, cursor: 'default', display: 'inline-flex', alignItems: 'center', gap: 5 }}>
              <AxIcon name="help" size={12}/> ¿Qué debe cumplir un documento?
            </button>
          </div>
          {reglas ? (
            <div style={{
              marginBottom: 10, fontSize: 12, color: 'var(--ax-fg-muted)', lineHeight: 1.6,
              background: 'var(--ax-bg-1)', border: '1px solid var(--ax-border)', borderRadius: 8, padding: '10px 14px',
            }}>
              Legible y vigente, con rasgos y firmas claros · comprobantes de domicilio y estados de cuenta con
              <strong style={{ color: 'var(--ax-fg)' }}> máximo 3 meses</strong> · al cotejar contra el original se escribe
              <em> “Cotejado con el original que se tuvo a la vista”</em> con fecha, nombre y firma ·
              los documentos con sello o QR de portales oficiales cuentan como originales (no requieren cotejo).
            </div>
          ) : null}
          <div style={{ border: '1px solid var(--ax-border)', borderRadius: 8, overflow: 'hidden' }}>
            {kyc.docs.map((d, i) => {
              const sem = AdmixPersonas.semaforoDoc(d);
              const color = sem.code === 'ok' ? 'var(--ax-accent)' : sem.code === 'atencion' ? 'var(--ax-warm)' : 'var(--ax-danger)';
              const iconName = sem.code === 'ok' ? 'check' : sem.code === 'atencion' ? 'alert' : 'x';
              return (
                <div key={d.def.id} style={{
                  padding: '12px 14px', borderTop: i > 0 ? '1px solid var(--ax-border)' : 'none',
                  display: 'flex', alignItems: 'center', gap: 12,
                }}>
                  <span style={{
                    width: 24, height: 24, borderRadius: 5, flexShrink: 0,
                    background: color + '22', border: '1px solid ' + color + '44', color,
                    display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                  }}><AxIcon name={iconName} size={13}/></span>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 13, color: 'var(--ax-fg-strong)' }}>
                      {d.def.nombre}
                      {d.def.condicional ? <span style={{ fontSize: 11, color: 'var(--ax-fg-faint)' }}> · si aplica</span> : null}
                    </div>
                    <div style={{ fontSize: 11, color: 'var(--ax-fg-muted)' }}>
                      {d.estado === 'cotejado' && d.cotejo
                        ? '“Cotejado con el original” · ' + AdmixData.formatDateES(d.cotejo.fecha) + ' · ' + d.cotejo.por
                        : d.estado === 'cargado'
                          ? 'Subido el ' + AdmixData.formatDateES(d.fechaCarga) + ' · falta cotejar contra el original'
                          : d.def.detalle}
                    </div>
                  </div>
                  <span style={{ fontSize: 11, color, whiteSpace: 'nowrap' }}>{sem.label}</span>
                  {d.estado === 'falta' ? (
                    <AxButton size="sm" variant="secondary" icon="upload"
                      onClick={() => pushToast({ kind: 'info', message: 'Aquí subirías o tomarías foto del documento (maqueta).' })}>Subir</AxButton>
                  ) : d.estado === 'cargado' ? (
                    <AxButton size="sm" variant="secondary" icon="check"
                      onClick={() => pushToast({ kind: 'success', message: 'Marcado como cotejado con el original (maqueta).' })}>Cotejar</AxButton>
                  ) : (
                    <AxButton size="sm" variant="tertiary" icon="eye"
                      onClick={() => pushToast({ kind: 'info', message: 'Aquí verías el documento (maqueta).' })}/>
                  )}
                </div>
              );
            })}
          </div>
        </div>
      ) : (
        <div style={{
          border: '1px dashed var(--ax-border-strong)', borderRadius: 8, padding: '14px 16px',
          fontSize: 12.5, color: 'var(--ax-fg-muted)', display: 'flex', gap: 10, alignItems: 'flex-start',
        }}>
          <span style={{ flexShrink: 0, marginTop: 1, display: 'inline-flex' }}><AxIcon name="info" size={14}/></span>
          <span>
            Cuando haya un pago de siniestro o esta persona pase a contratar una póliza, Piixi te pedirá aquí
            las copias de sus documentos (identificación oficial, comprobante de domicilio, constancia CURP y declaración firmada).
          </span>
        </div>
      )}
    </div>
  );
}

function Peldano({ n, titulo, detalle, done, locked }) {
  const color = done ? 'var(--ax-accent)' : locked ? 'var(--ax-fg-faint)' : 'var(--ax-warm)';
  return (
    <div style={{
      border: '1px solid ' + (done ? 'var(--ax-accent-line)' : 'var(--ax-border)'),
      background: done ? 'var(--ax-accent-soft)' : 'var(--ax-bg-1)',
      borderRadius: 8, padding: '10px 12px', display: 'flex', gap: 10, alignItems: 'flex-start',
    }}>
      <span style={{
        width: 20, height: 20, borderRadius: '50%', flexShrink: 0, marginTop: 1,
        border: '1px solid ' + color, color,
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        fontSize: 10, fontFamily: 'var(--font-mono)',
      }}>{done ? <AxIcon name="check" size={11}/> : n}</span>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontSize: 12, fontWeight: 600, color: done ? 'var(--ax-accent)' : 'var(--ax-fg-strong)' }}>{titulo}</div>
        <div style={{ fontSize: 11, color: 'var(--ax-fg-muted)', marginTop: 2, lineHeight: 1.4 }}>{detalle}</div>
      </div>
    </div>
  );
}

function DatosCheckCard({ titulo, items }) {
  return (
    <div style={{ border: '1px solid var(--ax-border)', borderRadius: 8, padding: '12px 14px' }}>
      <div className="ax-eyebrow" style={{ marginBottom: 8 }}>{titulo}</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        {items.map(([label, ok]) => (
          <div key={label} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 12.5 }}>
            <span style={{ color: ok ? 'var(--ax-accent)' : 'var(--ax-warm)', display: 'inline-flex' }}>
              <AxIcon name={ok ? 'check' : 'x'} size={12}/>
            </span>
            <span style={{ color: ok ? 'var(--ax-fg)' : 'var(--ax-fg-muted)' }}>{label}</span>
            {!ok ? <span style={{ fontSize: 10, color: 'var(--ax-warm)', marginLeft: 'auto' }}>falta</span> : null}
          </div>
        ))}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// CONSOLIDADOR de fichas duplicadas
// ─────────────────────────────────────────────────────────────
function ConsolidadorScreen() {
  const { navigate } = useHashRoute();
  const { pushToast } = useAxStore();
  const [resueltos, setResueltos] = useState({}); // clusterId → 'unido' | 'descartado'
  const [wizardCluster, setWizardCluster] = useState(null);

  const pendientes = AdmixPersonas.DUP_CLUSTERS.filter((c) => !resueltos[c.id]);

  return (
    <div style={{ flex: 1, overflow: 'auto' }}>
      <AxPageHeader
        breadcrumb={<AxCrumb items={[{ label: 'Clientes', to: '/clientes' }, { label: 'Fichas repetidas' }]}/>}
        eyebrow="Cartera"
        title="Fichas repetidas"
        subtitle="Cuando importas desde PDFs y desde el portal, la misma persona puede quedar con varias fichas. Aquí las unes para ver su cartera completa."
      />
      <div style={{ padding: '24px 32px 48px', maxWidth: 980, display: 'flex', flexDirection: 'column', gap: 16 }}>
        {pendientes.length === 0 ? (
          <AxEmpty icon="check" title="No hay fichas repetidas por revisar"
            body="Cada persona de tu cartera tiene una sola ficha."
            action={<AxButton variant="secondary" onClick={() => navigate('/clientes')}>Volver a clientes</AxButton>}/>
        ) : pendientes.map((cl) => {
          const fichas = cl.personaIds.map((pid) => ({
            persona: AdmixPersonas.personaById(pid),
            rels: AdmixPersonas.policiesOfPersona(pid),
          }));
          return (
            <div key={cl.id} className="ax-card" style={{ padding: 20 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14 }}>
                <AxIcon name="copy" size={15} style={{ color: 'var(--ax-warm)' }}/>
                <span style={{ fontSize: 14, color: 'var(--ax-fg-strong)', fontWeight: 500, flex: 1 }}>
                  Estas {fichas.length} fichas parecen ser la misma persona
                </span>
                <AxPill tone="warm">{cl.evidencia}</AxPill>
              </div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(' + fichas.length + ', 1fr)', gap: 10, marginBottom: 14 }}>
                {fichas.map(({ persona, rels }) => (
                  <div key={persona.id} style={{
                    border: '1px solid ' + (persona.id === cl.sugeridaId ? 'var(--ax-accent-line)' : 'var(--ax-border)'),
                    background: persona.id === cl.sugeridaId ? 'var(--ax-accent-soft)' : 'var(--ax-bg-1)',
                    borderRadius: 8, padding: '12px 14px',
                  }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
                      <AxAvatar name={persona.nombre} size={24}/>
                      <span style={{ fontSize: 13, color: 'var(--ax-fg-strong)', fontWeight: 500, flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{persona.nombre}</span>
                    </div>
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 3, fontSize: 11, color: 'var(--ax-fg-muted)' }}>
                      <span>Fuente: {persona.origen === 'gnp' ? 'portal GNP' : 'PDF de póliza'}</span>
                      <span className="ax-mono">{persona.rfc || 'sin RFC'}</span>
                      <span>{persona.fechaNacimiento ? 'Nac. ' + AdmixData.formatDateES(persona.fechaNacimiento) : 'sin fecha de nacimiento'}</span>
                      <span>{rels.length} {rels.length === 1 ? 'póliza ligada' : 'pólizas ligadas'}</span>
                    </div>
                    {persona.id === cl.sugeridaId ? (
                      <div style={{ marginTop: 8 }}><AxPill tone="accent" dot>ficha más completa</AxPill></div>
                    ) : null}
                  </div>
                ))}
              </div>
              <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
                <AxButton variant="tertiary" onClick={() => {
                  setResueltos((r) => ({ ...r, [cl.id]: 'descartado' }));
                  pushToast({ kind: 'info', message: 'Anotado: no son la misma persona. No volveré a sugerirlo.' });
                }}>No son la misma persona</AxButton>
                <AxButton variant="primary" onClick={() => setWizardCluster(cl)}>Unir estas fichas</AxButton>
              </div>
            </div>
          );
        })}
      </div>

      <MergeWizard
        cluster={wizardCluster}
        onClose={() => setWizardCluster(null)}
        onDone={(cl, principal) => {
          setResueltos((r) => ({ ...r, [cl.id]: 'unido' }));
          setWizardCluster(null);
          pushToast({
            kind: 'success', title: 'Fichas unidas',
            message: 'La cartera completa quedó en la ficha de ' + principal.nombre + '.',
          });
        }}
      />
    </div>
  );
}

// Wizard de 3 pasos (patrón HubSpot/Salesforce): elegir principal → resolver
// SÓLO los campos que difieren → confirmar con resumen de re-ligado.
function MergeWizard({ cluster, onClose, onDone }) {
  const [paso, setPaso] = useState(1);
  const [principalId, setPrincipalId] = useState(null);
  const [eleccion, setEleccion] = useState({});
  useEffect(() => {
    if (cluster) { setPaso(1); setPrincipalId(cluster.sugeridaId); setEleccion({}); }
  }, [cluster]);
  if (!cluster) return null;

  const fichas = cluster.personaIds.map((pid) => AdmixPersonas.personaById(pid));
  const principal = AdmixPersonas.personaById(principalId);
  const totalPolizas = cluster.personaIds.reduce((s, pid) => s + AdmixPersonas.policiesOfPersona(pid).length, 0);

  // Campos comparables; sólo pedimos decisión donde los valores difieren.
  const CAMPOS = [
    ['nombre', 'Nombre'], ['rfc', 'RFC'], ['fechaNacimiento', 'Fecha de nacimiento'],
    ['telefono', 'Teléfono'], ['email', 'Correo'],
  ];
  const difieren = CAMPOS.filter(([k]) => {
    const vals = new Set(fichas.map((f) => f[k]).filter((v) => v != null));
    return vals.size > 1;
  });
  const valorFinal = (k) => {
    if (eleccion[k] != null) return eleccion[k];
    if (principal && principal[k] != null) return principal[k];
    const alt = fichas.find((f) => f[k] != null);
    return alt ? alt[k] : null;
  };

  return (
    <AxModal open={!!cluster} onClose={onClose} width={620}
      title={'Unir fichas · paso ' + paso + ' de 3'}
      footer={
        <>
          <AxButton variant="secondary" onClick={paso === 1 ? onClose : () => setPaso(paso - 1)}>
            {paso === 1 ? 'Cancelar' : 'Atrás'}
          </AxButton>
          {paso < 3 ? (
            <AxButton variant="primary" onClick={() => setPaso(paso + 1)}>Siguiente</AxButton>
          ) : (
            <AxButton variant="primary" icon="check" onClick={() => onDone(cluster, principal)}>Unir fichas</AxButton>
          )}
        </>
      }
    >
      {paso === 1 ? (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          <div style={{ fontSize: 13, color: 'var(--ax-fg-muted)' }}>
            Elige la ficha que se queda. Las demás se unen a ella y desaparecen de la lista.
          </div>
          {fichas.map((f) => {
            const activa = f.id === principalId;
            return (
              <button key={f.id} onClick={() => setPrincipalId(f.id)} style={{
                appearance: 'none', textAlign: 'left', cursor: 'default', color: 'inherit',
                background: activa ? 'var(--ax-accent-soft)' : 'var(--ax-bg-1)',
                border: '1px solid ' + (activa ? 'var(--ax-accent-line)' : 'var(--ax-border)'),
                borderRadius: 8, padding: '12px 14px', display: 'flex', alignItems: 'center', gap: 12,
              }}>
                <span style={{
                  width: 16, height: 16, borderRadius: '50%', flexShrink: 0,
                  border: '2px solid ' + (activa ? 'var(--ax-accent)' : 'var(--ax-border-strong)'),
                  background: activa ? 'var(--ax-accent)' : 'transparent',
                  boxShadow: activa ? 'inset 0 0 0 3px var(--ax-bg-2)' : 'none',
                }}/>
                <AxAvatar name={f.nombre} size={26}/>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13, color: 'var(--ax-fg-strong)' }}>{f.nombre}</div>
                  <div style={{ fontSize: 11, color: 'var(--ax-fg-muted)' }}>
                    {f.origen === 'gnp' ? 'portal GNP' : 'PDF'} · {f.rfc || 'sin RFC'} · {AdmixPersonas.policiesOfPersona(f.id).length} pólizas
                  </div>
                </div>
                {f.id === cluster.sugeridaId ? <AxPill tone="accent">sugerida</AxPill> : null}
              </button>
            );
          })}
        </div>
      ) : null}

      {paso === 2 ? (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <div style={{ fontSize: 13, color: 'var(--ax-fg-muted)' }}>
            {difieren.length === 0
              ? 'Los datos no chocan entre sí: no hay nada que decidir.'
              : 'Sólo decide en los campos donde las fichas difieren. Lo demás se toma solo.'}
          </div>
          {difieren.map(([k, label]) => (
            <div key={k} style={{ border: '1px solid var(--ax-border)', borderRadius: 8, padding: '10px 12px' }}>
              <div className="ax-eyebrow" style={{ marginBottom: 8 }}>{label}</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                {Array.from(new Set(fichas.map((f) => f[k]).filter((v) => v != null))).map((v) => {
                  const sel = valorFinal(k) === v;
                  return (
                    <button key={String(v)} onClick={() => setEleccion((e) => ({ ...e, [k]: v }))} style={{
                      appearance: 'none', textAlign: 'left', cursor: 'default',
                      background: sel ? 'var(--ax-accent-soft)' : 'transparent',
                      border: '1px solid ' + (sel ? 'var(--ax-accent-line)' : 'var(--ax-border)'),
                      borderRadius: 6, padding: '7px 10px', color: 'var(--ax-fg)', fontSize: 13,
                      display: 'flex', alignItems: 'center', gap: 8,
                    }}>
                      <span style={{
                        width: 12, height: 12, borderRadius: '50%', flexShrink: 0,
                        border: '2px solid ' + (sel ? 'var(--ax-accent)' : 'var(--ax-border-strong)'),
                        background: sel ? 'var(--ax-accent)' : 'transparent',
                      }}/>
                      <span className={k === 'rfc' || k === 'fechaNacimiento' ? 'ax-mono' : undefined}>{k === 'fechaNacimiento' ? AdmixData.formatDateES(v) : String(v)}</span>
                    </button>
                  );
                })}
              </div>
            </div>
          ))}
        </div>
      ) : null}

      {paso === 3 ? (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div style={{
            background: 'var(--ax-bg-1)', border: '1px solid var(--ax-border)', borderRadius: 8, padding: '14px 16px',
            display: 'flex', gap: 12, alignItems: 'center',
          }}>
            <AxAvatar name={valorFinal('nombre')} size={36}/>
            <div>
              <div style={{ fontSize: 14, color: 'var(--ax-fg-strong)', fontWeight: 600 }}>{valorFinal('nombre')}</div>
              <div className="ax-mono" style={{ fontSize: 11, color: 'var(--ax-fg-muted)' }}>{valorFinal('rfc') || 'sin RFC'}</div>
            </div>
          </div>
          <div style={{ fontSize: 13, color: 'var(--ax-fg)', lineHeight: 1.6 }}>
            Se unirán <strong>{fichas.length} fichas en una</strong>. Las <strong>{totalPolizas} pólizas</strong> y
            sus roles (contratante, asegurado, beneficiario) quedarán ligados a esta ficha. Su expediente de
            identificación también se junta.
          </div>
          <div style={{
            display: 'flex', gap: 10, alignItems: 'flex-start',
            background: 'var(--ax-warm-soft)', border: '1px solid var(--ax-warm-line)',
            borderRadius: 8, padding: '10px 12px', fontSize: 12.5, color: 'var(--ax-fg)',
          }}>
            <span style={{ color: 'var(--ax-warm)', flexShrink: 0, marginTop: 1, display: 'inline-flex' }}><AxIcon name="alert" size={14}/></span>
            <span>Esta acción no se puede deshacer. Si dudas, elige “No son la misma persona” y revísalo después.</span>
          </div>
        </div>
      ) : null}
    </AxModal>
  );
}

Object.assign(window, {
  ClientsScreen,
  AxVigenciaHumana, AxRolPill, AxKycPill, AxChipRow,
});
