Sistema de diseño · v3

Guía de estilos SuperLeads

Todo lo que hace falta para que cualquier persona del equipo diseñe y construya con la misma calidad. Esta página está hecha con el propio sistema que describe: los botones, campos y tarjetas que ves son los reales — pásales el cursor.

3
Colores primarios
1
Tipografía · Plus Jakarta Sans
.5px
Todos los bordes
22
Secciones
Fundamento

1 · Los seis principios

Todo lo demás en esta guía es consecuencia de estos seis. Si algo no está documentado, resuélvelo con ellos.

1 · El fondo manda el color

El verde solo existe sobre oscuro. El navy solo sobre claro. Es la regla que más se rompe y la que más delata un diseño que no es nuestro.

2 · Bordes de medio píxel

.5px solid, nunca 1px. Un borde grueso separa una interfaz cara de una barata.

3 · Todo lo que se toca, responde

Un botón que no se mueve al pasarle el cursor se siente muerto.

4 · Movimiento lento y suave

Un solo easing, y las cosas suben 2 o 3 píxeles, no 10. Si la animación se nota, está mal calibrada.

5 · Jerarquía con color

Un texto secundario es #5b6478, no negro al 50%. La opacidad se adivina en pantalla y desaparece impresa.

6 · Nada se inventa

Si no hay dato, va un guion largo . Un cero fingiendo ser dato es peor que un hueco honesto.

Base

3 · Color

Tres primarios resuelven el 80% de cualquier pantalla. Los secundarios sostienen y matizan; los de estado están reservados y nunca se reciclan.

Colores primarios

Aa
Verde SuperLeads#56EF9F

Acento principal. CTA, highlights e íconos sobre fondo oscuro.

Aa
Navy#002582

Texto y botones sobre fondo claro. La voz de la marca.

Aa
Navy profundo#001240

Fondo oscuro: hero, footer, sidebar, bloques de CTA.

Colores secundarios

Aa
Verde hover#2BC878

Hover del verde en superficies sólidas.

Aa
Navy medio#001a5e

Fondo oscuro secundario · hover de botón navy.

Aa
Blue#0039C8

Links, bordes activos, tags y eyebrows en claro.

Aa
Blue medio#2A89FB

Íconos, stats, acentos de gráfica.

Aa
Blue soft#F4F7FF

Fondo de sección clara y fondo general de app.

Aa
Blue softer#EEF2FF

Fondo de tarjetas y bloques dentro de contexto claro.

Neutros y texto

Aa
Ink#1a1a1a

Texto body sobre claro.

Aa
Border#e0e8f8

Bordes estructurales en fondos claros.

Aa
Muted#5b6478

Texto secundario, hints, notas.

Aa
Dim#98a1b0

Terciario: fechas, metadatos, marcas de gráfica.

Textos sobre fondo oscuro

#ffffff — Texto principal

#7a9fd4 — Subtítulos y descripciones

#4a6aaa — Labels, notas, contadores

#3a5a9a — Texto de apoyo, el más tenue permitido

Colores de estado

Reservados. Nunca decorativos ni como "serie 4" de una gráfica. Siempre acompañados de texto o ícono — el color solo nunca comunica.

Aa
Bien#0ca30c

Dentro de meta.

Aa
Atención#eb6834

Requiere revisión.

Aa
Crítico#d03b3b

Fuera de rango, acción inmediata.

Aa
Destructivo#d92d43

Borrar, cancelar, errores de formulario.

Tokens — copia esto al inicio de tu CSS

:root{
  /* — Primarios — */
  --green:#56EF9F; --navy:#002582; --navy-deep:#001240;

  /* — Secundarios — */
  --green-d:#2BC878; --navy-mid:#001a5e;
  --blue:#0039C8; --blue-mid:#2A89FB;
  --blue-soft:#F4F7FF; --blue-softer:#EEF2FF;

  /* — Neutros — */
  --ink:#1a1a1a; --border:#e0e8f8;
  --muted:#5b6478; --dim:#98a1b0;

  /* — Estado — */
  --ok:#0ca30c; --warn:#eb6834;
  --bad:#d03b3b; --destructive:#d92d43;

  /* — Gráficas (paleta validada, separada de la marca) — */
  --chart-1:#2a78d6; --chart-2:#eb6834; --chart-3:#1baf7a;

  /* — Movimiento — */
  --ease:cubic-bezier(.16,1,.3,1);

  /* — Sombras — */
  --shadow-sm:0 1px 2px rgba(0,37,130,.04);
  --shadow-card:0 10px 32px rgba(0,37,130,.08);
  --shadow-btn:0 10px 28px rgba(0,37,130,.22);
  --shadow-cta:0 10px 28px rgba(86,239,159,.28);
  --shadow-pill:0 10px 32px rgba(0,37,130,.08);
}

Reglas de uso — las que no se negocian

ReglaPor qué
Verde SOLO sobre navy/oscuro. Nunca sobre blanco.Sobre blanco no alcanza contraste y se ve barato. Sobre claro, usa navy o blue.
Navy para texto y botones sobre fondos claros.Es la voz de la marca en documentos y formularios.
Blue para links, bordes activos y eyebrows claros.Es el "verde del contexto claro".
Los colores de estado no se reciclan.Si el rojo también es decorativo, el rojo de alerta deja de alarmar.
Las gráficas usan --chart-*, no la marca.La paleta de marca no pasa pruebas de daltonismo en marcas pequeñas.
Texto siempre en tinta, nunca del color de su serie.Un valor pintado del color de su barra se vuelve ilegible.
Base

4 · Tipografía

Familia única: Plus Jakarta Sans. No hay segunda fuente.

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,400;0,500;0,600;0,700;0,800;1,700;1,800&display=swap" rel="stylesheet">

Hero H1 con énfasis

46–50px · 800 · -1.8px · 1.07

Título de página

32–36px · 800 · -0.8px · 1.12

Título de tarjeta

16–22px · 800 · -0.3px · 1.2

Subtítulo de sección — la línea que explica de qué va lo que sigue, en tono tranquilo.

14–15px · 400 · 1.7

Texto body. El cuerpo de todo lo que se lee de corrido, con interlineado generoso para que el ojo no se pierda entre renglones largos.

13–15px · 400–500 · 1.78

Eyebrow / label

10–11px · 700 · 1.3px · mayúsculas

$4,260,000.00

Stat · 26–32px · 800 · -1px · tabular-nums

Reglas

  • Énfasis en H1: <em> italic — verde sobre oscuro, azul sobre claro
  • Números en columna o que cambian en vivo: font-variant-numeric: tabular-nums. Sin esto los dígitos bailan al actualizarse
  • Nunca centres párrafos de más de dos líneas. Títulos sí, texto corrido no
  • Ancho de lectura: 65–75 caracteres (max-width: 46rem en documentos)
Base

5 · Espaciado y radios

Escala de múltiplos de 4, sin excepción: 4 · 8 · 12 · 16 · 20 · 24 · 32 · 40 · 56 · 72

8px
controles

12px
tarjetas

16–24px
contenedores

pill
badges

ContextoDesktopMobile
Hero / Footer / CTA block72px 56px28px 18px
Sección estándar72px 56px28px 18px
Tarjeta20–24px16px
Panel interno16–20px14px
Base

6 · Sombras y bordes

Grandes, suaves y teñidas de navy — nunca negras ni duras. Una sombra negra sobre nuestro azul se ve sucia.

Nivel 0
Al ras · solo borde
Nivel 1
Apoyado · tarjeta en reposo
Nivel 2
Levantado · hover, panel
Nivel 3
Encima · modal, píldora
/* Nivel 0 — al ras */
border:.5px solid var(--border);
/* Nivel 1 — apoyado */
box-shadow:0 1px 2px rgba(0,37,130,.04);
/* Nivel 2 — levantado */
box-shadow:0 10px 32px rgba(0,37,130,.08);
/* Nivel 3 — encima de todo */
box-shadow:0 8px 40px rgba(0,0,0,.12);
/* Intención — CTA verde en hover */
box-shadow:0 10px 28px rgba(86,239,159,.28);
/* Intención — navy en hover */
box-shadow:0 10px 28px rgba(0,37,130,.22);

Bordes

  • Estructurales: siempre .5px solid. En Tailwind: border-[0.5px]
  • Sobre claro: #e0e8f8 · Sobre oscuro: rgba(255,255,255,.07), hover rgba(86,239,159,.25)
  • Punteado solo para zonas de "agregar" y estados vacíos
Interacción

7 · Movimiento — el sentir del clic

Esta sección separa una interfaz que se siente cara de una que se siente lenta. Todo se mide desde que el dedo toca.

La única curva

--ease:cubic-bezier(.16,1,.3,1);

Sale rápido y frena suave. Todo usa esta curva. Si algo usa linear o ease-in-out, está fuera del sistema.

Los tiempos

InteracciónDuraciónQué se mueve
Presionado (active)0ms — inmediatoBaja a scale(.98) o pierde su lift. Debe ser instantáneo: es el acuse de recibo del clic.
Hover de botón200mstranslateY(-2px) + sombra de intención
Hover de tarjeta300mstranslateY(-3px) + sombra nivel 2
Cambio de color200mscolor, background, border-color
Panel / acordeón300msopacity + translateY(6px→0)
Modal / overlay250msopacity + scale(.95→1)
Fondo decorativo90–130sDeriva imperceptible (§16)

La regla de los 400 ms

Lo que tarda una acción define cómo se comunica:

TardaQué mostrar
< 100msNada. Solo el estado active del botón.
100–400msNada más que el active. Un spinner que parpadea molesta más que ayuda.
400ms – 2sSpinner dentro del botón + botón deshabilitado. El texto no cambia.
2s – 10sSpinner + texto que cambia ("Guardando…", "Analizando…").
> 10sPantalla de proceso con etapas que avanzan. El usuario tiene que ver que algo pasa, no un spinner eterno.

Retrasos de guardado (debounce)

AcciónEsperaPor qué
Autoguardado de formulario2500msSuficiente para no guardar en cada tecla, corto para no perder trabajo.
Autoguardado de nota1200msEl texto libre se escribe en ráfagas más cortas.
Búsqueda mientras se escribe300msDebajo se siente nervioso; arriba, lento.
Al salir de la pantalla0msTodo debounce pendiente debe dispararse. Nunca se pierde lo tecleado.
El acuse de recibo

Todo botón que dispara algo debe, en este orden: 1) hundirse al instante · 2) deshabilitarse mientras trabaja · 3) decir cómo terminó (Guardado 14:32 o el mensaje real del error). Nunca "algo salió mal" — siempre qué salió mal y qué hacer.

Componentes

8 · Botones

Pásales el cursor: todos son los reales del sistema.

Primario — verde (CTA principal)

El de la acción más importante de la pantalla. Solo uno por vista.

.btn-primary{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  background:var(--green);color:var(--navy);
  padding:14px 26px;border-radius:8px;border:none;
  font-family:inherit;font-size:14px;font-weight:700;cursor:pointer;
  transition:transform .2s var(--ease),box-shadow .2s var(--ease),background-color .2s;
}
.btn-primary:hover{transform:translateY(-2px);box-shadow:var(--shadow-cta)}
.btn-primary:active{transform:translateY(0);box-shadow:none}
.btn-primary:disabled{opacity:.5;cursor:not-allowed;transform:none;box-shadow:none}
.btn-primary:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

Secundario — navy

La acción importante pero no principal, sobre fondo claro.

.btn-navy{
  background:var(--navy);color:#fff;
  padding:12px 22px;border-radius:8px;border:none;
  font-size:13px;font-weight:700;cursor:pointer;
  transition:transform .2s var(--ease),box-shadow .2s var(--ease),background-color .2s;
}
.btn-navy:hover{background:var(--navy-mid);transform:translateY(-2px);box-shadow:var(--shadow-btn)}
.btn-navy:active{transform:translateY(0);box-shadow:none}

Terciario, fantasma y destructivo

/* Terciario — acciones de apoyo en fila */
.btn-outline{background:#fff;color:var(--navy);border:.5px solid var(--border);
  padding:10px 18px;border-radius:8px;font-size:13px;font-weight:700}
.btn-outline:hover{background:var(--navy);color:#fff;border-color:var(--navy)}

/* Fantasma — navegación, cancelar */
.btn-ghost{background:transparent;color:var(--muted);padding:10px 18px;font-size:13px;font-weight:600}
.btn-ghost:hover{background:rgba(0,37,130,.05);color:var(--navy)}

/* Destructivo — discreto hasta que se necesita */
.btn-danger{background:transparent;color:var(--muted);padding:8px;border-radius:8px}
.btn-danger:hover{background:#fef2f2;color:var(--destructive)}

Tamaños e íconos

TamañoPaddingFuenteCuándo
Grande16px 30px15pxHero, CTA de cierre
Normal14px 26px14pxAcción principal
Compacto10px 18px13pxBarras de acciones
Mini6px 14px12pxDentro de tarjetas, nav
Ícono36px cuadradoSolo ícono, title obligatorio
  • Íconos de 14–16px, stroke-width:2, fill:none
  • Color: navy sobre verde · blanco sobre navy · hereda en outline y ghost
  • gap:8px respecto al texto. Ícono a la izquierda, salvo flechas de avance
Estado de carga

El botón no cambia de tamaño al entrar en carga (reserva el ancho). Un botón que se encoge y crece es el detalle que arruina una interfaz por lo demás correcta.

Componentes

9 · Formularios

Achica la ventana y mira la rejilla: se compacta sola de dos columnas a una, sin media queries.

La rejilla que se compacta sola

.form-grid{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
  gap:20px;
}
/* Campo que necesita todo el ancho */
.form-grid .full{grid-column:1/-1}

auto-fit + minmax es la clave: si caben dos columnas de 280px las pone, si no colapsa a una. Nunca uses repeat(2, 1fr) fijo — se desborda en móvil. Para grupos de tres: minmax(200px, 1fr).

Formulario vivo

Como aparece en el panel y en la hoja del cliente.

Se muestra junto al colegio durante la llamada.

Solo alumnos pagando colegiatura hoy — sin lista de espera.

Liga o celular — el botón verde abre la conversación al instante.

Correo inválido.

💬

El botón nunca desaparece: se apaga y ocupa el mismo espacio.

Marca todas: lo normal es más de una.

Anatomía de un campo

.field{display:flex;flex-direction:column;gap:6px}
.field label{font-size:13px;font-weight:500;color:var(--navy)}
.field input,.field textarea,.field select{
  width:100%;padding:10px 14px;
  border:.5px solid var(--border);border-radius:8px;background:#fff;
  font-family:inherit;font-size:14px;color:var(--ink);
  transition:border-color .2s,box-shadow .2s;
}
.field input::placeholder{color:var(--dim)}
.field input:hover{border-color:#c9d6f0}
.field input:focus{
  outline:none;border-color:var(--blue);
  box-shadow:0 0 0 3px rgba(0,57,200,.10);
}
.hint{font-size:11px;line-height:1.45;color:var(--muted)}
.err-msg{font-size:12px;font-weight:500;color:var(--destructive)}
.field input[aria-invalid="true"]{border-color:var(--destructive)}

/* Número protagonista */
.field input.grande{height:56px;font-size:24px;font-weight:600;
  color:var(--navy);font-variant-numeric:tabular-nums}

El hint es obligatorio en cualquier campo donde quepa duda de qué contar o en qué unidad. Resuelve la pregunta antes de que se haga: qué incluir, qué no, o a qué cálculo alimenta el dato.

La regla de los tres estados

Nada arranca seleccionado

Un Sí/No con "No" preseleccionado hace que el campo se vea contestado sin que nadie lo haya contestado — y contamina los datos.

Clic sobre la opción ya activa la des-selecciona. Y en el código: if (valor != null), nunca if (valor) — porque 0 es una respuesta.

ValorSignificaSe ve
nullSin preguntarNingún chip activo
0 / noRespondió que noChip "No" activo
1 / síRespondió que síChip "Sí" activo

Validación y autoguardado

  • Valida al salir del campo (blur), no en cada tecla — marcar en rojo un correo a medio teclear es hostil
  • Solo lo verdaderamente obligatorio bloquea. Un campo que frena el avance rompe la conversación en una sesión en vivo
  • Si el envío falla, lleva al usuario al error. Un botón que no hace nada porque hay un error en otra pantalla es un botón roto
  • Se guarda solo, y se dice: debounce 2.5s, flush al salir, indicador Guardando… → Guardado 14:32
  • El botón de avanzar se llama "Guardar y Continuar", no "Continuar" — nombra lo que hace y da tranquilidad
Componentes

12 · Tarjetas

Pásales el cursor: suben 3px con sombra teñida de navy.

Finalizado

Sobre fondo claro

Blanco, borde .5px, radio 12px, sombra nivel 1.

Borrador

Misma altura

Todas las tarjetas de una rejilla miden igual.

Sobre fondo oscuro

Fondo blanco al 4%, borde blanco al 7%. Hover: borde verde al 25%.

.card{
  background:#fff;border:.5px solid var(--border);border-radius:12px;
  padding:20px;box-shadow:var(--shadow-sm);
  transition:transform .3s var(--ease),box-shadow .3s,border-color .3s;
}
.card:hover{transform:translateY(-3px);box-shadow:var(--shadow-card);
  border-color:rgba(0,57,200,.25)}

/* Sobre oscuro */
.card-dark{background:rgba(255,255,255,.04);border:.5px solid rgba(255,255,255,.07)}
.card-dark:hover{border-color:rgba(86,239,159,.25)}

/* Rejilla uniforme */
.cards{display:grid;gap:24px;grid-template-columns:repeat(auto-fill,minmax(280px,1fr))}
Regla de rejilla

Todas las tarjetas con la misma altura y el mismo ancho (height:100% en el hijo). Una tarjeta "destacada" del doble de ancho deja huecos con casi cualquier número de elementos — la simetría gana.

Componentes

13 · Eyebrows, badges y stats

Eyebrow

Sobre fondo claro
Sobre fondo oscuro
.eyebrow{display:flex;align-items:center;gap:8px;margin-bottom:10px}
.eyebrow::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--blue)}
.eyebrow span{font-size:11px;font-weight:700;text-transform:uppercase;
  letter-spacing:1.3px;color:var(--blue)}
/* Sobre oscuro */
.eyebrow-dark::before{background:var(--green)}
.eyebrow-dark span{color:var(--green)}

Badges y pills

FinalizadoBorrador
● Diagnóstico de admisiones

Stats

480
Alumnos hoy
600
Capacidad instalada
120
Lugares de sobra

El stat héroe (la cifra que sostiene la conversación) va solo, sobre navy-deep, a 48–60px, con su contexto humano debajo en una fila de stats chicos. Una cifra grande sin contexto es un número; con contexto es un argumento.

Layout

14 · Grids y layout

UsoColumnas
Hero1fr 1fr
Tarjetas de featuresrepeat(auto-fill, minmax(280px, 1fr))
Stats barrepeat(auto-fit, minmax(160px, 1fr))
Formulariorepeat(auto-fit, minmax(280px, 1fr))
CTA block1fr auto
Contenido + widget1fr 1fr
Panel de appsidebar 288px + 1fr

Anchos máximos: app 1400px · página de contenido 1100px · documento de lectura 46rem.

Regla de oro del responsive

Usa auto-fit/auto-fill con minmax antes que media queries. El layout que se acomoda solo no se rompe en el tamaño que no probaste.

Datos

15 · Visualización de datos

La paleta de marca NO se usa en gráficas: el verde y el navy no pasan las pruebas de contraste ni de daltonismo en marcas pequeñas.

Aa
Chart 1#2a78d6

Serie 1 · secuencial base.

Aa
Chart 2#eb6834

Serie 2 · el "antes".

Aa
Chart 3#1baf7a

Serie 3 · el "después" / meta.

Aa
Neutro#c6ccd8

Sin explicar, resto, sin dato.

Comparación — barras a la misma escala

A su conversión de hoy3,650
Subiendo la conversión a 5%2,400

Composición — apilada al 100% con separación de 2px

Recomendados 50% Anuncios 30% Eventos 20%

Reglas

  • Un solo tono claro→oscuro para magnitudes. Dos tonos + gris para polaridad. Nunca arcoíris
  • El color sigue a la entidad, no a su posición: si un filtro cambia el número de series, las que quedan no cambian de color
  • Texto en tinta, nunca del color de la serie. La marca de color va al lado
  • Leyenda siempre con 2+ series, y etiqueta directa en las importantes
  • Marcas finas: líneas 2px, puntos ≥8px, separación de 2px entre segmentos apilados
  • Contraste en marcas oscuras: sobre relleno oscuro el texto va blanco, sin excepción
  • Nunca dos ejes Y. Dos magnitudes distintas → dos gráficas
  • Sin dato, no hay gráfica. No dibujes un cero: oculta el panel

Números en la interfaz

  • Moneda con dos decimales y símbolo ($134,000.00), porcentajes con 1–2 decimales
  • Sin dato: (guion largo), nunca 0, N/A ni vacío
  • Fechas en America/Mexico_City, formato medium (14 ago 2026)
Detalle

16 · Fondos y elementos decorativos

Círculos difusos muy tenues, muy grandes, siempre detrás. Y una deriva tan lenta que a simple vista está quieta.

.fondo{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0}
.globo-1{position:absolute;top:-30%;right:-15%;width:520px;height:520px;
  border-radius:50%;background:rgba(42,137,251,.05);filter:blur(100px)}
.globo-2{position:absolute;bottom:-30%;left:-10%;width:480px;height:480px;
  border-radius:50%;background:rgba(86,239,159,.05);filter:blur(110px)}

/* Deriva — el fondo respira sin que nadie lo note */
@keyframes deriva{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  50%    {transform:translate3d(-48px,36px,0) scale(1.08)}
}
.globo-1{animation:deriva  90s ease-in-out infinite}
.globo-2{animation:deriva 130s ease-in-out infinite reverse}

/* Círculo de acento en secciones oscuras */
section::before{content:"";position:absolute;right:-100px;top:-100px;
  width:480px;height:480px;border-radius:50%;
  background:rgba(86,239,159,.03);pointer-events:none}

Separador de barra de stats (sobre oscuro): rejilla con gap:1px y fondo #0a3070 — el de la cabecera de esta página.

Interacción

17 · Estados de la interfaz

Toda pantalla que carga datos necesita cuatro diseños, no uno.

Vacío

Aún no hay diagnósticos. Inicia una sesión para descubrir oportunidades.

Cargando

Consultando el censo del INEGI…

Arriba de 10s: etapas que avanzan.

Error

No se pudo guardar: verifica que la migración 0010 esté aplicada.

El mensaje real, junto a la acción que falló. Nunca destruye lo escrito.

Éxito

Discreto: Guardado 14:32 en tinta.

¡Análisis completado!

Toast solo para acciones grandes · 3s · abajo al centro.

Patrones

18 · Modos especiales

Modo presentación

  • Oculta la navegación y deja solo el contenido, para compartir pantalla
  • El botón que lo activa debe ser visible desde cualquier pantalla: si se puede encender en un lado y no apagar en otro, es una trampa
  • El estado persiste y se restaura antes del primer pintado, para que no haya parpadeo

Modo privado (métricas ocultas)

Conversión

6.16%

Ocupación

70.00%

  • filter: blur(7px); user-select: none; — no se lee ni se copia
  • Los nombres se ven, las cifras no. Un ojo al lado revela u oculta
  • Arranca oculto por defecto: es más seguro descubrir a propósito que tapar a las prisas
Salida

19 · Impresión y PDF

@media print{
  *{print-color-adjust:exact;-webkit-print-color-adjust:exact}
  @page{size:letter;margin:16mm}

  html,body{background:#fff !important}
  .no-print,nav,.sidebar,.topbar,button{display:none !important}

  /* Las tarjetas se aplanan: en papel solo gastan tinta */
  .card{border:0 !important;box-shadow:none !important;
    background:transparent !important;padding:0 !important}

  body{font-size:11pt;line-height:1.5}
  h1,h2,h3{break-after:avoid}
  figure,.par-dato{break-inside:avoid}
  /* Las secciones SÍ pueden partirse: evitarlo deja huecos al pie */
}
  • Jerarquía por color, nunca por opacidad: la mayoría de las impresoras no resuelven un azul al 30%
  • El documento se ve igual en pantalla que en papel — así nadie imprime sorpresas
Calidad

20 · Accesibilidad

  • Contraste mínimo: 4.5:1 en texto normal, 3:1 en texto grande y marcas de gráfica
  • Foco siempre visible: outline: 2px solid var(--blue); outline-offset: 2px. Nunca outline:none sin reemplazo — dale Tab a los botones de arriba
  • Área táctil mínima 44×44px. Un botón de 32px necesita padding invisible alrededor
  • Nada depende solo del color: los estados llevan ícono o texto además del color
  • Todo ícono solo lleva title y aria-label
  • Controles ocultos por hover deben verse en táctil (opacity-100 en móvil, hover solo desde md:). Un botón invisible que sí recibe toques es un accidente esperando
Cierre

21 · Checklist antes de entregar

Márcalo. Si algo queda sin palomear, no está listo.

Marca

Estructura

Interacción

Contenido

Cierre

Cierre

22 · Anti-patrones

Lo que delata un diseño fuera del sistema. Si tu pantalla tiene algo de la columna izquierda, corrígelo.

❌ No✅ Sí
Verde #56EF9F sobre blancoNavy o blue sobre claro; verde solo sobre oscuro
border: 1px solid #dddborder: .5px solid var(--border)
Sombras negras rgba(0,0,0,.2)Sombras teñidas de navy
opacity: .5 para jerarquía de textoEl color --muted o --dim
transition: all .3s easePropiedades nombradas + var(--ease)
Hover que mueve 8pxtranslateY(-2px) botón · -3px tarjeta
repeat(2, 1fr) fijo en formulariosrepeat(auto-fit, minmax(280px, 1fr))
Un <select> con 4 opcionesChips, todas visibles
Toggle con "No" preseleccionadoTres estados, nada activo al inicio
"Ocurrió un error, intenta de nuevo"El mensaje real y qué hacer
Mostrar 0 cuando no hay dato
Botón que se encoge al cargarAncho reservado, spinner adentro
Tarjeta destacada del doble de anchoCuadrícula uniforme
Colores de marca en gráficasPaleta --chart-* validada
Un spinner eterno sin explicaciónEtapas que avanzan arriba de 10s
Acción principal al fondo del menúAcción principal arriba
Si algo no está aquí

Resuélvelo con los seis principios — y luego agrégalo a esta guía.