@higinio/design-mcp 0.1.1 → 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.
@@ -0,0 +1,1591 @@
1
+ /* ============================================================
2
+ Bruma Lavanda — Design Tokens v1.0
3
+ Sistema de diseño de Higinio Sosa · light-first
4
+ Fuente de verdad: DESIGN-bruma-lavanda.md
5
+ Uso: importar ANTES de cualquier estilo propio.
6
+ Los componentes consumen SOLO aliases semánticos, nunca hex.
7
+ ============================================================ */
8
+
9
+ @import url("https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:wght@600;700&family=Atkinson+Hyperlegible+Next:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Atkinson+Hyperlegible+Mono:wght@400;500&display=swap");
10
+
11
+ :root {
12
+ /* == Primitivos: primario (Lavanda) ==
13
+ Lavanda apagada, nunca violeta saturado. El acento no rellena áreas grandes:
14
+ solo controles, estados activos y anillos de foco. */
15
+ --primary-50: #e5e3f1; --primary-100: #d8d5ea; --primary-200: #bdb9da;
16
+ --primary-300: #9d99c4; --primary-400: #7c78a8; --primary-500: #5b578a;
17
+ --primary-600: #4d4979; --primary-700: #403d66; --primary-800: #35334f;
18
+ --primary-900: #2c2b38;
19
+
20
+ /* == Primitivos: neutrales (Niebla) == */
21
+ --neutral-0: #fbfbfd; --neutral-50: #f2f1f6; --neutral-100: #e9e8f0;
22
+ --neutral-200: #dedce8; --neutral-300: #b8b6c8; --neutral-400: #86849a;
23
+ --neutral-500: #5d5b6e; --neutral-600: #48475a; --neutral-700: #393846;
24
+ --neutral-800: #2c2b38; --neutral-900: #1f1e28;
25
+
26
+ /* == Primitivos: semánticos (ramp de 3: sólido / fondo / texto AA) ==
27
+ El éxito es verde azulado, lejos del acento lavanda: el acento nunca comunica éxito. */
28
+ --success-500: #2f7a68; --success-100: #dcefe9; --success-text: #235e50;
29
+ --warning-500: #b07f2a; --warning-100: #f5ecd9; --warning-text: #7a5716;
30
+ --danger-500: #b24c55; --danger-100: #f6e3e5; --danger-text: #8b3540;
31
+ --info-500: #4f7896; --info-100: #e1eaf1; --info-text: #3a5b74;
32
+
33
+ /* == Aliases semánticos (los componentes consumen SOLO esto) == */
34
+ --bg: var(--neutral-50);
35
+ --surface: var(--neutral-0);
36
+ --surface-alt: var(--neutral-100);
37
+ --border: var(--neutral-200);
38
+ --border-strong: var(--neutral-400);
39
+ --text-primary: var(--neutral-800);
40
+ --text-secondary: var(--neutral-600);
41
+ --text-muted: var(--neutral-500);
42
+ --text-disabled: var(--neutral-400);
43
+ --text-on-primary: #ffffff;
44
+ --text-on-primary-solid: var(--primary-700);
45
+ --accent: var(--primary-500);
46
+ --accent-hover: var(--primary-600);
47
+ --accent-active: var(--primary-700);
48
+ --accent-soft: var(--primary-50);
49
+ --accent-soft-strong: var(--primary-100);
50
+ --link: var(--primary-600); /* AA 7.98:1 sobre --surface — texto de links y ghost */
51
+
52
+ /* == Tipografía == */
53
+ --font-display: "Bricolage Grotesque", system-ui, sans-serif;
54
+ --font-body: "Atkinson Hyperlegible Next", system-ui, -apple-system, sans-serif;
55
+ --font-mono: "Atkinson Hyperlegible Mono", ui-monospace, monospace;
56
+ --text-xs: .75rem; --text-sm: .875rem; --text-base: 1rem; --text-lg: 1.125rem;
57
+ --text-xl: 1.25rem; --text-2xl: 1.5625rem; --text-3xl: 1.9375rem;
58
+ --text-4xl: 2.4375rem; --text-5xl: 3.0625rem;
59
+ --leading-xs: 1.5; --leading-sm: 1.5; --leading-base: 1.6; --leading-lg: 1.55;
60
+ --leading-xl: 1.4; --leading-2xl: 1.3; --leading-3xl: 1.25;
61
+ --leading-4xl: 1.15; --leading-5xl: 1.1;
62
+ --tracking-display: -0.02em; --tracking-body: 0; --tracking-label: 0.04em;
63
+ --weight-regular: 400; --weight-medium: 500; --weight-semibold: 600; --weight-bold: 700;
64
+ --measure: 65ch;
65
+
66
+ /* == Espaciado (escala base 4px; densidad algo compacta) == */
67
+ --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
68
+ --space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px;
69
+ --space-12: 48px; --space-16: 64px; --space-20: 80px; --space-24: 96px;
70
+ --card-padding: var(--space-5); --card-padding-mobile: var(--space-4);
71
+ --section-gap: var(--space-12); --form-gap: var(--space-5);
72
+ --button-padding-md: 12px 20px; --button-padding-sm: 8px 14px;
73
+ --control-height-sm: 36px; --control-height-md: 44px; --control-height-lg: 52px;
74
+ --gutter: 24px; --gutter-mobile: 16px;
75
+
76
+ /* == Radios, bordes y sombras ==
77
+ La elevación se apoya en el borde; las sombras son mínimas y van
78
+ teñidas de la tinta, nunca negro puro. */
79
+ --radius-sm: 6px; --radius-md: 8px; --radius-lg: 12px;
80
+ --radius-xl: 16px; --radius-full: 9999px;
81
+ --border-width: 1px;
82
+ --shadow-xs: 0 1px 1px rgba(44,43,56,.04);
83
+ --shadow-sm: 0 1px 2px rgba(44,43,56,.06);
84
+ --shadow-md: 0 2px 6px rgba(44,43,56,.07), 0 1px 2px rgba(44,43,56,.04);
85
+ --shadow-lg: 0 8px 20px rgba(44,43,56,.09), 0 2px 6px rgba(44,43,56,.05);
86
+ --shadow-xl: 0 16px 36px rgba(44,43,56,.12);
87
+
88
+ /* == Focus == */
89
+ --ring: 0 0 0 3px rgba(91,87,138,.25);
90
+ --ring-color: rgba(91,87,138,.25);
91
+
92
+ /* == Motion (corto y preciso) == */
93
+ --duration-instant: 100ms; --duration-fast: 140ms; --duration-base: 180ms;
94
+ --duration-slow: 240ms; --duration-page: 300ms;
95
+ --ease-out: cubic-bezier(0.2, 0, 0, 1);
96
+ --ease-in: cubic-bezier(0.4, 0, 1, 1);
97
+ --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1); /* moverse de A a B en pantalla */
98
+ --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
99
+ --stagger-step: 30ms;
100
+
101
+ color-scheme: light;
102
+
103
+ --overlay: rgba(31, 30, 40, .5);
104
+ --tooltip-bg: var(--neutral-900);
105
+ --tooltip-text: var(--neutral-0);
106
+ --focus-color: var(--accent);
107
+ --text-on-danger: var(--neutral-0);
108
+ --border-hover: var(--neutral-500);
109
+ --ring-danger: 0 0 0 3px rgba(178,76,85,.22);
110
+
111
+ --action-bg: var(--accent);
112
+ --action-hover: var(--accent-hover);
113
+ --action-active: var(--accent-active);
114
+ --text-on-action: var(--text-on-primary);
115
+ --control-border: var(--border-strong);
116
+ --placeholder: var(--text-muted);
117
+ --selection-bg: var(--action-bg);
118
+ --selection-text: var(--text-on-action);
119
+ --font-ui-heading: var(--font-body);
120
+ --text-ui-title: 2rem;
121
+ --touch-target: 44px;
122
+ --text-display-fluid: clamp(2.5rem, 1.8rem + 2.2vw, 4.25rem);
123
+
124
+ /* Series categóricas: orden estable; acompañar con etiqueta o forma. */
125
+ --chart-1: #857bc1;
126
+ --chart-2: #8a600a;
127
+ --chart-3: #4a8cc1;
128
+ --chart-4: #853f63;
129
+ --chart-5: #129a92;
130
+ --chart-6: #8e4031;
131
+ --chart-7: #5b975e;
132
+ /* Ritmo de contenido y formularios. */
133
+ --field-gap: 6px;
134
+ --heading-gap: var(--space-2);
135
+ --content-gap: var(--space-4);
136
+ --card-content-gap: var(--space-4);
137
+ --card-group-gap: var(--space-5);
138
+
139
+ }
140
+
141
+ /* == Modo oscuro (variante) — alternar data-theme en <html> ==
142
+ Sin sombras en las capas: se separan por superficie y borde, y solo
143
+ los overlays (lg/xl) conservan una sombra tenue. */
144
+ [data-theme="dark"] {
145
+ --bg: #16151c;
146
+ --surface: #1f1e27;
147
+ --surface-alt: #27262f;
148
+ --border: #2f2d3a;
149
+ --border-strong: #747189;
150
+ --text-primary: #e7e6ef;
151
+ --text-secondary: #c9c7d6;
152
+ --text-muted: #aaa8bb;
153
+ --text-disabled: #7b7990;
154
+ --accent: #b0acdc;
155
+ --accent-hover: #c4c1e6;
156
+ --accent-active: #9d98cf;
157
+ --accent-soft: #2b2940;
158
+ --accent-soft-strong: #36334f;
159
+ --text-on-primary: #16151c;
160
+ --text-on-primary-solid: #c4c1e6;
161
+ --link: #c4c1e6;
162
+ --success-500: #6cc1ad; --success-100: #13261f; --success-text: #8bd1c0;
163
+ --warning-500: #d6a752; --warning-100: #29220f; --warning-text: #e4c07f;
164
+ --danger-500: #e08890; --danger-100: #2c171a; --danger-text: #eba4ab;
165
+ --info-500: #8daecb; --info-100: #172129; --info-text: #a8c3da;
166
+ --ring: 0 0 0 3px rgba(176,172,220,.3);
167
+ --ring-color: rgba(176,172,220,.3);
168
+ --shadow-xs: none;
169
+ --shadow-sm: none;
170
+ --shadow-md: none;
171
+ --shadow-lg: 0 8px 20px rgba(8,8,12,.28);
172
+ --shadow-xl: 0 16px 32px rgba(8,8,12,.32);
173
+ color-scheme: dark;
174
+
175
+ --overlay: rgba(0, 0, 0, .6);
176
+ --tooltip-bg: #e7e6ef;
177
+ --tooltip-text: #1f1e28;
178
+ --focus-color: var(--accent);
179
+ --text-on-danger: #16151c;
180
+ --border-hover: #aaa8bb;
181
+ --ring-danger: 0 0 0 3px rgba(224,136,144,.25);
182
+
183
+ --selection-bg: var(--action-bg);
184
+ --selection-text: var(--text-on-action);
185
+
186
+ /* Series categóricas: orden estable; acompañar con etiqueta o forma. */
187
+ --chart-1: #877cc3;
188
+ --chart-2: #946a1c;
189
+ --chart-3: #5798ce;
190
+ --chart-4: #a0587c;
191
+ --chart-5: #2aa79e;
192
+ --chart-6: #aa5849;
193
+ --chart-7: #67a369;
194
+ }
195
+
196
+ /* == Accesibilidad del movimiento == */
197
+
198
+ @media (prefers-reduced-motion: reduce) {
199
+ :root {
200
+ --duration-instant: 0ms; --duration-fast: 0ms; --duration-base: 0ms;
201
+ --duration-slow: 0ms; --duration-page: 0ms; --stagger-step: 0ms;
202
+ }
203
+ }
204
+
205
+ *, *::before, *::after { box-sizing: border-box; }
206
+
207
+ /* Focus ring global de teclado — especificidad cero vía :where() */
208
+ :where(a, button, [role="button"], input, select, textarea, summary, [tabindex]):focus-visible {
209
+ outline: 2px solid var(--focus-color);
210
+ outline-offset: 2px;
211
+ border-radius: 2px;
212
+ }
213
+
214
+ .bruma-reset {
215
+ margin: 0;
216
+ background: var(--bg);
217
+ color: var(--text-primary);
218
+ font-family: var(--font-body);
219
+ font-size: var(--text-base);
220
+ line-height: var(--leading-base);
221
+ letter-spacing: var(--tracking-body);
222
+ -webkit-font-smoothing: antialiased;
223
+ text-rendering: optimizeLegibility;
224
+ }
225
+ .bruma-reset h1, .bruma-reset h2 {
226
+ font-family: var(--font-display);
227
+ font-weight: var(--weight-bold);
228
+ letter-spacing: var(--tracking-display);
229
+ color: var(--text-primary);
230
+ margin: 0 0 .5em;
231
+ }
232
+ .bruma-reset h1 { font-size: var(--text-4xl); line-height: var(--leading-4xl); }
233
+ .bruma-reset h2 { font-size: var(--text-3xl); line-height: var(--leading-3xl); font-weight: var(--weight-semibold); }
234
+ .bruma-reset h3, .bruma-reset h4, .bruma-reset h5, .bruma-reset h6 {
235
+ font-family: var(--font-body);
236
+ font-weight: var(--weight-semibold);
237
+ color: var(--text-primary);
238
+ margin: 0 0 .5em;
239
+ }
240
+ .bruma-reset h3 { font-size: var(--text-2xl); line-height: var(--leading-2xl); }
241
+ .bruma-reset h4 { font-size: var(--text-xl); line-height: var(--leading-xl); }
242
+ .bruma-reset h5 { font-size: var(--text-lg); line-height: var(--leading-lg); }
243
+ .bruma-reset h6 { font-size: var(--text-base); line-height: var(--leading-base); }
244
+ .bruma-reset p { max-width: var(--measure); margin: 0 0 1em; }
245
+ .bruma-reset table { font-variant-numeric: tabular-nums; }
246
+ .bruma-reset ::placeholder { color: var(--placeholder); }
247
+ .bruma-reset ::selection { background: var(--ring-color); }
248
+
249
+
250
+
251
+ /* --------------------------------------------------------------------------
252
+ 3. LAYOUT — contenedor, grid 12 col (§14)
253
+ -------------------------------------------------------------------------- */
254
+ .container { width: 100%; margin-inline: auto; padding-inline: var(--gutter-mobile); }
255
+ @media (min-width: 640px) { .container { padding-inline: var(--space-4); } }
256
+ @media (min-width: 768px) { .container { max-width: 720px; } }
257
+ @media (min-width: 1024px) { .container { max-width: 960px; } }
258
+ @media (min-width: 1280px) { .container { max-width: 1200px; } }
259
+
260
+ .grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--gutter-mobile); }
261
+ @media (min-width: 768px) { .grid { gap: var(--gutter); } }
262
+ .col-1{grid-column:span 1}.col-2{grid-column:span 2}.col-3{grid-column:span 3}
263
+ .col-4{grid-column:span 4}.col-5{grid-column:span 5}.col-6{grid-column:span 6}
264
+ .col-7{grid-column:span 7}.col-8{grid-column:span 8}.col-9{grid-column:span 9}
265
+ .col-10{grid-column:span 10}.col-11{grid-column:span 11}.col-12{grid-column:span 12}
266
+ @media (min-width: 768px) {
267
+ .col-md-3{grid-column:span 3}.col-md-4{grid-column:span 4}
268
+ .col-md-6{grid-column:span 6}.col-md-8{grid-column:span 8}.col-md-12{grid-column:span 12}
269
+ }
270
+ @media (min-width: 1024px) {
271
+ .col-lg-3{grid-column:span 3}.col-lg-4{grid-column:span 4}
272
+ .col-lg-6{grid-column:span 6}.col-lg-8{grid-column:span 8}.col-lg-12{grid-column:span 12}
273
+ }
274
+
275
+ /* --------------------------------------------------------------------------
276
+ 4. BOTONES (§10.1) · ICON BUTTON (§10.2) · SPINNER (§10.3)
277
+ -------------------------------------------------------------------------- */
278
+ .btn {
279
+ display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
280
+ height: var(--control-height-md); padding: var(--button-padding-md);
281
+ border: var(--border-width) solid transparent; border-radius: var(--radius-md);
282
+ font-family: var(--font-body); font-size: var(--text-base); font-weight: var(--weight-semibold);
283
+ line-height: 1; color: var(--text-primary); background: transparent;
284
+ cursor: pointer; text-decoration: none; white-space: nowrap; user-select: none;
285
+ transition: background-color var(--duration-fast) var(--ease-out),
286
+ border-color var(--duration-fast) var(--ease-out),
287
+ box-shadow var(--duration-fast) var(--ease-out),
288
+ transform var(--duration-instant) var(--ease-out);
289
+ }
290
+ .btn:active:not(:disabled) { transform: scale(.98); }
291
+ .btn:disabled { cursor: not-allowed; }
292
+ .btn svg { width: 20px; height: 20px; flex: none; }
293
+
294
+ /* Gating de hover (§11.5): los hover que mueven/elevan (transform, box-shadow) van
295
+ dentro de @media (hover: hover) and (pointer: fine) — en touch el tap dispara
296
+ hovers falsos que se quedan pegados. Los hover de solo color/fondo quedan fuera. */
297
+ .btn--primary { background: var(--action-bg); color: var(--text-on-action); }
298
+ .btn--primary:hover:not(:disabled) { background: var(--action-hover); }
299
+ @media (hover: hover) and (pointer: fine) {
300
+ .btn--primary:hover:not(:disabled) { box-shadow: var(--shadow-sm); }
301
+ }
302
+ .btn--primary:active:not(:disabled) { background: var(--action-active); box-shadow: none; }
303
+ .btn--primary:disabled { background: var(--border); color: var(--text-disabled); box-shadow: none; }
304
+
305
+ .btn--secondary { background: var(--surface); border-color: var(--border-strong); color: var(--text-primary); }
306
+ .btn--secondary:hover:not(:disabled) { background: var(--bg); }
307
+ .btn--secondary:active:not(:disabled) { background: var(--surface-alt); }
308
+ .btn--secondary:disabled { opacity: .5; }
309
+
310
+ .btn--outline { background: transparent; border-color: var(--accent); color: var(--link); }
311
+ .btn--outline:hover:not(:disabled) { background: var(--accent-soft); border-color: var(--accent-hover); }
312
+ .btn--outline:active:not(:disabled) { background: var(--accent-soft-strong); }
313
+ .btn--outline:disabled { opacity: .5; }
314
+
315
+ .btn--ghost { color: var(--link); }
316
+ .btn--ghost:hover:not(:disabled) { background: var(--accent-soft); }
317
+ .btn--ghost:active:not(:disabled) { background: var(--accent-soft-strong); }
318
+ .btn--ghost:disabled { background: var(--border); color: var(--text-disabled); }
319
+
320
+ .btn--danger { background: var(--danger-500); color: var(--text-on-danger); }
321
+ .btn--danger:hover:not(:disabled) { background: color-mix(in srgb, var(--danger-500) 92%, black); }
322
+ .btn--danger:active:not(:disabled) { background: color-mix(in srgb, var(--danger-500) 86%, black); }
323
+ .btn--danger:disabled { opacity: .5; }
324
+
325
+ .btn--sm { height: var(--control-height-sm); padding: var(--button-padding-sm); font-size: var(--text-sm); }
326
+ .btn--lg { height: var(--control-height-lg); padding: 14px 24px; font-size: var(--text-lg); }
327
+
328
+ /* IconButton — requiere aria-label */
329
+ .icon-btn {
330
+ display: inline-grid; place-items: center;
331
+ width: var(--control-height-md); height: var(--control-height-md); padding: 0; flex: none;
332
+ border: var(--border-width) solid transparent; border-radius: var(--radius-md);
333
+ background: transparent; color: var(--text-secondary); cursor: pointer;
334
+ transition: background-color var(--duration-fast) var(--ease-out),
335
+ border-color var(--duration-fast) var(--ease-out),
336
+ transform var(--duration-instant) var(--ease-out);
337
+ }
338
+ .icon-btn:active:not(:disabled) { transform: scale(.98); }
339
+ .icon-btn:disabled { opacity: .5; cursor: not-allowed; }
340
+ .icon-btn svg { width: 18px; height: 18px; }
341
+ .icon-btn--sm { width: 32px; height: 32px; } .icon-btn--sm svg { width: 16px; height: 16px; }
342
+ .icon-btn--lg { width: 48px; height: 48px; } .icon-btn--lg svg { width: 20px; height: 20px; }
343
+ .icon-btn--ghost:hover:not(:disabled) { background: var(--surface-alt); color: var(--text-primary); }
344
+ .icon-btn--primary { background: var(--accent); color: var(--text-on-primary); }
345
+ .icon-btn--primary:hover:not(:disabled) { background: var(--accent-hover); }
346
+ .icon-btn--secondary { background: var(--surface); border-color: var(--border-strong); }
347
+ .icon-btn--secondary:hover:not(:disabled) { background: var(--bg); }
348
+
349
+ /* Spinner */
350
+ .spinner { width: 16px; height: 16px; animation: bl-spin .8s linear infinite; color: var(--accent); }
351
+ .spinner circle { opacity: .25; }
352
+ .spinner path { opacity: 1; }
353
+ @keyframes bl-spin { to { transform: rotate(360deg); } }
354
+
355
+ /* --------------------------------------------------------------------------
356
+ 5. FORMULARIOS — field, input, textarea, select (§10.4–10.6)
357
+ -------------------------------------------------------------------------- */
358
+ .field { display: flex; flex-direction: column; gap: 6px; }
359
+ .field__label { font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-secondary); }
360
+ .field__help { font-size: var(--text-sm); color: var(--text-muted); }
361
+ .field__error { font-size: var(--text-sm); color: var(--danger-text); display: inline-flex; align-items: center; gap: 6px; }
362
+ .field__error svg { width: 14px; height: 14px; flex: none; }
363
+ /* Campo obligatorio (§10.4): asterisco decorativo; el input lleva required/aria-required */
364
+ .field--required .field__label::after { content: " *"; color: var(--danger-text); }
365
+
366
+ .input, .textarea, .select {
367
+ width: 100%; font-family: var(--font-body); font-size: var(--text-base);
368
+ color: var(--text-primary); background: var(--surface);
369
+ border: var(--border-width) solid var(--control-border); border-radius: var(--radius-sm);
370
+ transition: border-color var(--duration-fast) var(--ease-out),
371
+ box-shadow var(--duration-fast) var(--ease-out);
372
+ }
373
+ .input, .select { height: var(--control-height-md); padding: 0 14px; }
374
+ .input:hover:not(:disabled):not(:focus),
375
+ .textarea:hover:not(:disabled):not(:focus),
376
+ .select:hover:not(:disabled):not(:focus) { border-color: var(--border-hover); }
377
+ .input:focus, .textarea:focus, .select:focus {
378
+ outline: none; border-color: var(--accent); box-shadow: var(--ring);
379
+ }
380
+ .input:disabled, .textarea:disabled, .select:disabled {
381
+ background: var(--surface-alt); color: var(--text-disabled); cursor: not-allowed;
382
+ }
383
+ .input--error, .input--error:focus, .textarea--error { border-color: var(--danger-500); box-shadow: var(--ring-danger); }
384
+ .input--success { border-color: var(--success-500); }
385
+
386
+ .input-icon { position: relative; }
387
+ .input-icon > svg {
388
+ position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
389
+ width: 18px; height: 18px; color: var(--text-disabled); pointer-events: none;
390
+ }
391
+ .input-icon .input { padding-left: 40px; }
392
+
393
+ .textarea { min-height: 96px; padding: 12px 14px; resize: vertical; line-height: var(--leading-base); }
394
+ .textarea-counter { font-size: var(--text-xs); color: var(--text-muted); text-align: right; }
395
+
396
+ .select-wrap { position: relative; }
397
+ .select { appearance: none; padding-right: 38px; cursor: pointer; }
398
+ .select-wrap::after {
399
+ content: ""; position: absolute; right: 14px; top: 50%;
400
+ width: 16px; height: 16px; transform: translateY(-50%);
401
+ background: currentColor; color: var(--text-muted); pointer-events: none;
402
+ -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>') center / contain no-repeat;
403
+ mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>') center / contain no-repeat;
404
+ transition: transform var(--duration-base) var(--ease-out);
405
+ }
406
+
407
+ /* --------------------------------------------------------------------------
408
+ 6. SEGMENTED CONTROL (§10.7) · SLIDER (§10.8)
409
+ -------------------------------------------------------------------------- */
410
+ .segmented {
411
+ display: inline-flex; align-items: stretch;
412
+ background: var(--surface-alt); border-radius: var(--radius-md); padding: 3px;
413
+ height: 40px;
414
+ }
415
+ .segmented--sm { height: 32px; }
416
+ .segmented input { position: absolute; opacity: 0; pointer-events: none; }
417
+ .segmented label {
418
+ display: inline-flex; align-items: center; padding: 0 16px;
419
+ border-radius: calc(var(--radius-md) - 3px);
420
+ font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-secondary);
421
+ cursor: pointer; user-select: none; white-space: nowrap;
422
+ transition: background-color var(--duration-base) var(--ease-out),
423
+ color var(--duration-fast) var(--ease-out),
424
+ box-shadow var(--duration-base) var(--ease-out);
425
+ }
426
+ .segmented input:checked + label {
427
+ background: var(--surface); color: var(--text-primary);
428
+ font-weight: var(--weight-semibold); box-shadow: var(--shadow-xs);
429
+ }
430
+ .segmented input:focus-visible + label { outline: 2px solid var(--focus-color); outline-offset: 2px; }
431
+
432
+ .slider-row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 10px; }
433
+ .slider-row .slider-label { font-size: var(--text-sm); color: var(--text-secondary); }
434
+ .slider-row .slider-value { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted); }
435
+ .slider {
436
+ -webkit-appearance: none; appearance: none;
437
+ width: 100%; height: 6px; border-radius: var(--radius-full);
438
+ background: linear-gradient(to right, var(--accent) var(--slider-fill, 50%), var(--border) var(--slider-fill, 50%));
439
+ cursor: pointer;
440
+ }
441
+ .slider:disabled { opacity: .5; cursor: not-allowed; }
442
+ .slider::-webkit-slider-thumb {
443
+ -webkit-appearance: none; width: 18px; height: 18px; border-radius: 50%;
444
+ background: var(--surface); border: 2px solid var(--accent); box-shadow: var(--shadow-sm);
445
+ transition: transform var(--duration-instant) var(--ease-out);
446
+ }
447
+ .slider:active::-webkit-slider-thumb { transform: scale(1.15); }
448
+ .slider::-moz-range-thumb {
449
+ width: 14px; height: 14px; border-radius: 50%;
450
+ background: var(--surface); border: 2px solid var(--accent); box-shadow: var(--shadow-sm);
451
+ transition: transform var(--duration-instant) var(--ease-out);
452
+ }
453
+ .slider:active::-moz-range-thumb { transform: scale(1.15); }
454
+
455
+ /* --------------------------------------------------------------------------
456
+ 7. SELECCIÓN — checkbox, radio, switch (§10.9–10.10)
457
+ -------------------------------------------------------------------------- */
458
+ .checkbox, .radio {
459
+ display: inline-flex; align-items: center; gap: 10px;
460
+ font-size: var(--text-base); color: var(--text-primary); cursor: pointer; position: relative;
461
+ }
462
+ .checkbox input, .radio input, .switch input {
463
+ position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0;
464
+ }
465
+ .checkbox__box {
466
+ width: 20px; height: 20px; flex: none; display: grid; place-items: center;
467
+ background: var(--surface); border: 2px solid var(--control-border); border-radius: 4px;
468
+ transition: background-color var(--duration-fast) var(--ease-out),
469
+ border-color var(--duration-fast) var(--ease-out);
470
+ }
471
+ .checkbox__box svg {
472
+ width: 12px; height: 12px; fill: none; stroke: var(--text-on-primary);
473
+ stroke-width: 3; stroke-linecap: round; stroke-linejoin: round;
474
+ stroke-dasharray: 20; stroke-dashoffset: 20;
475
+ transition: stroke-dashoffset var(--duration-base) var(--ease-spring);
476
+ }
477
+ .checkbox:hover .checkbox__box { border-color: var(--focus-color); }
478
+ .checkbox input:checked ~ .checkbox__box { background: var(--accent); border-color: var(--accent); }
479
+ .checkbox input:checked ~ .checkbox__box svg { stroke-dashoffset: 0; }
480
+ .checkbox input:focus-visible ~ .checkbox__box { box-shadow: var(--ring); }
481
+ .checkbox input:disabled ~ * { opacity: .5; cursor: not-allowed; }
482
+ /* Estado indeterminate (§10.9): guion horizontal para "seleccionar todo" parcial */
483
+ .checkbox__box { position: relative; }
484
+ .checkbox input:indeterminate ~ .checkbox__box { background: var(--accent); border-color: var(--accent); }
485
+ .checkbox input:indeterminate ~ .checkbox__box svg { visibility: hidden; }
486
+ .checkbox input:indeterminate ~ .checkbox__box::after {
487
+ content: ""; position: absolute; top: 50%; left: 50%;
488
+ width: 10px; height: 2px;
489
+ background: var(--text-on-primary); transform: translate(-50%, -50%);
490
+ }
491
+
492
+ .radio__dot {
493
+ width: 20px; height: 20px; flex: none; display: grid; place-items: center;
494
+ background: var(--surface); border: 2px solid var(--control-border); border-radius: var(--radius-full);
495
+ transition: background-color var(--duration-fast) var(--ease-out),
496
+ border-color var(--duration-fast) var(--ease-out);
497
+ }
498
+ .radio__dot::after {
499
+ content: ""; width: 8px; height: 8px; border-radius: 50%;
500
+ background: var(--text-on-primary); transform: scale(0);
501
+ transition: transform var(--duration-base) var(--ease-spring);
502
+ }
503
+ .radio:hover .radio__dot { border-color: var(--focus-color); }
504
+ .radio input:checked ~ .radio__dot { background: var(--accent); border-color: var(--accent); }
505
+ .radio input:checked ~ .radio__dot::after { transform: scale(1); }
506
+ .radio input:focus-visible ~ .radio__dot { box-shadow: var(--ring); }
507
+
508
+ .switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; position: relative; font-size: var(--text-base); }
509
+ .switch__track {
510
+ width: 44px; height: 24px; flex: none; border-radius: var(--radius-full);
511
+ background: var(--border-strong); position: relative;
512
+ transition: background-color var(--duration-base) var(--ease-out);
513
+ }
514
+ .switch__track::after {
515
+ content: ""; position: absolute; top: 2px; left: 2px;
516
+ width: 20px; height: 20px; border-radius: 50%;
517
+ background: var(--neutral-0); box-shadow: var(--shadow-xs);
518
+ transition: transform var(--duration-base) var(--ease-spring);
519
+ }
520
+ .switch input:checked ~ .switch__track { background: var(--accent); }
521
+ .switch input:checked ~ .switch__track::after { transform: translateX(20px); }
522
+ .switch input:focus-visible ~ .switch__track { box-shadow: var(--ring); }
523
+ .switch input:disabled ~ * { opacity: .5; cursor: not-allowed; }
524
+
525
+ /* --------------------------------------------------------------------------
526
+ 8. SUPERFICIES — card, badge, tag, avatar, divider, accordion (§10.11–10.14)
527
+ -------------------------------------------------------------------------- */
528
+ .card {
529
+ background: var(--surface); border: var(--border-width) solid var(--border);
530
+ border-radius: var(--radius-lg); padding: var(--card-padding);
531
+ box-shadow: var(--shadow-sm);
532
+ }
533
+ @media (max-width: 639px) { .card { padding: var(--card-padding-mobile); } }
534
+ .card--interactive {
535
+ cursor: pointer;
536
+ transition: border-color var(--duration-base) var(--ease-out);
537
+ }
538
+ @media (hover: hover) and (pointer: fine) {
539
+ .card--interactive:hover { border-color: var(--border-strong); }
540
+ }
541
+
542
+ .badge {
543
+ display: inline-flex; align-items: center; gap: 4px;
544
+ font-size: var(--text-xs); font-weight: var(--weight-medium);
545
+ padding: 2px 8px; border-radius: var(--radius-full);
546
+ background: var(--surface-alt); color: var(--text-secondary);
547
+ }
548
+ .badge svg { width: 12px; height: 12px; }
549
+ .badge--success { background: var(--success-100); color: var(--success-text); }
550
+ .badge--warning { background: var(--warning-100); color: var(--warning-text); }
551
+ .badge--danger { background: var(--danger-100); color: var(--danger-text); }
552
+ .badge--info { background: var(--info-100); color: var(--info-text); }
553
+
554
+ .tag {
555
+ display: inline-flex; align-items: center; gap: 6px;
556
+ font-size: var(--text-xs); font-weight: var(--weight-medium);
557
+ padding: 3px 6px 3px 10px; border-radius: var(--radius-full);
558
+ background: var(--surface-alt); color: var(--text-secondary);
559
+ border: var(--border-width) solid var(--border);
560
+ }
561
+ .tag__close {
562
+ position: relative; display: grid; place-items: center; width: 16px; height: 16px;
563
+ border: 0; border-radius: 50%; background: transparent; color: inherit; cursor: pointer;
564
+ transition: background-color var(--duration-fast) var(--ease-out);
565
+ }
566
+ .tag__close:hover { background: var(--border); }
567
+ .tag__close svg { width: 10px; height: 10px; }
568
+
569
+ .avatar {
570
+ position: relative; display: inline-flex; flex: none;
571
+ width: 36px; height: 36px; font-size: 14px;
572
+ }
573
+ .avatar--sm { width: 28px; height: 28px; font-size: 12px; }
574
+ .avatar--lg { width: 48px; height: 48px; font-size: 18px; }
575
+ .avatar--xl { width: 64px; height: 64px; font-size: 24px; }
576
+ .avatar__img, .avatar__initials {
577
+ width: 100%; height: 100%; border-radius: var(--radius-full);
578
+ }
579
+ .avatar__img { object-fit: cover; }
580
+ .avatar__initials {
581
+ display: grid; place-items: center;
582
+ background: var(--accent-soft-strong); color: var(--text-on-primary-solid);
583
+ font-weight: var(--weight-semibold); text-transform: uppercase;
584
+ }
585
+ .avatar__dot {
586
+ position: absolute; right: 0; bottom: 0;
587
+ width: 28%; height: 28%; min-width: 8px; min-height: 8px;
588
+ border-radius: 50%; box-shadow: 0 0 0 2px var(--surface);
589
+ background: var(--neutral-300);
590
+ }
591
+ .avatar__dot--online { background: var(--success-500); }
592
+ .avatar__dot--busy { background: var(--danger-500); }
593
+ .avatar__dot--away { background: var(--warning-500); }
594
+
595
+ /* AvatarGroup (§10.27): stack solapado con anillo de superficie */
596
+ .avatar-group { display: inline-flex; align-items: center; }
597
+ .avatar-group .avatar { border: 2px solid var(--surface); border-radius: var(--radius-full); }
598
+ .avatar-group .avatar + .avatar,
599
+ .avatar-group .avatar-group__more { margin-left: -8px; }
600
+ .avatar-group__more {
601
+ display: grid; place-items: center; flex: none;
602
+ width: 36px; height: 36px; border-radius: var(--radius-full);
603
+ border: 2px solid var(--surface);
604
+ background: var(--accent-soft-strong); color: var(--text-on-primary-solid);
605
+ font-family: var(--font-body); font-size: var(--text-xs); font-weight: var(--weight-semibold);
606
+ }
607
+
608
+ .divider { border: 0; border-top: var(--border-width) solid var(--border); margin: var(--space-4) 0; }
609
+ .divider--label {
610
+ display: flex; align-items: center; gap: 12px; border: 0; margin: var(--space-4) 0;
611
+ color: var(--text-muted); font-size: var(--text-xs); font-weight: var(--weight-medium);
612
+ text-transform: uppercase; letter-spacing: var(--tracking-label);
613
+ }
614
+ .divider--label::before, .divider--label::after {
615
+ content: ""; flex: 1; border-top: var(--border-width) solid var(--border);
616
+ }
617
+ .divider--vertical {
618
+ display: inline-block; align-self: stretch; width: var(--border-width);
619
+ background: var(--border); border: 0; margin: 0 var(--space-3);
620
+ }
621
+
622
+ .accordion {
623
+ border: var(--border-width) solid var(--border); border-radius: var(--radius-lg);
624
+ background: var(--surface); overflow: hidden;
625
+ }
626
+ .accordion__item + .accordion__item { border-top: var(--border-width) solid var(--border); }
627
+ .accordion__header {
628
+ display: flex; align-items: center; justify-content: space-between; gap: 12px;
629
+ width: 100%; padding: 16px 20px; border: 0; background: transparent;
630
+ font-family: var(--font-body); font-size: var(--text-base); font-weight: var(--weight-medium);
631
+ color: var(--text-primary); text-align: left; cursor: pointer;
632
+ transition: background-color var(--duration-fast) var(--ease-out);
633
+ }
634
+ .accordion__header:hover { background: var(--bg); }
635
+ .accordion__header svg {
636
+ width: 18px; height: 18px; flex: none; color: var(--text-muted);
637
+ transition: transform var(--duration-base) var(--ease-out);
638
+ }
639
+ .accordion__item.is-open .accordion__header svg { transform: rotate(180deg); }
640
+ .accordion__panel {
641
+ display: grid; grid-template-rows: 0fr;
642
+ transition: grid-template-rows var(--duration-slow) var(--ease-out);
643
+ }
644
+ .accordion__item.is-open .accordion__panel { grid-template-rows: 1fr; }
645
+ .accordion__panel > div { overflow: hidden; }
646
+ .accordion__content {
647
+ padding: 0 20px 16px; font-size: var(--text-sm); color: var(--text-secondary);
648
+ opacity: 0; transition: opacity var(--duration-slow) var(--ease-out);
649
+ }
650
+ .accordion__item.is-open .accordion__content { opacity: 1; }
651
+
652
+ /* --------------------------------------------------------------------------
653
+ 9. FEEDBACK — tooltip, alert, toast, progress, skeleton, empty state
654
+ (§10.15–10.18, §10.25)
655
+ -------------------------------------------------------------------------- */
656
+ [data-tooltip] { position: relative; }
657
+ [data-tooltip]::after {
658
+ content: attr(data-tooltip);
659
+ position: absolute; bottom: calc(100% + 8px); left: 50%;
660
+ transform: translate(-50%, 4px);
661
+ background: var(--tooltip-bg); color: var(--tooltip-text);
662
+ font-size: var(--text-xs); line-height: 1.4; white-space: nowrap;
663
+ padding: 6px 10px; border-radius: var(--radius-sm);
664
+ opacity: 0; pointer-events: none; z-index: 70;
665
+ transition: opacity var(--duration-fast) var(--ease-out) 0s,
666
+ transform var(--duration-fast) var(--ease-out) 0s;
667
+ }
668
+ [data-tooltip]::before {
669
+ content: ""; position: absolute; bottom: calc(100% + 2px); left: 50%;
670
+ transform: translate(-50%, 4px);
671
+ border: 6px solid transparent; border-top-color: var(--tooltip-bg); border-bottom: 0;
672
+ opacity: 0; pointer-events: none; z-index: 70;
673
+ transition: opacity var(--duration-fast) var(--ease-out) 0s,
674
+ transform var(--duration-fast) var(--ease-out) 0s;
675
+ }
676
+ [data-tooltip]:focus-visible::after, [data-tooltip]:focus-visible::before {
677
+ opacity: 1; transform: translate(-50%, 0); transition-delay: 400ms;
678
+ }
679
+ /* Tooltip por hover solo con puntero real — en touch quedaría pegado tras el tap */
680
+ @media (hover: hover) and (pointer: fine) {
681
+ [data-tooltip]:hover::after, [data-tooltip]:hover::before {
682
+ opacity: 1; transform: translate(-50%, 0); transition-delay: 400ms;
683
+ }
684
+ }
685
+
686
+ .alert {
687
+ display: flex; gap: 12px; align-items: flex-start;
688
+ padding: 14px 16px; border-radius: var(--radius-md); font-size: var(--text-sm);
689
+ }
690
+ .alert > svg { width: 20px; height: 20px; flex: none; margin-top: 1px; }
691
+ .alert__title { font-weight: var(--weight-semibold); margin: 0 0 2px; }
692
+ .alert__body { margin: 0; }
693
+ .alert__close {
694
+ position: relative; margin-left: auto; flex: none; display: grid; place-items: center;
695
+ width: 24px; height: 24px; border: 0; border-radius: var(--radius-sm);
696
+ background: transparent; color: inherit; cursor: pointer; opacity: .7;
697
+ }
698
+ .alert__close:hover { opacity: 1; }
699
+ .alert__close svg { width: 16px; height: 16px; }
700
+ /* Botones de cierre de aspecto compacto: un ::before invisible centrado lleva
701
+ el área de toque a 44 px (§12) sin cambiar el tamaño visual. */
702
+ .alert__close::before, .search__clear::before, .file-upload__remove::before,
703
+ .tag__close::before {
704
+ content: ""; position: absolute; top: 50%; left: 50%;
705
+ width: var(--control-height-md); height: var(--control-height-md);
706
+ transform: translate(-50%, -50%);
707
+ }
708
+ .alert--info { background: var(--info-100); color: var(--info-text); }
709
+ .alert--info > svg { color: var(--info-500); }
710
+ .alert--success { background: var(--success-100); color: var(--success-text); }
711
+ .alert--success > svg { color: var(--success-500); }
712
+ .alert--warning { background: var(--warning-100); color: var(--warning-text); }
713
+ .alert--warning > svg { color: var(--warning-500); }
714
+ .alert--danger { background: var(--danger-100); color: var(--danger-text); }
715
+ .alert--danger > svg { color: var(--danger-500); }
716
+
717
+ .toast-stack {
718
+ position: fixed; top: 16px; right: 16px; z-index: 90;
719
+ display: flex; flex-direction: column; gap: 12px; align-items: flex-end;
720
+ }
721
+ @media (max-width: 639px) {
722
+ .toast-stack { right: 50%; transform: translateX(50%); align-items: center; }
723
+ }
724
+ .toast {
725
+ display: flex; gap: 12px; align-items: flex-start;
726
+ width: 360px; max-width: calc(100vw - 32px);
727
+ background: var(--surface); color: var(--text-primary);
728
+ border-left: 3px solid var(--info-500); border-radius: var(--radius-md);
729
+ box-shadow: var(--shadow-lg); padding: 14px 16px; font-size: var(--text-sm);
730
+ /* Entrada interrumpible (§11.2): transition + @starting-style, no @keyframes —
731
+ un keyframe no puede invertirse si el toast se apila o se descarta a mitad. */
732
+ opacity: 1; transform: none;
733
+ transition: opacity var(--duration-slow) var(--ease-out),
734
+ transform var(--duration-slow) var(--ease-out);
735
+ }
736
+ @starting-style {
737
+ .toast { opacity: 0; transform: translateX(24px); }
738
+ }
739
+ .toast.is-leaving { animation: bl-toast-out var(--duration-base) var(--ease-in) forwards; }
740
+ .toast > svg { width: 20px; height: 20px; flex: none; }
741
+ .toast--success { border-left-color: var(--success-500); } .toast--success > svg { color: var(--success-500); }
742
+ .toast--warning { border-left-color: var(--warning-500); } .toast--warning > svg { color: var(--warning-500); }
743
+ .toast--danger { border-left-color: var(--danger-500); } .toast--danger > svg { color: var(--danger-500); }
744
+ .toast--info { border-left-color: var(--info-500); } .toast--info > svg { color: var(--info-500); }
745
+ .toast__title { font-weight: var(--weight-semibold); margin: 0; }
746
+ .toast__body { color: var(--text-secondary); margin: 0; }
747
+ @keyframes bl-toast-out { to { opacity: 0; transform: translateX(24px); } }
748
+
749
+ .progress-row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; }
750
+ .progress-row .progress-label { font-size: var(--text-sm); color: var(--text-secondary); }
751
+ .progress-row .progress-value { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted); }
752
+ .progress {
753
+ height: 8px; border-radius: var(--radius-full);
754
+ background: var(--surface-alt); overflow: hidden;
755
+ }
756
+ .progress__bar {
757
+ height: 100%; width: 0; border-radius: var(--radius-full);
758
+ background: var(--accent);
759
+ transition: width var(--duration-slow) var(--ease-out);
760
+ }
761
+ .progress__bar--success { background: var(--success-500); }
762
+ .progress__bar--warning { background: var(--warning-500); }
763
+ .progress__bar--danger { background: var(--danger-500); }
764
+
765
+ .progress-ring { display: inline-grid; place-items: center; position: relative; }
766
+ .progress-ring svg { transform: rotate(-90deg); }
767
+ .progress-ring__track { fill: none; stroke: var(--surface-alt); }
768
+ .progress-ring__bar {
769
+ fill: none; stroke: var(--accent); stroke-linecap: round;
770
+ transition: stroke-dashoffset var(--duration-slow) var(--ease-out);
771
+ }
772
+ .progress-ring__value {
773
+ position: absolute; font-family: var(--font-mono); color: var(--text-primary);
774
+ font-weight: var(--weight-medium);
775
+ }
776
+
777
+ /* Pulso de opacidad, sin degradado: el bloque entero se atenúa y vuelve.
778
+ Con movimiento reducido, el reset global lo deja quieto y opaco. */
779
+ .skeleton {
780
+ background: var(--surface-alt); border-radius: var(--radius-sm);
781
+ min-height: 12px;
782
+ animation: bl-pulse calc(var(--duration-page) * 4) linear infinite alternate;
783
+ }
784
+ @keyframes bl-pulse { to { opacity: .5; } }
785
+ .skeleton--circle { border-radius: var(--radius-full); }
786
+
787
+ .empty-state {
788
+ display: flex; flex-direction: column; align-items: center; text-align: center;
789
+ gap: var(--space-3); padding: var(--space-10) var(--space-6);
790
+ }
791
+ .empty-state > svg { width: 40px; height: 40px; color: var(--primary-300); }
792
+ .empty-state__title { font-size: var(--text-lg); font-weight: var(--weight-semibold); color: var(--text-primary); margin: 0; }
793
+ .empty-state__desc { font-size: var(--text-sm); color: var(--text-muted); max-width: 40ch; margin: 0; }
794
+
795
+ /* --------------------------------------------------------------------------
796
+ 10. OVERLAYS — modal, menu (§10.19–10.20)
797
+ -------------------------------------------------------------------------- */
798
+ .modal {
799
+ position: fixed; inset: 0; z-index: 100;
800
+ display: grid; place-items: center; padding: var(--space-4);
801
+ visibility: hidden;
802
+ }
803
+ .modal.is-open { visibility: visible; }
804
+ .modal__overlay {
805
+ position: absolute; inset: 0; background: var(--overlay);
806
+ opacity: 0; transition: opacity var(--duration-base) var(--ease-out);
807
+ }
808
+ .modal.is-open .modal__overlay { opacity: 1; }
809
+ .modal__panel {
810
+ position: relative; width: min(480px, 100%);
811
+ background: var(--surface); border-radius: var(--radius-lg);
812
+ box-shadow: var(--shadow-xl); padding: var(--card-padding);
813
+ opacity: 0; transform: scale(.96);
814
+ transition: opacity var(--duration-slow) var(--ease-out),
815
+ transform var(--duration-slow) var(--ease-out);
816
+ }
817
+ .modal.is-open .modal__panel { opacity: 1; transform: scale(1); }
818
+ .modal__panel--lg { width: min(640px, 100%); }
819
+ .modal__header {
820
+ display: flex; align-items: center; justify-content: space-between;
821
+ gap: var(--space-4); margin-bottom: var(--space-4);
822
+ }
823
+ .modal__title { font-size: var(--text-xl); font-weight: var(--weight-semibold); margin: 0; }
824
+ .modal__footer {
825
+ display: flex; justify-content: flex-end; gap: var(--space-3);
826
+ margin-top: var(--space-6);
827
+ }
828
+
829
+ .menu-wrap { position: relative; display: inline-block; }
830
+ .menu {
831
+ position: absolute; top: calc(100% + 6px); left: 0; z-index: 50;
832
+ min-width: 190px; padding: 6px;
833
+ background: var(--surface); border: var(--border-width) solid var(--border);
834
+ border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
835
+ opacity: 0; transform: translateY(-4px); pointer-events: none;
836
+ transition: opacity var(--duration-fast) var(--ease-out), transform var(--duration-fast) var(--ease-out);
837
+
838
+ visibility: hidden;
839
+
840
+ display: none;
841
+ }
842
+ .menu--right { left: auto; right: 0; }
843
+ .menu.is-open { opacity: 1; transform: none; pointer-events: auto; visibility: visible; display: block; }
844
+ .menu__item {
845
+ display: flex; align-items: center; gap: 10px; width: 100%;
846
+ padding: 9px 12px; border: 0; border-radius: var(--radius-sm);
847
+ background: transparent; font-family: var(--font-body); font-size: var(--text-sm);
848
+ color: var(--text-primary); text-align: left; cursor: pointer;
849
+ transition: background-color var(--duration-fast) var(--ease-out);
850
+ }
851
+ .menu__item:hover { background: var(--bg); }
852
+ .menu__item svg { width: 16px; height: 16px; color: var(--text-muted); flex: none; }
853
+ .menu__item--danger, .menu__item--danger svg { color: var(--danger-text); }
854
+ .menu__item--danger:hover { background: var(--danger-100); }
855
+ .menu__sep { height: var(--border-width); background: var(--border); margin: 6px 4px; }
856
+
857
+ /* --------------------------------------------------------------------------
858
+ 11. DATOS — tabla, stat, pagination (§10.21–10.23)
859
+ -------------------------------------------------------------------------- */
860
+ .table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
861
+ .table thead th {
862
+ height: 40px; padding: 0 16px; text-align: left;
863
+ background: var(--bg); color: var(--text-muted);
864
+ font-size: var(--text-xs); font-weight: var(--weight-medium);
865
+ text-transform: uppercase; letter-spacing: var(--tracking-label);
866
+ border-bottom: var(--border-width) solid var(--border);
867
+ }
868
+ .table tbody td {
869
+ height: 52px; padding: 0 16px; color: var(--text-primary);
870
+ border-bottom: var(--border-width) solid var(--surface-alt);
871
+ }
872
+ .table tbody tr { transition: background-color var(--duration-fast) var(--ease-out); }
873
+ .table tbody tr:hover { background: var(--bg); }
874
+ .table tbody tr.is-selected { background: var(--accent-soft); }
875
+ .table .num, .table td.num, .table th.num { text-align: right; font-family: var(--font-mono); }
876
+
877
+ /* Variantes de tabla (§10.21): zebra, sticky header, orden y selección */
878
+ .table--zebra tbody tr:nth-child(even) { background: var(--surface-alt); }
879
+ .table--zebra tbody tr:nth-child(even):hover { background: var(--bg); }
880
+ .table--sticky thead th { position: sticky; top: 0; z-index: 1; }
881
+ .table tbody tr.row--selected,
882
+ .table tbody tr.row--selected:hover { background: var(--accent-soft); }
883
+ .table .col-select { width: 44px; text-align: center; }
884
+ .table .col-select .checkbox { display: inline-flex; justify-content: center; gap: 0; }
885
+
886
+ .th-sort {
887
+ display: inline-flex; align-items: center; gap: 6px; width: 100%;
888
+ border: 0; background: transparent; cursor: pointer;
889
+ font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; text-align: left;
890
+ }
891
+ .th-sort--num { justify-content: flex-end; }
892
+ .th-sort .sort-icon {
893
+ width: 14px; height: 14px; flex: none; opacity: .35;
894
+ transition: opacity var(--duration-fast) var(--ease-out),
895
+ transform var(--duration-base) var(--ease-out);
896
+ }
897
+ .table th[aria-sort="ascending"] .sort-icon,
898
+ .table th[aria-sort="descending"] .sort-icon { opacity: 1; color: var(--accent); }
899
+ .table th[aria-sort="descending"] .sort-icon { transform: rotate(180deg); }
900
+
901
+ .stat__label {
902
+ display: inline-flex; align-items: center; gap: 8px; margin-bottom: 8px;
903
+ font-size: var(--text-sm); color: var(--text-muted);
904
+ }
905
+ .stat__label svg { width: 16px; height: 16px; }
906
+ .stat__row { display: flex; align-items: baseline; gap: 10px; }
907
+ .stat__value {
908
+ font-family: var(--font-mono); font-size: var(--text-3xl);
909
+ font-weight: var(--weight-semibold); color: var(--text-primary);
910
+ letter-spacing: -0.01em; line-height: 1;
911
+ }
912
+ /* El delta indica tendencia, no éxito: tono neutro por defecto. --up/--down tiñen
913
+ solo cuando el producto decide qué sentido es bueno (deltaTone). */
914
+ .stat__delta {
915
+ display: inline-flex; align-items: center; gap: 4px;
916
+ font-size: var(--text-sm); font-weight: var(--weight-semibold);
917
+ color: var(--text-secondary);
918
+ }
919
+ .stat__delta svg { width: 14px; height: 14px; }
920
+ .stat__delta--up { color: var(--success-text); }
921
+ .stat__delta--down { color: var(--danger-text); }
922
+
923
+ /* Chip de métrica (§10.22): rótulo y valor en una pastilla de una línea */
924
+ .metric-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
925
+ .metric-chip {
926
+ display: inline-flex; align-items: center; gap: var(--space-2);
927
+ padding: var(--space-1) var(--space-3);
928
+ border: var(--border-width) solid var(--border); border-radius: var(--radius-full);
929
+ background: var(--surface);
930
+ font-family: var(--font-body); font-size: var(--text-sm); line-height: 1.5;
931
+ color: var(--text-secondary); white-space: nowrap;
932
+ }
933
+ .metric-chip svg { width: 16px; height: 16px; flex: none; color: var(--text-muted); }
934
+ .metric-chip__value {
935
+ font-weight: var(--weight-semibold); color: var(--link);
936
+ font-variant-numeric: tabular-nums;
937
+ }
938
+ button.metric-chip {
939
+ min-height: var(--control-height-md); padding-inline: var(--space-4);
940
+ cursor: pointer; text-align: left;
941
+ transition: background-color var(--duration-fast) var(--ease-out),
942
+ border-color var(--duration-fast) var(--ease-out),
943
+ transform var(--duration-instant) var(--ease-out);
944
+ }
945
+ button.metric-chip:hover { background: var(--accent-soft); border-color: var(--accent); }
946
+ button.metric-chip:active { background: var(--accent-soft-strong); transform: scale(.98); }
947
+ button.metric-chip:focus-visible { outline: 2px solid var(--focus-color); outline-offset: 2px; }
948
+ /* Meta cumplida: el ✓ va en el tono de éxito, nunca en el lavanda del valor */
949
+ .metric-chip--met svg { color: var(--success-500); }
950
+
951
+ .pagination { display: flex; align-items: center; gap: 4px; list-style: none; padding: 0; margin: 0; }
952
+ .pagination__btn {
953
+ display: inline-grid; place-items: center;
954
+ min-width: 36px; height: 36px; padding: 0 8px;
955
+ border: 0; border-radius: var(--radius-sm); background: transparent;
956
+ font-family: var(--font-body); font-size: var(--text-sm); font-weight: var(--weight-medium);
957
+ color: var(--text-secondary); cursor: pointer;
958
+ transition: background-color var(--duration-fast) var(--ease-out);
959
+ }
960
+ .pagination__btn:hover:not(:disabled):not(.is-active) { background: var(--surface-alt); }
961
+ .pagination__btn.is-active {
962
+ background: var(--accent); color: var(--text-on-primary); font-weight: var(--weight-semibold);
963
+ }
964
+ .pagination__btn:disabled { color: var(--text-disabled); cursor: not-allowed; }
965
+ .pagination__btn svg { width: 16px; height: 16px; }
966
+ .pagination__ellipsis { color: var(--text-disabled); padding: 0 4px; user-select: none; }
967
+
968
+ /* --------------------------------------------------------------------------
969
+ 12. NAVEGACIÓN — navbar, sidebar, tabs, breadcrumbs (§10.24)
970
+ -------------------------------------------------------------------------- */
971
+ .navbar {
972
+ display: flex; align-items: center; gap: var(--space-8);
973
+ height: 64px; padding: 0 var(--space-6);
974
+ background: var(--surface); border-bottom: var(--border-width) solid var(--border);
975
+ }
976
+ .navbar__brand { font-family: var(--font-display); font-weight: var(--weight-semibold); font-size: var(--text-lg); color: var(--text-primary); text-decoration: none; }
977
+ .navbar__nav { display: flex; align-items: stretch; gap: var(--space-6); height: 100%; }
978
+ .navbar__link {
979
+ position: relative; display: inline-flex; align-items: center;
980
+ font-size: var(--text-sm); font-weight: var(--weight-medium);
981
+ color: var(--text-secondary); text-decoration: none;
982
+ transition: color var(--duration-fast) var(--ease-out);
983
+ }
984
+ .navbar__link:hover { color: var(--text-primary); }
985
+ .navbar__link.is-active { color: var(--accent-active); }
986
+ .navbar__link.is-active::after {
987
+ content: ""; position: absolute; left: 0; right: 0; bottom: 0;
988
+ height: 2px; background: var(--accent);
989
+ }
990
+
991
+ .sidebar {
992
+ width: 260px; padding: var(--space-4);
993
+ background: var(--bg); border-right: var(--border-width) solid var(--border);
994
+ display: flex; flex-direction: column; gap: 2px;
995
+ }
996
+ .sidebar__item {
997
+ display: flex; align-items: center; gap: 10px;
998
+ padding: 10px 12px; border-radius: var(--radius-md);
999
+ font-family: var(--font-body); font-size: var(--text-sm); font-weight: var(--weight-medium);
1000
+ color: var(--text-secondary); text-decoration: none; border: 0; background: transparent;
1001
+ cursor: pointer; text-align: left; width: 100%;
1002
+ transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
1003
+ }
1004
+ .sidebar__item svg { width: 18px; height: 18px; flex: none; }
1005
+ .sidebar__item:hover { background: var(--surface-alt); color: var(--text-primary); }
1006
+ .sidebar__item.is-active { background: var(--accent-soft-strong); color: var(--link); }
1007
+ .sidebar__item.is-active svg { color: var(--accent); }
1008
+
1009
+ /* Grupos con rótulo dentro del sidebar */
1010
+ .sidebar__group { display: flex; flex-direction: column; gap: 2px; }
1011
+ .sidebar__group + .sidebar__group { margin-top: var(--space-4); }
1012
+ .sidebar__group-label {
1013
+ padding: 0 12px var(--space-1);
1014
+ font-size: var(--text-xs); font-weight: var(--weight-semibold);
1015
+ text-transform: uppercase; letter-spacing: var(--tracking-label);
1016
+ color: var(--text-muted); white-space: nowrap;
1017
+ }
1018
+ .sidebar__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1019
+
1020
+ /* Sidebar contraíble (§10.24): expandido 260 px, riel de iconos de 64 px.
1021
+ El ancho cambia sin transición; solo los rótulos se funden con opacity y transform. */
1022
+ .sidebar--collapsible .sidebar__label {
1023
+ transition: opacity var(--duration-fast) var(--ease-out),
1024
+ transform var(--duration-fast) var(--ease-out);
1025
+ }
1026
+ .sidebar__toggle { margin-top: auto; }
1027
+ .sidebar.is-collapsed { width: 64px; padding-inline: var(--space-3); }
1028
+ .sidebar.is-collapsed .sidebar__item { position: relative; justify-content: center; padding-inline: 0; }
1029
+ .sidebar.is-collapsed .sidebar__toggle svg { transform: rotate(180deg); }
1030
+ .sidebar.is-collapsed .sidebar__group + .sidebar__group { margin-top: var(--space-2); }
1031
+ /* En el riel, el rótulo de grupo es un separador de 1 px; su texto sigue en el árbol de accesibilidad */
1032
+ .sidebar.is-collapsed .sidebar__group-label {
1033
+ height: 1px; padding: 0; margin: 0 var(--space-2) var(--space-2);
1034
+ overflow: hidden; color: transparent; background: var(--border);
1035
+ }
1036
+ /* Oculto a la vista pero accesible (patrón de .u-visually-hidden) */
1037
+ .sidebar.is-collapsed .sidebar__label,
1038
+ .sidebar.is-collapsed .sidebar__group:first-child > .sidebar__group-label {
1039
+ position: absolute; width: 1px; height: 1px; margin: -1px;
1040
+ clip-path: inset(50%); overflow: hidden; white-space: nowrap;
1041
+ }
1042
+ .sidebar.is-collapsed .sidebar__label {
1043
+ border-radius: var(--radius-sm); background: var(--tooltip-bg); color: var(--tooltip-text);
1044
+ font-size: var(--text-xs); line-height: 16px;
1045
+ pointer-events: none; z-index: 70;
1046
+ opacity: 0; transform: translateX(-4px);
1047
+ }
1048
+ /* Tooltip del riel: el propio rótulo aparece a la derecha del ítem, también con teclado */
1049
+ .sidebar.is-collapsed .sidebar__item:focus-visible .sidebar__label {
1050
+ left: calc(100% + 8px); top: calc(50% - 14px); width: auto; height: auto;
1051
+ margin: 0; padding: 6px 10px; clip-path: none; overflow: visible;
1052
+ opacity: 1; transform: none; transition-delay: 400ms;
1053
+ }
1054
+ /* Por hover solo con puntero real — en touch quedaría pegado tras el tap */
1055
+ @media (hover: hover) and (pointer: fine) {
1056
+ .sidebar.is-collapsed .sidebar__item:hover .sidebar__label {
1057
+ left: calc(100% + 8px); top: calc(50% - 14px); width: auto; height: auto;
1058
+ margin: 0; padding: 6px 10px; clip-path: none; overflow: visible;
1059
+ opacity: 1; transform: none; transition-delay: 400ms;
1060
+ }
1061
+ }
1062
+ /* Por debajo de 768 px la navegación vive en un Drawer --left (§10.29), que abre el botón ☰
1063
+ .sidebar-trigger (combinado con .icon-btn); desde 768 px el sidebar es fijo y el botón sobra */
1064
+ @media (max-width: 767px) {
1065
+ .sidebar--collapsible { display: none; }
1066
+ }
1067
+ @media (min-width: 768px) {
1068
+ .sidebar-trigger { display: none; }
1069
+ }
1070
+
1071
+ .tabs { display: flex; gap: var(--space-6); border-bottom: var(--border-width) solid var(--border); }
1072
+ .tabs__tab {
1073
+ padding: 12px 4px; margin-bottom: -1px;
1074
+ border: 0; border-bottom: 2px solid transparent; background: transparent;
1075
+ font-family: var(--font-body); font-size: var(--text-sm); font-weight: var(--weight-medium);
1076
+ color: var(--text-secondary); cursor: pointer;
1077
+ transition: color var(--duration-fast) var(--ease-out),
1078
+ border-color var(--duration-slow) var(--ease-out);
1079
+ }
1080
+ .tabs__tab:hover { color: var(--text-primary); }
1081
+ .tabs__tab.is-active { color: var(--accent-active); border-bottom-color: var(--accent); }
1082
+
1083
+ .breadcrumbs { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--text-muted); }
1084
+ .breadcrumbs a { color: var(--text-muted); text-decoration: none; transition: color var(--duration-fast) var(--ease-out); }
1085
+ .breadcrumbs a:hover { color: var(--link); }
1086
+ .breadcrumbs__sep { user-select: none; }
1087
+ .breadcrumbs__current { color: var(--text-primary); }
1088
+
1089
+ /* --------------------------------------------------------------------------
1090
+ 13. TIPOGRÁFICOS — link, code
1091
+ -------------------------------------------------------------------------- */
1092
+ .link {
1093
+ color: var(--link); text-decoration: none;
1094
+ background-image: linear-gradient(currentColor, currentColor);
1095
+ background-size: 0% 1px; background-repeat: no-repeat; background-position: 0 100%;
1096
+ transition: color var(--duration-fast) var(--ease-out),
1097
+ background-size var(--duration-base) var(--ease-out);
1098
+ }
1099
+ .link:hover { background-size: 100% 1px; }
1100
+
1101
+ .code {
1102
+ font-family: var(--font-mono); font-size: .9em;
1103
+ background: var(--surface-alt); color: var(--text-primary);
1104
+ border: var(--border-width) solid var(--border);
1105
+ border-radius: var(--radius-sm); padding: 1px 6px;
1106
+ }
1107
+
1108
+ /* --------------------------------------------------------------------------
1109
+ 13b. COMBOBOX · BÚSQUEDA · DRAWER · POPOVER · BUTTONGROUP (§10.28–10.31)
1110
+ -------------------------------------------------------------------------- */
1111
+
1112
+ /* Combobox / Autocomplete (§10.28) */
1113
+ .combobox { position: relative; }
1114
+ .combobox__input {
1115
+ width: 100%; height: var(--control-height-md); padding: 0 14px;
1116
+ font-family: var(--font-body); font-size: var(--text-base);
1117
+ color: var(--text-primary); background: var(--surface);
1118
+ border: var(--border-width) solid var(--control-border); border-radius: var(--radius-sm);
1119
+ transition: border-color var(--duration-fast) var(--ease-out),
1120
+ box-shadow var(--duration-fast) var(--ease-out);
1121
+ }
1122
+ .combobox__input:hover:not(:disabled):not(:focus) { border-color: var(--border-hover); }
1123
+ .combobox__input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
1124
+ .combobox__input:disabled { background: var(--surface-alt); color: var(--text-disabled); cursor: not-allowed; }
1125
+ .combobox__list {
1126
+ position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 50;
1127
+ max-height: 264px; overflow-y: auto; margin: 0; padding: 6px; list-style: none;
1128
+ background: var(--surface); border: var(--border-width) solid var(--border);
1129
+ border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
1130
+ opacity: 0; transform: translateY(-4px); pointer-events: none;
1131
+ transition: opacity var(--duration-base) var(--ease-out),
1132
+ transform var(--duration-base) var(--ease-out);
1133
+ }
1134
+ .combobox.is-open .combobox__list { opacity: 1; transform: none; pointer-events: auto; }
1135
+ .combobox__option {
1136
+ display: flex; align-items: center; gap: 8px;
1137
+ padding: 10px 12px; border-radius: var(--radius-sm);
1138
+ font-size: var(--text-sm); color: var(--text-primary); cursor: pointer;
1139
+ transition: background-color var(--duration-fast) var(--ease-out);
1140
+ }
1141
+ .combobox__option .combobox__check {
1142
+ width: 16px; height: 16px; margin-left: auto; flex: none;
1143
+ color: var(--accent); opacity: 0;
1144
+ }
1145
+ .combobox__option.is-active { background: var(--accent-soft); }
1146
+ .combobox__option[aria-selected="true"] { color: var(--link); font-weight: var(--weight-medium); }
1147
+ .combobox__option[aria-selected="true"] .combobox__check { opacity: 1; }
1148
+ .combobox__empty { padding: 10px 12px; font-size: var(--text-sm); color: var(--text-muted); }
1149
+
1150
+ /* Búsqueda (§10.28) */
1151
+ .search { position: relative; display: flex; align-items: center; }
1152
+ .search__icon {
1153
+ position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
1154
+ width: 18px; height: 18px; color: var(--text-disabled); pointer-events: none;
1155
+ }
1156
+ .search__input {
1157
+ width: 100%; height: var(--control-height-md); padding: 0 40px;
1158
+ font-family: var(--font-body); font-size: var(--text-base);
1159
+ color: var(--text-primary); background: var(--surface);
1160
+ border: var(--border-width) solid var(--control-border); border-radius: var(--radius-sm);
1161
+ transition: border-color var(--duration-fast) var(--ease-out),
1162
+ box-shadow var(--duration-fast) var(--ease-out);
1163
+ }
1164
+ .search__input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
1165
+ .search__input:hover:not(:focus) { border-color: var(--border-hover); }
1166
+ .search__input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
1167
+ .search__clear {
1168
+ position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
1169
+ display: none; width: 32px; height: 32px; align-items: center; justify-content: center;
1170
+ border: 0; border-radius: var(--radius-full); background: transparent;
1171
+ color: var(--text-muted); cursor: pointer;
1172
+ transition: background-color var(--duration-fast) var(--ease-out),
1173
+ color var(--duration-fast) var(--ease-out);
1174
+ }
1175
+ .search__clear:hover { background: var(--surface-alt); color: var(--text-primary); }
1176
+ .search__clear svg { width: 16px; height: 16px; }
1177
+ .search__input:not(:placeholder-shown) ~ .search__clear { display: inline-flex; }
1178
+
1179
+ /* Drawer / Sheet (§10.29) */
1180
+ .drawer {
1181
+ position: fixed; inset: 0; z-index: 100;
1182
+ visibility: hidden; pointer-events: none;
1183
+ transition: visibility 0s linear var(--duration-base);
1184
+ }
1185
+ .drawer.is-open { visibility: visible; pointer-events: auto; transition-delay: 0s; }
1186
+ .drawer__overlay {
1187
+ position: absolute; inset: 0; background: var(--overlay);
1188
+ opacity: 0; transition: opacity var(--duration-base) var(--ease-out);
1189
+ }
1190
+ .drawer.is-open .drawer__overlay { opacity: 1; }
1191
+ .drawer__panel {
1192
+ position: absolute; inset: 0 0 0 auto; width: min(400px, 100%);
1193
+ display: flex; flex-direction: column; gap: var(--space-5);
1194
+ padding: var(--card-padding); background: var(--surface);
1195
+ box-shadow: var(--shadow-xl); overflow-y: auto; overscroll-behavior: contain;
1196
+ transform: translateX(100%);
1197
+ transition: transform var(--duration-base) var(--ease-in);
1198
+ }
1199
+ .drawer.is-open .drawer__panel {
1200
+ transform: none;
1201
+ transition: transform var(--duration-slow) var(--ease-out);
1202
+ }
1203
+ .drawer--right .drawer__panel { inset: 0 0 0 auto; transform: translateX(100%); }
1204
+ .drawer--left .drawer__panel { inset: 0 auto 0 0; transform: translateX(-100%); }
1205
+ .drawer--bottom .drawer__panel {
1206
+ inset: auto 0 0 0; width: 100%; max-height: 85vh;
1207
+ border-radius: var(--radius-lg) var(--radius-lg) 0 0; transform: translateY(100%);
1208
+ }
1209
+ .drawer__header {
1210
+ display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
1211
+ }
1212
+ .drawer__title { font-size: var(--text-lg); font-weight: var(--weight-semibold); margin: 0; }
1213
+ .drawer__body { flex: 1; }
1214
+ .drawer__footer {
1215
+ display: flex; justify-content: flex-end; gap: var(--space-3); margin-top: auto;
1216
+ }
1217
+
1218
+ /* Popover (§10.30) */
1219
+ .popover { position: relative; display: inline-block; }
1220
+ .popover__panel {
1221
+ position: absolute; top: calc(100% + 8px); left: 0; z-index: 60;
1222
+ width: max-content; max-width: 300px; padding: var(--space-4);
1223
+ background: var(--surface); border: var(--border-width) solid var(--border);
1224
+ border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
1225
+ transform-origin: top left; opacity: 0; transform: scale(.96); pointer-events: none;
1226
+ transition: opacity var(--duration-base) var(--ease-out),
1227
+ transform var(--duration-base) var(--ease-out);
1228
+
1229
+ visibility: hidden;
1230
+
1231
+ display: none;
1232
+ }
1233
+ .popover.is-open .popover__panel { opacity: 1; transform: none; pointer-events: auto; visibility: visible; display: block; }
1234
+ .popover--right .popover__panel { left: auto; right: 0; transform-origin: top right; }
1235
+
1236
+ /* ButtonGroup (§10.31) */
1237
+ .btn-group { display: inline-flex; }
1238
+ .btn-group .btn { border-radius: 0; }
1239
+ .btn-group .btn:first-child {
1240
+ border-top-left-radius: var(--radius-md); border-bottom-left-radius: var(--radius-md);
1241
+ }
1242
+ .btn-group .btn:last-child {
1243
+ border-top-right-radius: var(--radius-md); border-bottom-right-radius: var(--radius-md);
1244
+ }
1245
+ .btn-group .btn:not(:first-child) { margin-left: calc(var(--border-width) * -1); }
1246
+ .btn-group .btn:hover, .btn-group .btn:focus-visible { z-index: 1; }
1247
+
1248
+ /* --------------------------------------------------------------------------
1249
+ 13c. DATEPICKER · FILEUPLOAD · STEPPER · KBD (§10.32–10.35)
1250
+ -------------------------------------------------------------------------- */
1251
+
1252
+ /* DatePicker (§10.32) */
1253
+ .datepicker { position: relative; display: inline-block; }
1254
+ .datepicker__input {
1255
+ width: 100%; height: var(--control-height-md); padding: 0 40px 0 14px;
1256
+ font-family: var(--font-body); font-size: var(--text-base);
1257
+ color: var(--text-primary); background: var(--surface);
1258
+ border: var(--border-width) solid var(--control-border); border-radius: var(--radius-sm);
1259
+ transition: border-color var(--duration-fast) var(--ease-out),
1260
+ box-shadow var(--duration-fast) var(--ease-out);
1261
+ }
1262
+ .datepicker__input:hover:not(:disabled):not(:focus) { border-color: var(--border-hover); }
1263
+ .datepicker__input:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
1264
+ .datepicker__input:disabled { background: var(--surface-alt); color: var(--text-disabled); cursor: not-allowed; }
1265
+ .datepicker__icon {
1266
+ position: absolute; right: 12px; top: calc(var(--control-height-md) / 2); transform: translateY(-50%);
1267
+ width: 18px; height: 18px; color: var(--text-muted); pointer-events: none;
1268
+ }
1269
+ .datepicker__calendar {
1270
+ position: absolute; top: calc(100% + 8px); left: 0; z-index: 60;
1271
+ width: max-content; padding: var(--space-4);
1272
+ background: var(--surface); border: var(--border-width) solid var(--border);
1273
+ border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
1274
+ transform-origin: top left; opacity: 0; transform: scale(.96); pointer-events: none;
1275
+ transition: opacity var(--duration-base) var(--ease-out),
1276
+ transform var(--duration-base) var(--ease-out);
1277
+
1278
+ visibility: hidden;
1279
+
1280
+ display: none;
1281
+ }
1282
+ .datepicker.is-open .datepicker__calendar { opacity: 1; transform: none; pointer-events: auto; visibility: visible; display: block; }
1283
+ .datepicker--right .datepicker__calendar { left: auto; right: 0; transform-origin: top right; }
1284
+
1285
+ .calendar { width: 15.75rem; }
1286
+ .calendar__header {
1287
+ display: flex; align-items: center; justify-content: space-between;
1288
+ gap: var(--space-2); margin-bottom: var(--space-3);
1289
+ }
1290
+ .calendar__title { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--text-primary); }
1291
+ .calendar__weekdays,
1292
+ .calendar__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
1293
+ .calendar__weekdays { margin-bottom: 4px; }
1294
+ .calendar__week { display: contents; }
1295
+ .calendar__weekday {
1296
+ display: flex; align-items: center; justify-content: center; height: 28px;
1297
+ font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--text-muted);
1298
+ }
1299
+ .calendar__day {
1300
+ display: flex; align-items: center; justify-content: center;
1301
+ width: 34px; height: 34px; margin: 0 auto; padding: 0;
1302
+ border: 0; border-radius: var(--radius-sm); background: transparent;
1303
+ font-family: var(--font-body); font-size: var(--text-sm); color: var(--text-primary);
1304
+ cursor: pointer;
1305
+ transition: background-color var(--duration-fast) var(--ease-out),
1306
+ color var(--duration-fast) var(--ease-out);
1307
+ }
1308
+ .calendar__day:hover:not(:disabled):not(.calendar__day--selected) { background: var(--accent-soft); }
1309
+ .calendar__day--outside { color: var(--text-muted); }
1310
+ .calendar__day--today { font-weight: var(--weight-semibold); box-shadow: inset 0 0 0 1px var(--border-strong); }
1311
+ .calendar__day--selected { background: var(--accent); color: var(--text-on-primary); font-weight: var(--weight-semibold); }
1312
+ .calendar__day:disabled { color: var(--text-disabled); cursor: not-allowed; }
1313
+
1314
+ /* FileUpload (§10.33) */
1315
+ .file-upload {
1316
+ border: 2px dashed var(--border-strong); border-radius: var(--radius-lg);
1317
+ background: var(--surface);
1318
+ transition: border-color var(--duration-fast) var(--ease-out),
1319
+ background-color var(--duration-fast) var(--ease-out);
1320
+ }
1321
+ .file-upload.is-dragover { border-color: var(--accent); background: var(--accent-soft); }
1322
+ .file-upload__input {
1323
+ position: absolute; width: 1px; height: 1px; margin: -1px;
1324
+ clip-path: inset(50%); overflow: hidden; white-space: nowrap;
1325
+ }
1326
+ .file-upload__label {
1327
+ display: flex; flex-direction: column; align-items: center; text-align: center;
1328
+ gap: var(--space-2); padding: var(--space-8) var(--space-6); cursor: pointer;
1329
+ }
1330
+ .file-upload__label > svg { width: 32px; height: 32px; color: var(--text-muted); }
1331
+ .file-upload__title { font-size: var(--text-sm); color: var(--text-secondary); }
1332
+ .file-upload__hint { font-size: var(--text-xs); color: var(--text-muted); }
1333
+ .file-upload__button {
1334
+ display: inline-flex; align-items: center; justify-content: center;
1335
+ height: var(--control-height-sm); padding: 0 16px; margin-top: var(--space-1);
1336
+ border: var(--border-width) solid var(--border-strong); border-radius: var(--radius-md);
1337
+ font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--text-primary);
1338
+ background: var(--surface);
1339
+ transition: background-color var(--duration-fast) var(--ease-out);
1340
+ }
1341
+ .file-upload__label:hover .file-upload__button { background: var(--bg); }
1342
+ .file-upload__list { list-style: none; margin: var(--space-4) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
1343
+ .file-upload__item {
1344
+ display: flex; align-items: center; gap: var(--space-3);
1345
+ padding: var(--space-3); border: var(--border-width) solid var(--border);
1346
+ border-radius: var(--radius-md); background: var(--surface);
1347
+ }
1348
+ .file-upload__icon { width: 20px; height: 20px; color: var(--text-muted); flex: none; }
1349
+ .file-upload__meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1; }
1350
+ .file-upload__name {
1351
+ font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--text-primary);
1352
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
1353
+ }
1354
+ .file-upload__size { display: inline-flex; align-items: center; gap: 6px; font-size: var(--text-xs); color: var(--text-muted); }
1355
+ .file-upload__size svg { width: 12px; height: 12px; flex: none; }
1356
+ .file-upload__meta .progress { margin-top: 2px; }
1357
+ .file-upload__remove {
1358
+ position: relative; display: inline-flex; align-items: center; justify-content: center;
1359
+ width: 32px; height: 32px; flex: none; border: 0; border-radius: var(--radius-full);
1360
+ background: transparent; color: var(--text-muted); cursor: pointer;
1361
+ transition: background-color var(--duration-fast) var(--ease-out),
1362
+ color var(--duration-fast) var(--ease-out);
1363
+ }
1364
+ .file-upload__remove:hover { background: var(--surface-alt); color: var(--text-primary); }
1365
+ .file-upload__remove svg { width: 16px; height: 16px; }
1366
+ .file-upload__item--error { border-color: var(--danger-500); }
1367
+ .file-upload__item--error .file-upload__icon,
1368
+ .file-upload__item--error .file-upload__size { color: var(--danger-text); }
1369
+
1370
+ /* Stepper / Wizard (§10.34) */
1371
+ .stepper { display: flex; list-style: none; margin: 0; padding: 0; }
1372
+ .step {
1373
+ position: relative; flex: 1;
1374
+ display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--space-2);
1375
+ }
1376
+ .step__marker {
1377
+ position: relative; z-index: 1;
1378
+ display: inline-flex; align-items: center; justify-content: center;
1379
+ width: 32px; height: 32px; flex: none; border-radius: var(--radius-full);
1380
+ border: 2px solid var(--border-strong); background: var(--surface);
1381
+ font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--text-muted);
1382
+ }
1383
+ .step__marker svg { width: 16px; height: 16px; }
1384
+ .step__label { font-size: var(--text-sm); color: var(--text-secondary); }
1385
+ .step__connector {
1386
+ position: absolute; top: 16px; z-index: 0; left: 50%; right: -50%;
1387
+ height: 2px; margin: 0 20px; background: var(--border);
1388
+ }
1389
+ .step--complete .step__marker { background: var(--accent); border-color: var(--accent); color: var(--text-on-primary); }
1390
+ .step--complete .step__label { color: var(--text-primary); }
1391
+ .step--complete .step__connector { background: var(--accent); }
1392
+ .step--current .step__marker { border-color: var(--accent); color: var(--accent); }
1393
+ .step--current .step__label { color: var(--text-primary); font-weight: var(--weight-semibold); }
1394
+ .stepper--vertical { flex-direction: column; align-items: stretch; }
1395
+ .stepper--vertical .step {
1396
+ flex-direction: row; align-items: flex-start; text-align: left;
1397
+ gap: var(--space-3); padding-bottom: var(--space-6);
1398
+ }
1399
+ .stepper--vertical .step:last-child { padding-bottom: 0; }
1400
+ .stepper--vertical .step__connector {
1401
+ top: 36px; bottom: -4px; left: 15px; right: auto;
1402
+ width: 2px; height: auto; margin: 0;
1403
+ }
1404
+ .stepper--vertical .step__label { padding-top: 5px; }
1405
+
1406
+ /* Kbd (§10.35) */
1407
+ .kbd {
1408
+ display: inline-flex; align-items: center; justify-content: center;
1409
+ min-width: 20px; height: 20px; padding: 0 6px;
1410
+ font-family: var(--font-mono); font-size: var(--text-xs); line-height: 1;
1411
+ color: var(--text-secondary); background: var(--surface);
1412
+ border: var(--border-width) solid var(--border-strong);
1413
+ border-radius: var(--radius-sm); box-shadow: var(--shadow-xs);
1414
+ }
1415
+ .kbd-combo { display: inline-flex; align-items: center; gap: 4px; color: var(--text-muted); font-size: var(--text-xs); }
1416
+
1417
+ /* --------------------------------------------------------------------------
1418
+ 14. UTILIDADES MÍNIMAS
1419
+ -------------------------------------------------------------------------- */
1420
+ .u-visually-hidden {
1421
+ position: absolute; width: 1px; height: 1px; margin: -1px;
1422
+ clip-path: inset(50%); overflow: hidden; white-space: nowrap;
1423
+ }
1424
+ .u-mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
1425
+ .u-muted { color: var(--text-muted); }
1426
+ .u-measure { max-width: var(--measure); }
1427
+
1428
+ /* CONTRATOS COMPARTIDOS GENERADOS */
1429
+ /* Contratos comunes de interacción; la identidad y los valores viven en tokens.css. */
1430
+ .grid { grid-template-columns: repeat(12, minmax(0, 1fr)); }
1431
+ .grid > *, .field, .card { min-inline-size: 0; }
1432
+ .stack, .card__content, .form-stack, .text-group { display: flex; flex-direction: column; align-items: stretch; }
1433
+ .stack, .card__content { gap: var(--content-gap); }
1434
+ .stack--tight, .text-group { gap: var(--heading-gap); }
1435
+ .stack--cards { gap: var(--card-group-gap); }
1436
+ .form-stack { gap: var(--form-gap); }
1437
+ .cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
1438
+ .card { display: flex; flex-direction: column; gap: var(--card-content-gap); }
1439
+ .field { gap: var(--field-gap); }
1440
+ .field__label, .field__help, .field__error, .field > :is(label, p, span, div) { margin-block: 0; }
1441
+ :where(.field + .field, .field + .btn, .field + .cluster) { margin-block-start: var(--form-gap); }
1442
+ :where(.card + .card) { margin-block-start: var(--card-group-gap); }
1443
+ .stack > *, .card__content > *, .form-stack > *, .text-group > *, .grid > .card,
1444
+ .card > :is(h1, h2, h3, h4, h5, h6, p), .text-group > :is(h1, h2, h3, h4, h5, h6, p),
1445
+ .stack > :is(h1, h2, h3, h4, h5, h6, p) { margin-block: 0; }
1446
+ .form-stack > .field { margin-block: 0; }
1447
+ .btn {
1448
+ block-size: auto;
1449
+ min-block-size: var(--control-height-md);
1450
+ max-inline-size: 100%;
1451
+ white-space: normal;
1452
+ line-height: 1.35;
1453
+ text-align: center;
1454
+ }
1455
+ .btn--sm { min-block-size: var(--control-height-sm, 36px); }
1456
+ .btn--lg { min-block-size: var(--control-height-lg, 52px); }
1457
+ .btn--primary, .icon-btn--primary, .calendar__day--selected, .pagination__btn.is-active {
1458
+ background: var(--action-bg);
1459
+ color: var(--text-on-action);
1460
+ }
1461
+ .btn--primary:hover:not(:disabled), .icon-btn--primary:hover:not(:disabled) { background: var(--action-hover); color: var(--text-on-action); }
1462
+ .btn--primary:active:not(:disabled), .icon-btn--primary:active:not(:disabled) { background: var(--action-active); color: var(--text-on-action); }
1463
+ .input, .textarea, .select, .combobox__input, .search__input, .datepicker__input {
1464
+ max-inline-size: 100%;
1465
+ caret-color: var(--focus-color);
1466
+ }
1467
+ .input, .select, .combobox__input, .search__input, .datepicker__input {
1468
+ block-size: auto; min-block-size: var(--control-height-md);
1469
+ padding-block: var(--space-2); line-height: 1.5;
1470
+ }
1471
+ :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); }
1472
+ .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"]),
1473
+ .select:hover:not(:disabled):not(:focus), .combobox__input:hover:not(:disabled):not(:focus),
1474
+ .search__input:hover:not(:focus), .datepicker__input:hover:not(:disabled):not(:focus) { border-color: var(--border-hover); }
1475
+ .input:focus-visible, .textarea:focus-visible, .select:focus-visible,
1476
+ .combobox__input:focus-visible, .search__input:focus-visible, .datepicker__input:focus-visible {
1477
+ outline: 2px solid var(--focus-color);
1478
+ outline-offset: 2px;
1479
+ }
1480
+ .input[aria-invalid="true"], .textarea[aria-invalid="true"] { border-color: var(--danger-text, var(--danger)); }
1481
+ .input.input--error, .textarea.textarea--error,
1482
+ .input.input--error:hover:not(:disabled):not(:focus), .textarea.textarea--error:hover:not(:disabled):not(:focus),
1483
+ :is(.input, .textarea, .select, .combobox__input, .search__input, .datepicker__input)[aria-invalid="true"]:hover:not(:disabled):not(:focus) {
1484
+ border-color: var(--danger-text, var(--danger));
1485
+ }
1486
+ .input.input--success, .input.input--success:hover:not(:disabled):not(:focus) { border-color: var(--success-text, var(--success)); }
1487
+ .pagination { max-inline-size: 100%; flex-wrap: wrap; row-gap: var(--space-2); }
1488
+ .pagination__ellipsis { color: var(--text-muted); }
1489
+ .step--current .step__marker { color: var(--link); border-color: var(--focus-color); }
1490
+ .checkbox input:focus-visible ~ .checkbox__box,
1491
+ .radio input:focus-visible ~ .radio__dot,
1492
+ .switch input:focus-visible ~ .switch__track {
1493
+ outline: 2px solid var(--focus-color);
1494
+ outline-offset: 2px;
1495
+ }
1496
+ input.checkbox, input.radio { border-color: var(--control-border); }
1497
+ input.checkbox:hover, input.radio:hover { border-color: var(--focus-color); }
1498
+ input.checkbox:checked, input.checkbox:indeterminate, input.radio:checked { border-color: var(--focus-color); }
1499
+ .switch__track { background: var(--control-border); }
1500
+ .tabs { max-inline-size: 100%; overflow-x: auto; }
1501
+ .tabs__tab { flex-shrink: 0; }
1502
+ .segmented { max-inline-size: 100%; block-size: auto; min-block-size: var(--control-height-md); overflow-x: auto; }
1503
+ .segmented label { padding-block: var(--space-2); }
1504
+ .stat__row, .breadcrumbs, .check-row { flex-wrap: wrap; row-gap: var(--space-2); }
1505
+ .progress-row, .slider-row { flex-wrap: wrap; gap: var(--space-2); }
1506
+ .stat__value { max-inline-size: 100%; white-space: normal; overflow-wrap: anywhere; }
1507
+ .file-upload, .file-upload__label { min-inline-size: 0; max-inline-size: 100%; }
1508
+ .file-upload__button { max-inline-size: 100%; white-space: normal; text-align: center; }
1509
+ .file-upload__hint { overflow-wrap: anywhere; }
1510
+ .table-scroll { max-inline-size: 100%; overflow-x: auto; overscroll-behavior-inline: contain; }
1511
+ .popover__panel, .datepicker__calendar, .combobox__list {
1512
+ max-inline-size: calc(100vw - 2rem);
1513
+ max-block-size: min(32rem, 70dvh);
1514
+ overflow: auto;
1515
+ }
1516
+ .file-upload__input:focus-visible + .file-upload__label { outline: 2px solid var(--focus-color); outline-offset: 2px; }
1517
+ .calendar { max-inline-size: calc(100vw - 2rem); }
1518
+ .ui-title, :is(h1, h2, h3, h4, h5, h6).ui-title, [data-mode="operate"] :is(h1, h2, h3) {
1519
+ font-family: var(--font-ui-heading);
1520
+ letter-spacing: 0;
1521
+ line-height: 1.3;
1522
+ font-weight: var(--weight-semibold);
1523
+ }
1524
+ .ui-title, :is(h1, h2, h3, h4, h5, h6).ui-title, [data-mode="operate"] h1 { font-size: var(--text-ui-title); }
1525
+ [data-mode="operate"] h2 { font-size: var(--text-xl); }
1526
+ [data-mode="operate"] h3 { font-size: var(--text-lg); }
1527
+ .display, .reading-title, :is(h1, h2, h3, h4, h5, h6):is(.display, .reading-title) {
1528
+ font-family: var(--font-display);
1529
+ font-size: var(--text-display-fluid);
1530
+ line-height: 1.08;
1531
+ letter-spacing: var(--tracking-display);
1532
+ text-wrap: balance;
1533
+ }
1534
+ :where(.celeste-reset, .salvia-reset, .bruma-reset, .nocturna-reset, body[data-system]) {
1535
+ scrollbar-color: var(--control-border) var(--bg);
1536
+ }
1537
+ ::selection,
1538
+ .celeste-reset ::selection, .salvia-reset ::selection, .bruma-reset ::selection {
1539
+ background: var(--selection-bg); color: var(--selection-text);
1540
+ }
1541
+ ::placeholder { color: var(--placeholder); opacity: 1; }
1542
+ :where(a) { text-underline-offset: .2em; text-decoration-thickness: .08em; }
1543
+ .skip-link {
1544
+ position: fixed; inset-block-start: var(--space-2); inset-inline-start: var(--space-2);
1545
+ z-index: 1000; padding: var(--space-3) var(--space-4);
1546
+ background: var(--action-bg); color: var(--text-on-action);
1547
+ border-radius: var(--radius-sm); transform: translateY(-180%);
1548
+ }
1549
+ .skip-link:focus { transform: none; outline: 2px solid var(--focus-color); outline-offset: 2px; }
1550
+ [data-tooltip]::before, [data-tooltip]::after { display: none; }
1551
+ [data-tooltip]:focus-visible::before, [data-tooltip]:focus-visible::after { display: block; }
1552
+ .has-tooltip .tooltip { display: none; }
1553
+ .has-tooltip:has(:focus-visible) .tooltip { display: block; opacity: 1; transform: translate(-50%, 0); }
1554
+ @media (hover: hover) and (pointer: fine) {
1555
+ [data-tooltip]:hover::before, [data-tooltip]:hover::after { display: block; }
1556
+ .has-tooltip:hover .tooltip { display: block; }
1557
+ }
1558
+ @media (pointer: coarse) {
1559
+ .btn, .icon-btn, .segmented label, .pagination button,
1560
+ .tag__close, .search__clear, .toast__close, .check-row,
1561
+ .checkbox:not(input), .radio:not(input), .switch:not(input) {
1562
+ min-block-size: var(--touch-target);
1563
+ min-inline-size: var(--touch-target);
1564
+ }
1565
+ }
1566
+ @media (max-width: 479px) {
1567
+ .btn-group { flex-wrap: wrap; }
1568
+ .modal { max-inline-size: calc(100vw - 2rem); }
1569
+ .stepper { flex-direction: column; align-items: stretch; gap: var(--space-4); }
1570
+ .step { flex-direction: row; align-items: center; gap: var(--space-3); text-align: start; min-inline-size: 0; }
1571
+ .step__label { overflow-wrap: anywhere; }
1572
+ .step__connector { display: none; }
1573
+ }
1574
+ @media (prefers-reduced-motion: reduce) {
1575
+ html, html:focus-within { scroll-behavior: auto; }
1576
+ .spinner, .skeleton, .skeleton::after,
1577
+ .progress--indeterminate .progress__bar, .alert.is-leaving, .toast.is-leaving { animation: none; }
1578
+ .progress--indeterminate .progress__bar { transform: none; }
1579
+ .btn, .icon-btn, .card--interactive, .slider::-webkit-slider-thumb { transform: none; }
1580
+ .btn:active:not(:disabled), .icon-btn:active:not(:disabled), .card--interactive:hover { transform: none; }
1581
+ .btn, .icon-btn { transition: background-color 80ms linear, color 80ms linear; }
1582
+ .menu, .popover__panel, .datepicker__calendar, .link::after { transition: none; }
1583
+ .progress__bar, .progress-ring__value, .accordion__content, .accordion__body { transition: none; }
1584
+ }
1585
+ @media (forced-colors: active) {
1586
+ input.switch, .switch__track { border: 1px solid CanvasText; background: Canvas; }
1587
+ input.switch::after, .switch__track::after { background: CanvasText; }
1588
+ input.switch:checked, .switch input:checked ~ .switch__track { border-color: Highlight; }
1589
+ input.switch:checked::after, .switch input:checked ~ .switch__track::after { background: Highlight; }
1590
+ .checkbox__box, .radio__dot { border-color: CanvasText; }
1591
+ }