STACKR es un SaaS B2B para equipos de desarrollo indie que necesita diferenciarse de Notion y Linear con una identidad visual cruda, honesta y de alto rendimiento. El sistema de diseño neobrutalism aporta legibilidad extrema, jerarquía visual inmediata y personalidad sin ambigüedades.
Intención de diseño: Toda la UI de STACKR debe sentirse como un sistema construido para productividad máxima — sin decoración superflua, sin ambigüedad en los estados interactivos, y con contraste que funcione en pantallas de baja calidad y modo oscuro.
| Token CSS | Valor | Uso semántico | Nunca usar para |
|---|---|---|---|
--color-primary |
#FDC800 | CTA principal, estado activo, marcador de foco alternativo | Texto sobre blanco (ratio insuficiente) |
--color-secondary |
#432DD7 | Botones secundarios, links, focus rings | Background de cards completas |
--color-text |
#1C293C | Todo el texto, bordes, sombras offset | Fondos de pantalla completa |
--color-surface |
#FBFBF9 | Fondos de página, headers de cards | Texto o labels |
Regla: Inter para todo el texto UI. JetBrains Mono SOLO para labels de categoría, badges de estado, bloques de código y metadatos técnicos. Nunca mezclar pesos dentro de un mismo bloque de párrafo.
Base: 4px. Usar exclusivamente múltiplos del scale. Sin valores ad-hoc.
| Token | Valor | Aplicar en |
|---|---|---|
--border | 2px solid #1C293C | TODOS los elementos interactivos |
--radius-sm | 4px | Buttons, badges, inputs |
--radius-md | 8px | Cards, modales, panels |
--shadow-sm | 3px 3px 0 #1C293C | Badges, elementos pequeños |
--shadow-md | 4px 4px 0 #1C293C | Botones, inputs |
--shadow-lg | 6px 6px 0 #1C293C | Cards hover, botones large |
Las sombras SIEMPRE son offset (nunca blur/difusas). El color de sombra SIEMPRE es --color-text. Sin box-shadow con blur.
Anatomía: [icon?] + label + [icon-trailing?] · Padding horizontal siempre ≥ sp-4 · Nunca texto en minúsculas en CTA primario.
| Estado | Background | Sombra | Transform | Accesibilidad |
|---|---|---|---|---|
| Default | --color-primary | --shadow-md | none | role="button", aria-label si solo icono |
| Hover | --color-primary | --shadow-lg | translate(-1px,-1px) | cursor:pointer |
| Active / Pressed | --color-primary | none | translate(4px,4px) | Visual imita presión física |
| Focus-visible | --color-primary | --shadow-md | none | outline: 3px solid --color-secondary, offset 2px |
| Disabled | --color-primary @ 40% | none | none | aria-disabled="true", pointer-events:none |
Regla: siempre border: var(--border). Texto en MAYÚSCULAS con font-family: var(--font-mono). Mínimo 2px de padding lateral. No usar más de 4 badges distintos en una misma card.
Focus ring: box-shadow: 0 0 0 3px var(--color-secondary). Error ring: 0 0 0 3px var(--color-danger).
Label siempre encima del campo. Placeholder: color #aaa. La sombra offset se mantiene en todos los estados.
Todas las cards interactivas deben tener box-shadow: var(--shadow-md) en default y --shadow-lg en hover con transform: translate(-1px,-1px).
El footer de card siempre se separa con border-top: var(--border) y fondo --color-surface.
| Combinación | Ratio | Texto normal | Texto grande |
|---|---|---|---|
| Text sobre Surface | 14.3:1 | PASS | PASS |
| Text sobre Primary | 10.8:1 | PASS | PASS |
| White sobre Secondary | 7.2:1 | PASS | PASS |
| White sobre Danger | 4.9:1 | PASS | PASS |
| White sobre Success | 4.5:1 | PASS | PASS |
| Primary sobre White | 1.9:1 | FAIL | FAIL |
⚠ PROHIBIDO usar #FDC800 como color de texto sobre fondos claros. Solo usarlo como background con texto #1C293C.
:focus-visible en DevTools.
aria-label descriptivo. Modales deben tener role="dialog" + aria-labelledby.
Gradientes en botones:
Los gradientes eliminan el contraste predecible y rompen la estética raw. Usar siempre backgrounds planos de token.
Border-radius > 8px:
Bordes muy redondeados ablandan la identidad neobrutalism. Máximo --radius-md (8px) en cards, --radius-sm (4px) en buttons.
Texto primary sobre blanco:
Texto en amarillo — ilegible
Ratio 1.9:1. NUNCA usar #FDC800 como color de texto. Solo como background.
Sombras con blur:
Las sombras difusas son incompatibles con neobrutalism. Usar SOLO sombras offset sólidas var(--shadow-md).
Icono sin label en CTA principal:
Los CTAs primarios siempre incluyen texto visible. Solo se aceptan botones de solo icono en toolbars secundarias con aria-label.
Patrón correcto completo:
Background plano + border + shadow offset + texto legible + badge con estado.
var(--color-*)), sin valores hex literales en estilos de componente.
border: var(--border). Verificar con buscador de estilos.
box-shadow: var(--shadow-lg) y transform: translate(-1px,-1px).
margin: 10px o valores ad-hoc.
translate(4px,4px) en estado :active. Verificar manualmente click/tap.
outline: none sin alternativa.
border-radius supera var(--radius-md) (8px). Grep: border-radius: [9-9][0-9]px.
linear-gradient, radial-gradient) en elementos interactivos.
aria-label descriptivo. Verificado con lector de pantalla (VoiceOver/NVDA).
border-radius: 12px+ por var(--radius-md); (2) elimina box-shadow con blur; (3) reemplaza linear-gradient por tokens planos; (4) añade border: var(--border) a cada elemento interactivo que carezca de él; (5) verifica contraste de cada combinación texto/fondo con axe.