Sistema de Diseño — v1.3
Estética: minimalista tipo Apple (superficies limpias, blur, transiciones sutiles). Modo: solo claro. Tecnología: agnóstico — los tokens están en variables CSS y valen para HTML puro, React, Vue o lo que elijas. Este documento es la fuente de verdad. La página interactiva (UI Kit) debe implementar exactamente lo aquí definido. UI Kit en vivo: https://style.pgrhub.es (el propio documento se sirve en https://style.pgrhub.es/sistema).
1. Principios
- Contenido primero. El diseño desaparece; lo que destaca es el dato o la acción.
- Jerarquía por peso y espacio, no por color. El color se reserva para acciones y estados.
- Un solo acento. El azul es la única voz de acción en toda la app.
- Movimiento con propósito. Toda animación responde a una interacción; nada se mueve solo.
- Profundidad por material, no por bordes. Se usan blur y sombras suaves en lugar de líneas duras.
2. Tokens de color
Definidos como variables CSS en :root.
2.1 Neutros (fondos y texto)
| Token | Valor | Uso |
|---|---|---|
--bg-page |
#F5F5F7 |
Fondo general de la aplicación |
--bg-surface |
#FFFFFF |
Tarjetas, tablas, paneles, modales |
--bg-surface-2 |
#FAFAFC |
Superficies secundarias (cabecera de tabla, filas alternas) |
--bg-material |
rgba(255,255,255,0.72) |
Superficies translúcidas (header, sidebar) — siempre con blur |
--text-primary |
#1D1D1F |
Texto principal |
--text-secondary |
#6E6E73 |
Texto de apoyo, descripciones, labels |
--text-tertiary |
#AEAEB2 |
Placeholders, texto deshabilitado |
--border |
#E5E5EA |
Separadores y bordes por defecto |
--border-strong |
#D2D2D7 |
Bordes de inputs y controles |
2.2 Acento y semánticos
| Token | Valor | Hover | Pressed | Uso |
|---|---|---|---|---|
--accent |
#0071E3 |
#0077ED |
#006EDB |
Acciones, enlaces, selección, focus |
--accent-soft |
#EAF3FE |
— | — | Fondo de elementos activos (ítem de sidebar, chip seleccionado) |
--success |
#34C759 |
— | — | Confirmaciones, estados OK |
--warning |
#FF9500 |
— | — | Avisos |
--danger |
#FF3B30 |
#FF453A |
#E0342B |
Errores, acciones destructivas |
--danger-soft |
#FEECEB |
— | — | Fondo de mensajes de error |
Reglas de uso del color:
- Nunca dos acentos distintos compitiendo en la misma vista.
- Los semánticos solo comunican estado; no se usan como decoración.
- El texto sobre acento o semánticos es siempre blanco #FFFFFF.
3. Tipografía
Fuente: stack del sistema — así en Mac/iOS se renderiza SF Pro (la de Apple) automáticamente.
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text",
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
Alternativa si se quiere idéntica en todas las plataformas: Inter (Google Fonts).
Escala tipográfica
| Rol | Tamaño / línea | Peso | Tracking | Uso |
|---|---|---|---|---|
| Display | 34 / 40 px | 700 | −0.02em | Título de página principal |
| Título 1 | 28 / 34 px | 700 | −0.015em | Secciones grandes |
| Título 2 | 22 / 28 px | 600 | −0.01em | Cabeceras de tarjeta / modal |
| Título 3 | 17 / 24 px | 600 | 0 | Subsecciones |
| Cuerpo | 15 / 22 px | 400 | 0 | Texto general, celdas de tabla |
| Cuerpo fuerte | 15 / 22 px | 600 | 0 | Énfasis dentro del cuerpo |
| Caption | 13 / 18 px | 400 | 0 | Labels, ayudas, metadatos |
| Micro | 11 / 14 px | 500 | +0.01em | Badges |
| Micro caps | 11 / 14 px | 500 | +0.06em | Micro compuesto en MAYÚSCULAS: cabecera de tabla, labels de grupo de sidebar, labels de estado |
Micro caps (añadido en v1.1): cuando Micro se compone en mayúsculas, el tracking sube a +0.06em para compensar la caja alta. Los badges (caja mixta) mantienen +0.01em.
4. Espaciado, radios y sombras
4.1 Espaciado — base 4 px
4 · 8 · 12 · 16 · 24 · 32 · 48 · 64
- Padding interno de componentes: 12–16 px.
- Separación entre componentes: 16–24 px.
- Separación entre secciones: 32–48 px.
4.2 Radios
| Token | Valor | Uso |
|---|---|---|
--radius-sm |
8 px | Inputs, botones pequeños, chips |
--radius-md |
12 px | Botones estándar, dropdowns |
--radius-lg |
16 px | Tarjetas, tablas, modales |
--radius-full |
999 px | Toggles, avatares, badges, pills |
4.3 Sombras (elevación)
| Token | Valor | Uso |
|---|---|---|
--shadow-1 |
0 1px 3px rgba(0,0,0,0.06) |
Tarjetas en reposo |
--shadow-2 |
0 4px 16px rgba(0,0,0,0.08) |
Dropdowns, tarjeta en hover |
--shadow-3 |
0 12px 40px rgba(0,0,0,0.14) |
Modales, popovers |
Las sombras son siempre neutras y difusas. Nunca sombras duras ni de color.
4.4 Material translúcido (blur)
Firma visual del sistema. Se aplica a header, sidebar y popovers:
background: var(--bg-material);
backdrop-filter: saturate(180%) blur(20px);
-webkit-backdrop-filter: saturate(180%) blur(20px);
5. Movimiento
| Token | Valor | Uso |
|---|---|---|
--ease |
cubic-bezier(0.25, 0.1, 0.25, 1) |
Curva por defecto |
--ease-spring |
cubic-bezier(0.34, 1.56, 0.64, 1) |
Toggles y elementos que "rebotan" sutilmente |
--dur-fast |
150 ms | Hover, cambios de color |
--dur-med |
250 ms | Aparición de dropdowns, toasts |
--dur-slow |
350 ms | Modales, colapso de sidebar |
Reglas:
- Solo se animan opacity, transform, color, background-color y box-shadow (rendimiento).
- Efecto "pressed" universal: transform: scale(0.97) durante el clic.
- Respetar prefers-reduced-motion: si está activo, las transiciones se reducen a cambios instantáneos de color.
6. Iconos
- Librería recomendada: Lucide (trazo fino, estilo SF Symbols) o SF Symbols si es solo Apple.
- Trazo: 1.5 px. Tamaños: 16 px (inline), 20 px (botones, sidebar), 24 px (header, estados vacíos).
- El icono hereda el color del texto que lo acompaña (
currentColor).
Estados de un icono interactivo (ej. botón de icono)
| Estado | Especificación |
|---|---|
| Default | Color --text-secondary, fondo transparente |
| Hover | Color --text-primary, fondo rgba(0,0,0,0.05), radio --radius-sm, transición 150 ms |
| Pressed | Fondo rgba(0,0,0,0.09) + scale(0.94) |
| Activo/seleccionado | Color --accent, fondo --accent-soft |
| Deshabilitado | Color --text-tertiary, cursor: not-allowed, sin hover |
Área táctil mínima: 40 × 40 px aunque el icono mida 20 px.
7. Botones
Altura estándar 40 px (compacto 32, grande 48). Padding horizontal 20 px. Radio --radius-md. Tipografía Cuerpo fuerte (15/600). Icono opcional a 20 px con gap de 8 px.
7.1 Primario
| Estado | Fondo | Texto | Extra |
|---|---|---|---|
| Default | --accent |
blanco | — |
| Hover | #0077ED |
blanco | transición 150 ms |
| Pressed | #006EDB |
blanco | scale(0.97) |
| Focus (teclado) | --accent |
blanco | anillo: box-shadow: 0 0 0 4px rgba(0,113,227,0.25) |
| Deshabilitado | #D2D2D7 |
blanco | sin eventos |
| Cargando | --accent al 80% |
— | spinner blanco 16 px, texto oculto, ancho fijo |
7.2 Secundario
Fondo #F0F0F2 (gris relleno estilo Apple), texto --text-primary, sin borde.
Hover #E8E8ED · Pressed #E0E0E5 + scale · Deshabilitado: texto --text-tertiary.
7.3 Terciario / Ghost
Fondo transparente, texto --accent. Hover: fondo --accent-soft. Pressed: #DCEBFD (accent-soft más saturado) + scale.
7.4 Destructivo
Igual que el primario pero con la escala --danger. Se reserva para acciones irreversibles y siempre va precedido de confirmación.
8. Formularios
8.1 Campo de texto
- Altura 44 px, radio
--radius-sm, fondo--bg-surface, borde 1 px--border-strong. - Label encima en Caption
--text-secondary, margen inferior 6 px. - Placeholder en
--text-tertiary.
| Estado | Especificación |
|---|---|
| Hover | Borde #B8B8BF |
| Focus | Borde --accent + anillo 0 0 0 4px rgba(0,113,227,0.15), transición 150 ms |
| Error | Borde --danger + anillo rojo suave; mensaje debajo en Caption --danger |
| Deshabilitado | Fondo --bg-surface-2, texto --text-tertiary |
8.2 Toggle (interruptor iOS)
- Pista: 51 × 31 px, radio full. Apagado
#E5E5EA, encendido--success(verde iOS). Decidido en v1.1: verde — el on/off es un estado, no una acción, así que el azul queda reservado a acciones. - Bola: 27 px blanca con
--shadow-1; se desliza en 250 ms con--ease-spring.
8.3 Checkbox y radio
- 20 × 20 px. Sin marcar: borde 1.5 px
--border-strong, fondo blanco. - Marcado: fondo
--accent, check blanco; la marca aparece con scale de 0.5→1 en 150 ms. - Radio: círculo con punto interior de 8 px.
8.4 Select / Dropdown
- Cierre igual que campo de texto, con chevron 16 px a la derecha (rota 180° al abrir).
- Panel: fondo
--bg-surface, radio--radius-md,--shadow-2, aparece conopacity 0→1+translateY(-4px→0)en 250 ms. - Opción hover: fondo
#F0F0F2. Opción seleccionada: check--accenta la derecha. - Estados (como el campo de texto, §8.1): deshabilitado = fondo
--bg-surface-2, texto--text-tertiary; error = borde--danger+ anillo rojo suave.
8.5 Segmented control (muy Apple)
- Contenedor: fondo
#EFEFF1, radio--radius-sm, padding 2 px, altura 36 px. - Segmento activo: píldora blanca con
--shadow-1que se desliza entre posiciones (transform 250 ms). - Texto activo 600 / inactivo
--text-secondary400.
9. Tabla
- Contenedor: fondo
--bg-surface, radio--radius-lg,--shadow-1, sin bordes verticales. - Cabecera: fondo
--bg-surface-2, texto Micro en mayúsculas--text-secondary, altura 44 px. Columna ordenable: flecha 12 px al hacer hover; activa en--accent. - Filas: altura 52 px, separadas por línea 1 px
--border. Sin zebra por defecto (activable en tablas muy densas).
| Estado de fila | Especificación |
|---|---|
| Hover | Fondo #F7F7F9, transición 150 ms |
| Seleccionada | Fondo --accent-soft + checkbox marcado |
| Clicable | cursor: pointer + chevron gris al final que se oscurece en hover |
- Acciones por fila: iconos de 20 px visibles solo en hover (opacity 0→1).
- Paginación al pie: botones ghost + texto Caption "1–20 de 143".
- Estado vacío: icono 24 px
--text-tertiary+ título + botón primario de acción.
10. Sidebar
- Ancho 260 px (colapsada 72 px, transición 350 ms). Fondo
--bg-materialcon blur, borde derecho 1 px--border. - Ítem: altura 40 px, radio
--radius-sm, icono 20 px + texto Cuerpo, padding horizontal 12 px, margen lateral 12 px.
| Estado de ítem | Especificación |
|---|---|
| Default | Texto e icono --text-secondary |
| Hover | Fondo rgba(0,0,0,0.05), texto --text-primary |
| Activo | Fondo --accent-soft, texto e icono --accent, peso 600 |
| Pressed | scale(0.98) |
- Grupos con label Micro en mayúsculas
--text-tertiaryy margen superior 24 px. - Colapsada: solo iconos centrados; el nombre aparece como tooltip.
- Pie: avatar 32 px + nombre + icono de ajustes.
11. Header
- Altura 56 px,
position: sticky; top: 0, fondo--bg-material+ blur, borde inferior 1 px--border. - El borde inferior solo aparece al hacer scroll (opacity 0→1) — en reposo el header se funde con la página.
- Contenido: título de la vista (Título 3) a la izquierda; buscador y acciones (iconos 24 px + botón primario) a la derecha, gap 12 px.
- Buscador: 36 px de alto, fondo
#EFEFF1, radio--radius-full, sin borde; al focus se expande de 200 a 280 px (250 ms) y gana anillo azul.
12. Componentes de apoyo
Tarjeta
Fondo --bg-surface, radio --radius-lg, --shadow-1, padding 24 px. Si es clicable: hover --shadow-2 + translateY(-2px).
Modal
- Overlay
rgba(0,0,0,0.4)con fade 250 ms. - Panel: máx. 480 px, radio
--radius-lg,--shadow-3; entra conscale(0.96→1)+ fade 350 ms. - Título 2 arriba, acciones abajo a la derecha (secundario + primario). Cierre con Escape y clic fuera.
Toast
- Inferior centrado, fondo
#1D1D1F, texto blanco Cuerpo, radio--radius-full,--shadow-3. - Entra con
translateY(16px→0)+ fade; se autodescarta a los 4 s. - Variante éxito/error: icono semántico 16 px delante.
Badge / Chip
- Badge: Micro 500, padding 2×8 px, radio full, fondo suave + texto del semántico.
| Variante | Fondo | Texto |
|---|---|---|
| Éxito | #E8F8EC |
#1F7A34 |
| Aviso | #FFF4E5 |
#A05A00 |
| Error | --danger-soft |
#C0281E |
| Info | --accent-soft |
#0059B4 |
| Neutro | #F0F0F2 |
--text-secondary |
- Chip filtrable: como segmented pero individual; seleccionado = fondo
--accent, texto blanco.
Tooltip
Fondo #1D1D1F, texto blanco Caption, radio --radius-sm, padding 6×10 px. Aparece tras 400 ms de hover con fade 150 ms.
Tabs
Texto Cuerpo --text-secondary; activa: --text-primary 600 + subrayado 2 px --accent que se desliza entre pestañas (250 ms).
Alert inline (añadido en v1.3)
Mensaje persistente dentro de la página (el toast es efímero; el alert se queda hasta que se resuelve o se cierra).
- Contenedor: fondo suave del semántico (paleta de badges), radio
--radius-md, padding 12×16, sin borde. - Contenido: icono semántico 20 px + título opcional (Cuerpo fuerte) + texto Cuerpo, todo en el color de texto del semántico.
- Variantes: info (
--accent-soft/#0059B4), éxito (#E8F8EC/#1F7A34), aviso (#FFF4E5/#A05A00), error (--danger-soft/#C0281E). - Cierre opcional: botón de icono 16 px a la derecha (X), mismo color del texto.
Menú contextual (añadido en v1.3)
Acciones secundarias desde un botón de icono (⋯) o cualquier disparador.
- Panel: como el del select (§8.4) — fondo
--bg-surface, radio--radius-md,--shadow-2, padding 6 px, apariciónopacity 0→1+translateY(-4px→0)en 250 ms. Ancho mínimo 180 px, alineado al borde del disparador. - Ítem: icono 16 px + texto Cuerpo, altura 36 px, radio
--radius-sm, hover#F0F0F2. - Ítem destructivo: texto e icono
--danger; hover--danger-soft. - Separador: línea 1 px
--bordercon margen vertical 6 px. - Cierre: selección, clic fuera o Escape. El disparador marca estado abierto (
aria-expanded).
Breadcrumbs (añadido en v1.3)
- Caption (13 px). Enlaces
--text-secondary, hover--text-primary; página actual--text-primarypeso 500, sin enlace. - Separador: chevron-right 12 px
--text-tertiary, margen 6 px.
Progreso (añadido en v1.3)
- Barra: pista 6 px alto, radio full, fondo
#E5E5EA; relleno--accentradio full. El avance se anima contransform: scaleX()(250 ms--ease), nunca conwidth. - Spinner: círculo de trazo 2 px,
--accent(ocurrentColor), tamaños 16/20/28, rotación 700 ms linear. - Excepción a §1.4: spinner y skeleton pueden moverse "solos" únicamente mientras hay una carga real — la interacción que los dispara es la petición de datos.
Skeleton (añadido en v1.3)
- Bloques
#EFEFF1: línea de texto (alto 12 px, radio 6), avatar (círculo), bloque (radio--radius-sm), tarjeta (radio--radius-lg). - Pulso:
opacity 1→0.55, 1.2 s alterno, solo durante la carga (ver excepción en Progreso). - La silueta imita el layout final para evitar saltos al cargar el contenido.
Tarjeta KPI (añadido en v1.3)
- Tarjeta estándar (§12) con: label Caption
--text-secondary, valor Display (Título 1 en grids de 4+), delta con flecha 16 px + Caption (--successsi mejora,--dangersi empeora,--text-tertiarysi neutro) y comparación en Caption--text-tertiary. - Icono opcional 20 px arriba a la derecha en círculo
--accent-soft/--accentde 36 px.
Lista de actividad (añadido en v1.3)
- Ítem: avatar 32 px (o icono 16 px en círculo 32 px
--accent-soft/--accent) + texto Cuerpo (el actor y la acción clave en Cuerpo fuerte) + tiempo en Caption--text-tertiary. - Separación: línea 1 px
--borderentre ítems, padding vertical 12 px. Sin numeración ni bullets.
13. Accesibilidad (mínimos obligatorios)
- Contraste texto ≥ 4.5:1 sobre su fondo (los tokens ya lo cumplen; verificar combinaciones nuevas).
- Focus visible por teclado en todos los elementos interactivos (anillo azul del §7.1).
- Área táctil mínima 40 × 40 px.
prefers-reduced-motionrespetado (§5).- Iconos sin texto siempre con
aria-label.
14. La página UI Kit (el "template de prueba")
La página interactiva que quieres construir debe mostrar, en este orden:
- Fundamentos: muestras de todos los colores (con su hex al lado), escala tipográfica renderizada, radios y sombras aplicados a cajas de ejemplo, y demos de movimiento (duraciones y curvas reproducibles al clic, ida y vuelta).
- Botones: las 4 variantes × todos los estados. Los estados hover/pressed/focus se prueban en vivo, y además una fila "congelada" que los muestra forzados para poder compararlos.
- Iconos: grid con los 5 estados del §6, clicables para ver la transición real.
- Formularios: cada control en default, focus, error y disabled; el toggle y el segmented funcionando.
- Tabla completa: con orden, hover, selección, acciones en hover, paginación y estado vacío.
- Layout real: una demo con sidebar + header + contenido, donde se pueda colapsar la sidebar y hacer scroll para ver el blur del header.
- Apoyo: tarjeta, modal (botón que lo abre), toast (botón que lo dispara), badges, tooltip, tabs, y desde v1.3: alert inline, menú contextual, breadcrumbs, progreso, skeleton, tarjeta KPI y lista de actividad.
- Plantillas: tarjetas-enlace a las páginas de ejemplo completas de §15 (login, dashboard, ajustes, error).
Cada bloque lleva al pie sus tokens en chips copiables (etiqueta «Tokens de este bloque · clic para copiar»): al pulsar un chip se copia el valor exacto para pegarlo en el CSS del proyecto que se esté desarrollando.
15. Plantillas de página
Patrones de pantalla completa, montados solo con piezas de este documento. En el UI Kit viven bajo /plantillas/* y cada una lleva una píldora flotante «Volver al UI Kit» (material + blur, --shadow-2, inferior derecha).
15.1 Login
- Página centrada (vertical y horizontal) sobre
--bg-page; sin sidebar ni header. - Tarjeta de 400 px máx., radio
--radius-lg,--shadow-1, padding 40 px (32 en móvil). - Dentro, en orden: marca 40 px centrada, Título 2 («Inicia sesión»), Caption secundaria, campos email y contraseña (§8.1), fila con checkbox «Recordarme» + enlace Caption
--accent(«¿Has olvidado la contraseña?»), botón primario grande (48 px) a ancho completo con estado cargando. - Error de credenciales: alert inline de error encima de los campos + campos en estado error. El alert desaparece al corregir.
- Bajo la tarjeta, fuera de ella: Caption
--text-tertiaryde pie (contacto/registro).
15.2 Dashboard
- Layout real (§10 + §11): sidebar + header con buscador y acción primaria.
- Fila 1: grid de 4 tarjetas KPI.
- Fila 2: tarjeta grande (2/3) con gráfica de barras (CSS puro: barras
--accentradio 4 superior, hover--accent-hover+ tooltip; eje en Caption--text-tertiary) con segmented para cambiar el rango; tarjeta (1/3) con lista de actividad. - Fila 3: tabla compacta (§9) de últimos despliegues.
15.3 Ajustes
- Página de formulario dentro del layout real, ancho máx. 720 px: breadcrumbs, Título 1 y descripción.
- Secciones en tarjetas: Título 3 + Caption descriptiva + campos (§8) separados 16-20 px.
- Acciones al pie de cada tarjeta, alineadas a la derecha (secundario + primario con estado cargando).
- Zona peligrosa: tarjeta con título en
--danger, texto explicativo Caption y botón destructivo (§7.4) que siempre pide confirmación en modal.
15.4 Página de error (404/500)
- Centrada sobre
--bg-page: icono 24 px--text-tertiaryen círculo 56 px#EFEFF1, código en Display--text-tertiary, mensaje en Título 2, explicación Cuerpo secundaria y botón primario «Volver al inicio». - El servidor debe servirla como manejador real de 404.
16. Registro de cambios
- v1.3 — 3 jul 2026. Nuevos componentes de apoyo en §12: alert inline, menú contextual, breadcrumbs, progreso (barra + spinner), skeleton, tarjeta KPI y lista de actividad. Nueva §15 «Plantillas de página»: login, dashboard, ajustes y error 404, publicadas en
/plantillas/*. Excepción documentada a §1.4 para spinner/skeleton durante cargas reales. - v1.2 — 3 jul 2026. UI Kit: bloque de Movimiento rediseñado (duraciones reproducibles ida/vuelta, comparativa
--easevs--ease-spring, demo del pressed universal, reglas visibles); chips de token con etiqueta «clic para copiar» (§14); un solo control de sidebar en el header. - v1.1 — 3 jul 2026. UI Kit publicado en https://style.pgrhub.es (Flask, VPS propio). Decisiones fijadas al implementar: toggle encendido en verde
--success; ghost pressed#DCEBFD; paleta completa de badges (tabla en §12); rol «Micro caps» con tracking +0.06em (§3); estados deshabilitado/error del select (§8.4). - v1.0 — julio 2026. Versión inicial.
Cualquier componente nuevo debe definirse aquí antes de implementarse.