@higinio/design-mcp 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/bruma/design-doc.md +225 -33
- package/assets/bruma/framework.css +268 -51
- package/assets/bruma/styleguide.html +676 -168
- package/assets/bruma/tailwind.css +48 -6
- package/assets/bruma/tokens.css +61 -5
- package/assets/bruma/tokens.json +769 -25
- package/assets/celeste/design-doc.md +242 -40
- package/assets/celeste/framework.css +290 -62
- package/assets/celeste/styleguide.html +760 -178
- package/assets/celeste/tailwind.css +48 -6
- package/assets/celeste/tokens.css +67 -6
- package/assets/celeste/tokens.json +778 -26
- package/assets/nocturna/design-doc.md +346 -52
- package/assets/nocturna/framework.css +317 -108
- package/assets/nocturna/styleguide.html +809 -215
- package/assets/nocturna/tailwind.css +46 -3
- package/assets/nocturna/tokens.css +115 -6
- package/assets/nocturna/tokens.json +754 -21
- package/assets/salvia/design-doc.md +224 -31
- package/assets/salvia/framework.css +269 -51
- package/assets/salvia/styleguide.html +674 -168
- package/assets/salvia/tailwind.css +48 -6
- package/assets/salvia/tokens.css +61 -5
- package/assets/salvia/tokens.json +769 -25
- package/dist/server.js +1 -1
- package/dist/snippet.js +26 -17
- package/dist/tokens.js +42 -5
- package/package.json +32 -8
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
- **Casing:** sentence case en headings y botones ("Crear proyecto", no "Crear Proyecto" ni "CREAR PROYECTO"). Overlines/labels en uppercase con tracking `+0.08em`.
|
|
30
30
|
- **Copy de botones:** verbo + objeto, corto: "Guardar cambios", "Ver informe".
|
|
31
31
|
- **Mensajes de estado:** concretos y accionables — el error dice qué pasó **y qué hacer**.
|
|
32
|
-
- **Números y datos:** protagonistas — siempre en JetBrains Mono o `tabular-nums`, grandes en dashboards, con
|
|
32
|
+
- **Números y datos:** protagonistas — siempre en JetBrains Mono o `tabular-nums`, grandes en dashboards, con valor final visible desde la carga.
|
|
33
33
|
- **Fechas y números formateados:** siempre con `Intl.DateTimeFormat` / `Intl.NumberFormat` (`es-MX`), nunca formatos hardcodeados — un "12/07/2026" a mano se rompe al cambiar de locale.
|
|
34
34
|
- **`translate="no"`** en nombres de marca y tokens de código (IDs, comandos, rutas), para que la traducción automática no los corrompa.
|
|
35
35
|
- **Numerales para conteos:** "8 despliegues", no "ocho despliegues" — en un dashboard el dígito se escanea más rápido.
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
| `night-600` | `#2a2f3d` | Superficie de separadores sutiles |
|
|
77
77
|
| `night-500` | `#3d4354` | Bordes por defecto |
|
|
78
78
|
| `night-450` | `#5f6575` | Solo light: texto atenuado (`--text-muted`) — `night-400` caía a 4.27:1 sobre `--surface-3` |
|
|
79
|
-
| `night-400` | `#6b7183` |
|
|
79
|
+
| `night-400` | `#6b7183` | Solo controles deshabilitadoss |
|
|
80
80
|
| `night-300` | `#9aa0b0` | Texto terciario, captions |
|
|
81
81
|
| `night-200` | `#c5c9d4` | Texto secundario |
|
|
82
82
|
| `night-100` | `#e8eaef` | Texto principal |
|
|
@@ -106,7 +106,7 @@ Los componentes **nunca** usan los primitivos de arriba directamente: consumen e
|
|
|
106
106
|
| `--text-primary` | `night-100` | Texto principal |
|
|
107
107
|
| `--text-secondary` | `night-200` | Texto secundario |
|
|
108
108
|
| `--text-muted` | `night-300` | Terciario, captions |
|
|
109
|
-
| `--text-disabled` | `night-400` |
|
|
109
|
+
| `--text-disabled` | `night-400` | Solo controles deshabilitados |
|
|
110
110
|
| `--text-heading` | `night-50` | Headings, máximo énfasis |
|
|
111
111
|
| `--text-on-accent` | `night-950` | Texto sobre CTAs de acento (**oscuro, nunca blanco**) |
|
|
112
112
|
| `--accent-ghost-hover` | `rgba(82,186,237,.08)` | Hover de botones ghost |
|
|
@@ -115,17 +115,22 @@ Los componentes **nunca** usan los primitivos de arriba directamente: consumen e
|
|
|
115
115
|
| `--overlay` | `rgba(1,2,3,.7)` | Overlay de modal |
|
|
116
116
|
| `--success/--warning/--danger/--info` | sus `-400` | Estados semánticos |
|
|
117
117
|
|
|
118
|
-
### 3.6
|
|
118
|
+
### 3.6 Uso del color y jerarquía
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
- **30% — Texto y estructura** (`night-50→300`, bordes, índigo en fondos de sección).
|
|
122
|
-
- **10% — Acento eléctrico y semánticos**: CTAs, links, cifras clave, gráficas. (Excepción: una visualización de datos multiserie usa la paleta categórica validada de la skill `dataviz-marca`, exenta de este techo — son datos, no cromo decorativo.)
|
|
120
|
+
El primitivo de marca expresa identidad; el rol de acción asegura legibilidad. Una acción dominante por contexto de decisión: un formulario, un diálogo o una región independiente pueden tener su propia acción. Evita competir dentro del mismo grupo. La proporción de acento se decide por jerarquía y contenido; 60/30/10 es una orientación visual, no una cuota ni un criterio de conformidad.
|
|
123
121
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
128
|
-
-
|
|
122
|
+
| Rol semántico | Uso |
|
|
123
|
+
|---|---|
|
|
124
|
+
| `--action-bg`, `--action-hover`, `--action-active` | Relleno de acciones sólidas y selección con texto |
|
|
125
|
+
| `--text-on-action` | Texto e iconos sobre los tres fondos de acción; ≥4.5:1 |
|
|
126
|
+
| `--control-border` | Contorno necesario para reconocer campos, checkbox y radio; ≥3:1 |
|
|
127
|
+
| `--focus-color` | Contorno sólido de teclado, distinto del halo decorativo |
|
|
128
|
+
| `--placeholder` | Ayuda legible dentro de campos; nunca sustituye al label |
|
|
129
|
+
| `--selection-bg`, `--selection-text` | Selección nativa de texto, con contraste propio |
|
|
130
|
+
|
|
131
|
+
`--accent` conserva la firma cromática y no garantiza contraste como relleno de texto normal. No lo intercambies con `--action-bg`. Los separadores decorativos usan `--border`; los controles usan `--control-border`.
|
|
132
|
+
|
|
133
|
+
Para datos categóricos consulta `.claude/skills/dataviz-marca/references/paletas-graficas.md`: allí se declara la validación de cada paleta, sus límites y los fallbacks. La identidad de serie también necesita etiqueta, forma o patrón; un cambio de tendencia no significa éxito por defecto.
|
|
129
134
|
|
|
130
135
|
---
|
|
131
136
|
|
|
@@ -135,7 +140,7 @@ Reglas prácticas:
|
|
|
135
140
|
|
|
136
141
|
| Rol | Fuente | Fallback | Uso |
|
|
137
142
|
|---|---|---|---|
|
|
138
|
-
| Display | **Space Grotesk** (500–700) | system-ui, sans-serif |
|
|
143
|
+
| Display | **Space Grotesk** (500–700) | system-ui, sans-serif | Marca y títulos editoriales, cifras hero, navegación, wordmark |
|
|
139
144
|
| Body/UI | **Manrope** (400–700) | system-ui, sans-serif | Párrafos, formularios, tablas, **h4 en adelante** |
|
|
140
145
|
| Mono | **JetBrains Mono** (400–500) | monospace | Datos numéricos, código, IDs |
|
|
141
146
|
|
|
@@ -179,6 +184,14 @@ Carga vía Google Fonts CDN (sin binarios adjuntos — si hay licencias locales,
|
|
|
179
184
|
|
|
180
185
|
---
|
|
181
186
|
|
|
187
|
+
### Roles tipográficos por tarea
|
|
188
|
+
|
|
189
|
+
La etiqueta HTML expresa estructura, no una familia tipográfica. En **Operate** (formularios, datos, ajustes), usa `data-mode="operate"` en la región: la familia de UI lleva h1–h3, con una escala fija en rem de 32/20/18px. `.ui-title` permite aplicarla de forma local. Conserva un solo h1 de página y el orden de encabezados.
|
|
190
|
+
|
|
191
|
+
En **Read**, la familia display puede abrir una página editorial; `.reading-title` y `.display` consumen `--text-display-fluid`, con límites en rem y `text-wrap: balance`. El cuerpo mantiene 65–75ch y tamaños en rem. **Persuade** prioriza una decisión y **Experience** deja protagonismo a la obra: no copies la composición de un dashboard a una landing. Las cifras de tablas usan `tabular-nums`; reserva la mono para código, IDs o mediciones que lo necesiten.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
182
195
|
## 5. Espaciado
|
|
183
196
|
|
|
184
197
|
Escala base 4px — tokens `--space-1…24`: `4 · 8 · 12 · 16 · 20 · 24 · 32 · 40 · 48 · 64 · 80 · 96`
|
|
@@ -196,6 +209,40 @@ Aliases de uso (consumir estos, no números sueltos):
|
|
|
196
209
|
|
|
197
210
|
---
|
|
198
211
|
|
|
212
|
+
### Ritmo entre textos, controles y tarjetas
|
|
213
|
+
|
|
214
|
+
| Relación | Separación | Token |
|
|
215
|
+
|---|---:|---|
|
|
216
|
+
| Etiqueta → control; control → ayuda/error | 6px | `--field-gap` |
|
|
217
|
+
| Título → descripción del mismo grupo | 8px | `--heading-gap` |
|
|
218
|
+
| Párrafos o bloques relacionados | 16px | `--content-gap` |
|
|
219
|
+
| Bloques directos dentro de una tarjeta | 16px | `--card-content-gap` |
|
|
220
|
+
| Campos consecutivos y pie del formulario | 20px | `--form-gap` |
|
|
221
|
+
| Tarjetas consecutivas | 24px | `--card-group-gap` |
|
|
222
|
+
| Secciones independientes | 64px | `--section-gap` |
|
|
223
|
+
|
|
224
|
+
El padding protege el borde; el gap separa contenido. `.card` organiza sus hijos directos con `--card-content-gap`. Para anidar contenido usa `.card__content` o `.stack`; `.text-group` agrupa título y descripción a 8px. `.form-stack` separa campos a 20px; `.cluster` agrupa acciones con 12px y permite envolver. `.stack--cards` consume la separación de tarjetas de esta marca.
|
|
225
|
+
|
|
226
|
+
Un contenedor es dueño de la separación: dentro de stacks y grids se neutralizan los márgenes de sus hijos para no sumar margen y gap. Los `.field` consecutivos también se separan en flujo normal. Evita repartir márgenes manuales entre cada div; aplica el contenedor al grupo. Las alturas de control son mínimas: permiten crecer cuando aumenta el tamaño del texto.
|
|
227
|
+
|
|
228
|
+
```html
|
|
229
|
+
<div class="stack stack--cards">
|
|
230
|
+
<section class="card" data-mode="operate">
|
|
231
|
+
<header class="text-group"><h2>Datos de contacto</h2><p>Usaremos estos datos para responder.</p></header>
|
|
232
|
+
<form class="form-stack">
|
|
233
|
+
<div class="field"><label class="field__label" for="nombre">Nombre</label><input class="input" id="nombre" autocomplete="name"></div>
|
|
234
|
+
<div class="field"><label class="field__label" for="correo">Correo</label><input class="input" id="correo" type="email" autocomplete="email"></div>
|
|
235
|
+
<div class="cluster"><button class="btn btn--primary" type="submit">Guardar</button><button class="btn btn--secondary" type="button">Cancelar</button></div>
|
|
236
|
+
</form>
|
|
237
|
+
</section>
|
|
238
|
+
<section class="card"><h2 class="ui-title">Otra sección</h2><p>El contenedor mantiene su distancia respecto a la tarjeta anterior.</p></section>
|
|
239
|
+
</div>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Verifica la composición con ayuda/error multilínea, textos largos, 320px y texto al 200%. El texto debe envolver y los controles crecer; no reduzcas gaps para hacer caber contenido.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
199
246
|
## 6. Bordes, radios y focus
|
|
200
247
|
|
|
201
248
|
| Token | Valor | Uso |
|
|
@@ -464,7 +511,7 @@ Lista de acciones desplegable anclada a un trigger (acciones de fila, botón "m
|
|
|
464
511
|
- **Cifra:** JetBrains Mono 49px peso 500, line-height 1.05, color `accent-400`, `tabular-nums`, `white-space: nowrap`.
|
|
465
512
|
- **Delta** opcional debajo: mono 14px — `success-400` / `danger-400` / `night-300` (neutral).
|
|
466
513
|
- Gap vertical 6px. Formato numérico con `Intl.NumberFormat` (`es-MX`).
|
|
467
|
-
- **
|
|
514
|
+
- **valor final visible desde la carga.
|
|
468
515
|
|
|
469
516
|
#### Chip de métrica
|
|
470
517
|
|
|
@@ -668,7 +715,7 @@ Antes de animar algo, pregúntate: ¿de dónde vino, qué cambió, a dónde se f
|
|
|
668
715
|
### 11.2 Principios de movimiento
|
|
669
716
|
|
|
670
717
|
1. **Entra rápido, sale más rápido** — Salida ~20% más corta que la entrada.
|
|
671
|
-
2. **
|
|
718
|
+
2. **Propiedades según coste y propósito** — Prefiere `transform` y `opacity` para desplazamiento. Color y sombra pueden comunicar estados; las excepciones de layout son locales, cortas y medidas.
|
|
672
719
|
3. **Distancias cortas** — Entradas de 4–8px.
|
|
673
720
|
4. **Stagger en listas** — 30ms por ítem, máximo 6 ítems.
|
|
674
721
|
5. **Firma de marca:** los elementos con acento entran con fade + glow (opacidad del glow 0→1 en 220ms). Usar solo en el elemento hero/CTA.
|
|
@@ -696,7 +743,7 @@ Antes de animar algo, pregúntate: ¿de dónde vino, qué cambió, a dónde se f
|
|
|
696
743
|
| Toast | entrar | slide-in + fade 250ms |
|
|
697
744
|
| Icon swap (p. ej. copiar→check) | cambio | cross-fade: opacity + scale(0.9→1), 150ms; nunca blur |
|
|
698
745
|
| Página/vista | cambio | fade + translateY(8px→0) 350ms |
|
|
699
|
-
| Cifra/dato clave | montar |
|
|
746
|
+
| Cifra/dato clave | montar | valor final visible desde la carga|
|
|
700
747
|
|
|
701
748
|
### 11.4 Loading
|
|
702
749
|
|
|
@@ -707,26 +754,21 @@ Antes de animar algo, pregúntate: ¿de dónde vino, qué cambió, a dónde se f
|
|
|
707
754
|
|
|
708
755
|
### 11.5 Accesibilidad del movimiento
|
|
709
756
|
|
|
757
|
+
La preferencia reducida cambia los tokens de duración propios a 0ms y detiene spinner y skeleton. Los estados finales siguen visibles; el feedback de color de botones puede durar 80ms. No se acortan con un selector universal las animaciones de otras librerías. No uses eventos de animación como única condición para completar una operación o retirar un elemento.
|
|
758
|
+
|
|
710
759
|
```css
|
|
711
760
|
@media (prefers-reduced-motion: reduce) {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
transition-duration: 0.01ms !important;
|
|
716
|
-
scroll-behavior: auto !important;
|
|
761
|
+
:root {
|
|
762
|
+
--duration-instant: 0ms; --duration-fast: 0ms; --duration-base: 0ms;
|
|
763
|
+
--duration-slow: 0ms; --duration-page: 0ms; --stagger-step: 0ms;
|
|
717
764
|
}
|
|
765
|
+
html { scroll-behavior: auto; }
|
|
766
|
+
.spinner, .skeleton, .skeleton::after { animation: none; }
|
|
767
|
+
.btn, .icon-btn { transform: none; transition: background-color 80ms linear, color 80ms linear; }
|
|
718
768
|
}
|
|
719
769
|
```
|
|
720
770
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
**Gating de hover:** los efectos de hover que mueven o elevan (transform, box-shadow, glow) van dentro de `@media (hover: hover) and (pointer: fine)` — en touch no hay hover real y el tap dispara hovers falsos que se quedan pegados hasta el siguiente toque. Los hover de solo color/fondo pueden quedar fuera: un cambio de color pegado no estorba.
|
|
724
|
-
|
|
725
|
-
```css
|
|
726
|
-
@media (hover: hover) and (pointer: fine) {
|
|
727
|
-
.card--interactive:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }
|
|
728
|
-
}
|
|
729
|
-
```
|
|
771
|
+
Los hover que desplazan o elevan solo se aplican con `(hover: hover) and (pointer: fine)`. Verifica la alternativa reducida con el mismo contenido y flujo, incluidos abrir, cerrar, cargar y confirmar. Los datos llegan con su valor final desde HTML: no hay valor final visible desde la carga.
|
|
730
772
|
|
|
731
773
|
### 11.6 Anti-patrones de motion
|
|
732
774
|
|
|
@@ -760,7 +802,7 @@ Un "motion gap" es UI que aparece o desaparece sin transición y debería tenerl
|
|
|
760
802
|
- Estados de carga y de error.
|
|
761
803
|
- Paneles de settings / inspector.
|
|
762
804
|
|
|
763
|
-
|
|
805
|
+
La ausencia de transición no es un defecto por sí sola. Evalúa si el cambio se entiende y mantiene el foco. En tareas frecuentes, teclado o movimiento reducido, una actualización instantánea puede ser la respuesta correcta.
|
|
764
806
|
|
|
765
807
|
---
|
|
766
808
|
|
|
@@ -783,22 +825,36 @@ Ratios calculados con la fórmula WCAG 2.x (no estimados). El test `mcp/test/con
|
|
|
783
825
|
## 13. Tokens CSS consolidados
|
|
784
826
|
|
|
785
827
|
```css
|
|
828
|
+
/* ============================================================
|
|
829
|
+
Nocturna Eléctrica — Design Tokens v2.0
|
|
830
|
+
Sistema de diseño de Higinio Sosa · dark-first
|
|
831
|
+
Fuente de verdad: DESIGN-nocturna-electrica.md
|
|
832
|
+
Uso: importar ANTES de cualquier estilo propio.
|
|
833
|
+
Los componentes consumen SOLO aliases semánticos, nunca hex.
|
|
834
|
+
============================================================ */
|
|
835
|
+
|
|
836
|
+
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=Manrope:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
|
|
837
|
+
|
|
786
838
|
:root {
|
|
787
|
-
/* == Primitivos: acento ==
|
|
839
|
+
/* == Primitivos: acento (Celeste Eléctrico) ==
|
|
840
|
+
accent-600 sobre blanco da 4.01:1 — vale como UI (≥3) pero NO como texto (<4.5).
|
|
841
|
+
Para texto sobre claro se usa accent-700 (5.95:1) y accent-800 (8.74:1). */
|
|
788
842
|
--accent-100: #d9f0fb; --accent-200: #a8ddf6; --accent-300: #7dccf1;
|
|
789
843
|
--accent-400: #52baed; --accent-500: #2fa3dd; --accent-600: #1f87bb; --accent-700: #186a94;
|
|
844
|
+
--accent-800: #12506f;
|
|
790
845
|
|
|
791
|
-
/* == Primitivos: índigo == */
|
|
846
|
+
/* == Primitivos: índigo (Índigo Profundo) — nunca texto sobre negro == */
|
|
792
847
|
--indigo-300: #7a83c4; --indigo-400: #565fa3; --indigo-500: #353d7c;
|
|
793
848
|
--indigo-600: #2b3264; --indigo-700: #22284f; --indigo-800: #1a1e3b;
|
|
794
849
|
|
|
795
850
|
/* == Primitivos: escala nocturna == */
|
|
796
851
|
--night-950: #010203; --night-900: #0b0d12; --night-800: #14171f;
|
|
797
852
|
--night-700: #1e222d; --night-600: #2a2f3d; --night-500: #3d4354;
|
|
853
|
+
--night-450: #5f6575; /* texto atenuado en light: night-400 caía a 4.27:1 sobre --surface-3 */
|
|
798
854
|
--night-400: #6b7183; --night-300: #9aa0b0; --night-200: #c5c9d4;
|
|
799
855
|
--night-100: #e8eaef; --night-50: #f6f7f9;
|
|
800
856
|
|
|
801
|
-
/* == Primitivos: semánticos == */
|
|
857
|
+
/* == Primitivos: semánticos (calibrados para dark) == */
|
|
802
858
|
--success-400: #4ade80; --success-bg: #0a2617;
|
|
803
859
|
--warning-400: #fbbf24; --warning-bg: #2a2005;
|
|
804
860
|
--danger-400: #f87171; --danger-bg: #2c0f0f;
|
|
@@ -806,13 +862,24 @@ Ratios calculados con la fórmula WCAG 2.x (no estimados). El test `mcp/test/con
|
|
|
806
862
|
|
|
807
863
|
/* == Aliases semánticos (los componentes consumen SOLO esto) == */
|
|
808
864
|
--bg: var(--night-950);
|
|
809
|
-
--surface-1: var(--night-900);
|
|
810
|
-
--
|
|
811
|
-
--
|
|
812
|
-
--
|
|
813
|
-
|
|
865
|
+
--surface-1: var(--night-900);
|
|
866
|
+
--surface-2: var(--night-800);
|
|
867
|
+
--surface-3: var(--night-700);
|
|
868
|
+
--border: var(--night-500);
|
|
869
|
+
/* night-400, no night-600: en dark, oscurecer un borde lo DEBILITA (principio 2:
|
|
870
|
+
la elevación se comunica aclarando). n600 daba 1.46:1 vs los 1.97:1 del borde
|
|
871
|
+
normal — el énfasis se veía más flojo. n400 = 3.99:1 sobre surface-1. */
|
|
872
|
+
--border-strong: var(--night-400);
|
|
873
|
+
--text-primary: var(--night-100);
|
|
874
|
+
--text-secondary: var(--night-200);
|
|
875
|
+
--text-muted: var(--night-300);
|
|
876
|
+
--text-disabled: var(--night-400);
|
|
877
|
+
--text-heading: var(--night-50);
|
|
878
|
+
--text-on-accent: var(--night-950); /* texto de CTA oscuro, nunca blanco */
|
|
814
879
|
--success: var(--success-400); --warning: var(--warning-400);
|
|
815
880
|
--danger: var(--danger-400); --info: var(--info-400);
|
|
881
|
+
--link: var(--accent-400);
|
|
882
|
+
--link-hover: var(--accent-200);
|
|
816
883
|
--accent-ghost-hover: rgba(82,186,237,.08);
|
|
817
884
|
--accent-ghost-active: rgba(82,186,237,.14);
|
|
818
885
|
--accent-selected: rgba(82,186,237,.12);
|
|
@@ -830,7 +897,7 @@ Ratios calculados con la fórmula WCAG 2.x (no estimados). El test `mcp/test/con
|
|
|
830
897
|
--tracking-display: -0.02em; --tracking-overline: 0.08em;
|
|
831
898
|
--measure: 65ch;
|
|
832
899
|
|
|
833
|
-
/* == Espaciado == */
|
|
900
|
+
/* == Espaciado (escala base 4px) == */
|
|
834
901
|
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
|
|
835
902
|
--space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px;
|
|
836
903
|
--space-12: 48px; --space-16: 64px; --space-20: 80px; --space-24: 96px;
|
|
@@ -843,15 +910,15 @@ Ratios calculados con la fórmula WCAG 2.x (no estimados). El test `mcp/test/con
|
|
|
843
910
|
--radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px;
|
|
844
911
|
--radius-xl: 24px; --radius-full: 9999px;
|
|
845
912
|
--border-default: 1px solid var(--night-500);
|
|
846
|
-
--border-emphasis: 1px solid var(--night-400);
|
|
847
|
-
--focus-ring: 2px solid var(--
|
|
913
|
+
--border-emphasis: 1px solid var(--night-400); /* ver --border-strong */
|
|
914
|
+
--focus-ring: 2px solid var(--focus-color);
|
|
848
915
|
--focus-ring-offset: 2px;
|
|
849
916
|
|
|
850
|
-
/* == Elevación == */
|
|
917
|
+
/* == Elevación (superficie + sombra + borde) == */
|
|
851
918
|
--shadow-1: 0 1px 2px rgba(0,0,0,.4);
|
|
852
919
|
--shadow-2: 0 4px 12px rgba(0,0,0,.5);
|
|
853
920
|
--shadow-3: 0 12px 32px rgba(0,0,0,.6);
|
|
854
|
-
--glow-accent: 0 0 0 1px rgba(82,186,237,.35), 0 4px 20px rgba(82,186,237,.18);
|
|
921
|
+
--glow-accent: 0 0 0 1px rgba(82,186,237,.35), 0 4px 20px rgba(82,186,237,.18); /* máx. uno por pantalla */
|
|
855
922
|
--ring: 0 0 0 3px rgba(82,186,237,.2);
|
|
856
923
|
--ring-danger: 0 0 0 3px rgba(248,113,113,.2);
|
|
857
924
|
|
|
@@ -860,10 +927,168 @@ Ratios calculados con la fórmula WCAG 2.x (no estimados). El test `mcp/test/con
|
|
|
860
927
|
--duration-slow: 250ms; --duration-page: 350ms;
|
|
861
928
|
--ease-out: cubic-bezier(0.2, 0, 0, 1);
|
|
862
929
|
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
863
|
-
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
|
930
|
+
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1); /* moverse de A a B en pantalla */
|
|
864
931
|
--ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
|
|
932
|
+
--stagger-step: 30ms;
|
|
865
933
|
|
|
866
934
|
color-scheme: dark;
|
|
935
|
+
|
|
936
|
+
--focus-color: var(--accent-400);
|
|
937
|
+
--border-hover: var(--night-400);
|
|
938
|
+
--outline-hover-bg: var(--surface-2);
|
|
939
|
+
--outline-active-bg: var(--surface-3);
|
|
940
|
+
--text-on-danger: var(--night-950);
|
|
941
|
+
--data-color: var(--accent-400);
|
|
942
|
+
--elevated-border: var(--night-600);
|
|
943
|
+
--card-border: var(--night-600);
|
|
944
|
+
--code-color: var(--accent-300);
|
|
945
|
+
--code-border: var(--night-700);
|
|
946
|
+
--table-header-bg: var(--night-900);
|
|
947
|
+
--row-border: var(--night-800);
|
|
948
|
+
--row-hover: var(--night-700);
|
|
949
|
+
--navbar-bg: rgba(1,2,3,.8);
|
|
950
|
+
--nav-active: var(--accent-400);
|
|
951
|
+
--sidebar-bg: var(--night-900);
|
|
952
|
+
--sidebar-active-bg: var(--indigo-800);
|
|
953
|
+
--sidebar-active-text: var(--night-50);
|
|
954
|
+
--sidebar-active-icon: var(--accent-400);
|
|
955
|
+
--switch-off: var(--night-600);
|
|
956
|
+
--tooltip-bg: var(--night-700);
|
|
957
|
+
--tooltip-border: var(--night-600);
|
|
958
|
+
--tooltip-text: var(--night-100);
|
|
959
|
+
--skeleton-base: var(--night-800);
|
|
960
|
+
--skeleton-sheen: var(--night-700);
|
|
961
|
+
--empty-icon: var(--indigo-400);
|
|
962
|
+
|
|
963
|
+
--action-bg: var(--accent);
|
|
964
|
+
--action-hover: var(--accent-hover);
|
|
965
|
+
--action-active: var(--accent-active);
|
|
966
|
+
--text-on-action: var(--text-on-accent);
|
|
967
|
+
--control-border: var(--border-strong);
|
|
968
|
+
--placeholder: var(--text-muted);
|
|
969
|
+
--selection-bg: var(--action-bg);
|
|
970
|
+
--selection-text: var(--text-on-action);
|
|
971
|
+
--font-ui-heading: var(--font-body);
|
|
972
|
+
--text-ui-title: 2rem;
|
|
973
|
+
--control-height-md: 44px;
|
|
974
|
+
--button-padding-md: 12px 20px;
|
|
975
|
+
--surface: var(--surface-1);
|
|
976
|
+
--surface-alt: var(--surface-2);
|
|
977
|
+
--accent: var(--accent-400);
|
|
978
|
+
--accent-hover: var(--accent-300);
|
|
979
|
+
--accent-active: var(--accent-500);
|
|
980
|
+
--text-display-fluid: clamp(2.5rem, 1.5rem + 3.4vw, 5rem);
|
|
981
|
+
--text-on-primary-solid: var(--link);
|
|
982
|
+
--weight-regular: 400;
|
|
983
|
+
--weight-medium: 500;
|
|
984
|
+
--weight-semibold: 600;
|
|
985
|
+
--weight-bold: 700;
|
|
986
|
+
--leading-base: 1.6;
|
|
987
|
+
--leading-lg: 1.55;
|
|
988
|
+
--gutter: 24px;
|
|
989
|
+
--gutter-mobile: 16px;
|
|
990
|
+
|
|
991
|
+
/* Series categóricas: orden estable; acompañar con etiqueta o forma. */
|
|
992
|
+
--chart-1: #52baed;
|
|
993
|
+
--chart-2: #a0587c;
|
|
994
|
+
--chart-3: #2aa79e;
|
|
995
|
+
--chart-4: #aa5849;
|
|
996
|
+
--chart-5: #67a369;
|
|
997
|
+
--chart-6: #946a1c;
|
|
998
|
+
--chart-7: #877cc3;
|
|
999
|
+
/* Ritmo de contenido y formularios. */
|
|
1000
|
+
--field-gap: 6px;
|
|
1001
|
+
--heading-gap: var(--space-2);
|
|
1002
|
+
--content-gap: var(--space-4);
|
|
1003
|
+
--card-content-gap: var(--space-4);
|
|
1004
|
+
--card-group-gap: var(--space-6);
|
|
1005
|
+
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/* == Modo claro (variante) — alternar data-theme en <html> == */
|
|
1009
|
+
[data-theme="light"] {
|
|
1010
|
+
--bg: #f5f8fb;
|
|
1011
|
+
--surface-1: #ffffff;
|
|
1012
|
+
--surface-2: #ffffff;
|
|
1013
|
+
--surface-3: #eaf1f7;
|
|
1014
|
+
--border: #d8dfe8;
|
|
1015
|
+
/* border-strong NO se redefine en claro: night-400 (:root) cumple 1.4.11 en
|
|
1016
|
+
AMBOS temas (3.26-3.99:1 en dark, 4.27-4.87:1 en light). #b9c3d1 daba
|
|
1017
|
+
1.53-1.78:1, bajo el mínimo de 3:1 para UI. */
|
|
1018
|
+
--text-primary: #14171f;
|
|
1019
|
+
--text-secondary: #3d4354;
|
|
1020
|
+
--text-muted: var(--night-450); /* no night-400: ese caía a 4.27:1 sobre --surface-3 */
|
|
1021
|
+
--text-disabled: #9aa0b0;
|
|
1022
|
+
--text-heading: #14171f;
|
|
1023
|
+
--link: #186a94; /* accent-700 · 5.95:1 sobre blanco — accent-600 solo daba 4.01:1 */
|
|
1024
|
+
--link-hover: #12506f; /* accent-800 · en light el hover OSCURECE (en dark aclara) */
|
|
1025
|
+
--text-on-accent: #010203; /* CTA no cambia entre modos */
|
|
1026
|
+
/* Semánticos de light: son a la vez relleno y TEXTO sobre su propio --*-bg tintado,
|
|
1027
|
+
así que se calibran contra ese fondo, no contra blanco. */
|
|
1028
|
+
--success: #166534;
|
|
1029
|
+
--warning: #854d0e;
|
|
1030
|
+
--danger: #b02c2c;
|
|
1031
|
+
--info: #186a94;
|
|
1032
|
+
--success-bg: #e3f5ea; --warning-bg: #fbf3dd;
|
|
1033
|
+
--danger-bg: #fbe7e7; --info-bg: #e3f2fb;
|
|
1034
|
+
--accent-ghost-hover: rgba(31,135,187,.08);
|
|
1035
|
+
--accent-ghost-active: rgba(31,135,187,.14);
|
|
1036
|
+
--accent-selected: rgba(82,186,237,.12);
|
|
1037
|
+
--overlay: rgba(20,23,31,.45);
|
|
1038
|
+
--ring: 0 0 0 3px rgba(31,135,187,.25);
|
|
1039
|
+
--shadow-1: 0 1px 3px rgba(53,61,124,.08);
|
|
1040
|
+
--shadow-2: 0 4px 10px rgba(53,61,124,.10);
|
|
1041
|
+
--shadow-3: 0 12px 28px rgba(53,61,124,.14);
|
|
1042
|
+
--glow-accent: 0 0 0 1px rgba(82,186,237,.4), 0 4px 16px rgba(82,186,237,.25);
|
|
1043
|
+
color-scheme: light;
|
|
1044
|
+
|
|
1045
|
+
--focus-color: #186a94;
|
|
1046
|
+
--border-hover: #5f6575;
|
|
1047
|
+
--outline-hover-bg: #eaf1f7;
|
|
1048
|
+
--outline-active-bg: #d8dfe8;
|
|
1049
|
+
--text-on-danger: #ffffff;
|
|
1050
|
+
--data-color: #186a94;
|
|
1051
|
+
--elevated-border: #d8dfe8;
|
|
1052
|
+
--card-border: #d8dfe8;
|
|
1053
|
+
--code-color: #186a94;
|
|
1054
|
+
--code-border: #d8dfe8;
|
|
1055
|
+
--table-header-bg: #eaf1f7;
|
|
1056
|
+
--row-border: #eaf1f7;
|
|
1057
|
+
--row-hover: #f5f8fb;
|
|
1058
|
+
--navbar-bg: rgba(255,255,255,.8);
|
|
1059
|
+
--nav-active: #186a94;
|
|
1060
|
+
--sidebar-bg: #ffffff;
|
|
1061
|
+
--sidebar-active-bg: #e3f2fb;
|
|
1062
|
+
--sidebar-active-text: #14171f;
|
|
1063
|
+
--sidebar-active-icon: #1f87bb;
|
|
1064
|
+
--switch-off: var(--control-border);
|
|
1065
|
+
--tooltip-bg: #14171f;
|
|
1066
|
+
--tooltip-border: #14171f;
|
|
1067
|
+
--tooltip-text: #f6f7f9;
|
|
1068
|
+
--skeleton-base: #eaf1f7;
|
|
1069
|
+
--skeleton-sheen: #f5f8fb;
|
|
1070
|
+
--ring-danger: 0 0 0 3px rgba(192,53,53,.2);
|
|
1071
|
+
|
|
1072
|
+
--selection-bg: var(--action-bg);
|
|
1073
|
+
--selection-text: var(--text-on-action);
|
|
1074
|
+
|
|
1075
|
+
/* Series categóricas: orden estable; acompañar con etiqueta o forma. */
|
|
1076
|
+
--chart-1: #186a94;
|
|
1077
|
+
--chart-2: #853f63;
|
|
1078
|
+
--chart-3: #129a92;
|
|
1079
|
+
--chart-4: #8e4031;
|
|
1080
|
+
--chart-5: #5b975e;
|
|
1081
|
+
--chart-6: #8a600a;
|
|
1082
|
+
--chart-7: #857bc1;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
/* == Accesibilidad del movimiento == */
|
|
1086
|
+
|
|
1087
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1088
|
+
:root {
|
|
1089
|
+
--duration-instant: 0ms; --duration-fast: 0ms; --duration-base: 0ms;
|
|
1090
|
+
--duration-slow: 0ms; --duration-page: 0ms; --stagger-step: 0ms;
|
|
1091
|
+
}
|
|
867
1092
|
}
|
|
868
1093
|
```
|
|
869
1094
|
|
|
@@ -890,6 +1115,17 @@ Grid de 12 columnas, gutter 24px (16px móvil). Mobile-first.
|
|
|
890
1115
|
|
|
891
1116
|
---
|
|
892
1117
|
|
|
1118
|
+
### Adaptación de los componentes
|
|
1119
|
+
|
|
1120
|
+
- Reflow a 320 CSS px sin recortar contenido ni ocultar el desbordamiento del documento. Revisa también texto al 200% y zoom al 400%.
|
|
1121
|
+
- Acciones de formularios se apilan cuando no caben; el primario puede ocupar el ancho disponible en móvil. Las etiquetas largas pueden envolver sin quedar cortadas.
|
|
1122
|
+
- La navegación lateral se convierte en disclosure o drawer con estado accesible, cierre con Escape, devolución de foco y contenido cerrado fuera del orden de tabulación. Tabs largas conservan desplazamiento horizontal local.
|
|
1123
|
+
- Una tabla ancha usa `.table-scroll`, con nombre accesible y región enfocables si el scroll necesita teclado; prioriza columnas o una vista de detalle sin retirar datos necesarios.
|
|
1124
|
+
- Calendarios y grupos compactos mantienen objetivos de al menos 24×24px o espaciado equivalente; 44×44px es la preferencia de comodidad táctil, no el mínimo AA universal. El tamaño visible del icono puede ser menor que su zona activa.
|
|
1125
|
+
- Popovers, combobox y calendarios respetan el viewport y se reposicionan cerca de sus bordes. En producción usa top layer, portal o posicionamiento con detección de colisiones para escapar de ancestros con overflow. El framework CSS por sí solo no gestiona colisiones ni foco.
|
|
1126
|
+
|
|
1127
|
+
---
|
|
1128
|
+
|
|
893
1129
|
## 15. Modo claro (variante)
|
|
894
1130
|
|
|
895
1131
|
El sistema es **dark-first**, pero todo producto debe soportar light mode con los mismos tokens semánticos. La energía de la marca se conserva; solo se invierte el escenario.
|
|
@@ -958,7 +1194,7 @@ El glow de acento se mantiene como firma, pero más tenue: `0 0 0 1px rgba(82,18
|
|
|
958
1194
|
- **Toast:** fondo blanco, borde `#d8dfe8`, borde izquierdo semántico.
|
|
959
1195
|
- **Overlay de modal:** `rgba(20,23,31,.45)` + blur 4px.
|
|
960
1196
|
- **Skeleton:** base `#eaf1f7`, shimmer hacia `#f5f8fb`.
|
|
961
|
-
- **
|
|
1197
|
+
- **valor final visible desde la carga.6.
|
|
962
1198
|
|
|
963
1199
|
### 15.5 Contraste en light
|
|
964
1200
|
|
|
@@ -1002,24 +1238,74 @@ Ratios calculados con la fórmula WCAG 2.x, no estimados a ojo. `mcp/test/contra
|
|
|
1002
1238
|
--surface-2: #ffffff;
|
|
1003
1239
|
--surface-3: #eaf1f7;
|
|
1004
1240
|
--border: #d8dfe8;
|
|
1005
|
-
/*
|
|
1241
|
+
/* border-strong NO se redefine en claro: night-400 (:root) cumple 1.4.11 en
|
|
1242
|
+
AMBOS temas (3.26-3.99:1 en dark, 4.27-4.87:1 en light). #b9c3d1 daba
|
|
1243
|
+
1.53-1.78:1, bajo el mínimo de 3:1 para UI. */
|
|
1006
1244
|
--text-primary: #14171f;
|
|
1007
1245
|
--text-secondary: #3d4354;
|
|
1008
|
-
--text-muted:
|
|
1009
|
-
--
|
|
1010
|
-
--
|
|
1011
|
-
--
|
|
1012
|
-
/*
|
|
1246
|
+
--text-muted: var(--night-450); /* no night-400: ese caía a 4.27:1 sobre --surface-3 */
|
|
1247
|
+
--text-disabled: #9aa0b0;
|
|
1248
|
+
--text-heading: #14171f;
|
|
1249
|
+
--link: #186a94; /* accent-700 · 5.95:1 sobre blanco — accent-600 solo daba 4.01:1 */
|
|
1250
|
+
--link-hover: #12506f; /* accent-800 · en light el hover OSCURECE (en dark aclara) */
|
|
1251
|
+
--text-on-accent: #010203; /* CTA no cambia entre modos */
|
|
1252
|
+
/* Semánticos de light: son a la vez relleno y TEXTO sobre su propio --*-bg tintado,
|
|
1253
|
+
así que se calibran contra ese fondo, no contra blanco. */
|
|
1013
1254
|
--success: #166534;
|
|
1014
1255
|
--warning: #854d0e;
|
|
1015
1256
|
--danger: #b02c2c;
|
|
1016
1257
|
--info: #186a94;
|
|
1258
|
+
--success-bg: #e3f5ea; --warning-bg: #fbf3dd;
|
|
1259
|
+
--danger-bg: #fbe7e7; --info-bg: #e3f2fb;
|
|
1260
|
+
--accent-ghost-hover: rgba(31,135,187,.08);
|
|
1261
|
+
--accent-ghost-active: rgba(31,135,187,.14);
|
|
1262
|
+
--accent-selected: rgba(82,186,237,.12);
|
|
1263
|
+
--overlay: rgba(20,23,31,.45);
|
|
1017
1264
|
--ring: 0 0 0 3px rgba(31,135,187,.25);
|
|
1018
1265
|
--shadow-1: 0 1px 3px rgba(53,61,124,.08);
|
|
1019
1266
|
--shadow-2: 0 4px 10px rgba(53,61,124,.10);
|
|
1020
1267
|
--shadow-3: 0 12px 28px rgba(53,61,124,.14);
|
|
1021
1268
|
--glow-accent: 0 0 0 1px rgba(82,186,237,.4), 0 4px 16px rgba(82,186,237,.25);
|
|
1022
1269
|
color-scheme: light;
|
|
1270
|
+
|
|
1271
|
+
--focus-color: #186a94;
|
|
1272
|
+
--border-hover: #5f6575;
|
|
1273
|
+
--outline-hover-bg: #eaf1f7;
|
|
1274
|
+
--outline-active-bg: #d8dfe8;
|
|
1275
|
+
--text-on-danger: #ffffff;
|
|
1276
|
+
--data-color: #186a94;
|
|
1277
|
+
--elevated-border: #d8dfe8;
|
|
1278
|
+
--card-border: #d8dfe8;
|
|
1279
|
+
--code-color: #186a94;
|
|
1280
|
+
--code-border: #d8dfe8;
|
|
1281
|
+
--table-header-bg: #eaf1f7;
|
|
1282
|
+
--row-border: #eaf1f7;
|
|
1283
|
+
--row-hover: #f5f8fb;
|
|
1284
|
+
--navbar-bg: rgba(255,255,255,.8);
|
|
1285
|
+
--nav-active: #186a94;
|
|
1286
|
+
--sidebar-bg: #ffffff;
|
|
1287
|
+
--sidebar-active-bg: #e3f2fb;
|
|
1288
|
+
--sidebar-active-text: #14171f;
|
|
1289
|
+
--sidebar-active-icon: #1f87bb;
|
|
1290
|
+
--switch-off: var(--control-border);
|
|
1291
|
+
--tooltip-bg: #14171f;
|
|
1292
|
+
--tooltip-border: #14171f;
|
|
1293
|
+
--tooltip-text: #f6f7f9;
|
|
1294
|
+
--skeleton-base: #eaf1f7;
|
|
1295
|
+
--skeleton-sheen: #f5f8fb;
|
|
1296
|
+
--ring-danger: 0 0 0 3px rgba(192,53,53,.2);
|
|
1297
|
+
|
|
1298
|
+
--selection-bg: var(--action-bg);
|
|
1299
|
+
--selection-text: var(--text-on-action);
|
|
1300
|
+
|
|
1301
|
+
/* Series categóricas: orden estable; acompañar con etiqueta o forma. */
|
|
1302
|
+
--chart-1: #186a94;
|
|
1303
|
+
--chart-2: #853f63;
|
|
1304
|
+
--chart-3: #129a92;
|
|
1305
|
+
--chart-4: #8e4031;
|
|
1306
|
+
--chart-5: #5b975e;
|
|
1307
|
+
--chart-6: #8a600a;
|
|
1308
|
+
--chart-7: #857bc1;
|
|
1023
1309
|
}
|
|
1024
1310
|
```
|
|
1025
1311
|
|
|
@@ -1045,3 +1331,11 @@ El sistema se distribuye en varios formatos para poder usarlo desde cualquier st
|
|
|
1045
1331
|
2. Los componentes consumen solo aliases semánticos (§3.5) — nunca hex.
|
|
1046
1332
|
3. Para dark/light: alternar `data-theme` en `<html>`; los tokens hacen el resto.
|
|
1047
1333
|
4. En el `<head>`: `<meta name="theme-color" content="#010203">` (el `--bg` nocturno) — sin él, la barra del navegador queda clara sobre la app oscura. Con el tema claro activo, actualizarlo a `#f5f8fb`.
|
|
1334
|
+
|
|
1335
|
+
### Mantenimiento de las distribuciones
|
|
1336
|
+
|
|
1337
|
+
Los contratos se definen en esta especificación y sus valores ejecutables en `dist/nocturna-electrica/tokens.css`. Los ajustes comunes de componentes están en `web/component-contracts.css`; la presentación compartida de las guías, en `web/styleguide.css`. Tras editar, ejecuta `node scripts/build-design-assets.mjs`: regenera el prefijo de tokens del framework, el CSS embebido de las guías y los roles semánticos de Tailwind/DTCG. Los componentes propios del framework se conservan. Luego sincroniza skills, paquete CSS y MCP. Las guías siguen siendo HTML autocontenido, excepto la carga externa de fuentes.
|
|
1338
|
+
|
|
1339
|
+
### Series categóricas
|
|
1340
|
+
|
|
1341
|
+
`--chart-1` a `--chart-7` mantienen su orden y cambian de paso con el tema. La prueba `mcp/test/chart-palettes.test.ts` verifica contraste ≥3:1 contra la superficie y separación entre colores adyacentes en OKLab: ≥15 en visión normal y ≥8 bajo simulaciones Machado de protanopía, deuteranopía y tritanopía. Son umbrales internos, no certificación WCAG ni garantía para todos los pares o personas; usa etiquetas, formas o patrones y tabla equivalente.
|