Accesibilidad
WCAG 2.1 AA · fase 4 · diseño
01

Estándares

Atlas apunta a cumplir WCAG 2.1 nivel AA. Este es el estándar que la mayoría de jurisdicciones (EU, US, MX) exigen para servicios digitales. Documento qué criterios cubren los wireframes actuales, dónde hay gaps y cómo verificarlos.

Criterios de éxito en uso

  • 1.4.3 Contraste mínimo · 4.5:1 texto normal, 3:1 texto grande (≥18pt o ≥14pt bold).
  • 1.4.11 Contraste de no-texto · 3:1 para componentes UI y gráficos esenciales (border-color, focus rings, icons).
  • 2.1.1 Teclado · toda funcionalidad accesible vía teclado.
  • 2.4.7 Focus visible · indicador de foco visible para cualquier elemento focusable.
  • 2.5.5 Tamaño objetivo (AAA opcional) · áreas táctiles ≥44×44 px.
  • 4.1.2 Nombre, rol, valor · controles personalizados con ARIA correcta.
  • 2.3.3 Animación por interacción · respetar prefers-reduced-motion.
02

Tabla de contrastes · en vivo

Ratios computados en tiempo real desde los tokens activos. Alterna el tema con el toggle del header — la tabla recalcula. Fórmula WCAG: (L1 + 0.05) / (L2 + 0.05) con luminancia relativa sRGB.

Foreground Background Uso Ratio AA texto AA grande
✓ AA ≥ 4.5:1 · pasa texto normal ~ Solo grande 3:1 - 4.5:1 · solo texto grande/bold ✗ Falla < 3:1 · no cumple AA
03

Focus visible

Todo elemento focusable muestra un indicador claro de foco. Implementamos con :focus-visible + --shadow-focus (4px ring brand al 15% alpha). Esto solo se muestra en navegación por teclado — clicks con mouse no disparan el ring, evitando ruido visual.

Demo · estados forzados

Tabula con Tab sobre estos elementos para ver el focus real. Los de la columna derecha tienen el estado aplicado a la fuerza para visualizarlo siempre.

Botón primario
Botón ghost
Input
Checkbox
04

Patrones ARIA

Catálogo de atributos ARIA usados en los wireframes y dónde se aplican. ARIA = Accessible Rich Internet Applications, atributos HTML que comunican rol y estado a tecnologías asistivas.

aria-label="…"
Botones icon-only · en todos los wireframes
Da nombre accesible a botones sin texto visible. Ejemplo: campana de notificaciones, botón de cerrar, theme toggle, día siguiente/anterior.
aria-hidden="true"
SVGs decorativos · transversal
Aplicado a iconos que acompañan texto descriptivo (no aportan información adicional). Los lectores de pantalla los omiten.
aria-current="page"
.nav__item--active · sidebars de app
Indica el ítem de navegación correspondiente a la página actual. Implementado pero solo aplicado en aria-current cuando es relevante; el estilo visual se da con la clase.
aria-selected="true"
Día seleccionado · routine-editor.html
En el calendario semanal, indica qué día está expandido en el detail panel.
aria-current="date"
Día = hoy · routine-editor.html
Indica el día actual dentro de un calendario, distinto de "seleccionado".
role="group" + aria-label
Filtros, disciplinas, OTP, mood selector
Agrupa controles relacionados con un nombre accesible (ej. "Disciplinas", "Código de 6 dígitos", "Mood").
role="radiogroup"
Mood selector · diario.html
Indica que solo una opción puede estar seleccionada a la vez. Las opciones llevan aria-checked.
aria-pressed="true|false"
Toggle buttons · diario toolbar
Para botones de formato (B, I, U) que se activan/desactivan. El lector lee "Negrita, presionado".
aria-labelledby
<section> con título interno
La sección referencia el id del heading interno como su etiqueta. Da estructura semántica a regiones de la página.
autocomplete
Inputs de login/registro
email, current-password, new-password, one-time-code, name. Ayuda a managers de contraseñas y a autofill nativo del navegador.
inputmode="numeric"
OTP cells · 2fa.html
En móvil, abre el teclado numérico directamente para los dígitos del código TOTP.
role="status"
Verify-note · registro.html
Indica que el bloque comunica info de estado (verificación de correo). Lectores de pantalla lo anuncian.
05

Navegación por teclado

Toda interacción debe ser posible sin mouse. Estándar de teclas mantenido a lo largo del sistema.

Tecla Acción
Tab Avanza al siguiente elemento focusable. Orden visual = orden DOM.
Shift + Tab Retrocede al elemento anterior.
Enter Activa botones, envía formularios, sigue links.
Space Activa botones y toggleas checkboxes / chips.
Esc Cierra modales / drawers (pendiente · sin modales en wireframes aún).
Navega entre items en radiogroup (mood selector), week-pills, OTP cells.
⌘ K / Ctrl K Abre búsqueda global (atajo visible en biblioteca y diario).
06

Reducción de movimiento

Usuarios con vestibular disorders (trastornos vestibulares — sensibilidad al movimiento que produce mareo) configuran su sistema con prefers-reduced-motion: reduce. Debemos respetar esa preferencia desactivando animaciones no esenciales.

Propuesta · agregar a tokens.css

Una regla global que neutraliza transiciones y animaciones cuando el usuario lo pide. Se agrega al final de tokens.css para que actúe sobre cualquier componente.

@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } }

Excepciones permitidas

Algunas animaciones comunican información (indicadores en vivo): el pulse del eyebrow en active-protocol, el blink del timer OTP, el dot pulsante del recovery status. Estas podrían bajar a una versión fade en lugar de eliminarse completamente — preservan el mensaje sin causar mareo.

07

Lectores de pantalla

Convenciones para que el contenido sea legible por NVDA, JAWS, VoiceOver, TalkBack.

  • HTML semántico · usar <header>, <nav>, <main>, <section>, <article> en vez de <div> cuando aplique. Implementado a lo largo de todos los wireframes.
  • Jerarquía de headings · un solo <h1> por página, anidamiento lógico hacia abajo.
  • .sr-only · clase utilitaria para texto visible solo a lectores (cuando el contexto visual ya es claro pero la semántica necesita una etiqueta). Definida en components.css.
  • Etiquetas vinculadas a inputs · usar <label for="…"> + id matching, no solo placeholders.
  • Idioma · <html lang="es-MX"> activa pronunciación correcta en lectores.
  • Tabla de contenidos · en design-system y accessibility, el sidebar TOC permite saltar a secciones sin tabular por todo.
08

Gaps conocidos · TODOs para implementación

Cosas detectadas durante el diseño que NO están cubiertas en los wireframes pero deben atenderse al implementar. Lista honesta — el design system no es perfecto, es un punto de partida sólido.

Skip-to-content link
Falta un link "Saltar al contenido principal" como primer elemento focusable. Usuarios de teclado deben poder evitar tabular toda la sidebar para llegar al contenido.
Live regions para feedback dinámico
"Guardado automáticamente hace 12s" en el diario, "Código válido por 18s" en 2FA, conteo de palabras — deberían ser aria-live="polite" para anunciarse al lector sin interrumpir.
Focus trap en modales
Los wireframes aún no incluyen modales. Al implementarlos, el foco debe quedar atrapado dentro del modal mientras está abierto, y volver al elemento que abrió el modal al cerrar. Esc debe cerrar.
aria-describedby para errores de formulario
Los errores visualmente acompañan al input pero el lector no sabe que están vinculados. Cada .field__error necesita un id y el input correspondiente debe llevarlo en aria-describedby.
Información codificada solo por color
Severity dots (verde/ámbar/rojo) y status badges comunican estado solo con color. Para usuarios con daltonismo, agregar texto o ícono complementario. Mitigado parcialmente porque el texto adyacente ("Leve", "Moderada", "Grave") está presente, pero hay que garantizar que SIEMPRE acompaña.
prefers-reduced-motion no implementado
Las animaciones (pulse, blink, ring, hover transforms) no respetan la preferencia del sistema. Pendiente agregar la regla CSS propuesta en §06 a tokens.css.
Tamaño objetivo en móvil
Algunos íconos en topbar (back, theme toggle) son 36×36px. WCAG 2.5.5 (AAA) recomienda ≥44×44px. AA actual no lo exige pero conviene cumplirlo en touch para usuarios con motricidad reducida.