@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.
@@ -15,29 +15,36 @@
15
15
  })();
16
16
  </script>
17
17
  <style>
18
- /* ==========================================================================
19
- CELESTE CLÁSICA — Framework CSS v2.0 (embebido)
20
- Idéntico a dist/celeste-clasica/celeste-clasica.css
21
- ========================================================================== */
18
+ /* ============================================================
19
+ Celeste Clásica — Design Tokens v2.0
20
+ Sistema de diseño de Higinio Sosa · light-first
21
+ Fuente de verdad: DESIGN-celeste-clasica.md
22
+ Uso: importar ANTES de cualquier estilo propio.
23
+ Los componentes consumen SOLO aliases semánticos, nunca hex.
24
+ ============================================================ */
22
25
 
23
26
  @import url("https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,600;0,9..144,700;1,9..144,600&family=Public+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&family=IBM+Plex+Mono:wght@400;500&display=swap");
24
27
 
25
28
  :root {
29
+ /* == Primitivos: primario (Azul Acero) == */
26
30
  --primary-50: #f2f6fa; --primary-100: #dfe9f2; --primary-200: #c3d5e6;
27
31
  --primary-300: #a0c0d4; --primary-400: #87a8c7; --primary-500: #7192ba;
28
32
  --primary-600: #5d7ba3; --primary-700: #4d6588; --primary-800: #40536e;
29
33
  --primary-900: #31343e;
30
34
 
35
+ /* == Primitivos: neutrales (Gris Azulado) == */
31
36
  --neutral-0: #ffffff; --neutral-50: #f7f8fa; --neutral-100: #eef0f3;
32
37
  --neutral-200: #dcdfe5; --neutral-300: #b8bdc7; --neutral-400: #8a8f9c;
33
38
  --neutral-500: #666b78; --neutral-600: #4d5160; --neutral-700: #3d414e;
34
39
  --neutral-800: #31343e; --neutral-900: #22242b;
35
40
 
41
+ /* == Primitivos: semánticos (ramp de 3: sólido / fondo / texto AA) == */
36
42
  --success-500: #3d9970; --success-100: #e2f3ec; --success-text: #2b6e50;
37
43
  --warning-500: #c9922e; --warning-100: #faf1de; --warning-text: #8a651c;
38
44
  --danger-500: #c04d4d; --danger-100: #f9e7e7; --danger-text: #8f3232;
39
45
  --info-500: #7192ba; --info-100: #dfe9f2; --info-text: #4d6588;
40
46
 
47
+ /* == Aliases semánticos (los componentes consumen SOLO esto) == */
41
48
  --bg: var(--neutral-50);
42
49
  --surface: var(--neutral-0);
43
50
  --surface-alt: var(--neutral-100);
@@ -54,11 +61,9 @@
54
61
  --accent-active: var(--primary-700);
55
62
  --accent-soft: var(--primary-50);
56
63
  --accent-soft-strong: var(--primary-100);
57
- --link: var(--primary-700);
58
- --overlay: rgba(49, 52, 62, .5);
59
- --tooltip-bg: var(--neutral-900);
60
- --tooltip-text: #ffffff;
64
+ --link: var(--primary-700); /* AA ~6:1 — texto de links y ghost; primary-500 solo para UI */
61
65
 
66
+ /* == Tipografía == */
62
67
  --font-display: "Fraunces", Georgia, serif;
63
68
  --font-body: "Public Sans", system-ui, -apple-system, sans-serif;
64
69
  --font-mono: "IBM Plex Mono", ui-monospace, monospace;
@@ -72,6 +77,7 @@
72
77
  --weight-regular: 400; --weight-medium: 500; --weight-semibold: 600; --weight-bold: 700;
73
78
  --measure: 65ch;
74
79
 
80
+ /* == Espaciado (escala base 4px) == */
75
81
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
76
82
  --space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px;
77
83
  --space-12: 48px; --space-16: 64px; --space-20: 80px; --space-24: 96px;
@@ -81,6 +87,7 @@
81
87
  --control-height-sm: 36px; --control-height-md: 44px; --control-height-lg: 52px;
82
88
  --gutter: 24px; --gutter-mobile: 16px;
83
89
 
90
+ /* == Radios, bordes y sombras (teñidas de tinta, nunca negro puro) == */
84
91
  --radius-sm: 6px; --radius-md: 10px; --radius-lg: 14px;
85
92
  --radius-xl: 20px; --radius-full: 9999px;
86
93
  --border-width: 1px;
@@ -90,20 +97,60 @@
90
97
  --shadow-lg: 0 12px 24px rgba(49,52,62,.12), 0 4px 8px rgba(49,52,62,.06);
91
98
  --shadow-xl: 0 24px 48px rgba(49,52,62,.16);
92
99
 
100
+ /* == Focus == */
93
101
  --ring: 0 0 0 3px rgba(113,146,186,.25);
94
102
  --ring-color: rgba(113,146,186,.25);
95
- --ring-danger: 0 0 0 3px rgba(192,77,77,.22);
96
103
 
104
+ /* == Motion == */
97
105
  --duration-instant: 100ms; --duration-fast: 150ms; --duration-base: 200ms;
98
106
  --duration-slow: 250ms; --duration-page: 320ms;
99
107
  --ease-out: cubic-bezier(0.2, 0, 0, 1);
100
108
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
101
109
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1); /* moverse de A a B en pantalla */
102
110
  --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
111
+ --stagger-step: 30ms;
103
112
 
104
113
  color-scheme: light;
105
- }
106
114
 
115
+ --overlay: rgba(49, 52, 62, .5);
116
+ --tooltip-bg: var(--neutral-900);
117
+ --tooltip-text: #ffffff;
118
+ --ring-danger: 0 0 0 3px rgba(192,77,77,.22);
119
+
120
+ --action-bg: var(--primary-700);
121
+ --action-hover: var(--primary-800);
122
+ --action-active: var(--primary-900);
123
+ --text-on-action: var(--text-on-primary);
124
+ --control-border: var(--neutral-400);
125
+ --placeholder: var(--text-muted);
126
+ --selection-bg: var(--action-bg);
127
+ --selection-text: var(--text-on-action);
128
+ --font-ui-heading: var(--font-body);
129
+ --text-ui-title: 2rem;
130
+ --touch-target: 44px;
131
+ --focus-color: var(--accent);
132
+ --text-display-fluid: clamp(2.75rem, 1.7rem + 3vw, 4.75rem);
133
+ --border-hover: var(--neutral-500);
134
+ --text-on-danger: #ffffff;
135
+
136
+ /* Series categóricas: orden estable; acompañar con etiqueta o forma. */
137
+ --chart-1: #4a8cc1;
138
+ --chart-2: #853f63;
139
+ --chart-3: #129a92;
140
+ --chart-4: #8e4031;
141
+ --chart-5: #5b975e;
142
+ --chart-6: #8a600a;
143
+ --chart-7: #857bc1;
144
+ /* Ritmo de contenido y formularios. */
145
+ --field-gap: 6px;
146
+ --heading-gap: var(--space-2);
147
+ --content-gap: var(--space-4);
148
+ --card-content-gap: var(--space-4);
149
+ --card-group-gap: var(--space-6);
150
+
151
+ }
152
+
153
+ /* == Modo oscuro (variante) — alternar data-theme en <html> == */
107
154
  [data-theme="dark"] {
108
155
  --bg: #16181e;
109
156
  --surface: #1d2028;
@@ -120,28 +167,58 @@
120
167
  --accent-soft: rgba(113,146,186,.12);
121
168
  --accent-soft-strong: rgba(113,146,186,.18);
122
169
  --text-on-primary: #16181e;
123
- --text-on-primary-solid: #a0c0d4;
124
170
  --link: #a0c0d4;
125
- --overlay: rgba(0, 0, 0, .6);
126
- --tooltip-bg: #e6e9ee;
127
- --tooltip-text: #31343e;
128
171
  --success-500: #5cbf93; --success-100: #12291f; --success-text: #7fd4ae;
129
172
  --warning-500: #e0ad4d; --warning-100: #2b2210; --warning-text: #ecc57e;
130
173
  --danger-500: #e07777; --danger-100: #2e1515; --danger-text: #eb9e9e;
131
174
  --info-500: #87a8c7; --info-100: #1a2430; --info-text: #a0c0d4;
132
175
  --ring: 0 0 0 3px rgba(160,192,212,.3);
133
- --ring-danger: 0 0 0 3px rgba(224,119,119,.25);
176
+ --ring-color: rgba(160,192,212,.3);
134
177
  --shadow-sm: 0 1px 2px rgba(0,0,0,.35);
135
178
  --shadow-md: 0 4px 12px rgba(0,0,0,.45);
136
179
  --shadow-lg: 0 12px 32px rgba(0,0,0,.55);
137
180
  color-scheme: dark;
181
+
182
+ --text-on-primary-solid: #a0c0d4;
183
+ --overlay: rgba(0, 0, 0, .6);
184
+ --tooltip-bg: #e6e9ee;
185
+ --tooltip-text: #31343e;
186
+ --ring-danger: 0 0 0 3px rgba(224,119,119,.25);
187
+
188
+ --selection-bg: var(--action-bg);
189
+ --selection-text: var(--text-on-action);
190
+ --action-bg: var(--accent);
191
+ --action-hover: var(--accent-hover);
192
+ --action-active: var(--accent-active);
193
+ --control-border: var(--text-muted);
194
+ --border-hover: var(--text-secondary);
195
+ --text-on-danger: #16181e;
196
+ --focus-color: var(--accent);
197
+
198
+ /* Series categóricas: orden estable; acompañar con etiqueta o forma. */
199
+ --chart-1: #5798ce;
200
+ --chart-2: #a0587c;
201
+ --chart-3: #2aa79e;
202
+ --chart-4: #aa5849;
203
+ --chart-5: #67a369;
204
+ --chart-6: #946a1c;
205
+ --chart-7: #877cc3;
206
+ }
207
+
208
+ /* == Accesibilidad del movimiento == */
209
+
210
+ @media (prefers-reduced-motion: reduce) {
211
+ :root {
212
+ --duration-instant: 0ms; --duration-fast: 0ms; --duration-base: 0ms;
213
+ --duration-slow: 0ms; --duration-page: 0ms; --stagger-step: 0ms;
214
+ }
138
215
  }
139
216
 
140
217
  *, *::before, *::after { box-sizing: border-box; }
141
- html, body { overflow-x: clip; }
142
218
 
219
+ /* Focus ring global de teclado — especificidad cero vía :where() */
143
220
  :where(a, button, [role="button"], input, select, textarea, summary, [tabindex]):focus-visible {
144
- outline: 2px solid var(--primary-500);
221
+ outline: 2px solid var(--focus-color);
145
222
  outline-offset: 2px;
146
223
  border-radius: 2px;
147
224
  }
@@ -178,18 +255,14 @@ html, body { overflow-x: clip; }
178
255
  .celeste-reset h6 { font-size: var(--text-base); line-height: var(--leading-base); }
179
256
  .celeste-reset p { max-width: var(--measure); margin: 0 0 1em; }
180
257
  .celeste-reset table { font-variant-numeric: tabular-nums; }
181
- .celeste-reset ::placeholder { color: var(--text-disabled); }
258
+ .celeste-reset ::placeholder { color: var(--placeholder); }
182
259
  .celeste-reset ::selection { background: rgba(113,146,186,.25); }
183
260
 
184
- @media (prefers-reduced-motion: reduce) {
185
- *, *::before, *::after {
186
- animation-duration: 0.01ms !important;
187
- animation-iteration-count: 1 !important;
188
- transition-duration: 0.01ms !important;
189
- scroll-behavior: auto !important;
190
- }
191
- }
192
261
 
262
+
263
+ /* --------------------------------------------------------------------------
264
+ 3. LAYOUT — contenedor, grid 12 col (§14)
265
+ -------------------------------------------------------------------------- */
193
266
  .container { width: 100%; margin-inline: auto; padding-inline: var(--gutter-mobile); }
194
267
  @media (min-width: 640px) { .container { padding-inline: var(--space-4); } }
195
268
  @media (min-width: 768px) { .container { max-width: 720px; } }
@@ -211,6 +284,9 @@ html, body { overflow-x: clip; }
211
284
  .col-lg-6{grid-column:span 6}.col-lg-8{grid-column:span 8}.col-lg-12{grid-column:span 12}
212
285
  }
213
286
 
287
+ /* --------------------------------------------------------------------------
288
+ 4. BOTONES (§10.1) · ICON BUTTON (§10.2) · SPINNER (§10.3)
289
+ -------------------------------------------------------------------------- */
214
290
  .btn {
215
291
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
216
292
  height: var(--control-height-md); padding: var(--button-padding-md);
@@ -227,15 +303,15 @@ html, body { overflow-x: clip; }
227
303
  .btn:disabled { cursor: not-allowed; }
228
304
  .btn svg { width: 20px; height: 20px; flex: none; }
229
305
 
230
- /* Gating de hover (§11.5): los hover que mueven/elevan van dentro de
231
- @media (hover: hover) and (pointer: fine) — en touch el tap deja el hover pegado.
232
- Los hover de solo color/fondo quedan fuera. */
233
- .btn--primary { background: var(--accent); color: var(--text-on-primary); }
234
- .btn--primary:hover:not(:disabled) { background: var(--accent-hover); }
306
+ /* Gating de hover (§11.5): los hover que mueven/elevan (transform, box-shadow) van
307
+ dentro de @media (hover: hover) and (pointer: fine) — en touch el tap dispara
308
+ hovers falsos que se quedan pegados. Los hover de solo color/fondo quedan fuera. */
309
+ .btn--primary { background: var(--action-bg); color: var(--text-on-action); }
310
+ .btn--primary:hover:not(:disabled) { background: var(--action-hover); }
235
311
  @media (hover: hover) and (pointer: fine) {
236
312
  .btn--primary:hover:not(:disabled) { box-shadow: var(--shadow-sm); }
237
313
  }
238
- .btn--primary:active:not(:disabled) { background: var(--accent-active); box-shadow: none; }
314
+ .btn--primary:active:not(:disabled) { background: var(--action-active); box-shadow: none; }
239
315
  .btn--primary:disabled { background: var(--border); color: var(--text-disabled); box-shadow: none; }
240
316
 
241
317
  .btn--secondary { background: var(--surface); border-color: var(--border-strong); color: var(--text-primary); }
@@ -253,7 +329,7 @@ html, body { overflow-x: clip; }
253
329
  .btn--ghost:active:not(:disabled) { background: var(--accent-soft-strong); }
254
330
  .btn--ghost:disabled { background: var(--border); color: var(--text-disabled); }
255
331
 
256
- .btn--danger { background: var(--danger-500); color: #fff; }
332
+ .btn--danger { background: var(--danger-500); color: var(--text-on-danger); }
257
333
  .btn--danger:hover:not(:disabled) { background: color-mix(in srgb, var(--danger-500) 92%, #000); }
258
334
  .btn--danger:active:not(:disabled) { background: color-mix(in srgb, var(--danger-500) 86%, #000); }
259
335
  .btn--danger:disabled { opacity: .5; }
@@ -261,9 +337,10 @@ html, body { overflow-x: clip; }
261
337
  .btn--sm { height: var(--control-height-sm); padding: var(--button-padding-sm); font-size: var(--text-sm); }
262
338
  .btn--lg { height: var(--control-height-lg); padding: 14px 24px; font-size: var(--text-lg); }
263
339
 
340
+ /* IconButton — requiere aria-label */
264
341
  .icon-btn {
265
342
  display: inline-grid; place-items: center;
266
- width: var(--control-height-md); height: var(--control-height-md); padding: 0;
343
+ width: 40px; height: 40px; padding: 0;
267
344
  border: var(--border-width) solid transparent; border-radius: var(--radius-md);
268
345
  background: transparent; color: var(--text-secondary); cursor: pointer;
269
346
  transition: background-color var(--duration-fast) var(--ease-out),
@@ -273,7 +350,7 @@ html, body { overflow-x: clip; }
273
350
  .icon-btn:active:not(:disabled) { transform: scale(.98); }
274
351
  .icon-btn:disabled { opacity: .5; cursor: not-allowed; }
275
352
  .icon-btn svg { width: 18px; height: 18px; }
276
- .icon-btn--sm { width: var(--control-height-sm); height: var(--control-height-sm); } .icon-btn--sm svg { width: 16px; height: 16px; }
353
+ .icon-btn--sm { width: 32px; height: 32px; } .icon-btn--sm svg { width: 16px; height: 16px; }
277
354
  .icon-btn--lg { width: 48px; height: 48px; } .icon-btn--lg svg { width: 20px; height: 20px; }
278
355
  .icon-btn--ghost:hover:not(:disabled) { background: var(--surface-alt); color: var(--text-primary); }
279
356
  .icon-btn--primary { background: var(--accent); color: var(--text-on-primary); }
@@ -281,15 +358,19 @@ html, body { overflow-x: clip; }
281
358
  .icon-btn--secondary { background: var(--surface); border-color: var(--border-strong); }
282
359
  .icon-btn--secondary:hover:not(:disabled) { background: var(--bg); }
283
360
 
361
+ /* Spinner */
284
362
  .spinner { width: 16px; height: 16px; animation: cc-spin .8s linear infinite; color: var(--accent); }
285
363
  .spinner circle { opacity: .25; }
286
364
  .spinner path { opacity: 1; }
287
365
  @keyframes cc-spin { to { transform: rotate(360deg); } }
288
366
 
367
+ /* --------------------------------------------------------------------------
368
+ 5. FORMULARIOS — field, input, textarea, select (§10.4–10.6)
369
+ -------------------------------------------------------------------------- */
289
370
  .field { display: flex; flex-direction: column; gap: 6px; }
290
371
  .field__label { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-secondary); }
291
372
  .field__help { font-size: var(--text-sm); color: var(--text-muted); }
292
- .field__error { font-size: var(--text-sm); color: var(--danger-500); display: inline-flex; align-items: center; gap: 6px; }
373
+ .field__error { font-size: var(--text-sm); color: var(--danger-text); display: inline-flex; align-items: center; gap: 6px; }
293
374
  .field__error svg { width: 14px; height: 14px; flex: none; }
294
375
  /* Campo obligatorio (§10.4): asterisco decorativo; el input lleva required/aria-required */
295
376
  .field--required .field__label::after { content: " *"; color: var(--danger-500); }
@@ -297,14 +378,14 @@ html, body { overflow-x: clip; }
297
378
  .input, .textarea, .select {
298
379
  width: 100%; font-family: var(--font-body); font-size: var(--text-base);
299
380
  color: var(--text-primary); background: var(--surface);
300
- border: var(--border-width) solid var(--border-strong); border-radius: var(--radius-sm);
381
+ border: var(--border-width) solid var(--control-border); border-radius: var(--radius-sm);
301
382
  transition: border-color var(--duration-fast) var(--ease-out),
302
383
  box-shadow var(--duration-fast) var(--ease-out);
303
384
  }
304
385
  .input, .select { height: var(--control-height-md); padding: 0 14px; }
305
386
  .input:hover:not(:disabled):not(:focus),
306
387
  .textarea:hover:not(:disabled):not(:focus),
307
- .select:hover:not(:disabled):not(:focus) { border-color: var(--text-disabled); }
388
+ .select:hover:not(:disabled):not(:focus) { border-color: var(--border-hover); }
308
389
  .input:focus, .textarea:focus, .select:focus {
309
390
  outline: none; border-color: var(--accent); box-shadow: var(--ring);
310
391
  }
@@ -335,6 +416,9 @@ html, body { overflow-x: clip; }
335
416
  transition: transform var(--duration-base) var(--ease-out);
336
417
  }
337
418
 
419
+ /* --------------------------------------------------------------------------
420
+ 6. SEGMENTED CONTROL (§10.7) · SLIDER (§10.8)
421
+ -------------------------------------------------------------------------- */
338
422
  .segmented {
339
423
  display: inline-flex; align-items: stretch;
340
424
  background: var(--surface-alt); border-radius: var(--radius-md); padding: 3px;
@@ -355,7 +439,7 @@ html, body { overflow-x: clip; }
355
439
  background: var(--surface); color: var(--text-primary);
356
440
  font-weight: var(--weight-semibold); box-shadow: var(--shadow-xs);
357
441
  }
358
- .segmented input:focus-visible + label { outline: 2px solid var(--primary-500); outline-offset: 2px; }
442
+ .segmented input:focus-visible + label { outline: 2px solid var(--focus-color); outline-offset: 2px; }
359
443
 
360
444
  .slider-row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 10px; }
361
445
  .slider-row .slider-label { font-size: var(--text-sm); color: var(--text-secondary); }
@@ -380,6 +464,9 @@ html, body { overflow-x: clip; }
380
464
  }
381
465
  .slider:active::-moz-range-thumb { transform: scale(1.15); }
382
466
 
467
+ /* --------------------------------------------------------------------------
468
+ 7. SELECCIÓN — checkbox, radio, switch (§10.9–10.10)
469
+ -------------------------------------------------------------------------- */
383
470
  .checkbox, .radio {
384
471
  display: inline-flex; align-items: center; gap: 10px;
385
472
  font-size: var(--text-base); color: var(--text-primary); cursor: pointer; position: relative;
@@ -389,7 +476,7 @@ html, body { overflow-x: clip; }
389
476
  }
390
477
  .checkbox__box {
391
478
  width: 20px; height: 20px; flex: none; display: grid; place-items: center;
392
- background: var(--surface); border: 2px solid var(--border-strong); border-radius: 4px;
479
+ background: var(--surface); border: 2px solid var(--control-border); border-radius: 4px;
393
480
  transition: background-color var(--duration-fast) var(--ease-out),
394
481
  border-color var(--duration-fast) var(--ease-out);
395
482
  }
@@ -399,7 +486,7 @@ html, body { overflow-x: clip; }
399
486
  stroke-dasharray: 20; stroke-dashoffset: 20;
400
487
  transition: stroke-dashoffset var(--duration-base) var(--ease-spring);
401
488
  }
402
- .checkbox:hover .checkbox__box { border-color: var(--primary-400); }
489
+ .checkbox:hover .checkbox__box { border-color: var(--focus-color); }
403
490
  .checkbox input:checked ~ .checkbox__box { background: var(--accent); border-color: var(--accent); }
404
491
  .checkbox input:checked ~ .checkbox__box svg { stroke-dashoffset: 0; }
405
492
  .checkbox input:focus-visible ~ .checkbox__box { box-shadow: var(--ring); }
@@ -416,7 +503,7 @@ html, body { overflow-x: clip; }
416
503
 
417
504
  .radio__dot {
418
505
  width: 20px; height: 20px; flex: none; display: grid; place-items: center;
419
- background: var(--surface); border: 2px solid var(--border-strong); border-radius: var(--radius-full);
506
+ background: var(--surface); border: 2px solid var(--control-border); border-radius: var(--radius-full);
420
507
  transition: background-color var(--duration-fast) var(--ease-out),
421
508
  border-color var(--duration-fast) var(--ease-out);
422
509
  }
@@ -425,7 +512,7 @@ html, body { overflow-x: clip; }
425
512
  background: var(--text-on-primary); transform: scale(0);
426
513
  transition: transform var(--duration-base) var(--ease-spring);
427
514
  }
428
- .radio:hover .radio__dot { border-color: var(--primary-400); }
515
+ .radio:hover .radio__dot { border-color: var(--focus-color); }
429
516
  .radio input:checked ~ .radio__dot { background: var(--accent); border-color: var(--accent); }
430
517
  .radio input:checked ~ .radio__dot::after { transform: scale(1); }
431
518
  .radio input:focus-visible ~ .radio__dot { box-shadow: var(--ring); }
@@ -447,6 +534,9 @@ html, body { overflow-x: clip; }
447
534
  .switch input:focus-visible ~ .switch__track { box-shadow: var(--ring); }
448
535
  .switch input:disabled ~ * { opacity: .5; cursor: not-allowed; }
449
536
 
537
+ /* --------------------------------------------------------------------------
538
+ 8. SUPERFICIES — card, badge, tag, avatar, divider, accordion (§10.11–10.14)
539
+ -------------------------------------------------------------------------- */
450
540
  .card {
451
541
  background: var(--surface); border: var(--border-width) solid var(--border);
452
542
  border-radius: var(--radius-lg); padding: var(--card-padding);
@@ -572,6 +662,10 @@ html, body { overflow-x: clip; }
572
662
  }
573
663
  .accordion__item.is-open .accordion__content { opacity: 1; }
574
664
 
665
+ /* --------------------------------------------------------------------------
666
+ 9. FEEDBACK — tooltip, alert, toast, progress, skeleton, empty state
667
+ (§10.15–10.18, §10.25)
668
+ -------------------------------------------------------------------------- */
575
669
  [data-tooltip] { position: relative; }
576
670
  [data-tooltip]::after {
577
671
  content: attr(data-tooltip);
@@ -611,11 +705,11 @@ html, body { overflow-x: clip; }
611
705
  .alert__body { margin: 0; }
612
706
  .alert__close {
613
707
  margin-left: auto; flex: none; display: grid; place-items: center;
614
- width: 36px; height: 36px; border: 0; border-radius: var(--radius-sm);
708
+ width: 24px; height: 24px; border: 0; border-radius: var(--radius-sm);
615
709
  background: transparent; color: inherit; cursor: pointer; opacity: .7;
616
710
  }
617
711
  .alert__close:hover { opacity: 1; }
618
- .alert__close svg { width: 18px; height: 18px; }
712
+ .alert__close svg { width: 16px; height: 16px; }
619
713
  .alert--info { background: var(--info-100); color: var(--info-text); }
620
714
  .alert--info > svg { color: var(--info-500); }
621
715
  .alert--success { background: var(--success-100); color: var(--success-text); }
@@ -707,6 +801,9 @@ html, body { overflow-x: clip; }
707
801
  .empty-state__title { font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--text-primary); margin: 0; }
708
802
  .empty-state__desc { font-size: var(--text-sm); color: var(--text-muted); max-width: 40ch; margin: 0; }
709
803
 
804
+ /* --------------------------------------------------------------------------
805
+ 10. OVERLAYS — modal, menu (§10.19–10.20)
806
+ -------------------------------------------------------------------------- */
710
807
  .modal {
711
808
  position: fixed; inset: 0; z-index: 100;
712
809
  display: grid; place-items: center; padding: var(--space-4);
@@ -745,10 +842,14 @@ html, body { overflow-x: clip; }
745
842
  background: var(--surface); border: var(--border-width) solid var(--border);
746
843
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
747
844
  opacity: 0; transform: translateY(-4px); pointer-events: none;
748
- transition: opacity 160ms var(--ease-out), transform 160ms var(--ease-out);
845
+ transition: opacity var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-out);
846
+
847
+ visibility: hidden;
848
+
849
+ display: none;
749
850
  }
750
851
  .menu--right { left: auto; right: 0; }
751
- .menu.is-open { opacity: 1; transform: none; pointer-events: auto; }
852
+ .menu.is-open { opacity: 1; transform: none; pointer-events: auto; visibility: visible; display: block; }
752
853
  .menu__item {
753
854
  display: flex; align-items: center; gap: 10px; width: 100%;
754
855
  padding: 9px 12px; border: 0; border-radius: var(--radius-sm);
@@ -758,10 +859,13 @@ html, body { overflow-x: clip; }
758
859
  }
759
860
  .menu__item:hover { background: var(--bg); }
760
861
  .menu__item svg { width: 16px; height: 16px; color: var(--text-muted); flex: none; }
761
- .menu__item--danger, .menu__item--danger svg { color: var(--danger-500); }
862
+ .menu__item--danger, .menu__item--danger svg { color: var(--danger-text); }
762
863
  .menu__item--danger:hover { background: var(--danger-100); }
763
864
  .menu__sep { height: var(--border-width); background: var(--border); margin: 6px 4px; }
764
865
 
866
+ /* --------------------------------------------------------------------------
867
+ 11. DATOS — tabla, stat, pagination (§10.21–10.23)
868
+ -------------------------------------------------------------------------- */
765
869
  .table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
766
870
  .table thead th {
767
871
  height: 40px; padding: 0 16px; text-align: left;
@@ -847,7 +951,7 @@ button.metric-chip {
847
951
  }
848
952
  button.metric-chip:hover { background: var(--accent-soft); border-color: var(--accent); }
849
953
  button.metric-chip:active { background: var(--accent-soft-strong); transform: scale(.98); }
850
- button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
954
+ button.metric-chip:focus-visible { outline: 2px solid var(--focus-color); outline-offset: 2px; }
851
955
 
852
956
  .pagination { display: flex; align-items: center; gap: 4px; list-style: none; padding: 0; margin: 0; }
853
957
  .pagination__btn {
@@ -866,6 +970,9 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
866
970
  .pagination__btn svg { width: 16px; height: 16px; }
867
971
  .pagination__ellipsis { color: var(--text-disabled); padding: 0 4px; user-select: none; }
868
972
 
973
+ /* --------------------------------------------------------------------------
974
+ 12. NAVEGACIÓN — navbar, sidebar, tabs, breadcrumbs (§10.24)
975
+ -------------------------------------------------------------------------- */
869
976
  .navbar {
870
977
  display: flex; align-items: center; gap: var(--space-8);
871
978
  height: 64px; padding: 0 var(--space-6);
@@ -984,6 +1091,9 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
984
1091
  .breadcrumbs__sep { user-select: none; }
985
1092
  .breadcrumbs__current { color: var(--text-primary); }
986
1093
 
1094
+ /* --------------------------------------------------------------------------
1095
+ 13. TIPOGRÁFICOS — link, code
1096
+ -------------------------------------------------------------------------- */
987
1097
  .link {
988
1098
  color: var(--link); text-decoration: none;
989
1099
  background-image: linear-gradient(currentColor, currentColor);
@@ -1000,17 +1110,21 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1000
1110
  border-radius: var(--radius-sm); padding: 1px 6px;
1001
1111
  }
1002
1112
 
1113
+ /* --------------------------------------------------------------------------
1114
+ 13b. COMBOBOX · BÚSQUEDA · DRAWER · POPOVER · BUTTONGROUP (§10.28–10.31)
1115
+ -------------------------------------------------------------------------- */
1116
+
1003
1117
  /* Combobox / Autocomplete (§10.28) */
1004
1118
  .combobox { position: relative; }
1005
1119
  .combobox__input {
1006
1120
  width: 100%; height: var(--control-height-md); padding: 0 14px;
1007
1121
  font-family: var(--font-body); font-size: var(--text-base);
1008
1122
  color: var(--text-primary); background: var(--surface);
1009
- border: var(--border-width) solid var(--border-strong); border-radius: var(--radius-sm);
1123
+ border: var(--border-width) solid var(--control-border); border-radius: var(--radius-sm);
1010
1124
  transition: border-color var(--duration-fast) var(--ease-out),
1011
1125
  box-shadow var(--duration-fast) var(--ease-out);
1012
1126
  }
1013
- .combobox__input:hover:not(:disabled):not(:focus) { border-color: var(--text-disabled); }
1127
+ .combobox__input:hover:not(:disabled):not(:focus) { border-color: var(--border-hover); }
1014
1128
  .combobox__input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
1015
1129
  .combobox__input:disabled { background: var(--surface-alt); color: var(--text-disabled); cursor: not-allowed; }
1016
1130
  .combobox__list {
@@ -1048,12 +1162,12 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1048
1162
  width: 100%; height: var(--control-height-md); padding: 0 40px;
1049
1163
  font-family: var(--font-body); font-size: var(--text-base);
1050
1164
  color: var(--text-primary); background: var(--surface);
1051
- border: var(--border-width) solid var(--border-strong); border-radius: var(--radius-sm);
1165
+ border: var(--border-width) solid var(--control-border); border-radius: var(--radius-sm);
1052
1166
  transition: border-color var(--duration-fast) var(--ease-out),
1053
1167
  box-shadow var(--duration-fast) var(--ease-out);
1054
1168
  }
1055
1169
  .search__input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
1056
- .search__input:hover:not(:focus) { border-color: var(--text-disabled); }
1170
+ .search__input:hover:not(:focus) { border-color: var(--border-hover); }
1057
1171
  .search__input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
1058
1172
  .search__clear {
1059
1173
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
@@ -1116,8 +1230,12 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1116
1230
  transform-origin: top left; opacity: 0; transform: scale(.96); pointer-events: none;
1117
1231
  transition: opacity var(--duration-base) var(--ease-out),
1118
1232
  transform var(--duration-base) var(--ease-out);
1233
+
1234
+ visibility: hidden;
1235
+
1236
+ display: none;
1119
1237
  }
1120
- .popover.is-open .popover__panel { opacity: 1; transform: none; pointer-events: auto; }
1238
+ .popover.is-open .popover__panel { opacity: 1; transform: none; pointer-events: auto; visibility: visible; display: block; }
1121
1239
  .popover--right .popover__panel { left: auto; right: 0; transform-origin: top right; }
1122
1240
 
1123
1241
  /* ButtonGroup (§10.31) */
@@ -1132,17 +1250,21 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1132
1250
  .btn-group .btn:not(:first-child) { margin-left: calc(var(--border-width) * -1); }
1133
1251
  .btn-group .btn:hover, .btn-group .btn:focus-visible { z-index: 1; }
1134
1252
 
1253
+ /* --------------------------------------------------------------------------
1254
+ 13c. DATEPICKER · FILEUPLOAD · STEPPER · KBD (§10.32–10.35)
1255
+ -------------------------------------------------------------------------- */
1256
+
1135
1257
  /* DatePicker (§10.32) */
1136
1258
  .datepicker { position: relative; display: inline-block; }
1137
1259
  .datepicker__input {
1138
1260
  width: 100%; height: var(--control-height-md); padding: 0 40px 0 14px;
1139
1261
  font-family: var(--font-body); font-size: var(--text-base);
1140
1262
  color: var(--text-primary); background: var(--surface);
1141
- border: var(--border-width) solid var(--border-strong); border-radius: var(--radius-sm);
1263
+ border: var(--border-width) solid var(--control-border); border-radius: var(--radius-sm);
1142
1264
  transition: border-color var(--duration-fast) var(--ease-out),
1143
1265
  box-shadow var(--duration-fast) var(--ease-out);
1144
1266
  }
1145
- .datepicker__input:hover:not(:disabled):not(:focus) { border-color: var(--text-disabled); }
1267
+ .datepicker__input:hover:not(:disabled):not(:focus) { border-color: var(--border-hover); }
1146
1268
  .datepicker__input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
1147
1269
  .datepicker__input:disabled { background: var(--surface-alt); color: var(--text-disabled); cursor: not-allowed; }
1148
1270
  .datepicker__icon {
@@ -1157,8 +1279,12 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1157
1279
  transform-origin: top left; opacity: 0; transform: scale(.96); pointer-events: none;
1158
1280
  transition: opacity var(--duration-base) var(--ease-out),
1159
1281
  transform var(--duration-base) var(--ease-out);
1282
+
1283
+ visibility: hidden;
1284
+
1285
+ display: none;
1160
1286
  }
1161
- .datepicker.is-open .datepicker__calendar { opacity: 1; transform: none; pointer-events: auto; }
1287
+ .datepicker.is-open .datepicker__calendar { opacity: 1; transform: none; pointer-events: auto; visibility: visible; display: block; }
1162
1288
  .datepicker--right .datepicker__calendar { left: auto; right: 0; transform-origin: top right; }
1163
1289
 
1164
1290
  .calendar { width: 15.75rem; }
@@ -1293,6 +1419,9 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1293
1419
  }
1294
1420
  .kbd-combo { display: inline-flex; align-items: center; gap: 4px; color: var(--text-muted); font-size: var(--text-xs); }
1295
1421
 
1422
+ /* --------------------------------------------------------------------------
1423
+ 14. UTILIDADES MÍNIMAS
1424
+ -------------------------------------------------------------------------- */
1296
1425
  .u-visually-hidden {
1297
1426
  position: absolute; width: 1px; height: 1px; margin: -1px;
1298
1427
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
@@ -1301,6 +1430,172 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1301
1430
  .u-muted { color: var(--text-muted); }
1302
1431
  .u-measure { max-width: var(--measure); }
1303
1432
 
1433
+ /* CONTRATOS COMPARTIDOS GENERADOS */
1434
+ /* Contratos comunes de interacción; la identidad y los valores viven en tokens.css. */
1435
+ .grid { grid-template-columns: repeat(12, minmax(0, 1fr)); }
1436
+ .grid > *, .field, .card { min-inline-size: 0; }
1437
+ .stack, .card__content, .form-stack, .text-group { display: flex; flex-direction: column; align-items: stretch; }
1438
+ .stack, .card__content { gap: var(--content-gap); }
1439
+ .stack--tight, .text-group { gap: var(--heading-gap); }
1440
+ .stack--cards { gap: var(--card-group-gap); }
1441
+ .form-stack { gap: var(--form-gap); }
1442
+ .cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
1443
+ .card { display: flex; flex-direction: column; gap: var(--card-content-gap); }
1444
+ .field { gap: var(--field-gap); }
1445
+ .field__label, .field__help, .field__error, .field > :is(label, p, span, div) { margin-block: 0; }
1446
+ :where(.field + .field, .field + .btn, .field + .cluster) { margin-block-start: var(--form-gap); }
1447
+ :where(.card + .card) { margin-block-start: var(--card-group-gap); }
1448
+ .stack > *, .card__content > *, .form-stack > *, .text-group > *, .grid > .card,
1449
+ .card > :is(h1, h2, h3, h4, h5, h6, p), .text-group > :is(h1, h2, h3, h4, h5, h6, p),
1450
+ .stack > :is(h1, h2, h3, h4, h5, h6, p) { margin-block: 0; }
1451
+ .form-stack > .field { margin-block: 0; }
1452
+ .btn {
1453
+ block-size: auto;
1454
+ min-block-size: var(--control-height-md);
1455
+ max-inline-size: 100%;
1456
+ white-space: normal;
1457
+ line-height: 1.35;
1458
+ text-align: center;
1459
+ }
1460
+ .btn--sm { min-block-size: var(--control-height-sm, 36px); }
1461
+ .btn--lg { min-block-size: var(--control-height-lg, 52px); }
1462
+ .btn--primary, .icon-btn--primary, .calendar__day--selected, .pagination__btn.is-active {
1463
+ background: var(--action-bg);
1464
+ color: var(--text-on-action);
1465
+ }
1466
+ .btn--primary:hover:not(:disabled), .icon-btn--primary:hover:not(:disabled) { background: var(--action-hover); color: var(--text-on-action); }
1467
+ .btn--primary:active:not(:disabled), .icon-btn--primary:active:not(:disabled) { background: var(--action-active); color: var(--text-on-action); }
1468
+ .input, .textarea, .select, .combobox__input, .search__input, .datepicker__input {
1469
+ max-inline-size: 100%;
1470
+ caret-color: var(--focus-color);
1471
+ }
1472
+ .input, .select, .combobox__input, .search__input, .datepicker__input {
1473
+ block-size: auto; min-block-size: var(--control-height-md);
1474
+ padding-block: var(--space-2); line-height: 1.5;
1475
+ }
1476
+ :is(.input, .textarea, .select, .combobox__input, .search__input, .datepicker__input):not(.input--error, .input--success, .textarea--error, [aria-invalid="true"]) { border-color: var(--control-border); }
1477
+ .input:hover:not(:disabled):not(:focus):not(.input--error, .input--success, [aria-invalid="true"]), .textarea:hover:not(:disabled):not(:focus):not(.textarea--error, [aria-invalid="true"]),
1478
+ .select:hover:not(:disabled):not(:focus), .combobox__input:hover:not(:disabled):not(:focus),
1479
+ .search__input:hover:not(:focus), .datepicker__input:hover:not(:disabled):not(:focus) { border-color: var(--border-hover); }
1480
+ .input:focus-visible, .textarea:focus-visible, .select:focus-visible,
1481
+ .combobox__input:focus-visible, .search__input:focus-visible, .datepicker__input:focus-visible {
1482
+ outline: 2px solid var(--focus-color);
1483
+ outline-offset: 2px;
1484
+ }
1485
+ .input[aria-invalid="true"], .textarea[aria-invalid="true"] { border-color: var(--danger-text, var(--danger)); }
1486
+ .input.input--error, .textarea.textarea--error,
1487
+ .input.input--error:hover:not(:disabled):not(:focus), .textarea.textarea--error:hover:not(:disabled):not(:focus),
1488
+ :is(.input, .textarea, .select, .combobox__input, .search__input, .datepicker__input)[aria-invalid="true"]:hover:not(:disabled):not(:focus) {
1489
+ border-color: var(--danger-text, var(--danger));
1490
+ }
1491
+ .input.input--success, .input.input--success:hover:not(:disabled):not(:focus) { border-color: var(--success-text, var(--success)); }
1492
+ .pagination { max-inline-size: 100%; flex-wrap: wrap; row-gap: var(--space-2); }
1493
+ .pagination__ellipsis { color: var(--text-muted); }
1494
+ .step--current .step__marker { color: var(--link); border-color: var(--focus-color); }
1495
+ .checkbox input:focus-visible ~ .checkbox__box,
1496
+ .radio input:focus-visible ~ .radio__dot,
1497
+ .switch input:focus-visible ~ .switch__track {
1498
+ outline: 2px solid var(--focus-color);
1499
+ outline-offset: 2px;
1500
+ }
1501
+ input.checkbox, input.radio { border-color: var(--control-border); }
1502
+ input.checkbox:hover, input.radio:hover { border-color: var(--focus-color); }
1503
+ input.checkbox:checked, input.checkbox:indeterminate, input.radio:checked { border-color: var(--focus-color); }
1504
+ .switch__track { background: var(--control-border); }
1505
+ .tabs { max-inline-size: 100%; overflow-x: auto; }
1506
+ .tabs__tab { flex-shrink: 0; }
1507
+ .segmented { max-inline-size: 100%; block-size: auto; min-block-size: var(--control-height-md); overflow-x: auto; }
1508
+ .segmented label { padding-block: var(--space-2); }
1509
+ .stat__row, .breadcrumbs, .check-row { flex-wrap: wrap; row-gap: var(--space-2); }
1510
+ .progress-row, .slider-row { flex-wrap: wrap; gap: var(--space-2); }
1511
+ .stat__value { max-inline-size: 100%; white-space: normal; overflow-wrap: anywhere; }
1512
+ .file-upload, .file-upload__label { min-inline-size: 0; max-inline-size: 100%; }
1513
+ .file-upload__button { max-inline-size: 100%; white-space: normal; text-align: center; }
1514
+ .file-upload__hint { overflow-wrap: anywhere; }
1515
+ .table-scroll { max-inline-size: 100%; overflow-x: auto; overscroll-behavior-inline: contain; }
1516
+ .popover__panel, .datepicker__calendar, .combobox__list {
1517
+ max-inline-size: calc(100vw - 2rem);
1518
+ max-block-size: min(32rem, 70dvh);
1519
+ overflow: auto;
1520
+ }
1521
+ .file-upload__input:focus-visible + .file-upload__label { outline: 2px solid var(--focus-color); outline-offset: 2px; }
1522
+ .calendar { max-inline-size: calc(100vw - 2rem); }
1523
+ .ui-title, :is(h1, h2, h3, h4, h5, h6).ui-title, [data-mode="operate"] :is(h1, h2, h3) {
1524
+ font-family: var(--font-ui-heading);
1525
+ letter-spacing: 0;
1526
+ line-height: 1.3;
1527
+ font-weight: var(--weight-semibold);
1528
+ }
1529
+ .ui-title, :is(h1, h2, h3, h4, h5, h6).ui-title, [data-mode="operate"] h1 { font-size: var(--text-ui-title); }
1530
+ [data-mode="operate"] h2 { font-size: var(--text-xl); }
1531
+ [data-mode="operate"] h3 { font-size: var(--text-lg); }
1532
+ .display, .reading-title, :is(h1, h2, h3, h4, h5, h6):is(.display, .reading-title) {
1533
+ font-family: var(--font-display);
1534
+ font-size: var(--text-display-fluid);
1535
+ line-height: 1.08;
1536
+ letter-spacing: var(--tracking-display);
1537
+ text-wrap: balance;
1538
+ }
1539
+ :where(.celeste-reset, .salvia-reset, .bruma-reset, .nocturna-reset, body[data-system]) {
1540
+ scrollbar-color: var(--control-border) var(--bg);
1541
+ }
1542
+ ::selection,
1543
+ .celeste-reset ::selection, .salvia-reset ::selection, .bruma-reset ::selection {
1544
+ background: var(--selection-bg); color: var(--selection-text);
1545
+ }
1546
+ ::placeholder { color: var(--placeholder); opacity: 1; }
1547
+ :where(a) { text-underline-offset: .2em; text-decoration-thickness: .08em; }
1548
+ .skip-link {
1549
+ position: fixed; inset-block-start: var(--space-2); inset-inline-start: var(--space-2);
1550
+ z-index: 1000; padding: var(--space-3) var(--space-4);
1551
+ background: var(--action-bg); color: var(--text-on-action);
1552
+ border-radius: var(--radius-sm); transform: translateY(-180%);
1553
+ }
1554
+ .skip-link:focus { transform: none; outline: 2px solid var(--focus-color); outline-offset: 2px; }
1555
+ [data-tooltip]::before, [data-tooltip]::after { display: none; }
1556
+ [data-tooltip]:focus-visible::before, [data-tooltip]:focus-visible::after { display: block; }
1557
+ .has-tooltip .tooltip { display: none; }
1558
+ .has-tooltip:has(:focus-visible) .tooltip { display: block; opacity: 1; transform: translate(-50%, 0); }
1559
+ @media (hover: hover) and (pointer: fine) {
1560
+ [data-tooltip]:hover::before, [data-tooltip]:hover::after { display: block; }
1561
+ .has-tooltip:hover .tooltip { display: block; }
1562
+ }
1563
+ @media (pointer: coarse) {
1564
+ .btn, .icon-btn, .segmented label, .pagination button,
1565
+ .tag__close, .search__clear, .toast__close, .check-row,
1566
+ .checkbox:not(input), .radio:not(input), .switch:not(input) {
1567
+ min-block-size: var(--touch-target);
1568
+ min-inline-size: var(--touch-target);
1569
+ }
1570
+ }
1571
+ @media (max-width: 479px) {
1572
+ .btn-group { flex-wrap: wrap; }
1573
+ .modal { max-inline-size: calc(100vw - 2rem); }
1574
+ .stepper { flex-direction: column; align-items: stretch; gap: var(--space-4); }
1575
+ .step { flex-direction: row; align-items: center; gap: var(--space-3); text-align: start; min-inline-size: 0; }
1576
+ .step__label { overflow-wrap: anywhere; }
1577
+ .step__connector { display: none; }
1578
+ }
1579
+ @media (prefers-reduced-motion: reduce) {
1580
+ html, html:focus-within { scroll-behavior: auto; }
1581
+ .spinner, .skeleton, .skeleton::after,
1582
+ .progress--indeterminate .progress__bar, .alert.is-leaving, .toast.is-leaving { animation: none; }
1583
+ .progress--indeterminate .progress__bar { transform: none; }
1584
+ .btn, .icon-btn, .card--interactive, .slider::-webkit-slider-thumb { transform: none; }
1585
+ .btn:active:not(:disabled), .icon-btn:active:not(:disabled), .card--interactive:hover { transform: none; }
1586
+ .btn, .icon-btn { transition: background-color 80ms linear, color 80ms linear; }
1587
+ .menu, .popover__panel, .datepicker__calendar, .link::after { transition: none; }
1588
+ .progress__bar, .progress-ring__value, .accordion__content, .accordion__body { transition: none; }
1589
+ }
1590
+ @media (forced-colors: active) {
1591
+ input.switch, .switch__track { border: 1px solid CanvasText; background: Canvas; }
1592
+ input.switch::after, .switch__track::after { background: CanvasText; }
1593
+ input.switch:checked, .switch input:checked ~ .switch__track { border-color: Highlight; }
1594
+ input.switch:checked::after, .switch input:checked ~ .switch__track::after { background: Highlight; }
1595
+ .checkbox__box, .radio__dot { border-color: CanvasText; }
1596
+ }
1597
+
1598
+
1304
1599
  /* ==========================================================================
1305
1600
  ESTILOS DE LA PÁGINA DE DOCUMENTACIÓN (.ds-*)
1306
1601
  ========================================================================== */
@@ -1447,7 +1742,7 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1447
1742
  .ds-type-row__meta { width: 190px; flex: none; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-muted); }
1448
1743
  .ds-type-row__sample { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1449
1744
 
1450
- .ds-font-card h4 { margin-bottom: 2px; }
1745
+ .ds-font-card h3 { margin-bottom: 2px; }
1451
1746
  .ds-font-card .ds-font-sample { font-size: var(--text-3xl); line-height: 1.2; margin: 6px 0; }
1452
1747
  .ds-font-card p { font-size: var(--text-sm); color: var(--text-muted); margin: 0; max-width: none; }
1453
1748
 
@@ -1485,10 +1780,10 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1485
1780
  @media (hover: hover) and (pointer: fine) {
1486
1781
  .ds-ease-chip:hover { transform: translateX(24px); }
1487
1782
  }
1488
- .ds-ease-chip--out { transition: transform 400ms var(--ease-out); }
1489
- .ds-ease-chip--in { transition: transform 400ms var(--ease-in); }
1490
- .ds-ease-chip--inout { transition: transform 400ms var(--ease-in-out); }
1491
- .ds-ease-chip--spring{ transition: transform 400ms var(--ease-spring); }
1783
+ .ds-ease-chip--out { transition: transform var(--duration-page) var(--ease-out); }
1784
+ .ds-ease-chip--in { transition: transform var(--duration-page) var(--ease-in); }
1785
+ .ds-ease-chip--inout { transition: transform var(--duration-page) var(--ease-in-out); }
1786
+ .ds-ease-chip--spring{ transition: transform var(--duration-page) var(--ease-spring); }
1492
1787
 
1493
1788
  .ds-icon-grid { display: flex; flex-wrap: wrap; gap: var(--space-4); }
1494
1789
  .ds-icon-cell {
@@ -1517,9 +1812,118 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1517
1812
  .ds-main, .ds-footer { margin-left: 0; }
1518
1813
  .ds-main { padding: var(--space-8) var(--space-4) var(--space-16); }
1519
1814
  }
1815
+ /* ESTILOS COMPARTIDOS GENERADOS */
1816
+ /* La documentación comparte navegación y deja que cada marca determine el ritmo. */
1817
+ .ds-topbar { gap: var(--space-3); }
1818
+ .ds-brand { min-inline-size: 0; }
1819
+ .ds-brand, .ds-brand__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1820
+ .ds-theme-toggle, .ds-hamburger { flex-shrink: 0; }
1821
+ .ds-main { padding-block-start: var(--space-12); }
1822
+ .ds-main > section { scroll-margin-block-start: 88px; }
1823
+ .ds-main > section > h2 { text-wrap: balance; }
1824
+ .ds-main :is(h1, h2, h3, h4, h5, h6) { overflow-wrap: anywhere; }
1825
+ .ds-hero {
1826
+ display: grid;
1827
+ grid-template-columns: minmax(0, 1.45fr) minmax(12rem, .65fr);
1828
+ column-gap: var(--space-12);
1829
+ row-gap: var(--space-6);
1830
+ padding-block-start: var(--space-6);
1831
+ }
1832
+ .ds-hero > h1 {
1833
+ grid-column: 1 / -1;
1834
+ font-size: var(--text-display-fluid);
1835
+ line-height: 1.08;
1836
+ letter-spacing: var(--tracking-display);
1837
+ text-wrap: balance;
1838
+ margin: 0;
1839
+ }
1840
+ .ds-hero > .ds-lead { grid-column: 1; margin: 0; max-inline-size: 55ch; }
1841
+ .ds-hero > .ds-actions { grid-column: 1; margin: 0; display: flex; flex-wrap: wrap; gap: var(--space-3); }
1842
+ .ds-hero__palette {
1843
+ grid-column: 2; grid-row: 2 / 4;
1844
+ display: grid; grid-template-columns: 2fr 1.25fr .75fr;
1845
+ gap: var(--space-1); margin: 0; min-block-size: 150px;
1846
+ align-self: stretch; overflow: hidden; border-radius: var(--radius-lg);
1847
+ }
1848
+ .ds-hero__chip { inline-size: auto; block-size: auto; border: 0; border-radius: 0; }
1849
+ .ds-principles {
1850
+ grid-column: 1 / -1; display: grid;
1851
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1852
+ gap: var(--space-6) var(--space-10); margin-block: var(--space-4) 0;
1853
+ }
1854
+ .ds-principle { padding-block-start: var(--space-4); border-block-start: 1px solid var(--border); }
1855
+ .ds-principle h2 { font-family: var(--font-body); font-size: var(--text-base); line-height: 1.5; margin: 0 0 var(--space-2); }
1856
+ .ds-principle p { font-size: var(--text-sm); color: var(--text-secondary); margin: 0; max-inline-size: 48ch; }
1857
+ .ds-hero > .alert, .ds-hero > .ds-callout { grid-column: 1 / -1; margin: var(--space-3) 0 0; }
1858
+ .ds-callout { border: 1px solid var(--border); border-radius: var(--radius-md); }
1859
+ .ds-recipes { margin: 0; }
1860
+ .ds-recipes > div {
1861
+ display: grid; grid-template-columns: minmax(8rem, .4fr) minmax(0, 1fr);
1862
+ gap: var(--space-4); padding-block: var(--space-5); border-block-start: 1px solid var(--border);
1863
+ }
1864
+ .ds-recipes dt { font-weight: var(--weight-semibold); }
1865
+ .ds-recipes dd { margin: 0; color: var(--text-secondary); max-inline-size: 65ch; }
1866
+ .ds-chart-palette { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--space-4); }
1867
+ .ds-chart-palette li { display: grid; gap: var(--space-2); }
1868
+ .ds-chart-palette__color { display: block; block-size: 56px; border-radius: var(--radius-sm); }
1869
+ .ds-chart-palette code { font-family: var(--font-mono); font-size: var(--text-sm); }
1870
+ .ds-chart-palette [data-chart-color] { color: var(--text-muted); font-size: var(--text-sm); }
1871
+ .ds-nav a { min-block-size: 36px; display: flex; align-items: center; }
1872
+ .ds-nav__sub a { font-size: var(--text-sm); }
1873
+ .ds-demo { min-inline-size: 0; max-inline-size: 100%; }
1874
+ .ds-demo > * { min-inline-size: 0; max-inline-size: 100%; }
1875
+ .ds-demo :has(> .divider--vertical) { flex-wrap: wrap; row-gap: var(--space-3); }
1876
+ .ds-wordmark-demo { display: inline-block; max-inline-size: 100%; overflow-x: auto; vertical-align: bottom; }
1877
+ .ds-main code:not(.ds-pre code), .ds-main .code, .ds-main .u-mono { overflow-wrap: anywhere; white-space: normal; }
1878
+ .ds-demo .popover__panel { max-inline-size: calc(100vw - var(--space-20)); }
1879
+ .ds-demo--grid, .ds-semantic-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); }
1880
+ .ds-copy { min-block-size: 36px; }
1881
+ .ds-code summary { padding-block: var(--space-3); }
1882
+ .ds-pre { max-inline-size: 100%; }
1883
+ .ds-type-row__sample { min-inline-size: 0; white-space: normal; overflow-wrap: anywhere; }
1884
+ .ds-main table { min-inline-size: 0; }
1885
+ .ds-theme-toggle[data-tooltip]::after { left: auto; right: 0; transform: translateY(4px); }
1886
+ .ds-theme-toggle[data-tooltip]:hover::after, .ds-theme-toggle[data-tooltip]:focus-visible::after { transform: translateY(0); }
1887
+ [data-system="nocturna"] .ds-wordmark-badge { color: var(--night-50); }
1888
+ .ds-main p { overflow-wrap: anywhere; }
1889
+ .ds-type-row { min-inline-size: 0; }
1890
+ [data-system="celeste"] .ds-hero { padding-block-start: var(--space-10); }
1891
+ [data-system="salvia"] .ds-principles { row-gap: var(--space-8); }
1892
+ [data-system="bruma"] .ds-principles { gap: var(--space-4) var(--space-8); }
1893
+ [data-system="nocturna"] .ds-main { padding-block-start: calc(64px + var(--space-10)); }
1894
+ @media (max-width: 1023px) {
1895
+ .ds-main { padding-inline: var(--space-5); }
1896
+ .ds-hero { column-gap: var(--space-6); }
1897
+ .ds-nav a { min-block-size: var(--touch-target); }
1898
+ .ds-sidenav:not(.is-open), .ds-sidebar:not(.is-open) { visibility: hidden; }
1899
+ }
1900
+ @media (max-width: 639px) {
1901
+ .ds-topbar { padding-inline: var(--space-4); }
1902
+ .ds-version { max-inline-size: 44vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1903
+ .ds-main { padding-inline: var(--space-4); padding-block-start: var(--space-8); }
1904
+ .ds-hero { grid-template-columns: minmax(0, 1fr); row-gap: var(--space-5); padding-block-start: var(--space-2); }
1905
+ .ds-hero > h1, .ds-hero > .ds-lead, .ds-hero > .ds-actions { grid-column: 1; }
1906
+ .ds-hero__palette { grid-column: 1; grid-row: auto; min-block-size: 64px; }
1907
+ .ds-principles { grid-template-columns: minmax(0, 1fr); }
1908
+ .ds-demo { padding: var(--space-4); }
1909
+ .ds-type-row { display: grid; gap: var(--space-2); }
1910
+ .ds-type-row__meta { inline-size: auto; }
1911
+ .ds-space-item { min-inline-size: 0; }
1912
+ .ds-space-item .u-mono { inline-size: 96px; flex: none; }
1913
+ .ds-space-bar { max-inline-size: calc(100vw - 164px); }
1914
+ .ds-recipes > div { grid-template-columns: minmax(0, 1fr); gap: var(--space-2); }
1915
+ .ds-actions > .btn { flex: 1 1 12rem; }
1916
+ .ds-copy { min-block-size: var(--touch-target); }
1917
+ }
1918
+ @media (prefers-reduced-motion: reduce) {
1919
+ .ds-sidenav, .ds-sidebar, .ds-swatch, .ds-ease-chip { transition: none; }
1920
+ .ds-swatch:hover, .ds-ease-chip:hover { transform: none; }
1921
+ }
1922
+
1520
1923
  </style>
1521
1924
  </head>
1522
- <body class="celeste-reset">
1925
+ <body class="celeste-reset" data-system="celeste" data-mode="read">
1926
+ <a class="skip-link" href="#contenido">Saltar al contenido</a>
1523
1927
 
1524
1928
  <!-- Iconos (estilo Lucide, trazo 2px) -->
1525
1929
  <svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">
@@ -1578,10 +1982,13 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1578
1982
  <nav class="ds-nav" id="dsNav">
1579
1983
  <div class="ds-nav__group">Fundamentos</div>
1580
1984
  <a href="#introduccion">Introducción</a>
1985
+ <a href="#datos">Color para datos</a>
1986
+ <a href="#criterio">Criterio de uso</a>
1581
1987
  <a href="#voz">Voz y contenido</a>
1582
1988
  <a href="#colores">Colores</a>
1583
1989
  <a href="#tipografia">Tipografía</a>
1584
1990
  <a href="#espaciado">Espaciado</a>
1991
+ <a href="#ritmo">Ritmo de contenido</a>
1585
1992
  <a href="#bordes">Bordes, radios y focus</a>
1586
1993
  <a href="#elevacion">Elevación</a>
1587
1994
  <a href="#iconografia">Iconografía</a>
@@ -1634,11 +2041,10 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1634
2041
  </nav>
1635
2042
  </aside>
1636
2043
 
1637
- <main class="ds-main">
2044
+ <main class="ds-main" id="contenido" tabindex="-1">
1638
2045
 
1639
2046
  <!-- ============================== INTRODUCCIÓN ============================== -->
1640
2047
  <section id="introduccion" class="ds-hero">
1641
- <p class="ds-eyebrow">Sistema de diseño · Higinio Sosa</p>
1642
2048
  <h1>Celeste Clásica</h1>
1643
2049
  <p class="ds-lead u-measure">
1644
2050
  Sistema de marca <strong>light-first</strong>, sereno y confiable, para todos los productos de
@@ -1651,17 +2057,17 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1651
2057
  <div class="ds-hero__chip" style="background:#31343e"></div>
1652
2058
  </div>
1653
2059
 
1654
- <div style="display:flex;gap:16px;flex-wrap:wrap;margin:24px 0;">
2060
+ <div class="ds-actions">
1655
2061
  <button class="btn btn--primary" id="dsHeroStart">Empezar a construir</button>
1656
2062
  <button class="btn btn--outline" id="dsHeroTokens">Ver tokens</button>
1657
2063
  </div>
1658
2064
 
1659
2065
  <div class="ds-principles">
1660
- <div class="card"><span class="ds-num">01</span><h4>Claridad primero</h4><p>El contenido siempre por encima de la decoración.</p></div>
1661
- <div class="card"><span class="ds-num">02</span><h4>Calma visual</h4><p>Superficies claras, whitespace generoso, contraste solo donde importa.</p></div>
1662
- <div class="card"><span class="ds-num">03</span><h4>Un acento a la vez</h4><p>El azul acero guía la acción; nunca compite consigo mismo.</p></div>
1663
- <div class="card"><span class="ds-num">04</span><h4>Consistencia sobre novedad</h4><p>Mismos tokens en todos los productos; cero valores mágicos.</p></div>
1664
- <div class="card"><span class="ds-num">05</span><h4>Movimiento con propósito</h4><p>La animación explica — aparece, cambia, desaparece — nunca decora sola.</p></div>
2066
+ <div class="ds-principle"><h2>Claridad primero</h2><p>El contenido siempre por encima de la decoración.</p></div>
2067
+ <div class="ds-principle"><h2>Calma visual</h2><p>Superficies claras, whitespace generoso, contraste solo donde importa.</p></div>
2068
+ <div class="ds-principle"><h2>Un acento a la vez</h2><p>El azul acero guía la acción; nunca compite consigo mismo.</p></div>
2069
+ <div class="ds-principle"><h2>Consistencia sobre novedad</h2><p>Mismos tokens en todos los productos; cero valores mágicos.</p></div>
2070
+ <div class="ds-principle"><h2>Movimiento con propósito</h2><p>La animación explica — aparece, cambia, desaparece — nunca decora sola.</p></div>
1665
2071
  </div>
1666
2072
 
1667
2073
  <div class="alert alert--info" style="margin-top:24px">
@@ -1674,8 +2080,43 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1674
2080
  </section>
1675
2081
 
1676
2082
  <!-- ============================== VOZ Y CONTENIDO ============================== -->
2083
+ <section id="datos">
2084
+ <h2>Color para datos</h2>
2085
+ <p>Serie categórica de orden estable, con pasos propios en cada tema. El color identifica; etiquetas, formas o patrones conservan el significado. Los labels usan tinta, no el color de la serie.</p>
2086
+ <ul class="ds-chart-palette"><li><span class="ds-chart-palette__color" style="background:var(--chart-1)" aria-hidden="true"></span><code>--chart-1</code><span data-chart-color="--chart-1"></span></li><li><span class="ds-chart-palette__color" style="background:var(--chart-2)" aria-hidden="true"></span><code>--chart-2</code><span data-chart-color="--chart-2"></span></li><li><span class="ds-chart-palette__color" style="background:var(--chart-3)" aria-hidden="true"></span><code>--chart-3</code><span data-chart-color="--chart-3"></span></li><li><span class="ds-chart-palette__color" style="background:var(--chart-4)" aria-hidden="true"></span><code>--chart-4</code><span data-chart-color="--chart-4"></span></li><li><span class="ds-chart-palette__color" style="background:var(--chart-5)" aria-hidden="true"></span><code>--chart-5</code><span data-chart-color="--chart-5"></span></li><li><span class="ds-chart-palette__color" style="background:var(--chart-6)" aria-hidden="true"></span><code>--chart-6</code><span data-chart-color="--chart-6"></span></li><li><span class="ds-chart-palette__color" style="background:var(--chart-7)" aria-hidden="true"></span><code>--chart-7</code><span data-chart-color="--chart-7"></span></li></ul>
2087
+ <p class="u-muted">Las pruebas comprueban contraste con la superficie y separación perceptual entre colores adyacentes. Ofrece una tabla equivalente; más de siete series necesitan agrupación u otra composición.</p>
2088
+ </section>
2089
+
2090
+ <section id="ritmo">
2091
+ <h2>Ritmo de contenido</h2>
2092
+ <p>El espacio sigue a la relación: 6px dentro de un campo, 8px entre título y descripción, 16px entre bloques, 20px entre campos y 24px entre tarjetas. Las secciones se separan 64px.</p>
2093
+ <div class="stack stack--cards" data-spacing-example data-mode="operate">
2094
+ <section class="card">
2095
+ <header class="text-group"><h3>Datos de contacto</h3><p>Ejemplo de composición. El título y su descripción forman un grupo.</p></header>
2096
+ <form class="form-stack" onsubmit="return false">
2097
+ <div class="field"><label class="field__label" for="rh-name">Nombre</label><input class="input" id="rh-name" autocomplete="name" placeholder="Tu nombre"><p class="field__help">Escribe el nombre que quieres mostrar.</p></div>
2098
+ <div class="field"><label class="field__label" for="rh-email">Correo</label><input class="input" id="rh-email" type="email" autocomplete="email" placeholder="nombre@ejemplo.com"><p class="field__help">La ayuda puede ocupar varias líneas sin juntarse con el siguiente control.</p></div>
2099
+ <div class="cluster"><button class="btn btn--primary" type="button">Acción de ejemplo</button><button class="btn btn--secondary" type="button">Cancelar</button></div>
2100
+ </form>
2101
+ </section>
2102
+ <section class="card">
2103
+ <header class="text-group"><h3>Contenido relacionado</h3><p>Una tarjeta distinta conserva su propia distancia.</p></header>
2104
+ <div class="stack"><p>Los párrafos y los divs no necesitan una colección de márgenes manuales.</p><div>Este bloque mantiene 16px respecto al párrafo anterior.</div></div>
2105
+ </section>
2106
+ </div>
2107
+ </section>
2108
+
2109
+ <section id="criterio">
2110
+ <h2>Diseñar con Celeste Clásica</h2>
2111
+ <dl class="ds-recipes">
2112
+ <div><dt>Operar</dt><dd>Una tarea clara por región. Títulos en la familia de UI, datos estables y una acción dominante por contexto. Usa <code>data-mode="operate"</code> en formularios, paneles y tablas.</dd></div>
2113
+ <div><dt>Leer</dt><dd>Display para abrir la lectura; cuerpo de 65–75 caracteres por línea. Agrupa lo relacionado y separa las secciones con espacio, sin convertir cada párrafo en una tarjeta.</dd></div>
2114
+ <div><dt>Decidir</dt><dd>La composición sigue a la decisión: contexto, evidencia y acción. Conserva la identidad de marca y evita trasladar la densidad de un dashboard a una landing.</dd></div>
2115
+ <div><dt>Interactuar</dt><dd>Los botones sólidos usan <code>--action-bg</code> y <code>--text-on-action</code>. Foco, hover y error deben seguir siendo reconocibles en ambos temas, con teclado y con movimiento reducido.</dd></div>
2116
+ </dl>
2117
+ </section>
2118
+
1677
2119
  <section id="voz">
1678
- <p class="ds-eyebrow">Fundamentos</p>
1679
2120
  <h2>Voz y contenido</h2>
1680
2121
  <p class="ds-lead">Una consultora seria pero cálida — "banca privada boutique", no "startup ruidosa".</p>
1681
2122
  <div class="ds-demo ds-demo--col">
@@ -1695,7 +2136,6 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1695
2136
 
1696
2137
  <!-- ============================== COLORES ============================== -->
1697
2138
  <section id="colores">
1698
- <p class="ds-eyebrow">Fundamentos</p>
1699
2139
  <h2>Colores</h2>
1700
2140
  <p class="ds-lead">Un solo acento — azul acero <span class="u-mono">#7192ba</span> — sobre neutrales grisáceo-azulados derivados de la tinta <span class="u-mono">#31343e</span>. Haz clic en cualquier muestra para copiar su variable.</p>
1701
2141
 
@@ -1713,7 +2153,7 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1713
2153
  <p>Los componentes consumen <strong>solo esta capa</strong> — así el cambio de tema es un cambio de atributo.</p>
1714
2154
  <div class="ds-demo ds-demo--col" style="padding:16px">
1715
2155
  <table class="table" id="aliasTable">
1716
- <thead><tr><th style="width:52px"></th><th>Alias</th><th>Valor (light)</th><th>Rol</th></tr></thead>
2156
+ <thead><tr><th style="width:min(100%, 52px)"></th><th>Alias</th><th>Valor (light)</th><th>Rol</th></tr></thead>
1717
2157
  <tbody></tbody>
1718
2158
  </table>
1719
2159
  </div>
@@ -1730,14 +2170,13 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1730
2170
  <div class="ds-ratio">
1731
2171
  <div style="flex:6;background:var(--bg);color:var(--text-secondary)">60% neutrales claros</div>
1732
2172
  <div style="flex:3;background:var(--neutral-600);color:#fff">30% tinta y estructura</div>
1733
- <div style="flex:1;background:var(--accent);color:var(--text-on-primary)">10%</div>
2173
+ <div style="flex:1;background:var(--action-bg);color:var(--text-on-action)">10%</div>
1734
2174
  </div>
1735
2175
  <p><strong>Un solo botón primario visible por pantalla</strong>; el resto secundarios o ghost. Fondos siempre planos: sin gradientes, texturas ni patrones. El acento pierde poder si supera el 10&nbsp;%.</p>
1736
2176
  </section>
1737
2177
 
1738
2178
  <!-- ============================== TIPOGRAFÍA ============================== -->
1739
2179
  <section id="tipografia">
1740
- <p class="ds-eyebrow">Fundamentos</p>
1741
2180
  <h2>Tipografía</h2>
1742
2181
  <p class="ds-lead">Tres familias con roles estrictos. Escala 1.25 (tercera mayor) desde 16&nbsp;px.</p>
1743
2182
 
@@ -1766,7 +2205,6 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1766
2205
 
1767
2206
  <!-- ============================== ESPACIADO ============================== -->
1768
2207
  <section id="espaciado">
1769
- <p class="ds-eyebrow">Fundamentos</p>
1770
2208
  <h2>Espaciado</h2>
1771
2209
  <p class="ds-lead">Escala base 4&nbsp;px — cero valores mágicos. El número del token = px ÷ 4.</p>
1772
2210
  <div class="ds-space-list" id="spaceScale"></div>
@@ -1788,7 +2226,6 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1788
2226
 
1789
2227
  <!-- ============================== BORDES, RADIOS Y FOCUS ============================== -->
1790
2228
  <section id="bordes">
1791
- <p class="ds-eyebrow">Fundamentos</p>
1792
2229
  <h2>Bordes, radios y focus</h2>
1793
2230
  <p class="ds-lead">Bordes de 1&nbsp;px, radios generosos y un focus siempre visible — la geometría que sostiene la calma de la marca.</p>
1794
2231
  <h3>Radios</h3>
@@ -1797,14 +2234,13 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1797
2234
  <div class="ds-radius-box" style="border-radius:var(--radius-md)">md · 10</div>
1798
2235
  <div class="ds-radius-box" style="border-radius:var(--radius-lg)">lg · 14</div>
1799
2236
  <div class="ds-radius-box" style="border-radius:var(--radius-xl)">xl · 20</div>
1800
- <div class="ds-radius-box" style="border-radius:var(--radius-full);width:72px">full</div>
2237
+ <div class="ds-radius-box" style="border-radius:var(--radius-full);width:min(100%, 72px)">full</div>
1801
2238
  </div>
1802
2239
  <p>Borde por defecto <span class="u-mono">1px solid var(--border)</span>. Focus ring global de teclado: <span class="u-mono">2px var(--primary-500)</span> con offset 2px vía <span class="u-mono">:focus-visible</span> — el click de ratón no lo dispara. Único uso de transparencia: overlay de modal y ring de focus. <strong>No hay blur ni glassmorphism en Celeste Clásica.</strong></p>
1803
2240
  </section>
1804
2241
 
1805
2242
  <!-- ============================== ELEVACIÓN ============================== -->
1806
2243
  <section id="elevacion">
1807
- <p class="ds-eyebrow">Fundamentos</p>
1808
2244
  <h2>Elevación</h2>
1809
2245
  <p class="ds-lead">Sombras frías teñidas con la tinta <span class="u-mono">rgba(49,52,62,…)</span>, nunca negro puro. Máximo 3 niveles de elevación visibles por pantalla. Sin resplandor de acento: el <span class="u-mono">glow</span> es exclusivo de Nocturna Eléctrica.</p>
1810
2246
  <h3>Niveles</h3>
@@ -1826,7 +2262,6 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1826
2262
 
1827
2263
  <!-- ============================== ICONOGRAFÍA ============================== -->
1828
2264
  <section id="iconografia">
1829
- <p class="ds-eyebrow">Fundamentos</p>
1830
2265
  <h2>Iconografía</h2>
1831
2266
  <p class="ds-lead">Set sustituto: <a class="link" href="https://lucide.dev" target="_blank" rel="noopener noreferrer">Lucide</a> — trazo 1.5–2&nbsp;px, esquinas redondeadas, geométrico. Si existe un set propio de marca, reemplazar.</p>
1832
2267
  <div class="ds-icon-grid">
@@ -1846,7 +2281,6 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1846
2281
 
1847
2282
  <!-- ============================== MARCA / WORDMARK ============================== -->
1848
2283
  <section id="marca">
1849
- <p class="ds-eyebrow">Fundamentos</p>
1850
2284
  <h2>Marca / wordmark</h2>
1851
2285
  <p class="ds-lead">No hay logo ni imágenes de marca. Donde un mockup necesite logotipo se renderiza <strong>«Higinio»</strong> (o el nombre del producto) en <span class="u-mono">--font-display</span> (Fraunces) — nunca se dibuja un logo aproximado.</p>
1852
2286
  <div class="ds-demo" style="gap:32px">
@@ -1863,7 +2297,6 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1863
2297
 
1864
2298
  <!-- ============================== COMPONENTES ============================== -->
1865
2299
  <section id="componentes">
1866
- <p class="ds-eyebrow">Biblioteca</p>
1867
2300
  <h2>Componentes</h2>
1868
2301
  <p class="ds-lead">Los 35 componentes del sistema, renderizados en vivo con las clases del framework <span class="u-mono">celeste-clasica.css</span>. Cada bloque incluye su código de uso.</p>
1869
2302
 
@@ -1932,8 +2365,8 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
1932
2365
  <p class="ds-spec">Trazo 2.5, rotación 0.8 s linear. Si la carga dura &lt;300 ms, no mostrar spinner. Blanco dentro de botones primarios.</p>
1933
2366
  <div class="ds-demo">
1934
2367
  <svg class="spinner" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2.5"/><path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg>
1935
- <svg class="spinner" style="width:24px;height:24px" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2.5"/><path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg>
1936
- <svg class="spinner" style="width:32px;height:32px;color:var(--text-muted)" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2.5"/><path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg>
2368
+ <svg class="spinner" style="width:min(100%, 24px);height:24px" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2.5"/><path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg>
2369
+ <svg class="spinner" style="width:min(100%, 32px);height:32px;color:var(--text-muted)" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2.5"/><path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg>
1937
2370
  </div>
1938
2371
  <details class="ds-code"><summary>Ver código</summary>
1939
2372
  <div class="ds-code-box"><button class="ds-copy">Copiar</button>
@@ -2463,7 +2896,7 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
2463
2896
  <p class="ds-spec">Panel 190 px mín. con <span class="u-mono">shadow-lg</span> · entrada fade + translateY(-4→0) 160 ms · ítem danger con hover <span class="u-mono">danger-100</span>.</p>
2464
2897
  <div class="ds-demo" style="padding-bottom:180px">
2465
2898
  <div class="menu-wrap">
2466
- <button class="btn btn--secondary js-menu-toggle">Acciones<svg style="width:16px;height:16px"><use href="#i-chevron-down"/></svg></button>
2899
+ <button class="btn btn--secondary js-menu-toggle">Acciones<svg style="width:min(100%, 16px);height:16px"><use href="#i-chevron-down"/></svg></button>
2467
2900
  <div class="menu" role="menu">
2468
2901
  <button class="menu__item" role="menuitem"><svg><use href="#i-pencil"/></svg>Editar</button>
2469
2902
  <button class="menu__item" role="menuitem"><svg><use href="#i-copy"/></svg>Duplicar</button>
@@ -2569,13 +3002,13 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
2569
3002
  <!-- Stat -->
2570
3003
  <div class="ds-component" id="comp-stat">
2571
3004
  <h3>Stat</h3>
2572
- <p class="ds-spec">KPI único, componer dentro de Card. Valor en mono <span class="u-mono">text-3xl</span> · delta con flecha en tonos <span class="u-mono">--*-text</span> · count-up al entrar en viewport.</p>
3005
+ <p class="ds-spec">KPI único, componer dentro de Card. Valor en mono <span class="u-mono">text-3xl</span> · delta con flecha en tonos <span class="u-mono">--*-text</span> · valor final visible desde la carga.</p>
2573
3006
  <div class="grid">
2574
3007
  <div class="card col-12 col-md-4">
2575
3008
  <div class="stat">
2576
3009
  <span class="stat__label"><svg><use href="#i-chart"/></svg>Ingresos del mes</span>
2577
3010
  <div class="stat__row">
2578
- <span class="stat__value js-countup" data-target="128400" data-prefix="$ ">$ 0</span>
3011
+ <span class="stat__value " data-target="128400" data-prefix="$ ">$ 128,400</span>
2579
3012
  <span class="stat__delta stat__delta--up"><svg><use href="#i-trending-up"/></svg>+12.4%</span>
2580
3013
  </div>
2581
3014
  </div>
@@ -2584,7 +3017,7 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
2584
3017
  <div class="stat">
2585
3018
  <span class="stat__label"><svg><use href="#i-user"/></svg>Clientes activos</span>
2586
3019
  <div class="stat__row">
2587
- <span class="stat__value js-countup" data-target="1284">0</span>
3020
+ <span class="stat__value " data-target="1284">1,284</span>
2588
3021
  <span class="stat__delta stat__delta--down"><svg><use href="#i-trending-down"/></svg>-2.1%</span>
2589
3022
  </div>
2590
3023
  </div>
@@ -2593,7 +3026,7 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
2593
3026
  <div class="stat">
2594
3027
  <span class="stat__label"><svg><use href="#i-folder"/></svg>Proyectos abiertos</span>
2595
3028
  <div class="stat__row">
2596
- <span class="stat__value js-countup" data-target="37">0</span>
3029
+ <span class="stat__value " data-target="37">37</span>
2597
3030
  <span class="stat__delta"><svg><use href="#i-minus"/></svg>0%</span>
2598
3031
  </div>
2599
3032
  </div>
@@ -2778,7 +3211,7 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
2778
3211
  <div class="grid">
2779
3212
  <div class="card col-12 col-md-6">
2780
3213
  <div style="display:flex;gap:12px;align-items:center;margin-bottom:16px">
2781
- <div class="skeleton skeleton--circle" style="width:40px;height:40px"></div>
3214
+ <div class="skeleton skeleton--circle" style="width:min(100%, 40px);height:40px"></div>
2782
3215
  <div style="flex:1;display:flex;flex-direction:column;gap:8px">
2783
3216
  <div class="skeleton" style="height:12px;width:60%"></div>
2784
3217
  <div class="skeleton" style="height:10px;width:40%"></div>
@@ -2800,7 +3233,7 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
2800
3233
  <details class="ds-code"><summary>Ver código</summary>
2801
3234
  <div class="ds-code-box"><button class="ds-copy">Copiar</button>
2802
3235
  <pre class="ds-pre"><code>&lt;div class="skeleton" style="height:10px;width:85%"&gt;&lt;/div&gt;
2803
- &lt;div class="skeleton skeleton--circle" style="width:40px;height:40px"&gt;&lt;/div&gt;
3236
+ &lt;div class="skeleton skeleton--circle" style="width:min(100%, 40px);height:40px"&gt;&lt;/div&gt;
2804
3237
 
2805
3238
  &lt;div class="empty-state"&gt;
2806
3239
  &lt;svg&gt;…icono 40px…&lt;/svg&gt;
@@ -3206,7 +3639,6 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
3206
3639
 
3207
3640
  <!-- ============================== MOTION ============================== -->
3208
3641
  <section id="motion">
3209
- <p class="ds-eyebrow">Sistema</p>
3210
3642
  <h2>Motion</h2>
3211
3643
  <p class="ds-lead">Solo <span class="u-mono">transform</span> y <span class="u-mono">opacity</span>. La salida siempre ~20 % más corta que la entrada. Distancias de 4–8 px: nada "vuela" por la pantalla.</p>
3212
3644
  <div class="ds-demo ds-demo--col" style="padding:16px">
@@ -3231,13 +3663,12 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
3231
3663
  <ul style="max-width:var(--measure)">
3232
3664
  <li>Stagger en listas: 30 ms por ítem, máximo 6 ítems.</li>
3233
3665
  <li>Si la carga dura &lt;300 ms, no mostrar spinner (evita parpadeo).</li>
3234
- <li><span class="u-mono">prefers-reduced-motion</span> colapsa toda animación a 0.01 ms.</li>
3666
+ <li><span class="u-mono">prefers-reduced-motion</span> conserva estados finales, evita desplazamientos y detiene la carga animada.</li>
3235
3667
  </ul>
3236
3668
  </section>
3237
3669
 
3238
3670
  <!-- ============================== ACCESIBILIDAD ============================== -->
3239
3671
  <section id="accesibilidad">
3240
- <p class="ds-eyebrow">Sistema</p>
3241
3672
  <h2>Accesibilidad</h2>
3242
3673
  <p class="ds-lead">WCAG AA mínimo: 4.5:1 texto normal, 3:1 texto grande y componentes UI. Touch targets de 44×44 px. Estado nunca comunicado solo con color.</p>
3243
3674
  <div class="ds-demo ds-demo--col" style="padding:16px">
@@ -3261,73 +3692,208 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
3261
3692
 
3262
3693
  <!-- ============================== TOKENS Y DESCARGA ============================== -->
3263
3694
  <section id="tokens">
3264
- <p class="ds-eyebrow">Sistema</p>
3265
3695
  <h2>Tokens y descarga</h2>
3266
3696
  <p class="ds-lead">El sistema completo vive en <span class="u-mono">dist/celeste-clasica/</span>: <span class="u-mono">celeste-clasica.css</span> (framework completo), <span class="u-mono">tokens.css</span> (solo variables), <span class="u-mono">tailwind.css</span> (@theme para Tailwind v4) y <span class="u-mono">tokens.json</span> (W3C DTCG 2025.10, interoperable con Figma / Tokens Studio / Style Dictionary).</p>
3267
3697
 
3268
3698
  <h3>Variables CSS</h3>
3269
3699
  <div class="ds-code-box"><button class="ds-copy">Copiar</button>
3270
- <pre class="ds-pre"><code>:root {
3271
- /* Primario */
3700
+ <pre class="ds-pre"><code>/* ============================================================
3701
+ Celeste Clásica — Design Tokens v2.0
3702
+ Sistema de diseño de Higinio Sosa · light-first
3703
+ Fuente de verdad: DESIGN-celeste-clasica.md
3704
+ Uso: importar ANTES de cualquier estilo propio.
3705
+ Los componentes consumen SOLO aliases semánticos, nunca hex.
3706
+ ============================================================ */
3707
+
3708
+ @import url("https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,600;0,9..144,700;1,9..144,600&amp;family=Public+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&amp;family=IBM+Plex+Mono:wght@400;500&amp;display=swap");
3709
+
3710
+ :root {
3711
+ /* == Primitivos: primario (Azul Acero) == */
3272
3712
  --primary-50: #f2f6fa; --primary-100: #dfe9f2; --primary-200: #c3d5e6;
3273
3713
  --primary-300: #a0c0d4; --primary-400: #87a8c7; --primary-500: #7192ba;
3274
3714
  --primary-600: #5d7ba3; --primary-700: #4d6588; --primary-800: #40536e;
3275
3715
  --primary-900: #31343e;
3276
3716
 
3277
- /* Neutrales */
3717
+ /* == Primitivos: neutrales (Gris Azulado) == */
3278
3718
  --neutral-0: #ffffff; --neutral-50: #f7f8fa; --neutral-100: #eef0f3;
3279
3719
  --neutral-200: #dcdfe5; --neutral-300: #b8bdc7; --neutral-400: #8a8f9c;
3280
3720
  --neutral-500: #666b78; --neutral-600: #4d5160; --neutral-700: #3d414e;
3281
3721
  --neutral-800: #31343e; --neutral-900: #22242b;
3282
3722
 
3283
- /* Semánticos (ramp de 3) */
3723
+ /* == Primitivos: semánticos (ramp de 3: sólido / fondo / texto AA) == */
3284
3724
  --success-500: #3d9970; --success-100: #e2f3ec; --success-text: #2b6e50;
3285
3725
  --warning-500: #c9922e; --warning-100: #faf1de; --warning-text: #8a651c;
3286
3726
  --danger-500: #c04d4d; --danger-100: #f9e7e7; --danger-text: #8f3232;
3287
3727
  --info-500: #7192ba; --info-100: #dfe9f2; --info-text: #4d6588;
3288
3728
 
3289
- /* Aliases (los componentes consumen SOLO esto) */
3290
- --bg: var(--neutral-50); --surface: var(--neutral-0); --surface-alt: var(--neutral-100);
3291
- --border: var(--neutral-200); --border-strong: var(--neutral-300);
3292
- --text-primary: var(--neutral-800); --text-secondary: var(--neutral-600);
3293
- --text-muted: var(--neutral-500); --text-disabled: var(--neutral-400);
3294
- --text-on-primary: #ffffff; --text-on-primary-solid: var(--primary-700);
3295
- --accent: var(--primary-500); --accent-hover: var(--primary-600);
3296
- --accent-active: var(--primary-700); --accent-soft: var(--primary-50);
3297
- --accent-soft-strong: var(--primary-100); --link: var(--primary-700);
3298
-
3299
- /* Tipografía */
3729
+ /* == Aliases semánticos (los componentes consumen SOLO esto) == */
3730
+ --bg: var(--neutral-50);
3731
+ --surface: var(--neutral-0);
3732
+ --surface-alt: var(--neutral-100);
3733
+ --border: var(--neutral-200);
3734
+ --border-strong: var(--neutral-300);
3735
+ --text-primary: var(--neutral-800);
3736
+ --text-secondary: var(--neutral-600);
3737
+ --text-muted: var(--neutral-500);
3738
+ --text-disabled: var(--neutral-400);
3739
+ --text-on-primary: #ffffff;
3740
+ --text-on-primary-solid: var(--primary-700);
3741
+ --accent: var(--primary-500);
3742
+ --accent-hover: var(--primary-600);
3743
+ --accent-active: var(--primary-700);
3744
+ --accent-soft: var(--primary-50);
3745
+ --accent-soft-strong: var(--primary-100);
3746
+ --link: var(--primary-700); /* AA ~6:1 — texto de links y ghost; primary-500 solo para UI */
3747
+
3748
+ /* == Tipografía == */
3300
3749
  --font-display: "Fraunces", Georgia, serif;
3301
3750
  --font-body: "Public Sans", system-ui, -apple-system, sans-serif;
3302
3751
  --font-mono: "IBM Plex Mono", ui-monospace, monospace;
3303
3752
  --text-xs: .75rem; --text-sm: .875rem; --text-base: 1rem; --text-lg: 1.125rem;
3304
3753
  --text-xl: 1.25rem; --text-2xl: 1.5625rem; --text-3xl: 1.9375rem;
3305
3754
  --text-4xl: 2.4375rem; --text-5xl: 3.0625rem;
3306
- --tracking-display: -0.02em; --tracking-label: 0.04em; --measure: 65ch;
3755
+ --leading-xs: 1.5; --leading-sm: 1.5; --leading-base: 1.6; --leading-lg: 1.55;
3756
+ --leading-xl: 1.4; --leading-2xl: 1.3; --leading-3xl: 1.25;
3757
+ --leading-4xl: 1.15; --leading-5xl: 1.1;
3758
+ --tracking-display: -0.02em; --tracking-body: 0; --tracking-label: 0.04em;
3759
+ --weight-regular: 400; --weight-medium: 500; --weight-semibold: 600; --weight-bold: 700;
3760
+ --measure: 65ch;
3307
3761
 
3308
- /* Espaciado (base 4px) */
3762
+ /* == Espaciado (escala base 4px) == */
3309
3763
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
3310
3764
  --space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px;
3311
3765
  --space-12: 48px; --space-16: 64px; --space-20: 80px; --space-24: 96px;
3766
+ --card-padding: var(--space-6); --card-padding-mobile: var(--space-4);
3767
+ --section-gap: var(--space-16); --form-gap: var(--space-5);
3768
+ --button-padding-md: 12px 20px; --button-padding-sm: 8px 14px;
3312
3769
  --control-height-sm: 36px; --control-height-md: 44px; --control-height-lg: 52px;
3770
+ --gutter: 24px; --gutter-mobile: 16px;
3313
3771
 
3314
- /* Radios y sombras */
3772
+ /* == Radios, bordes y sombras (teñidas de tinta, nunca negro puro) == */
3315
3773
  --radius-sm: 6px; --radius-md: 10px; --radius-lg: 14px;
3316
3774
  --radius-xl: 20px; --radius-full: 9999px;
3775
+ --border-width: 1px;
3317
3776
  --shadow-xs: 0 1px 2px rgba(49,52,62,.06);
3318
3777
  --shadow-sm: 0 1px 3px rgba(49,52,62,.08), 0 1px 2px rgba(49,52,62,.05);
3319
3778
  --shadow-md: 0 4px 8px rgba(49,52,62,.09), 0 2px 4px rgba(49,52,62,.05);
3320
3779
  --shadow-lg: 0 12px 24px rgba(49,52,62,.12), 0 4px 8px rgba(49,52,62,.06);
3321
3780
  --shadow-xl: 0 24px 48px rgba(49,52,62,.16);
3781
+
3782
+ /* == Focus == */
3322
3783
  --ring: 0 0 0 3px rgba(113,146,186,.25);
3784
+ --ring-color: rgba(113,146,186,.25);
3323
3785
 
3324
- /* Motion */
3786
+ /* == Motion == */
3325
3787
  --duration-instant: 100ms; --duration-fast: 150ms; --duration-base: 200ms;
3326
3788
  --duration-slow: 250ms; --duration-page: 320ms;
3327
3789
  --ease-out: cubic-bezier(0.2, 0, 0, 1);
3328
3790
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
3329
- --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
3791
+ --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1); /* moverse de A a B en pantalla */
3330
3792
  --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
3793
+ --stagger-step: 30ms;
3794
+
3795
+ color-scheme: light;
3796
+
3797
+ --overlay: rgba(49, 52, 62, .5);
3798
+ --tooltip-bg: var(--neutral-900);
3799
+ --tooltip-text: #ffffff;
3800
+ --ring-danger: 0 0 0 3px rgba(192,77,77,.22);
3801
+
3802
+ --action-bg: var(--primary-700);
3803
+ --action-hover: var(--primary-800);
3804
+ --action-active: var(--primary-900);
3805
+ --text-on-action: var(--text-on-primary);
3806
+ --control-border: var(--neutral-400);
3807
+ --placeholder: var(--text-muted);
3808
+ --selection-bg: var(--action-bg);
3809
+ --selection-text: var(--text-on-action);
3810
+ --font-ui-heading: var(--font-body);
3811
+ --text-ui-title: 2rem;
3812
+ --touch-target: 44px;
3813
+ --focus-color: var(--accent);
3814
+ --text-display-fluid: clamp(2.75rem, 1.7rem + 3vw, 4.75rem);
3815
+ --border-hover: var(--neutral-500);
3816
+ --text-on-danger: #ffffff;
3817
+
3818
+ /* Series categóricas: orden estable; acompañar con etiqueta o forma. */
3819
+ --chart-1: #4a8cc1;
3820
+ --chart-2: #853f63;
3821
+ --chart-3: #129a92;
3822
+ --chart-4: #8e4031;
3823
+ --chart-5: #5b975e;
3824
+ --chart-6: #8a600a;
3825
+ --chart-7: #857bc1;
3826
+ /* Ritmo de contenido y formularios. */
3827
+ --field-gap: 6px;
3828
+ --heading-gap: var(--space-2);
3829
+ --content-gap: var(--space-4);
3830
+ --card-content-gap: var(--space-4);
3831
+ --card-group-gap: var(--space-6);
3832
+
3833
+ }
3834
+
3835
+ /* == Modo oscuro (variante) — alternar data-theme en &lt;html&gt; == */
3836
+ [data-theme="dark"] {
3837
+ --bg: #16181e;
3838
+ --surface: #1d2028;
3839
+ --surface-alt: #252935;
3840
+ --border: #3a3f4d;
3841
+ --border-strong: #4a5060;
3842
+ --text-primary: #e6e9ee;
3843
+ --text-secondary: #b9bfcb;
3844
+ --text-muted: #8b91a0;
3845
+ --text-disabled: #6f7585;
3846
+ --accent: #87a8c7;
3847
+ --accent-hover: #a0c0d4;
3848
+ --accent-active: #7192ba;
3849
+ --accent-soft: rgba(113,146,186,.12);
3850
+ --accent-soft-strong: rgba(113,146,186,.18);
3851
+ --text-on-primary: #16181e;
3852
+ --link: #a0c0d4;
3853
+ --success-500: #5cbf93; --success-100: #12291f; --success-text: #7fd4ae;
3854
+ --warning-500: #e0ad4d; --warning-100: #2b2210; --warning-text: #ecc57e;
3855
+ --danger-500: #e07777; --danger-100: #2e1515; --danger-text: #eb9e9e;
3856
+ --info-500: #87a8c7; --info-100: #1a2430; --info-text: #a0c0d4;
3857
+ --ring: 0 0 0 3px rgba(160,192,212,.3);
3858
+ --ring-color: rgba(160,192,212,.3);
3859
+ --shadow-sm: 0 1px 2px rgba(0,0,0,.35);
3860
+ --shadow-md: 0 4px 12px rgba(0,0,0,.45);
3861
+ --shadow-lg: 0 12px 32px rgba(0,0,0,.55);
3862
+ color-scheme: dark;
3863
+
3864
+ --text-on-primary-solid: #a0c0d4;
3865
+ --overlay: rgba(0, 0, 0, .6);
3866
+ --tooltip-bg: #e6e9ee;
3867
+ --tooltip-text: #31343e;
3868
+ --ring-danger: 0 0 0 3px rgba(224,119,119,.25);
3869
+
3870
+ --selection-bg: var(--action-bg);
3871
+ --selection-text: var(--text-on-action);
3872
+ --action-bg: var(--accent);
3873
+ --action-hover: var(--accent-hover);
3874
+ --action-active: var(--accent-active);
3875
+ --control-border: var(--text-muted);
3876
+ --border-hover: var(--text-secondary);
3877
+ --text-on-danger: #16181e;
3878
+ --focus-color: var(--accent);
3879
+
3880
+ /* Series categóricas: orden estable; acompañar con etiqueta o forma. */
3881
+ --chart-1: #5798ce;
3882
+ --chart-2: #a0587c;
3883
+ --chart-3: #2aa79e;
3884
+ --chart-4: #aa5849;
3885
+ --chart-5: #67a369;
3886
+ --chart-6: #946a1c;
3887
+ --chart-7: #877cc3;
3888
+ }
3889
+
3890
+ /* == Accesibilidad del movimiento == */
3891
+
3892
+ @media (prefers-reduced-motion: reduce) {
3893
+ :root {
3894
+ --duration-instant: 0ms; --duration-fast: 0ms; --duration-base: 0ms;
3895
+ --duration-slow: 0ms; --duration-page: 0ms; --stagger-step: 0ms;
3896
+ }
3331
3897
  }</code></pre>
3332
3898
  </div>
3333
3899
 
@@ -3388,7 +3954,6 @@ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-off
3388
3954
 
3389
3955
  <!-- ============================== INSTALACIÓN ============================== -->
3390
3956
  <section id="instalacion">
3391
- <p class="ds-eyebrow">Sistema</p>
3392
3957
  <h2>Instalación</h2>
3393
3958
  <p class="ds-lead">El sistema se distribuye como paquete npm (<span class="u-mono">@higinio/design-css</span>) y también como archivos sueltos en <span class="u-mono">dist/celeste-clasica/</span>. Instálalo o cópialos, y elige qué importar según tu stack (A/B/C). En todas: <strong>light por defecto</strong>; <span class="u-mono">&lt;html data-theme="dark"&gt;</span> activa el modo oscuro, y los componentes consumen <strong>solo aliases semánticos</strong>, nunca hex.</p>
3394
3959
 
@@ -3453,7 +4018,6 @@ npm i tailwindcss @tailwindcss/postcss
3453
4018
 
3454
4019
  <!-- ============================== MCP ============================== -->
3455
4020
  <section id="mcp">
3456
- <p class="ds-eyebrow">Sistema</p>
3457
4021
  <h2>MCP</h2>
3458
4022
  <p class="ds-lead">El paquete <span class="code">@higinio/design-mcp</span> expone los sistemas de diseño de Higinio Sosa, entre ellos Celeste Clásica (<span class="u-mono">system="celeste"</span>), a cualquier IDE o cliente compatible con Model Context Protocol: tokens, componentes, reglas duras y validación de código. Complementa a las skills de Claude, no las reemplaza: misma fuente de verdad, accesible también fuera del entorno de Claude.</p>
3459
4023
 
@@ -3654,24 +4218,6 @@ npm i tailwindcss @tailwindcss/postcss
3654
4218
  if (heroStart) heroStart.addEventListener("click", function () { scrollToId("componentes"); });
3655
4219
  if (heroTokens) heroTokens.addEventListener("click", function () { scrollToId("tokens"); });
3656
4220
 
3657
- /* ---------- Menú móvil ---------- */
3658
- var burger = d.getElementById("dsHamburger");
3659
- var sidenav = d.getElementById("dsSidenav");
3660
- if (burger && sidenav) {
3661
- burger.addEventListener("click", function (e) {
3662
- e.stopPropagation();
3663
- sidenav.classList.toggle("is-open");
3664
- });
3665
- d.addEventListener("click", function (e) {
3666
- if (sidenav.classList.contains("is-open") && !sidenav.contains(e.target) && e.target !== burger) {
3667
- sidenav.classList.remove("is-open");
3668
- }
3669
- });
3670
- sidenav.addEventListener("click", function (e) {
3671
- if (e.target.closest("a")) sidenav.classList.remove("is-open");
3672
- });
3673
- }
3674
-
3675
4221
  /* ---------- Copiar al portapapeles ---------- */
3676
4222
  function copyText(text, feedbackFn) {
3677
4223
  function done() { if (feedbackFn) feedbackFn(); }
@@ -3695,7 +4241,7 @@ npm i tailwindcss @tailwindcss/postcss
3695
4241
  if (!code) return;
3696
4242
  copyText(code.textContent, function () {
3697
4243
  var prev = btn.textContent;
3698
- btn.textContent = "¡Copiado!";
4244
+ btn.textContent = "Copiado";
3699
4245
  setTimeout(function () { btn.textContent = prev; }, 1600);
3700
4246
  });
3701
4247
  });
@@ -3747,10 +4293,10 @@ npm i tailwindcss @tailwindcss/postcss
3747
4293
  ["--text-primary", "neutral-800", "Texto principal"],
3748
4294
  ["--text-secondary", "neutral-600", "Texto secundario"],
3749
4295
  ["--text-muted", "neutral-500", "Terciario, captions"],
3750
- ["--text-disabled", "neutral-400", "Deshabilitado, placeholder"],
3751
- ["--text-on-primary", "#ffffff", "Texto sobre botón primario"],
3752
- ["--accent", "primary-500", "Rellenos de acción, bordes activos, focus"],
3753
- ["--accent-hover", "primary-600", "Hover del primario"],
4296
+ ["--text-disabled", "neutral-400", "Solo controles deshabilitados"],
4297
+ ["--text-on-primary", "#ffffff", "Texto de compatibilidad sobre acento"],
4298
+ ["--accent", "primary-500", "Firma de marca y acentos de UI"],
4299
+ ["--accent-hover", "primary-600", "Hover del acento de marca"],
3754
4300
  ["--accent-active", "primary-700", "Pressed"],
3755
4301
  ["--accent-soft", "primary-50", "Hover de ghost, fondos sutiles"],
3756
4302
  ["--accent-soft-strong", "primary-100", "Seleccionados suaves"],
@@ -3798,7 +4344,7 @@ npm i tailwindcss @tailwindcss/postcss
3798
4344
  var tr = d.createElement("tr");
3799
4345
  var chipColor = a[1].indexOf("#") === 0 ? a[1] : "var(--" + a[1] + ")";
3800
4346
  tr.innerHTML =
3801
- '<td><span style="display:inline-block;width:24px;height:24px;border-radius:6px;border:1px solid var(--border);background:' + chipColor + '"></span></td>' +
4347
+ '<td><span style="display:inline-block;width:min(100%, 24px);height:24px;border-radius:6px;border:1px solid var(--border);background:' + chipColor + '"></span></td>' +
3802
4348
  '<td class="u-mono">' + a[0] + "</td>" +
3803
4349
  '<td class="u-mono" style="color:var(--text-muted)">' + a[1] + "</td>" +
3804
4350
  "<td>" + a[2] + "</td>";
@@ -3812,7 +4358,7 @@ npm i tailwindcss @tailwindcss/postcss
3812
4358
  var nameEl = sw.querySelector(".ds-swatch__name") || sw.querySelector(".ds-swatch__hex");
3813
4359
  if (!nameEl) return;
3814
4360
  var prev = nameEl.textContent;
3815
- nameEl.textContent = "¡Copiado!";
4361
+ nameEl.textContent = "Copiado";
3816
4362
  setTimeout(function () { nameEl.textContent = prev; }, 1200);
3817
4363
  });
3818
4364
  });
@@ -4097,7 +4643,8 @@ npm i tailwindcss @tailwindcss/postcss
4097
4643
  function dismiss() {
4098
4644
  if (!toast.parentElement) return;
4099
4645
  toast.classList.add("is-leaving");
4100
- toast.addEventListener("animationend", function () { toast.remove(); });
4646
+ toast.addEventListener("animationend", function () { toast.remove(); }, { once: true });
4647
+ setTimeout(function () { toast.remove(); }, 400);
4101
4648
  if (reduceMotion) toast.remove();
4102
4649
  }
4103
4650
  }
@@ -4173,40 +4720,6 @@ npm i tailwindcss @tailwindcss/postcss
4173
4720
  renderPagination();
4174
4721
  }
4175
4722
 
4176
- /* ---------- Count-up de Stat ---------- */
4177
- function countUp(el) {
4178
- var target = parseFloat(el.getAttribute("data-target") || 0);
4179
- var prefix = el.getAttribute("data-prefix") || "";
4180
- var suffix = el.getAttribute("data-suffix") || "";
4181
- function fmt(v) { return prefix + Math.round(v).toLocaleString("es-MX") + suffix; }
4182
- if (reduceMotion) { el.textContent = fmt(target); return; }
4183
- var start = null, DUR = 600;
4184
- function tick(ts) {
4185
- if (start === null) start = ts;
4186
- var t = Math.min(1, (ts - start) / DUR);
4187
- var eased = 1 - Math.pow(1 - t, 3);
4188
- el.textContent = fmt(target * eased);
4189
- if (t < 1) requestAnimationFrame(tick);
4190
- }
4191
- requestAnimationFrame(tick);
4192
- }
4193
- var countEls = d.querySelectorAll(".js-countup");
4194
- if ("IntersectionObserver" in window) {
4195
- var seen = new WeakSet();
4196
- var counter = new IntersectionObserver(function (entries) {
4197
- entries.forEach(function (entry) {
4198
- if (entry.isIntersecting && !seen.has(entry.target)) {
4199
- seen.add(entry.target);
4200
- countUp(entry.target);
4201
- counter.unobserve(entry.target);
4202
- }
4203
- });
4204
- }, { threshold: 0.4 });
4205
- Array.prototype.forEach.call(countEls, function (el) { counter.observe(el); });
4206
- } else {
4207
- Array.prototype.forEach.call(countEls, countUp);
4208
- }
4209
-
4210
4723
  /* ---------- Drawer (§10.29): focus-trap + retorno de foco + Esc ---------- */
4211
4724
  var drawerTrigger = null;
4212
4725
  function openDrawer(dr, trigger) {
@@ -4525,6 +5038,75 @@ npm i tailwindcss @tailwindcss/postcss
4525
5038
  });
4526
5039
  }
4527
5040
  })();
5041
+ </script>
5042
+ <!-- INTERACCIONES COMPARTIDAS GENERADAS -->
5043
+ <script>
5044
+ (function () {
5045
+ "use strict";
5046
+ var trigger = document.getElementById("dsHamburger");
5047
+ var panel = document.getElementById("dsSidenav") || document.getElementById("dsSidebar");
5048
+ var mobile = window.matchMedia("(max-width: 1023px)");
5049
+
5050
+ /**
5051
+ * Actualiza la navegación como disclosure, sin crear una trampa de foco.
5052
+ * @param {boolean} open - Si la navegación móvil debe estar disponible.
5053
+ * @param {boolean} restore - Si el cierre debe devolver foco al disparador.
5054
+ * @returns {void}
5055
+ */
5056
+ function setNavigation(open, restore) {
5057
+ if (!trigger || !panel) return;
5058
+ panel.classList.toggle("is-open", open);
5059
+ panel.inert = mobile.matches && !open;
5060
+ trigger.setAttribute("aria-expanded", String(open));
5061
+ trigger.setAttribute("aria-label", open ? "Cerrar navegación" : "Abrir navegación");
5062
+ if (restore) trigger.focus();
5063
+ }
5064
+
5065
+ if (trigger && panel) {
5066
+ trigger.setAttribute("aria-controls", panel.id);
5067
+ setNavigation(false, false);
5068
+ trigger.addEventListener("click", function () { setNavigation(!panel.classList.contains("is-open"), false); });
5069
+ panel.addEventListener("click", function (event) {
5070
+ var link = event.target.closest("a[href^='#']");
5071
+ if (!link || !mobile.matches) return;
5072
+ var target = document.getElementById(link.hash.slice(1));
5073
+ setNavigation(false, false);
5074
+ if (target) {
5075
+ target.setAttribute("tabindex", "-1");
5076
+ target.focus({ preventScroll: true });
5077
+ }
5078
+ });
5079
+ document.addEventListener("keydown", function (event) {
5080
+ if (event.key === "Escape" && mobile.matches && panel.classList.contains("is-open")) setNavigation(false, true);
5081
+ });
5082
+ document.addEventListener("click", function (event) {
5083
+ if (mobile.matches && !panel.contains(event.target) && !trigger.contains(event.target)) setNavigation(false, false);
5084
+ });
5085
+ mobile.addEventListener("change", function () { setNavigation(false, false); });
5086
+ }
5087
+
5088
+ var themeButton = document.getElementById("dsThemeToggle") || document.getElementById("dsTheme");
5089
+ /**
5090
+ * Nombra la acción de tema y mantiene semántica de ubicación en el índice.
5091
+ * @returns {void}
5092
+ */
5093
+ function updateLabels() {
5094
+ if (themeButton) themeButton.setAttribute("aria-label", document.documentElement.dataset.theme === "dark" ? "Usar tema claro" : "Usar tema oscuro");
5095
+ document.querySelectorAll(".ds-nav a").forEach(function (link) {
5096
+ if (link.classList.contains("is-active")) link.setAttribute("aria-current", "location");
5097
+ else link.removeAttribute("aria-current");
5098
+ });
5099
+ var style = getComputedStyle(document.documentElement);
5100
+ document.querySelectorAll("[data-chart-color]").forEach(function (label) {
5101
+ label.textContent = style.getPropertyValue(label.getAttribute("data-chart-color")).trim();
5102
+ });
5103
+ }
5104
+ updateLabels();
5105
+ new MutationObserver(updateLabels).observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] });
5106
+ var nav = document.querySelector(".ds-nav");
5107
+ if (nav) new MutationObserver(updateLabels).observe(nav, { subtree: true, attributes: true, attributeFilter: ["class"] });
5108
+ })();
5109
+
4528
5110
  </script>
4529
5111
  </body>
4530
5112
  </html>