# Etapa 1 — Logo InQuality en header de PDFs + whitespace-nowrap

**Sprint:** 6
**Fecha:** 2026-06-23
**Alcance:** 3 PDFs (Actual, Automatizado, ROI) + un fix de una línea en ComparisonTable.

---

## Contexto

El header compartido de los 3 PDFs (`src/lib/export/pdf-sections-shared.ts`, función `drawSharedHeader`) hoy dibuja el texto "InQ ROI" en naranja bold como identidad de marca. El logo PNG de InQuality ya existe en `assets/`. El objetivo es reemplazar el texto por el logo, manteniendo el layout del header sin cambios estructurales.

---

## Parte A — Logo en header de PDFs

### Assets disponibles

En `assets/` (ruta desde la raíz del proyecto):
- `MARCA FINAL 2023 AREA DE SEGURIDAD 1 COLOR.png` — logo horizontal color, sobre fondos claros — **usar este**
- `MARCA FINAL 2023 AREA DE SEGURIDAD 1 BCO.png` — logo horizontal blanco (no aplica, el header es blanco)

### Cómo cargar el PNG en jsPDF

Importar la URL del asset con Vite:

```ts
// En pdf-export.ts (o en un helper de carga)
import logoColorUrl from '../../../assets/MARCA FINAL 2023 AREA DE SEGURIDAD 1 COLOR.png?url'
```

Convertir a base64 antes de generar cualquier PDF (operación async, una vez por export):

```ts
async function loadImageBase64(url: string): Promise<string> {
  const response = await fetch(url)
  const blob = await response.blob()
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = () => resolve(reader.result as string)
    reader.onerror = reject
    reader.readAsDataURL(blob)
  })
}
```

Llamar una vez al inicio de cada función de export (`exportPdf`, `exportRoiPdf`) y pasar el resultado como parámetro.

### Cambios en `PdfHeaderOptions`

Agregar un campo opcional:

```ts
export interface PdfHeaderOptions {
  pageNumber: number
  processName: string
  sectionTitle?: string
  clientName?: string
  simulatedAt: number
  logoBase64?: string   // ← nuevo, opcional para retrocompatibilidad
}
```

### Cambios en `drawSharedHeader`

Reemplazar el bloque de texto "InQ ROI" por lógica condicional:

```ts
// ANTES:
doc.setFont('helvetica', 'bold')
doc.setFontSize(13)
doc.setTextColor(...PDF_COLORS.inqOrange)
doc.text('InQ ROI', MARGIN, y)

// DESPUÉS:
if (options.logoBase64) {
  // Logo PNG: ancho 32mm, alto proporcional (~9mm para este logo horizontal)
  // Alinear el baseline del logo con la primera línea de texto: y - 7 (arriba del baseline)
  doc.addImage(options.logoBase64, 'PNG', MARGIN, y - 7, 32, 9)
} else {
  // Fallback al texto (retrocompatibilidad y tests)
  doc.setFont('helvetica', 'bold')
  doc.setFontSize(13)
  doc.setTextColor(...PDF_COLORS.inqOrange)
  doc.text('InQ ROI', MARGIN, y)
}
```

**Nota sobre dimensiones:** el logo horizontal de InQuality tiene una proporción aproximada de 3.5:1 (ancho:alto). A 32mm de ancho → ~9mm de alto. Ajustar si el resultado visual no queda bien — la validación visual del director confirma antes del OK formal.

### Cambios en `pdf-export.ts`

En las dos funciones de export (`exportPdf` y `exportRoiPdf`), agregar la carga del logo al inicio:

```ts
export async function exportPdf(...): Promise<void> {
  const logoBase64 = await loadImageBase64(logoColorUrl).catch(() => undefined)

  const headerOpts: PdfHeaderOptions = {
    // ...opciones existentes...
    logoBase64,
  }
  // resto sin cambios
}
```

El `.catch(() => undefined)` garantiza que si el fetch del asset falla (ej: entorno sin red), el PDF se genera igual con el fallback de texto. No bloquear el export por el logo.

### Importante — NO cambiar

- La estructura del header (posiciones de proceso, cliente, fecha, border-bottom) no cambia.
- El footer ("Powered by InQuality") no cambia.
- `drawSharedFooter` y `applyFootersToAllPages` no se tocan.
- No agregar el logo en páginas 1 de cada PDF que tengan su propio diseño de portada (verificar si `drawScenarioPage1` y `drawRoiPage1` usan o no `drawSharedHeader` — si no lo usan, el logo solo aplica a las páginas que sí lo llaman).

---

## Parte B — whitespace-nowrap en celda de Eficiencia

En `src/features/report/ComparisonTable.tsx`, dentro de `MetricCell`, el `<span>` que muestra el valor numérico de la columna "Eficiencia" se corta en dos líneas ("1.02" / "USD/min") porque la celda es angosta.

Fix: agregar `whitespace-nowrap` al className del `<span>`:

```tsx
// Buscar el span que tiene el valor formateado de la Eficiencia y agregar whitespace-nowrap
<span className="font-mono text-slate-700 text-xs w-14 text-right whitespace-nowrap">
  {format(value)}
</span>
```

Una línea de cambio. Sin tests que actualizar.

---

## Criterios de validación

- [ ] Logo visible en el header de todas las páginas de los 3 PDFs (Actual, Automatizado, ROI)
- [ ] Logo en tamaño coherente con el header — no dominante, no microscópico
- [ ] Alineación correcta: logo a la izquierda, fecha y cliente a la derecha
- [ ] El footer "Powered by InQuality" sigue presente en todas las páginas
- [ ] Si el asset no carga (fetch falla), el PDF se genera igual con texto "InQ ROI" como fallback
- [ ] "1.02 USD/min" aparece en una sola línea en ComparisonTable
- [ ] `npm run lint` sin errores
- [ ] `npm run build` limpio
- [ ] `npm run test` → 542 tests verdes (sin regresiones — los tests de PDF existentes usan mocks y no verifican el logo)
- [ ] **Validación visual del director sobre el PDF exportado antes del OK formal** — esta es la validación principal de la etapa

---

## Archivos a modificar

1. `src/lib/export/pdf-sections-shared.ts` — `PdfHeaderOptions` + `drawSharedHeader`
2. `src/lib/export/pdf-export.ts` — carga del logo + pasar `logoBase64` a `headerOpts`
3. `src/features/report/ComparisonTable.tsx` — `whitespace-nowrap` en `MetricCell`

No modificar ningún otro archivo. En particular, no tocar los tests de PDF existentes — el fallback de texto garantiza que sigan pasando sin cambios.
