// ─── Micos CRM · Inbox (lista de correos) ──────────

const { useState: _useStateCI, useMemo: _useMemoCI, useEffect: _useEffectCI } = React;

// ─── Sparkline (replica del ERP, nombre propio para no colisionar) ──
function CrmSparkline({ data, positive = true, width = 90, height = 36 }) {
  if (!data || data.length < 2) return null;
  const max = Math.max(...data), min = Math.min(...data);
  const range = max - min || 1;
  const stepX = width / (data.length - 1);
  const pts = data.map((v, i) => [i * stepX, height - ((v - min) / range) * (height - 4) - 2]);
  const line = pts.map(([x, y], i) => (i === 0 ? `M${x},${y}` : `L${x},${y}`)).join(' ');
  const area = `${line} L${width},${height} L0,${height} Z`;
  const stroke = positive ? 'var(--accent)' : 'var(--danger)';
  const gid = 'crm-spark-' + Math.random().toString(36).slice(2, 8);
  return (
    <svg width={width} height={height} viewBox={`0 0 ${width} ${height}`} className="absolute bottom-3 right-3 pointer-events-none opacity-90" aria-hidden="true">
      <defs>
        <linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={stroke} stopOpacity="0.32" />
          <stop offset="100%" stopColor={stroke} stopOpacity="0" />
        </linearGradient>
      </defs>
      <path d={area} fill={`url(#${gid})`} />
      <path d={line} fill="none" stroke={stroke} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

// ─── KPI tile (replica del ERP) ────────────────────
function CrmKpiCard({ label, value, delta, deltaTone = 'pos', icon: Icon, trend }) {
  const c = {
    pos:  ['var(--success)', 'rgba(5,150,105,0.10)',  'rgba(5,150,105,0.22)'],
    neg:  ['var(--danger)', 'rgba(220,38,38,0.10)',  'rgba(220,38,38,0.22)'],
    warn: ['#b45309', 'rgba(180,83,9,0.10)',   'rgba(180,83,9,0.22)'],
    neutral: ['var(--muted-foreground)', 'color-mix(in oklab, var(--muted-foreground) 10%, transparent)', 'color-mix(in oklab, var(--muted-foreground) 22%, transparent)'],
  }[deltaTone] || ['var(--success)', 'rgba(5,150,105,0.10)', 'rgba(5,150,105,0.22)'];
  return (
    <div className="kpi-card-tile relative rounded-2xl p-5 sm:p-6 transition-all duration-300 overflow-hidden"
      style={{ background: 'var(--card)', border: '1px solid color-mix(in oklab, var(--border) 60%, transparent)', boxShadow: 'var(--shadow-card)' }}>
      {trend && trend.length > 1 && <CrmSparkline data={trend} positive={deltaTone !== 'neg'} />}
      <div className="relative flex items-start justify-between gap-3">
        <p className="text-[10.5px] font-bold uppercase tracking-[0.14em]" style={{ color: 'var(--muted-foreground)' }}>{label}</p>
        {Icon && (
          <span className="inline-flex items-center justify-center rounded-xl flex-shrink-0"
            style={{ width: 34, height: 34, background: 'color-mix(in oklab, var(--accent) 12%, transparent)', color: 'var(--accent)' }}>
            <Icon size={16} />
          </span>
        )}
      </div>
      <p className="relative text-[clamp(26px,4vw,34px)] font-extrabold tabular-nums tracking-tight leading-none mt-4" style={{ color: 'var(--foreground)' }}>{value}</p>
      {delta && (
        <div className="relative mt-4">
          <span className="inline-flex items-center gap-1 px-2 py-1 rounded-md text-[11px] font-bold tabular-nums"
            style={{ background: c[1], border: '1px solid ' + c[2], color: c[0] }}>
            {delta}
          </span>
        </div>
      )}
    </div>
  );
}

// ─── Blindaje: último mensaje de un hilo ───────────
// RLS filtra mensajes `visibilidad='privada'` que no son del usuario actual
// (ni ADMIN/JEFE los ven) — un hilo visible en `crm_hilos` puede llegar con
// `messages: []` para ESE usuario puntual si el único mensaje era privado
// entre otros dos. Nunca asumimos que hay al menos uno; se usa en toda la
// bandeja (y la exponemos para que crm-app.jsx/crm-thread.jsx reusen el mismo
// blindaje en vez de indexar `messages[length-1]` a mano).
function _crmLastMsg(email) {
  const msgs = (email && email.messages) || [];
  return msgs[msgs.length - 1] || {
    from: { nombre: '', email: '' }, to: [], cc: [],
    fecha: new Date(0).toISOString(), cuerpo: '',
  };
}

// Filtros rápidos (lo demás vive en el panel lateral)
const CRM_QUICK_FILTERS = [
  { key: 'leidos',    label: 'Leídos',    test: (e) => !e.unread },
  { key: 'no-leidos', label: 'No leídos', test: (e) => e.unread },
];

// Toolbar above the email list (modo compacto). `allSel`/`someSel` (aud. #10):
// tildado solo con TODOS seleccionados, intermedio con algunos. `onSnooze`
// recibe el ISO del selector de Posponer (aud. #9).
function InboxToolbar({ selectedIds, allSel, someSel, onSelectAll, onClearSel, onArchive, unarchive, onTrash, onMarkRead, onSnooze, isTrash, onRestore, total }) {
  const hasSel = selectedIds.length > 0;
  return (
    <div
      className="flex items-center gap-2.5 px-4 sm:px-5 py-3"
      style={{ borderBottom: '1px solid var(--border)', background: 'var(--background)' }}
    >
      <label className="inline-flex items-center cursor-pointer" title="Seleccionar todo">
        <input
          type="checkbox"
          className="cc-check"
          ref={(el) => { if (el) el.indeterminate = !!someSel; }}
          checked={!!allSel}
          onChange={(e) => e.target.checked ? onSelectAll() : onClearSel()}
        />
      </label>

      {hasSel ? isTrash ? (
        <>
          <button type="button" onClick={onRestore} className="btn btn-ghost h-8" title="Restaurar">
            <IconInbox size={14} />
            <span className="text-[12px]">Restaurar</span>
          </button>
          <span className="text-[11.5px] ml-2" style={{ color: 'var(--muted-foreground)' }}>
            {selectedIds.length} seleccionado{selectedIds.length === 1 ? '' : 's'}
          </span>
        </>
      ) : (
        <>
          <button type="button" onClick={onArchive} className="btn btn-ghost h-8" title={unarchive ? 'Desarchivar' : 'Archivar'}>
            {unarchive ? <IconInbox size={14} /> : <IconArchive size={14} />}
            <span className="text-[12px]">{unarchive ? 'Desarchivar' : 'Archivar'}</span>
          </button>
          <button type="button" onClick={onMarkRead} className="btn btn-ghost h-8" title="Marcar leído">
            <IconCheck size={14} />
            <span className="text-[12px]">Leído</span>
          </button>
          <SnoozeMenu onSnooze={onSnooze} />
          <button type="button" onClick={onTrash} className="btn btn-ghost h-8" title="Eliminar">
            <IconTrash size={14} />
            <span className="text-[12px]">Eliminar</span>
          </button>
          <span className="text-[11.5px] ml-2" style={{ color: 'var(--muted-foreground)' }}>
            {selectedIds.length} seleccionado{selectedIds.length === 1 ? '' : 's'}
          </span>
        </>
      ) : (
        <>
          <span className="text-[10.5px] font-bold uppercase tracking-[0.16em]" style={{ color: 'color-mix(in oklab, var(--muted-foreground) 80%, transparent)' }}>
            Registros
          </span>
          <span className="text-[12px] font-bold tabular-nums" style={{ color: 'var(--foreground)' }}>
            {total}
          </span>
        </>
      )}
    </div>
  );
}

function SortDropdown({ sortBy, onSort }) {
  const [open, setOpen] = _useStateCI(false);
  const opts = [
    { key: 'fecha',    label: 'Más recientes' },
    { key: 'sla',      label: 'SLA (urgente)' },
    { key: 'unread',   label: 'No leídos' },
    { key: 'important',label: 'Importantes' },
  ];
  const current = opts.find(o => o.key === sortBy) || opts[0];
  return (
    <div className="relative">
      <button
        type="button"
        onClick={() => setOpen(o => !o)}
        className="btn btn-ghost h-8 text-[12px]"
        style={{ color: 'var(--muted-foreground)' }}
      >
        <IconFilter size={13} />
        <span>{current.label}</span>
        <IconChevronDown size={12} />
      </button>
      {open && (
        <>
          <div className="fixed inset-0 z-20" onClick={() => setOpen(false)} />
          <div
            className="absolute right-0 top-full mt-1 z-30 py-1 rounded-lg"
            style={{
              background: 'var(--card)',
              border: '1px solid var(--border)',
              boxShadow: 'var(--shadow-lg)',
              minWidth: 180,
            }}
          >
            {opts.map(o => (
              <button
                key={o.key}
                type="button"
                onClick={() => { onSort(o.key); setOpen(false); }}
                className="w-full text-left px-3 py-1.5 text-[12.5px] cursor-pointer flex items-center gap-2"
                style={{
                  color: o.key === sortBy ? 'var(--accent)' : 'var(--foreground)',
                  fontWeight: o.key === sortBy ? 700 : 500,
                }}
                onMouseEnter={(e) => e.currentTarget.style.background = 'var(--surface)'}
                onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
              >
                <span style={{ width: 12 }}>{o.key === sortBy && <IconCheck size={12} />}</span>
                {o.label}
              </button>
            ))}
          </div>
        </>
      )}
    </div>
  );
}

// ─── Menú desplegable genérico de acción masiva (mismo look que SortDropdown) ──
function _BulkMenu({ trigger, children, open, setOpen, width = 230 }) {
  return (
    <div className="relative">
      {trigger}
      {open && (
        <>
          <div className="fixed inset-0 z-20" onClick={() => setOpen(false)} />
          <div
            className="absolute left-0 top-full mt-1 z-30 py-1 rounded-lg"
            style={{ background: 'var(--card)', border: '1px solid var(--border)', boxShadow: 'var(--shadow-lg)', minWidth: width }}
          >
            {children}
          </div>
        </>
      )}
    </div>
  );
}

const _bulkItemStyle = { color: 'var(--foreground)', fontWeight: 500 };
function _BulkItem({ onClick, children, sub }) {
  return (
    <button
      type="button"
      onClick={onClick}
      className="w-full text-left px-3 py-2 text-[12.5px] cursor-pointer flex items-center gap-2"
      style={_bulkItemStyle}
      onMouseEnter={(e) => e.currentTarget.style.background = 'var(--surface)'}
      onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
    >
      <span className="flex-1">{children}</span>
      {sub && <span className="text-[11px] tabular-nums" style={{ color: 'var(--muted-foreground)' }}>{sub}</span>}
    </button>
  );
}

// ─── Posponer CON selector (auditoría 05/07 #9: era snooze sin snooze) ─────
// Presets con fecha concreta a la vista + "Elegir fecha y hora". onSnooze
// recibe el ISO de snooze_until.
function SnoozeMenu({ onSnooze }) {
  const [open, setOpen] = _useStateCI(false);
  const [custom, setCustom] = _useStateCI('');
  const presets = open ? crmSnoozePresets() : [];
  const elegir = (fecha) => { setOpen(false); setCustom(''); onSnooze(fecha.toISOString()); };
  return (
    <_BulkMenu
      open={open} setOpen={setOpen} width={250}
      trigger={
        <button type="button" onClick={() => setOpen(o => !o)} className="btn btn-ghost h-8" title="Posponer hasta…">
          <IconSnooze size={14} />
          <span className="text-[12px]">Posponer</span>
          <IconChevronDown size={11} />
        </button>
      }
    >
      <p className="px-3 pt-1.5 pb-1 text-[10.5px] font-bold uppercase tracking-[0.12em]" style={{ color: 'var(--muted-foreground)' }}>
        Volver a Recibidos…
      </p>
      {presets.map(p => (
        <_BulkItem key={p.key} onClick={() => elegir(p.fecha)} sub={crmFechaCorta(p.fecha)}>{p.label}</_BulkItem>
      ))}
      <div className="px-3 py-2 flex items-center gap-2" style={{ borderTop: '1px solid color-mix(in oklab, var(--border) 50%, transparent)' }}>
        <input
          type="datetime-local"
          value={custom}
          onChange={(e) => setCustom(e.target.value)}
          className="flex-1 min-w-0 h-8 px-2 rounded-lg text-[12px] font-medium 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)' }}
        />
        <button
          type="button"
          className="btn btn-primary h-8 px-2.5 text-[11.5px]"
          disabled={!custom || isNaN(new Date(custom).getTime()) || new Date(custom).getTime() <= Date.now()}
          onClick={() => elegir(new Date(custom))}
        >
          Listo
        </button>
      </div>
    </_BulkMenu>
  );
}

// ─── Etiquetar en masa (cierra el ciclo crear→ASIGNAR→filtrar, aud. #6) ────
function EtiquetarMenu({ etiquetas, emails, selectedIds, onToggle }) {
  const [open, setOpen] = _useStateCI(false);
  const sel = (emails || []).filter(e => selectedIds.includes(e.id));
  return (
    <_BulkMenu
      open={open} setOpen={setOpen} width={220}
      trigger={
        <button type="button" onClick={() => setOpen(o => !o)} className="btn btn-ghost h-8" title="Etiquetar seleccionados">
          <IconTag size={14} />
          <span className="text-[12px]">Etiquetar</span>
          <IconChevronDown size={11} />
        </button>
      }
    >
      {(etiquetas || []).length === 0 ? (
        <p className="px-3 py-2.5 text-[12px]" style={{ color: 'var(--muted-foreground)' }}>
          No hay etiquetas todavía. Creá una con el + de "Etiquetas" en el panel izquierdo.
        </p>
      ) : (
        etiquetas.map(et => {
          const laTienenTodos = sel.length > 0 && sel.every(e => (e.etiquetasIds || []).includes(et.id));
          return (
            <_BulkItem key={et.id} onClick={() => { onToggle(et.id); setOpen(false); }}>
              <span className="inline-flex items-center gap-2">
                <span style={{ width: 10, height: 10, borderRadius: 3, background: et.color || 'var(--muted-foreground)', display: 'inline-block', flexShrink: 0 }} />
                <span>{et.nombre}</span>
                {laTienenTodos && <IconCheck size={12} style={{ color: 'var(--accent)' }} />}
              </span>
            </_BulkItem>
          );
        })
      )}
    </_BulkMenu>
  );
}

// ─── Chips clickeables del buscador: persona / etiqueta / fecha ────────────
// Sin sintaxis tipeada (auditoría #5): tres desplegables que se combinan con
// el texto libre. El estado vive en crm/app.jsx (searchChips).
function SearchChipsRow({ emails, etiquetas, chips, onSetChips }) {
  const [openMenu, setOpenMenu] = _useStateCI(null); // 'persona' | 'etiqueta' | 'fecha' | null
  const [personaQ, setPersonaQ] = _useStateCI('');

  // Remitentes únicos (externos primero, por frecuencia) para el chip Persona.
  const personas = _useMemoCI(() => {
    const map = new Map();
    (emails || []).forEach(e => (e.messages || []).forEach(m => {
      const em = (m.from && m.from.email || '').toLowerCase();
      if (!em) return;
      const cur = map.get(em) || { email: em, nombre: (m.from.nombre || em), n: 0 };
      cur.n += 1;
      map.set(em, cur);
    }));
    return [...map.values()].sort((a, b) => b.n - a.n);
  }, [emails]);
  const personasVisibles = personaQ.trim()
    ? personas.filter(p => p.nombre.toLowerCase().includes(personaQ.toLowerCase()) || p.email.includes(personaQ.toLowerCase()))
    : personas.slice(0, 12);

  const setChip = (patch) => { onSetChips(c => ({ ...c, ...patch })); setOpenMenu(null); setPersonaQ(''); };

  const hoyISO = () => new Date().toISOString().slice(0, 10);
  const haceDiasISO = (n) => { const d = new Date(); d.setDate(d.getDate() - n); return d.toISOString().slice(0, 10); };

  const chipStyle = (active) => active
    ? { background: 'color-mix(in oklab, var(--accent) 14%, transparent)', color: 'var(--accent)', border: '1px solid color-mix(in oklab, var(--accent) 35%, transparent)' }
    : { background: 'color-mix(in oklab, var(--muted-foreground) 8%, transparent)', color: 'var(--muted-foreground)', border: '1px solid transparent' };

  const etiquetaCfg = chips.etiqueta
    ? (CRM_LABELS[chips.etiqueta] ? { nombre: CRM_LABELS[chips.etiqueta].label } : (etiquetas || []).find(x => x.id === chips.etiqueta))
    : null;

  const fechaLabel = chips.desde && chips.hasta && chips.desde === chips.hasta ? 'Hoy'
    : chips.desde || chips.hasta
      ? `${chips.desde ? chips.desde.split('-').reverse().join('/') : '…'} – ${chips.hasta ? chips.hasta.split('-').reverse().join('/') : 'hoy'}`
      : null;

  const renderMenu = (key, children, width) => openMenu === key && (
    <>
      <div className="fixed inset-0 z-20" onClick={() => setOpenMenu(null)} />
      <div className="absolute left-0 top-full mt-1 z-30 py-1 rounded-lg" style={{ background: 'var(--card)', border: '1px solid var(--border)', boxShadow: 'var(--shadow-lg)', minWidth: width }}>
        {children}
      </div>
    </>
  );

  return (
    <div className="flex items-center gap-2 px-5 py-2.5 flex-wrap" style={{ borderBottom: '1px solid color-mix(in oklab, var(--border) 40%, transparent)' }}>
      <span className="text-[10.5px] font-bold uppercase tracking-[0.14em]" style={{ color: 'color-mix(in oklab, var(--muted-foreground) 75%, transparent)' }}>
        Filtrar por
      </span>

      {/* Persona */}
      <div className="relative">
        <button type="button" className="chip" style={chipStyle(!!chips.persona)} onClick={() => setOpenMenu(o => o === 'persona' ? null : 'persona')}>
          {chips.persona ? `Persona: ${chips.personaNombre || chips.persona}` : 'Persona'}
          {chips.persona
            ? <span role="button" tabIndex={0} className="inline-flex cursor-pointer" title="Quitar filtro" onClick={(e) => { e.stopPropagation(); setChip({ persona: null, personaNombre: null }); }}><IconX size={11} /></span>
            : <IconChevronDown size={11} />}
        </button>
        {renderMenu('persona', (
          <>
            <div className="px-2.5 pt-1.5 pb-1">
              <input
                autoFocus
                value={personaQ}
                onChange={(e) => setPersonaQ(e.target.value)}
                placeholder="Buscar persona…"
                className="w-full h-8 px-2.5 rounded-lg text-[12px] font-medium 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 style={{ maxHeight: 260, overflowY: 'auto' }}>
              {personasVisibles.length === 0 && <p className="px-3 py-2 text-[12px]" style={{ color: 'var(--muted-foreground)' }}>Sin resultados.</p>}
              {personasVisibles.map(p => (
                <_BulkItem key={p.email} onClick={() => setChip({ persona: p.email, personaNombre: p.nombre })} sub={String(p.n)}>
                  <span className="block truncate">{p.nombre}</span>
                  <span className="block truncate text-[10.5px]" style={{ color: 'var(--muted-foreground)' }}>{p.email}</span>
                </_BulkItem>
              ))}
            </div>
          </>
        ), 260)}
      </div>

      {/* Etiqueta */}
      <div className="relative">
        <button type="button" className="chip" style={chipStyle(!!chips.etiqueta)} onClick={() => setOpenMenu(o => o === 'etiqueta' ? null : 'etiqueta')}>
          {etiquetaCfg ? `Etiqueta: ${etiquetaCfg.nombre}` : 'Etiqueta'}
          {chips.etiqueta
            ? <span role="button" tabIndex={0} className="inline-flex cursor-pointer" title="Quitar filtro" onClick={(e) => { e.stopPropagation(); setChip({ etiqueta: null }); }}><IconX size={11} /></span>
            : <IconChevronDown size={11} />}
        </button>
        {renderMenu('etiqueta', (
          <>
            {Object.keys(CRM_LABELS).map(id => (
              <_BulkItem key={id} onClick={() => setChip({ etiqueta: id })}>{CRM_LABELS[id].label}</_BulkItem>
            ))}
            {(etiquetas || []).map(et => (
              <_BulkItem key={et.id} onClick={() => setChip({ etiqueta: et.id })}>
                <span className="inline-flex items-center gap-2">
                  <span style={{ width: 10, height: 10, borderRadius: 3, background: et.color || 'var(--muted-foreground)', display: 'inline-block' }} />
                  {et.nombre}
                </span>
              </_BulkItem>
            ))}
          </>
        ), 210)}
      </div>

      {/* Fecha */}
      <div className="relative">
        <button type="button" className="chip" style={chipStyle(!!fechaLabel)} onClick={() => setOpenMenu(o => o === 'fecha' ? null : 'fecha')}>
          {fechaLabel ? `Fecha: ${fechaLabel}` : 'Fecha'}
          {fechaLabel
            ? <span role="button" tabIndex={0} className="inline-flex cursor-pointer" title="Quitar filtro" onClick={(e) => { e.stopPropagation(); setChip({ desde: null, hasta: null }); }}><IconX size={11} /></span>
            : <IconChevronDown size={11} />}
        </button>
        {renderMenu('fecha', (
          <>
            <_BulkItem onClick={() => setChip({ desde: hoyISO(), hasta: hoyISO() })}>Hoy</_BulkItem>
            <_BulkItem onClick={() => setChip({ desde: haceDiasISO(7), hasta: null })}>Últimos 7 días</_BulkItem>
            <_BulkItem onClick={() => setChip({ desde: haceDiasISO(30), hasta: null })}>Últimos 30 días</_BulkItem>
            <div className="px-3 py-2 space-y-1.5" style={{ borderTop: '1px solid color-mix(in oklab, var(--border) 50%, transparent)' }}>
              <label className="flex items-center gap-2 text-[11.5px] font-semibold" style={{ color: 'var(--muted-foreground)' }}>
                Desde
                <input type="date" defaultValue={chips.desde || ''} onChange={(e) => onSetChips(c => ({ ...c, desde: e.target.value || null }))}
                  className="flex-1 h-8 px-2 rounded-lg text-[12px] 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)' }} />
              </label>
              <label className="flex items-center gap-2 text-[11.5px] font-semibold" style={{ color: 'var(--muted-foreground)' }}>
                Hasta
                <input type="date" defaultValue={chips.hasta || ''} onChange={(e) => onSetChips(c => ({ ...c, hasta: e.target.value || null }))}
                  className="flex-1 h-8 px-2 rounded-lg text-[12px] 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)' }} />
              </label>
              <div className="flex justify-end">
                <button type="button" className="btn btn-primary h-8 px-2.5 text-[11.5px]" onClick={() => setOpenMenu(null)}>Listo</button>
              </div>
            </div>
          </>
        ), 230)}
      </div>
    </div>
  );
}

// Smart view banner (shows description above list when active)
function SmartViewBanner({ view }) {
  if (!view) return null;
  return (
    <div
      className="px-4 py-3 flex items-center gap-3"
      style={{
        borderBottom: '1px solid var(--border)',
        background: `color-mix(in oklab, ${view.accent} 6%, transparent)`,
      }}
    >
      <div style={{
        width: 32, height: 32, borderRadius: 10,
        background: `color-mix(in oklab, ${view.accent} 18%, transparent)`,
        color: view.accent,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        flexShrink: 0,
      }}>
        {(() => {
          const Icon = CRM_ICON_MAP[view.icon] || IconSparkles;
          return <Icon size={16} />;
        })()}
      </div>
      <div className="min-w-0">
        <p className="text-[13px] font-extrabold" style={{ color: 'var(--foreground)' }}>{view.label}</p>
        <p className="text-[11.5px] mt-0.5" style={{ color: 'var(--muted-foreground)' }}>{view.description}</p>
      </div>
    </div>
  );
}

// Etiqueta banner (shows label description above list when active).
// Las etiquetas del equipo (crm_etiquetas) traen colorHex plano de la DB.
function LabelBanner({ label, count }) {
  if (!label) return null;
  const palette = {
    presupuesto: 'var(--pipeline-presupuesto)', remito: 'var(--pipeline-remito)',
    'doc-medica': 'var(--pipeline-doc-medica)', recibo: 'var(--pipeline-recibo)',
    oc: 'var(--pipeline-oc)', factura: 'var(--pipeline-factura)',
    iniciado: 'var(--pipeline-iniciado)', destructive: 'var(--danger)',
    neutral: 'var(--muted-foreground)',
  };
  const color = label.colorHex || palette[label.tone] || palette.neutral;
  return (
    <div
      className="px-4 py-3 flex items-center gap-3"
      style={{ borderBottom: '1px solid var(--border)', background: `color-mix(in oklab, ${color} 6%, transparent)` }}
    >
      <div style={{
        width: 32, height: 32, borderRadius: 10,
        background: `color-mix(in oklab, ${color} 16%, transparent)`,
        display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
      }}>
        <span style={{ width: 13, height: 13, borderRadius: 4, background: color, display: 'block' }} />
      </div>
      <div className="min-w-0">
        <p className="text-[13px] font-extrabold" style={{ color: 'var(--foreground)' }}>{label.label}</p>
        <p className="text-[11.5px] mt-0.5" style={{ color: 'var(--muted-foreground)' }}>
          {label.desc || `${count} conversación${count === 1 ? '' : 'es'} con esta etiqueta.`}
        </p>
      </div>
    </div>
  );
}

// ─── Estado / referencia helpers (lenguaje de expediente) ──
// Cada correo se presenta como un registro del ERP: una referencia mono
// (expediente vinculado o nº de correspondencia) + un estado de workflow.
const _ESTADO_PALETTE = {
  presupuesto: ['var(--pipeline-presupuesto-bg)', 'var(--pipeline-presupuesto)'],
  remito:      ['var(--pipeline-remito-bg)',      'var(--pipeline-remito)'],
  recibo:      ['var(--pipeline-recibo-bg)',      'var(--pipeline-recibo)'],
  oc:          ['var(--pipeline-oc-bg)',          'var(--pipeline-oc)'],
  factura:     ['var(--pipeline-factura-bg)',     'var(--pipeline-factura)'],
  iniciado:    ['var(--pipeline-iniciado-bg)',    'var(--pipeline-iniciado)'],
  destructive: ['rgba(220, 38, 38, 0.12)',        'var(--danger)'],
  neutral:     ['color-mix(in oklab, var(--muted-foreground) 14%, transparent)', 'var(--muted-foreground)'],
};

function emailEstado(e) {
  if (e.folder === 'drafts')                                   return { key: 'borrador',   label: 'Borrador',   tone: 'neutral' };
  if (e.tags.includes('reclamo'))                              return { key: 'reclamo',    label: 'Reclamo',    tone: 'destructive' };
  if (e.tags.includes('aprobacion'))                           return { key: 'aprobacion', label: 'Aprobación', tone: 'oc' };
  if (e.slaHours >= 24 && e.lastFrom === 'external')           return { key: 'vencido',    label: 'Vencido',    tone: 'destructive' };
  if (e.folder === 'sent' || e.lastFrom === 'me')              return { key: 'respondido', label: 'Respondido', tone: 'recibo' };
  if (e.unread)                                                return { key: 'nuevo',      label: 'Nuevo',      tone: 'iniciado' };
  return { key: 'en-curso', label: 'En curso', tone: 'presupuesto' };
}

// Mono reference: expediente vinculado, o nº de correspondencia derivado.
function emailRef(e) {
  if (e.linkedExpedienteId) return { id: e.linkedExpedienteId, tipo: 'Expediente' };
  const n = (e.id.match(/\d+/) || ['0'])[0];
  return { id: 'COR-' + String(n).padStart(8, '0'), tipo: 'Correspondencia' };
}

// ERP-style status pill
function EstadoPill({ estado }) {
  const [bg, fg] = _ESTADO_PALETTE[estado.tone] || _ESTADO_PALETTE.neutral;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      background: bg, color: fg,
      padding: '4px 11px', borderRadius: 999,
      fontSize: 10.5, fontWeight: 800, letterSpacing: '0.06em',
      textTransform: 'uppercase', whiteSpace: 'nowrap',
    }}>
      <span style={{ width: 5, height: 5, borderRadius: 999, background: fg, display: 'block' }} />
      {estado.label}
    </span>
  );
}

// Source/canal label for the contacto sub-line
function emailCanal(e) {
  const t = e.linkedEntityType;
  if (t === 'medico')    return 'Médico derivante';
  if (t === 'entidad')   return 'Entidad / cliente';
  if (t === 'proveedor') return 'Proveedor';
  if (t === 'interno')   return 'Interno · Micos';
  if (t === 'externo')   return 'Organismo externo';
  return 'Contacto';
}

// Column template for the expediente-style record grid
const CRM_COL_TEMPLATE = '24px 120px minmax(86px,1fr) minmax(104px,1.6fr) 130px';
const CRM_COL_GAP = 12;

// Pill de etiqueta del equipo (crm_etiquetas): misma silueta que LabelPill
// pero con el color hex de la DB. Los ids huérfanos (etiqueta soft-borrada)
// no se pintan — lookup contra el catálogo, contrato B0.
function EtiquetaPill({ id, etiquetas, size = 'xs' }) {
  const et = (etiquetas || []).find(x => x.id === id);
  if (!et) return null;
  const color = et.color || 'var(--muted-foreground)';
  const sizing = size === 'xs'
    ? { padding: '3px 11px', fontSize: '10px' }
    : { padding: '4px 12px', fontSize: '10.5px' };
  return (
    <span className="pill" style={{
      ...sizing,
      whiteSpace: 'nowrap',
      background: `color-mix(in oklab, ${color} 14%, transparent)`,
      color,
    }}>
      {et.nombre}
    </span>
  );
}

// ─── Email record row (presentado como expediente del ERP) ──
function EmailRow({ email, selected, isOpen, compact, onSelect, onToggleSel, onToggleStar, etiquetas, showSnoozeChip }) {
  const lastMsg = _crmLastMsg(email);
  const isUnread = email.unread;
  const fechaIso = lastMsg.fecha;
  const slaTone = email.slaHours >= 48 ? 'var(--danger)' : email.slaHours >= 24 ? 'var(--warning)' : null;

  // Hora primero (24hs, regla de la casa); si pasaron 24h o más, hora · día ("28 may")
  const _d = new Date(fechaIso);
  const _diffH = (Date.now() - _d.getTime()) / 3600000;
  const _hh = String(_d.getHours()).padStart(2, '0');
  const _min = String(_d.getMinutes()).padStart(2, '0');
  const _hhmm = `${_hh}:${_min}`;
  const _mes = _d.toLocaleDateString('es-AR', { month: 'short' }).replace(/\.$/, '');
  const _dia = `${_d.getDate()} ${_mes}`;
  const fechaLabel = _diffH < 24 ? _hhmm : `${_hhmm} · ${_dia}`;
  const tagList = (email.tags || []).filter(t => CRM_LABELS[t]).slice(0, 3);
  const adjuntos = email.adjuntos || [];

  // Asunto + extracto en una sola línea (estilo Gmail)
  const SubjectLine = ({ size = 13 }) => (
    <span className="truncate min-w-0 block" style={{ fontSize: size }}>
      <span style={{ fontWeight: isUnread ? 700 : 400, color: 'var(--foreground)' }}>{email.asunto}</span>
      <span style={{ color: 'var(--muted-foreground)', fontWeight: 400 }}>{'  —  '}{email.snippet}</span>
    </span>
  );

  const StarBtn = ({ s = 14 }) => (
    <button
      type="button"
      onClick={(e) => { e.stopPropagation(); onToggleStar(email.id); }}
      style={{ color: email.starred ? '#f5b301' : 'color-mix(in oklab, var(--muted-foreground) 42%, transparent)', cursor: 'pointer', display: 'inline-flex', flexShrink: 0 }}
      title={email.starred ? 'Quitar de destacados' : 'Destacar'}
    >
      {email.starred ? <IconStarFilled size={s} /> : <IconStar size={s} />}
    </button>
  );

  // Etiquetas (debajo del título): seed (tags legacy) + las del equipo
  // (etiquetasIds → crm_etiquetas, con su color de la DB).
  const etiquetaIds = (email.etiquetasIds || []).slice(0, 3);
  const TagRow = () => (tagList.length === 0 && etiquetaIds.length === 0) ? null : (
    <div className="flex items-center gap-1.5 flex-wrap">
      {tagList.map(t => <LabelPill key={t} id={t} size="xs" />)}
      {etiquetaIds.map(id => <EtiquetaPill key={id} id={id} etiquetas={etiquetas} size="xs" />)}
    </div>
  );

  // Adjuntos (debajo de las etiquetas)
  const AttachmentRow = () => adjuntos.length === 0 ? null : (
    <div className="flex items-center gap-1.5 flex-wrap">
      {adjuntos.map((a, i) => (
        <span
          key={i}
          role="button"
          tabIndex={0}
          onClick={(e) => { e.stopPropagation(); window.openDoc && window.openDoc(a, email); }}
          onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); window.openDoc && window.openDoc(a, email); } }}
          className="inline-flex items-center gap-1.5 cursor-pointer transition-colors"
          style={{
            fontSize: 10.5, fontWeight: 600,
            color: 'color-mix(in oklab, var(--foreground) 78%, transparent)',
            background: 'color-mix(in oklab, var(--muted-foreground) 10%, transparent)',
            border: '1px solid color-mix(in oklab, var(--border) 60%, transparent)',
            padding: '2px 8px 2px 6px', borderRadius: 6, maxWidth: 220,
          }}
          onMouseEnter={(e) => { e.currentTarget.style.borderColor = 'color-mix(in oklab, var(--accent) 45%, var(--border))'; e.currentTarget.style.color = 'var(--accent)'; }}
          onMouseLeave={(e) => { e.currentTarget.style.borderColor = 'color-mix(in oklab, var(--border) 60%, transparent)'; e.currentTarget.style.color = 'color-mix(in oklab, var(--foreground) 78%, transparent)'; }}
          title={`Abrir ${a.nombre}`}
        >
          <IconPaperclip size={11} style={{ opacity: 0.65, flexShrink: 0 }} />
          <span className="truncate">{a.nombre}</span>
        </span>
      ))}
    </div>
  );

  // ── Compact (lista maestra de 380px) — estilo Gmail móvil ──
  if (compact) {
    return (
      <div
        className="exp-row group cursor-pointer"
        onClick={() => onSelect(email.id)}
        style={{
          display: 'flex', flexDirection: 'column', gap: 6,
          padding: '12px 16px',
          borderBottom: '1px solid color-mix(in oklab, var(--border) 50%, transparent)',
          background: isOpen ? 'color-mix(in oklab, var(--accent) 7%, transparent)' : (isUnread ? 'color-mix(in oklab, var(--accent) 3%, transparent)' : 'transparent'),
          position: 'relative',
        }}
      >
        <div className="flex items-center gap-2 min-w-0">
          <StarBtn s={13} />
          {isUnread && <span style={{ width: 6, height: 6, borderRadius: 999, background: 'var(--accent)', flexShrink: 0 }} />}
          <span className={`truncate text-[12.5px] flex-1 ${isUnread ? 'font-extrabold' : 'font-normal'}`} style={{ color: isUnread ? 'var(--foreground)' : 'color-mix(in oklab, var(--foreground) 82%, transparent)' }}>
            {lastMsg.from.nombre}
          </span>
          <span className="text-[10.5px] tabular-nums flex-shrink-0 whitespace-nowrap" style={{ color: 'var(--muted-foreground)', fontWeight: 600 }}>{fechaLabel}</span>
        </div>
        <div className="flex flex-col gap-1.5 min-w-0 pl-[21px]">
          <SubjectLine size={12.5} />
          <TagRow />
          <AttachmentRow />
        </div>
      </div>
    );
  }

  // ── Full (estilo Gmail de escritorio) ──
  return (
    <div
      className="exp-row group cursor-pointer"
      onClick={() => onSelect(email.id)}
      style={{
        display: 'grid',
        gridTemplateColumns: 'auto auto 168px minmax(0,1fr) auto',
        alignItems: 'start',
        columnGap: 14,
        padding: '13px 20px',
        borderBottom: '1px solid color-mix(in oklab, var(--border) 45%, transparent)',
        background: isOpen ? 'color-mix(in oklab, var(--accent) 7%, transparent)' : (isUnread ? 'color-mix(in oklab, var(--accent) 3%, transparent)' : 'transparent'),
        position: 'relative',
      }}
    >
      {/* Checkbox */}
      <input
        type="checkbox"
        className="cc-check"
        checked={selected}
        onClick={(e) => e.stopPropagation()}
        onChange={() => onToggleSel(email.id)}
        style={{ marginTop: 2 }}
      />

      {/* Estrella */}
      <span style={{ marginTop: 1 }}><StarBtn s={15} /></span>

      {/* Remitente (columna fija) */}
      <span
        className={`truncate text-[13.5px] ${isUnread ? 'font-extrabold' : 'font-normal'}`}
        style={{ marginTop: 1, color: isUnread ? 'var(--foreground)' : 'color-mix(in oklab, var(--foreground) 80%, transparent)' }}
      >
        {lastMsg.from.nombre}
        {email.messages.length > 1 && (
          <span className="ml-1.5 text-[11px] tabular-nums" style={{ color: 'var(--muted-foreground)', fontWeight: 600 }}>
            {email.messages.length}
          </span>
        )}
      </span>

      {/* Contenido: asunto · etiquetas · adjuntos */}
      <div className="flex flex-col gap-2 min-w-0">
        <SubjectLine size={13.5} />
        <TagRow />
        <AttachmentRow />
      </div>

      {/* Hora + SLA (columna derecha) */}
      <div className="flex flex-col items-end gap-1.5" style={{ marginTop: 1 }}>
        <span
          className={`text-[11.5px] tabular-nums whitespace-nowrap ${isUnread ? 'font-extrabold' : 'font-normal'}`}
          style={{ color: isUnread ? 'var(--foreground)' : 'var(--muted-foreground)' }}
        >
          {fechaLabel}
        </span>
        {slaTone && (
          <span
            className="text-[9.5px] font-bold tabular-nums"
            style={{ color: slaTone, background: `color-mix(in oklab, ${slaTone} 12%, transparent)`, padding: '1px 5px', borderRadius: 4 }}
            title={`Sin responder hace ${email.slaHours}h`}
          >
            +{email.slaHours}h
          </span>
        )}
        {showSnoozeChip && crmSnoozeActivo(email) && (
          <span
            className="text-[9.5px] font-bold tabular-nums whitespace-nowrap"
            style={{ color: 'var(--accent)', background: 'color-mix(in oklab, var(--accent) 12%, transparent)', padding: '1px 5px', borderRadius: 4 }}
            title="Pospuesto — vuelve a Recibidos en esta fecha"
          >
            Vuelve {crmFechaCorta(email.snoozeUntil)}
          </span>
        )}
      </div>
    </div>
  );
}

// ─── Main inbox component ──────────────────────────
// `searchChips`/`onSetChips`: chips clickeables del buscador (persona/
// etiqueta/fecha — estado en crm/app.jsx para que el lector navegue la misma
// lista). `etiquetas`: catálogo de crm_etiquetas. `borradores`/`onOpenDraft`/
// `onDeleteDraft`: la bandeja Borradores real (/api/crm-borradores).
function CrmInbox({
  folder, smartView, labelFilter, activeLabel, search, searchChips, onSetChips, sortBy,
  emails, etiquetas, borradores, borradoresError, onOpenDraft, onDeleteDraft,
  onUpdateEmail, selectedIds, setSelectedIds,
  openEmailId, onOpenEmail, compact, onCompose, contextTitle,
}) {
  const [estadoFilter, setEstadoFilter] = _useStateCI(null);
  _useEffectCI(() => { setEstadoFilter(null); }, [folder, smartView, labelFilter]);

  const chips = searchChips || {};

  // Viendo la bandeja "Archivados": el botón de bulk-archivar pasa a Desarchivar
  // (vuelve a Recibidos) en vez de re-archivar lo que ya está archivado.
  const isArchivedFolder = folder === 'archived' && !smartView && !labelFilter;
  const toggleArchive = () => {
    const target = isArchivedFolder ? 'inbox' : 'archived';
    selectedIds.forEach(id => onUpdateEmail(id, { folder: target }));
    clearSel();
  };

  // Viendo la Papelera: no tiene sentido archivar/posponer/re-eliminar lo ya
  // eliminado — el bulk toolbar pasa a mostrar SOLO "Restaurar" (vuelve a
  // Recibidos, mismo criterio que "Desarchivar" arriba).
  const isTrashFolder = folder === 'trash' && !smartView && !labelFilter;
  const restoreSelected = () => {
    selectedIds.forEach(id => onUpdateEmail(id, { folder: 'inbox' }));
    clearSel();
  };

  // Viendo "Pospuestos": el bulk ofrece devolver a Recibidos (quita el snooze).
  const isScheduledFolder = folder === 'scheduled' && !smartView && !labelFilter;
  const unsnoozeSelected = () => {
    selectedIds.forEach(id => onUpdateEmail(id, { snoozeUntil: null, folder: 'inbox' }));
    clearSel();
  };

  // Posponer con fecha real (snooze_until per-usuario, contrato B0): saca el
  // hilo de Recibidos hasta esa fecha; vencida, reaparece solo.
  const snoozeSelected = (iso) => {
    selectedIds.forEach(id => onUpdateEmail(id, { snoozeUntil: iso }));
    clearSel();
  };

  // Bandeja "Borradores": muestra crm_borradores (del usuario), no hilos.
  const isDraftsFolder = folder === 'drafts' && !smartView && !labelFilter;

  // Vista "Para responder": pila de trabajo, el más viejo primero.
  const isParaResponder = folder === 'para-responder' && !smartView && !labelFilter;

  // Etiquetar en masa: toggle — si TODOS los seleccionados ya la tienen, se
  // la saca; si no, se la pone a los que falta (reemplazo completo del array,
  // contrato B0 etiquetasIds).
  const toggleEtiqueta = (etId) => {
    const sel = emails.filter(e => selectedIds.includes(e.id));
    const todosLaTienen = sel.length > 0 && sel.every(e => (e.etiquetasIds || []).includes(etId));
    sel.forEach(e => {
      const actuales = e.etiquetasIds || [];
      const nuevas = todosLaTienen ? actuales.filter(x => x !== etId) : (actuales.includes(etId) ? actuales : [...actuales, etId]);
      onUpdateEmail(e.id, { etiquetasIds: nuevas });
    });
  };

  // Filtro + orden UNIFICADOS con el lector (crm/data.js) — auditoría 05/07
  // #5/#7: una sola fuente de verdad; Spam ya filtra folder === 'spam' real.
  const filtered = _useMemoCI(() => {
    const result = crmFiltrarEmails(emails, {
      folder, smartView, labelFilter, search,
      persona: chips.persona, etiqueta: chips.etiqueta,
      desde: chips.desde, hasta: chips.hasta, etiquetas,
    });
    return crmOrdenarEmails(result, sortBy, (labelFilter || smartView) ? null : folder);
  }, [emails, folder, smartView, labelFilter, search, chips.persona, chips.etiqueta, chips.desde, chips.hasta, etiquetas, sortBy]);

  const activeView = smartView ? CRM_SMART_VIEWS.find(v => v.key === smartView) : null;

  const toggleSel = (id) => {
    setSelectedIds(sel => sel.includes(id) ? sel.filter(s => s !== id) : [...sel, id]);
  };
  const selectAll = () => setSelectedIds(displayed.map(e => e.id));
  const clearSel = () => setSelectedIds([]);
  const hasSel = selectedIds.length > 0;

  // Conteo por filtro rápido + lista filtrada
  const estadoCounts = _useMemoCI(() => {
    const c = {};
    CRM_QUICK_FILTERS.forEach(q => { c[q.key] = filtered.filter(q.test).length; });
    return c;
  }, [filtered]);
  const displayed = _useMemoCI(() => {
    const q = CRM_QUICK_FILTERS.find(x => x.key === estadoFilter);
    return q ? filtered.filter(q.test) : filtered;
  }, [filtered, estadoFilter]);

  // "Seleccionar todo" honesto (auditoría 05/07 #10): tildado SOLO si están
  // todos los visibles; algunos → estado intermedio (indeterminate nativo).
  const allSel = displayed.length > 0 && displayed.every(e => selectedIds.includes(e.id));
  const someSel = hasSel && !allSel;
  const selectAllRef = (el) => { if (el) el.indeterminate = someSel; };

  // KPIs (sobre la bandeja activa, antes del filtro de estado)
  const kpis = _useMemoCI(() => {
    const total = filtered.length;
    const sinLeer = filtered.filter(e => e.unread).length;
    const vencidos = filtered.filter(e => e.slaHours >= 24 && e.lastFrom === 'external').length;
    const atencion = filtered.filter(e => e.important || (e.tags || []).includes('reclamo') || (e.tags || []).includes('aprobacion')).length;
    return { total, sinLeer, vencidos, atencion };
  }, [filtered]);

  // ── Lista de registros (compartida) ──
  const renderRows = () => (
    displayed.length === 0 ? (
      <div className="flex flex-col items-center justify-center py-20 text-center px-6">
        <div style={{
          width: 56, height: 56, borderRadius: 16,
          background: 'color-mix(in oklab, var(--accent) 8%, var(--card))',
          color: 'var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 14,
        }}>
          {isParaResponder ? <IconCheckCircle size={26} /> : <IconInbox size={26} />}
        </div>
        <p className="text-[14px] font-extrabold" style={{ color: 'var(--foreground)' }}>
          {isParaResponder && !search.trim() && !estadoFilter ? 'Estás al día' : 'Sin registros'}
        </p>
        <p className="text-[12px] mt-1 max-w-xs" style={{ color: 'var(--muted-foreground)' }}>
          {search.trim() ? 'Probá con otra búsqueda.'
            : estadoFilter ? 'No hay registros con este estado.'
            : isParaResponder ? 'No hay correos esperando tu respuesta.'
            : (activeView?.description || 'Esta bandeja está vacía.')}
        </p>
      </div>
    ) : (
      <div className="stagger-rows">
        {displayed.map(e => (
          <EmailRow
            key={e.id}
            email={e}
            compact={compact}
            etiquetas={etiquetas}
            showSnoozeChip={isScheduledFolder}
            selected={selectedIds.includes(e.id)}
            isOpen={openEmailId === e.id}
            onSelect={(id) => { onOpenEmail(id); onUpdateEmail(id, { unread: false }); }}
            onToggleSel={toggleSel}
            onToggleStar={(id) => onUpdateEmail(id, { starred: !e.starred })}
          />
        ))}
      </div>
    )
  );

  // ── Bandeja Borradores (crm_borradores — clickear retoma el composer) ──
  const renderDrafts = () => (
    (borradores || []).length === 0 ? (
      <div className="flex flex-col items-center justify-center py-20 text-center px-6">
        <div style={{
          width: 56, height: 56, borderRadius: 16,
          background: 'color-mix(in oklab, var(--accent) 8%, var(--card))',
          color: 'var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 14,
        }}>
          <IconPencil size={26} />
        </div>
        <p className="text-[14px] font-extrabold" style={{ color: 'var(--foreground)' }}>
          {borradoresError ? 'No se pudieron cargar los borradores' : 'No hay borradores'}
        </p>
        <p className="text-[12px] mt-1 max-w-xs" style={{ color: 'var(--muted-foreground)' }}>
          {borradoresError ? 'Probá refrescar. Si sigue, avisale a sistemas.' : 'Lo que dejes a medias en Redactar queda guardado acá.'}
        </p>
      </div>
    ) : (
      <div className="stagger-rows">
        {borradores.map(b => (
          <div
            key={b.id}
            className="exp-row group cursor-pointer flex items-start gap-4"
            onClick={() => onOpenDraft && onOpenDraft(b)}
            style={{ padding: '13px 20px', borderBottom: '1px solid color-mix(in oklab, var(--border) 45%, transparent)' }}
            title="Seguir escribiendo"
          >
            <span className="text-[11px] font-extrabold uppercase tracking-[0.08em] flex-shrink-0" style={{ color: 'var(--pipeline-remito)', marginTop: 2 }}>
              Borrador
            </span>
            <div className="flex flex-col gap-1 min-w-0 flex-1">
              <span className="truncate text-[13.5px]">
                <span style={{ fontWeight: 700, color: 'var(--foreground)' }}>{b.asunto || 'Sin asunto'}</span>
                <span style={{ color: 'var(--muted-foreground)', fontWeight: 400 }}>{'  —  '}{(b.cuerpo || '').slice(0, 120) || 'Sin contenido'}</span>
              </span>
              <span className="truncate text-[11.5px]" style={{ color: 'var(--muted-foreground)' }}>
                {(b.para || []).length > 0 ? `Para: ${(b.para || []).join(', ')}` : 'Sin destinatario todavía'}
              </span>
            </div>
            <div className="flex items-center gap-2 flex-shrink-0" style={{ marginTop: 1 }}>
              <span className="text-[11.5px] tabular-nums whitespace-nowrap" style={{ color: 'var(--muted-foreground)' }}>
                {crmFechaCorta(b.updatedAt || b.createdAt)}
              </span>
              <button
                type="button"
                className="btn btn-ghost h-8 px-2 opacity-0 group-hover:opacity-100 transition-opacity"
                title="Descartar borrador"
                onClick={(e) => { e.stopPropagation(); if (window.confirm('¿Descartar este borrador?')) onDeleteDraft && onDeleteDraft(b.id); }}
              >
                <IconTrash size={13} />
              </button>
            </div>
          </div>
        ))}
      </div>
    )
  );

  // ── Modo compacto (lista maestra de 380px cuando hay un hilo abierto) ──
  if (compact) {
    return (
      <div className="flex-1 flex flex-col" style={{ minWidth: 0, background: 'var(--card)' }}>
        <SmartViewBanner view={activeView} />
        {labelFilter && activeLabel && <LabelBanner label={activeLabel} count={filtered.length} />}
        <InboxToolbar
          selectedIds={selectedIds}
          allSel={allSel}
          someSel={someSel}
          onSelectAll={selectAll}
          onClearSel={clearSel}
          onArchive={toggleArchive}
          unarchive={isArchivedFolder}
          onTrash={() => { selectedIds.forEach(id => onUpdateEmail(id, { folder: 'trash' })); clearSel(); }}
          isTrash={isTrashFolder}
          onRestore={restoreSelected}
          onMarkRead={() => { selectedIds.forEach(id => onUpdateEmail(id, { unread: false })); clearSel(); }}
          onSnooze={snoozeSelected}
          total={displayed.length}
        />
        <div className="flex-1 overflow-y-auto">{renderRows()}</div>
      </div>
    );
  }

  // ── Modo pantalla completa (estructura de la pantalla Expedientes del ERP) ──
  const subtitle = labelFilter
    ? (activeLabel?.desc || 'Correos con esta etiqueta.')
    : activeView
      ? activeView.description
      : isParaResponder
        ? 'Los correos que esperan una respuesta tuya, el que más espera primero. Respondé, archivá o posponé — cuando esta lista queda vacía, terminaste.'
        : isDraftsFolder
          ? 'Correos a medio escribir. Clickeá uno para seguir donde lo dejaste.'
          : isScheduledFolder
            ? 'Correos pospuestos: vuelven solos a Recibidos en la fecha elegida.'
            : 'Bandeja de correos vinculada a expedientes, entidades y médicos del ERP.';

  return (
    <div className="flex-1 overflow-y-auto" style={{ minWidth: 0, background: 'var(--background)' }}>
      <div className="px-4 sm:px-6 lg:px-8 pt-2 pb-12 space-y-7">
        {/* ── Header ───────────────────────────────── */}
        <div className="flex flex-wrap items-end justify-between gap-4 animate-fade-in-up pt-2">
          <div className="space-y-3 min-w-0">
            <p className="text-[11px] font-bold uppercase tracking-[0.18em]" style={{ color: 'var(--accent)' }}>
              Correos · Operaciones
            </p>
            <h1 className="text-[clamp(28px,4.2vw,40px)] leading-[1.05] font-extrabold tracking-[-0.02em]" style={{ color: 'var(--foreground)' }}>
              {contextTitle || 'Correos'}
            </h1>
            <p className="text-[13.5px] font-medium max-w-2xl" style={{ color: 'var(--muted-foreground)' }}>
              {subtitle}
            </p>
          </div>
          <div className="flex items-center gap-2.5 flex-shrink-0">
            <button className="btn btn-primary" type="button" onClick={onCompose}>
              <IconPencil size={15} />
              <span className="hidden sm:inline">Redactar</span>
              <span className="sm:hidden">Nuevo</span>
            </button>
          </div>
        </div>

        {/* ── Chips de estado (no aplican a Borradores) ── */}
        {!isDraftsFolder && (
        <div className="flex items-center gap-2 overflow-x-auto pb-1 scrollbar-none animate-fade-in-up" style={{ animationDelay: '180ms' }}>
          <button
            type="button"
            onClick={() => setEstadoFilter(null)}
            className="chip"
            style={!estadoFilter
              ? { background: 'var(--accent)', color: 'var(--accent-foreground)', boxShadow: '0 6px 18px -8px rgba(15,187,182,0.55)' }
              : { background: 'color-mix(in oklab, var(--muted-foreground) 8%, transparent)', color: 'var(--muted-foreground)' }}
          >
            Todos
            <span className="opacity-70 tabular-nums">{filtered.length}</span>
          </button>
          {CRM_QUICK_FILTERS.map(s => {
            const count = estadoCounts[s.key] || 0;
            if (count === 0) return null;
            const active = estadoFilter === s.key;
            return (
              <button
                key={s.key}
                type="button"
                onClick={() => setEstadoFilter(active ? null : s.key)}
                className="chip"
                style={active
                  ? { background: 'var(--accent)', color: 'var(--accent-foreground)', boxShadow: '0 6px 18px -8px rgba(15,187,182,0.55)' }
                  : { background: 'color-mix(in oklab, var(--muted-foreground) 8%, transparent)', color: 'var(--muted-foreground)' }}
              >
                {s.label}
                <span className="opacity-70 tabular-nums">{count}</span>
              </button>
            );
          })}
        </div>
        )}

        {/* ── Tarjeta: buscador + tabla ─────────────── */}
        <div
          className="glow-track animate-fade-in-up rounded-2xl"
          style={{
          animationDelay: '220ms',
          background: 'var(--card)',
          border: '1px solid color-mix(in oklab, var(--border) 55%, transparent)',
          boxShadow: 'var(--shadow-card)',
          overflow: 'hidden',
        }}>
          {/* Buscador + contador / acciones de selección */}
          {hasSel && !isDraftsFolder ? (
            <div className="flex items-center gap-2 px-5 py-3.5" style={{ borderBottom: '1px solid color-mix(in oklab, var(--border) 55%, transparent)' }}>
              <input
                type="checkbox"
                className="cc-check"
                ref={selectAllRef}
                checked={allSel}
                onChange={(e) => e.target.checked ? selectAll() : clearSel()}
                title="Seleccionar todo"
              />
              <span className="text-[12.5px] font-bold" style={{ color: 'var(--foreground)' }}>
                {selectedIds.length} seleccionado{selectedIds.length === 1 ? '' : 's'}
              </span>
              <div className="ml-3 flex items-center gap-1.5 flex-wrap">
                {isTrashFolder ? (
                  <button type="button" onClick={restoreSelected} className="btn btn-ghost h-8"><IconInbox size={14} /><span className="text-[12px]">Restaurar</span></button>
                ) : (
                  <>
                    {isScheduledFolder && (
                      <button type="button" onClick={unsnoozeSelected} className="btn btn-ghost h-8" title="Quitar el posponer — vuelve a Recibidos ya">
                        <IconInbox size={14} /><span className="text-[12px]">Volver a Recibidos</span>
                      </button>
                    )}
                    <button type="button" onClick={toggleArchive} className="btn btn-ghost h-8">{isArchivedFolder ? <IconInbox size={14} /> : <IconArchive size={14} />}<span className="text-[12px]">{isArchivedFolder ? 'Desarchivar' : 'Archivar'}</span></button>
                    <button type="button" onClick={() => { selectedIds.forEach(id => onUpdateEmail(id, { unread: false })); clearSel(); }} className="btn btn-ghost h-8"><IconCheck size={14} /><span className="text-[12px]">Leído</span></button>
                    {!isScheduledFolder && <SnoozeMenu onSnooze={snoozeSelected} />}
                    <EtiquetarMenu etiquetas={etiquetas} emails={emails} selectedIds={selectedIds} onToggle={toggleEtiqueta} />
                    <button type="button" onClick={() => { selectedIds.forEach(id => onUpdateEmail(id, { folder: 'trash' })); clearSel(); }} className="btn btn-ghost h-8"><IconTrash size={14} /><span className="text-[12px]">Eliminar</span></button>
                  </>
                )}
              </div>
              <button type="button" onClick={clearSel} className="ml-auto btn btn-ghost h-8 text-[12px]" style={{ color: 'var(--muted-foreground)' }}>Cancelar</button>
            </div>
          ) : !isDraftsFolder ? (
            <>
              <div className="flex items-center justify-between gap-4 px-5 py-4" style={{ borderBottom: '1px solid color-mix(in oklab, var(--border) 55%, transparent)' }}>
                <div className="flex items-center gap-3 flex-1 min-w-0">
                  <input
                    type="checkbox"
                    className="cc-check"
                    ref={selectAllRef}
                    checked={allSel}
                    onChange={(e) => e.target.checked ? selectAll() : clearSel()}
                    title="Seleccionar todo"
                  />
                  <div className="relative flex-1 max-w-2xl">
                    <IconSearch size={15} className="absolute left-3.5 top-1/2 -translate-y-1/2" style={{ color: 'var(--muted-foreground)' }} />
                    <input
                      value={search}
                      onChange={(e) => onUpdateEmail('__search', e.target.value)}
                      placeholder="Buscar correos, contactos, etiquetas…"
                      className="w-full h-10 pl-10 pr-3 text-[13px] font-medium rounded-lg outline-none transition-colors"
                      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>
                <div className="flex items-center gap-2 flex-shrink-0">
                  {/* Orden (auditoría #11: existía y nunca se montaba). En
                      "Para responder" no va — ahí manda el más viejo primero. */}
                  {!isParaResponder && <SortDropdown sortBy={sortBy} onSort={(s) => onUpdateEmail('__sort', s)} />}
                  <span className="text-[12px] font-semibold tabular-nums whitespace-nowrap" style={{ color: 'var(--muted-foreground)' }}>
                    {displayed.length} resultados
                  </span>
                </div>
              </div>
              {/* Chips clickeables persona/etiqueta/fecha (buscador unificado) */}
              <SearchChipsRow emails={emails} etiquetas={etiquetas} chips={chips} onSetChips={onSetChips} />
            </>
          ) : (
            <div className="flex items-center justify-between gap-4 px-5 py-4" style={{ borderBottom: '1px solid color-mix(in oklab, var(--border) 55%, transparent)' }}>
              <span className="text-[12.5px] font-bold" style={{ color: 'var(--foreground)' }}>Borradores</span>
              <span className="text-[12px] font-semibold tabular-nums whitespace-nowrap" style={{ color: 'var(--muted-foreground)' }}>
                {(borradores || []).length} guardado{(borradores || []).length === 1 ? '' : 's'}
              </span>
            </div>
          )}

          {/* Filas (estilo email de Gmail) */}
          {isDraftsFolder ? renderDrafts() : renderRows()}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { CrmInbox, crmLastMsg: _crmLastMsg, EtiquetaPill });
