@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
|
@@ -106,7 +106,7 @@ Los componentes **nunca** usan los primitivos directamente: consumen esta capa.
|
|
|
106
106
|
| `--text-primary` | `neutral-800` | Texto principal |
|
|
107
107
|
| `--text-secondary` | `neutral-600` | Texto secundario |
|
|
108
108
|
| `--text-muted` | `neutral-500` | Terciario, captions |
|
|
109
|
-
| `--text-disabled` | `neutral-400` |
|
|
109
|
+
| `--text-disabled` | `neutral-400` | Solo controles deshabilitados |
|
|
110
110
|
| `--text-on-primary` | `#ffffff` | Texto sobre botón primario |
|
|
111
111
|
| `--text-on-primary-solid` | `primary-700` | Texto de peso normal sobre `primary-100` |
|
|
112
112
|
| `--accent` | `primary-500` | Rellenos de controles, bordes activos, focus |
|
|
@@ -121,26 +121,32 @@ Los componentes **nunca** usan los primitivos directamente: consumen esta capa.
|
|
|
121
121
|
|
|
122
122
|
> ⚠️ **Regla de área del acento:** `--accent` es un color de control, no de superficie. Si una pieza mide más que un botón grande, no va en lavanda sólida: una tarjeta destacada se marca con borde `--border-strong` o con un indicador de 2–3px en `--accent`, nunca con fondo lavanda. El éxito, por su parte, es verde azulado (`--success-500`), lejos del acento (ΔE76 52.6 en claro y 49.2 en oscuro), y siempre lleva ✓.
|
|
123
123
|
|
|
124
|
-
### 3.5
|
|
124
|
+
### 3.5 Uso del color y jerarquía
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
- **30% — Tinta y estructura** (`neutral-600→900`, bordes): texto, iconos, divisores.
|
|
128
|
-
- **10% — Lavanda y semánticos**: botones, links, estados activos, foco, gráficas. **El acento pierde poder si supera el 10%**, y en Bruma además no puede concentrarse en una sola área grande (§1). (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.)
|
|
126
|
+
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.
|
|
129
127
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
-
|
|
128
|
+
| Rol semántico | Uso |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `--action-bg`, `--action-hover`, `--action-active` | Relleno de acciones sólidas y selección con texto |
|
|
131
|
+
| `--text-on-action` | Texto e iconos sobre los tres fondos de acción; ≥4.5:1 |
|
|
132
|
+
| `--control-border` | Contorno necesario para reconocer campos, checkbox y radio; ≥3:1 |
|
|
133
|
+
| `--focus-color` | Contorno sólido de teclado, distinto del halo decorativo |
|
|
134
|
+
| `--placeholder` | Ayuda legible dentro de campos; nunca sustituye al label |
|
|
135
|
+
| `--selection-bg`, `--selection-text` | Selección nativa de texto, con contraste propio |
|
|
136
|
+
|
|
137
|
+
`--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`.
|
|
138
|
+
|
|
139
|
+
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.
|
|
134
140
|
|
|
135
141
|
---
|
|
136
142
|
|
|
137
143
|
## 4. Tipografía
|
|
138
144
|
|
|
139
|
-
### 4.1 Familias
|
|
145
|
+
### 4.1 Familias y funciones
|
|
140
146
|
|
|
141
147
|
| Rol | Fuente | Fallback | Uso |
|
|
142
148
|
|---|---|---|---|
|
|
143
|
-
| Display | **Bricolage Grotesque** (600–700) | system-ui, sans-serif |
|
|
149
|
+
| Display | **Bricolage Grotesque** (600–700) | system-ui, sans-serif | Marca y títulos editoriales, cifras hero, títulos de marketing — nunca UI ni párrafos |
|
|
144
150
|
| Body/UI | **Atkinson Hyperlegible Next** (400–700) | system-ui, sans-serif | Párrafos, botones, formularios, h3–h6 |
|
|
145
151
|
| Mono | **Atkinson Hyperlegible Mono** (400–500) | ui-monospace, monospace | Datos numéricos, código, IDs, cantidades en tablas |
|
|
146
152
|
|
|
@@ -191,6 +197,14 @@ Pesos tokenizados: `--weight-regular 400` · `--weight-medium 500` · `--weight-
|
|
|
191
197
|
|
|
192
198
|
---
|
|
193
199
|
|
|
200
|
+
### Roles tipográficos por tarea
|
|
201
|
+
|
|
202
|
+
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.
|
|
203
|
+
|
|
204
|
+
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.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
194
208
|
## 5. Espaciado
|
|
195
209
|
|
|
196
210
|
Escala base 4px — tokens `--space-1…24` (número = px/4): `4 · 8 · 12 · 16 · 20 · 24 · 32 · 40 · 48 · 64 · 80 · 96`
|
|
@@ -210,6 +224,40 @@ Aliases de uso (consumir estos, no números sueltos):
|
|
|
210
224
|
|
|
211
225
|
---
|
|
212
226
|
|
|
227
|
+
### Ritmo entre textos, controles y tarjetas
|
|
228
|
+
|
|
229
|
+
| Relación | Separación | Token |
|
|
230
|
+
|---|---:|---|
|
|
231
|
+
| Etiqueta → control; control → ayuda/error | 6px | `--field-gap` |
|
|
232
|
+
| Título → descripción del mismo grupo | 8px | `--heading-gap` |
|
|
233
|
+
| Párrafos o bloques relacionados | 16px | `--content-gap` |
|
|
234
|
+
| Bloques directos dentro de una tarjeta | 16px | `--card-content-gap` |
|
|
235
|
+
| Campos consecutivos y pie del formulario | 20px | `--form-gap` |
|
|
236
|
+
| Tarjetas consecutivas | 20px | `--card-group-gap` |
|
|
237
|
+
| Secciones independientes | 48px | `--section-gap` |
|
|
238
|
+
|
|
239
|
+
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.
|
|
240
|
+
|
|
241
|
+
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.
|
|
242
|
+
|
|
243
|
+
```html
|
|
244
|
+
<div class="stack stack--cards">
|
|
245
|
+
<section class="card" data-mode="operate">
|
|
246
|
+
<header class="text-group"><h2>Datos de contacto</h2><p>Usaremos estos datos para responder.</p></header>
|
|
247
|
+
<form class="form-stack">
|
|
248
|
+
<div class="field"><label class="field__label" for="nombre">Nombre</label><input class="input" id="nombre" autocomplete="name"></div>
|
|
249
|
+
<div class="field"><label class="field__label" for="correo">Correo</label><input class="input" id="correo" type="email" autocomplete="email"></div>
|
|
250
|
+
<div class="cluster"><button class="btn btn--primary" type="submit">Guardar</button><button class="btn btn--secondary" type="button">Cancelar</button></div>
|
|
251
|
+
</form>
|
|
252
|
+
</section>
|
|
253
|
+
<section class="card"><h2 class="ui-title">Otra sección</h2><p>El contenedor mantiene su distancia respecto a la tarjeta anterior.</p></section>
|
|
254
|
+
</div>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
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.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
213
261
|
## 6. Bordes, radios y focus
|
|
214
262
|
|
|
215
263
|
| Token | Valor | Uso |
|
|
@@ -296,11 +344,11 @@ No hay logo ni imágenes de marca — el wordmark es puramente tipográfico. Don
|
|
|
296
344
|
|
|
297
345
|
### 10.1 Botones
|
|
298
346
|
|
|
299
|
-
Alturas: 36 (sm) / 44 (md) / 52px (lg). Radius `md`. Peso 600, `text-sm`/`text-base`; lg usa padding `14px 24px` y `text-lg`.
|
|
347
|
+
Alturas: 36 (sm) / 44 (md) / 52px (lg). Radius `md`. Peso 600, `text-sm`/`text-base`; lg usa padding `14px 24px` y `text-lg`. Una acción dominante por contexto de decisión; ghost y outline usan `--link` (AA), no `primary-500`.
|
|
300
348
|
|
|
301
349
|
| Variante | Reposo | Hover | Active | Disabled |
|
|
302
350
|
|---|---|---|---|---|
|
|
303
|
-
| Primario | fondo `--
|
|
351
|
+
| Primario | fondo `--action-bg`, texto `--text-on-action` | `--action-hover` | `--action-active`, sin sombra | fondo `--border`, texto `--text-disabled` |
|
|
304
352
|
| Secundario | fondo `--surface`, borde `--border-strong`, texto `--text-primary` | fondo `--bg` | fondo `--surface-alt` | opacidad 50% |
|
|
305
353
|
| Outline | fondo transparente, borde `--accent`, **texto `--link`** | fondo `--accent-soft`, borde `--accent-hover` | fondo `--accent-soft-strong` | opacidad 50% |
|
|
306
354
|
| Ghost | **texto `--link`** (`primary-600`) | fondo `--accent-soft` | fondo `--accent-soft-strong` | fondo `--border`, texto `--text-disabled` |
|
|
@@ -309,7 +357,7 @@ Alturas: 36 (sm) / 44 (md) / 52px (lg). Radius `md`. Peso 600, `text-sm`/`text-b
|
|
|
309
357
|
- `--text-on-danger` es un token del framework: `neutral-0` en claro (5.01:1 sobre `danger-500`) y la tinta oscura `#16151c` en oscuro (6.99:1), donde el rojo se aclara y el texto claro ya no alcanza AA. Los oscurecidos de hover y active (`color-mix` con negro al 92% y 86%) se mantienen por encima de 4.5:1 en los dos modos.
|
|
310
358
|
- Con icono: gap 8px, icono 20px.
|
|
311
359
|
- Loading: spinner 16px reemplaza el texto (el botón conserva su ancho — fijar `min-width`).
|
|
312
|
-
- El botón
|
|
360
|
+
- El botón puede ocupar el ancho disponible de un formulario móvil. La restricción de lavanda en grandes superficies se aplica a héroes, secciones y banners decorativos; no impide un control cómodo y legible.
|
|
313
361
|
|
|
314
362
|
### 10.2 IconButton
|
|
315
363
|
|
|
@@ -401,7 +449,7 @@ Rango de valor único.
|
|
|
401
449
|
|
|
402
450
|
- Contenedor: borde `--border`, radius `lg`, fondo `--surface`, ítems separados por borde interno.
|
|
403
451
|
- Header: botón full-width, padding `16px 20px`, `text-base` medium `--text-primary`, hover fondo `--bg`; chevron 18px `--text-muted` rota 180° (180ms). `aria-expanded`.
|
|
404
|
-
- Panel: altura animada con `grid-template-rows` 0fr→1fr 240ms ease-out (
|
|
452
|
+
- Panel: altura animada con `grid-template-rows` 0fr→1fr 240ms ease-out (con layout local controlado); contenido `text-sm --text-secondary`, padding `0 20px 16px`.
|
|
405
453
|
- Un panel abierto a la vez salvo `allowMultiple`; `defaultOpen` por ids.
|
|
406
454
|
|
|
407
455
|
### 10.15 Tooltip
|
|
@@ -628,7 +676,7 @@ Campo de fecha con un calendario en popover. Reusa el patrón visual del `Popove
|
|
|
628
676
|
- **`.datepicker`** — contenedor relativo (`.is-open` lo abre). **`.datepicker__input`** con el look de `Input` (borde `--border-strong`, focus `--accent` + `--ring`), `readonly` + `aria-haspopup="dialog"` + `aria-controls` (sin `aria-expanded`, que no es válido en un `input` de texto; el estado abierto lo da `.is-open`); un `.datepicker__icon` de calendario 18px a la derecha (decorativo, `aria-hidden`).
|
|
629
677
|
- **`.datepicker__calendar`** — panel flotante `role="dialog"` con `aria-label`, mismo patrón que `.popover__panel`. Variante `.datepicker--right` ancla a la derecha.
|
|
630
678
|
- **`.calendar`** — dentro del panel: `.calendar__header` (mes/año en `.calendar__title` + botones prev/next con `#i-chevron-left/right`), `.calendar__table` (`role="grid"`) que envuelve la fila de cabeceras `.calendar__weekdays` (`role="row"`, 7 encabezados `role="columnheader"` con `aria-label` completo: "lunes"…) y `.calendar__grid` (`role="rowgroup"`) con una `.calendar__week` (`role="row"`, `display: contents` para no romper la rejilla) por semana, y `.calendar__day` (botón `role="gridcell"`, `aria-label` de la fecha completa vía `Intl.DateTimeFormat` y `aria-selected`). Semana empieza en lunes.
|
|
631
|
-
- **Estados de día:** `.calendar__day--today` (semibold + anillo interior `--border-strong`), `.calendar__day--selected` (fondo `--
|
|
679
|
+
- **Estados de día:** `.calendar__day--today` (semibold + anillo interior `--border-strong`), `.calendar__day--selected` (fondo `--action-bg`, texto `--text-on-action`), `.calendar__day--outside` (días de otro mes, `--text-muted`), `[disabled]` (no seleccionable). El hover usa `--accent-soft`.
|
|
632
680
|
- **Teclado y foco (como Popover):** el input abre por click (o Enter/Espacio/↓); al abrir, el foco entra al calendario (día enfocado). Dentro de la rejilla las **flechas** mueven el foco entre días (roving `tabindex`, cambiando de mes al cruzar el borde), Home/End saltan a los extremos de la semana, PageUp/PageDown cambian de mes, Enter/Espacio selecciona; **Esc** cierra y devuelve el foco al input. La fecha se formatea con `Intl` (`es-MX`), nunca a mano.
|
|
633
681
|
- **Motion:** el panel aparece con fade + `scale(0.96→1)`, `--duration-base` `--ease-out`, bajo el techo `--duration-page`. Solo `transform`/`opacity`.
|
|
634
682
|
|
|
@@ -700,7 +748,7 @@ Las duraciones son cortas y precisas: el movimiento confirma y se aparta, y esa
|
|
|
700
748
|
### 11.2 Principios de movimiento
|
|
701
749
|
|
|
702
750
|
1. **Entra rápido, sale más rápido** — La salida siempre es ~20% más corta que la entrada.
|
|
703
|
-
2. **
|
|
751
|
+
2. **Propiedades según coste y propósito** — Prefiere `transform` y `opacity` para desplazamiento y aparición. Color y sombra pueden acompañar un estado. Width de Progress y `grid-template-rows` del Accordion recalculan layout: mantenlos locales, cortos y medidos; no son animaciones gratis.
|
|
704
752
|
3. **Distancias cortas** — Desplazamientos de entrada de 4–8px; nada "vuela" por la pantalla.
|
|
705
753
|
4. **Jerarquía temporal** — En listas, stagger de `--stagger-step` (30ms) por ítem (máximo 6 ítems con stagger).
|
|
706
754
|
5. **La animación explica** — Todo movimiento responde a: ¿de dónde vino, qué cambió, a dónde se fue?
|
|
@@ -740,27 +788,21 @@ Las duraciones son cortas y precisas: el movimiento confirma y se aparta, y esa
|
|
|
740
788
|
|
|
741
789
|
### 11.5 Accesibilidad del movimiento
|
|
742
790
|
|
|
791
|
+
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.
|
|
792
|
+
|
|
743
793
|
```css
|
|
744
794
|
@media (prefers-reduced-motion: reduce) {
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
transition-duration: 0.01ms !important;
|
|
749
|
-
scroll-behavior: auto !important;
|
|
795
|
+
:root {
|
|
796
|
+
--duration-instant: 0ms; --duration-fast: 0ms; --duration-base: 0ms;
|
|
797
|
+
--duration-slow: 0ms; --duration-page: 0ms; --stagger-step: 0ms;
|
|
750
798
|
}
|
|
799
|
+
html { scroll-behavior: auto; }
|
|
800
|
+
.spinner, .skeleton, .skeleton::after { animation: none; }
|
|
801
|
+
.btn, .icon-btn { transform: none; transition: background-color 80ms linear, color 80ms linear; }
|
|
751
802
|
}
|
|
752
803
|
```
|
|
753
804
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
**Gating de hover:** los efectos de hover que mueven o elevan (transform, box-shadow) 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. La sombra del botón primario va dentro; el borde de la tarjeta interactiva también, aunque solo cambie de color, para que un tap no la deje marcada como si siguiera bajo el cursor.
|
|
757
|
-
|
|
758
|
-
```css
|
|
759
|
-
@media (hover: hover) and (pointer: fine) {
|
|
760
|
-
.btn--primary:hover:not(:disabled) { box-shadow: var(--shadow-sm); }
|
|
761
|
-
.card--interactive:hover { border-color: var(--border-strong); }
|
|
762
|
-
}
|
|
763
|
-
```
|
|
805
|
+
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.
|
|
764
806
|
|
|
765
807
|
### 11.6 Anti-patrones de motion
|
|
766
808
|
|
|
@@ -794,7 +836,7 @@ Un "motion gap" es UI que aparece o desaparece sin transición y debería tenerl
|
|
|
794
836
|
- Estados de carga y de error.
|
|
795
837
|
- Paneles de settings / inspector.
|
|
796
838
|
|
|
797
|
-
|
|
839
|
+
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.
|
|
798
840
|
|
|
799
841
|
---
|
|
800
842
|
|
|
@@ -827,6 +869,16 @@ Ratios calculados con la fórmula WCAG 2.x (no estimados). El test `mcp/test/con
|
|
|
827
869
|
## 13. Tokens CSS consolidados
|
|
828
870
|
|
|
829
871
|
```css
|
|
872
|
+
/* ============================================================
|
|
873
|
+
Bruma Lavanda — Design Tokens v1.0
|
|
874
|
+
Sistema de diseño de Higinio Sosa · light-first
|
|
875
|
+
Fuente de verdad: DESIGN-bruma-lavanda.md
|
|
876
|
+
Uso: importar ANTES de cualquier estilo propio.
|
|
877
|
+
Los componentes consumen SOLO aliases semánticos, nunca hex.
|
|
878
|
+
============================================================ */
|
|
879
|
+
|
|
880
|
+
@import url("https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:wght@600;700&family=Atkinson+Hyperlegible+Next:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Atkinson+Hyperlegible+Mono:wght@400;500&display=swap");
|
|
881
|
+
|
|
830
882
|
:root {
|
|
831
883
|
/* == Primitivos: primario (Lavanda) ==
|
|
832
884
|
Lavanda apagada, nunca violeta saturado. El acento no rellena áreas grandes:
|
|
@@ -918,6 +970,107 @@ Ratios calculados con la fórmula WCAG 2.x (no estimados). El test `mcp/test/con
|
|
|
918
970
|
--stagger-step: 30ms;
|
|
919
971
|
|
|
920
972
|
color-scheme: light;
|
|
973
|
+
|
|
974
|
+
--overlay: rgba(31, 30, 40, .5);
|
|
975
|
+
--tooltip-bg: var(--neutral-900);
|
|
976
|
+
--tooltip-text: var(--neutral-0);
|
|
977
|
+
--focus-color: var(--accent);
|
|
978
|
+
--text-on-danger: var(--neutral-0);
|
|
979
|
+
--border-hover: var(--neutral-500);
|
|
980
|
+
--ring-danger: 0 0 0 3px rgba(178,76,85,.22);
|
|
981
|
+
|
|
982
|
+
--action-bg: var(--accent);
|
|
983
|
+
--action-hover: var(--accent-hover);
|
|
984
|
+
--action-active: var(--accent-active);
|
|
985
|
+
--text-on-action: var(--text-on-primary);
|
|
986
|
+
--control-border: var(--border-strong);
|
|
987
|
+
--placeholder: var(--text-muted);
|
|
988
|
+
--selection-bg: var(--action-bg);
|
|
989
|
+
--selection-text: var(--text-on-action);
|
|
990
|
+
--font-ui-heading: var(--font-body);
|
|
991
|
+
--text-ui-title: 2rem;
|
|
992
|
+
--touch-target: 44px;
|
|
993
|
+
--text-display-fluid: clamp(2.5rem, 1.8rem + 2.2vw, 4.25rem);
|
|
994
|
+
|
|
995
|
+
/* Series categóricas: orden estable; acompañar con etiqueta o forma. */
|
|
996
|
+
--chart-1: #857bc1;
|
|
997
|
+
--chart-2: #8a600a;
|
|
998
|
+
--chart-3: #4a8cc1;
|
|
999
|
+
--chart-4: #853f63;
|
|
1000
|
+
--chart-5: #129a92;
|
|
1001
|
+
--chart-6: #8e4031;
|
|
1002
|
+
--chart-7: #5b975e;
|
|
1003
|
+
/* Ritmo de contenido y formularios. */
|
|
1004
|
+
--field-gap: 6px;
|
|
1005
|
+
--heading-gap: var(--space-2);
|
|
1006
|
+
--content-gap: var(--space-4);
|
|
1007
|
+
--card-content-gap: var(--space-4);
|
|
1008
|
+
--card-group-gap: var(--space-5);
|
|
1009
|
+
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/* == Modo oscuro (variante) — alternar data-theme en <html> ==
|
|
1013
|
+
Sin sombras en las capas: se separan por superficie y borde, y solo
|
|
1014
|
+
los overlays (lg/xl) conservan una sombra tenue. */
|
|
1015
|
+
[data-theme="dark"] {
|
|
1016
|
+
--bg: #16151c;
|
|
1017
|
+
--surface: #1f1e27;
|
|
1018
|
+
--surface-alt: #27262f;
|
|
1019
|
+
--border: #2f2d3a;
|
|
1020
|
+
--border-strong: #747189;
|
|
1021
|
+
--text-primary: #e7e6ef;
|
|
1022
|
+
--text-secondary: #c9c7d6;
|
|
1023
|
+
--text-muted: #aaa8bb;
|
|
1024
|
+
--text-disabled: #7b7990;
|
|
1025
|
+
--accent: #b0acdc;
|
|
1026
|
+
--accent-hover: #c4c1e6;
|
|
1027
|
+
--accent-active: #9d98cf;
|
|
1028
|
+
--accent-soft: #2b2940;
|
|
1029
|
+
--accent-soft-strong: #36334f;
|
|
1030
|
+
--text-on-primary: #16151c;
|
|
1031
|
+
--text-on-primary-solid: #c4c1e6;
|
|
1032
|
+
--link: #c4c1e6;
|
|
1033
|
+
--success-500: #6cc1ad; --success-100: #13261f; --success-text: #8bd1c0;
|
|
1034
|
+
--warning-500: #d6a752; --warning-100: #29220f; --warning-text: #e4c07f;
|
|
1035
|
+
--danger-500: #e08890; --danger-100: #2c171a; --danger-text: #eba4ab;
|
|
1036
|
+
--info-500: #8daecb; --info-100: #172129; --info-text: #a8c3da;
|
|
1037
|
+
--ring: 0 0 0 3px rgba(176,172,220,.3);
|
|
1038
|
+
--ring-color: rgba(176,172,220,.3);
|
|
1039
|
+
--shadow-xs: none;
|
|
1040
|
+
--shadow-sm: none;
|
|
1041
|
+
--shadow-md: none;
|
|
1042
|
+
--shadow-lg: 0 8px 20px rgba(8,8,12,.28);
|
|
1043
|
+
--shadow-xl: 0 16px 32px rgba(8,8,12,.32);
|
|
1044
|
+
color-scheme: dark;
|
|
1045
|
+
|
|
1046
|
+
--overlay: rgba(0, 0, 0, .6);
|
|
1047
|
+
--tooltip-bg: #e7e6ef;
|
|
1048
|
+
--tooltip-text: #1f1e28;
|
|
1049
|
+
--focus-color: var(--accent);
|
|
1050
|
+
--text-on-danger: #16151c;
|
|
1051
|
+
--border-hover: #aaa8bb;
|
|
1052
|
+
--ring-danger: 0 0 0 3px rgba(224,136,144,.25);
|
|
1053
|
+
|
|
1054
|
+
--selection-bg: var(--action-bg);
|
|
1055
|
+
--selection-text: var(--text-on-action);
|
|
1056
|
+
|
|
1057
|
+
/* Series categóricas: orden estable; acompañar con etiqueta o forma. */
|
|
1058
|
+
--chart-1: #877cc3;
|
|
1059
|
+
--chart-2: #946a1c;
|
|
1060
|
+
--chart-3: #5798ce;
|
|
1061
|
+
--chart-4: #a0587c;
|
|
1062
|
+
--chart-5: #2aa79e;
|
|
1063
|
+
--chart-6: #aa5849;
|
|
1064
|
+
--chart-7: #67a369;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/* == Accesibilidad del movimiento == */
|
|
1068
|
+
|
|
1069
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1070
|
+
:root {
|
|
1071
|
+
--duration-instant: 0ms; --duration-fast: 0ms; --duration-base: 0ms;
|
|
1072
|
+
--duration-slow: 0ms; --duration-page: 0ms; --stagger-step: 0ms;
|
|
1073
|
+
}
|
|
921
1074
|
}
|
|
922
1075
|
```
|
|
923
1076
|
|
|
@@ -944,6 +1097,17 @@ Grid de 12 columnas, gutter 24px (16px móvil). Mobile-first. Navbar fija de 64p
|
|
|
944
1097
|
|
|
945
1098
|
---
|
|
946
1099
|
|
|
1100
|
+
### Adaptación de los componentes
|
|
1101
|
+
|
|
1102
|
+
- Reflow a 320 CSS px sin recortar contenido ni ocultar el desbordamiento del documento. Revisa también texto al 200% y zoom al 400%.
|
|
1103
|
+
- 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.
|
|
1104
|
+
- 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.
|
|
1105
|
+
- 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.
|
|
1106
|
+
- 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.
|
|
1107
|
+
- 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.
|
|
1108
|
+
|
|
1109
|
+
---
|
|
1110
|
+
|
|
947
1111
|
## 15. Modo oscuro (variante)
|
|
948
1112
|
|
|
949
1113
|
El sistema es **light-first**, pero todo producto debe soportar dark mode con los mismos tokens semánticos. La marca no cambia: cambia el escenario — de la niebla de la mañana a la penumbra de la noche, igual de ordenada.
|
|
@@ -1053,6 +1217,26 @@ Ratios calculados, no estimados (mismo test que §12).
|
|
|
1053
1217
|
--shadow-lg: 0 8px 20px rgba(8,8,12,.28);
|
|
1054
1218
|
--shadow-xl: 0 16px 32px rgba(8,8,12,.32);
|
|
1055
1219
|
color-scheme: dark;
|
|
1220
|
+
|
|
1221
|
+
--overlay: rgba(0, 0, 0, .6);
|
|
1222
|
+
--tooltip-bg: #e7e6ef;
|
|
1223
|
+
--tooltip-text: #1f1e28;
|
|
1224
|
+
--focus-color: var(--accent);
|
|
1225
|
+
--text-on-danger: #16151c;
|
|
1226
|
+
--border-hover: #aaa8bb;
|
|
1227
|
+
--ring-danger: 0 0 0 3px rgba(224,136,144,.25);
|
|
1228
|
+
|
|
1229
|
+
--selection-bg: var(--action-bg);
|
|
1230
|
+
--selection-text: var(--text-on-action);
|
|
1231
|
+
|
|
1232
|
+
/* Series categóricas: orden estable; acompañar con etiqueta o forma. */
|
|
1233
|
+
--chart-1: #877cc3;
|
|
1234
|
+
--chart-2: #946a1c;
|
|
1235
|
+
--chart-3: #5798ce;
|
|
1236
|
+
--chart-4: #a0587c;
|
|
1237
|
+
--chart-5: #2aa79e;
|
|
1238
|
+
--chart-6: #aa5849;
|
|
1239
|
+
--chart-7: #67a369;
|
|
1056
1240
|
}
|
|
1057
1241
|
```
|
|
1058
1242
|
|
|
@@ -1081,3 +1265,11 @@ El sistema se distribuye en varios formatos para poder usarlo desde cualquier st
|
|
|
1081
1265
|
3. Los componentes consumen solo aliases semánticos (§3.4) — nunca hex.
|
|
1082
1266
|
4. Para light/dark: alternar `data-theme` en `<html>`; los tokens hacen el resto.
|
|
1083
1267
|
5. En el `<head>`: `<meta name="theme-color" content="#f2f1f6">` (el `--bg` claro, niebla); con el tema oscuro activo, actualizarlo a `#16151c` para que la barra del navegador acompañe al fondo.
|
|
1268
|
+
|
|
1269
|
+
### Mantenimiento de las distribuciones
|
|
1270
|
+
|
|
1271
|
+
Los contratos se definen en esta especificación y sus valores ejecutables en `dist/bruma-lavanda/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.
|
|
1272
|
+
|
|
1273
|
+
### Series categóricas
|
|
1274
|
+
|
|
1275
|
+
`--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.
|