FORMA Design System / Technical Audit

AUDIT
REPORT

Actualizado: 05 Jun 2026 (original: 03 Jun 2026) Archivos analizados: 10 HTML · 6 CSS · 3 JS Scope: Accessibility · Performance · Responsive · Theming · Anti-Patterns

Audit Health Score

# Dimensión Score Hallazgo principal
1 Accessibility 4 ✓ Skip-link funcional en todas las páginas; burger con ARIA completo + focus trap; hero SVG con role="img"; touch targets 44px
2 Performance 4 ✓ rAF del cubo pausado con IntersectionObserver; Bebas Neue cargada en <head>; tokens de animación corregidos
3 Responsive Design 4 ✓ Sidebar mobile → barra horizontal scrollable. ✓ Banda de nav ahora scrollable horizontal en mobile. Cosmético: font-size-body-sm 12px fijo · inline colors en swatches
4 Theming 4 ✓ Tokens de animación unificados; neutral-600 oscurecido a #4d555c (≥5:1); @supports para text-box-trim
5 Anti-Patterns 4 Diseño genuinamente intencional. Sin glassmorphism, sin gradient text, sin border-left decorativo. Tipografía distintiva.
Total 20/20 Excellent — 2 issues P2 cosméticos pendientes
Health score 20 / 20

Anti-Patterns Verdict

✓ PASA — No parece AI-generated

FORMA tiene un punto de vista de diseño claro y ejecutado con coherencia. Bebas Neue + Barlow + JetBrains Mono es una triada deliberada, no un default de entrenamiento. El grid de celdas hairline-border con 1px gaps es estructural, no decorativo. El cubo 3D en el hero es memorable por razones correctas: muestra el sistema en sí mismo.

Sin gradient text. Sin glassmorphism. Sin border-left decorativo en alertas. Sin generic drop shadows redondeadas. El único riesgo borderline es el .stat-row en hero.css (big number + label grid = "hero metrics" template), pero en contexto de design system documentation es semánticamente válido, no decorativo.

Executive Summary

Conteo por Severidad

0
P0 Blocking
0
P1 Major
2
P2 Minor
0
P3 Polish

Issues Abiertos (2)

  • [P2] --font-size-body-xs: 12px fijo — muy pequeño en mobile; considerar clamp(11px, 1.4vw, 12px)
  • [P2] Inline colors en swatches de color system (#090d10, #127ae6, etc.) — defensible como demo pero mejor con var(--color-neutral-900)

Accessibility

Score: 4/4 — Excelente. Todos los gaps estructurales resueltos: skip-link funcional, ARIA completo en burger + overlay, hero SVG etiquetado, touch targets 44px.

✓ RESUELTO
Skip link ausente en HTML
Ubicación: shared.css:8 / todas las páginas HTML
Categoría: Accessibility
WCAG: 2.4.1 Bypass Blocks (A)

.skip-to-main está perfectamente definido en shared.css con el comportamiento correcto (top: -100% → top: 8px en focus). Sin embargo, ningún archivo HTML contiene el elemento <a class="skip-to-main" href="#main-content">. El CSS existe en vacío.

Fix: Agregar <a class="skip-to-main" href="#main-content">Skip to main content</a> como primer hijo de <body> en todas las páginas.

/adapt

✓ RESUELTO 04 Jun 2026 — Skip-link inyectado por header.js. Todas las páginas con <main> actualizadas a id="main".

✓ RESUELTO
Burger button sin ARIA completo
Ubicación: header.js (injected) / shared.css:157
Categoría: Accessibility
WCAG: 4.1.2 Name, Role, Value (A)

El .forma-header__burger es un <button> sin aria-expanded, aria-controls, ni aria-label. Screen readers no pueden comunicar el estado del menú ni su propósito.

Fix: aria-label="Open navigation menu" + aria-expanded="false" (toggle a true al abrir) + aria-controls="nav-overlay". El overlay necesita id="nav-overlay" y aria-modal="true" cuando está abierto.

/adapt

✓ RESUELTO 04 Jun 2026 — aria-label, aria-expanded, aria-controls="navOverlay" en burger. aria-modal="true" + focus trap (Tab/Shift+Tab) en el overlay.

✓ RESUELTO
Hero SVG principal sin nombre accesible
Ubicación: index.html:1111
Categoría: Accessibility
WCAG: 1.1.1 Non-text Content (A)

El SVG #hero-mark (el logo animado principal) no tiene aria-label ni aria-hidden="true". Si es decorativo, debería ocultarse; si es informativo (muestra el logo FORMA), necesita un label.

Fix: <svg id="hero-mark" aria-label="FORMA logo mark" role="img" ...> o aria-hidden="true" si el wordmark adyacente ya comunica la marca.

/adapt

✓ RESUELTO 04 Jun 2026 — Añadido role="img" aria-label="FORMA logo mark" al SVG #hero-mark en index.html.

✓ RESUELTO
Enlace roto en banda de navegación
Ubicación: index.html:1329
Categoría: Accessibility / UX

<a href="audit.html#architecture">Tokens</a> apunta a audit.html pero el archivo en el repo se llama audits.html (o no existe). El link retorna 404.

/polish

✓ RESUELTO — Los archivos de auditoría están correctamente en auditoria/audit.html y auditoria/index.html. No hay 404.

✓ RESUELTO
Contraste de texto secundario borderline
Ubicación: tokens.css — color-neutral-600 sobre color-neutral-50
Categoría: Accessibility
WCAG: 1.4.3 Contrast (AA)

--color-neutral-600 (#575f66) sobre --color-neutral-50 (#f5f8fc) = ratio ~4.7:1. Pasa AA (4.5:1) con un margen muy escaso. Cualquier variación de pantalla puede hacerlo fallar. Se usa como --text-secondary y --text-ghost extensamente.

Fix: Oscurecer neutral-600 a ~#4d555c (≥4.9:1) para margen de seguridad.

/colorize

✓ RESUELTO 04 Jun 2026 — --color-neutral-600 cambiado a #4d555c en tokens.css.

Performance

Score: 4/4 — Excelente. rAF del cubo pausado con IntersectionObserver; Bebas Neue cargada en <head> de todas las páginas; tokens de animación corregidos.

✓ RESUELTO
Tokens CSS undefined rompen todas las transiciones
Ubicación: components.css:490–492 · index.html:188,230,633
Categoría: Theming / Performance

Los siguientes tokens son referenciados pero no están definidos en tokens.css:

--duration-fast, --duration-base, --easing-standard

Los tokens definidos son: --dur-fast: 240ms, --dur-base: 500ms, --ease-expo, --ease-quart.

Esto significa que las transiciones de .input, .band__item, .hero__cta, e .input-demo se reducen a transition: prop 0s — sin animación. El bug es silencioso: no hay error en consola.

Fix: En tokens.css agregar aliases: --duration-fast: var(--dur-fast); --duration-base: var(--dur-base); --easing-standard: var(--ease-quart); — o reemplazar todas las referencias con los nombres correctos.

/polish

✓ RESUELTO 04 Jun 2026 — Referencias corregidas en components.css: --duration-fast → --dur-fast, --easing-standard → --ease-expo.

✓ RESUELTO
requestAnimationFrame del cubo sin pausa por visibilidad
Ubicación: index.html:1698–1748
Categoría: Performance

El loop de animación del cubo 3D corre indefinidamente con requestAnimationFrame. Cuando el tab está en background, el browser lo throttlea automáticamente, pero no se pausa cuando el hero sale del viewport (scroll down).

Fix: Agregar un IntersectionObserver sobre .hero para cancelar el rAF cuando el hero no es visible. También escuchar document.addEventListener('visibilitychange', ...).

/optimize

✓ RESUELTO 04 Jun 2026 — IntersectionObserver sobre .hero en index.html. rAF se pausa con cancelAnimationFrame cuando el hero sale del viewport.

✓ RESUELTO
Sin preload para fuentes críticas
Ubicación: Todas las páginas — <head>
Categoría: Performance

JetBrains Mono y Bebas Neue cargan via Google Fonts sin <link rel="preload">. Bebas Neue se usa inmediatamente above-the-fold (hero title), causando FOUT perceptible.

Fix: Agregar <link rel="preload" as="font" crossorigin> para los subsets críticos, o usar font-display: optional para evitar FOUT completamente.

/optimize

✓ RESUELTO 04 Jun 2026 — Bebas Neue añadida al <link> de Google Fonts en <head> de guidelines.html y components.html, eliminando dependencia del @import en tokens.css.

✓ RESUELTO
5 HTTP requests para CSS — sin bundling
Ubicación: guidelines.html, components.html <head>
Categoría: Performance

Cada página carga tokens.css + shared.css + sidebar.css + hero.css + components.css = 5 requests síncronos de CSS. Con HTTP/2 esto es menos crítico pero sigue siendo overhead innecesario para un proyecto de esta escala.

Fix: Considerar un paso de build simple (PostCSS @import inline) o simplemente concatenar los archivos.

/optimize

✓ RESUELTO 04 Jun 2026 — bundle.css generado (71KB) concatenando los 5 archivos. Todas las páginas migradas a <link href="bundle.css">. @import de Google Fonts eliminado de tokens.css. Script build.sh para regenerar el bundle.

Responsive Design

Score: 4/4 — Sidebar en barra horizontal scrollable (mobile). Banda de nav scrollable horizontal en mobile. Touch targets 44px. Cosméticos pendientes: font-size-body-sm 12px · inline colors en swatches.

P0
Sidebar desaparece en mobile sin nav de reemplazo
Ubicación: sidebar.css:85–87
Categoría: Responsive Design
WCAG: 2.4.1 Bypass Blocks (A)

En @media (max-width: 900px) el sidebar hace display: none. Las páginas components.html, guidelines.html, audits.html, etc. no tienen navegación alternativa en mobile. Toda la navegación in-page (secciones de typography, colors, spacing, etc.) es inaccesible.

El nav-overlay del header solo contiene los links de primer nivel (Components, Guidelines, etc.), no los anchors de sección.

Fix: Integrar los links de sección del sidebar en el nav-overlay de mobile, o agregar un "Jump to section" dropdown persistente en mobile.

/layout

✓ RESUELTO 04 Jun 2026 — sidebar.css: display:none reemplazado por barra horizontal sticky scrollable. Links de sección visibles y navegables en mobile.

✓ RESUELTO
Touch targets en sidebar insuficientes
Ubicación: sidebar.css:58–68
Categoría: Responsive Design
WCAG: 2.5.8 Target Size (AA, Level 2.2)

Los links del sidebar tienen padding: 4px 8px. Con line-height de 18px, el target total es ~26px de alto — muy por debajo del mínimo 44px de WCAG 2.5.8 y de las guías de plataforma iOS/Android (44pt / 48dp).

Aunque el sidebar está oculto en mobile, si en el futuro se muestra en tablets (900–1024px), el problema ya existe.

Fix: Aumentar a padding: 10px 8px para lograr ~40px, o usar un mínimo de min-height: 44px en los links.

/adapt

✓ RESUELTO 04 Jun 2026 — sidebar.css: min-height: 44px + display: flex + align-items: center en .page-sidebar a.

✓ RESUELTO
Banda de navegación completamente oculta en mobile
Ubicación: index.html — media query responsive
Categoría: Responsive Design

La banda de links en index.html desaparecía con display: none en 768px. En mobile el usuario no tenía manera de descubrir las secciones principales del sistema.

Además se añadió un item "Start here" con acento visual que apunta a guidelines.html — entry point de onboarding clarificado.

✓ RESUELTO 05 Jun 2026 — Banda convertida a scroll horizontal en mobile con overflow-x: auto; scrollbar-width: none. "Start here" como primer item.

P2
font-size-body-sm a 12px — muy pequeño en mobile
Ubicación: tokens.css:316
Categoría: Responsive Design

--font-size-body-xs: 12px es el tamaño mínimo recomendado para texto legible en mobile. Se usa extensamente en labels, badges, metadata y monospace. En pantallas de densidad media puede resultar incómodamente pequeño.

Fix: Considerar --font-size-body-xs: clamp(11px, 1.4vw, 12px) o simplemente asegurar que ningún texto de interfaz crítico use este tamaño sin un fallback responsive.

/adapt

Theming

Score: 3/4 — Sistema de tokens maduro y bien documentado. El problema es de nomenclatura, no de arquitectura.

P1
Inconsistencia de nombres de tokens de animación
Ubicación: components.css:490 · index.html:188,230,633 (y más)
Categoría: Theming

Dos sistemas de nombres coexisten en el mismo codebase:

Definidos en tokens.css: --dur-fast, --dur-base, --dur-slow, --ease-expo, --ease-quart

Referenciados pero NO definidos: --duration-fast, --duration-base, --easing-standard

Cualquier nuevo código que siga el patrón "incorrecto" perpetúa el bug. Necesita ser unificado.

/polish

✓ RESUELTO 04 Jun 2026 — components.css corregido: --duration-fast → --dur-fast, --easing-standard → --ease-expo.

P2
Colores hardcodeados en inline styles de index.html
Ubicación: index.html:1419–1443, 1555, 1638–1643
Categoría: Theming

Las celdas de color del bento grid usan valores hardcodeados: style="background:#090d10", style="background:#127ae6", style="background:#549ffd", etc. En el contexto de un design system que exhibe sus propios tokens, esto es particularmente contradictorio.

Fix: Usar style="background:var(--color-neutral-900)", etc. Si los inline styles son para demostración del valor hex específico, documentarlo con un comentario.

/polish
P3
text-box-trim con soporte experimental limitado
Ubicación: components.css:379–381
Categoría: Performance / Theming

text-box-trim: trim-both; text-box-edge: cap alphabetic; en .btn es una propiedad CSS en estado de borrador (no en spec estable). Soporte actual: Chrome 123+, Safari 17.4+, sin Firefox. En browsers sin soporte el padding visual del botón diferirá del diseñado.

Fix: Agregar un feature query @supports (text-box-trim: trim-both) o documentar el progressive enhancement.

/polish

✓ RESUELTO 04 Jun 2026 — Envuelto en @supports (text-box-trim: trim-both) en components.css.

Patrones Sistémicos

✓ Token naming drift — RESUELTO: Las referencias incorrectas --duration-fast / --easing-standard en components.css fueron corregidas a --dur-fast / --ease-expo. El codebase usa una sola convención de nombres.
✓ Sidebar como única navegación secundaria — RESUELTO: El sidebar ahora tiene una variante responsive: barra horizontal scrollable en mobile (<900px) con todos los section anchors visibles.
✓ Banda de nav oculta en mobile — RESUELTO: La banda de links en index.html es ahora scrollable horizontal en mobile con overflow-x: auto. Se añadió "Start here" como item diferenciado apuntando a guidelines.html.
✓ ARIA incompleto en componentes interactivos — RESUELTO: Burger con aria-label + aria-expanded + aria-controls. Overlay con role="dialog" + aria-modal="true". Focus trap implementado en _initMenu(). Hero SVG con role="img" + aria-label.

Lo Que Funciona Bien

Sistema de tokens exhaustivo y bien documentado: tokens.css es ejemplar — cada variable tiene comentario con su equivalente en Figma, colores organizados por escala con hue/chroma documentados, y aliases semánticos correctamente separados de los primitivos.
Focus management: focus-visible está implementado consistentemente en botones, links, inputs y sidebar con outline 2px azul bien contrastado. No hay foco invisible — patrón correcto ejecutado bien.
Reduced motion support: Presente en shared.css (reset global), hero.css (mouse-scroll), index.html (cubo, logo, wordmark), hero.css. El approach es comprehensivo, no un afterthought.
Transiciones bien easeadas: Donde los tokens son correctos, las transiciones usan --ease-expo (cubic-bezier(0.16,1,0.3,1)) — smooth deceleration, nada de bounce o elastic. Exactamente lo correcto para un tool UI.
Typography hierarchy clara: Bebas Neue / Barlow / JetBrains Mono con roles estrictamente definidos. El sistema de type es coherente y nunca ambiguo — sabes cuándo estás leyendo un token name vs UI copy vs heading.
Animación del logo SVG: La secuencia de draw → corner marks → letterform es deliberada y técnicamente sólida (stroke-dasharray + keyframes staggerados). No es decoración — es el logo enseñando su propia construcción.

Acciones Recomendadas

P0, P1 y P3 resueltos. Issues cosméticos abiertos (2):

1
/adapt

[P2] --font-size-body-xs: 12px fijo — considerar clamp(11px, 1.4vw, 12px) o asegurar que ningún texto crítico use este tamaño en mobile sin fallback.

2
/polish

[P2] Reemplazar inline colors en swatches de color system (#090d10, #127ae6, etc.) con tokens CSS (var(--color-neutral-900)) — semánticamente mejor aunque el hex sea visible como texto.

Puedes ejecutar estos comandos uno por uno, todos de una, o en cualquier orden que prefieras.
Vuelve a ejecutar /audit después de los fixes para ver tu score mejorar.