// ─── Selector de parte (paciente/médico/entidad/proveedor) ──────────
// PartySelectorModal: primitivo transversal para "elegir un registro del
// directorio existente" — lo usan Expedientes (alta/detalle, paciente/médico/
// entidad, SIN creación embebida — ver P25 abajo), Compras/Logística/
// Inventario (proveedor, CON creación embebida) y Finanzas (Nota/Factura/
// Recibo/Pago/FacturaRecibida: proveedor con creación; Factura/Recibo
// standalone: entidad con creación). Extraído de screens-nuevo.jsx en P4
// (vivía ahí pese a ser transversal a 5 módulos). Expone a window:
// PartySelectorModal, EmptyPartySlot, FilledPartySlot, PARTY_META,
// MODAL_FIELDS. Consume window.PARTICULARES/MEDICOS/ENTIDADES/PROVEEDORES,
// window.AltaSelect (ui/primitives.jsx, promovida en P6 — antes vivía en
// screens-nuevo.jsx, dependencia ui→screens invertida), formatCuit
// (dominio/formato.js).
// P4: se borró PartySelectorModal.handleDeleteNuevo (muerto+roto — llamaba
// setDelTarget, estado que el componente nunca declaraba, y 0 callers).
// P18 (recorrido §2): "Agregar X" → "Cargar X" en paciente/médico/entidad
// (proveedor no cambia). EmptyPartySlot suma el prop opcional `onCrear`
// (botón "Crear X" debajo del CTA de elegir, ver su header) — lo consume
// screens/expedientes/alta.jsx Y detalle.jsx (P25, ver abajo; el disparo real
// vive en ui/record-form.jsx, RecordFormModal, motor record-form reusado).
// P25 (Fran, 03/07 — "Cargar X" seguía ofreciendo crear con los requeridos
// VIEJOS, ej. DNI/matrícula obligatorios): el modal ahora acepta `allowCrear`
// (default true, preserva TODO caller existente) — Expedientes (alta.jsx Y
// detalle.jsx) lo pasa en `false`: "Cargar X" ahí queda 100% buscar/elegir,
// cero creación embebida (la creación real es el botón "Crear X" aparte, que
// ya reusaba RECORD_FORMS con los requeridos correctos desde P18 — detalle.jsx
// no lo tenía todavía, P25 se lo suma para no dejar el flujo de edición SIN
// ninguna vía de crear una parte nueva). `MODAL_FIELDS.paciente`/`.medico` se
// podan enteras (0 callers reales fuera de este form embebido — confirmado
// `grep type="paciente"|type="medico"` en todo public/erp: solo Expedientes,
// que ahora no los usa más). `editInitial` (la variante "editar un `__nuevo`
// recién creado" del modo `create`) también se poda: su ÚNICO caller era
// Expedientes (`partes.editInit`, partes-editor.js) y con `allowCrear=false`
// ya no tiene sentido — un registro creado por RecordFormModal ya es un dato
// real y persistido del directorio (se edita desde su propia pantalla, regla
// §8). `MODAL_FIELDS.entidad`/`.proveedor` SIGUEN (Finanzas standalone y
// Compras/Logística/Inventario los siguen consumiendo con `allowCrear` en su
// default `true` — sin cambios ahí).

const { useState: _usePSState, useRef: _usePSRef, useEffect: _usePSEffect } = React;

// P18 (recorrido §2): "Agregar X" → "Cargar X" (elegir existente) en las 3
// partes del expediente — proveedor NO cambia (Compras/Logística/Inventario,
// fuera del alcance del recorrido). `crearCta` (nuevo) alimenta el botón
// chico "Crear X" de EmptyPartySlot, debajo del CTA de elegir — solo en las
// 3 partes de expediente (proveedor no lo usa hoy).
const PARTY_META = {
  paciente:  { icon: IconUser,         eyebrow: 'Paciente',            cta: 'Cargar paciente', crearCta: 'Crear paciente' },
  medico:    { icon: IconStethoscope,  eyebrow: 'Médico',              cta: 'Cargar médico',   crearCta: 'Crear médico' },
  entidad:   { icon: IconBuilding,     eyebrow: 'Entidad / Cobertura', cta: 'Cargar entidad',  crearCta: 'Crear entidad' },
  proveedor: { icon: IconTruck,        eyebrow: 'Proveedor',           cta: 'Agregar proveedor' },
};

// Campos de cada alta del modal — fuente única, calcada de «Altas (mockup).html».
// (span: fila completa · req: obligatorio · mono · type: select/date)
// P25: `.paciente`/`.medico` se podaron (0 callers reales — la creación de esas
// 2 partes va SOLO por RecordFormModal/RECORD_FORMS, ui/record-form.jsx, con
// los requeridos correctos). `.entidad`/`.proveedor` siguen: Finanzas
// standalone (factura.jsx/recibo.jsx) y Compras/Logística/Inventario/Finanzas
// (nota/pago/factura-recibida) los siguen consumiendo vía `allowCrear` default.
const MODAL_FIELDS = {
  entidad: [
    { k: 'razonSocial', label: 'Razón social', req: true, span: true, ph: 'Ej: Galeno Plata' },
    { k: 'tipo', label: 'Tipo', type: 'select', opts: ['Obra social', 'Prepaga', 'Sanatorio', 'Clínica', 'Hospital', 'Mutual'] },
    { k: 'cuit', label: 'CUIT', req: true, mono: true, ph: '30-00000000-0' },
    { k: 'condicionIva', label: 'Condición IVA', req: true, type: 'select', opts: ['Responsable Inscripto', 'Exento', 'Monotributo'] },
    { k: 'condicionVenta', label: 'Condición de venta', type: 'select', opts: ['Contado', 'CC 30 días', 'CC 45 días', 'CC 60 días', 'CC 90 días'] },
    { k: 'convenio', label: 'Convenio / Plan', ph: 'Ej: Convenio Pro-Salud 2025' },
    { k: 'domicilio', label: 'Domicilio', span: true, ph: 'Calle y número' },
    { k: 'localidad', label: 'Localidad', ph: 'Ej: CABA' },
    { k: 'provincia', label: 'Provincia', ph: 'Ej: Buenos Aires' },
    { k: 'telefono', label: 'Teléfono', mono: true, ph: '+54 …' },
    { k: 'email', label: 'Email', ph: 'facturacion@…' },
  ],
  proveedor: [
    { k: 'razonSocial', label: 'Razón social', req: true, span: true, ph: 'Ej: Stryker Argentina S.A.' },
    { k: 'cuit', label: 'CUIT', req: true, mono: true, ph: '30-00000000-0' },
    { k: 'condicionIva', label: 'Condición IVA', req: true, type: 'select', opts: ['Responsable Inscripto', 'Exento', 'Monotributo'] },
    { k: 'condicionVenta', label: 'Condición de venta', type: 'select', opts: ['Contado', 'CC 30 días', 'CC 45 días', 'CC 60 días'] },
    { k: 'rubro', label: 'Rubro', type: 'select', opts: ['Implantes', 'Tornillería', 'Instrumental', 'Insumos', 'Ortopedia', 'Otros'] },
    { k: 'domicilio', label: 'Domicilio', span: true, ph: 'Calle y número' },
    { k: 'localidad', label: 'Localidad', ph: 'Ej: CABA' },
    { k: 'provincia', label: 'Provincia', ph: 'Ej: Buenos Aires' },
    { k: 'telefono', label: 'Teléfono', mono: true, ph: '+54 …' },
    { k: 'email', label: 'Email', ph: 'pedidos@…' },
  ],
};

// ─── Campo de formulario (módulo: no remonta en cada tecla) — solo del modal ──
function NuevoField({ label, children, error, required }) {
  return (
    <div>
      <label className="block text-[11px] font-bold uppercase tracking-[0.12em] mb-1.5" style={{ color: 'var(--muted-foreground)' }}>
        {label}{required && <span style={{ color: 'var(--accent)' }}>*</span>}
      </label>
      {children}
      {error && <p className="text-[11px] font-semibold mt-1" style={{ color: 'var(--danger)' }}>{error}</p>}
    </div>
  );
}

// Un campo del formulario del modal (label + control), calcado del mockup.
function ModalField({ f, value, onChange, error }) {
  let control;
  if (f.type === 'select') {
    control = (
      <AltaSelect value={value || ''} onChange={(e) => onChange(f.k, e.target.value)}>
        <option value="">Seleccionar…</option>
        {f.opts.map((o) => <option key={o} value={o}>{o}</option>)}
      </AltaSelect>
    );
  } else {
    control = (
      <input className={`input${f.mono ? ' font-mono tabular-nums' : ''}`} type={f.type === 'date' ? 'date' : 'text'}
        placeholder={f.ph || ''} value={value || ''} onChange={(e) => onChange(f.k, e.target.value)} />
    );
  }
  return <NuevoField label={f.label} required={f.req} error={error}>{control}</NuevoField>;
}

// ─── Slot vacío (punteado) ───────────────────────
// P18: prop opcional `onCrear` — si viene, suma un botón chico DEBAJO del
// CTA de elegir ("Crear X", motor record-form vía RecordFormModal) del
// mismo ancho (w-full, igual al botón de arriba) y alto de input (.btn ya
// mide 2.5rem, igual que .input — ver styles.css). Sin `onCrear` (default)
// se ve IDÉNTICO a antes — ampliación de API, no rotura de callers
// existentes (detalle.jsx no lo pasa).
function EmptyPartySlot({ type, onClick, onCrear }) {
  const m = PARTY_META[type];
  const Icon = m.icon;
  return (
    <div className="flex flex-col gap-2 w-full">
      <button
        type="button"
        onClick={onClick}
        className="rounded-xl p-4 flex flex-col items-center justify-center text-center gap-2 cursor-pointer transition-all w-full"
        style={{
          minHeight: 132,
          border: '1.5px dashed color-mix(in oklab, var(--border) 90%, transparent)',
          background: 'transparent',
          color: 'var(--muted-foreground)',
        }}
        onMouseEnter={(e) => {
          e.currentTarget.style.borderColor = 'color-mix(in oklab, var(--accent) 60%, var(--border))';
          e.currentTarget.style.background = 'color-mix(in oklab, var(--accent) 5%, transparent)';
          e.currentTarget.style.color = 'var(--accent)';
        }}
        onMouseLeave={(e) => {
          e.currentTarget.style.borderColor = 'color-mix(in oklab, var(--border) 90%, transparent)';
          e.currentTarget.style.background = 'transparent';
          e.currentTarget.style.color = 'var(--muted-foreground)';
        }}
      >
        <span className="inline-flex items-center justify-center rounded-lg"
          style={{ width: 34, height: 34, background: 'color-mix(in oklab, currentColor 12%, transparent)' }}>
          <Icon size={16} />
        </span>
        <span className="text-[10.5px] font-bold uppercase tracking-[0.12em]">{m.eyebrow}</span>
        <span className="inline-flex items-center gap-1 text-[12.5px] font-bold">
          <IconPlus size={13} />
          {m.cta}
        </span>
      </button>
      {onCrear && (
        <button type="button" onClick={onCrear} className="btn btn-outline w-full justify-center">
          <IconPlus size={12} />
          <span>{m.crearCta}</span>
        </button>
      )}
    </div>
  );
}

// ─── Slot completo (con editar/cambiar + quitar) ────────
function FilledPartySlot({ type, primary, lines = [], onPencil, pencilTitle = 'Cambiar', onClear, onTrash }) {
  const m = PARTY_META[type];
  const Icon = m.icon;
  return (
    <div className="rounded-xl p-4 relative group animate-fade-in-up" style={{
      minHeight: 132,
      background: 'color-mix(in oklab, var(--surface) 55%, transparent)',
      border: '1px solid color-mix(in oklab, var(--accent) 30%, var(--border))',
    }}>
      <div className="absolute top-2.5 right-2.5 flex items-center gap-1">
        <button type="button" onClick={onPencil} title={pencilTitle}
          className="inline-flex items-center justify-center rounded-md transition-colors" style={{ width: 26, height: 26, color: 'var(--muted-foreground)' }}
          onMouseEnter={(e) => e.currentTarget.style.color = 'var(--accent)'}
          onMouseLeave={(e) => e.currentTarget.style.color = 'var(--muted-foreground)'}>
          <IconPencil size={13} />
        </button>
        {onTrash && (
          <button type="button" onClick={onTrash} title="Eliminar registro"
            className="inline-flex items-center justify-center rounded-md transition-colors" style={{ width: 26, height: 26, color: 'var(--muted-foreground)' }}
            onMouseEnter={(e) => e.currentTarget.style.color = 'var(--destructive)'}
            onMouseLeave={(e) => e.currentTarget.style.color = 'var(--muted-foreground)'}>
            <IconTrash size={13} />
          </button>
        )}
        <button type="button" onClick={onClear} title="Quitar"
          className="inline-flex items-center justify-center rounded-md transition-colors" style={{ width: 26, height: 26, color: 'var(--muted-foreground)' }}
          onMouseEnter={(e) => e.currentTarget.style.color = 'var(--danger)'}
          onMouseLeave={(e) => e.currentTarget.style.color = 'var(--muted-foreground)'}>
          <IconX size={13} />
        </button>
      </div>
      <div className="flex items-center gap-2.5 mb-3">
        <span className="inline-flex items-center justify-center rounded-lg"
          style={{ width: 28, height: 28, background: 'color-mix(in oklab, var(--accent) 12%, transparent)', color: 'var(--accent)' }}>
          <Icon size={14} />
        </span>
        <p className="text-[10.5px] font-bold uppercase tracking-[0.12em]" style={{ color: 'var(--muted-foreground)' }}>
          {m.eyebrow}
        </p>
      </div>
      <p className="text-[15px] font-extrabold tracking-tight pr-12" style={{ color: 'var(--foreground)' }}>
        {primary}
      </p>
      <div className="mt-2 space-y-1">
        {lines.filter(Boolean).map((l, i) => (
          <p key={i} className="text-[12px]" style={{ color: 'var(--muted-foreground)' }}>{l}</p>
        ))}
      </div>
    </div>
  );
}

// ─── Modal selector: elegir existente o (si `allowCrear`) crear nuevo ──
// P25: `allowCrear` (default true) reemplaza la vieja `editInitial` — ver
// header del archivo. Con `allowCrear=false` el modal SIEMPRE arranca y se
// queda en modo 'list' (buscar/elegir), sin footer de "Crear X nuevo".
function PartySelectorModal({ type, open, onClose, onPick, allowCrear = true }) {
  const [mode, setMode] = _usePSState('list');
  const [search, setSearch] = _usePSState('');
  const [form, setForm] = _usePSState({});
  const [touched, setTouched] = _usePSState(false);
  const searchRef = _usePSRef(null);

  _usePSEffect(() => {
    if (!open) return;
    setMode('list');
    setForm({});
    setSearch(''); setTouched(false);
    const t = setTimeout(() => searchRef.current?.focus(), 60);
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    return () => { clearTimeout(t); document.removeEventListener('keydown', onKey); document.body.style.overflow = prev; };
  }, [open, type]);

  if (!open || !type) return null;

  const m = PARTY_META[type];
  const titulo = type === 'paciente' ? 'paciente' : type === 'medico' ? 'médico' : type === 'proveedor' ? 'proveedor' : 'entidad';
  const isOrg = type === 'entidad' || type === 'proveedor';

  const source = type === 'paciente' ? (window.PARTICULARES || [])
    : type === 'medico' ? (window.MEDICOS || [])
    : type === 'proveedor' ? (window.PROVEEDORES || [])
    : (window.ENTIDADES || []);

  const q = search.trim().toLowerCase();
  const results = source.filter((r) => {
    if (!q) return true;
    if (isOrg) return `${r.razonSocial} ${r.cuit || ''}`.toLowerCase().includes(q);
    return `${r.apellido} ${r.nombre} ${r.dni || ''} ${r.especialidad || ''} ${r.matricula || ''}`.toLowerCase().includes(q);
  });

  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));

  // ── crear: armar objeto + persistir de verdad (hallazgo #18, auditoría
  // 05/07/2026) ──────────────────────────────────────────────────────────
  // P25: sin rama de edición (era exclusiva de `editInitial`, podada — ver
  // header). Solo llega acá `type === 'entidad' | 'proveedor'` (únicos con
  // `MODAL_FIELDS` vivo); igual queda genérico por las dudas.
  //
  // Antes esto era `arr.unshift(obj)`: SOLO memoria, nunca pegaba al backend
  // — el id lo fabricaba `buildAndCreate` a mano ('ent-'/'prv-'+Date.now()).
  // El documento que lo referencia (Compras/Logística/Inventario/Finanzas,
  // los 4 módulos con `allowCrear`) guarda ESE id como `entidadId`/
  // `proveedorId`, una FK uuid real (`compras.proveedor_id references
  // proveedores(id)`, etc.) — al guardar, Postgres rechazaba el insert
  // ("invalid input syntax for type uuid"). Fix: `MicosStore.create()` (ya
  // existe, mismo mecanismo que ya usa ui/record-form.jsx para las altas de
  // Directorio) — asigna su propio id temporal optimista (`_tmp-...`),
  // dispara el POST real y reconcilia el objeto in-place al uuid real
  // cuando el server contesta.
  //
  // `onPick` se llama DOS VECES (mismo patrón id-race que record-form.jsx/
  // app.jsx, 3er argumento `onReconciled` de `create()`): la primera,
  // optimista, con el id temporal — cierra el modal al toque, sin esperar
  // la red; la segunda, cuando el POST resuelve, con el objeto YA
  // reconciliado al uuid real. Los 6 callers existentes (Compras/
  // Logística/Inventario/Finanzas×3) ya toleran que `onPick` los llame de
  // nuevo — solo hacen `setDraft(...)`/`setPicker(false)`, idempotente —
  // así el FK del documento apunta al id real antes de guardar.
  const commit = (obj) => {
    const key = type === 'proveedor' ? 'proveedores' : 'entidades';
    const created = window.MicosStore.create(key, obj, (reconciliado) => onPick(reconciliado));
    onPick(created);
  };

  const buildAndCreate = () => {
    setTouched(true);
    const spec = MODAL_FIELDS[type] || [];
    for (const f of spec) { if (f.req && !String(form[f.k] || '').trim()) return; }
    const obj = { __nuevo: true };
    spec.forEach((f) => { obj[f.k] = String(form[f.k] || '').trim(); });
    if (type === 'entidad') {
      if (!obj.convenio) obj.convenio = 'Sin convenio';
      if (!obj.condicionVenta) obj.condicionVenta = 'CC 30 días';
      obj.expedientesActivos = 0;
      obj.saldoCobrar = 0;
    } else if (type === 'proveedor') {
      obj.estado = 'ACTIVO';
      obj.saldoPagar = 0;
    }
    commit(obj);
  };

  return (
    <div
      className="fixed inset-0 z-50 flex items-start sm:items-center justify-center p-4 sm:p-6 overflow-y-auto"
      style={{ background: 'color-mix(in oklab, #0a1418 62%, transparent)', backdropFilter: 'blur(4px)' }}
      onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}
    >
      <div
        className="w-full max-w-lg rounded-2xl my-auto animate-fade-in-up"
        style={{ background: 'var(--card)', border: '1px solid color-mix(in oklab, var(--border) 65%, transparent)', boxShadow: '0 30px 80px -20px rgba(8, 20, 24, 0.55)' }}
        onMouseDown={(e) => e.stopPropagation()}
      >
        {/* Header */}
        <div className="flex items-start justify-between gap-4 px-6 pt-5 pb-4"
          style={{ borderBottom: '1px solid color-mix(in oklab, var(--border) 55%, transparent)' }}>
          <div className="flex items-center gap-3 min-w-0">
            <span className="inline-flex items-center justify-center rounded-lg flex-shrink-0"
              style={{ width: 34, height: 34, background: 'color-mix(in oklab, var(--accent) 12%, transparent)', color: 'var(--accent)' }}>
              <m.icon size={16} />
            </span>
            <div className="min-w-0">
              <p className="text-[11px] font-bold uppercase tracking-[0.16em]" style={{ color: 'var(--accent)' }}>
                {mode === 'list' ? 'Seleccionar' : 'Crear'}
              </p>
              <h2 className="text-[18px] font-extrabold tracking-tight capitalize" style={{ color: 'var(--foreground)' }}>
                {titulo}
              </h2>
            </div>
          </div>
          <button type="button" onClick={onClose}
            className="inline-flex items-center justify-center flex-shrink-0 rounded-lg transition-colors"
            style={{ width: 34, height: 34, border: '1px solid color-mix(in oklab, var(--border) 60%, transparent)', color: 'var(--muted-foreground)' }}
            onMouseEnter={(e) => { e.currentTarget.style.color = 'var(--foreground)'; e.currentTarget.style.borderColor = 'color-mix(in oklab, var(--border) 90%, transparent)'; }}
            onMouseLeave={(e) => { e.currentTarget.style.color = 'var(--muted-foreground)'; e.currentTarget.style.borderColor = 'color-mix(in oklab, var(--border) 60%, transparent)'; }}
            aria-label="Cerrar">
            <IconX size={16} />
          </button>
        </div>

        {mode === 'list' ? (
          <>
            {/* Buscador */}
            <div className="px-6 pt-4 pb-3">
              <div className="relative">
                <IconSearch size={15} className="absolute left-3.5 top-1/2 -translate-y-1/2" style={{ color: 'var(--muted-foreground)' }} />
                <input ref={searchRef} value={search} onChange={(e) => setSearch(e.target.value)}
                  placeholder={`Buscar ${titulo}…`}
                  className="w-full h-10 pl-10 pr-3 text-[13px] font-medium rounded-lg outline-none"
                  style={{ background: 'color-mix(in oklab, var(--surface) 50%, transparent)', border: '1px solid color-mix(in oklab, var(--border) 45%, transparent)', color: 'var(--foreground)' }} />
              </div>
            </div>

            {/* Lista */}
            <div className="px-3 pb-2 space-y-1 overflow-y-auto" style={{ maxHeight: '46vh' }}>
              {type === 'entidad' && (
                <button type="button" onClick={() => onPick({ __sinEntidad: true })}
                  className="w-full flex items-center gap-3 rounded-xl px-3 py-3 text-left transition-colors cursor-pointer"
                  style={{ background: 'transparent' }}
                  onMouseEnter={(e) => e.currentTarget.style.background = 'color-mix(in oklab, var(--surface) 50%, transparent)'}
                  onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}>
                  <span className="inline-flex items-center justify-center rounded-lg flex-shrink-0"
                    style={{ width: 36, height: 36, background: 'color-mix(in oklab, var(--muted-foreground) 12%, transparent)', color: 'var(--muted-foreground)' }}>
                    <IconUser size={16} />
                  </span>
                  <div className="min-w-0">
                    <p className="text-[13px] font-bold" style={{ color: 'var(--foreground)' }}>Particular (sin entidad)</p>
                    <p className="text-[11.5px]" style={{ color: 'var(--muted-foreground)' }}>Pago directo del paciente</p>
                  </div>
                </button>
              )}
              {results.map((r) => (
                <button key={r.id} type="button" onClick={() => onPick(r)}
                  className="w-full flex items-center gap-3 rounded-xl px-3 py-3 text-left transition-colors cursor-pointer"
                  style={{ background: 'transparent' }}
                  onMouseEnter={(e) => e.currentTarget.style.background = 'color-mix(in oklab, var(--surface) 50%, transparent)'}
                  onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}>
                  <span className="inline-flex items-center justify-center rounded-full text-[11px] font-extrabold flex-shrink-0"
                    style={{ width: 36, height: 36, background: 'color-mix(in oklab, var(--accent) 14%, transparent)', color: 'var(--accent)' }}>
                    {isOrg
                      ? (r.razonSocial || '?').slice(0, 2).toUpperCase()
                      : `${(r.apellido || '?')[0]}${(r.nombre || '?').replace(/^(Dr|Dra)\.?\s*/i, '')[0] || ''}`.toUpperCase()}
                  </span>
                  <div className="min-w-0 flex-1">
                    <p className="text-[13px] font-bold truncate flex items-center gap-2" style={{ color: 'var(--foreground)' }}>
                      {isOrg ? r.razonSocial : `${r.titulo ? r.titulo + ' ' : ''}${r.nombre} ${r.apellido}`}
                      {r.__nuevo && (
                        <span className="text-[9px] font-bold uppercase tracking-wide px-1.5 py-0.5 rounded"
                          style={{ background: 'color-mix(in oklab, var(--accent) 16%, transparent)', color: 'var(--accent)' }}>Nuevo</span>
                      )}
                    </p>
                    <p className="text-[11.5px] truncate" style={{ color: 'var(--muted-foreground)' }}>
                      {isOrg ? (r.cuit ? `CUIT ${formatCuit(r.cuit)}` : r.convenio || r.rubro || '')
                        : type === 'medico' ? [r.especialidad, r.matricula].filter(Boolean).join(' · ')
                        : [r.dni ? `DNI ${r.dni}` : '', r.telefono].filter(Boolean).join(' · ')}
                    </p>
                  </div>
                  <IconChevronRight size={15} style={{ color: 'var(--muted-foreground)' }} />
                </button>
              ))}
              {results.length === 0 && (
                <p className="px-3 py-8 text-center text-[13px] font-semibold" style={{ color: 'var(--muted-foreground)' }}>
                  Sin coincidencias.
                </p>
              )}
            </div>

            {/* Footer: crear nuevo — P25: gateado por `allowCrear` (Expedientes
                lo pasa en false: "Cargar X" ahí es solo buscar/elegir, la
                creación real es el botón aparte "Crear X", ver header). */}
            {allowCrear && (
              <div className="px-6 py-4" style={{ borderTop: '1px solid color-mix(in oklab, var(--border) 55%, transparent)' }}>
                <button type="button" onClick={() => { setMode('create'); setTouched(false); }}
                  className="btn btn-outline w-full justify-center">
                  {`Crear ${titulo} nuevo`}
                </button>
              </div>
            )}
          </>
        ) : (
          <form onSubmit={(e) => { e.preventDefault(); buildAndCreate(); }}>
            {/* Form crear — campos del mockup (Altas) según el tipo */}
            <div className="px-6 py-5 grid grid-cols-2 gap-x-4 gap-y-4" style={{ maxHeight: '62vh', overflowY: 'auto' }}>
              {(MODAL_FIELDS[type] || []).map((f) => (
                <div key={f.k} style={{ gridColumn: f.span ? '1 / -1' : 'auto' }}>
                  <ModalField f={f} value={form[f.k]} onChange={set}
                    error={touched && f.req && !String(form[f.k] || '').trim() ? 'Requerido.' : null} />
                </div>
              ))}
            </div>
            {/* Footer crear */}
            <div className="flex items-center justify-end gap-2.5 px-6 py-4" style={{ borderTop: '1px solid color-mix(in oklab, var(--border) 55%, transparent)' }}>
              <button type="button" className="btn btn-outline"
                onClick={() => { setMode('list'); setTouched(false); setForm({}); }}>
                Descartar
              </button>
              <button type="submit" className="btn btn-primary" style={{ boxShadow: 'none' }}>
                Continuar
              </button>
            </div>
          </form>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { PartySelectorModal, EmptyPartySlot, FilledPartySlot, PARTY_META, MODAL_FIELDS });
