# Interfaz de aplicación de Quov: instrucciones para agentes de IA

Usa este archivo cuando diseñes o construyas una interfaz de producto de Quov: una pantalla de aplicación, un tablero, un back office, un portal detrás de un inicio de sesión. Carga primero `quov-brand.es.md` (https://quov.io/design-system/quov-brand.es.md); este archivo aplica la marca a la interfaz de producto y nunca la contradice.

Los archivos del logo están listados en el archivo de marca y se sirven desde `https://quov.io/design-system/logo/`. En la aplicación, el símbolo sigue el tema: el círculo en `--mark`, las letras en `--foreground` (el SVG en línea del archivo de marca). Nunca vuelvas a dibujar el símbolo.

## Postura

Densa, exacta, como un libro mayor. Las cifras son la interfaz; todo lo demás son filetes y un andamiaje silencioso a su alrededor. La confianza se gana con claridad y contención, nunca con decoración.

1. **Las cifras son la interfaz.** Toda cantidad, porcentaje y fecha va en monoespaciada y con cifras tabulares, para que las columnas se alineen y las cifras se lean, no se descifren.
2. **El color significa algo, y nada más.** Los tonos de ganancia, pérdida y advertencia aparecen solo con significado financiero o de estado. Las superficies neutras cargan con el resto.
3. **Estructura con filetes, no tarjetas flotantes.** La profundidad son bordes de cerca de 10% de opacidad, sin sombras.
4. **Precisión antes que simpatía.** Radio pequeño, escala tipográfica ajustada, espaciado contenido. Un instrumento, no una aplicación que quiere caer bien.
5. **La claridad gana confianza.** Ante la duda, quita en lugar de agregar. Un lector nunca debe tener que interpretar; un operador nunca debe tener que buscar.

Si una pantalla puede confundirse con una plantilla genérica de analítica, ha fallado.

## Temas

El oscuro es el predeterminado; el papel es la alternativa, que el usuario activa y que se recuerda. Ambos temas comparten todos los nombres de token; solo cambian los valores. A mayor elevación, un poco más claro en oscuro y un poco más blanco sobre papel.

## Tokens

El conjunto completo, en Tailwind CSS 4. La paleta base es la de la marca; la aplicación agrega superficies, colores semánticos y una rampa para gráficos.

```css
@import 'tailwindcss';
@import '@fontsource/aoboshi-one/latin-400.css';
@import '@fontsource-variable/geist';
@import '@fontsource-variable/geist-mono';

@custom-variant light (&:where([data-theme='light'], [data-theme='light'] *));

@theme inline {
  --font-heading: 'Aoboshi One', ui-serif, Georgia, serif;
  --font-sans: 'Geist Variable', 'Geist', ui-sans-serif, system-ui, sans-serif;
  --font-mono: 'Geist Mono Variable', 'Geist Mono', ui-monospace, Menlo, monospace;
  --radius-sm: calc(var(--radius) * 0.6);
  --radius-md: calc(var(--radius) * 0.8);
  --radius-lg: var(--radius);

  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);
  --color-popover: var(--popover);
  --color-popover-foreground: var(--popover-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-destructive: var(--destructive);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --color-mark: var(--mark);
  --color-sidebar: var(--sidebar);
  --color-table-header: var(--table-header);
  --color-table-header-foreground: var(--table-header-foreground);
  --color-gain: var(--gain);
  --color-gain-muted: var(--gain-muted);
  --color-loss: var(--loss);
  --color-loss-muted: var(--loss-muted);
  --color-warn: var(--warn);
  --color-warn-muted: var(--warn-muted);
  --color-chart-1: var(--chart-1);
  --color-chart-2: var(--chart-2);
  --color-chart-3: var(--chart-3);
  --color-chart-4: var(--chart-4);
  --color-chart-5: var(--chart-5);
}

/* Dark (default): cold slate, hue 260. */
:root {
  color-scheme: dark;
  --radius: 0.375rem;
  --background: oklch(0.11 0.01 260);
  --foreground: oklch(0.93 0.01 260);
  --card: oklch(0.15 0.01 260);
  --card-foreground: oklch(0.93 0.01 260);
  --popover: oklch(0.17 0.015 260);
  --popover-foreground: oklch(0.93 0.01 260);
  --primary: oklch(0.93 0 0);
  --primary-foreground: oklch(0.13 0 0);
  --secondary: oklch(0.2 0.01 260);
  --secondary-foreground: oklch(0.85 0.01 260);
  --muted: oklch(0.2 0.01 260);
  --muted-foreground: oklch(0.64 0.01 260);
  --destructive: oklch(0.65 0.2 25);
  --border: oklch(1 0 0 / 10%);
  --input: oklch(1 0 0 / 12%);
  --ring: oklch(0.55 0.01 260);
  --mark: oklch(0.06 0.005 260);
  --sidebar: oklch(0.13 0.01 260);
  --table-header: oklch(0.15 0.01 260);
  --table-header-foreground: oklch(0.64 0.01 260);
  --gain: oklch(0.75 0.15 160);
  --gain-muted: oklch(0.75 0.15 160 / 12%);
  --loss: oklch(0.7 0.17 25);
  --loss-muted: oklch(0.7 0.17 25 / 12%);
  --warn: oklch(0.8 0.15 85);
  --warn-muted: oklch(0.8 0.15 85 / 12%);
  --chart-1: oklch(0.87 0 0);
  --chart-2: oklch(0.55 0 0);
  --chart-3: oklch(0.44 0 0);
  --chart-4: oklch(0.37 0 0);
  --chart-5: oklch(0.27 0 0);
}

/* Light: sugar-cane paper, hue 75. */
:root[data-theme='light'] {
  color-scheme: light;
  --background: oklch(0.95 0.02 75);
  --foreground: oklch(0.18 0.01 75);
  --card: oklch(0.98 0.015 75);
  --card-foreground: oklch(0.18 0.01 75);
  --popover: oklch(0.99 0.01 75);
  --popover-foreground: oklch(0.18 0.01 75);
  --primary: oklch(0.18 0 0);
  --primary-foreground: oklch(0.95 0.02 75);
  --secondary: oklch(0.91 0.02 75);
  --secondary-foreground: oklch(0.25 0.01 75);
  --muted: oklch(0.91 0.02 75);
  --muted-foreground: oklch(0.48 0.01 75);
  --destructive: oklch(0.55 0.2 25);
  --border: oklch(0 0 0 / 10%);
  --input: oklch(0 0 0 / 8%);
  --ring: oklch(0.48 0.02 75);
  --mark: oklch(0.995 0.005 75);
  --sidebar: oklch(0.93 0.02 75);
  --table-header: oklch(0.48 0.015 75);
  --table-header-foreground: oklch(0.92 0.015 75);
  --gain: oklch(0.45 0.15 160);
  --gain-muted: oklch(0.45 0.15 160 / 10%);
  --loss: oklch(0.5 0.17 25);
  --loss-muted: oklch(0.5 0.17 25 / 10%);
  --warn: oklch(0.48 0.13 85);
  --warn-muted: oklch(0.48 0.13 85 / 10%);
  --chart-1: oklch(0.18 0 0);
  --chart-2: oklch(0.35 0 0);
  --chart-3: oklch(0.5 0 0);
  --chart-4: oklch(0.65 0 0);
  --chart-5: oklch(0.78 0 0);
}
```

Si la aplicación cambia de tema con una clase `.dark` en `<html>` (como hace `next-themes`), conserva los valores: pon el bloque claro en `:root`, el bloque oscuro bajo `.dark` y renderiza `<html class="dark">` por defecto.

Tres valores difieren de lo que usan hoy las aplicaciones de producto, los tres para cumplir WCAG AA, y las aplicaciones deberían adoptarlos:

- el `--muted-foreground` oscuro es `0.64` (`0.55` mide 4.2:1 sobre el fondo);
- el `--table-header-foreground` oscuro es `0.64`, por la misma razón (`0.55` mide 4.0:1 sobre el encabezado);
- el `--warn` de papel es `oklch(0.48 0.13 85)` (`oklch(0.55 0.15 85)` mide 4.2:1 sobre el fondo y 3.7:1 sobre su propio tinte).

## Color semántico

El color aparece solo con significado, nunca como decoración, y se mantiene muy por debajo del 10% de cualquier pantalla.

| Token         | Significado                                                    |
| ------------- | -------------------------------------------------------------- |
| `gain`        | Rendimientos positivos, depósitos, un estado activo o completo |
| `loss`        | Rendimientos negativos, ventas, un estado vencido              |
| `warn`        | Retiros, estados pendientes, advertencias                      |
| `destructive` | Acciones destructivas y mensajes de error                      |
| `*-muted`     | El tinte detrás de una insignia con ese significado            |

- Acompaña siempre un color semántico con un signo (`+4.20%`, `-1.35%`), una etiqueta ("Pendiente") o una posición, para que el significado sobreviva al daltonismo y a la escala de grises.
- El texto `destructive` va solo sobre `background` o `card` (4.6:1 sobre papel); nunca rellena un botón.

Contraste, calculado a partir de los valores de arriba y redondeado hacia abajo:

| Par                                        | Oscuro | Claro |
| ------------------------------------------ | ------ | ----- |
| gain sobre background                      | 9.7:1  | 5.6:1 |
| gain sobre gain-muted                      | 8.4:1  | 4.8:1 |
| loss sobre background                      | 7.1:1  | 5.6:1 |
| loss sobre loss-muted                      | 6.3:1  | 4.8:1 |
| warn sobre background                      | 10.8:1 | 5.6:1 |
| warn sobre warn-muted                      | 9.2:1  | 4.9:1 |
| destructive sobre background               | 5.7:1  | 4.6:1 |
| table-header-foreground sobre table-header | 5.8:1  | 5.1:1 |

## Tipografía

| Función                                                            | Familia         | Clase                    |
| ------------------------------------------------------------------ | --------------- | ------------------------ |
| Todo el texto de la interfaz: cuerpo, rótulos, botones, navegación | Geist           | `font-sans`              |
| Toda cantidad, porcentaje y fecha                                  | Geist Mono      | `font-mono tabular-nums` |
| Títulos de página y el nombre del producto                         | Aoboshi One 400 | `font-heading`           |

Jerarquía por contraste de escala y peso, no por decoración. El texto de interfaz es en su mayoría `text-sm`; las cifras de los resúmenes llegan hasta `text-lg`. Aoboshi One nunca va en negrita ni como texto corrido.

## Profundidad, radio, espaciado

- **Profundidad:** solo bordes, con la transparencia de `--border`. Sin sombras, sin tarjetas flotantes. Las tarjetas no son el contenedor por defecto, y nunca se anidan.
- **Radio:** `--radius: 0.375rem`. Precisión, no redondez amable.
- **Espaciado** (escala de Tailwind): `px-3 py-2.5` en celdas de tabla; `px-6 py-4` en el encabezado de página; `gap-1.5` entre insignias en línea; `gap-2` dentro de un campo de formulario y `gap-4` entre campos; `gap-8` entre cifras de resumen; `mb-3` del rótulo de una sección a su contenido; `mb-6` a `mb-8` entre secciones.

## Estructura de la aplicación

- `flex min-h-screen`: el riel de navegación y luego una columna de contenido con desplazamiento.
- Cada página abre con una barra de encabezado (`px-6 py-4 border-b`): el título de la página en Aoboshi One a la izquierda; las acciones, el selector de vista y el menú de usuario a la derecha.
- Luego las cifras de resumen, luego los datos.

## Riel de navegación

- Gobernado por estado, no por hover. Colapsado `w-14` (solo íconos; un clic en cualquier parte del riel lo expande); expandido `w-56` (etiquetas visibles, un botón para colapsar abajo con lucide `PanelLeftClose` / `PanelLeftOpen`). El estado persiste entre páginas.
- Transición de ancho de 200 ms, las etiquetas aparecen con un fundido de 200 ms, con salida suave.
- Superficie `bg-sidebar` con un filete a la derecha.
- Elemento activo `bg-secondary text-foreground`; los demás `text-muted-foreground hover:bg-secondary hover:text-foreground`.
- Arriba: el símbolo a 28 px y el nombre del producto en Aoboshi One, que aparece con un fundido al expandir.
- Un ícono lucide de 16 px por elemento, siempre con su etiqueta cuando el riel está expandido.

## Tablas

- La tabla va dentro de `overflow-hidden rounded-md border border-border`.
- Fila de encabezado `bg-table-header`, sin cambio en hover; celdas de encabezado `text-xs uppercase tracking-wider text-table-header-foreground`.
- Celdas `px-3 py-2.5`, texto alineado a la izquierda.
- Cantidades y porcentajes `text-right font-mono tabular-nums`.
- Fechas `font-mono text-xs tabular-nums text-muted-foreground`, en una columna de ancho fijo (`w-24`); columnas de insignias `w-20`.
- Totales en una fila de pie en `font-medium`, con el rótulo en `text-muted-foreground`.
- Filas con clic: `relative cursor-pointer` en la fila y un enlace `absolute inset-0` dentro de la primera celda. Nunca envuelvas una fila en un enlace.
- Las listas de primer nivel ofrecen una vista de tabla y una de tarjetas, que se alternan con un selector de vista (lucide `List` y `LayoutGrid` en un grupo de botones pequeño) en el encabezado de la página.

## Insignias

- Base: `inline-flex items-center rounded-sm px-1.5 py-0.5 text-xs font-medium`.
- Semánticas: `bg-gain-muted text-gain`, `bg-loss-muted text-loss`, `bg-warn-muted text-warn`. Las cifras dentro de una insignia conservan `font-mono tabular-nums` y un signo explícito.
- Neutras (completado, inactivo, una compra): `bg-secondary text-muted-foreground`.
- Estado: activo y completo en gain, pendiente en warn, vencido en loss.
- Un segundo eje que no es ni bueno ni malo (por ejemplo, cómo se firmó un documento): una insignia con borde, `border border-foreground/20 text-foreground` o `border border-muted-foreground/20 text-muted-foreground`.
- Etiquetas: `rounded-sm bg-secondary px-1.5 py-px text-xs text-secondary-foreground`, en una fila `flex gap-1.5`.

## Cifras de resumen

Una lista de descripción: el rótulo (`dt`) en `text-xs text-muted-foreground` sobre el valor (`dd`) en `font-mono tabular-nums`, con `gap-8` entre cifras. Nunca un mosaico con ícono, degradado o un minigráfico usado como decoración.

## Formularios y botones

- Etiqueta sobre el control; `gap-2` dentro de un campo, `gap-4` entre campos.
- Campos: `h-9 rounded-md border border-input bg-transparent px-3 text-sm`. Los campos de cantidad, porcentaje y fecha usan `font-mono tabular-nums`.
- Foco: `border-ring` con un halo de 3 px `ring-ring/50`. Es el único halo del sistema, y marca el foco, no la profundidad.
- Errores: `aria-invalid` en el control y el mensaje debajo en `text-destructive` con un ícono, diciendo qué hacer ("Ingresa una cantidad mayor que cero."). Nunca solo con color.
- Botones, `h-9 rounded-md px-4 text-sm font-medium`: principal `bg-primary text-primary-foreground`; con contorno `border border-border hover:bg-secondary`; discreto `hover:bg-secondary`; destructivo `border border-destructive/40 text-destructive`. Un solo botón principal por formulario. El botón de envío de un formulario puede ocupar todo el ancho (`w-full`).
- Los menús y diálogos usan `bg-popover` con un borde de filete.

## Cifras

- **Dinero:** el código de moneda, comas de miles y dos decimales: `COP 48,250,000.00`. Una sola función de formato para toda cantidad mostrada; la aritmética en una biblioteca decimal, nunca en punto flotante.
- **Porcentajes:** dos decimales, con signo explícito cuando el valor es una variación: `+4.20%`, `-1.35%`.
- **Fechas:** ISO en tablas (`2026-10-25`); una fecha escrita en el texto.

## Gráficos

- Las series se distinguen por luminosidad en la rampa acromática (`chart-1` a `chart-5`), nunca por tono.
- Colores semánticos solo para una serie que tiene signo (ganancias y pérdidas).
- Líneas delgadas, líneas de guía de filete en `--border`, rótulos de eje en monoespaciada tabular. Sin degradados, sin áreas rellenas decorativas, sin 3D.

## Movimiento

Discreto y funcional: el ancho del riel (200 ms), los fundidos de las etiquetas (200 ms), un fundido de color de 300 ms al cambiar de tema. Salida suave, nunca rebote. Nunca animes propiedades de maquetación. Respeta `prefers-reduced-motion`.

## Accesibilidad

- WCAG 2.2 AA en ambos temas (las relaciones de arriba).
- Navegación con teclado por cada control; foco siempre visible.
- El significado nunca depende solo del color.

## Textos

- Los textos de la interfaz dicen qué ocurre: "Guardar", "Registrar transacción", "Eliminar documento". Inglés sin contracciones, español con _tú_.
- Sin rayas (em dash), sin superlativos, sin emojis, sin cifras inventadas.

## Antes de terminar

1. Revisa cada pantalla en ambos temas; confirma que las cifras se alinean en sus columnas.
2. Confirma que cada color semántico tiene un signo, una etiqueta o una posición a su lado.
3. Confirma que no hay sombras, ni tarjetas anidadas, ni color fuera de los tokens semánticos.
4. Relee los textos en ambos idiomas buscando rayas, contracciones y _usted_.
