# Pulso · Manual de diseño y desarrollo

Versión 2.0.0 · 26 de septiembre de 2026 · Marca: Cuotario

## 1. Propósito y principios

Pulso da un lenguaje común al producto de estadísticas de fútbol Cuotario, dirigido a personas que comparan datos y cuotas con frecuencia. Se priorizan la lectura rápida, la trazabilidad y una identidad reconocible.

1. La señal primero: marcador, tiempo, mercado, dato y fuente tienen precedencia sobre decoración.
2. Confianza trazable: distinguir observación, estimación y precio; mostrar ausencia e incertidumbre.
3. Carácter consistente: acento intenso en acciones y comunicación; significado estable en estados.

## 2. Identidad

Cuotario es la marca del producto. Pulso es su sistema de diseño. El símbolo combina una C circular abierta y un punto independiente: una señal dentro del contexto. Se simplifica para lectura a 24 px.

- Símbolo mínimo: 24 px. Firma mínima: 144 px de ancho.
- Protección: ¼ del ancho del símbolo por cada lado.
- Versiones: firma oscura, clara y símbolo monocromo en `assets/brand/`.
- No deformar, rotar, añadir glow ni sustituir la marca por colores de resultados.
- Las firmas SVG 1.1 están trazadas, sin elementos de texto ni fuentes externas. La firma usa Plus Jakarta Sans Bold convertida a contornos. El símbolo y su punto conservan la misma silueta en monocromo.
- Pulso usa una señal de trazo como distintivo del manual, no como reemplazo de la firma Cuotario en el producto.

## 3. Fundaciones y tokens

Fuente: `pulso.tokens.json`, con `$type`, `$value` y aliases `{primitive.color.cobalt-600}`. Color usa sRGB. El compilador soporta color, dimension, duration, fontFamily, fontWeight, number y cubicBezier.

Tres niveles: primitivas → semánticos dark/light → componentes. Un componente usa roles semánticos, no hex duplicados. `common` contiene medidas compartidas entre temas. Los nombres CSS empiezan por `--p-`. Los aliases antiguos `--ob-*` y `--accent` permiten migración gradual.

| Rol | Oscuro | Claro | Uso |
| --- | --- | --- | --- |
| bg | #0C0E14 | #EEF0F3 | Fondo general |
| surface | #141722 | #FFFFFF | Panel |
| surface-raised | #1D2230 | #EBEEF5 | Interior/elevación |
| text | #F6F7FB | #0C0E14 | Texto principal |
| text-muted | #B5BDD0 | #48516B | Texto secundario |
| action | #4F5BFF | #141722 | Acción principal, tinta blanca |
| brand | #D8FF3E | #141722 | Enlace y texto de marca |
| highlight | #D8FF3E | #D8FF3E | Hoy, hover y selección; tinta #223000 |
| success | #65E0AC | #087344 | Estado positivo |
| warning | #FFD080 | #865400 | Advertencia |
| danger | #FF9BAB | #B42342 | Error o indicador de directo con etiqueta |
| info | #7BD7F5 | #006480 | Contexto informativo |

El lima no comunica rentabilidad ni seguridad. Un borde decorativo no cumple la función del borde de control. No mezclar tinta y fondo de temas diferentes. Objetivos de contraste: 4,5:1 para texto normal; 3:1 para texto grande, límites de controles y foco.

Plus Jakarta Sans: familia única para interfaz y marca. Respaldo system-ui y sans-serif. Escala tipográfica de producto: 12/16, 14/20, 16/24, 18/26, 20/28, 24/30, 28/36, 35/40, 60/60 (tamaño/interlínea px). Cada paso incluye tracking mediante --p-type-N-size, --p-type-N-line y --p-type-N-tracking. El paso 9 se reserva a marketing. Controles 600–700; títulos 700. Cifras comparables tabulares. Fuente variable local en `assets/fonts/`, cargada por `pulso-fonts.css`, con `font-display: swap`. Licencia SIL OFL 1.1 incluida; origen: https://github.com/tokotype/PlusJakartaSans.

Espacio 0/4/8/12/16/20/24/32/40/48/64/80/96 px. Radios: control 12 px, tarjeta 16–20 px, destacado 22 px, badge completo. Campos 48 px, botón 44 px, selección 36 px con ratón y 44 px táctil. Márgenes del dashboard 12 px en móvil y 20 px en escritorio. Mercados en dos columnas desde 1100 px; partidos en tres desde 1450 px. Sidebar 208 px. No hacer scroll horizontal en toda la página: solo tablas extensas dentro de su contenedor.

Movimiento: 120 ms para respuesta; 180–240 para transiciones; easing .2,0,0,1. Respetar `prefers-reduced-motion`. Sin carruseles automáticos ni parpadeo de marcadores.

Iconos: 24 × 24, trazo 1,75 px, extremos redondeados. En botones sin texto, nombre accesible. SVG decorativo con aria-hidden. Banderas y escudos con respaldo si el recurso no carga; texto de equipo siempre visible.

## 4. Contratos de componentes

La biblioteca base y controles se complementa con `pulso-data.css`. Badges, selección, mercados, destacados y recomendación se usan en el producto. `pulso-product.css` adapta las estructuras heredadas; no es la fuente de un componente nuevo. Las demos de datos usan `pulso-data-demo.js`, sin red ni almacenamiento. Otros componentes del catálogo continúan en piloto.

| Componente | Anatomía y variantes | Interacción / acceso |
| --- | --- | --- |
| Botón `.p-button` | Texto, icono opcional; primary, secondary, ghost, danger; default, compact, large | Button nativo; foco; loading con aria-busy y bloqueo de doble envío; disabled con causa próxima |
| Badge `.p-badge` | Etiqueta + icono/punto opcional; live, success, warning, error, info, editorial | No interactivo; texto define el significado |
| Input `.p-input` | Label, campo, ayuda, error | aria-describedby, aria-invalid, nombre persistente; foco al primer error |
| Select `.p-select` | Label, opción elegida y ayuda | Select nativo; teclado del sistema; mantener valor ante fallo |
| Checkbox `.p-check` | Input y label completo pulsable | Selección múltiple; checked/disabled; indeterminate solo para grupos |
| Radio `.p-check` | Fieldset, legend, opciones del mismo name | Selección única, flechas nativas |
| Switch `.p-switch` | Checkbox con role=switch y nombre estable | Efecto inmediato, Espacio; checked nativo |
| Tabs `.p-tabs` | Tablist, tab, tabpanel vinculados por ids | Un tabIndex 0, resto -1; flechas/Home/End, Tab al panel; selección automática solo si no hay latencia |
| Tabla `.p-table` | Caption, thead, tbody, th con scope | aria-sort en columna activa; botón de ordenación; mantener semántica en móvil |
| Aviso `.p-alert` | Título, explicación, recuperación | Info/warning/error; role=alert solo al aparecer error urgente |
| Vacío `.p-empty` | Motivo y siguiente paso | Diferenciar sin resultados, primera visita y error |
| Carga `.p-skeleton` | Bloques que conservan geometría | aria-hidden; aria-busy en región real; un anuncio cortés y fin de carga |
| Acordeón `.p-accordion` | Details, summary, contenido | Nativo; no esconder advertencias críticas |
| Diálogo `.p-dialog` | Título, descripción, cierre, acciones | showModal, foco seguro, Escape, foco devuelto; no anidar |
| Toast `.p-toast` | Mensaje, cierre | role=status, no roba foco ni desaparece automáticamente; error junto a su origen |
| Métrica `.p-metric` | Nombre, cifra, unidad, fuente/contexto | Cifras tabulares; — cuando falta; tendencia con base comparable |
| Partido `.p-match` | Competición, estado, equipos, marcador/hora, acción | Programado/live/descanso/final/aplazado/atrasado; sin controles anidados |
| Lectura `.p-pick` | Mercado/línea, estimación, cuota, cobertura, contexto | Sin precio no hay comparación; sin acción si precio/mercado no es operativo |

Estado obligatorio al entregar una pieza: reposo, hover cuando aplique, foco, presión/selección, deshabilitado, cargando, vacío, error y éxito cuando existan en el flujo. No fabricar variantes irrelevantes.

## 5. Patrones de datos deportivos

**Observado**: proviene de un feed y puede corregirse. Conservar proveedor, periodo/minuto, timestamp de recepción y estado del encuentro. La hora prevista por sí sola no prueba que el partido esté en vivo.

**Estimado**: salida del modelo, con mercado exacto, versión, cobertura y variables ausentes. Mostrar intervalos solo cuando exista un método que los produzca; describir qué significan. No tratar la probabilidad de la selección como porcentaje de aciertos validado del sistema.

**Precio**: cuota capturada con casa, mercado, línea y hora. Separarla de cuota mínima y de proyección. Si falta, mostrar — / Sin cuota; no derivar una ventaja económica sin precio vigente. Mercado suspendido o feed vencido retiran acciones operativas.

La vigencia debe configurarse por proveedor/mercado/frecuencia contratada y probarse con el motor. Diseño define cómo representarla, no inventa una política temporal universal.

No disponible ≠ 0. Error ≠ sin partidos. Sin muestra ≠ baja confianza numérica inventada. Ante fuentes en conflicto, mostrar pendiente de confirmar con origen, no un resultado definitivo.

Gráficos: barras desde cero, escalas comunes, labels/unidades, tabla o descripción equivalente. Diferenciar series por texto y patrón, no solo color. Tooltip accesible por teclado y opcional para entender el dato. Sin gráficos 3D ni cortes de escala que exageren diferencias.

## 6. Voz, números y comercial

Clara, útil y sobria. “Faltan alineaciones confirmadas; la estimación puede cambiar” es preferible a ocultar limitaciones. “Cuota registrada a las 15:42” debe acompañar al precio.

No usar garantías de ganancia, urgencia artificial ni “acierto verificado” sin evidencia. Formatear con Intl por idioma/moneda. Guardar UTC, mostrar zona local. Las tablas numéricas alinean decimales cuando el formato lo permita.

El plan actual se comunica como S/19 por 30 días, pago único. No presentarlo como renovación automática. Cualquier cambio de precio o condiciones requiere modificar fuente comercial y contenido de forma coordinada.

## 7. Accesibilidad y definición de terminado

Objetivo WCAG 2.2 AA. Verificar:

- Teclado completo, orden de foco, foco visible y no oculto por barras fijas.
- Dialog: título, contexto, foco inicial, Tab/Shift+Tab, Escape y restauración.
- Tabs: roles y vínculos, selección única, Home/End/flechas.
- Contraste de texto y controles en ambos temas; estado no dependiente de color.
- Zoom 200%; reflow a 320 CSS px; objetivo táctil 44 px por defecto.
- Label, ayuda y errores vinculados; conservar datos ante errores.
- Live regions moderadas: no anunciar reloj cada segundo ni mover foco al actualizar.
- Movimiento reducido y controles de pausa si en el futuro se incorpora contenido animado.
- Revisión de lector de pantalla antes de declarar la cobertura integral.

La comprobación de pares de tokens y del manual no certifica automáticamente el producto completo.

## 8. Gobernanza y colaboración

Responsabilidades por asignar nominalmente en el equipo: diseño mantiene anatomía/estados y ejemplos; desarrollo mantiene tokens/contratos y comportamiento; producto valida contenido, fuentes y alcance comercial. Una pieza requiere revisión de las tres perspectivas; no inventar aprobadores que aún no existen.

Flujo: proponer problema y pantallas → revisar reutilización → diseñar variantes/estados → implementar → validar accesibilidad/datos → publicar versión y migración. Componentes nuevos empiezan en piloto. Estable requiere uso real y documentación; obsoleto requiere alternativa y plazo de sustitución.

SemVer: patch compatible corrige; minor añade sin romper; major cambia nombres o contratos. Conservar aliases en una transición y publicar mapa antiguo → nuevo. Actualizar la versión del JSON, cache keys de recursos afectados y changelog.

Plantilla para una propuesta:

```
Nombre / responsable / fecha:
Problema del usuario y evidencia:
Pantallas afectadas y alternativa existente:
Anatomía, propiedades y variantes:
Estados y casos sin datos:
Tokens, temas y comportamiento responsive:
Teclado, foco, anuncios y texto alternativo:
Contrato de datos / fuente / vigencia:
Revisión de producto, diseño y desarrollo:
Verificación y limitaciones:
Versión y migración:
```

Figma futuro: páginas “Inicio”, “Fundamentos”, “Componentes”, “Patrones”, “Archivo”; colección Primitives y Semantic con modos Dark/Light; variables enlazadas y variantes Size/Intent/State; auto-layout y medidas por tokens. No duplicar la fuente manualmente sin registrar la versión. Esta entrega no contiene un archivo Figma sincronizado.

## 9. Implementación y migración

Editar JSON → `python scripts/build_pulso_tokens.py` → `--check`. Cargar tokens antes de componentes. No editar CSS generado. Pruebas Python de tokens y regresiones; pruebas `node tests/ui-navigation.cjs` de navegación existente; navegador para teclado/tema/responsive.

Rebrand aplicado a textos de interfaz, metadatos de nombre, símbolo, fondos, acciones principales, inicio y landing. Los estilos históricos siguen migrándose; no todos usan todavía `p-*`. Paquete Python, tablas, rutas, claves de almacenamiento y códigos OB se conservan por compatibilidad.

Los canónicos y enlaces operativos conservan optimalbet.app hasta adquirir/configurar dominio nuevo, DNS, OAuth y despliegue. Ninguna compra forma parte de esta entrega. Los descriptores visibles del producto no cambian la cuenta de comercio.

## 10. Benchmark y referencias

Revisión visual desde la [búsqueda compartida](https://dribbble.com/search/dashboard-design-ui-2026), 26/09/2026. Esta es la fecha de consulta; no se atribuye una fecha de publicación no verificada a los shots. No son pruebas de conversión.

- [Coinstax, Rizki Mulyawan](https://dribbble.com/shots/27352332-Coinstax-Crypto-Dashboard): tarjetas blancas, base neutra, selección lima, controles planos.
- [FIFA Live Dashboard, Farhan](https://dribbble.com/shots/27443080-FIFA-Live-Streaming-Dashboard-Sports-Analytics-Admin-Panel): densidad útil, agrupación deportiva y acento lima en oscuro.
- [FIFA Stats & Analytics Hub, Sogaso / Orizon](https://dribbble.com/shots/26877580-FIFA-World-Cup-2026-Stats-Analytics-Hub): jerarquía de marcadores y módulos de comparación.


## 14. Pulso 2: contratos de datos y migración

La app abre clara si no existe una preferencia guardada. Se respeta el tema elegido por el usuario. `.p-theme-dark` crea una isla oscura para directo y su detalle, independiente de la página. No escribir valores de un tema dentro de otro: volver a declarar los aliases heredados en el contenedor.

| Antes | Contrato 2.0 | Reglas |
| --- | --- | --- |
| `.dia-pill` aislada | `.p-badge` + `.today` / `.live` | 5×10 px de padding; no anidar badges; texto + punto en directo |
| `+` suelto | `.p-selection`, `aria-pressed` | 36/44 px; check además del color; nombre incluye selección y acción |
| Fila estadística a todo el ancho | `.p-market-card` / `.p-market-row` | Equipo, proyección, rango, línea, probabilidad estimada, añadir |
| Hero vacío | `.p-feature` | Banderas en blur decorativas, marcador legible, paginación manual, no autoplay |
| Cupón oculto en escritorio | Header Ticket + FAB con contador | Revisar borrador local, editar cuota, quitar, guardar según plan |

Acceso y dato son estados distintos: `pro_requerido` muestra “Disponible con Pro”, no “Sin señal”. Sin proyección muestra —, nunca 0. Sin recomendación no se inventa una línea. Una cuota de modelo siempre conserva su origen; no presentarla como una oferta de una casa.

Ticket: las instancias duplicadas de una selección se sincronizan al añadir, quitar, editar, vaciar o guardar. Escape cierra y devuelve foco al activador; Tab permanece en el panel. Revisar un borrador es accesible sin Pro; guardado e historial conservan el control Pro. La app no ejecuta apuestas.

QA: `node tests/ui-ticket.cjs`, `node tests/ui-markets.cjs`, `node tests/ui-navigation.cjs`, `node tests/ui-controls.cjs`, `node tests/ui-dashboard.cjs`; tokens y backend con pytest. Completar con navegador a 1440/390/320 px y ambos temas. Los casos de guardado se prueban en memoria, sin alterar apuestas del usuario.


## Pulso 2.1 · Interacción por tema

Todo cambio de lineamiento nace en Pulso. `pulso.tokens.json` define colores, `pulso-data.css` define componentes, `pulso-product.css` solo adapta los selectores heredados de la app.

- `live-fill` / `live-ink`: señal suave del directo, con punto y texto en ambos temas.
- `surface-hover`: tarjetas neutras, sin invertir sus colores de texto.
- `emphasis`: cifras y sugerencias en cobalto claro / lima oscuro. Las sugerencias usan 16 px, 14 px en móvil estrecho.
- `emphasis-fill`, `emphasis-ink`, `emphasis-hover`: botón Pro con un hover distinto del reposo.
- Carrusel: hover interior blanco al 30%, 1 px.
- Editor de ticket: vive dentro de la selección; 200 ms entrada, 180 ms salida, sin animación con movimiento reducido.
- Directo: overlay al 35%, paneles de lectura y estadísticas comparativas. Ausente se representa con —; nunca se fabrican barras para un dato ausente.
- Grillas: tres encuentros por fila desde 1500 px; tres mercados desde 1720 px. Tarjetas plegadas alineadas al inicio, sin estirarse al vecino.

Ejemplos compartidos y contrato: `/design-system#estados-21`.

## Corrección de controles y acceso a picks · 26/09/2026

- `.p-button.icon`: flex centrado en ambos ejes, padding 0, SVG sin línea base. La variante `.compact` usa icono de 18 px y caja de 36 px (44 px con entrada táctil). No sustituir flechas por caracteres de texto ni ajustar con desplazamientos ópticos locales.
- `.p-button.emphasis.block`: acción principal de sección, 48 px de alto mínimo, ancho completo. Colores y hover por los roles `emphasis` del tema.
- Picks del día mantiene «Ver los mejores picks» debajo del resumen; la misma acción carga o reabre todos los picks. No reducirlo a un enlace secundario ni reemplazarlo por «Comparar picks».
- Ejemplos en ambos temas: `/design-system#estados-21`. Estilos compartidos en `pulso-data.css`; la app consume las mismas clases.

- Cerrar ticket y diálogo: usar `.p-button.icon` con SVG de cruz de 18 px, viewBox 24 y trazo 1.8. Comparte caja de 44 px con vaciar; no usar el carácter ×, cuyo centro depende de la tipografía.

## Lienzo y separación de detalle · 26/09/2026

- `.p-canvas` usa `--p-bg`: gris azulado #EEF0F3 en claro y grafito #0C0E14 en oscuro. Sin halos ni degradados globales heredados. Los fondos decorativos del carrusel permanecen contenidos en su componente.
- `.p-match-header` separa navegación, banner y análisis: 12 px arriba y 16 px debajo, con los tokens `--p-space-12` y `--p-space-16`. El margen del primer hijo no se acumula y el contenedor vacío no ocupa espacio. Igual en móvil y escritorio; el espacio se mantiene con carga, datos o error.
- Contrato y ejemplos claro/oscuro: `/design-system#estructura`.

## Pulso 2.2 · Jerarquía del detalle

- `icon-accent`: lima en oscuro y cobalto en claro para iconos de contenido. Iconos dentro de botones con relleno heredan la tinta del botón para conservar contraste.
- Proyección: 16/24 px, peso 600, `text-muted`; 14/20 px bajo 400 px. Sugerencia: acento de tema, peso 750, 16/22 px.
- `.p-standings`: padding 16 px, filas interactivas de 44 px, escudos de 22 px, título y nota de temporada. Sin márgenes internos heredados; alineada con la recomendación vecina.
- `.p-notice`: `notice-bg / notice-text`, icono de tema y énfasis textual neutro. Se conserva el mensaje de cobertura/riesgo. Reservar warning/danger para estados que requieren atención específica, no para colorear párrafos informativos enteros.
- `.p-app-header`: sombra por `header-edge / header-shadow`, solo en el header global.
- `.p-button.tonal` en `.p-detail-nav`: «Ver partidos de [liga]» sobre el banner. Móvil: fila completa. Próximos partidos de la competición, estado expandido y foco de regreso; no prometer partidos fuera de la cobertura de la API.
- Banner separado del análisis por `space-16`, tanto para Favorito de victoria como para Cara a cara. Lienzo neutro sin el antiguo brillo verde.
- Ejemplos: `/design-system#detalle-22`. Tokens → componentes compartidos → adaptadores del producto.


## Pulso 2.3 · Header unificado y elevación

- El header global abarca todo el ancho y contiene un único logo, buscador y acciones. Altura de producto `app-header-height`: 64 px. El sidebar (`app-sidebar-width`: 208 px) y el contenido empiezan debajo. El logo no vive en la navegación lateral.
- `.p-app-header` consume `elevation-header`: línea de contacto y dos sombras visibles, con `header-shadow / header-edge` por tema. La sombra pasa también bajo el logo. Header en capa dropdown; sidebar en sticky; diálogos por encima de ambos.
- `elevation-card` usa dos sombras (0 2px 4px y 0 8px 20px) desde `card-shadow`: grafito al 8% en claro y negro al 24% en oscuro. Aplicable también a opciones 1X2 y doble oportunidad.
- Ejemplos de ambos temas: `/design-system#encabezado-23`. Tokens → componentes Pulso → adaptación de Cuotario.

### Cara a cara · fila completa

`.p-match-history` ocupa todas las columnas del contexto del partido, debajo de posiciones y recomendación. Mantiene el ancho completo abierto, cerrado o sin historial; no rellena un hueco junto a otra tarjeta cuando no hay recomendación. El chevrón se alinea a la derecha y «últimos 5» usa texto secundario. En móvil conserva una sola columna. El encabezado comunica `aria-expanded` y controla un panel inerte al cerrarse. Ejemplo: `/design-system#detalle-22`.


### Hover del botón de selección

El hover de `.p-selection` usa `selection-hover-fill` (negro de Pulso) y `selection-hover-ink` (lima), en ambos temas. En opciones 1X2 y doble oportunidad también se activa al pasar sobre la tarjeta, para distinguir el + sobre su superficie lima. Al salir conserva su estado normal o seleccionado. Controles deshabilitados no reaccionan. Los ejemplos de selección en `/design-system#estados-21` consumen el mismo componente.


### Acordeones consecutivos

Agrupar los acordeones verticales con `.p-accordion-stack`. El contenedor define una columna y `gap: var(--p-space-16)`; los hijos no agregan márgenes. Así mantiene 16 px entre tarjetas abiertas o cerradas, sin acumular márgenes ni dejar espacio vacío al plegar. La verificación de resultados históricos consume este patrón para Favorito de victoria y todos sus mercados. El ejemplo de Acordeón en `/design-system` muestra tres estados consecutivos con el mismo componente.


### Alineaciones y cancha compacta

`pulso-lineups.js` y `pulso-lineups.css` son la fuente compartida de la vista de alineaciones; Cuotario consume `PulsoLineups.render(alineaciones, eventos, {language})`. El ejemplo en `/design-system#alineaciones` usa ese mismo generador con datos ilustrativos.

- La cancha no crece con todo el viewport: 400 px de alto en horizontal, máximo 760 px de ancho. Desde 1100 px del contenedor, ocupa una columna junto a las dos listas de titulares.
- Bajo 600 px del contenedor gira a vertical, con 460 px de alto para conservar los nombres. No hay scroll interno ni recortes de jugadores. Bajo 440 px las listas se apilan.
- Equipos, condición local/visitante y formación preceden a la cancha y a cada lista. No inferir una formación si la fuente no la publica.
- El local usa énfasis cobalt en claro y lime en oscuro; el visitante usa un marcador neutral delineado. La superficie de la cancha y sus líneas derivan de los tokens existentes.
- Suplentes y cambios se despliegan bajo sus encabezados; los titulares permanecen a la vista. Details/summary aporta teclado y estado accesible.
- Conservar todos los jugadores aunque no tengan posición, dorsal o equipo rival disponible; nombres completos en las listas y etiquetas escapadas. La distribución sin grid se identifica como orientativa.


### Cuenta en el header

`.p-user-control` comparte 44 px de altura con `.p-header-icon`. Usa padding horizontal simétrico de 12 px, 7 px verticales, borde de 1 px, avatar de 28 px y gap de 8 px. El texto usa interlínea de 20 px y el nombre largo se trunca. Bajo 640 px se oculta el nombre y el control queda en 44 × 44 px, con el avatar centrado y una etiqueta accesible completa. El ejemplo en `/design-system#perfil-header` cubre ambos temas.


### Apertura inicial de mercados

`PulsoMarketGrid.initialize(grid)` abre únicamente la primera fila renderizada de `.p-markets-grid`: 3 tarjetas en ancho amplio, 2 en mediano y 1 en móvil, según la retícula CSS existente. Se inicializa una sola vez por partido; no restablece las decisiones de la persona al redimensionar o volver a llamar al inicializador. Los encabezados del resto permanecen visibles, con `aria-expanded=false` y paneles `inert`. Las secciones complementarias empiezan plegadas, incluidas las cuotas por casa, que se consultan cuando se abren. Ejemplo interactivo: `/design-system#mercados-inicial`.


## Pulso 3.0 · Biblioteca funcional

La documentación ocupa todo el ancho disponible y se organiza por ficha. 42 componentes con ejemplo, estados, anatomía, teclado y código. Explorar `/design-system#componentes`, `#color`, `#motion`, `#interacciones` y `#loaders`.

Las seis escalas propias de 12 pasos y ambos temas están en los tokens. Consumir roles semánticos antes que tonos aislados. Cobalt en claro, lima en oscuro; avisos sobre superficies neutras. Alpha se calcula sobre el lienzo y no garantiza contraste en otros fondos.

Motion: respuesta 120–180 ms; entrada 240 ms; salida 160 ms; panel lateral 320 ms. Sin rebotes ni animación de datos. Respetar `prefers-reduced-motion` sin perder información.

Contratos nuevos: `pulso-library.css`, `pulso-library.js`, `pulso-motion.css`. Tras insertar contenido dinámico llamar `PulsoUI.init(contenedor)`. Los atributos `data-studio-*` son exclusivos de demos. Ver investigación y decisiones en `docs/pulso-3.md`; la integración actual de Cuotario se documenta en `/design-system#integracion`.


### Legibilidad de avisos y navegación de detalle

`notice-bg` usa blanco en claro y superficie elevada en oscuro. `notice-text` usa tinta principal; `notice-border` delimita el aviso con un borde neutro de 1 px. `.p-notice` comparte 14 px / 22 px y un icono de 18 px en documentación y producto. Objetivos de contraste: texto ≥ 7:1; icono y borde ≥ 3:1 sobre el aviso; borde ≥ 3:1 sobre el lienzo. Los botones tonales conservan borde de énfasis visible en reposo y hover y foco de teclado separado. Mantener la paleta: cobalt claro, lima oscuro; no sustituir estos roles por colores locales.

## Pulso 3.1 · Contrato de producto

Cuotario carga `pulso-runtime.js` antes de `pulso-library.js` y utiliza `PulsoUI.observe(document.body)` para vistas dinámicas. Botones, campos, selectores, búsqueda, acordeones, capas, avisos y carga usan la biblioteca. No duplicar en una pantalla el comportamiento de foco, Escape, estados o errores.

Las capas usan `openLayer/closeLayer`; los campos `fieldError/setBusy`; búsquedas `combobox`; confirmaciones `prompt/confirm`. La app conserva la petición, el resultado, permisos y persistencia. Los ejemplos simulados requieren `data-p-demo` y nunca se activan en Cuotario.

Antes de publicar: probar teclado, ambos temas y móvil; verificar respuesta obsoleta de búsqueda, validación y cancelación, foco al cerrar y paneles cerrados inertes. Cambiar el contrato compartido primero y documentar su consumo real.

### Header compacto

Ticket y cuenta usan controles de 44 px. `.p-header-ticket` superpone el contador en móvil; `.p-user-guest` comparte la anatomía del perfil. Bajo 360 px `.p-header-brand-name` se oculta conservando el nombre accesible del enlace. El catálogo incluye `/design-system#header-compacto`.

### Tabs del detalle de partido

Estadísticas, Línea de tiempo y Alineaciones consumen `.p-tabs` y `.p-tab`, igual que `/design-system#c-tabs`. El indicador y texto activos usan `emphasis`: cobalto en claro, lima en oscuro. Los tabs conservan su ancho de contenido, sin el contenedor redondeado, relleno seleccionado ni columnas iguales de la antigua variante `.subtab`. El producto aporta solo el margen exterior y el contenido del panel.

`data-p-tablist` mantiene flechas, Home/End y estado seleccionado; `data-p-panel` asocia el panel dinámico con el tab activo. El panel acepta foco para continuar con Tab.

## Resultados y estados

Pulso distingue `success` (verde Mint) de `emphasis` / `highlight` (cobalto / lima de marca).
`p-result[data-result=win|draw|loss]` presenta la forma V/E/D en 24 px, con `role=img`, `aria-label` y `title`. Un dato desconocido se muestra como raya neutra; nunca se infiere victoria. En inglés usa W/D/L.

`p-badge.success|error|warning|info|neutral|live` comparte los fondos semánticos y sus textos accesibles en ambos temas. Cada etiqueta nombra el estado: acertó, falló, pendiente o va ganando. Cash out y empate son neutros. Una cifra de beneficio cero o sin datos también es neutra. Pronósticos, cuotas y sugerencias conservan énfasis de marca; no usan el verde de una victoria consumada.

Las gráficas local/visitante usan `chart-home` / `chart-away` y etiquetas; el color no implica ganador/perdedor. La leyenda debe seguir el mismo orden que las series. Las variantes se revisan en `/design-system#resultados`.

### Editar una selección del ticket

Usar `.p-button.p-ticket-edit` solo con SVG de 18 px centrado, sin texto visible.
La caja mide 44 × 44 px y no tiene padding. Conservar `aria-label` y `title`
para «Editar» y «Listo», que mantienen la misma caja; el estado
`aria-expanded` comparte los colores de énfasis. `.p-ticket-actions` separa
este botón de Quitar. El editor se identifica mediante `aria-controls`.
Ejemplo interactivo: `/design-system#datos`; misma pieza en el ticket de Cuotario.


### Espaciado del listado de picks

`.p-picks-list` apila las tarjetas con `space-12`. Cada `.p-pick-item` usa
`space-16` de padding y separación entre contenido y acciones. `.p-pick-copy`
separa sus bloques con `space-8`. Las alternativas usan flex-wrap y gaps de
4 × 8 px; no se separan mediante caracteres. El filtro queda a 16 px del listado.
En móvil, probabilidad y botón se apilan para conservar espacio para el texto.
Componente compartido en `/design-system#picks-espaciado` y la lista de mejores
picks de Cuotario, con los mismos tokens en ambos temas.


## Evolución del modelo · administración

Fuente: `pulso-monitor.css` y `pulso-monitor.js`; ejemplo `#evolucion-modelo`.
Usar `PulsoModelMonitor.mount(host, {request, headers})` dentro de `data-pulso`.
El producto entrega las peticiones autenticadas; el patrón no contiene credenciales.
`demo:true` deshabilita exportación y publicación, con datos ficticios explícitos.
Separar origen histórico/prospectivo; nunca mezclar errores de unidades distintas.
Contar partidos además de observaciones. Mostrar muestra, variante y fecha.
La tabla conserva encabezados y región desplazable con teclado en móvil.
Color semántico acompañado por signo; carga anunciada, errores recuperables,
respuestas obsoletas descartadas y controles de publicación reversibles.

## Picks destacados y home comercial · 27 septiembre 2026

- El carrusel de picks usa `pulso-picks.css` y `PulsoPicks.render` en la app y en `#picks-carrusel`. No hace peticiones ni avanza solo. Admite carga, vacío, error y reintento; acciones separadas para detalle, selección y listado completo. Datos ya filtrados por vigencia y plan.
- El tamaño visible es tres tarjetas en escritorio, dos en tablet y una con avance en móvil. Las flechas del teclado, Inicio/Fin y botones desplazan la lista. Reduce el movimiento según preferencia del sistema.
- La home usa `pulso-marketing.css`, tokens, tipografía y botones compartidos. `/landing` y `/landing?lang=en` sirven HTML completo, con FAQ nativa y metadatos consistentes. La muestra visual es ilustrativa y los planes usan la configuración real.
- Los cambios de composición empiezan en estos patrones de Pulso. El visor `/assets/pulso-responsive-preview.html` comprueba la distribución a 390 px; no emula hardware móvil.

## Consola de administración · 1.0

El patrón `pulso-admin.css/js` se usa en `/admin`: lienzo completo, navegación lateral por áreas, métricas, gráficos SVG accesibles y tablas de exploración. Mantiene los roles semánticos de Pulso en ambos temas. Las cabeceras de tabla usan el estilo tipográfico original y dos triángulos, con `aria-sort` para el estado; no se convierten visualmente en botones. Búsqueda/filtros preceden a la paginación. Exportar modelo incluye los resultados filtrados; exportar listas incluye solo la página indicada. Detalle de benchmark, contratos y límites: `docs/ADMIN_CONSOLE.md`.
