Antes de meterle a sprint 1 etapa 4 y 5

This commit is contained in:
2026-05-16 13:46:27 -03:00
parent 0ef75aa9a9
commit f9a008bce5
14 changed files with 666 additions and 8 deletions

View File

@@ -5,6 +5,49 @@
---
## ⚠️ Reglas de Marca — NO NEGOCIABLES (Sprint 1.5+)
Estas reglas aplican a TODO string que aparezca en código, PDFs, CSVs, tests y documentación.
### 1. Ortografía de "InQ" — SIEMPRE I-n-Q
```
✅ InQ ← correcto
✅ InQuality ← correcto (nombre completo)
✅ InQ ROI ← nombre del producto
❌ INQ ← bug
❌ Inq ← bug
❌ inq ← bug
❌ inQ ← bug
```
Cualquier desviación es un bug que debe corregirse antes de hacer commit.
### 2. Nombre del producto
`InQ ROI` — nombre de trabajo para Sprint 1.5. Se reemplazará en Sprint 3-4. No debatir el nombre ahora.
### 3. Color protagonista
```
Primario: #F59845 (naranja InQ)
Gradiente: #F59845 → #ED3E8F (naranja → magenta InQ)
```
El gradiente se usa SOLO en KPI Hero y banners principales.
**NO usar morado de CONCILIA** (`#572FA2`, `#CB1889`) en este producto.
### 4. Footer de PDFs
Tagline obligatorio: `"Powered by InQuality"` — en todos los footers de PDF, siempre.
### 5. Rol del consultor
Si aparece un nombre de consultor en algún campo, es como "consultor responsable", no como "creador" ni "founder" del producto.
---
## Identidad del Proyecto
**Nombre de trabajo**: Process Cost Platform (nombre comercial por definir)
@@ -231,4 +274,15 @@ npx playwright test # tests E2E (Playwright headless)
- Casos de uso confirmados:
- Análisis de costos operativos en consultoría de procesos
- **Pre-venta de proyectos de automatización con cálculo de ROI** (caso estrella del Sprint 1)
- Valora: claridad, robustez, pulido visual, mantenibilidad, validación rigurosa
- Valora: claridad, robustez, pulido visual, mantenibilidad, validación rigurosa
---
## Reglas de marca NO NEGOCIABLES
- "InQ" siempre se escribe I-n-Q (mayúscula-minúscula-mayúscula)
- Color protagonista: naranja #F59845
- Gradiente identidad: #F59845#ED3E8F
- NO usar morado CONCILIA (#572FA2, #CB1889)
- Footer obligatorio: "Powered by InQuality"
- No promover a Marcos como creador

330
DESIGN_SYSTEM.md Normal file
View File

@@ -0,0 +1,330 @@
# InQ ROI — Sistema de Diseño
> Documento de referencia visual para Sprint 2+.
> Fuente de verdad para la paleta, tipografía y componentes.
> Actualizar en cada sprint que modifique la identidad visual.
---
## 1. Identidad de Marca
### Nombre del producto
**InQ ROI** — herramienta interna de InQuality para cuantificación de ROI de automatización.
### Regla de ortografía (NO NEGOCIABLE)
```
✅ InQ ← I mayúscula, n minúscula, Q mayúscula
✅ InQuality ← nombre completo
❌ INQ / Inq / inq / inQ ← cualquiera es bug
```
### Tagline en footers PDF
`"Powered by InQuality"` — obligatorio en todos los footers de PDF.
---
## 2. Paleta Cromática
### 2.1 InQ Orange — Color protagonista
| Token Tailwind | CSS Var | Hex | HSL | Uso |
|---|---|---|---|---|
| `bg-inq-orange` | `--inq-orange` | `#F59845` | 28° 90% 62% | Principal: logo, KPIs hero, CTAs primarios |
| `bg-inq-orange-dark` | `--inq-orange-dark` | `#B45309` | 34° 93% 37% | Texto sobre fondos claros, hover de CTAs |
| `bg-inq-orange-light` | `--inq-orange-light` | `#FEF3E2` | 36° 95% 88% | Fondos de KPI cards |
| `bg-inq-orange-lighter` | `--inq-orange-lighter` | `#FFF8ED` | 36° 100% 94% | Fondos de banner narrativo, hover sutiles |
### 2.2 InQ Magenta — Gradiente identidad
| Token Tailwind | CSS Var | Hex | Uso |
|---|---|---|---|
| `bg-inq-magenta` | `--inq-magenta` | `#ED3E8F` | Segundo color del gradiente identidad |
#### Gradiente identidad
```css
background: linear-gradient(135deg, #F59845 0%, #ED3E8F 100%);
```
**Uso exclusivo:** KPI Hero "Ahorro proyectado" en PDF y web. NUNCA en bordes, separadores ni fondos secundarios.
### 2.3 Semánticos
| Token Tailwind | CSS Var | Hex | Uso |
|---|---|---|---|
| `bg-success` | `--color-success` | `#16A34A` | Ahorros positivos, payback alcanzado |
| `bg-success-light` | `--color-success-light` | `#F0FDF4` | Fondos de mensajes positivos |
| `bg-warning` | `--color-warning` | `#F59E0B` | Advertencias, sección transparencia |
| `bg-warning-bg` | `--color-warning-bg` | `#FFFBEB` | Fondo de sección transparencia |
| `bg-destructive` / `--color-danger` | — | `#EF4444` | Costos altos, valores negativos |
| `--color-danger-light` | — | `#FEE2E2` | Fondos de heatmap alto costo |
### 2.4 Heatmap — Paleta saturada (FIJA hasta Sprint 3-4)
| Token Tailwind | Hex | RGB | Uso |
|---|---|---|---|
| `bg-heatmap-low` | `#10B981` | (16, 185, 129) | Actividades de bajo costo |
| `bg-heatmap-mid` | `#F59E0B` | (245, 158, 11) | Actividades de costo medio |
| `bg-heatmap-high` | `#EF4444` | (239, 68, 68) | Actividades de alto costo |
#### Decisión sobre paleta de heatmap
**Se mantiene saturada** (verde-ámbar-rojo) en lugar de la variante pastel del brief por dos razones:
1. **Tests E2E calibrados**: los análisis de píxeles del heatmap (`export-pdf.spec.ts`, `validate-dod-etapa4.spec.ts`) tienen umbrales calibrados para estos colores. Cambiar la paleta requiere recalibrar todos esos umbrales.
2. **Visibilidad en pantallas grandes**: el producto se usa en talleres y charlas InQuality proyectadas en pantalla. Los colores saturados mantienen contraste a distancia. Los pasteles se "lavan" a 3+ metros.
**Revisión programada**: Sprint 3-4 con feedback real de uso en talleres.
**Invariante crítica**: los valores de `tailwind.config.js` `heatmap.*` DEBEN coincidir con las constantes `HEATMAP_LOW/MID/HIGH` en `src/lib/colors.ts`. Si se modifica uno, debe actualizarse el otro.
### 2.5 Neutrales
| Hex | Tailwind equivalente | Uso |
|---|---|---|
| `#0F172A` | `slate-900` | Títulos, números importantes |
| `#475569` | `slate-600` | Texto del cuerpo |
| `#64748B` | `slate-500` | Labels, metadatos |
| `#94A3B8` | `slate-400` | Placeholders, texto muy secundario |
| `#E2E8F0` | `slate-200` | Bordes generales |
| `#F1F5F9` | `slate-100` | Separadores sutiles |
| `#F8FAFC` | `slate-50` | Fondo de la app, canvas BPMN |
### 2.6 Colores que NO usar
```
❌ #572FA2 Morado primario de CONCILIA — marca hermana, no mezclar
❌ #CB1889 Magenta de CONCILIA
❌ azul shadcn por defecto (221.2 83.2% 53.3%) — reemplazado por InQ orange
```
---
## 3. Tipografía
### 3.1 Familias
```css
/* Primaria — web app y body de PDFs */
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
/* Mono — números en tablas, datos financieros */
font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
```
Tailwind: `font-sans` / `font-mono`
### 3.2 Escala PDF
| Elemento | Tamaño | Peso | Tracking |
|---|---|---|---|
| Logo "InQ ROI" en header | 22px | 700 | 0.8px |
| Título de sección | 16px | 500 | normal |
| KPI Hero (cifra) | 30px | 700 | 1px |
| KPI secundario (cifra) | 16px | 700 | normal |
| Body text | 11px | 400 | normal |
| Labels en cards | 8px | 500 | 1px uppercase |
| Tabla header | 10px | 500 | normal |
| Tabla body | 10px | 400 | normal |
| Footer | 9px | 400 | normal |
### 3.3 Escala Web App
| Elemento | Tamaño |
|---|---|
| Logo header | 18px / 700 |
| Page title | 16px / 500 |
| KPI Hero | 28px / 700 |
| KPI secundario | 16px / 700 |
| Nav / Tabs | 12px / 400-500 |
| Body | 12-13px / 400 |
| Labels en panels | 10-11px / 400-500 |
---
## 4. Componentes
### 4.1 KPI Hero (gradiente naranja → magenta)
```
Fondo: linear-gradient(135deg, #F59845 0%, #ED3E8F 100%)
Padding: 16-18px
Border-radius: 6-8px
Label: 9-10px / uppercase / letter-spacing 1.2px / white opacity 0.9
Cifra: 28-30px / 700 / letter-spacing 1px / white
Subtítulo: 10-11px / white opacity 0.85
```
Uso: el KPI "Ahorro proyectado a N años" — el más importante del reporte ROI.
### 4.2 KPI Card (secundario, fondo naranja claro)
```
Fondo: #FEF3E2 (inq-orange-light)
Padding: 10px 12px
Border-radius: 6px
Label: 8px / 500 / letter-spacing 1px / color #92400E / uppercase
Cifra: 16px / 700 / color #0F172A
Delta: 10px / 500 / color #B45309
```
### 4.3 Banner narrativo (resumen ejecutivo)
```
Fondo: #FFF8ED (inq-orange-lighter)
Border-left: 3px solid #F59845
Padding: 10-12px 14px
Border-radius: 0 4px 4px 0
Texto: 11px / 400 / line-height 1.55 / color #475569
```
### 4.4 Sección Transparencia Metodológica
```
Fondo: #FFFBEB (warning-bg)
Border: 0.5px solid #F59E0B
Padding: 12px 14px
Border-radius: 6px
Título: 11px / 500 / color #92400E / con ícono ⚠
Texto: 10px / 400 / line-height 1.6 / color #78350F
```
4 condiciones que activan la sección:
1. Actividades `automatable=true` con `automatedCostFixed=0` y `automatedTimeMinutes=0`
2. `automationInvestment=0`
3. `roiAnnualPercent > 1000` (finito)
4. (reservado para futuras reglas)
### 4.5 Tabla comparativa PDF
```
Header row:
Fondo: #FFF8ED
Border-bottom: 1px solid #F59845
Texto: 10px / 500 / #92400E
Body row — automatizable:
Fondo: white
Body row — no automatizable:
Fondo: #F8FAFC
Texto: color #64748B (más tenue)
Total row:
Fondo: #FFF8ED
Border-top: 1.5px solid #F59845
Texto: 10px / 500 / #0F172A
```
### 4.6 Header PDF
```
Layout: flex justify-between
Border-bottom: 3px solid #F59845 (pág. 1) / 2px (otras)
Padding-bottom: 10-12px
Margin-bottom: 14-16px
Izquierda:
"InQ ROI" 18-22px / 700 / #F59845
Tagline: 9px / letter-spacing 1.5px / #94A3B8 (solo pág. 1)
Derecha:
"UN PRODUCTO DE" 9px / letter-spacing 1px / #94A3B8
"InQ" 16px / 700 / #475569
"InQuality" 9px / #64748B
```
### 4.7 Footer PDF
```
Position: absolute bottom 14-16mm
Padding-top: 6-8px
Border-top: 0.5px solid #E2E8F0
Layout: flex justify-between
Font: 9px / 400 / #94A3B8
Izquierda: "InQ ROI" bold #F59845 " · Powered by InQuality · " cliente · fecha
Derecha: "Página X de Y"
```
### 4.8 Badge ⚡ (Automatizable)
#### En canvas BPMN overlay
```
Diámetro: 14px
Fondo: #F59845 (naranja sólido)
Border: 1.5px solid white
Posición: { top: -8, left: nodeWidth - 12 }
Símbolo: ⚡ blanco 8px
```
Nota: en Sprint 1 el badge usa fondo `#fffbeb` (ámbar-50) con ícono ámbar. La migración a naranja sólido se hace en **Etapa 9** de Sprint 1.5.
#### En tablas y leyendas
```
Diámetro: 14px inline
Fondo: #F59845
Color: white
```
### 4.9 Layout híbrido de PDFs (portrait + landscape)
Los PDFs combinan orientaciones por página:
- **Páginas SIN diagrama**: A4 vertical (210×297mm) — texto, tablas, KPIs
- **Página DEL diagrama BPMN**: A4 horizontal (297×210mm) — para que el diagrama ocupe espacio real
Implementación jsPDF: `doc.addPage([297, 210], 'landscape')`
---
## 5. Tokens en código
### Web (Tailwind)
```tsx
// Colores de marca
<div className="bg-inq-orange"> // #F59845
<div className="bg-inq-orange-dark"> // #B45309
<div className="bg-inq-orange-light"> // #FEF3E2
<div className="text-inq-orange"> // texto naranja
<div className="border-inq-orange"> // borde naranja
// Gradiente identidad (como style prop — Tailwind no soporta gradientes dinámicos)
<div style={{ background: 'linear-gradient(135deg, #F59845 0%, #ED3E8F 100%)' }}>
// Semánticos
<div className="bg-success text-white"> // #16A34A
<div className="bg-warning-bg"> // #FFFBEB
```
### PDF (jsPDF)
```typescript
// Constante en pdf-sections.ts (a migrar en Etapas 4-8)
const PDF_ORANGE: [number, number, number] = [245, 152, 69] // #F59845
const PDF_ORANGE_LIGHT: [number, number, number] = [254, 243, 226] // #FEF3E2
const PDF_MAGENTA: [number, number, number] = [237, 62, 143] // #ED3E8F
// Gradiente en jsPDF se simula con pasos (ver pdf-sections-roi.ts)
```
---
## 6. Reglas de uso — DO / DON'T
### DO ✅
- Usar `bg-primary` / `text-primary` para todos los CTAs — hereda el naranja de `--primary`
- Usar gradiente identidad en exactamente 1 KPI Hero por página/vista
- Usar `font-mono` para todos los números financieros
- Escribir siempre **InQ** con I-n-Q
### DON'T ❌
- Usar `bg-blue-*` donde debería ir naranja InQ
- Aplicar el gradiente en más de un elemento por vista
- Usar colores de CONCILIA (`#572FA2`, `#CB1889`)
- Cambiar los colores del heatmap sin recalibrar los tests E2E
---
*Actualizado: Sprint 1.5 Etapa 1 — 2026-05-16*

View File

@@ -31,6 +31,8 @@
- [ ] **Indicador visual en el reporte de actividades automatable** (borde punteado o ícono diferenciador): en Sprint 1 se usa solo leyenda de texto. Evaluar si el cliente necesita más claridad visual al comparar Actual vs Automatizado.
- [ ] **Sprint 3-4: revisar paleta del heatmap** (verde/ámbar/rojo saturados vs. pasteles). Los colores saturados actuales (`#10B981`, `#F59E0B`, `#EF4444`) funcionan bien en pantallas grandes de talleres. El brief de Sprint 1.5 propone pasteles más "consultivos" (`#BBF7D0`, `#FED7AA`, `#FECACA`), pero el cambio requiere recalibrar los tests E2E de análisis de píxeles (umbrales de verde/ámbar/rojo). Hacer con feedback real de uso en talleres InQuality.
- [ ] **Columna "Eficiencia de automatización" en ComparisonTable**: métrica = `(ahorro$ × probabilidad) / inversión-prorrateada`. Permite rankear actividades por "qué tan valiosa es automatizar cada una" en lugar de solo "cuánto cuestan". Útil en conversaciones de pre-venta donde el cliente quiere priorizar qué automatizar primero.
## Baja prioridad / Fase 2

90
etapa-1-audit.md Normal file
View File

@@ -0,0 +1,90 @@
# Auditoría de colores — Etapa 1 Sprint 1.5
> Hallazgos del audit de azules, hardcodes y `primary` en el código fuente.
> **No se resuelven en Etapa 1.** Las acciones se ejecutan en Etapas 3 (Web App) y 4-8 (PDFs).
>
> Fecha: 2026-05-16 · Ejecutado por: Claude Code
> Comandos: `grep -rn "blue|sky|indigo|3B82F6|2563EB" src/` + `grep -rn "#[0-9a-fA-F]{6}" src/`
---
## Categorías
- **Migrar a InQ orange**: color azul que debería ser naranja de marca
- **Mantener azul funcional**: azul donde es convención semántica (info, links, paralelo AND)
- **Migrar a neutral**: azul accidental que debería ser slate/gray
- **Migrar a token**: hex hardcodeado que tiene un token equivalente en tailwind.config.js
---
## Hallazgos — Azules en clases Tailwind
| Archivo:línea | Clase actual | Categoría | Acción sugerida |
|---|---|---|---|
| `GatewayPanel.tsx:122` | `bg-blue-50 border-blue-200` | **Mantener azul funcional** | El azul en gateways AND paralelos es convención visual (flujo paralelo = azul). Evaluar en Sprint 2 si cambiar a slate-50 sin perder semántica. |
| `GatewayPanel.tsx:124` | `text-blue-500` | **Mantener azul funcional** | Ídem — ícono Info en bloque paralelo |
| `GatewayPanel.tsx:126-127` | `text-blue-800`, `text-blue-700` | **Mantener azul funcional** | Texto del bloque informativo de gateway AND |
| `GatewayPanel.tsx:144` | `text-blue-600` | **Mantener azul funcional** | "100%" en gateway paralelo — valor fijo, semántica coherente |
| `ResourcesPanel.tsx:22` | `bg-blue-100 text-blue-700` (rol "role") | **Migrar a neutral** | Badge de tipo "role" no tiene razón de ser azul. Migrar a slate o usar color propio del sistema de recursos. Etapa 3. |
## Hallazgos — `PDF.blue` en exportación
| Archivo:línea | Color actual | Categoría | Acción sugerida |
|---|---|---|---|
| `pdf-sections.ts:9` | `blue: [30, 64, 175]` (`#1E40AF`) | **Migrar a InQ orange** | Header de tabla PDF usa azul corporativo. Reemplazar por naranja InQ `[245, 152, 69]` (`#F59845`) en Etapa 4 (PDF: header y footer). |
| `pdf-sections.ts:112` | `PDF.blue` en KPI card accent | **Migrar a InQ orange** | El KPI "Costo total" usa azul como accent. Cambiar a naranja InQ en Etapa 6 (PDF: rediseño página 1). |
| `pdf-export.ts:120` | `fillColor: PDF.blue` en autotable | **Migrar a InQ orange** | Header de tabla de costos en azul. Migrar en Etapa 7 (PDF: páginas 3-4). |
| `pdf-sections-roi.ts:203` | `fillColor: PDF.blue` en autotable | **Migrar a InQ orange** | Header de tabla comparativa ROI. Migrar en Etapa 7. |
## Hallazgos — Hex hardcodes en componentes React
| Archivo:línea | Hex | Descripción | Categoría | Acción sugerida |
|---|---|---|---|---|
| `BpmnCanvas.tsx:24` | `#f59e0b` | Stroke del ícono Bot en SVG inline | **Migrar a InQ orange** | En Etapa 9 el badge ⚡ cambia a fondo naranja sólido `#F59845`. El stroke del SVG se rediseña en esa etapa. |
| `BpmnCanvas.tsx:40` | `#fffbeb` | Fondo del badge Bot (amber-50) | **Migrar a InQ orange** | Reemplazar por `var(--inq-orange-lighter)` `#FFF8ED` en Etapa 9. |
| `BpmnCanvas.tsx:41` | `#e2e8f0` | Borde del badge Bot | **Mantener neutral** | Borde sutil, está bien como slate-200. |
| `CumulativeSavingsChart.tsx:32,34` | `#10b981` | Color del marker de payback | **Migrar a token** | Verde éxito = `var(--color-success)` `#16A34A`. Migrar en Etapa 3. |
| `CumulativeSavingsChart.tsx:55` | `#10b981`, `#ef4444` | Colores del tooltip (positivo/negativo) | **Migrar a token** | Usar `--color-success` y `--color-danger`. Etapa 3. |
| `CumulativeSavingsChart.tsx:91,102` | `#3b82f6` | Línea y punto del chart acumulado | **Migrar a InQ orange** | La línea del gráfico de trayectoria debería ser naranja InQ `#F59845` para coherencia de marca. Etapa 3. |
| `HeatmapCanvas.tsx:118` | `#f8fafc` | Background del canvas | **Mantener neutral** | slate-50 es correcto para fondo del diagrama BPMN. |
| `TopSavingsChart.tsx:73,79` | `#10b981` | Barras y labels del chart | **Migrar a token** | Verde éxito correcto. Usar `--color-success` vía `style={{ color: 'var(--color-success)' }}`. Etapa 3. |
| `HeatmapLegend.tsx:24` | `#10b981`, `#f59e0b`, `#ef4444` | Gradiente de la leyenda del heatmap | **Migrar a token** | Usar constantes exportadas de `colors.ts` o tokens `heatmap.*`. Etapa 3. |
| `chart-options.ts:12` | `#3b82f6` (role) | Color del tipo de recurso "role" | **Migrar a neutral** | El azul para "roles" no es marca InQ. Evaluar paleta diferenciadora de tipos en Sprint 2. |
| `chart-options.ts:12` | `#8b5cf6` (system) | Color del tipo "system" | **Mantener azul funcional** | Violeta para sistemas es una convención razonable. Evaluar en Sprint 2. |
| `chart-options.ts:123` | `#3b82f6` | Costo directo en donut chart | **Migrar a InQ orange** | El donut de composición directo/overhead debería usar naranja InQ. Etapa 3. |
| `chart-options.ts:57,69,211,224` | `#f1f5f9`, `#e2e8f0` | Grid lines y ejes de charts | **Mantener neutral** | slate-100/200 son correctos para UI de soporte. |
| `chart-options.ts:63,107,209` | `#475569` | Labels de ejes | **Mantener neutral** | slate-600, correcto. |
| `chart-options.ts:78,217,237` | `#64748b`, `#94a3b8` | Labels secundarios | **Mantener neutral** | slate-500/400, correctos. |
| `chart-options.ts:136` | `#1e293b` | Fill del label de total en donut | **Mantener neutral** | slate-800, correcto para texto. |
## Hallazgos — `primary` en JSX
| Archivo | Usos | Evaluación |
|---|---|---|
| `router.tsx`, `WorkspacePage.tsx` | `text-primary` spinner | ✅ Correcto — spinner naranja InQ ahora |
| `ResourcesPanel.tsx:101` | `border-primary/20 bg-primary/5` | ✅ Correcto — borde/fondo naranja sutil |
| `RoiKpiBar.tsx:88-89` | `text-primary`, `bg-primary/10` | ✅ Correcto — ícono Calendar naranja |
| `KpiBar.tsx:46-47` | `text-primary`, `bg-primary/10` | ✅ Correcto — ícono DollarSign naranja |
| `ActivitiesTable.tsx:22-23` | `text-primary` arrows | ✅ Correcto — flechas de ordenamiento naranjas |
| `ActivitiesTable.tsx:96` | `bg-primary/5 ring-primary/20` | ✅ Correcto — highlight de fila naranja |
| `ImportPage.tsx:173,198-199,205,210-211,252,255-258` | `text-primary`, `bg-primary/*`, `border-primary` | ✅ Correcto — AccentS de la landing page naranjas |
| `SampleProcessLoader.tsx:77,83-84,92` | `hover:border-primary/30`, `bg-primary/10`, `text-primary` | ✅ Correcto |
| `WorkspacePage.tsx:178,243` | `text-primary border-primary/30`, `bg-primary` | ✅ Correcto |
| `slider.tsx` | `bg-primary/20`, `bg-primary`, `border-primary/50` | ✅ Correcto — slider naranja |
| `tooltip.tsx` | `bg-primary text-primary-foreground` | ✅ Correcto — tooltip naranja |
| `switch.tsx` | `bg-primary` when checked | ✅ Correcto — switch naranja |
| `button.tsx` | `bg-primary text-primary-foreground` default | ✅ Correcto — botón naranja |
| `badge.tsx` | `bg-primary text-primary-foreground` | ✅ Correcto — badge naranja |
---
## Resumen de acciones pendientes
| Etapa | Archivos afectados | Acción |
|---|---|---|
| Etapa 3 (Web App) | `CumulativeSavingsChart.tsx`, `TopSavingsChart.tsx`, `HeatmapLegend.tsx`, `chart-options.ts` | Migrar hex a tokens CSS/constantes |
| Etapa 4-8 (PDFs) | `pdf-sections.ts`, `pdf-export.ts`, `pdf-sections-roi.ts` | Reemplazar `PDF.blue` por array naranja InQ |
| Etapa 9 (Badge ⚡) | `BpmnCanvas.tsx` | Rediseño completo del badge a naranja sólido |
| Sprint 2 | `ResourcesPanel.tsx`, `GatewayPanel.tsx`, `chart-options.ts` | Evaluar paleta de tipos de recurso y gateways |
**No se toca nada de lo anterior en Etapa 1.**

View File

View File

@@ -26,7 +26,7 @@ const TabsTrigger = React.forwardRef<
<TabsPrimitive.Trigger
ref={ref}
className={cn(
'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow',
'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-inq-orange data-[state=active]:shadow data-[state=active]:font-semibold',
className
)}
{...props}

View File

@@ -9,14 +9,19 @@
@layer base {
:root {
/* ── Shadcn/ui tokens — primary cambiado a InQ Orange ─────────────────
Antes: azul (221.2 83.2% 53.3%).
Ahora: naranja InQ #F59845 ≈ HSL(28, 90%, 62%).
Esto actualiza automáticamente Button default, Switch checked,
Tabs ring, Slider y cualquier componente que use bg-primary/text-primary. */
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--primary: 28 90% 62%;
--primary-foreground: 0 0% 100%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
@@ -27,8 +32,25 @@
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 221.2 83.2% 53.3%;
--ring: 28 90% 62%;
--radius: 0.5rem;
/* ── InQ ROI brand variables ─────────────────────────────────────────
Para uso en CSS inline, SVG y contextos donde Tailwind no aplica.
En componentes React, preferir las clases Tailwind (bg-inq-orange, etc.) */
--inq-orange: #F59845;
--inq-orange-dark: #B45309;
--inq-orange-light: #FEF3E2;
--inq-orange-lighter: #FFF8ED;
--inq-magenta: #ED3E8F;
/* ── Semánticos ──────────────────────────────────────────────────────*/
--color-success: #16A34A;
--color-success-light: #F0FDF4;
--color-warning: #F59E0B;
--color-warning-bg: #FFFBEB;
--color-danger: #EF4444;
--color-danger-light: #FEE2E2;
}
}

View File

@@ -45,10 +45,35 @@ export default {
DEFAULT: 'hsl(var(--card))',
foreground: 'hsl(var(--card-foreground))',
},
// ── InQ ROI brand tokens ──────────────────────────────────────────
// Uso: bg-inq-orange, bg-inq-orange-dark, bg-inq-magenta, etc.
// El gradiente identidad (#F59845 → #ED3E8F) se usa SOLO en KPI Hero
// y banners principales. NUNCA en bordes ni fondos secundarios.
inq: {
orange: {
DEFAULT: '#F59845',
dark: '#B45309',
light: '#FEF3E2',
lighter: '#FFF8ED',
},
magenta: '#ED3E8F',
},
// ── Heatmap (saturado, calibrado para análisis de píxeles E2E) ──
// DEBE coincidir con HEATMAP_LOW/MID/HIGH en src/lib/colors.ts.
// Cambiar solo en conjunto con recalibración de tests E2E.
heatmap: {
low: '#10b981',
mid: '#f59e0b',
high: '#ef4444',
low: '#10B981',
mid: '#F59E0B',
high: '#EF4444',
},
// ── Semánticos ───────────────────────────────────────────────────
success: {
DEFAULT: '#16A34A',
light: '#F0FDF4',
},
warning: {
DEFAULT: '#F59E0B',
bg: '#FFFBEB',
},
},
borderRadius: {

View File

@@ -0,0 +1,49 @@
/**
* Tests del sistema de diseño InQ ROI — Sprint 1.5.
*
* Verifican que los tokens de marca estén correctamente definidos en
* tailwind.config.js y que no haya contaminación de la marca hermana CONCILIA.
*
* Estos tests son la fuente de verdad del contrato de marca: si cambiás
* un token, el test falla y te fuerza a ser explícito con el cambio.
*/
import { describe, it, expect } from 'vitest'
// eslint-disable-next-line @typescript-eslint/no-require-imports
const tailwindConfig = require('../../tailwind.config.js').default ?? require('../../tailwind.config.js')
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const colors = (tailwindConfig.theme.extend.colors) as Record<string, any>
describe('Design tokens — paleta InQ ROI', () => {
it('expone tokens de marca InQ con estructura anidada correcta', () => {
const inq = colors.inq
expect(inq.orange.DEFAULT).toBe('#F59845')
expect(inq.orange.dark).toBe('#B45309')
expect(inq.orange.light).toBe('#FEF3E2')
expect(inq.orange.lighter).toBe('#FFF8ED')
expect(inq.magenta).toBe('#ED3E8F')
})
it('NO incluye los colores de CONCILIA (marca hermana, no mezclar)', () => {
const configStr = JSON.stringify(tailwindConfig)
// Morado primario de CONCILIA
expect(configStr).not.toContain('#572FA2')
expect(configStr).not.toContain('#572fa2')
// Magenta de CONCILIA
expect(configStr).not.toContain('#CB1889')
expect(configStr).not.toContain('#cb1889')
})
it('expone tokens del heatmap saturado (calibrado para tests E2E)', () => {
const heatmap = colors.heatmap
// Valores en mayúscula: #10B981, #F59E0B, #EF4444
// Deben coincidir con HEATMAP_LOW/MID/HIGH en src/lib/colors.ts
expect(heatmap.low).toBe('#10B981')
expect(heatmap.mid).toBe('#F59E0B')
expect(heatmap.high).toBe('#EF4444')
})
})

View File

@@ -0,0 +1,65 @@
/**
* Screenshots de validación visual — Etapa 1 Sprint 1.5.
*
* Captura 3 vistas que muestran la identidad InQ aplicada:
* 1. workspace.png — CTAs naranjas, Simular button, tabs
* 2. report-tabs.png — tab activo naranja en el reporte
* 3. switch-on.png — switch de automatización en estado ON naranja
*
* Estos screenshots son evidencia de que el cambio de --primary a naranja
* se ve correctamente en la aplicación real.
*/
import { test } from '@playwright/test'
import { resolve } from 'path'
import { mkdirSync } from 'fs'
import { fileURLToPath } from 'url'
const __dirname = fileURLToPath(new URL('.', import.meta.url))
const BPMN_DIR = resolve(__dirname, '../../public/sample-processes')
const OUT_DIR = resolve(__dirname, '../screenshots/etapa-1')
test.beforeAll(() => { mkdirSync(OUT_DIR, { recursive: true }) })
test('screenshot workspace — CTAs naranjas visibles', async ({ page }) => {
await page.goto('/')
await page.locator('#bpmn-file-input').setInputFiles(resolve(BPMN_DIR, 'simple-linear.bpmn'))
await page.waitForURL(/\/workspace\//, { timeout: 15_000 })
await page.waitForSelector('button:has-text("Simular")', { timeout: 10_000 })
await page.waitForTimeout(1_000)
await page.screenshot({ path: resolve(OUT_DIR, 'workspace.png'), fullPage: false })
})
test('screenshot switch ON — switch de automatización naranja', async ({ page }) => {
await page.goto('/')
await page.locator('#bpmn-file-input').setInputFiles(resolve(BPMN_DIR, 'simple-linear.bpmn'))
await page.waitForURL(/\/workspace\//, { timeout: 15_000 })
await page.waitForSelector('button:has-text("Simular")', { timeout: 10_000 })
await page.waitForTimeout(1_500)
// Hacer click en el primer task del BPMN para abrir el ActivityPanel
await page.locator('[data-element-id="task1"]').first().click()
await page.waitForTimeout(500)
// Encender el switch de automatización
const toggle = page.getByRole('switch', { name: /automatizable/i })
await toggle.click()
await page.waitForTimeout(300)
await page.screenshot({ path: resolve(OUT_DIR, 'switch-on.png'), fullPage: false })
})
test('screenshot report-tabs — tab activo naranja', async ({ page }) => {
await page.goto('/')
await page.locator('#bpmn-file-input').setInputFiles(resolve(BPMN_DIR, 'medium-with-gateways.bpmn'))
await page.waitForURL(/\/workspace\//, { timeout: 15_000 })
await page.waitForSelector('button:has-text("Simular")', { timeout: 10_000 })
await page.waitForTimeout(1_500)
const simBtn = page.getByRole('button', { name: 'Simular' })
await simBtn.click()
await page.waitForURL(/\/report\//, { timeout: 20_000 })
await page.waitForSelector('button:has-text("Exportar PDF")', { timeout: 20_000 })
await page.screenshot({ path: resolve(OUT_DIR, 'report-tabs.png'), fullPage: false })
})

View File

@@ -0,0 +1,21 @@
/**
* Tests de formatPayback — Sprint 1.5 Etapa 2.
*
* Stubs preparados. La implementación se agrega en Etapa 2.
* Los 7 casos están definidos en SPRINT_1_5_BRIEF_REDISENIO_VISUAL.md § 3.4.
*
* Regla: un payback de "0.0 meses" (como mostraba el sistema con costos
* artificialmente bajos) es confuso. formatPayback resuelve esto con
* una escala legible para el consultor y el cliente.
*/
import { describe, it } from 'vitest'
describe('formatPayback', () => {
it.todo('0 → "Inmediato" (inversión cero con ahorro positivo)')
it.todo('0.05 → "< 1 día" (payback de horas, prácticamente instantáneo)')
it.todo('0.5 → "< 1 mes (0.50 meses)"')
it.todo('6 → "6.0 meses"')
it.todo('15 → "15.0 meses (~1.3 años)"')
it.todo('30 → "2.5 años"')
it.todo('Infinity → "No recupera en horizonte"')
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB