// ─── Expedientes · Detalle ──────────────────────────────────────────
// ExpedienteDetailScreen: header con partes, financiero y los 7 acordeones del
// pipeline (ExpedienteDocumentos, screens/expedientes/detalle-cards.jsx), con
// edición in-place de partes/vendedor/estado (usePartiesEditor, screens/
// expedientes/partes-editor.js). P6 — acá MUERE el dual-path EXPEDIENTE_DETAIL
// ("Sofía"): TODO expediente pasa por el MISMO camino — al montar se pide el
// detalle rico a /api/expedientes/detail?id=<uuid>, MicosMergeDetalleRico
// (dominio/expediente-docs.js) lo mergea en las colecciones globales y
// MicosResolveExpedienteDocs resuelve desde ahí; guardar es SIEMPRE
// MicosStore.update('expedientes', id, patch) — sin singleton, sin rama
// especial. Expone a window: ExpedienteDetailScreen. Consume
// window.MicosResolveExpedienteDocs/MicosMergeDetalleRico (dominio/
// expediente-docs.js), window.usePartiesEditor/initPart, PartySelectorModal/
// FilledPartySlot/EmptyPartySlot (ui/party-selector.jsx), AltaSelect/
// ReadOnlyField/StatusPill (ui/primitives.jsx), PartyCard/MetaCol/
// ExpedienteDocumentos (detalle-cards.jsx), FinancieroCard (financiero-card.jsx),
// vendedoresDisponibles (lista.jsx), STATUS_CONFIG/PIPELINE_STATUSES,
// formatMoney/formatCuit/formatDate (dominio/formato.js).
//
// FIX P13 (ítem 4): el archivo estaba en 426 líneas, por encima del techo DURO
// de 400 (no ya una excepción "al límite", una violación real). Se evaluó UNA
// extracción natural: la tarjeta "Financiero" (~50 líneas, bloque cohesivo,
// sin dependencias del resto del render salvo `exp`/`editing`/`hasMoney`) sale
// a `screens/expedientes/financiero-card.jsx` (`FinancieroCard`, nombre
// propio, no `Helper1`). Resultado: bajo el techo duro.
//
// EXCEPCIÓN DE TECHO (regla ~250/400, sigue por encima de ~250): un solo tema
// (la pantalla de detalle) ya partida en 4 (tarjetas/acordeones →
// detalle-cards.jsx, financiero → financiero-card.jsx, estado de partes →
// partes-editor.js, merge de datos → dominio); lo que queda es el layout
// propio de ESTA pantalla (header editable + partes + documentos + modales) —
// partirlo más solo repartiría el mismo render en archivos sin nombre propio,
// contra el criterio de "partir por TEMA" de AGENTS.md.
//
// P25 (Fran, 03/07): "Cargar X" (PartySelectorModal) pasa `allowCrear={false}`
// — el form embebido viejo (requeridos VIEJOS: DNI/matrícula obligatorios) se
// podó de ui/party-selector.jsx. Esta pantalla suma el botón "Crear X" bajo
// cada parte vacía en modo edición (EmptyPartySlot, prop `onCrear` → abre
// `RecordFormModal`, ui/record-form.jsx — MISMO patrón que P18 ya usaba en
// alta.jsx; acá no existía porque P18 lo había dejado explícitamente fuera de
// alcance). Sin este agregado, editar un expediente YA GUARDADO se quedaba
// sin ninguna vía de crear una parte nueva (la única que tenía, el form
// embebido, es justo la que se está podando). Consume también
// window.RecordFormModal/RECORD_FORMS (ui/record-form.jsx).

const { useState: _useStateD, useEffect: _useEffectD, useMemo: _useMemoD } = React;

const _UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;

// ─── Link inverso ERP→CRM (carril B-erp, top10 #3) ──
// Si el expediente tiene correos vinculados (crm_hilos.linked_expediente_id =
// publicId), muestra un chip "Ver mails (N)" que abre el CRM. Solo si el usuario
// puede ver el CRM (permiso 'crm') y hay al menos 1 hilo (N>=1, versión mínima
// válida). Contrato de navegación: /crm?expediente=<publicId> — el filtrado del
// inbox por ese expediente lo completa el carril del CRM (anotado para el fixer).
function ExpedienteMailChip({ expedientePublicId }) {
  const [n, setN] = _useStateD(0);
  _useEffectD(() => {
    if (!expedientePublicId) return undefined;
    if (window.MicosPuedeVer && !window.MicosPuedeVer('crm')) return undefined;
    let cancel = false;
    fetch('/api/crm-unread?expediente=' + encodeURIComponent(expedientePublicId), { credentials: 'same-origin' })
      .then((r) => (r.ok ? r.json() : null))
      .then((d) => { if (!cancel && d && typeof d.count === 'number') setN(d.count); })
      .catch(() => {});
    return () => { cancel = true; };
  }, [expedientePublicId]);

  if (n < 1) return null;
  return (
    <button
      onClick={() => { window.location.href = '/crm?expediente=' + encodeURIComponent(expedientePublicId); }}
      className="inline-flex items-center gap-1.5 text-[11px] font-bold uppercase tracking-[0.1em] px-2.5 py-1 rounded-md cursor-pointer transition-colors"
      style={{ background: 'color-mix(in oklab, var(--accent) 10%, transparent)', color: 'var(--accent)', border: '1px solid color-mix(in oklab, var(--accent) 30%, var(--border))' }}
      onMouseEnter={(e) => { e.currentTarget.style.background = 'color-mix(in oklab, var(--accent) 18%, transparent)'; }}
      onMouseLeave={(e) => { e.currentTarget.style.background = 'color-mix(in oklab, var(--accent) 10%, transparent)'; }}
      title="Ver los correos vinculados a este expediente"
    >
      <IconMail size={13} />
      <span>{`Ver mails (${n})`}</span>
    </button>
  );
}

// ─── Detail Screen ──────────────────────────────
function ExpedienteDetailScreen({ expediente, onBack, onOpenSubview }) {
  // ── Edición in-place: las partes, el vendedor y el estado se editan acá
  // mismo; el resto (financiero, documentos) queda visible pero deshabilitado.
  const [editing, setEditing] = _useStateD(false);
  const [estado, setEstado] = _useStateD('INICIADO');
  const [delExp, setDelExp] = _useStateD(false);
  const [toast, setToast] = _useStateD(null);
  // Estado + handlers compartidos con el alta (P6 — antes duplicados 1:1 acá
  // con otros nombres: pac/med_/ent_). Arranca vacío; reset(exp) al editar.
  const partes = usePartiesEditor(null);
  const [detalleTick, setDetalleTick] = _useStateD(0);
  // P25: tipo de parte que se está creando por el motor record-form ('paciente'
  // | 'medico' | 'entidad' | null = cerrado) — mismo patrón que alta.jsx (P18).
  const [crearTipo, setCrearTipo] = _useStateD(null);

  const expId = expediente && expediente.id;

  // Detalle rico on-demand (solo ids reales de la DB — un expediente recién
  // creado tiene id temporal `_tmp-…` hasta que el POST resuelve: no hay nada
  // que buscar todavía, sus documentos aparecen a medida que se cargan).
  _useEffectD(() => {
    if (!expId || !_UUID_RE.test(String(expId))) return undefined;
    let cancelled = false;
    fetch('/api/expedientes/detail?id=' + encodeURIComponent(expId), { credentials: 'same-origin' })
      .then((r) => (r.ok ? r.json() : Promise.reject(r.status)))
      .then((rich) => {
        if (cancelled || !rich || !rich.id) return;
        // Merge en las colecciones globales (dominio/expediente-docs.js): los docs
        // del expediente abierto quedan visibles aunque estén fuera de BIG_LIMIT.
        window.MicosMergeDetalleRico(rich);
        // Marcá el detalle como cargado en esta página: al abrir un documento del
        // expediente (sub-ruta), DocSubrouteGate ve esto y monta directo, sin re-pedir
        // el detalle ni parpadear un loading (screens/docs/compartido.jsx).
        (window.__micosDetalleCargado || (window.__micosDetalleCargado = new Set())).add(expId);
        setDetalleTick((t) => t + 1); // re-resuelve `exp` con los docs mergeados
      })
      .catch((err) => console.warn('[ExpedienteDetailScreen] detalle rico', expId, err));
    return () => { cancelled = true; };
  }, [expId]);

  // Camino genérico ÚNICO: resolver documentos desde las colecciones, para
  // cualquier expediente (el ejemplo rico embebido murió con P6). `toast` en
  // las deps: re-resuelve tras guardar (los documentos no cambian, las partes sí).
  const exp = _useMemoD(() => {
    const base = expediente || {};
    return window.MicosResolveExpedienteDocs ? window.MicosResolveExpedienteDocs(base) : base;
  }, [expediente, detalleTick, editing, toast]);

  // Sin expediente seleccionado (deep-link inválido / fila que dejó de existir):
  // pantalla honesta, nunca un expediente de ejemplo (eso era el dual-path).
  if (!expediente) {
    return (
      <div className="space-y-7 pt-2">
        <button onClick={onBack}
          className="flex items-center gap-2 text-[11px] font-bold uppercase tracking-[0.12em] cursor-pointer transition-colors animate-fade-in-up"
          style={{ color: 'var(--muted-foreground)' }}>
          <IconArrowLeft size={13} />
          Volver a expedientes
        </button>
        <div className="rounded-2xl bg-card p-8 text-center" style={{ border: '1px solid color-mix(in oklab, var(--border) 55%, transparent)' }}>
          <p className="text-[14px] font-semibold" style={{ color: 'var(--muted-foreground)' }}>
            No encontramos este expediente. Volvé a la lista y abrilo de nuevo.
          </p>
        </div>
      </div>
    );
  }

  const enterEdit = () => {
    partes.reset(exp);
    setEstado(exp.status || 'INICIADO');
    setEditing(true);
  };
  const cancelEdit = () => { setEditing(false); partes.closePicker(); };

  // Al guardar en el modal de creación rápida (RecordFormModal): el registro
  // ya está en window.PARTICULARES/MEDICOS/ENTIDADES (MicosStore.create lo
  // empuja sincrónicamente, optimista) — se busca por el id con el que
  // disparó onSaved y se deja seleccionado en el slot correspondiente.
  // Mismo patrón que alta.jsx (P18/P25).
  const handleParteCreada = (id) => {
    const globalKey = crearTipo === 'paciente' ? 'PARTICULARES' : crearTipo === 'medico' ? 'MEDICOS' : 'ENTIDADES';
    const creado = (window[globalKey] || []).find((x) => x.id === id);
    if (creado) {
      if (crearTipo === 'paciente') partes.setPaciente(creado);
      else if (crearTipo === 'medico') partes.setMedico(creado);
      else { partes.setEntidad(creado); partes.setEntidadSet(true); }
    }
    setCrearTipo(null);
  };

  const saveEdit = () => {
    if (!partes.canSave) return;
    const patch = {
      ...partes.buildParts(exp),
      status: estado,
      actualizado: (window.MicosTodayISO()),
    };
    window.MicosStore.update('expedientes', exp.id, patch);
    setEditing(false);
    partes.closePicker();
    setToast('Expediente actualizado');
    setTimeout(() => setToast(null), 3200);
  };

  const confirmDeleteExp = () => {
    window.MicosStore.remove('expedientes', exp.id);
    setDelExp(false);
    onBack();
  };

  // Valores mostrados (borrador cuando se está editando).
  const par = editing ? partes.paciente || {} : exp.particular || {};
  const med = editing ? partes.medico || {} : exp.medico || {};
  const ent = editing ? (partes.entidadSet ? partes.entidad : null) : exp.entidad || null;
  const dispStatus = editing ? estado : exp.status;
  const hasMoney = exp.total != null;

  return (
    <div className="space-y-7 pt-2">
      {/* ── Back link ─────────────────────────────── */}
      <button onClick={onBack}
      className="flex items-center gap-2 text-[11px] font-bold uppercase tracking-[0.12em] cursor-pointer transition-colors animate-fade-in-up"
      style={{ color: 'var(--muted-foreground)' }}
      onMouseEnter={(e) => e.currentTarget.style.color = 'var(--accent)'}
      onMouseLeave={(e) => e.currentTarget.style.color = 'var(--muted-foreground)'}>

        <IconArrowLeft size={13} />
        Volver a expedientes
      </button>

      {/* ── Header ────────────────────────────────── */}
      <div className="flex flex-wrap items-start justify-between gap-4 animate-fade-in-up" style={{ animationDelay: '40ms' }}>
        <div className="space-y-3 min-w-0 flex-1">
          <div className="flex items-center gap-3 flex-wrap">
            <span className="font-mono text-[14px] font-extrabold tracking-wider uppercase" style={{ color: 'var(--accent)' }}>
              {/* Alta recién guardada: el publicId lo asigna el trigger de la DB, no el
                  cliente (BUGS-caza-01-07-2026.md #25/B1) — placeholder honesto mientras
                  el POST está en vuelo (ventana muy breve). */}
              {exp.publicId || 'EXP-… (asignando)'}
            </span>
            <StatusPill status={dispStatus} size="sm" />
            {/* Link inverso al CRM: correos vinculados a este expediente (top10 #3). */}
            <ExpedienteMailChip expedientePublicId={exp.publicId} />
            {editing &&
            <span className="text-[10.5px] font-bold uppercase tracking-[0.14em] px-2 py-1 rounded-md"
            style={{ background: 'color-mix(in oklab, var(--accent) 12%, transparent)', color: 'var(--accent)' }}>
                Editando
              </span>
            }
          </div>
          <h1 className="text-[clamp(28px,4.2vw,40px)] leading-[1.05] font-extrabold tracking-[-0.02em]" style={{ color: 'var(--foreground)' }}>
            {`${par.nombre || ''} ${par.apellido || ''}`.trim() || 'Sin paciente'}
          </h1>
          <p className="text-[13.5px] font-medium" style={{ color: 'var(--muted-foreground)' }}>
            {`${med.titulo ? med.titulo + ' ' : ''}${med.nombre || ''} ${med.apellido || ''}`.trim() || 'Sin médico'}
            {med.especialidad && <><span className="mx-1.5 opacity-50">·</span>{med.especialidad}</>}
            <span className="mx-1.5 opacity-50">·</span>
            <span className="font-bold" style={{ color: 'var(--foreground)' }}>{ent?.razonSocial || 'Particular'}</span>
          </p>
        </div>
        <div className="flex items-center gap-2 flex-shrink-0 flex-wrap">
          {editing ?
          <>
              {/* Borrado global (regla §8 del CLAUDE.md del bundle): todo registro es
                  eliminable desde dentro de su edición — P6 quita el viejo gate __nuevo
                  (mismo criterio ya aplicado en RecordFormScreen). Soft-delete real. */}
              <button className="btn" onClick={() => setDelExp(true)}
              style={{ background: 'var(--card)', color: 'var(--destructive)', border: '1px solid color-mix(in oklab, var(--destructive) 55%, var(--border))' }}>
                <IconTrash size={14} />
                <span className="hidden sm:inline">Eliminar</span>
              </button>
              <span aria-hidden="true" style={{ width: 1, height: 26, background: 'color-mix(in oklab, var(--border) 85%, transparent)', margin: '0 4px', flexShrink: 0 }} />
              <button className="btn btn-outline" onClick={cancelEdit} style={{ fontSize: "13px", height: "42px" }}>
                <IconX size={14} />
                <span className="hidden sm:inline">Descartar</span>
              </button>
              <button className="btn btn-primary" onClick={saveEdit} style={!partes.canSave ? { opacity: 0.55 } : {}}>
                <IconCheck size={14} />
                <span className="hidden sm:inline">Guardar cambios</span>
              </button>
            </> :

          <button className="btn btn-primary" onClick={enterEdit}>
              <IconPencil size={14} />
              <span className="hidden sm:inline">Editar</span>
            </button>
          }
        </div>
      </div>

      {/* ── Parties + Financiero (split) ──────────── */}
      <div className="space-y-4 pt-2">
        <p className="text-[10.5px] font-bold uppercase tracking-[0.18em]" style={{ color: 'var(--accent)' }}>
          Información general
        </p>
        <div className="grid grid-cols-1 xl:grid-cols-[1fr_360px] gap-4 sm:gap-5 animate-fade-in-up" style={{ animationDelay: '80ms' }}>
        {/* Parties */}
        <div className="rounded-2xl bg-card p-5 sm:p-6 space-y-5" style={{
            border: '1px solid color-mix(in oklab, var(--border) 55%, transparent)',
            boxShadow: 'var(--shadow-card)'
          }}>
          <div className="flex items-center justify-between flex-wrap gap-2">
            <p className="text-[10.5px] font-bold uppercase tracking-[0.18em]" style={{ color: 'var(--accent)' }}>
              Partes involucradas
            </p>
            {/* FIX hallazgo auditoría 05/07/2026: "En progreso" era un string hardcodeado sin
                binding — se mostraba igual para CUALQUIER estado, incluido RECIBO (cerrado/
                cobrado). Ahora se deriva de dispStatus (mismo dato que ya usa el StatusPill
                del header, arriba) — RECIBO es el último paso del pipeline (STATUS_CONFIG,
                dominio/pipeline.js). */}
            <span className="inline-flex items-center gap-1.5 text-[10.5px] font-bold uppercase tracking-[0.1em]"
              style={{ color: dispStatus === 'RECIBO' ? 'var(--success)' : 'var(--accent)' }}>
              <span className="inline-block rounded-full" style={{ width: 6, height: 6, background: dispStatus === 'RECIBO' ? 'var(--success)' : 'var(--accent)' }} />
              {dispStatus === 'RECIBO' ? 'Completado' : 'En progreso'}
            </span>
          </div>

          {editing ?
            <div className="grid grid-cols-1 md:grid-cols-3 gap-3">
              {partes.paciente ?
              <FilledPartySlot type="paciente"
              primary={`${partes.paciente.nombre || ''} ${partes.paciente.apellido || ''}`.trim() || 'Paciente'}
              lines={[partes.paciente.dni ? `DNI ${partes.paciente.dni}` : null, partes.paciente.telefono]}
              pencilTitle={partes.pencilTitle(partes.paciente)}
              onPencil={() => partes.openPicker('paciente', partes.paciente)}
              onTrash={partes.paciente.__nuevo ? () => partes.setDelNuevo({ type: 'paciente', record: partes.paciente }) : undefined}
              onClear={() => partes.setPaciente(null)} /> :
              <EmptyPartySlot type="paciente" onClick={() => partes.openPicker('paciente', null)} onCrear={() => setCrearTipo('paciente')} />}
              {partes.medico ?
              <FilledPartySlot type="medico"
              primary={`${partes.medico.titulo ? partes.medico.titulo + ' ' : ''}${partes.medico.nombre || ''} ${partes.medico.apellido || ''}`.trim() || 'Médico'}
              lines={[partes.medico.especialidad, partes.medico.matricula]}
              pencilTitle={partes.pencilTitle(partes.medico)}
              onPencil={() => partes.openPicker('medico', partes.medico)}
              onTrash={partes.medico.__nuevo ? () => partes.setDelNuevo({ type: 'medico', record: partes.medico }) : undefined}
              onClear={() => partes.setMedico(null)} /> :
              <EmptyPartySlot type="medico" onClick={() => partes.openPicker('medico', null)} onCrear={() => setCrearTipo('medico')} />}
              {partes.entidadSet ?
              <FilledPartySlot type="entidad"
              primary={partes.entidad ? partes.entidad.razonSocial : 'Particular'}
              lines={partes.entidad ? [partes.entidad.cuit ? `CUIT ${partes.entidad.cuit}` : null, partes.entidad.convenio] : ['Pago directo del paciente']}
              pencilTitle={partes.pencilTitle(partes.entidad)}
              onPencil={() => partes.openPicker('entidad', partes.entidad)}
              onTrash={partes.entidad && partes.entidad.__nuevo ? () => partes.setDelNuevo({ type: 'entidad', record: partes.entidad }) : undefined}
              onClear={() => { partes.setEntidad(null); partes.setEntidadSet(false); }} /> :
              <EmptyPartySlot type="entidad" onClick={() => partes.openPicker('entidad', null)} onCrear={() => setCrearTipo('entidad')} />}
            </div> :

            <div className="grid grid-cols-1 md:grid-cols-3 gap-3">
              <PartyCard
                icon={IconUser}
                eyebrow="Paciente"
                primary={`${par.nombre || ''} ${par.apellido || ''}`.trim() || 'Sin paciente'}
                lines={[par.dni ? `DNI ${par.dni}` : null, par.telefono].filter(Boolean)} />

              <PartyCard
                icon={IconStethoscope}
                eyebrow="Médico"
                primary={`${med.titulo ? med.titulo + ' ' : ''}${med.nombre || ''} ${med.apellido || ''}`.trim() || 'Sin médico'}
                lines={[med.especialidad, med.matricula].filter(Boolean)} />

              <PartyCard
                icon={IconBuilding}
                eyebrow="Entidad / Cobertura"
                primary={ent?.razonSocial || 'Particular'}
                lines={ent ? [ent.cuit ? `CUIT ${formatCuit(ent.cuit)}` : null, ent.convenio].filter(Boolean) : []} />

            </div>
            }

          <div className="h-px" style={{ background: 'color-mix(in oklab, var(--border) 45%, transparent)' }} />

          <div className="grid grid-cols-2 md:grid-cols-4 gap-4 sm:gap-5 items-start">
            {editing ?
              <>
                <div className="space-y-1.5">
                  <p className="text-[10px] font-bold uppercase tracking-[0.12em]" style={{ color: 'var(--muted-foreground)' }}>Vendedor</p>
                  <AltaSelect value={partes.vendedor} onChange={(e) => partes.setVendedor(e.target.value)}>
                    <option value="">Sin vendedor</option>
                    {vendedoresDisponibles().map((v) => <option key={v} value={v}>{v}</option>)}
                  </AltaSelect>
                </div>
                <div className="space-y-1.5">
                  <p className="text-[10px] font-bold uppercase tracking-[0.12em]" style={{ color: 'var(--muted-foreground)' }}>Vendedor aux.</p>
                  <AltaSelect value={partes.vendedorAux} onChange={(e) => partes.setVendedorAux(e.target.value)}>
                    <option value="">Sin asignar</option>
                    {vendedoresDisponibles().filter((v) => v !== partes.vendedor).map((v) => <option key={v} value={v}>{v}</option>)}
                  </AltaSelect>
                </div>
                <div className="space-y-1.5">
                  <p className="text-[10px] font-bold uppercase tracking-[0.12em]" style={{ color: 'var(--muted-foreground)' }}>Estado</p>
                  <AltaSelect value={estado} onChange={(e) => setEstado(e.target.value)}>
                    {(window.PIPELINE_STATUSES || []).map((s) => <option key={s} value={s}>{(STATUS_CONFIG[s] || {}).label || s}</option>)}
                  </AltaSelect>
                </div>
                <ReadOnlyField label="Inicio" value={exp.inicio ? formatDate(exp.inicio) : '—'} />
              </> :

              <>
                <MetaCol label="Vendedor" value={exp.vendedor?.name || 'Sin vendedor'} />
                <MetaCol label="Vendedor aux." value={exp.vendedorAux?.name || '—'} />
                <MetaCol label="Inicio" value={exp.inicio ? formatDate(exp.inicio) : '—'} />
                <MetaCol label="Última actualización" value={formatDate(exp.actualizado || exp.inicio) || '—'} />
              </>
              }
          </div>
        </div>

        {/* Financiero — FinancieroCard, extraída a screens/expedientes/financiero-card.jsx (P13, ítem 4) */}
        <FinancieroCard exp={exp} editing={editing} hasMoney={hasMoney} />
        </div>
      </div>

      {/* ── Documentos ────────────────────────────── */}
      <div className="space-y-4 stagger pt-2" style={{ opacity: editing ? 0.55 : 1, pointerEvents: editing ? 'none' : 'auto' }}>
        <p className="text-[10.5px] font-bold uppercase tracking-[0.18em]" style={{ color: 'var(--accent)' }}>
          Documentos del expediente
        </p>
        {editing &&
        <p className="text-[12px] -mt-1" style={{ color: 'var(--muted-foreground)' }}>
            Visibles para referencia · se cargan desde el detalle (fuera del modo edición).
          </p>
        }
        <ExpedienteDocumentos exp={exp} status={dispStatus} onOpenSubview={onOpenSubview} />
      </div>

      {/* ── Modales de edición ───────────────────── */}
      {/* P25: `allowCrear={false}` — "Cargar X" acá es solo buscar/elegir, la
          creación real es el botón aparte "Crear X" bajo cada parte vacía. */}
      <PartySelectorModal type={partes.picker} open={!!partes.picker}
      onClose={partes.closePicker} onPick={partes.handlePick} allowCrear={false} />

      <RecordFormModal
        type={crearTipo === 'paciente' ? 'particular' : crearTipo}
        open={!!crearTipo}
        onClose={() => setCrearTipo(null)}
        onCreated={handleParteCreada}
      />

      {partes.delNuevo &&
      <ConfirmDeleteModal
        title={partes.delNuevo.type === 'entidad' ? '¿Eliminar entidad?' : partes.delNuevo.type === 'medico' ? '¿Eliminar médico?' : '¿Eliminar paciente?'}
        itemName={partes.delNuevo.type === 'entidad' ? partes.delNuevo.record.razonSocial : `${partes.delNuevo.record.titulo ? partes.delNuevo.record.titulo + ' ' : ''}${partes.delNuevo.record.nombre} ${partes.delNuevo.record.apellido}`}
        description="Se va a borrar este registro que creaste y se quitará del expediente. Esta acción no se puede deshacer."
        confirmLabel="Sí, eliminar"
        onCancel={() => partes.setDelNuevo(null)}
        onConfirm={() => partes.confirmDeleteNuevo(partes.delNuevo)} />

      }

      {delExp &&
      <ConfirmDeleteModal
        title="¿Eliminar expediente?"
        itemName={`${exp.publicId || 'EXP-… (asignando)'}${par && par.nombre ? ' · ' + `${par.nombre} ${par.apellido || ''}`.trim() : ''}`}
        description="Se va a borrar este expediente y todo lo cargado en él. Esta acción no se puede deshacer."
        confirmLabel="Sí, eliminar"
        onCancel={() => setDelExp(false)}
        onConfirm={confirmDeleteExp} />

      }

      {/* Toast de confirmación */}
      {toast &&
      <div
        className="fixed bottom-6 right-6 z-50 flex items-center gap-3 rounded-xl px-4 py-3 animate-fade-in-up"
        style={{
          background: 'var(--card)',
          border: '1px solid color-mix(in oklab, var(--accent) 45%, transparent)',
          boxShadow: '0 18px 50px -14px rgba(8, 20, 24, 0.5)',
          maxWidth: 'min(92vw, 380px)'
        }}>
          <span className="inline-flex items-center justify-center rounded-lg flex-shrink-0"
        style={{ width: 30, height: 30, background: 'color-mix(in oklab, var(--accent) 16%, transparent)', color: 'var(--accent)' }}>
            <IconCheck size={16} />
          </span>
          <p className="text-[12.5px] font-bold truncate" style={{ color: 'var(--foreground)' }}>
            {toast}
          </p>
        </div>
      }
    </div>);

}

Object.assign(window, { ExpedienteDetailScreen });
