Agent bundle · Markdown

Farmatodo Brand Manual — todas las secciones

Esta página está optimizada para agentes (LLMs, asistentes y herramientas automatizadas). Cada sección está renderizada como Markdown plano dentro de bloques <pre> para que pueda ser copiada o scrapeada sin pérdida de formato. Usa los anclas (#slug) para enlazar a una sección concreta.

Section · principles

00 · Principios de UI

# Principios de UI — Especificación completa

## 1. Marco
6 principios fundamentales que guían toda decisión de diseño. Cada
componente del sistema debe poder justificarse a través de al menos 2 de
ellos. Cuando hay conflicto, el orden de precedencia es:
**P4 > P1 > P2 > P3 > P5 > P6**.

---

## P1 · Claridad sobre densidad
**Aplica a**: Scorecards, Tipografía, Tablas, Dashboards.

Espacio negativo > información extra. Si un dato no es accionable, ocultarlo.
Cards con padding mínimo 24px. Tablas con altura de fila ≥ 40px. Una métrica
por scorecard, no múltiples.

**Test**: ¿Puedes eliminar el 30% del contenido sin perder función? Hazlo.

---

## P2 · Jerarquía con tipografía, no con color
**Aplica a**: Tipografía, Color, Componentes.

Usar peso (300/400/500/700) y tamaño antes que tono. El color es funcional
(estado, brand), no jerárquico. Un solo color de texto por bloque con
variaciones `foreground` / `muted-foreground`.

**Test**: Si imprimes la pantalla en B/N, ¿la jerarquía sigue siendo clara?

---

## P3 · Color con intención
**Aplica a**: Color, Data viz, Estados.

**Un acento por vista.** AI siempre `#1465FF`. CTAs primarios `#0040B9`.
Estados semánticos solo cuando hay estado real. No usar color para decorar.

**Test**: ¿Cada uso de color tiene un propósito comunicativo? Si no → quitar.

---

## P4 · AI como copiloto, no protagonista
**Aplica a**: AI components, Agent demo.

AiSpark acompaña, nunca domina. AI se integra al flujo existente, no lo
reemplaza. Confirmación obligatoria antes de mutar datos. Razonamiento
visible (no caja negra).

**Test**: ¿El usuario mantiene el control? ¿Puede entender qué hizo el agente?

---

## P5 · Iconografía consistente
**Aplica a**: Iconografía, Componentes.

Lucide stroke 1.75 en todo el sistema. Pétalos en múltiplos de 15°. AiSpark
exclusivo para AI. No mezclar familias de iconos.

**Test**: ¿Todos los iconos del flujo vienen del mismo set con el mismo stroke?

---

## P6 · Composición con espacio
**Aplica a**: Logo, Producto, Layouts.

Áreas de seguridad respetadas. Padding generoso (24px+ en cards). Ritmo
modular (escala 4px). Separación entre secciones ≥ 48px.

**Test**: ¿Todo elemento tiene aire suficiente? ¿El ritmo es consistente?

---

## 2. Aplicación cruzada
| Componente | Principios principales |
|---|---|
| Scorecard | P1, P2, P6 |
| Botón primario | P3, P5, P6 |
| AgentBubble | P4, P3, P5 |
| ConfirmCard | P4, P3, P1 |
| Sidebar | P1, P5, P6 |
| Tabla | P1, P2, P6 |
| Logo | P5, P6 |
| Data viz | P1, P2, P3 |

## 3. Anti-patrones (rompen los principios)
- ❌ Color para indicar jerarquía (rompe P2).
- ❌ AI omnipresente con sparkles decorativos (rompe P4).
- ❌ Mezclar iconos de Lucide + Heroicons (rompe P5).
- ❌ Cards sin padding interno (rompe P6).
- ❌ 5 series de color sin orden (rompe P1, P3).
- ❌ Mutaciones AI sin confirmación (rompe P4).

## 4. Decisión guiada
Cuando dudes sobre una decisión de diseño:
1. ¿Cuál es el principio dominante para este contexto?
2. ¿Mi solución lo refuerza o lo viola?
3. Si lo viola, ¿hay un principio de mayor precedencia que lo justifique?
4. Si no → cambiar la solución.

## 5. QA Checklist
- [ ] Cada componente respeta al menos 2 principios.
- [ ] Decisiones de color justificables por P2/P3.
- [ ] Decisiones AI justificables por P4.
- [ ] Sin anti-patrones documentados.
- [ ] Jerarquía sigue funcionando en B/N.
Section · colors

01 · Color

# Color — Especificación completa

## 1. Filosofía
Color con intención: **un acento por vista**. La jerarquía la define la
tipografía y el espacio, no el color. Los azules son el ADN de marca; los
estados son funcionales y no deben competir con la identidad.

## 2. Paleta de marca
| Token | Hex | OKLCH (referencia) | Uso primario |
|---|---|---|---|
| Azul Farmatodo | `#002858` | oklch(0.262 0.094 256) | Color principal, headers, fondos brand, CTAs sobre claro |
| Azul Profundo  | `#0040B9` | oklch(0.418 0.197 263) | CTAs primarios, énfasis tipográfico, links |
| Azul Eléctrico | `#1465FF` | oklch(0.572 0.220 263) | **Reservado para AI** — sparkle, AiSpark, highlights agénticos |
| Azul Cielo     | `#7B8FE6` | oklch(0.660 0.103 269) | Estado *waiting*, decorativo suave, ilustración |

## 3. Estados semánticos
| Estado | Hex | Uso | Pareja texto |
|---|---|---|---|
| Éxito  | `#27AE60` | Confirmaciones, badges *done* | Blanco o `#0E5F33` |
| Aviso  | `#F39C12` | Tareas en progreso, alertas no críticas | `#5C3B00` |
| Error  | `#E74C3C` | Errores, validaciones fallidas, destructivo | Blanco |
| Info   | `#1465FF` | Mensajes informativos AI | Blanco |

## 4. Neutros (tokens semánticos)
Definidos en `src/styles.css` en formato `oklch`:
```css
:root {
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --muted: oklch(0.97 0 0);
  --muted-foreground: oklch(0.556 0 0);
  --border: oklch(0.922 0 0);
  --primary: oklch(0.262 0.094 256);   /* #002858 */
  --primary-foreground: oklch(0.985 0 0);
}
```

Mapeo a Tailwind: `bg-background`, `text-foreground`, `text-muted-foreground`,
`border-border`, `bg-primary`, `text-primary-foreground`.

## 5. Reglas de combinación
1. Máximo **2 azules brand** por composición.
2. `#1465FF` solo en componentes AI (AiSpark, agent bubble eyebrow,
   highlights de "investigar en chat").
3. Estados (success/warn/error) **no** se mezclan entre sí en un mismo bloque.
4. Gradientes solo en hero/marketing, jamás en UI funcional.

## 6. Contraste mínimo (WCAG)
| Elemento | Ratio mínimo |
|---|---|
| Texto cuerpo (≤ 18px) | 4.5:1 (AA) |
| Texto grande (≥ 18px bold o 24px) | 3:1 (AA) |
| Componentes UI (bordes, iconos) | 3:1 |
| Texto sobre estado | 4.5:1 |

Verificar con herramientas como `npx @tailwindcss/contrast` o Stark.

## 7. Do / Don't
**DO**
- Usar tokens semánticos (`bg-primary`) en lugar de hex literales.
- Reservar `#1465FF` para AI.
- Usar `#0040B9` para CTAs primarios sobre fondo claro.

**DON'T**
- ❌ Hex literales en componentes (excepto specs documentales y tokens hard-coded).
- ❌ Más de 2 azules en un bloque.
- ❌ Rojo/verde para series neutrales en data viz.
- ❌ Texto `text-muted-foreground` sobre `bg-muted` (contraste insuficiente).

## 8. Snippet — definir un nuevo token
```css
/* src/styles.css */
:root {
  --ai-glow: oklch(0.572 0.220 263 / 0.12);
}
@theme inline {
  --color-ai-glow: var(--ai-glow);
}
/* Uso: bg-ai-glow */
```

## 9. QA Checklist
- [ ] Todos los textos pasan AA contra su fondo.
- [ ] AiSpark / acentos AI usan exclusivamente `#1465FF`.
- [ ] CTAs primarios usan `#0040B9` (no `#002858`).
- [ ] Sin hex literales en componentes nuevos (usar tokens).
- [ ] Estados semánticos respetan paleta (no inventar tonos).
Section · typography

02 · Tipografía

# Tipografía — Especificación completa

## 1. Familias
| Familia | Pesos | Ubicación | Uso |
|---|---|---|---|
| **Gotham** | 300, 400, 500, 700, 900 | self-hosted `/public/fonts/Gotham-*.woff2` | Display + UI |
| **JetBrains Mono** | 400, 600 | Google Fonts | Eyebrows, metadatos, código, tabular nums |

```css
/* src/styles.css */
@font-face { font-family: "Gotham"; src: url("/fonts/Gotham-Light.woff2") format("woff2");
  font-weight: 300; font-display: swap; }
/* …Book 400, Medium 500, Bold 700, Black 900 */

@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600&display=swap");
```

## 2. Escala tipográfica
| Token | Tamaño | Line-height | Peso típico | Uso |
|---|---|---|---|---|
| Display XL | 60–96px (`text-5xl` → `text-7xl`) | 0.95 | 300 | H1 portada |
| Display L  | 36–48px (`text-3xl` → `text-4xl`) | 1.05 | 300 / 400 | H1 sección |
| Display M  | 24–30px (`text-2xl` → `text-3xl`) | 1.1 | 400 | H2 |
| Title      | 18–20px (`text-lg` → `text-xl`) | 1.3 | 500 | Card titles |
| Body Lg    | 17–18px (`text-[17px]`) | 1.6 | 400 | Intro / lead |
| Body       | 15–16px (`text-base`) | 1.6 | 400 | Texto base |
| Body Sm    | 13–14px (`text-sm`) | 1.5 | 400 | UI secundaria |
| Caption    | 12px (`text-xs`) | 1.4 | 400 | Notas, ayudas |
| Eyebrow    | 10–11px UPPERCASE `tracking-[0.14em]` | 1.2 | 400 mono | Etiquetas de sección |

## 3. Pesos · cuándo usar cada uno
- **300 Light** → cifras grandes, displays. Da aire y elegancia.
- **400 Book** → caballo de batalla del cuerpo de texto.
- **500 Medium** → títulos de card, navegación activa, énfasis sutil.
- **700 Bold** → CTAs, etiquetas de estado, énfasis fuerte.
- **900 Black** → reservado para titulares enfáticos. **Nunca para párrafos**.

## 4. Reglas tipográficas
1. **Jerarquía con peso/tamaño, no con color.** Un solo color de texto por bloque
   con variaciones `text-foreground` / `text-muted-foreground`.
2. **Eyebrows siempre** en JetBrains Mono UPPERCASE `tracking-[0.14em]`.
3. **Líneas largas** ≤ 75 caracteres (`max-w-2xl` aprox).
4. **Tabular nums** para números en tablas: `font-variant-numeric: tabular-nums`.
5. **No mezclar** más de 2 pesos por bloque.
6. **No usar UPPERCASE** para texto corrido (solo eyebrows y badges cortos).
7. **Italic** solo para citas o énfasis breve. No para titulares.

## 5. Pairing canónico
```tsx
<div>
  <div className="font-mono text-[10px] uppercase tracking-[0.14em] text-muted-foreground">
    Sección 03
  </div>
  <h2 className="font-display text-3xl mt-2">Título de sección</h2>
  <p className="text-sm text-muted-foreground mt-3 leading-relaxed max-w-xl">
    Subtítulo o descripción en body sm con muted foreground.
  </p>
</div>
```

## 6. Do / Don't
**DO**
- Display 300 para cifras grandes (`font-display text-5xl font-light`).
- Eyebrow mono UPPERCASE para etiquetar secciones.
- Tabular nums en métricas.

**DON'T**
- ❌ Fuentes del sistema o fallback decorativo.
- ❌ Más de 2 pesos por bloque.
- ❌ UPPERCASE en párrafos.
- ❌ Italic en titulares.
- ❌ Line-height < 1.4 en body.

## 7. Accesibilidad
- Tamaño mínimo legible: 12px (solo metadatos).
- Body siempre ≥ 14px.
- Contraste 4.5:1 mínimo (ver Color spec).
- No justificar texto largo (causa rivers).

## 8. QA Checklist
- [ ] Display usa Gotham 300/400.
- [ ] Eyebrows en mono UPPERCASE `tracking-[0.14em]`.
- [ ] Líneas de texto ≤ 75 caracteres.
- [ ] Máximo 2 pesos por bloque.
- [ ] Body ≥ 14px.
- [ ] Tabular nums en tablas/scorecards.
Section · iconography

04 · Iconografía

# Iconografía — Especificación completa

## 1. Dos sistemas paralelos
La marca usa **dos** sistemas de iconografía con propósitos distintos:

### A. Pétalos (decorativos / brand)
ADN visual de Farmatodo. Forma orgánica de gota inscrita en cuadrado. Tres
tonos azules generan profundidad sin perder identidad.

| Pétalo | Hex | Archivo |
|---|---|---|
| 1 — Azul Farmatodo | `#002858` | `@/assets/petalo-1.svg` |
| 2 — Azul Profundo  | `#0040B9` | `@/assets/petalo-2.svg` |
| 3 — Azul Eléctrico | `#1465FF` | `@/assets/petalo-3.svg` |

### B. Iconos UI (funcionales)
Set único: **`lucide-react`** (con algunas excepciones documentadas en
`@radix-ui/react-icons` para iconos abstractos).

```tsx
import { Search, Bell, ArrowRight } from "lucide-react";
<Search className="w-4 h-4" strokeWidth={1.75} />
```

## 2. Reglas — Pétalos
- Rotación en **múltiplos de 15°** (0°, 15°, 30°, 45°, …).
- Composición libre: máximo 3 pétalos por agrupación visual.
- Sobre fondos brand → versión blanca (`brightness-0 invert`).
- Pueden solaparse parcialmente (overlap 20–40% del ancho).
- **Nunca**: gradientes internos, sombras, outline, ni colores fuera de la paleta.

## 3. Reglas — Iconos UI
| Atributo | Valor |
|---|---|
| Set | lucide-react |
| Stroke width | **1.75** (default brand) |
| Tamaño base | 16px (`w-4 h-4`) |
| Tamaño táctil | 24px en hit area de 40×40px mínimo |
| Color por defecto | `currentColor` (heredan del padre) |
| Estilo | Outline (no relleno) salvo estados activos |

### Tamaños canónicos
| Contexto | Tamaño | Clase |
|---|---|---|
| Inline en texto | 12–14px | `w-3 h-3` / `w-3.5 h-3.5` |
| UI estándar | 16px | `w-4 h-4` |
| Botones grandes | 20px | `w-5 h-5` |
| Hero / iconografía decorativa | 32–48px | `w-8 h-8` / `w-12 h-12` |

## 4. AiSpark — caso especial
```tsx
import { Sparkles } from "lucide-react";
export function AiSpark({ className = "w-4 h-4" }) {
  return <Sparkles className={className} strokeWidth={2} style={{ color: "#1465FF" }} />;
}
```
Reservado **exclusivamente** para componentes AI. No usar como icono decorativo.

## 5. Do / Don't
**DO**
- Combinar máximo 3 pétalos por composición libre.
- Usar pétalos en blanco sobre azul brand.
- Mantener stroke 1.75 consistente.
- `aria-label` en iconos sin texto acompañante.

**DON'T**
- ❌ Mezclar familias (lucide + heroicons + tabler).
- ❌ Rellenar pétalos con gradientes.
- ❌ Iconos rellenos para acciones (solo para estados activos).
- ❌ AiSpark en contextos no-AI.
- ❌ Stroke distinto a 1.75 (rompe consistencia visual).

## 6. Snippet — botón con icono
```tsx
<button className="inline-flex items-center gap-2 px-3 py-2 rounded-md hover:bg-muted">
  <Search className="w-4 h-4" strokeWidth={1.75} />
  <span className="text-sm">Buscar</span>
</button>
```

## 7. Accesibilidad
- Iconos decorativos: `aria-hidden="true"`.
- Iconos accionables sin texto: `aria-label="Descripción acción"`.
- Hit area mínima 44×44px en mobile (puede ser mayor que el visual).

## 8. QA Checklist
- [ ] Iconos lucide stroke 1.75.
- [ ] Pétalos en tonos definidos, rotación múltiplo de 15°.
- [ ] AiSpark solo en componentes AI.
- [ ] Sin mezcla de sets.
- [ ] aria-label en iconos sin texto.
- [ ] Hit area ≥ 44px en mobile.
Section · product

05 · Producto (UI Components)

# Producto (UI Components) — Especificación completa

## 1. Tokens base

### Espaciado (escala 4px)
| Token | px | Clase |
|---|---|---|
| 0.5 | 2 | `gap-0.5` |
| 1 | 4 | `gap-1` |
| 2 | 8 | `gap-2` |
| 3 | 12 | `gap-3` |
| 4 | 16 | `gap-4` |
| 6 | 24 | `gap-6` |
| 8 | 32 | `gap-8` |
| 12 | 48 | `gap-12` |

### Radios
| Token | Valor | Uso |
|---|---|---|
| `rounded-md` | 6px | Inputs, chips, botones pequeños |
| `rounded-lg` | 8px | Botones estándar |
| `rounded-xl` | 12px | CTAs, badges |
| `rounded-2xl` | 16px | Cards, contenedores |
| `rounded-full` | 9999px | Burbujas chat, avatares |

### Sombras
- Solo para elevación crítica (popover, modal).
- Default: `shadow-sm` para cards interactivas.
- Brand glow: `box-shadow: 0 8px 22px -8px <accent>` para CTAs destacados.

## 2. Anatomía de componentes

### Card
```tsx
<div className="border border-border rounded-2xl bg-background p-6">
  <div className="font-mono text-[10px] uppercase tracking-[0.14em] text-muted-foreground">
    Eyebrow
  </div>
  <h3 className="font-display text-xl mt-2">Título</h3>
  <p className="text-sm text-muted-foreground mt-2">Descripción</p>
</div>
```

### Botón primario
```tsx
<button
  className="inline-flex items-center gap-2 px-4 py-2.5 rounded-xl text-sm font-medium text-white hover:opacity-90 transition-opacity"
  style={{ backgroundColor: "#0040B9" }}
>
  Acción primaria
</button>
```

### Botón secundario
```tsx
<button className="inline-flex items-center gap-2 px-4 py-2.5 rounded-xl text-sm border border-border bg-background hover:bg-muted">
  Acción secundaria
</button>
```

### Botón destructivo
```tsx
<button className="px-4 py-2.5 rounded-xl text-sm text-white" style={{ backgroundColor: "#E74C3C" }}>
  Eliminar
</button>
```

### Input
```tsx
<input
  className="h-10 w-full rounded-md border border-border bg-background px-3 text-sm focus:outline-none focus:ring-2 focus:ring-primary"
  placeholder="Buscar…"
/>
```

### Badge / Chip
```tsx
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs border border-border bg-background">
  Etiqueta
</span>
```

## 3. Estados (canónicos)
| Estado | Tratamiento visual | Snippet |
|---|---|---|
| Hover  | `hover:bg-muted` o `hover:opacity-90` | — |
| Active | `bg-muted font-medium` | — |
| Focus  | Ring 2px brand + offset 2px | `focus:ring-2 focus:ring-primary focus:ring-offset-2` |
| Disabled | `opacity-50 pointer-events-none` + `cursor-not-allowed` | `disabled:opacity-50 disabled:pointer-events-none` |
| Loading | Loader2 animado + texto "Cargando" | `<Loader2 className="w-4 h-4 animate-spin" />` |
| Error | Border `border-destructive` + mensaje debajo | — |

## 4. Patrones de layout

### Sección con eyebrow lateral
```tsx
<section className="px-6 lg:px-10 py-12 border-b border-border">
  <div className="grid lg:grid-cols-[140px_1fr] gap-6 lg:gap-10">
    <div className="font-mono text-[10px] text-muted-foreground sticky top-8">5.1 Bloque</div>
    <div>
      <h2 className="font-display text-2xl lg:text-3xl mb-8">Título</h2>
      {/* contenido */}
    </div>
  </div>
</section>
```

### Grid de cards
- Mobile: 1 col
- Tablet: 2 cols (`md:grid-cols-2`)
- Desktop: 3 cols (`lg:grid-cols-3`)
- Gap: `gap-6` (24px)

## 5. Reglas
1. Padding interno mínimo de cards: **24px** (`p-6`).
2. Separación entre secciones: **48px** (`py-12` o más).
3. Bordes `rounded-2xl` para contenedores, `rounded-xl` para CTAs.
4. Máximo 2 niveles de anidamiento de cards.
5. Sombras solo para elevación crítica (popover, modal, dropdown).
6. Una acción primaria por vista — el resto son secundarias o link.

## 6. Do / Don't
**DO**
- Tokens semánticos para color (`bg-primary`, `text-foreground`).
- Foco visible siempre.
- Touch target ≥ 44px en mobile.

**DON'T**
- ❌ Mezclar radios sin propósito (`rounded-md` + `rounded-3xl` en un mismo grupo).
- ❌ Anidar más de 2 cards.
- ❌ Sombras decorativas.
- ❌ Múltiples CTAs primarios en una vista.

## 7. Accesibilidad
- Contraste 4.5:1 cuerpo, 3:1 grande.
- Focus ring visible — outline 2px Azul Brillante con offset 2px.
- Áreas táctiles ≥ 44×44px en mobile.
- Iconos sin texto → `aria-label`.
- Estados disabled comunicados por más que opacidad (`aria-disabled`, cursor).
- Modales con `role="dialog"` + `aria-modal="true"` + focus trap.

## 8. QA Checklist
- [ ] Estados hover / active / focus / disabled visibles.
- [ ] Padding interno ≥ 24px en cards.
- [ ] Foco con ring 2px y offset.
- [ ] Touch target ≥ 44px.
- [ ] Una sola acción primaria por vista.
- [ ] Sin sombras decorativas.
- [ ] Tokens semánticos (sin hex literales).
Section · data-viz

06 · Data Viz

# Data Viz — Especificación completa

## 1. Principios
1. **Claridad sobre densidad** — espacio negativo > información extra.
2. **Color con intención** — una serie, un tono. Color para diferenciar, no decorar.
3. **Etiquetas siempre legibles** — ≥ 11px, contraste AA.
4. **Tabular numbers** en métricas.
5. **Cero ≠ vacío** — usar `—` para faltante, `0` solo cuando sea real.
6. **Orden con intención** — descendente por valor por defecto, salvo orden temporal.

## 2. Paleta de series
| Serie | Hex | Uso |
|---|---|---|
| Principal | `#0040B9` | Serie destacada |
| Secundaria | `#1465FF` | Comparativo principal |
| Terciaria | `#7B8FE6` | Tercera serie |
| Cuaternaria | `#94A3B8` | Comparativo neutro / benchmark |
| Positivo | `#27AE60` | Delta positivo |
| Negativo | `#E74C3C` | Delta negativo |
| Neutro | `#94A3B8` | Sin cambio |

Máximo **4 series** por gráfico. Más → usar small multiples.

## 3. Componentes

### Scorecard
```tsx
<div className="border border-border rounded-2xl p-6">
  <div className="font-mono text-[10px] uppercase tracking-[0.14em] text-muted-foreground">
    Ventas mes
  </div>
  <div className="font-display text-5xl font-light mt-3 tabular-nums">
    $124.530
  </div>
  <div className="flex items-center gap-1.5 mt-2 text-xs">
    <ArrowUp className="w-3 h-3" style={{ color: "#27AE60" }} />
    <span style={{ color: "#27AE60" }}>+12,4%</span>
    <span className="text-muted-foreground">vs mes anterior</span>
  </div>
</div>
```

### Filter chip clicable
- Trigger: chip con label + ChevronDown.
- Click → dropdown absoluto (`z-20`) con click-outside-close.
- ChevronDown rota 180° cuando está abierto.
- Selección actualiza label + cierra dropdown.

### Tabla
- Header: `bg-muted/50`, eyebrow mono UPPERCASE.
- Rows: hover `bg-muted/30`, separador `border-t border-border`.
- Números alineados a la derecha + `tabular-nums`.
- Sticky header en tablas largas.

## 4. Anatomía de gráficos

### Ejes
- Línea: `#94A3B8` 1px.
- Gridlines: `#94A3B8` con `opacity-30`, solo horizontales.
- Labels: 11px, `text-muted-foreground`.
- Tick marks: cada N para evitar saturación.

### Tooltip
```tsx
<div className="rounded-lg border border-border bg-background shadow-md px-3 py-2 text-xs">
  <div className="font-medium">Marzo 2026</div>
  <div className="flex items-center gap-2 mt-1">
    <span className="w-2 h-2 rounded-full" style={{ backgroundColor: "#0040B9" }} />
    <span>Ventas:</span>
    <span className="font-mono tabular-nums">$124.530</span>
  </div>
</div>
```

### Leyenda
- Posición: arriba-derecha o abajo del gráfico.
- Dot 8px del color de la serie + label 12px.
- Click en leyenda → toggle visibilidad (opcional).

## 5. Tipos de gráfico — cuándo usar
| Tipo | Cuándo |
|---|---|
| Línea | Tendencia temporal continua |
| Barra vertical | Comparación entre categorías (≤ 12) |
| Barra horizontal | Categorías con label largo o muchas (>12) |
| Área apilada | Composición a lo largo del tiempo |
| Donut | Composición parte/todo (≤ 5 segmentos) — preferir barras |
| Scatter | Correlación entre 2 variables |
| Sparkline | Tendencia inline en tabla/scorecard |

**Evitar**: pie con > 5 segmentos, 3D, eje Y truncado sin indicarlo.

## 6. Deltas y comparativos
```tsx
function Delta({ value }: { value: number }) {
  const Icon = value > 0 ? ArrowUp : value < 0 ? ArrowDown : Minus;
  const color = value > 0 ? "#27AE60" : value < 0 ? "#E74C3C" : "#94A3B8";
  const sign = value > 0 ? "+" : "";
  return (
    <span className="inline-flex items-center gap-1 text-xs font-medium tabular-nums" style={{ color }}>
      <Icon className="w-3 h-3" />
      {sign}{value}%
    </span>
  );
}
```

## 7. Do / Don't
**DO**
- Filtros clicables con dropdown.
- Deltas con flecha + signo + color.
- Tooltip con valor exacto al hover.
- Tabular nums en cifras.
- Ordenar descendente por defecto.

**DON'T**
- ❌ Más de 4 series por gráfico.
- ❌ 3D, sombras decorativas, gradientes innecesarios.
- ❌ Rojo/verde para series neutrales (reservar para deltas).
- ❌ Eje Y truncado sin indicador (`~` o break).
- ❌ Pie con > 5 segmentos.
- ❌ Filtros decorativos no clicables.

## 8. Accesibilidad
- Color **+** texto: nunca solo color para distinguir series.
- Patterns/dashes alternativos para daltonismo.
- Tabla equivalente disponible para screen readers.
- Alt text descriptivo en gráficos exportados como imagen.

## 9. QA Checklist
- [ ] Filtros responden a click (no decorativos).
- [ ] Deltas con signo, color y flecha.
- [ ] Ejes legibles en mobile (≥ 11px).
- [ ] Tabular nums en métricas y tablas.
- [ ] Máximo 4 series por gráfico.
- [ ] Tooltip con valor exacto.
- [ ] Cero distinguido de faltante.
Section · ai-components

07 · AI Components

# AI Components — Especificación completa

## 1. Filosofía
**AI como copiloto, no protagonista.** El sparkle azul (`#1465FF`) es la firma
de marca AI. Burbujas redondeadas y tonos brand diferencian acción humana,
agente y sistema. Las experiencias agénticas siempre permiten cancelar y
confirman antes de mutar datos.

## 2. AiSpark (marca AI)
```tsx
import { Sparkles } from "lucide-react";
export function AiSpark({ className = "w-4 h-4" }: { className?: string }) {
  return <Sparkles className={className} strokeWidth={2} style={{ color: "#1465FF" }} />;
}
```

| Tamaño | Clase | Uso |
|---|---|---|
| 16px | `w-4 h-4` | Inline en texto, eyebrow de burbuja |
| 24px | `w-6 h-6` | Headers de bloque AI |
| 40px | `w-10 h-10` | Hero, splash agente |

## 3. Burbujas de chat

### UserBubble
```tsx
<div className="flex justify-end">
  <div className="max-w-[80%] px-5 py-3 rounded-full text-sm text-white" style={{ backgroundColor: "#0040B9" }}>
    {children}
  </div>
</div>
```
- Fondo: `#0040B9` (Azul Profundo).
- Border radius: `rounded-full` (pill).
- Alineada a la derecha.

### AgentBubble
```tsx
<div className="space-y-2 max-w-[80%]">
  <div className="flex items-center gap-2 px-1">
    <AiSpark className="w-3 h-3" />
    <span className="font-mono text-[10px] text-muted-foreground">{agent}</span>
  </div>
  <div className="px-5 py-3 rounded-2xl text-sm bg-muted/60 text-foreground">
    {children}
  </div>
</div>
```
- Fondo: `bg-muted/60`.
- Border radius: `rounded-2xl` (no pill).
- Eyebrow obligatorio: AiSpark + nombre del agente.

## 4. Stepper (borrador agéntico)
Estados:
| Estado | Visual |
|---|---|
| `done` | Check azul `#0040B9` strokeWidth 3 |
| `current` | Dot azul lleno + label en bold |
| `todo` | Círculo con border, label muted |
| `ready` | Check con halo, indica listo para confirmar |

## 5. AgentThinking (razonamiento)
- Lista de pasos colapsable.
- Cada paso: status (`done` / `doing` / `todo`), label, detail opcional, duration.
- `doing` muestra `Loader2` animado en `#1465FF`.
- Modo `collapsed` cuando termina, mostrar resumen.

## 6. Confirmación (diálogos finales)

### ConfirmCard
- Stroke 3px en color accent (`accent + opacity 40`).
- Halo blur (`blur-3xl`, `accent + opacity 10`).
- Eyebrow mono UPPERCASE: "Confirmación" o "Atención" (destructivo).
- Icono central en círculo `3px solid accent`, fondo halo.
- Botón confirmar con `box-shadow: 0 8px 20px -8px <accent>`.
- `onCancel` y `onConfirm` requeridos.

### CelebrationCard
- ConfettiBg animado (7 dots).
- RocketIcon en círculo accent.
- Título display 3xl.
- CTA primario con glow.

### Tonos
| Tone | Accent | Eyebrow |
|---|---|---|
| default | `#0040B9` | "Confirmación" |
| destructive | `#E74C3C` | "Atención" |

## 7. Sidebar AI

### Estructura
```
SidebarShell (280px)
├── SidebarBrand (workspace + agent)
├── NewChatButton
├── SidebarSection "Navegación"
│   └── SidebarNavItem × N
├── SidebarDivider
├── SidebarSection "Acciones rápidas"
│   └── QuickAction × N
├── SidebarDivider
├── SidebarSection "Tarea actual"
│   └── TaskProgressCard
├── SidebarDivider
├── SidebarSection "Conversaciones"
│   └── ChatRow × N
└── AgentStatusCard (footer)
```

### Tokens del sidebar
- Ancho: `280px`.
- Eyebrow de grupo: `font-mono text-[10px] uppercase tracking-[0.14em] text-muted-foreground`.
- Divisor: `border-t border-border` con margen `mx-4`.
- Items: padding `px-3 py-2`, hover `bg-muted/50`, active `bg-muted font-medium`.
- Status dots: 6px (`w-1.5 h-1.5`).
  - `in_progress` `#F39C12`
  - `waiting` `#7B8FE6`
  - `done` `#27AE60`
  - `draft` `#94A3B8`

## 8. ContextualSummary ("Lo que está pasando")
- Eyebrow con AiSpark + label UPPERCASE.
- Bullets con tono (`warn` `#F39C12` / `info` `#1465FF` / `ok` `#27AE60`).
- Términos investigables como `<button>` con `underline decoration-dotted decoration-[2px] underline-offset-[6px]`.
- Subrayado **gris** `#CBD5E1` → descriptivo (entidad, contexto).
- Subrayado **azul** `#1465FF` → métrica o delta clave.
- Hint inferior con flecha → "Toca cualquier subrayado para investigar en chat".

```tsx
<ContextualSummary
  items={[
    { tone: "warn", parts: [
      { text: "10 personas están de baja en " },
      { text: "3 tiendas", hl: "muted", bold: true },
      { text: " (Medellín, Recoleta, La Plata)." },
    ]},
  ]}
  onInvestigate={(text) => openChatWith(text)}
/>
```

## 9. Streaming AI (implementación)
- Llamadas vía edge function — **nunca** desde cliente.
- API key en backend (`LOVABLE_API_KEY`).
- SSE token-by-token, parsear línea a línea, manejar CRLF y `[DONE]`.
- Manejar 429 (rate limit) y 402 (créditos) con toast claro.
- Markdown rendering en respuestas (`react-markdown`).
- Enviar **toda** la conversación en cada request (memoria).

## 10. Do / Don't
**DO**
- AiSpark en todo elemento operado por agente.
- Streaming para respuestas largas.
- Confirmación obligatoria antes de mutaciones.
- Permitir cancelar pasos del agente.
- Mostrar pasos de razonamiento colapsables.

**DON'T**
- ❌ AI como elemento dominante visual (es copiloto).
- ❌ Exponer prompts o API keys en cliente.
- ❌ Llamar al modelo directamente desde el browser.
- ❌ Mezclar AiSpark con CTAs primarios sin contexto AI.
- ❌ Mutaciones sin confirmación explícita.

## 11. Accesibilidad
- Burbujas con `role="log"` + `aria-live="polite"`.
- Loaders con `aria-busy="true"`.
- Streaming visible para screen readers cuando termina cada token.
- Botones de confirmación con label descriptivo (no solo "OK").

## 12. QA Checklist
- [ ] AiSpark consistente en todos los componentes AI.
- [ ] Streaming sin saltos ni texto duplicado.
- [ ] Estados 429 / 402 con toast amigable.
- [ ] Confirmación antes de mutar datos.
- [ ] Cancelable en cualquier paso.
- [ ] Memoria conversacional completa enviada al modelo.
- [ ] Markdown renderizado en respuestas.
Section · agent-demo

08 · Agent Demo

# Agent Demo — Especificación completa

## 1. Propósito
Demostración integrada del flujo agéntico end-to-end. Combina sidebar AI,
chat, razonamiento, borrador con stepper, diff de impacto y confirmación.
Sirve como referencia de implementación para construir flujos similares.

## 2. Flujo canónico (6 pasos)
1. **Intent** — usuario envía instrucción en lenguaje natural via `AiInput`.
2. **Razonamiento** — agente muestra `AgentThinking` con pasos visibles.
3. **Borrador** — `AgentStepper` con campos editables (Empleado, Destino, Vigencia, Confirmar).
4. **Impacto** — `DiffCard` muestra qué cambia (sale de / entra a, deltas).
5. **Confirmación** — `ConfirmCard` con tono según destructividad.
6. **Éxito** — `CelebrationCard` confirma y ofrece próxima acción.

## 3. Componentes obligatorios
| Componente | Rol |
|---|---|
| `AgentTaskHeader` | Título de la tarea en curso |
| `AgentThinking` | Pasos de razonamiento visibles |
| `AgentStepper` | Borrador con estado por campo |
| `DiffCard` | Resumen de impacto antes/después |
| `RelationRow` | Personas relacionadas (encargado, etc.) |
| `ConfirmCta` | Botón principal con shortcut ⌘↵ |
| `ConfirmCard` | Diálogo de confirmación |
| `CelebrationCard` | Diálogo de éxito |

## 4. Layout (3 columnas)
```
┌─────────────┬──────────────────────┬──────────────┐
│  Sidebar    │  Chat / Razonamiento │  Borrador    │
│  (280px)    │  (flex-1)            │  (380px)     │
│             │                      │              │
│  Nav        │  AgentThinking       │  Stepper     │
│  Acciones   │  Bubbles             │  DiffCard    │
│  Convers.   │  AiInput             │  ConfirmCta  │
└─────────────┴──────────────────────┴──────────────┘
```

## 5. Reglas
1. Cada paso del agente debe ser **cancelable**.
2. ETA visible cuando aplique (ej. "~30s").
3. Toda acción **destructiva** pasa por `ConfirmCard` con `tone="destructive"`.
4. Estados de error con retry visible.
5. Chat persiste durante la sesión (no se borra al confirmar).
6. Borrador se actualiza en vivo conforme el agente extrae datos.
7. Shortcut `⌘↵` confirma cuando `ready === true`.

## 6. Estados de la tarea
| Estado | Indicador | Acción permitida |
|---|---|---|
| `gathering` | AgentThinking activo | Cancelar |
| `drafting` | Stepper en `current` | Editar campos |
| `ready` | Stepper en `ready` | Confirmar / Editar |
| `confirming` | ConfirmCard abierta | Confirmar / Cancelar |
| `success` | CelebrationCard | Cerrar / Próxima acción |
| `error` | Toast + estado anterior | Retry / Cancelar |

## 7. Snippet — hook de progreso
```tsx
function useThinkingProgress(ready: boolean) {
  const [index, setIndex] = useState(0);
  useEffect(() => {
    if (!ready) return;
    setIndex(0);
    const id = setInterval(() => {
      setIndex((i) => (i >= STEPS.length ? (clearInterval(id), i) : i + 1));
    }, 900);
    return () => clearInterval(id);
  }, [ready]);
  return STEPS.map((s, i) => ({
    ...s,
    status: i < index ? "done" : i === index ? "doing" : "todo",
  }));
}
```

## 8. Do / Don't
**DO**
- Mostrar razonamiento (transparencia).
- Permitir editar el borrador antes de confirmar.
- Confirmar mutaciones siempre.

**DON'T**
- ❌ Ejecutar acciones sin confirmación.
- ❌ Ocultar pasos de razonamiento (caja negra).
- ❌ Bloquear edición durante el borrador.
- ❌ Cerrar el chat al confirmar.

## 9. QA Checklist
- [ ] Flujo completo en ≤ 4 pantallas.
- [ ] Confirmación obligatoria antes de mutar.
- [ ] Estado de error con retry.
- [ ] Cancelable en cualquier paso.
- [ ] Shortcut ⌘↵ funcional.
- [ ] Borrador se actualiza en vivo.
- [ ] CelebrationCard ofrece próxima acción.