@higinio/design-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +17 -0
- package/README.md +164 -0
- package/assets/celeste/design-doc.md +842 -0
- package/assets/celeste/framework.css +914 -0
- package/assets/celeste/styleguide.html +3060 -0
- package/assets/celeste/tailwind.css +117 -0
- package/assets/celeste/tokens.css +137 -0
- package/assets/celeste/tokens.json +1013 -0
- package/assets/nocturna/design-doc.md +857 -0
- package/assets/nocturna/framework.css +992 -0
- package/assets/nocturna/styleguide.html +2714 -0
- package/assets/nocturna/tailwind.css +115 -0
- package/assets/nocturna/tokens.css +145 -0
- package/assets/nocturna/tokens.json +952 -0
- package/dist/cli.js +269 -0
- package/dist/data.js +33 -0
- package/dist/doc.js +52 -0
- package/dist/http.js +64 -0
- package/dist/index.js +39 -0
- package/dist/motion.js +142 -0
- package/dist/preflight.js +181 -0
- package/dist/server.js +219 -0
- package/dist/slop.js +257 -0
- package/dist/snippet.js +54 -0
- package/dist/systems.js +21 -0
- package/dist/tokens.js +76 -0
- package/dist/types.js +1 -0
- package/dist/validate.js +135 -0
- package/package.json +37 -0
|
@@ -0,0 +1,2714 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es" data-theme="dark">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Nocturna Eléctrica — Sistema de Diseño</title>
|
|
7
|
+
<meta name="description" content="Sistema de diseño dark-first de Higinio Sosa: tokens, componentes, motion y accesibilidad.">
|
|
8
|
+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%23010203'/%3E%3Ctext x='16' y='22' font-family='system-ui,sans-serif' font-size='18' font-weight='700' fill='%2352baed' text-anchor='middle'%3Eh%3C/text%3E%3C/svg%3E">
|
|
9
|
+
<script>(function(){var t=null;try{t=localStorage.getItem('ne-theme');}catch(e){}if(t==='light'||t==='dark')document.documentElement.dataset.theme=t;})();</script>
|
|
10
|
+
<style>
|
|
11
|
+
/* ============================================================================
|
|
12
|
+
NOCTURNA ELÉCTRICA — Framework CSS v2.0
|
|
13
|
+
Sistema de diseño dark-first de Higinio Sosa.
|
|
14
|
+
Fuente de verdad: DESIGN-nocturna-electrica.md
|
|
15
|
+
Uso: enlazar este archivo antes de cualquier estilo propio.
|
|
16
|
+
Tema: dark por defecto; <html data-theme="light"> activa la variante clara.
|
|
17
|
+
Los componentes consumen SOLO aliases semánticos — nunca hex directos.
|
|
18
|
+
========================================================================== */
|
|
19
|
+
|
|
20
|
+
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=Manrope:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
|
|
21
|
+
|
|
22
|
+
/* ============================================================
|
|
23
|
+
1. TOKENS — primitivos + aliases (dark por defecto)
|
|
24
|
+
============================================================ */
|
|
25
|
+
:root {
|
|
26
|
+
/* -- Primitivos: acento -- */
|
|
27
|
+
--accent-100: #d9f0fb; --accent-200: #a8ddf6; --accent-300: #7dccf1;
|
|
28
|
+
--accent-400: #52baed; --accent-500: #2fa3dd; --accent-600: #1f87bb; --accent-700: #186a94;
|
|
29
|
+
|
|
30
|
+
/* -- Primitivos: índigo -- */
|
|
31
|
+
--indigo-300: #7a83c4; --indigo-400: #565fa3; --indigo-500: #353d7c;
|
|
32
|
+
--indigo-600: #2b3264; --indigo-700: #22284f; --indigo-800: #1a1e3b;
|
|
33
|
+
|
|
34
|
+
/* -- Primitivos: escala nocturna -- */
|
|
35
|
+
--night-950: #010203; --night-900: #0b0d12; --night-800: #14171f;
|
|
36
|
+
--night-700: #1e222d; --night-600: #2a2f3d; --night-500: #3d4354;
|
|
37
|
+
--night-400: #6b7183; --night-300: #9aa0b0; --night-200: #c5c9d4;
|
|
38
|
+
--night-100: #e8eaef; --night-50: #f6f7f9;
|
|
39
|
+
|
|
40
|
+
/* -- Primitivos: semánticos -- */
|
|
41
|
+
--success-400: #4ade80; --success-bg: #0a2617;
|
|
42
|
+
--warning-400: #fbbf24; --warning-bg: #2a2005;
|
|
43
|
+
--danger-400: #f87171; --danger-bg: #2c0f0f;
|
|
44
|
+
--info-400: #52baed; --info-bg: #0d1f2c;
|
|
45
|
+
|
|
46
|
+
/* -- Aliases semánticos (los componentes consumen SOLO esto) -- */
|
|
47
|
+
--bg: var(--night-950);
|
|
48
|
+
--surface-1: var(--night-900);
|
|
49
|
+
--surface-2: var(--night-800);
|
|
50
|
+
--surface-3: var(--night-700);
|
|
51
|
+
--border: var(--night-500);
|
|
52
|
+
--border-strong: var(--night-600);
|
|
53
|
+
--text-primary: var(--night-100);
|
|
54
|
+
--text-secondary: var(--night-200);
|
|
55
|
+
--text-muted: var(--night-300);
|
|
56
|
+
--text-disabled: var(--night-400);
|
|
57
|
+
--text-heading: var(--night-50);
|
|
58
|
+
--text-on-accent: var(--night-950);
|
|
59
|
+
--success: var(--success-400);
|
|
60
|
+
--warning: var(--warning-400);
|
|
61
|
+
--danger: var(--danger-400);
|
|
62
|
+
--info: var(--info-400);
|
|
63
|
+
--accent-ghost-hover: rgba(82,186,237,.08);
|
|
64
|
+
--accent-ghost-active: rgba(82,186,237,.14);
|
|
65
|
+
--accent-selected: rgba(82,186,237,.12);
|
|
66
|
+
--overlay: rgba(1,2,3,.7);
|
|
67
|
+
|
|
68
|
+
/* -- Aliases de componentes (derivados; cambian con el tema) -- */
|
|
69
|
+
--link: var(--accent-400);
|
|
70
|
+
--link-hover: var(--accent-200);
|
|
71
|
+
--focus-color: var(--accent-400);
|
|
72
|
+
--border-hover: var(--night-400);
|
|
73
|
+
--outline-hover-bg: var(--surface-2);
|
|
74
|
+
--outline-active-bg: var(--surface-3);
|
|
75
|
+
--text-on-danger: var(--night-950);
|
|
76
|
+
--data-color: var(--accent-400); /* cifras/datos clave */
|
|
77
|
+
--elevated-border: var(--night-600); /* borde de toasts, modales, menús */
|
|
78
|
+
--card-border: var(--night-600);
|
|
79
|
+
--code-color: var(--accent-300);
|
|
80
|
+
--code-border: var(--night-700);
|
|
81
|
+
--table-header-bg: var(--night-900);
|
|
82
|
+
--row-border: var(--night-800);
|
|
83
|
+
--row-hover: var(--night-700);
|
|
84
|
+
--navbar-bg: rgba(1,2,3,.8);
|
|
85
|
+
--nav-active: var(--accent-400);
|
|
86
|
+
--sidebar-bg: var(--night-900);
|
|
87
|
+
--sidebar-active-bg: var(--indigo-800);
|
|
88
|
+
--sidebar-active-text: var(--night-50);
|
|
89
|
+
--sidebar-active-icon: var(--accent-400);
|
|
90
|
+
--switch-off: var(--night-600);
|
|
91
|
+
--tooltip-bg: var(--night-700);
|
|
92
|
+
--tooltip-border: var(--night-600);
|
|
93
|
+
--tooltip-text: var(--night-100);
|
|
94
|
+
--skeleton-base: var(--night-800);
|
|
95
|
+
--skeleton-sheen: var(--night-700);
|
|
96
|
+
--empty-icon: var(--indigo-400);
|
|
97
|
+
|
|
98
|
+
/* -- Tipografía -- */
|
|
99
|
+
--font-display: "Space Grotesk", system-ui, sans-serif;
|
|
100
|
+
--font-body: "Manrope", system-ui, sans-serif;
|
|
101
|
+
--font-mono: "JetBrains Mono", monospace;
|
|
102
|
+
--text-xs: .75rem; --text-sm: .875rem; --text-base: 1rem; --text-lg: 1.125rem;
|
|
103
|
+
--text-xl: 1.25rem; --text-2xl: 1.5625rem; --text-3xl: 1.9375rem;
|
|
104
|
+
--text-4xl: 2.4375rem; --text-5xl: 3.0625rem;
|
|
105
|
+
--leading-tight: 1.05; --leading-heading: 1.15; --leading-h2: 1.2;
|
|
106
|
+
--leading-h3: 1.3; --leading-h4: 1.4; --leading-snug: 1.5; --leading-body: 1.6;
|
|
107
|
+
--tracking-display: -0.02em; --tracking-overline: 0.08em;
|
|
108
|
+
--measure: 65ch;
|
|
109
|
+
|
|
110
|
+
/* -- Espaciado -- */
|
|
111
|
+
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
|
|
112
|
+
--space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px;
|
|
113
|
+
--space-12: 48px; --space-16: 64px; --space-20: 80px; --space-24: 96px;
|
|
114
|
+
--card-padding: 24px; --card-padding-mobile: 16px;
|
|
115
|
+
--section-gap: 64px; --form-gap: 20px;
|
|
116
|
+
--button-padding: 12px 20px; --touch-target: 44px;
|
|
117
|
+
--grid-gutter: 24px; --grid-gutter-mobile: 16px;
|
|
118
|
+
|
|
119
|
+
/* -- Radios y bordes -- */
|
|
120
|
+
--radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px;
|
|
121
|
+
--radius-xl: 24px; --radius-full: 9999px;
|
|
122
|
+
--border-default: 1px solid var(--night-500);
|
|
123
|
+
--border-emphasis: 1px solid var(--night-600);
|
|
124
|
+
--focus-ring: 2px solid var(--accent-400);
|
|
125
|
+
--focus-ring-offset: 2px;
|
|
126
|
+
|
|
127
|
+
/* -- Elevación -- */
|
|
128
|
+
--shadow-1: 0 1px 2px rgba(0,0,0,.4);
|
|
129
|
+
--shadow-2: 0 4px 12px rgba(0,0,0,.5);
|
|
130
|
+
--shadow-3: 0 12px 32px rgba(0,0,0,.6);
|
|
131
|
+
--glow-accent: 0 0 0 1px rgba(82,186,237,.35), 0 4px 20px rgba(82,186,237,.18);
|
|
132
|
+
--ring: 0 0 0 3px rgba(82,186,237,.2);
|
|
133
|
+
--ring-danger: 0 0 0 3px rgba(248,113,113,.2);
|
|
134
|
+
|
|
135
|
+
/* -- Motion -- */
|
|
136
|
+
--duration-instant: 100ms; --duration-fast: 150ms; --duration-base: 220ms;
|
|
137
|
+
--duration-slow: 250ms; --duration-page: 350ms;
|
|
138
|
+
--ease-out: cubic-bezier(0.2, 0, 0, 1);
|
|
139
|
+
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
140
|
+
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1); /* moverse de A a B en pantalla */
|
|
141
|
+
--ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
|
|
142
|
+
|
|
143
|
+
color-scheme: dark;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* ============================================================
|
|
147
|
+
2. VARIANTE LIGHT — <html data-theme="light">
|
|
148
|
+
El CTA primario NO cambia (fondo #52baed, texto #010203).
|
|
149
|
+
============================================================ */
|
|
150
|
+
[data-theme="light"] {
|
|
151
|
+
--bg: #f5f8fb;
|
|
152
|
+
--surface-1: #ffffff;
|
|
153
|
+
--surface-2: #ffffff;
|
|
154
|
+
--surface-3: #eaf1f7;
|
|
155
|
+
--border: #d8dfe8;
|
|
156
|
+
--border-strong: #b9c3d1;
|
|
157
|
+
--text-primary: #14171f;
|
|
158
|
+
--text-secondary: #3d4354;
|
|
159
|
+
--text-muted: #6b7183;
|
|
160
|
+
--text-disabled: #9aa0b0;
|
|
161
|
+
--text-heading: #0b0d12;
|
|
162
|
+
--text-on-accent: #010203; /* el CTA no cambia */
|
|
163
|
+
--success: #15803d; --success-bg: #e3f5ea;
|
|
164
|
+
--warning: #a16207; --warning-bg: #fbf3dd;
|
|
165
|
+
--danger: #c03535; --danger-bg: #fbe7e7;
|
|
166
|
+
--info: #1f87bb; --info-bg: #e3f2fb;
|
|
167
|
+
--accent-ghost-hover: rgba(31,135,187,.08);
|
|
168
|
+
--accent-ghost-active: rgba(31,135,187,.14);
|
|
169
|
+
--accent-selected: rgba(82,186,237,.12);
|
|
170
|
+
--overlay: rgba(20,23,31,.45);
|
|
171
|
+
|
|
172
|
+
--link: #1f87bb;
|
|
173
|
+
--link-hover: #186a94;
|
|
174
|
+
--focus-color: #1f87bb;
|
|
175
|
+
--border-hover: #b9c3d1;
|
|
176
|
+
--outline-hover-bg: #eaf1f7;
|
|
177
|
+
--outline-active-bg: #d8dfe8;
|
|
178
|
+
--text-on-danger: #ffffff;
|
|
179
|
+
--data-color: #1f87bb;
|
|
180
|
+
--elevated-border: #d8dfe8;
|
|
181
|
+
--card-border: #d8dfe8;
|
|
182
|
+
--code-color: #186a94;
|
|
183
|
+
--code-border: #d8dfe8;
|
|
184
|
+
--table-header-bg: #eaf1f7;
|
|
185
|
+
--row-border: #eaf1f7;
|
|
186
|
+
--row-hover: #f5f8fb;
|
|
187
|
+
--navbar-bg: rgba(255,255,255,.8);
|
|
188
|
+
--nav-active: #186a94;
|
|
189
|
+
--sidebar-bg: #ffffff;
|
|
190
|
+
--sidebar-active-bg: #e3f2fb;
|
|
191
|
+
--sidebar-active-text: #14171f;
|
|
192
|
+
--sidebar-active-icon: #1f87bb;
|
|
193
|
+
--switch-off: #b9c3d1;
|
|
194
|
+
--tooltip-bg: #14171f;
|
|
195
|
+
--tooltip-border: #14171f;
|
|
196
|
+
--tooltip-text: #f6f7f9;
|
|
197
|
+
--skeleton-base: #eaf1f7;
|
|
198
|
+
--skeleton-sheen: #f5f8fb;
|
|
199
|
+
|
|
200
|
+
--ring: 0 0 0 3px rgba(31,135,187,.25);
|
|
201
|
+
--ring-danger: 0 0 0 3px rgba(192,53,53,.2);
|
|
202
|
+
--shadow-1: 0 1px 3px rgba(53,61,124,.08);
|
|
203
|
+
--shadow-2: 0 4px 10px rgba(53,61,124,.10);
|
|
204
|
+
--shadow-3: 0 12px 28px rgba(53,61,124,.14);
|
|
205
|
+
--glow-accent: 0 0 0 1px rgba(82,186,237,.4), 0 4px 16px rgba(82,186,237,.25);
|
|
206
|
+
|
|
207
|
+
color-scheme: light;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/* ============================================================
|
|
211
|
+
3. ACCESIBILIDAD DEL MOVIMIENTO
|
|
212
|
+
============================================================ */
|
|
213
|
+
@media (prefers-reduced-motion: reduce) {
|
|
214
|
+
*, *::before, *::after {
|
|
215
|
+
animation-duration: 0.01ms !important;
|
|
216
|
+
animation-iteration-count: 1 !important;
|
|
217
|
+
transition-duration: 0.01ms !important;
|
|
218
|
+
scroll-behavior: auto !important;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* ============================================================
|
|
223
|
+
4. BASE
|
|
224
|
+
============================================================ */
|
|
225
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
226
|
+
html, body { overflow-x: clip; }
|
|
227
|
+
|
|
228
|
+
body {
|
|
229
|
+
margin: 0;
|
|
230
|
+
background: var(--bg);
|
|
231
|
+
color: var(--text-primary);
|
|
232
|
+
font-family: var(--font-body);
|
|
233
|
+
font-size: var(--text-base);
|
|
234
|
+
line-height: var(--leading-body);
|
|
235
|
+
-webkit-font-smoothing: antialiased;
|
|
236
|
+
text-rendering: optimizeLegibility;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* h1–h3 en display; h4 en adelante usa body */
|
|
240
|
+
h1, h2, h3 {
|
|
241
|
+
font-family: var(--font-display);
|
|
242
|
+
color: var(--text-heading);
|
|
243
|
+
letter-spacing: var(--tracking-display);
|
|
244
|
+
margin: 0 0 var(--space-4);
|
|
245
|
+
}
|
|
246
|
+
h1 { font-size: var(--text-4xl); line-height: var(--leading-heading); font-weight: 700; }
|
|
247
|
+
h2 { font-size: var(--text-3xl); line-height: var(--leading-h2); font-weight: 700; }
|
|
248
|
+
h3 { font-size: var(--text-2xl); line-height: var(--leading-h3); font-weight: 600; }
|
|
249
|
+
h4 { font-family: var(--font-body); font-size: var(--text-xl); line-height: var(--leading-h4); font-weight: 600; color: var(--text-heading); margin: 0 0 var(--space-3); }
|
|
250
|
+
|
|
251
|
+
p { max-width: var(--measure); margin: 0 0 var(--space-4); }
|
|
252
|
+
|
|
253
|
+
a { color: var(--link); text-decoration: none; transition: color var(--duration-fast) var(--ease-out); }
|
|
254
|
+
a:hover { color: var(--link-hover); }
|
|
255
|
+
|
|
256
|
+
::placeholder { color: var(--text-disabled); }
|
|
257
|
+
::selection { background: rgba(82,186,237,.3); }
|
|
258
|
+
|
|
259
|
+
:focus-visible {
|
|
260
|
+
outline: 2px solid var(--focus-color);
|
|
261
|
+
outline-offset: var(--focus-ring-offset);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* ============================================================
|
|
265
|
+
5. LAYOUT — contenedor y grid de 12 columnas
|
|
266
|
+
Breakpoints: sm 640 · md 768 · lg 1024 · xl 1280
|
|
267
|
+
============================================================ */
|
|
268
|
+
.container { width: 100%; margin-inline: auto; padding-inline: var(--space-4); }
|
|
269
|
+
@media (min-width: 640px) { .container { max-width: calc(100% - 32px); } }
|
|
270
|
+
@media (min-width: 768px) { .container { max-width: 720px; } }
|
|
271
|
+
@media (min-width: 1024px) { .container { max-width: 960px; } }
|
|
272
|
+
@media (min-width: 1280px) { .container { max-width: 1200px; } }
|
|
273
|
+
|
|
274
|
+
.grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--grid-gutter-mobile); }
|
|
275
|
+
@media (min-width: 768px) { .grid { gap: var(--grid-gutter); } }
|
|
276
|
+
[class*="col-"] { grid-column: span 12; }
|
|
277
|
+
@media (min-width: 768px) {
|
|
278
|
+
.col-1{grid-column:span 1}.col-2{grid-column:span 2}.col-3{grid-column:span 3}
|
|
279
|
+
.col-4{grid-column:span 4}.col-5{grid-column:span 5}.col-6{grid-column:span 6}
|
|
280
|
+
.col-7{grid-column:span 7}.col-8{grid-column:span 8}.col-9{grid-column:span 9}
|
|
281
|
+
.col-10{grid-column:span 10}.col-11{grid-column:span 11}.col-12{grid-column:span 12}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* ============================================================
|
|
285
|
+
6. BOTONES — .btn
|
|
286
|
+
============================================================ */
|
|
287
|
+
.btn {
|
|
288
|
+
display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
|
|
289
|
+
height: 44px; padding: var(--button-padding); min-width: 44px;
|
|
290
|
+
border: 1px solid transparent; border-radius: var(--radius-md);
|
|
291
|
+
font-family: var(--font-body); font-size: var(--text-base); font-weight: 600;
|
|
292
|
+
line-height: 1; cursor: pointer; white-space: nowrap; text-decoration: none;
|
|
293
|
+
transition: background-color var(--duration-fast) var(--ease-out),
|
|
294
|
+
border-color var(--duration-fast) var(--ease-out),
|
|
295
|
+
color var(--duration-fast) var(--ease-out),
|
|
296
|
+
box-shadow var(--duration-base) var(--ease-out),
|
|
297
|
+
transform var(--duration-instant) var(--ease-out);
|
|
298
|
+
}
|
|
299
|
+
.btn:active:not(:disabled) { transform: scale(.98); }
|
|
300
|
+
.btn:disabled { cursor: not-allowed; }
|
|
301
|
+
.btn svg { width: 20px; height: 20px; flex: none; }
|
|
302
|
+
|
|
303
|
+
.btn--sm { height: 36px; padding: 8px 14px; font-size: var(--text-sm); }
|
|
304
|
+
.btn--lg { height: 52px; padding: 14px 24px; font-size: var(--text-lg); }
|
|
305
|
+
|
|
306
|
+
/* Primario — texto oscuro sobre acento, nunca blanco */
|
|
307
|
+
/* Gating de hover (§11.5): los hover que mueven/elevan van dentro de
|
|
308
|
+
@media (hover: hover) and (pointer: fine) — en touch el tap deja el hover pegado.
|
|
309
|
+
Los hover de solo color/fondo quedan fuera. */
|
|
310
|
+
.btn--primary { background: var(--accent-400); color: var(--text-on-accent); }
|
|
311
|
+
.btn--primary:hover:not(:disabled) { background: var(--accent-500); }
|
|
312
|
+
@media (hover: hover) and (pointer: fine) {
|
|
313
|
+
.btn--primary:hover:not(:disabled) { box-shadow: var(--glow-accent); }
|
|
314
|
+
}
|
|
315
|
+
.btn--primary:active:not(:disabled) { background: var(--accent-600); box-shadow: none; }
|
|
316
|
+
.btn--primary:disabled { background: var(--surface-3); color: var(--text-disabled); }
|
|
317
|
+
|
|
318
|
+
/* Secundario — índigo (idéntico en ambos temas) */
|
|
319
|
+
.btn--secondary { background: var(--indigo-500); color: var(--night-50); }
|
|
320
|
+
.btn--secondary:hover:not(:disabled) { background: var(--indigo-600); }
|
|
321
|
+
.btn--secondary:active:not(:disabled) { background: var(--indigo-700); }
|
|
322
|
+
.btn--secondary:disabled { opacity: .5; }
|
|
323
|
+
|
|
324
|
+
/* Outline */
|
|
325
|
+
.btn--outline { background: transparent; border-color: var(--border); color: var(--text-primary); }
|
|
326
|
+
.btn--outline:hover:not(:disabled) { background: var(--outline-hover-bg); border-color: var(--border-hover); }
|
|
327
|
+
.btn--outline:active:not(:disabled) { background: var(--outline-active-bg); }
|
|
328
|
+
.btn--outline:disabled { opacity: .5; }
|
|
329
|
+
|
|
330
|
+
/* Ghost */
|
|
331
|
+
.btn--ghost { background: transparent; color: var(--link); }
|
|
332
|
+
.btn--ghost:hover:not(:disabled) { background: var(--accent-ghost-hover); }
|
|
333
|
+
.btn--ghost:active:not(:disabled) { background: var(--accent-ghost-active); }
|
|
334
|
+
.btn--ghost:disabled { color: var(--text-disabled); }
|
|
335
|
+
|
|
336
|
+
/* Destructivo */
|
|
337
|
+
.btn--danger { background: var(--danger); color: var(--text-on-danger); }
|
|
338
|
+
.btn--danger:hover:not(:disabled) { filter: brightness(.92); }
|
|
339
|
+
.btn--danger:active:not(:disabled) { filter: brightness(.86); }
|
|
340
|
+
.btn--danger:disabled { opacity: .5; filter: none; }
|
|
341
|
+
|
|
342
|
+
/* ============================================================
|
|
343
|
+
7. ICON BUTTON — .icon-btn (siempre con aria-label)
|
|
344
|
+
============================================================ */
|
|
345
|
+
.icon-btn {
|
|
346
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
347
|
+
width: 44px; height: 44px; padding: 0; flex: none;
|
|
348
|
+
border: 1px solid transparent; border-radius: var(--radius-md);
|
|
349
|
+
background: transparent; cursor: pointer;
|
|
350
|
+
transition: background-color var(--duration-fast) var(--ease-out),
|
|
351
|
+
border-color var(--duration-fast) var(--ease-out),
|
|
352
|
+
color var(--duration-fast) var(--ease-out),
|
|
353
|
+
transform var(--duration-instant) var(--ease-out);
|
|
354
|
+
}
|
|
355
|
+
.icon-btn:active:not(:disabled) { transform: scale(.98); }
|
|
356
|
+
.icon-btn:disabled { opacity: .5; cursor: not-allowed; }
|
|
357
|
+
.icon-btn svg { width: 20px; height: 20px; }
|
|
358
|
+
.icon-btn--sm { width: 36px; height: 36px; } .icon-btn--sm svg { width: 18px; height: 18px; }
|
|
359
|
+
.icon-btn--lg { width: 52px; height: 52px; }
|
|
360
|
+
|
|
361
|
+
.icon-btn--outline { border-color: var(--border); color: var(--text-secondary); }
|
|
362
|
+
.icon-btn--outline:hover:not(:disabled) { background: var(--outline-hover-bg); border-color: var(--border-hover); }
|
|
363
|
+
.icon-btn--outline:active:not(:disabled) { background: var(--outline-active-bg); }
|
|
364
|
+
|
|
365
|
+
.icon-btn--ghost { color: var(--text-muted); }
|
|
366
|
+
.icon-btn--ghost:hover:not(:disabled) { background: var(--outline-hover-bg); color: var(--text-primary); }
|
|
367
|
+
.icon-btn--ghost:active:not(:disabled) { background: var(--outline-active-bg); }
|
|
368
|
+
|
|
369
|
+
.icon-btn--accent { color: var(--link); }
|
|
370
|
+
.icon-btn--accent:hover:not(:disabled) { background: var(--accent-ghost-hover); }
|
|
371
|
+
.icon-btn--accent:active:not(:disabled) { background: var(--accent-ghost-active); }
|
|
372
|
+
|
|
373
|
+
/* ============================================================
|
|
374
|
+
8. SPINNER — .spinner
|
|
375
|
+
============================================================ */
|
|
376
|
+
.spinner {
|
|
377
|
+
display: inline-block; width: 16px; height: 16px; flex: none;
|
|
378
|
+
border: 2px solid color-mix(in srgb, currentColor 25%, transparent);
|
|
379
|
+
border-top-color: currentColor; border-radius: var(--radius-full);
|
|
380
|
+
color: var(--accent-400);
|
|
381
|
+
animation: ne-spin .8s linear infinite;
|
|
382
|
+
}
|
|
383
|
+
@keyframes ne-spin { to { transform: rotate(360deg); } }
|
|
384
|
+
|
|
385
|
+
/* ============================================================
|
|
386
|
+
9. FORMULARIOS — .field, .input, .textarea, .select
|
|
387
|
+
============================================================ */
|
|
388
|
+
.field { display: flex; flex-direction: column; margin-bottom: var(--form-gap); }
|
|
389
|
+
.field__label { font-size: var(--text-sm); font-weight: 500; color: var(--text-secondary); margin-bottom: 6px; }
|
|
390
|
+
.field__help { font-size: var(--text-sm); color: var(--text-muted); margin-top: 6px; }
|
|
391
|
+
.field__error {
|
|
392
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
393
|
+
font-size: var(--text-sm); color: var(--danger); margin-top: 6px;
|
|
394
|
+
}
|
|
395
|
+
.field__error svg { width: 14px; height: 14px; flex: none; }
|
|
396
|
+
|
|
397
|
+
.input, .textarea, .select {
|
|
398
|
+
width: 100%; background: var(--surface-2);
|
|
399
|
+
border: 1px solid var(--border); border-radius: var(--radius-sm);
|
|
400
|
+
color: var(--text-primary); font-family: var(--font-body); font-size: var(--text-base);
|
|
401
|
+
transition: border-color var(--duration-fast) var(--ease-out),
|
|
402
|
+
box-shadow var(--duration-fast) var(--ease-out);
|
|
403
|
+
}
|
|
404
|
+
.input, .select { height: 44px; padding: 0 14px; }
|
|
405
|
+
.input:hover:not(:disabled):not(:focus) { border-color: var(--border-hover); }
|
|
406
|
+
.input:focus, .textarea:focus, .select:focus {
|
|
407
|
+
outline: none; border-color: var(--focus-color); box-shadow: var(--ring);
|
|
408
|
+
}
|
|
409
|
+
.input:disabled, .textarea:disabled {
|
|
410
|
+
background: var(--surface-1); color: var(--text-disabled); cursor: not-allowed;
|
|
411
|
+
}
|
|
412
|
+
.input--error, .input--error:hover { border-color: var(--danger); }
|
|
413
|
+
.input--error:focus { border-color: var(--danger); box-shadow: var(--ring-danger); }
|
|
414
|
+
.input--success { border-color: var(--success); }
|
|
415
|
+
|
|
416
|
+
/* Input con icono leading */
|
|
417
|
+
.input-wrap { position: relative; }
|
|
418
|
+
.input-wrap > svg {
|
|
419
|
+
position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
|
|
420
|
+
width: 18px; height: 18px; color: var(--text-disabled); pointer-events: none;
|
|
421
|
+
}
|
|
422
|
+
.input-wrap .input { padding-left: 40px; }
|
|
423
|
+
|
|
424
|
+
.textarea { min-height: 96px; padding: 12px 14px; resize: vertical; line-height: var(--leading-body); }
|
|
425
|
+
.field__count { font-size: var(--text-xs); color: var(--text-disabled); text-align: right; margin-top: 4px; }
|
|
426
|
+
|
|
427
|
+
/* Select nativo estilizado (el menú custom usa .menu) */
|
|
428
|
+
.select-wrap { position: relative; }
|
|
429
|
+
.select { appearance: none; padding-right: 40px; cursor: pointer; }
|
|
430
|
+
.select-wrap::after {
|
|
431
|
+
content: ""; position: absolute; right: 14px; top: 50%;
|
|
432
|
+
width: 8px; height: 8px; pointer-events: none;
|
|
433
|
+
border-right: 2px solid var(--text-muted); border-bottom: 2px solid var(--text-muted);
|
|
434
|
+
transform: translateY(-70%) rotate(45deg);
|
|
435
|
+
transition: transform var(--duration-base) var(--ease-out);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/* Menú desplegable (dropdown/select custom) */
|
|
439
|
+
.menu {
|
|
440
|
+
min-width: 190px; padding: 6px; max-height: 320px; overflow: auto;
|
|
441
|
+
background: var(--surface-2); border: 1px solid var(--elevated-border);
|
|
442
|
+
border-radius: var(--radius-md); box-shadow: var(--shadow-3);
|
|
443
|
+
}
|
|
444
|
+
.menu__item {
|
|
445
|
+
display: flex; align-items: center; gap: 10px; width: 100%;
|
|
446
|
+
padding: 10px 12px; border: 0; border-radius: var(--radius-sm);
|
|
447
|
+
background: transparent; color: var(--text-primary);
|
|
448
|
+
font-family: var(--font-body); font-size: var(--text-sm); text-align: left; cursor: pointer;
|
|
449
|
+
transition: background-color var(--duration-fast) var(--ease-out);
|
|
450
|
+
}
|
|
451
|
+
.menu__item:hover { background: var(--surface-3); }
|
|
452
|
+
.menu__item.is-selected { background: var(--accent-selected); color: var(--accent-300); }
|
|
453
|
+
[data-theme="light"] .menu__item.is-selected { color: var(--link); }
|
|
454
|
+
.menu__item svg { width: 16px; height: 16px; color: var(--text-muted); flex: none; }
|
|
455
|
+
|
|
456
|
+
/* SegmentedControl */
|
|
457
|
+
.segmented {
|
|
458
|
+
display: inline-flex; align-items: stretch;
|
|
459
|
+
background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 3px;
|
|
460
|
+
height: 44px;
|
|
461
|
+
}
|
|
462
|
+
.segmented--sm { height: 36px; }
|
|
463
|
+
.segmented input { position: absolute; opacity: 0; pointer-events: none; }
|
|
464
|
+
.segmented label {
|
|
465
|
+
display: inline-flex; align-items: center; padding: 0 16px;
|
|
466
|
+
border-radius: calc(var(--radius-md) - 3px);
|
|
467
|
+
font-size: var(--text-sm); font-weight: 500; color: var(--text-secondary);
|
|
468
|
+
cursor: pointer; user-select: none; white-space: nowrap;
|
|
469
|
+
transition: background-color var(--duration-base) var(--ease-out),
|
|
470
|
+
color var(--duration-fast) var(--ease-out),
|
|
471
|
+
box-shadow var(--duration-base) var(--ease-out);
|
|
472
|
+
}
|
|
473
|
+
.segmented--sm label { padding: 0 12px; font-size: var(--text-xs); }
|
|
474
|
+
.segmented input:checked + label {
|
|
475
|
+
background: var(--surface-3); color: var(--accent-300);
|
|
476
|
+
font-weight: 600; box-shadow: var(--shadow-1);
|
|
477
|
+
}
|
|
478
|
+
.segmented input:focus-visible + label { outline: var(--focus-ring); outline-offset: 2px; }
|
|
479
|
+
|
|
480
|
+
/* Slider */
|
|
481
|
+
.slider-row { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 10px; }
|
|
482
|
+
.slider-row .slider-label { font-size: var(--text-sm); color: var(--text-secondary); }
|
|
483
|
+
.slider-row .slider-value { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--text-muted); font-variant-numeric: tabular-nums; }
|
|
484
|
+
.slider {
|
|
485
|
+
appearance: none; -webkit-appearance: none;
|
|
486
|
+
width: 100%; height: 6px; border-radius: var(--radius-full);
|
|
487
|
+
background: linear-gradient(to right, var(--accent-400) var(--slider-fill, 50%), var(--surface-3) var(--slider-fill, 50%));
|
|
488
|
+
cursor: pointer;
|
|
489
|
+
}
|
|
490
|
+
.slider:focus-visible { outline: var(--focus-ring); outline-offset: 2px; }
|
|
491
|
+
.slider:disabled { opacity: .5; cursor: not-allowed; }
|
|
492
|
+
.slider::-webkit-slider-thumb {
|
|
493
|
+
-webkit-appearance: none; width: 18px; height: 18px; border-radius: var(--radius-full);
|
|
494
|
+
background: var(--night-50); border: 2px solid var(--accent-400); box-shadow: var(--shadow-1);
|
|
495
|
+
transition: transform var(--duration-instant) var(--ease-out);
|
|
496
|
+
}
|
|
497
|
+
.slider:active::-webkit-slider-thumb { transform: scale(1.15); }
|
|
498
|
+
.slider::-moz-range-thumb {
|
|
499
|
+
width: 14px; height: 14px; border-radius: var(--radius-full); border: 2px solid var(--accent-400);
|
|
500
|
+
background: var(--night-50); box-shadow: var(--shadow-1);
|
|
501
|
+
transition: transform var(--duration-instant) var(--ease-out);
|
|
502
|
+
}
|
|
503
|
+
.slider:active::-moz-range-thumb { transform: scale(1.15); }
|
|
504
|
+
@media (prefers-reduced-motion: reduce) {
|
|
505
|
+
.slider::-webkit-slider-thumb { transition-duration: 0.01ms !important; }
|
|
506
|
+
.slider::-moz-range-thumb { transition-duration: 0.01ms !important; }
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/* ============================================================
|
|
510
|
+
10. SELECCIÓN — .checkbox, .radio, .switch
|
|
511
|
+
============================================================ */
|
|
512
|
+
.check-row { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; font-size: var(--text-base); }
|
|
513
|
+
|
|
514
|
+
.checkbox, .radio {
|
|
515
|
+
appearance: none; width: 20px; height: 20px; margin: 0; flex: none;
|
|
516
|
+
background: transparent; border: 2px solid var(--border); cursor: pointer;
|
|
517
|
+
display: inline-grid; place-content: center;
|
|
518
|
+
transition: background-color var(--duration-base) var(--ease-out),
|
|
519
|
+
border-color var(--duration-fast) var(--ease-out);
|
|
520
|
+
}
|
|
521
|
+
.checkbox { border-radius: 4px; }
|
|
522
|
+
.radio { border-radius: var(--radius-full); }
|
|
523
|
+
.checkbox:hover, .radio:hover { border-color: var(--accent-300); }
|
|
524
|
+
.checkbox:checked, .radio:checked { background: var(--accent-400); border-color: var(--accent-400); }
|
|
525
|
+
.checkbox::after {
|
|
526
|
+
content: ""; width: 10px; height: 6px;
|
|
527
|
+
border-left: 2px solid var(--text-on-accent); border-bottom: 2px solid var(--text-on-accent);
|
|
528
|
+
transform: rotate(-45deg) scale(0); transform-origin: center;
|
|
529
|
+
transition: transform var(--duration-base) var(--ease-spring);
|
|
530
|
+
margin-top: -2px;
|
|
531
|
+
}
|
|
532
|
+
.checkbox:checked::after { transform: rotate(-45deg) scale(1); }
|
|
533
|
+
.radio::after {
|
|
534
|
+
content: ""; width: 8px; height: 8px; border-radius: var(--radius-full);
|
|
535
|
+
background: var(--text-on-accent); transform: scale(0);
|
|
536
|
+
transition: transform var(--duration-base) var(--ease-spring);
|
|
537
|
+
}
|
|
538
|
+
.radio:checked::after { transform: scale(1); }
|
|
539
|
+
|
|
540
|
+
/* Switch 44×24 */
|
|
541
|
+
.switch {
|
|
542
|
+
appearance: none; width: 44px; height: 24px; margin: 0; flex: none;
|
|
543
|
+
background: var(--switch-off); border: 0; border-radius: var(--radius-full);
|
|
544
|
+
position: relative; cursor: pointer;
|
|
545
|
+
transition: background-color var(--duration-base) var(--ease-out);
|
|
546
|
+
}
|
|
547
|
+
.switch::after {
|
|
548
|
+
content: ""; position: absolute; top: 2px; left: 2px;
|
|
549
|
+
width: 20px; height: 20px; border-radius: var(--radius-full);
|
|
550
|
+
background: var(--night-50); box-shadow: var(--shadow-1);
|
|
551
|
+
transition: transform var(--duration-base) var(--ease-spring);
|
|
552
|
+
}
|
|
553
|
+
.switch:checked { background: var(--accent-400); }
|
|
554
|
+
.switch:checked::after { transform: translateX(20px); }
|
|
555
|
+
|
|
556
|
+
/* ============================================================
|
|
557
|
+
11. BADGES Y TAGS
|
|
558
|
+
============================================================ */
|
|
559
|
+
.badge {
|
|
560
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
561
|
+
padding: 2px 8px; border-radius: var(--radius-full);
|
|
562
|
+
font-size: var(--text-xs); font-weight: 500; line-height: var(--leading-snug);
|
|
563
|
+
background: var(--surface-2); color: var(--text-secondary); border: 1px solid var(--border);
|
|
564
|
+
}
|
|
565
|
+
.badge svg { width: 14px; height: 14px; flex: none; }
|
|
566
|
+
.badge--success { background: var(--success-bg); color: var(--success); border: 1px solid color-mix(in srgb, var(--success) 30%, transparent); }
|
|
567
|
+
.badge--warning { background: var(--warning-bg); color: var(--warning); border: 1px solid color-mix(in srgb, var(--warning) 30%, transparent); }
|
|
568
|
+
.badge--danger { background: var(--danger-bg); color: var(--danger); border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent); }
|
|
569
|
+
.badge--info { background: var(--info-bg); color: var(--info); border: 1px solid color-mix(in srgb, var(--info) 30%, transparent); }
|
|
570
|
+
|
|
571
|
+
.tag {
|
|
572
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
573
|
+
padding: 4px 10px; border-radius: var(--radius-full);
|
|
574
|
+
background: var(--surface-2); border: 1px solid var(--border);
|
|
575
|
+
color: var(--text-secondary); font-size: var(--text-xs); font-weight: 500;
|
|
576
|
+
}
|
|
577
|
+
.tag__x {
|
|
578
|
+
display: inline-grid; place-content: center; width: 14px; height: 14px; padding: 0;
|
|
579
|
+
border: 0; border-radius: var(--radius-full); background: transparent;
|
|
580
|
+
color: inherit; cursor: pointer; font-size: 12px; line-height: 1;
|
|
581
|
+
transition: background-color var(--duration-fast) var(--ease-out);
|
|
582
|
+
}
|
|
583
|
+
.tag__x:hover { background: var(--surface-3); }
|
|
584
|
+
|
|
585
|
+
/* ============================================================
|
|
586
|
+
12. AVATAR — .avatar (xs 24 · sm 32 · md 40 · lg 48 · xl 64)
|
|
587
|
+
============================================================ */
|
|
588
|
+
.avatar {
|
|
589
|
+
--avatar-size: 40px; --avatar-font: 15px;
|
|
590
|
+
position: relative; display: inline-flex; align-items: center; justify-content: center;
|
|
591
|
+
width: var(--avatar-size); height: var(--avatar-size); flex: none;
|
|
592
|
+
border-radius: var(--radius-full);
|
|
593
|
+
background: var(--indigo-700); border: 1px solid var(--indigo-600);
|
|
594
|
+
color: var(--night-50); font-family: var(--font-display); font-weight: 600;
|
|
595
|
+
font-size: var(--avatar-font); letter-spacing: var(--tracking-display);
|
|
596
|
+
text-transform: uppercase; user-select: none;
|
|
597
|
+
}
|
|
598
|
+
.avatar--xs { --avatar-size: 24px; --avatar-font: 10px; }
|
|
599
|
+
.avatar--sm { --avatar-size: 32px; --avatar-font: 12px; }
|
|
600
|
+
.avatar--lg { --avatar-size: 48px; --avatar-font: 18px; }
|
|
601
|
+
.avatar--xl { --avatar-size: 64px; --avatar-font: 24px; }
|
|
602
|
+
.avatar img {
|
|
603
|
+
width: 100%; height: 100%; object-fit: cover;
|
|
604
|
+
border-radius: inherit;
|
|
605
|
+
}
|
|
606
|
+
.avatar__dot {
|
|
607
|
+
position: absolute; right: 0; bottom: 0;
|
|
608
|
+
width: max(28%, 8px); height: max(28%, 8px);
|
|
609
|
+
border-radius: var(--radius-full); border: 2px solid var(--bg);
|
|
610
|
+
}
|
|
611
|
+
.avatar__dot--online { background: var(--success); }
|
|
612
|
+
.avatar__dot--busy { background: var(--danger); }
|
|
613
|
+
.avatar__dot--away { background: var(--warning); }
|
|
614
|
+
.avatar__dot--offline { background: var(--border); }
|
|
615
|
+
|
|
616
|
+
/* ============================================================
|
|
617
|
+
12B. DIVIDER — .divider (hairline), .divider--label, .divider--vertical
|
|
618
|
+
============================================================ */
|
|
619
|
+
.divider { border: 0; border-top: 1px solid var(--border); margin: var(--space-4) 0; }
|
|
620
|
+
.divider--label {
|
|
621
|
+
display: flex; align-items: center; gap: 12px; border: 0; margin: var(--space-4) 0;
|
|
622
|
+
color: var(--text-muted); font-size: var(--text-xs); font-weight: 500;
|
|
623
|
+
text-transform: uppercase; letter-spacing: var(--tracking-overline);
|
|
624
|
+
}
|
|
625
|
+
.divider--label::before, .divider--label::after {
|
|
626
|
+
content: ""; flex: 1; border-top: 1px solid var(--border);
|
|
627
|
+
}
|
|
628
|
+
.divider--vertical {
|
|
629
|
+
display: inline-block; align-self: stretch; width: 1px;
|
|
630
|
+
background: var(--border); border: 0; margin: 0 var(--space-3);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/* ============================================================
|
|
634
|
+
13. STAT — cifra de dashboard con count-up (JS opcional)
|
|
635
|
+
============================================================ */
|
|
636
|
+
.stat { display: flex; flex-direction: column; gap: 6px; }
|
|
637
|
+
.stat__label {
|
|
638
|
+
font-size: var(--text-xs); font-weight: 500; text-transform: uppercase;
|
|
639
|
+
letter-spacing: var(--tracking-overline); color: var(--text-muted);
|
|
640
|
+
}
|
|
641
|
+
.stat__value {
|
|
642
|
+
font-family: var(--font-mono); font-size: var(--text-5xl); font-weight: 500;
|
|
643
|
+
line-height: var(--leading-tight); color: var(--data-color);
|
|
644
|
+
font-variant-numeric: tabular-nums; white-space: nowrap;
|
|
645
|
+
}
|
|
646
|
+
.stat__delta { font-family: var(--font-mono); font-size: var(--text-sm); display: inline-flex; align-items: center; gap: 4px; }
|
|
647
|
+
.stat__delta--up { color: var(--success); }
|
|
648
|
+
.stat__delta--down { color: var(--danger); }
|
|
649
|
+
.stat__delta--neutral { color: var(--text-muted); }
|
|
650
|
+
|
|
651
|
+
/* ============================================================
|
|
652
|
+
13B. PAGINATION — .pagination (activa: fondo acento + peso, no solo color)
|
|
653
|
+
============================================================ */
|
|
654
|
+
.pagination { display: flex; align-items: center; gap: 4px; list-style: none; margin: 0; padding: 0; }
|
|
655
|
+
.pagination__btn {
|
|
656
|
+
display: inline-grid; place-items: center;
|
|
657
|
+
min-width: 36px; height: 36px; padding: 0 8px;
|
|
658
|
+
border: 0; border-radius: var(--radius-sm); background: transparent;
|
|
659
|
+
font-family: var(--font-body); font-size: var(--text-sm); font-weight: 500;
|
|
660
|
+
color: var(--text-secondary); cursor: pointer;
|
|
661
|
+
transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
|
|
662
|
+
}
|
|
663
|
+
.pagination__btn:hover:not(:disabled):not(.is-active) { background: var(--surface-2); color: var(--text-primary); }
|
|
664
|
+
.pagination__btn:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-ring-offset); }
|
|
665
|
+
.pagination__btn.is-active {
|
|
666
|
+
background: var(--accent-400); color: var(--text-on-accent); font-weight: 700;
|
|
667
|
+
}
|
|
668
|
+
.pagination__btn:disabled { color: var(--text-disabled); cursor: not-allowed; }
|
|
669
|
+
.pagination__btn svg { width: 16px; height: 16px; }
|
|
670
|
+
.pagination__ellipsis { color: var(--text-disabled); padding: 0 4px; user-select: none; }
|
|
671
|
+
|
|
672
|
+
/* ============================================================
|
|
673
|
+
14. CARD — elevación nivel 1; interactiva sube de nivel
|
|
674
|
+
============================================================ */
|
|
675
|
+
.card {
|
|
676
|
+
background: var(--surface-1);
|
|
677
|
+
border: 1px solid var(--card-border);
|
|
678
|
+
border-radius: var(--radius-lg);
|
|
679
|
+
padding: var(--card-padding);
|
|
680
|
+
box-shadow: var(--shadow-1);
|
|
681
|
+
}
|
|
682
|
+
@media (max-width: 639px) { .card { padding: var(--card-padding-mobile); } }
|
|
683
|
+
.card--interactive {
|
|
684
|
+
cursor: pointer;
|
|
685
|
+
transition: transform var(--duration-base) var(--ease-out),
|
|
686
|
+
background-color var(--duration-base) var(--ease-out),
|
|
687
|
+
box-shadow var(--duration-base) var(--ease-out);
|
|
688
|
+
}
|
|
689
|
+
.card--interactive:hover { background: var(--surface-2); }
|
|
690
|
+
@media (hover: hover) and (pointer: fine) {
|
|
691
|
+
.card--interactive:hover { transform: translateY(-2px); box-shadow: var(--shadow-2); }
|
|
692
|
+
}
|
|
693
|
+
/* Glow de marca: MÁXIMO UNO POR PANTALLA (solo el elemento hero/CTA) */
|
|
694
|
+
.card--glow { box-shadow: var(--glow-accent); }
|
|
695
|
+
|
|
696
|
+
/* ============================================================
|
|
697
|
+
15. TOOLTIP — .has-tooltip > .tooltip (delay 400ms)
|
|
698
|
+
============================================================ */
|
|
699
|
+
.has-tooltip { position: relative; display: inline-flex; }
|
|
700
|
+
.tooltip {
|
|
701
|
+
position: absolute; bottom: calc(100% + 8px); left: 50%;
|
|
702
|
+
transform: translate(-50%, 4px);
|
|
703
|
+
background: var(--tooltip-bg); border: 1px solid var(--tooltip-border);
|
|
704
|
+
color: var(--tooltip-text); font-size: var(--text-xs); line-height: var(--leading-snug);
|
|
705
|
+
padding: 6px 10px; border-radius: var(--radius-sm); white-space: nowrap;
|
|
706
|
+
opacity: 0; pointer-events: none;
|
|
707
|
+
transition: opacity var(--duration-fast) var(--ease-out) 0ms,
|
|
708
|
+
transform var(--duration-fast) var(--ease-out) 0ms;
|
|
709
|
+
}
|
|
710
|
+
.has-tooltip:focus-visible .tooltip {
|
|
711
|
+
opacity: 1; transform: translate(-50%, 0);
|
|
712
|
+
transition-delay: 400ms, 400ms;
|
|
713
|
+
}
|
|
714
|
+
/* Tooltip por hover solo con puntero real — en touch quedaría pegado tras el tap */
|
|
715
|
+
@media (hover: hover) and (pointer: fine) {
|
|
716
|
+
.has-tooltip:hover .tooltip {
|
|
717
|
+
opacity: 1; transform: translate(-50%, 0);
|
|
718
|
+
transition-delay: 400ms, 400ms;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/* ============================================================
|
|
723
|
+
ALERT — .alert (banner inline persistente; vs Toast, transitorio)
|
|
724
|
+
Estado por icono + texto + color — nunca solo color.
|
|
725
|
+
============================================================ */
|
|
726
|
+
.alert {
|
|
727
|
+
display: flex; gap: 12px; align-items: flex-start;
|
|
728
|
+
padding: 14px 16px; border-radius: var(--radius-md); border: 1px solid;
|
|
729
|
+
font-size: var(--text-sm);
|
|
730
|
+
}
|
|
731
|
+
.alert > svg { width: 20px; height: 20px; flex: none; margin-top: 1px; }
|
|
732
|
+
.alert__title { font-weight: 600; margin: 0 0 2px; color: inherit; }
|
|
733
|
+
.alert__body { margin: 0; color: inherit; opacity: .88; }
|
|
734
|
+
.alert__close {
|
|
735
|
+
margin-left: auto; flex: none; display: grid; place-items: center;
|
|
736
|
+
width: 36px; height: 36px; border: 0; border-radius: var(--radius-sm);
|
|
737
|
+
background: transparent; color: inherit; cursor: pointer; opacity: .75;
|
|
738
|
+
transition: opacity var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out);
|
|
739
|
+
}
|
|
740
|
+
.alert__close:hover { opacity: 1; background: color-mix(in srgb, currentColor 14%, transparent); }
|
|
741
|
+
.alert__close svg { width: 18px; height: 18px; }
|
|
742
|
+
.alert--info { background: var(--info-bg); color: var(--info); border-color: color-mix(in srgb, var(--info) 30%, transparent); }
|
|
743
|
+
.alert--success { background: var(--success-bg); color: var(--success); border-color: color-mix(in srgb, var(--success) 30%, transparent); }
|
|
744
|
+
.alert--warning { background: var(--warning-bg); color: var(--warning); border-color: color-mix(in srgb, var(--warning) 30%, transparent); }
|
|
745
|
+
.alert--danger { background: var(--danger-bg); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 30%, transparent); }
|
|
746
|
+
.alert.is-leaving { animation: ne-alert-out 200ms var(--ease-in) forwards; }
|
|
747
|
+
@keyframes ne-alert-out { to { opacity: 0; transform: scale(.98); } }
|
|
748
|
+
|
|
749
|
+
/* ============================================================
|
|
750
|
+
16. TOAST — .toast-stack (fixed) + .toast
|
|
751
|
+
============================================================ */
|
|
752
|
+
.toast-stack {
|
|
753
|
+
position: fixed; top: var(--space-4); right: var(--space-4); z-index: 90;
|
|
754
|
+
display: flex; flex-direction: column; gap: 12px; width: 360px; max-width: calc(100vw - 32px);
|
|
755
|
+
}
|
|
756
|
+
@media (max-width: 639px) { .toast-stack { right: 50%; transform: translateX(50%); } }
|
|
757
|
+
.toast {
|
|
758
|
+
display: flex; gap: 10px; align-items: flex-start;
|
|
759
|
+
background: var(--surface-2); border: 1px solid var(--elevated-border);
|
|
760
|
+
border-left-width: 3px; border-radius: var(--radius-md);
|
|
761
|
+
padding: 14px 16px; box-shadow: var(--shadow-3);
|
|
762
|
+
/* Entrada interrumpible (§11.2): transition + @starting-style, no @keyframes —
|
|
763
|
+
un keyframe no puede invertirse si el toast se apila o se descarta a mitad. */
|
|
764
|
+
opacity: 1; transform: none;
|
|
765
|
+
transition: opacity var(--duration-slow) var(--ease-out),
|
|
766
|
+
transform var(--duration-slow) var(--ease-out);
|
|
767
|
+
}
|
|
768
|
+
@starting-style {
|
|
769
|
+
.toast { opacity: 0; transform: translateX(24px); }
|
|
770
|
+
}
|
|
771
|
+
.toast--success { border-left-color: var(--success); } .toast--success > svg { color: var(--success); }
|
|
772
|
+
.toast--warning { border-left-color: var(--warning); } .toast--warning > svg { color: var(--warning); }
|
|
773
|
+
.toast--danger { border-left-color: var(--danger); } .toast--danger > svg { color: var(--danger); }
|
|
774
|
+
.toast--info { border-left-color: var(--info); } .toast--info > svg { color: var(--info); }
|
|
775
|
+
.toast > svg { width: 20px; height: 20px; flex: none; margin-top: 1px; }
|
|
776
|
+
.toast__title { font-size: var(--text-sm); font-weight: 600; color: var(--text-primary); }
|
|
777
|
+
.toast__body { font-size: var(--text-sm); color: var(--text-muted); }
|
|
778
|
+
.toast.is-leaving { animation: ne-toast-out 200ms var(--ease-in) forwards; }
|
|
779
|
+
@keyframes ne-toast-out { to { opacity: 0; transform: translateX(24px); } }
|
|
780
|
+
|
|
781
|
+
/* ============================================================
|
|
782
|
+
17. MODAL — .modal-overlay + .modal
|
|
783
|
+
============================================================ */
|
|
784
|
+
.modal-overlay {
|
|
785
|
+
position: fixed; inset: 0; z-index: 100;
|
|
786
|
+
display: grid; place-items: center; padding: var(--space-4);
|
|
787
|
+
background: var(--overlay); backdrop-filter: blur(4px);
|
|
788
|
+
animation: ne-fade var(--duration-base) var(--ease-out);
|
|
789
|
+
}
|
|
790
|
+
.modal-overlay[hidden] { display: none; }
|
|
791
|
+
.modal {
|
|
792
|
+
width: 100%; max-width: 480px;
|
|
793
|
+
background: var(--surface-2); border: 1px solid var(--elevated-border);
|
|
794
|
+
border-radius: var(--radius-lg); box-shadow: var(--shadow-3);
|
|
795
|
+
padding: var(--card-padding);
|
|
796
|
+
animation: ne-modal-in var(--duration-slow) var(--ease-out);
|
|
797
|
+
}
|
|
798
|
+
.modal--lg { max-width: 640px; }
|
|
799
|
+
.modal__header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-4); }
|
|
800
|
+
.modal__title { font-family: var(--font-body); font-size: var(--text-xl); font-weight: 600; color: var(--text-heading); margin: 0; }
|
|
801
|
+
.modal__footer { display: flex; justify-content: flex-end; gap: var(--space-3); margin-top: var(--space-6); }
|
|
802
|
+
@keyframes ne-fade { from { opacity: 0; } }
|
|
803
|
+
@keyframes ne-modal-in { from { opacity: 0; transform: scale(.96); } }
|
|
804
|
+
|
|
805
|
+
/* ============================================================
|
|
806
|
+
18. TABLA — .table
|
|
807
|
+
============================================================ */
|
|
808
|
+
.table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
|
|
809
|
+
.table th {
|
|
810
|
+
background: var(--table-header-bg);
|
|
811
|
+
font-size: var(--text-xs); font-weight: 500; text-transform: uppercase;
|
|
812
|
+
letter-spacing: var(--tracking-overline); color: var(--text-muted);
|
|
813
|
+
text-align: left; padding: 12px 16px;
|
|
814
|
+
border-bottom: 1px solid var(--border-strong);
|
|
815
|
+
}
|
|
816
|
+
.table td {
|
|
817
|
+
height: 52px; padding: 8px 16px;
|
|
818
|
+
border-bottom: 1px solid var(--row-border);
|
|
819
|
+
color: var(--text-secondary);
|
|
820
|
+
}
|
|
821
|
+
.table tbody tr { transition: background-color var(--duration-fast) var(--ease-out); }
|
|
822
|
+
.table tbody tr:hover { background: var(--row-hover); }
|
|
823
|
+
.table tbody tr.is-selected { background: var(--accent-selected); box-shadow: inset 2px 0 0 var(--accent-400); }
|
|
824
|
+
.table .num, .table td.num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
|
|
825
|
+
|
|
826
|
+
/* ============================================================
|
|
827
|
+
19. NAVEGACIÓN — .navbar, .sidebar, .tabs, .breadcrumbs
|
|
828
|
+
============================================================ */
|
|
829
|
+
.navbar {
|
|
830
|
+
position: sticky; top: 0; z-index: 50;
|
|
831
|
+
display: flex; align-items: center; gap: var(--space-6);
|
|
832
|
+
height: 64px; padding: 0 var(--space-6);
|
|
833
|
+
background: var(--navbar-bg); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
|
|
834
|
+
border-bottom: 1px solid var(--elevated-border);
|
|
835
|
+
}
|
|
836
|
+
.navbar__links { display: flex; gap: var(--space-2); align-items: center; height: 100%; }
|
|
837
|
+
.navbar__link {
|
|
838
|
+
position: relative; display: inline-flex; align-items: center; height: 100%;
|
|
839
|
+
padding: 0 var(--space-3); color: var(--text-secondary); font-size: var(--text-sm); font-weight: 500;
|
|
840
|
+
transition: color var(--duration-fast) var(--ease-out);
|
|
841
|
+
}
|
|
842
|
+
.navbar__link:hover { color: var(--text-primary); }
|
|
843
|
+
.navbar__link.is-active { color: var(--nav-active); }
|
|
844
|
+
.navbar__link.is-active::after {
|
|
845
|
+
content: ""; position: absolute; left: var(--space-3); right: var(--space-3); bottom: 0;
|
|
846
|
+
height: 2px; background: var(--accent-400);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
.sidebar {
|
|
850
|
+
width: 260px; padding: var(--space-3);
|
|
851
|
+
background: var(--sidebar-bg); border-right: 1px solid var(--row-border);
|
|
852
|
+
display: flex; flex-direction: column; gap: 2px;
|
|
853
|
+
}
|
|
854
|
+
.sidebar__item {
|
|
855
|
+
display: flex; align-items: center; gap: 10px;
|
|
856
|
+
padding: 10px 12px; border-radius: var(--radius-md);
|
|
857
|
+
color: var(--text-secondary); font-size: var(--text-sm); font-weight: 500;
|
|
858
|
+
transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
|
|
859
|
+
}
|
|
860
|
+
.sidebar__item:hover { background: var(--surface-2); color: var(--text-primary); }
|
|
861
|
+
.sidebar__item.is-active { background: var(--sidebar-active-bg); color: var(--sidebar-active-text); }
|
|
862
|
+
.sidebar__item svg { width: 18px; height: 18px; color: var(--text-muted); flex: none; }
|
|
863
|
+
.sidebar__item.is-active svg { color: var(--sidebar-active-icon); }
|
|
864
|
+
|
|
865
|
+
.tabs { position: relative; display: flex; gap: var(--space-2); border-bottom: 1px solid var(--border-strong); }
|
|
866
|
+
.tabs__btn {
|
|
867
|
+
padding: 10px 14px; border: 0; background: transparent; cursor: pointer;
|
|
868
|
+
color: var(--text-secondary); font-family: var(--font-body); font-size: var(--text-sm); font-weight: 500;
|
|
869
|
+
transition: color var(--duration-fast) var(--ease-out);
|
|
870
|
+
}
|
|
871
|
+
.tabs__btn:hover { color: var(--text-primary); }
|
|
872
|
+
.tabs__btn.is-active { color: var(--text-primary); }
|
|
873
|
+
.tabs__indicator {
|
|
874
|
+
position: absolute; bottom: -1px; left: 0; height: 2px; width: 0;
|
|
875
|
+
background: var(--accent-400);
|
|
876
|
+
/* Se mueve de A a B en pantalla → --ease-in-out (§11.2) */
|
|
877
|
+
transition: transform var(--duration-slow) var(--ease-in-out), width var(--duration-slow) var(--ease-in-out);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.breadcrumbs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); list-style: none; margin: 0; padding: 0; font-size: var(--text-sm); }
|
|
881
|
+
.breadcrumbs li { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--text-muted); }
|
|
882
|
+
.breadcrumbs li + li::before { content: "/"; color: var(--text-disabled); }
|
|
883
|
+
.breadcrumbs a { color: var(--text-muted); } .breadcrumbs a:hover { color: var(--text-primary); }
|
|
884
|
+
.breadcrumbs li:last-child { color: var(--text-primary); }
|
|
885
|
+
|
|
886
|
+
/* ============================================================
|
|
887
|
+
20. ACCORDION — .accordion (animación grid-template-rows)
|
|
888
|
+
============================================================ */
|
|
889
|
+
.accordion { border: 1px solid var(--elevated-border); border-radius: var(--radius-lg); overflow: hidden; }
|
|
890
|
+
.accordion__item { background: var(--surface-1); }
|
|
891
|
+
.accordion__item + .accordion__item { border-top: 1px solid var(--row-border); }
|
|
892
|
+
.accordion__header {
|
|
893
|
+
display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
|
|
894
|
+
width: 100%; padding: 16px 20px; border: 0; background: transparent; cursor: pointer;
|
|
895
|
+
color: var(--text-primary); font-family: var(--font-body); font-size: var(--text-base); font-weight: 500; text-align: left;
|
|
896
|
+
transition: background-color var(--duration-fast) var(--ease-out);
|
|
897
|
+
}
|
|
898
|
+
.accordion__header:hover { background: var(--surface-2); }
|
|
899
|
+
.accordion__header svg {
|
|
900
|
+
width: 18px; height: 18px; color: var(--text-muted); flex: none;
|
|
901
|
+
transition: transform var(--duration-slow) var(--ease-out);
|
|
902
|
+
}
|
|
903
|
+
.accordion__header[aria-expanded="true"] svg { transform: rotate(180deg); }
|
|
904
|
+
.accordion__panel {
|
|
905
|
+
display: grid; grid-template-rows: 0fr;
|
|
906
|
+
transition: grid-template-rows var(--duration-slow) var(--ease-out);
|
|
907
|
+
}
|
|
908
|
+
.accordion__header[aria-expanded="true"] + .accordion__panel { grid-template-rows: 1fr; }
|
|
909
|
+
.accordion__inner { overflow: hidden; }
|
|
910
|
+
.accordion__content {
|
|
911
|
+
padding: 0 20px 18px; font-size: 15px; line-height: var(--leading-body); color: var(--text-muted);
|
|
912
|
+
opacity: 0; transition: opacity var(--duration-slow) var(--ease-out);
|
|
913
|
+
}
|
|
914
|
+
.accordion__header[aria-expanded="true"] + .accordion__panel .accordion__content { opacity: 1; }
|
|
915
|
+
|
|
916
|
+
/* ============================================================
|
|
917
|
+
21. PROGRESS BAR — .progress (con glow de acento)
|
|
918
|
+
============================================================ */
|
|
919
|
+
.progress__head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; }
|
|
920
|
+
.progress__label { font-size: var(--text-sm); color: var(--text-secondary); }
|
|
921
|
+
.progress__value { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--data-color); font-variant-numeric: tabular-nums; }
|
|
922
|
+
.progress {
|
|
923
|
+
height: 6px; background: var(--surface-3); border-radius: var(--radius-full); overflow: hidden;
|
|
924
|
+
}
|
|
925
|
+
.progress__bar {
|
|
926
|
+
height: 100%; width: 0; background: var(--accent-400); border-radius: inherit;
|
|
927
|
+
box-shadow: 0 0 12px rgba(82,186,237,.5);
|
|
928
|
+
transition: width 300ms var(--ease-out);
|
|
929
|
+
}
|
|
930
|
+
.progress--no-glow .progress__bar { box-shadow: none; }
|
|
931
|
+
.progress--indeterminate .progress__bar { width: 40%; animation: ne-sweep 1.2s var(--ease-out) infinite; }
|
|
932
|
+
@keyframes ne-sweep { from { transform: translateX(-100%); } to { transform: translateX(250%); } }
|
|
933
|
+
|
|
934
|
+
.progress-ring { display: inline-grid; place-items: center; position: relative; }
|
|
935
|
+
.progress-ring svg { transform: rotate(-90deg); }
|
|
936
|
+
.progress-ring__track { fill: none; stroke: var(--surface-3); }
|
|
937
|
+
.progress-ring__bar {
|
|
938
|
+
fill: none; stroke: var(--accent-400); stroke-linecap: round;
|
|
939
|
+
transition: stroke-dashoffset var(--duration-slow) var(--ease-out);
|
|
940
|
+
}
|
|
941
|
+
.progress-ring__value {
|
|
942
|
+
position: absolute; font-family: var(--font-mono); font-size: var(--text-sm);
|
|
943
|
+
font-weight: 600; color: var(--data-color); font-variant-numeric: tabular-nums;
|
|
944
|
+
}
|
|
945
|
+
@media (prefers-reduced-motion: reduce) {
|
|
946
|
+
/* La regla global (§3) ya cubre el <circle>, pero se deja explícito
|
|
947
|
+
como en .slider::-webkit-slider-thumb: el anillo es la única animación
|
|
948
|
+
nueva de esta sección y no debe depender solo de la regla universal. */
|
|
949
|
+
.progress-ring__bar { transition-duration: 0.01ms !important; }
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
/* ============================================================
|
|
953
|
+
22. LINK Y CODE — .link (subrayado animado), .code (inline)
|
|
954
|
+
============================================================ */
|
|
955
|
+
.link { position: relative; display: inline-flex; align-items: center; gap: 4px; color: var(--link); }
|
|
956
|
+
.link::after {
|
|
957
|
+
content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
|
|
958
|
+
background: currentColor; transform: scaleX(0); transform-origin: left;
|
|
959
|
+
transition: transform 200ms var(--ease-out);
|
|
960
|
+
}
|
|
961
|
+
.link:hover { color: var(--link-hover); }
|
|
962
|
+
.link:hover::after { transform: scaleX(1); }
|
|
963
|
+
.link svg { width: 12px; height: 12px; }
|
|
964
|
+
|
|
965
|
+
.code {
|
|
966
|
+
font-family: var(--font-mono); font-size: .9em;
|
|
967
|
+
color: var(--code-color); background: var(--surface-2);
|
|
968
|
+
border: 1px solid var(--code-border); border-radius: 6px; padding: 1px 6px;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
/* ============================================================
|
|
972
|
+
23. SKELETON Y EMPTY STATE
|
|
973
|
+
============================================================ */
|
|
974
|
+
.skeleton {
|
|
975
|
+
position: relative; overflow: hidden;
|
|
976
|
+
background: var(--skeleton-base); border-radius: var(--radius-sm);
|
|
977
|
+
}
|
|
978
|
+
.skeleton--circle { border-radius: var(--radius-full); }
|
|
979
|
+
.skeleton::after {
|
|
980
|
+
content: ""; position: absolute; inset: 0;
|
|
981
|
+
background: linear-gradient(90deg, transparent, var(--skeleton-sheen), transparent);
|
|
982
|
+
transform: translateX(-100%);
|
|
983
|
+
animation: ne-shimmer 1.4s infinite;
|
|
984
|
+
}
|
|
985
|
+
@keyframes ne-shimmer { to { transform: translateX(100%); } }
|
|
986
|
+
|
|
987
|
+
.empty-state {
|
|
988
|
+
display: flex; flex-direction: column; align-items: center; text-align: center;
|
|
989
|
+
gap: var(--space-2); padding: var(--space-10) var(--space-6);
|
|
990
|
+
}
|
|
991
|
+
.empty-state svg { width: 40px; height: 40px; color: var(--empty-icon); margin-bottom: var(--space-2); }
|
|
992
|
+
.empty-state__title { font-size: var(--text-lg); font-weight: 600; color: var(--text-primary); }
|
|
993
|
+
.empty-state__desc { font-size: var(--text-sm); color: var(--text-muted); max-width: 36ch; }
|
|
994
|
+
.empty-state .btn { margin-top: var(--space-3); }
|
|
995
|
+
|
|
996
|
+
/* ============================================================
|
|
997
|
+
24. UTILIDADES MÍNIMAS
|
|
998
|
+
============================================================ */
|
|
999
|
+
.overline {
|
|
1000
|
+
font-size: var(--text-xs); font-weight: 500; text-transform: uppercase;
|
|
1001
|
+
letter-spacing: var(--tracking-overline); color: var(--text-muted);
|
|
1002
|
+
}
|
|
1003
|
+
.text-muted { color: var(--text-muted); }
|
|
1004
|
+
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
|
|
1005
|
+
.visually-hidden {
|
|
1006
|
+
position: absolute; width: 1px; height: 1px; margin: -1px;
|
|
1007
|
+
clip-path: inset(50%); overflow: hidden; white-space: nowrap;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
|
|
1011
|
+
/* ============================================================
|
|
1012
|
+
ESTILOS DE LA PÁGINA DE DOCS (.ds-*)
|
|
1013
|
+
============================================================ */
|
|
1014
|
+
html { scroll-behavior: smooth; }
|
|
1015
|
+
.ds-topbar {
|
|
1016
|
+
position: fixed; top: 0; left: 0; right: 0; z-index: 60;
|
|
1017
|
+
display: flex; align-items: center; gap: var(--space-4);
|
|
1018
|
+
height: 64px; padding: 0 var(--space-6);
|
|
1019
|
+
background: var(--navbar-bg); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
|
|
1020
|
+
border-bottom: 1px solid var(--elevated-border);
|
|
1021
|
+
}
|
|
1022
|
+
.ds-wordmark {
|
|
1023
|
+
font-family: var(--font-display); font-weight: 700; font-size: var(--text-xl);
|
|
1024
|
+
letter-spacing: var(--tracking-display); color: var(--text-heading); text-decoration: none;
|
|
1025
|
+
}
|
|
1026
|
+
.ds-wordmark .ds-dot { color: var(--accent-400); }
|
|
1027
|
+
.ds-version {
|
|
1028
|
+
font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-muted);
|
|
1029
|
+
border: 1px solid var(--border); border-radius: var(--radius-full); padding: 2px 10px;
|
|
1030
|
+
}
|
|
1031
|
+
.ds-topbar__spacer { flex: 1; }
|
|
1032
|
+
.ds-theme-toggle .ds-icon-sun { display: none; }
|
|
1033
|
+
[data-theme="light"] .ds-theme-toggle .ds-icon-sun { display: block; }
|
|
1034
|
+
[data-theme="light"] .ds-theme-toggle .ds-icon-moon { display: none; }
|
|
1035
|
+
.ds-hamburger { display: none; }
|
|
1036
|
+
|
|
1037
|
+
.ds-sidebar {
|
|
1038
|
+
position: fixed; top: 64px; bottom: 0; left: 0; z-index: 55;
|
|
1039
|
+
width: 260px; overflow-y: auto; padding: var(--space-6) var(--space-4) var(--space-10);
|
|
1040
|
+
background: var(--bg); border-right: 1px solid var(--row-border);
|
|
1041
|
+
}
|
|
1042
|
+
.ds-nav { display: flex; flex-direction: column; gap: 1px; }
|
|
1043
|
+
.ds-group { margin: var(--space-5) 0 var(--space-2); }
|
|
1044
|
+
.ds-group:first-child { margin-top: 0; }
|
|
1045
|
+
.ds-nav a {
|
|
1046
|
+
display: block; padding: 7px 12px; border-radius: var(--radius-md);
|
|
1047
|
+
color: var(--text-muted); font-size: var(--text-sm); text-decoration: none;
|
|
1048
|
+
transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
|
|
1049
|
+
}
|
|
1050
|
+
.ds-nav a:hover { background: var(--surface-2); color: var(--text-primary); }
|
|
1051
|
+
.ds-nav a.is-active { background: var(--sidebar-active-bg); color: var(--sidebar-active-text); }
|
|
1052
|
+
.ds-nav__sub a { padding-left: 24px; font-size: 13px; }
|
|
1053
|
+
|
|
1054
|
+
.ds-main { margin-left: 260px; padding: calc(64px + var(--space-10)) var(--space-12) var(--space-24); }
|
|
1055
|
+
.ds-main > section { max-width: 920px; margin: 0 auto var(--section-gap); scroll-margin-top: 88px; }
|
|
1056
|
+
.ds-main > section > h2 { margin-top: 0; }
|
|
1057
|
+
.ds-lead { font-size: var(--text-lg); color: var(--text-secondary); }
|
|
1058
|
+
|
|
1059
|
+
.ds-hero { padding-top: var(--space-6); }
|
|
1060
|
+
.ds-hero h1 { font-size: var(--text-4xl); margin-bottom: var(--space-3); }
|
|
1061
|
+
.ds-hero-cta { box-shadow: var(--glow-accent); } /* el ÚNICO glow permanente de la página */
|
|
1062
|
+
.ds-palette-chips { display: flex; gap: var(--space-2); margin: var(--space-4) 0; flex-wrap: wrap; }
|
|
1063
|
+
.ds-palette-chips .code { font-size: var(--text-xs); }
|
|
1064
|
+
|
|
1065
|
+
.ds-demo {
|
|
1066
|
+
display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4);
|
|
1067
|
+
background: var(--surface-1); border: 1px solid var(--card-border);
|
|
1068
|
+
border-radius: var(--radius-lg); padding: var(--space-8); margin-top: var(--space-4);
|
|
1069
|
+
}
|
|
1070
|
+
.ds-demo--col { flex-direction: column; align-items: stretch; }
|
|
1071
|
+
.ds-demo--grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); align-items: start; }
|
|
1072
|
+
.ds-demo:has(table) { overflow-x: auto; }
|
|
1073
|
+
|
|
1074
|
+
.ds-code { margin-top: var(--space-3); border: 1px solid var(--row-border); border-radius: var(--radius-md); overflow: hidden; }
|
|
1075
|
+
.ds-code summary {
|
|
1076
|
+
display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
|
|
1077
|
+
padding: 10px 16px; cursor: pointer; user-select: none;
|
|
1078
|
+
font-size: var(--text-sm); color: var(--text-muted); list-style: none;
|
|
1079
|
+
}
|
|
1080
|
+
.ds-code summary::-webkit-details-marker { display: none; }
|
|
1081
|
+
.ds-code summary:hover { color: var(--text-primary); background: var(--surface-1); }
|
|
1082
|
+
.ds-code pre {
|
|
1083
|
+
margin: 0; padding: var(--space-4); overflow-x: auto;
|
|
1084
|
+
background: var(--surface-1); border-top: 1px solid var(--row-border);
|
|
1085
|
+
font-family: var(--font-mono); font-size: var(--text-sm); line-height: 1.7;
|
|
1086
|
+
color: var(--text-secondary);
|
|
1087
|
+
}
|
|
1088
|
+
.ds-copy {
|
|
1089
|
+
border: 1px solid var(--border); background: transparent; color: var(--text-muted);
|
|
1090
|
+
font-family: var(--font-body); font-size: var(--text-xs); font-weight: 600;
|
|
1091
|
+
padding: 4px 12px; border-radius: var(--radius-full); cursor: pointer;
|
|
1092
|
+
transition: color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);
|
|
1093
|
+
}
|
|
1094
|
+
.ds-copy:hover { color: var(--link); border-color: var(--accent-700); }
|
|
1095
|
+
.ds-copy.is-done { color: var(--success); border-color: var(--success); }
|
|
1096
|
+
/* Resaltado de sintaxis de los ejemplos (tokens semánticos, sigue el tema) */
|
|
1097
|
+
.ds-code pre .tok-com { color: var(--text-muted); font-style: italic; }
|
|
1098
|
+
.ds-code pre .tok-str { color: var(--success); }
|
|
1099
|
+
.ds-code pre .tok-tag { color: var(--accent-300); }
|
|
1100
|
+
.ds-code pre .tok-attr { color: var(--warning); }
|
|
1101
|
+
.ds-code pre .tok-var { color: var(--accent-400); }
|
|
1102
|
+
.ds-code pre .tok-punct { color: var(--text-muted); }
|
|
1103
|
+
|
|
1104
|
+
.ds-swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: var(--space-3); margin-top: var(--space-4); }
|
|
1105
|
+
.ds-swatch { border: 1px solid var(--row-border); border-radius: var(--radius-md); overflow: hidden; cursor: pointer; background: var(--surface-1); transition: transform var(--duration-base) var(--ease-out); }
|
|
1106
|
+
@media (hover: hover) and (pointer: fine) {
|
|
1107
|
+
.ds-swatch:hover { transform: translateY(-2px); }
|
|
1108
|
+
}
|
|
1109
|
+
.ds-swatch__chip { height: 56px; }
|
|
1110
|
+
.ds-swatch__meta { padding: 8px 10px; display: flex; flex-direction: column; gap: 2px; }
|
|
1111
|
+
.ds-swatch__name { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-primary); }
|
|
1112
|
+
.ds-swatch__hex { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-muted); }
|
|
1113
|
+
|
|
1114
|
+
.ds-callout {
|
|
1115
|
+
display: flex; gap: 10px; align-items: flex-start;
|
|
1116
|
+
border-radius: var(--radius-md); padding: 14px 16px; margin: var(--space-4) 0;
|
|
1117
|
+
font-size: var(--text-sm); border: 1px solid;
|
|
1118
|
+
}
|
|
1119
|
+
.ds-callout svg { width: 18px; height: 18px; flex: none; margin-top: 2px; }
|
|
1120
|
+
.ds-callout--warning { background: var(--warning-bg); color: var(--warning); border-color: color-mix(in srgb, var(--warning) 30%, transparent); }
|
|
1121
|
+
.ds-callout--info { background: var(--info-bg); color: var(--info); border-color: color-mix(in srgb, var(--info) 30%, transparent); }
|
|
1122
|
+
|
|
1123
|
+
.ds-type-row { display: flex; align-items: baseline; gap: var(--space-5); padding: var(--space-3) 0; border-bottom: 1px solid var(--row-border); }
|
|
1124
|
+
.ds-type-row:last-child { border-bottom: 0; }
|
|
1125
|
+
.ds-type-meta { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-muted); min-width: 170px; }
|
|
1126
|
+
.ds-type-row { min-width: 0; max-width: 100%; overflow: hidden; }
|
|
1127
|
+
.ds-type-row > span:last-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1128
|
+
|
|
1129
|
+
.ds-space-row { display: flex; align-items: center; gap: var(--space-4); padding: 4px 0; min-width: 0; max-width: 100%; overflow-x: auto; }
|
|
1130
|
+
.ds-space-row .ds-type-meta { min-width: 120px; }
|
|
1131
|
+
.ds-space-bar { height: 14px; background: var(--accent-400); border-radius: 3px; opacity: .85; }
|
|
1132
|
+
|
|
1133
|
+
.ds-radius-demo { width: 96px; height: 72px; background: var(--surface-3); border: 1px solid var(--border); display: grid; place-content: center; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-muted); }
|
|
1134
|
+
.ds-elev-demo { width: 100%; min-height: 96px; border-radius: var(--radius-lg); display: grid; place-content: center; text-align: center; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-muted); gap: 4px; padding: var(--space-4); }
|
|
1135
|
+
|
|
1136
|
+
.ds-icon-grid { display: flex; flex-wrap: wrap; gap: var(--space-4); }
|
|
1137
|
+
.ds-icon-cell { display: flex; flex-direction: column; align-items: center; gap: 6px; width: 84px; padding: var(--space-3) 0; border: 1px solid var(--row-border); border-radius: var(--radius-md); font-family: var(--font-mono); font-size: 10px; color: var(--text-muted); }
|
|
1138
|
+
.ds-icon-cell svg { width: 20px; height: 20px; color: var(--text-primary); }
|
|
1139
|
+
|
|
1140
|
+
.ds-wordmark-demo { font-family: var(--font-display); font-weight: 700; font-size: var(--text-3xl); letter-spacing: var(--tracking-display); color: var(--text-heading); }
|
|
1141
|
+
.ds-wordmark-demo .ds-dot { color: var(--accent-400); }
|
|
1142
|
+
.ds-wordmark-badge {
|
|
1143
|
+
display: inline-block; font-size: 22px; padding: 14px 22px;
|
|
1144
|
+
background: var(--indigo-800); border: 1px solid var(--indigo-600); border-radius: var(--radius-md);
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
.ds-motion-box {
|
|
1148
|
+
width: 120px; height: 64px; border-radius: var(--radius-md);
|
|
1149
|
+
background: var(--surface-3); border: 1px solid var(--border);
|
|
1150
|
+
display: grid; place-content: center; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-muted);
|
|
1151
|
+
}
|
|
1152
|
+
.ds-anim-enter { animation: ds-enter var(--duration-page) var(--ease-out); }
|
|
1153
|
+
@keyframes ds-enter { from { opacity: 0; transform: translateY(8px); } }
|
|
1154
|
+
.ds-anim-glow { animation: ds-glow-in var(--duration-base) var(--ease-out); box-shadow: var(--glow-accent); }
|
|
1155
|
+
@keyframes ds-glow-in { from { opacity: 0; box-shadow: none; } }
|
|
1156
|
+
|
|
1157
|
+
.ds-footer { max-width: 920px; margin-inline: auto; padding-top: var(--space-8); border-top: 1px solid var(--row-border); color: var(--text-muted); font-size: var(--text-sm); }
|
|
1158
|
+
|
|
1159
|
+
@media (max-width: 1023px) {
|
|
1160
|
+
.ds-sidebar { transform: translateX(-100%); transition: transform var(--duration-slow) var(--ease-out); background: var(--surface-1); }
|
|
1161
|
+
.ds-sidebar.is-open { transform: translateX(0); box-shadow: var(--shadow-3); }
|
|
1162
|
+
.ds-main { margin-left: 0; padding-inline: var(--space-5); }
|
|
1163
|
+
.ds-hamburger { display: inline-flex; }
|
|
1164
|
+
}
|
|
1165
|
+
</style>
|
|
1166
|
+
</head>
|
|
1167
|
+
<body>
|
|
1168
|
+
|
|
1169
|
+
<header class="ds-topbar">
|
|
1170
|
+
<button class="icon-btn icon-btn--ghost ds-hamburger" id="dsHamburger" aria-label="Abrir navegación">
|
|
1171
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
|
|
1172
|
+
</button>
|
|
1173
|
+
<a class="ds-wordmark" href="#introduccion">higinio<span class="ds-dot">.</span>sosa</a>
|
|
1174
|
+
<span class="ds-version">Nocturna Eléctrica · v2.0</span>
|
|
1175
|
+
<span class="ds-topbar__spacer"></span>
|
|
1176
|
+
<button class="icon-btn icon-btn--outline ds-theme-toggle" id="dsTheme" aria-label="Cambiar tema claro/oscuro">
|
|
1177
|
+
<svg class="ds-icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.8A9 9 0 1 1 11.2 3 7 7 0 0 0 21 12.8z"/></svg>
|
|
1178
|
+
<svg class="ds-icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.9 4.9l1.4 1.4m11.4 11.4 1.4 1.4M2 12h2m16 0h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg>
|
|
1179
|
+
</button>
|
|
1180
|
+
</header>
|
|
1181
|
+
|
|
1182
|
+
<nav class="ds-sidebar" id="dsSidebar" aria-label="Navegación de la documentación">
|
|
1183
|
+
<div class="ds-nav">
|
|
1184
|
+
<div class="overline ds-group">Fundamentos</div>
|
|
1185
|
+
<a href="#introduccion">Introducción</a>
|
|
1186
|
+
<a href="#voz">Voz y contenido</a>
|
|
1187
|
+
<a href="#colores">Colores</a>
|
|
1188
|
+
<a href="#tipografia">Tipografía</a>
|
|
1189
|
+
<a href="#espaciado">Espaciado</a>
|
|
1190
|
+
<a href="#bordes">Bordes, radios y focus</a>
|
|
1191
|
+
<a href="#elevacion">Elevación</a>
|
|
1192
|
+
<a href="#iconografia">Iconografía</a>
|
|
1193
|
+
<a href="#marca">Marca / wordmark</a>
|
|
1194
|
+
<div class="overline ds-group">Componentes</div>
|
|
1195
|
+
<a href="#componentes">Todos los componentes</a>
|
|
1196
|
+
<div class="ds-nav__sub">
|
|
1197
|
+
<a href="#comp-botones">Botones</a>
|
|
1198
|
+
<a href="#comp-iconbutton">IconButton</a>
|
|
1199
|
+
<a href="#comp-spinner">Spinner</a>
|
|
1200
|
+
<a href="#comp-input">Input</a>
|
|
1201
|
+
<a href="#comp-textarea">Textarea</a>
|
|
1202
|
+
<a href="#comp-select">Select</a>
|
|
1203
|
+
<a href="#comp-segmented">SegmentedControl</a>
|
|
1204
|
+
<a href="#comp-slider">Slider</a>
|
|
1205
|
+
<a href="#comp-checkbox-radio">Checkbox y Radio</a>
|
|
1206
|
+
<a href="#comp-switch">Switch</a>
|
|
1207
|
+
<a href="#comp-badge-tag">Badge y Tag</a>
|
|
1208
|
+
<a href="#comp-avatar">Avatar</a>
|
|
1209
|
+
<a href="#comp-divider">Divider</a>
|
|
1210
|
+
<a href="#comp-accordion">Accordion</a>
|
|
1211
|
+
<a href="#comp-tooltip">Tooltip</a>
|
|
1212
|
+
<a href="#comp-alert">Alert</a>
|
|
1213
|
+
<a href="#comp-toast">Toast</a>
|
|
1214
|
+
<a href="#comp-progress">Progress y ProgressRing</a>
|
|
1215
|
+
<a href="#comp-modal">Modal</a>
|
|
1216
|
+
<a href="#comp-menu">Menu</a>
|
|
1217
|
+
<a href="#comp-tabla">Tabla</a>
|
|
1218
|
+
<a href="#comp-stat">Stat</a>
|
|
1219
|
+
<a href="#comp-pagination">Pagination</a>
|
|
1220
|
+
<a href="#comp-navegacion">Navegación</a>
|
|
1221
|
+
<a href="#comp-skeleton">Skeleton y EmptyState</a>
|
|
1222
|
+
<a href="#comp-card">Card, Link y Code</a>
|
|
1223
|
+
</div>
|
|
1224
|
+
<div class="overline ds-group">Recursos</div>
|
|
1225
|
+
<a href="#motion">Motion</a>
|
|
1226
|
+
<a href="#accesibilidad">Accesibilidad</a>
|
|
1227
|
+
<a href="#tokens">Tokens y descarga</a>
|
|
1228
|
+
<a href="#instalacion">Instalación</a>
|
|
1229
|
+
<a href="#mcp">MCP</a>
|
|
1230
|
+
</div>
|
|
1231
|
+
</nav>
|
|
1232
|
+
|
|
1233
|
+
<main class="ds-main">
|
|
1234
|
+
|
|
1235
|
+
<!-- ================= INTRODUCCIÓN ================= -->
|
|
1236
|
+
<section id="introduccion" class="ds-hero">
|
|
1237
|
+
<h1>Nocturna Eléctrica</h1>
|
|
1238
|
+
<p class="ds-lead">Sistema de diseño <strong>dark-first</strong>, enérgico y de alto contraste. El fondo casi negro es el escenario; el celeste eléctrico es el reflector.</p>
|
|
1239
|
+
<div class="ds-palette-chips">
|
|
1240
|
+
<span class="code">#52baed · celeste eléctrico</span>
|
|
1241
|
+
<span class="code">#353d7c · índigo profundo</span>
|
|
1242
|
+
<span class="code">#010203 · negro nocturno</span>
|
|
1243
|
+
</div>
|
|
1244
|
+
<div style="display:flex;gap:16px;flex-wrap:wrap;margin:24px 0;">
|
|
1245
|
+
<button class="btn btn--primary ds-hero-cta" id="heroCtaBuild">Empezar a construir</button>
|
|
1246
|
+
<button class="btn btn--outline" id="heroCtaTokens">Ver tokens</button>
|
|
1247
|
+
</div>
|
|
1248
|
+
<h3>Principios</h3>
|
|
1249
|
+
<ol style="color:var(--text-secondary);line-height:1.8;max-width:65ch;padding-left:20px;">
|
|
1250
|
+
<li><strong style="color:var(--text-primary)">Contraste con propósito</strong> — el acento solo aparece donde hay acción o dato clave.</li>
|
|
1251
|
+
<li><strong style="color:var(--text-primary)">Profundidad por luz</strong> — la elevación aclara superficies, no oscurece bordes.</li>
|
|
1252
|
+
<li><strong style="color:var(--text-primary)">Energía contenida</strong> — paleta vibrante, espaciado disciplinado: nunca ruidosa.</li>
|
|
1253
|
+
<li><strong style="color:var(--text-primary)">Datos protagonistas</strong> — cifras y gráficas brillan; el chrome se mantiene discreto.</li>
|
|
1254
|
+
<li><strong style="color:var(--text-primary)">Movimiento con propósito</strong> — la animación explica cambios de estado, nunca decora sola.</li>
|
|
1255
|
+
</ol>
|
|
1256
|
+
<div class="ds-callout ds-callout--info">
|
|
1257
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4m0-4h.01"/></svg>
|
|
1258
|
+
<div><strong>Regla de oro:</strong> los componentes consumen solo tokens semánticos (<span class="code">--surface-1</span>, <span class="code">--text-primary</span>…), nunca hex directos. El cambio de tema es un cambio de atributo, no un refactor. Pruébalo con el botón de tema de la esquina superior.</div>
|
|
1259
|
+
</div>
|
|
1260
|
+
</section>
|
|
1261
|
+
|
|
1262
|
+
<!-- ================= VOZ ================= -->
|
|
1263
|
+
<section id="voz">
|
|
1264
|
+
<h2>Voz y contenido</h2>
|
|
1265
|
+
<div class="ds-demo ds-demo--col" style="gap:12px;">
|
|
1266
|
+
<div><span class="overline">Idioma y tono</span><p style="margin:6px 0 0;">Español, técnico pero cercano. Tuteo implícito. Frases cortas y declarativas, con energía contenida.</p></div>
|
|
1267
|
+
<div><span class="overline">Casing</span><p style="margin:6px 0 0;">Sentence case en headings y botones: «Crear proyecto», no «Crear Proyecto». Overlines en uppercase con tracking <span class="code">+0.08em</span>.</p></div>
|
|
1268
|
+
<div><span class="overline">Botones</span><p style="margin:6px 0 0;">Verbo + objeto, corto: «Guardar cambios», «Ver informe».</p></div>
|
|
1269
|
+
<div><span class="overline">Errores</span><p style="margin:6px 0 0;">Concretos y accionables: dicen qué pasó <em>y qué hacer</em>.</p></div>
|
|
1270
|
+
<div><span class="overline">Datos</span><p style="margin:6px 0 0;">Siempre en JetBrains Mono o <span class="code">tabular-nums</span>; grandes en dashboards, con count-up de 350ms al montar.</p></div>
|
|
1271
|
+
<div><span class="overline">Emoji</span><p style="margin:6px 0 0;">No se usan. El estado se comunica con color + icono + texto.</p></div>
|
|
1272
|
+
</div>
|
|
1273
|
+
</section>
|
|
1274
|
+
|
|
1275
|
+
<!-- ================= COLORES ================= -->
|
|
1276
|
+
<section id="colores">
|
|
1277
|
+
<h2>Colores</h2>
|
|
1278
|
+
<p>Haz clic en cualquier swatch para copiar su variable CSS.</p>
|
|
1279
|
+
|
|
1280
|
+
<h3>Acento — Celeste Eléctrico</h3>
|
|
1281
|
+
<div class="ds-swatches" id="swAccent"></div>
|
|
1282
|
+
|
|
1283
|
+
<h3 style="margin-top:32px;">Secundario — Índigo Profundo</h3>
|
|
1284
|
+
<div class="ds-swatches" id="swIndigo"></div>
|
|
1285
|
+
<div class="ds-callout ds-callout--warning">
|
|
1286
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.7 18-8-14a2 2 0 0 0-3.5 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3z"/><path d="M12 9v4m0 4h.01"/></svg>
|
|
1287
|
+
<div>El índigo <span class="code">#353d7c</span> sobre negro da un contraste de ≈ 1.9:1 — <strong>nunca es texto sobre fondos nocturnos</strong>, solo fondos de sección, sidebars y estados seleccionados.</div>
|
|
1288
|
+
</div>
|
|
1289
|
+
|
|
1290
|
+
<h3 style="margin-top:32px;">Neutrales — Escala Nocturna</h3>
|
|
1291
|
+
<div class="ds-swatches" id="swNight"></div>
|
|
1292
|
+
|
|
1293
|
+
<h3 style="margin-top:32px;">Semánticos</h3>
|
|
1294
|
+
<div class="ds-swatches" id="swSem"></div>
|
|
1295
|
+
|
|
1296
|
+
<h3 style="margin-top:32px;">Regla 60-30-10</h3>
|
|
1297
|
+
<div class="ds-demo ds-demo--col" style="gap:8px;">
|
|
1298
|
+
<div style="display:flex;height:28px;border-radius:8px;overflow:hidden;">
|
|
1299
|
+
<div style="flex:6;background:var(--night-900);"></div>
|
|
1300
|
+
<div style="flex:3;background:var(--night-500);"></div>
|
|
1301
|
+
<div style="flex:1;background:var(--accent-400);"></div>
|
|
1302
|
+
</div>
|
|
1303
|
+
<p style="margin:8px 0 0;font-size:var(--text-sm);color:var(--text-muted);"><strong style="color:var(--text-secondary)">60%</strong> fondos nocturnos · <strong style="color:var(--text-secondary)">30%</strong> texto y estructura (índigo como fondo de marca) · <strong style="color:var(--text-secondary)">10%</strong> acento eléctrico y semánticos. El celeste es el único color que grita: <strong>un CTA primario por pantalla</strong>. Texto masivo en <span class="code">night-100</span>, nunca blanco puro.</p>
|
|
1304
|
+
</div>
|
|
1305
|
+
</section>
|
|
1306
|
+
|
|
1307
|
+
<!-- ================= TIPOGRAFÍA ================= -->
|
|
1308
|
+
<section id="tipografia">
|
|
1309
|
+
<h2>Tipografía</h2>
|
|
1310
|
+
<div class="ds-demo ds-demo--col">
|
|
1311
|
+
<div class="ds-type-row"><span class="ds-type-meta">Space Grotesk · display</span><span style="font-family:var(--font-display);font-size:var(--text-3xl);font-weight:700;letter-spacing:-0.02em;color:var(--text-heading);">Energía contenida</span></div>
|
|
1312
|
+
<div class="ds-type-row"><span class="ds-type-meta">Manrope · body/UI</span><span style="font-size:var(--text-lg);">El chrome discreto deja brillar los datos.</span></div>
|
|
1313
|
+
<div class="ds-type-row"><span class="ds-type-meta">JetBrains Mono · datos</span><span class="mono" style="font-size:var(--text-lg);color:var(--data-color);">1 024 768,50</span></div>
|
|
1314
|
+
</div>
|
|
1315
|
+
<div class="ds-callout ds-callout--info">
|
|
1316
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4m0-4h.01"/></svg>
|
|
1317
|
+
<div>Space Grotesk se reserva para <strong>h1–h3</strong>, cifras hero y navegación. <strong>h4 en adelante usa Manrope.</strong> En dark, el texto claro «engorda»: preferir peso 400 donde en light usarías 500.</div>
|
|
1318
|
+
</div>
|
|
1319
|
+
<h3>Escala (ratio 1.25, base 16px)</h3>
|
|
1320
|
+
<div class="ds-demo ds-demo--col" id="typeScale"></div>
|
|
1321
|
+
</section>
|
|
1322
|
+
|
|
1323
|
+
<!-- ================= ESPACIADO ================= -->
|
|
1324
|
+
<section id="espaciado">
|
|
1325
|
+
<h2>Espaciado</h2>
|
|
1326
|
+
<p>Escala base 4px. Aliases de uso: <span class="code">--card-padding: 24px</span> · <span class="code">--section-gap: 64px</span> · <span class="code">--form-gap: 20px</span> · <span class="code">--touch-target: 44px</span>.</p>
|
|
1327
|
+
<div class="ds-demo ds-demo--col" id="spaceScale"></div>
|
|
1328
|
+
</section>
|
|
1329
|
+
|
|
1330
|
+
<!-- ================= BORDES ================= -->
|
|
1331
|
+
<section id="bordes">
|
|
1332
|
+
<h2>Bordes, radios y focus</h2>
|
|
1333
|
+
<div class="ds-demo">
|
|
1334
|
+
<div class="ds-radius-demo" style="border-radius:var(--radius-sm);">sm · 8</div>
|
|
1335
|
+
<div class="ds-radius-demo" style="border-radius:var(--radius-md);">md · 12</div>
|
|
1336
|
+
<div class="ds-radius-demo" style="border-radius:var(--radius-lg);">lg · 16</div>
|
|
1337
|
+
<div class="ds-radius-demo" style="border-radius:var(--radius-xl);">xl · 24</div>
|
|
1338
|
+
<div class="ds-radius-demo" style="border-radius:var(--radius-full);width:72px;">full</div>
|
|
1339
|
+
</div>
|
|
1340
|
+
<p style="margin-top:16px;">Borde por defecto <span class="code">1px night-500</span>; énfasis <span class="code">night-600</span>. Focus ring global de teclado: <span class="code">2px accent-400</span> con offset 2px — pruébalo navegando con <kbd class="code">Tab</kbd>.</p>
|
|
1341
|
+
</section>
|
|
1342
|
+
|
|
1343
|
+
<!-- ================= ELEVACIÓN ================= -->
|
|
1344
|
+
<section id="elevacion">
|
|
1345
|
+
<h2>Elevación</h2>
|
|
1346
|
+
<p>Sobre negro las sombras solas no bastan: la elevación combina <strong>superficie más clara + sombra + borde sutil</strong>.</p>
|
|
1347
|
+
<div class="ds-demo ds-demo--grid">
|
|
1348
|
+
<div class="ds-elev-demo" style="background:var(--bg);border:1px dashed var(--border);">Nivel 0<br>night-950</div>
|
|
1349
|
+
<div class="ds-elev-demo" style="background:var(--surface-1);box-shadow:var(--shadow-1);border:1px solid var(--row-border);">Nivel 1<br>night-900 + shadow-1</div>
|
|
1350
|
+
<div class="ds-elev-demo" style="background:var(--surface-2);box-shadow:var(--shadow-2);border:1px solid var(--row-border);">Nivel 2<br>night-800 + shadow-2</div>
|
|
1351
|
+
<div class="ds-elev-demo" style="background:var(--surface-2);box-shadow:var(--shadow-3);border:1px solid var(--border-strong);">Nivel 3<br>night-800 + borde night-600 + shadow-3</div>
|
|
1352
|
+
</div>
|
|
1353
|
+
<h3 style="margin-top:32px;">Glow de acento</h3>
|
|
1354
|
+
<div class="ds-demo">
|
|
1355
|
+
<div class="ds-elev-demo" style="background:var(--surface-1);box-shadow:var(--glow-accent);max-width:280px;">glow-accent<br><span style="color:var(--text-disabled)">máximo uno por pantalla</span></div>
|
|
1356
|
+
</div>
|
|
1357
|
+
</section>
|
|
1358
|
+
|
|
1359
|
+
<!-- ================= ICONOGRAFÍA ================= -->
|
|
1360
|
+
<section id="iconografia">
|
|
1361
|
+
<h2>Iconografía</h2>
|
|
1362
|
+
<p>Set sustituto: <a class="link" href="https://lucide.dev" target="_blank" rel="noopener noreferrer">Lucide<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M7 7h10v10"/></svg></a> — trazo 2px, esquinas redondeadas, <span class="code">fill: none</span>, tamaño default 20px, color <span class="code">currentColor</span>. Tamaños: 20px en botones · 18px en inputs · 16px en chevrons. Sin emoji, sin unicode-como-icono.</p>
|
|
1363
|
+
<div class="ds-demo">
|
|
1364
|
+
<div class="ds-icon-grid">
|
|
1365
|
+
<div class="ds-icon-cell"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9 22V12h6v10"/></svg>home</div>
|
|
1366
|
+
<div class="ds-icon-cell"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v18h18"/><path d="M7 15v3m5-8v8m5-13v13"/></svg>chart</div>
|
|
1367
|
+
<div class="ds-icon-cell"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>bell</div>
|
|
1368
|
+
<div class="ds-icon-cell"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>search</div>
|
|
1369
|
+
<div class="ds-icon-cell"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14m-7-7v14"/></svg>plus</div>
|
|
1370
|
+
<div class="ds-icon-cell"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2 3 14h9l-1 8 10-12h-9z"/></svg>bolt</div>
|
|
1371
|
+
</div>
|
|
1372
|
+
</div>
|
|
1373
|
+
</section>
|
|
1374
|
+
|
|
1375
|
+
<!-- ================= MARCA ================= -->
|
|
1376
|
+
<section id="marca">
|
|
1377
|
+
<h2>Marca / wordmark</h2>
|
|
1378
|
+
<p>No hay logo dibujado: el wordmark es tipográfico — Space Grotesk 700, tracking <span class="code">-0.02em</span>, con el punto separador en <span class="code">accent-400</span>.</p>
|
|
1379
|
+
<div class="ds-demo" style="gap:32px;">
|
|
1380
|
+
<span class="ds-wordmark-demo">higinio<span class="ds-dot">.</span>sosa</span>
|
|
1381
|
+
<span class="ds-wordmark-demo ds-wordmark-badge">higinio<span class="ds-dot">.</span>sosa</span>
|
|
1382
|
+
</div>
|
|
1383
|
+
</section>
|
|
1384
|
+
|
|
1385
|
+
<!-- ================= COMPONENTES (overview) ================= -->
|
|
1386
|
+
<section id="componentes">
|
|
1387
|
+
<span class="overline">Biblioteca</span>
|
|
1388
|
+
<h2>Componentes</h2>
|
|
1389
|
+
<p class="ds-lead">Los 26 componentes del sistema, renderizados en vivo con las clases del framework <span class="code">nocturna-electrica.css</span>. Cada bloque incluye su código de uso.</p>
|
|
1390
|
+
</section>
|
|
1391
|
+
|
|
1392
|
+
<!-- ================= BOTONES ================= -->
|
|
1393
|
+
<section id="comp-botones">
|
|
1394
|
+
<h2>Botones</h2>
|
|
1395
|
+
<p>Alturas 36 / 44 / 52px. El primario lleva <strong>texto oscuro</strong> (contraste ≈ 8.5:1) — nunca blanco. Un solo primario por pantalla.</p>
|
|
1396
|
+
<div class="ds-demo">
|
|
1397
|
+
<button class="btn btn--primary">Guardar cambios</button>
|
|
1398
|
+
<button class="btn btn--secondary">Ver informe</button>
|
|
1399
|
+
<button class="btn btn--outline">Exportar</button>
|
|
1400
|
+
<button class="btn btn--ghost">Cancelar</button>
|
|
1401
|
+
<button class="btn btn--danger">Eliminar cuenta</button>
|
|
1402
|
+
<button class="btn btn--primary" disabled>Deshabilitado</button>
|
|
1403
|
+
</div>
|
|
1404
|
+
<div class="ds-demo">
|
|
1405
|
+
<button class="btn btn--primary btn--sm">Pequeño</button>
|
|
1406
|
+
<button class="btn btn--primary">Mediano</button>
|
|
1407
|
+
<button class="btn btn--primary btn--lg">Grande</button>
|
|
1408
|
+
<button class="btn btn--outline"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14m-7-7v14"/></svg>Con icono</button>
|
|
1409
|
+
<button class="btn btn--primary" style="min-width:160px;"><span class="spinner" style="color:currentColor;"></span></button>
|
|
1410
|
+
</div>
|
|
1411
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><button class="btn btn--primary">Guardar cambios</button>
|
|
1412
|
+
<button class="btn btn--secondary">Ver informe</button>
|
|
1413
|
+
<button class="btn btn--outline">Exportar</button>
|
|
1414
|
+
<button class="btn btn--ghost">Cancelar</button>
|
|
1415
|
+
<button class="btn btn--danger">Eliminar cuenta</button>
|
|
1416
|
+
|
|
1417
|
+
<!-- Tamaños: .btn--sm (36px) · default (44px) · .btn--lg (52px) -->
|
|
1418
|
+
<!-- Loading: fijar min-width y sustituir el texto por .spinner --></code></pre></details>
|
|
1419
|
+
</section>
|
|
1420
|
+
|
|
1421
|
+
<!-- ================= ICON BUTTON ================= -->
|
|
1422
|
+
<section id="comp-iconbutton">
|
|
1423
|
+
<h2>IconButton</h2>
|
|
1424
|
+
<p>Botón cuadrado solo-icono. <strong>Siempre con <span class="code">aria-label</span></strong>.</p>
|
|
1425
|
+
<div class="ds-demo">
|
|
1426
|
+
<button class="icon-btn icon-btn--outline" aria-label="Buscar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg></button>
|
|
1427
|
+
<button class="icon-btn icon-btn--ghost" aria-label="Notificaciones"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg></button>
|
|
1428
|
+
<button class="icon-btn icon-btn--accent" aria-label="Añadir"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14m-7-7v14"/></svg></button>
|
|
1429
|
+
<button class="icon-btn icon-btn--outline icon-btn--sm" aria-label="Copiar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="8" y="8" width="14" height="14" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></button>
|
|
1430
|
+
<button class="icon-btn icon-btn--outline" disabled aria-label="Deshabilitado"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
|
|
1431
|
+
</div>
|
|
1432
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><button class="icon-btn icon-btn--outline" aria-label="Buscar">
|
|
1433
|
+
<svg>…</svg>
|
|
1434
|
+
</button>
|
|
1435
|
+
<!-- Variantes: --outline · --ghost · --accent | Tamaños: --sm (36) · default (44) · --lg (52) --></code></pre></details>
|
|
1436
|
+
</section>
|
|
1437
|
+
|
|
1438
|
+
<!-- ================= SPINNER ================= -->
|
|
1439
|
+
<section id="comp-spinner">
|
|
1440
|
+
<h2>Spinner</h2>
|
|
1441
|
+
<p>Trazo 2px, rotación 0.8s. Si la carga dura menos de 300ms, no mostrar spinner.</p>
|
|
1442
|
+
<div class="ds-demo">
|
|
1443
|
+
<span class="spinner"></span>
|
|
1444
|
+
<span class="spinner" style="width:24px;height:24px;"></span>
|
|
1445
|
+
<span class="spinner" style="width:32px;height:32px;color:var(--text-muted);"></span>
|
|
1446
|
+
</div>
|
|
1447
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><span class="spinner"></span>
|
|
1448
|
+
<!-- Hereda currentColor; default accent-400 --></code></pre></details>
|
|
1449
|
+
</section>
|
|
1450
|
+
|
|
1451
|
+
<!-- ================= INPUT ================= -->
|
|
1452
|
+
<section id="comp-input">
|
|
1453
|
+
<h2>Input</h2>
|
|
1454
|
+
<p>Fondo <span class="code">--surface-2</span>, label siempre visible (nunca placeholder-como-label).</p>
|
|
1455
|
+
<div class="ds-demo ds-demo--grid">
|
|
1456
|
+
<div class="field">
|
|
1457
|
+
<label class="field__label" for="i1">Correo</label>
|
|
1458
|
+
<input class="input" id="i1" type="email" placeholder="tu@correo.com">
|
|
1459
|
+
<span class="field__help">Nunca compartiremos tu correo.</span>
|
|
1460
|
+
</div>
|
|
1461
|
+
<div class="field">
|
|
1462
|
+
<label class="field__label" for="i2">Con icono</label>
|
|
1463
|
+
<div class="input-wrap">
|
|
1464
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
|
|
1465
|
+
<input class="input" id="i2" type="text" placeholder="Buscar proyectos…">
|
|
1466
|
+
</div>
|
|
1467
|
+
</div>
|
|
1468
|
+
<div class="field">
|
|
1469
|
+
<label class="field__label" for="i3">Con error</label>
|
|
1470
|
+
<input class="input input--error" id="i3" type="text" value="usuario@">
|
|
1471
|
+
<span class="field__error"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><path d="M12 8v4m0 4h.01"/></svg>El correo no es válido — revisa el dominio.</span>
|
|
1472
|
+
</div>
|
|
1473
|
+
<div class="field">
|
|
1474
|
+
<label class="field__label" for="i4">Deshabilitado</label>
|
|
1475
|
+
<input class="input" id="i4" type="text" value="Solo lectura" disabled>
|
|
1476
|
+
</div>
|
|
1477
|
+
</div>
|
|
1478
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="field">
|
|
1479
|
+
<label class="field__label" for="email">Correo</label>
|
|
1480
|
+
<input class="input" id="email" type="email" placeholder="tu@correo.com">
|
|
1481
|
+
<span class="field__help">Texto de ayuda.</span>
|
|
1482
|
+
</div>
|
|
1483
|
+
<!-- Estados: .input--error (+ .field__error) · .input--success · disabled -->
|
|
1484
|
+
<!-- Icono leading: envolver en .input-wrap con un svg antes del input --></code></pre></details>
|
|
1485
|
+
</section>
|
|
1486
|
+
|
|
1487
|
+
<!-- ================= TEXTAREA ================= -->
|
|
1488
|
+
<section id="comp-textarea">
|
|
1489
|
+
<h2>Textarea</h2>
|
|
1490
|
+
<p>Fondo <span class="code">--surface-2</span>, label siempre visible (nunca placeholder-como-label).</p>
|
|
1491
|
+
<div class="ds-demo ds-demo--grid">
|
|
1492
|
+
<div class="field" style="grid-column:1/-1;">
|
|
1493
|
+
<label class="field__label" for="t1">Descripción</label>
|
|
1494
|
+
<textarea class="textarea" id="t1" placeholder="Describe el proyecto…"></textarea>
|
|
1495
|
+
<span class="field__count">0 / 280</span>
|
|
1496
|
+
</div>
|
|
1497
|
+
</div>
|
|
1498
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="field">
|
|
1499
|
+
<label class="field__label" for="desc">Descripción</label>
|
|
1500
|
+
<textarea class="textarea" id="desc" placeholder="Describe el proyecto…"></textarea>
|
|
1501
|
+
<span class="field__count">0 / 280</span>
|
|
1502
|
+
</div></code></pre></details>
|
|
1503
|
+
</section>
|
|
1504
|
+
|
|
1505
|
+
<!-- ================= SELECT ================= -->
|
|
1506
|
+
<section id="comp-select">
|
|
1507
|
+
<h2>Select</h2>
|
|
1508
|
+
<div class="ds-demo ds-demo--grid">
|
|
1509
|
+
<div class="field">
|
|
1510
|
+
<label class="field__label" for="s1">Proyecto</label>
|
|
1511
|
+
<div class="select-wrap">
|
|
1512
|
+
<select id="s1" class="select">
|
|
1513
|
+
<option>Panel analítico</option>
|
|
1514
|
+
<option>API de pagos</option>
|
|
1515
|
+
<option>App móvil</option>
|
|
1516
|
+
</select>
|
|
1517
|
+
</div>
|
|
1518
|
+
</div>
|
|
1519
|
+
</div>
|
|
1520
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="select-wrap">
|
|
1521
|
+
<select class="select"><option>Opción</option></select>
|
|
1522
|
+
</div></code></pre></details>
|
|
1523
|
+
</section>
|
|
1524
|
+
|
|
1525
|
+
<!-- ================= SEGMENTEDCONTROL ================= -->
|
|
1526
|
+
<section id="comp-segmented">
|
|
1527
|
+
<h2>SegmentedControl</h2>
|
|
1528
|
+
<p>2–4 opciones mutuamente excluyentes. Contenedor <span class="code">--surface-2</span>, opción activa en <span class="code">--surface-3</span> con texto <span class="code">--accent-300</span> y peso 600. Para más de 4 opciones, usar Select.</p>
|
|
1529
|
+
<div class="ds-demo" style="gap:24px;">
|
|
1530
|
+
<div class="segmented" role="radiogroup" aria-label="Vista">
|
|
1531
|
+
<input type="radio" name="seg-vista" id="seg-lista" checked><label for="seg-lista">Lista</label>
|
|
1532
|
+
<input type="radio" name="seg-vista" id="seg-tablero"><label for="seg-tablero">Tablero</label>
|
|
1533
|
+
<input type="radio" name="seg-vista" id="seg-cal"><label for="seg-cal">Calendario</label>
|
|
1534
|
+
</div>
|
|
1535
|
+
<div class="segmented segmented--sm" role="radiogroup" aria-label="Periodo">
|
|
1536
|
+
<input type="radio" name="seg-per" id="seg-7d" checked><label for="seg-7d">7 d</label>
|
|
1537
|
+
<input type="radio" name="seg-per" id="seg-30d"><label for="seg-30d">30 d</label>
|
|
1538
|
+
<input type="radio" name="seg-per" id="seg-12m"><label for="seg-12m">12 m</label>
|
|
1539
|
+
</div>
|
|
1540
|
+
</div>
|
|
1541
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="segmented" role="radiogroup" aria-label="Vista">
|
|
1542
|
+
<input type="radio" name="vista" id="lista" checked><label for="lista">Lista</label>
|
|
1543
|
+
<input type="radio" name="vista" id="tablero"><label for="tablero">Tablero</label>
|
|
1544
|
+
</div>
|
|
1545
|
+
<!-- Compacto: añadir segmented--sm --></code></pre></details>
|
|
1546
|
+
</section>
|
|
1547
|
+
|
|
1548
|
+
<!-- ================= SLIDER ================= -->
|
|
1549
|
+
<section id="comp-slider">
|
|
1550
|
+
<h2>Slider</h2>
|
|
1551
|
+
<p>Track 6 px, porción rellena en <span class="code">--accent-400</span> sobre <span class="code">--surface-3</span>; thumb <span class="code">--night-50</span> con borde de acento que escala 1.15 al presionar.</p>
|
|
1552
|
+
<div class="ds-demo ds-demo--col" style="max-width:420px;gap:24px;">
|
|
1553
|
+
<div>
|
|
1554
|
+
<div class="slider-row">
|
|
1555
|
+
<span class="slider-label">Límite de gasto</span>
|
|
1556
|
+
<span class="slider-value" id="demo-slider-value">$ 350</span>
|
|
1557
|
+
</div>
|
|
1558
|
+
<input class="slider js-slider" id="demo-slider" type="range" min="0" max="1000" step="10" value="350" aria-label="Límite de gasto">
|
|
1559
|
+
</div>
|
|
1560
|
+
<input class="slider js-slider" type="range" min="0" max="100" value="70" disabled aria-label="Slider deshabilitado">
|
|
1561
|
+
</div>
|
|
1562
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="slider-row">
|
|
1563
|
+
<span class="slider-label">Límite de gasto</span>
|
|
1564
|
+
<span class="slider-value">$ 350</span>
|
|
1565
|
+
</div>
|
|
1566
|
+
<input class="slider" type="range" min="0" max="1000" value="350">
|
|
1567
|
+
<!-- JS: --slider-fill = ((v-min)/(max-min))*100 + '%' --></code></pre></details>
|
|
1568
|
+
</section>
|
|
1569
|
+
|
|
1570
|
+
<!-- ================= CHECKBOX Y RADIO ================= -->
|
|
1571
|
+
<section id="comp-checkbox-radio">
|
|
1572
|
+
<h2>Checkbox y Radio</h2>
|
|
1573
|
+
<div class="ds-demo" style="gap:32px;">
|
|
1574
|
+
<label class="check-row"><input type="checkbox" class="checkbox" checked> Notificarme por correo</label>
|
|
1575
|
+
<label class="check-row"><input type="checkbox" class="checkbox"> Recordar sesión</label>
|
|
1576
|
+
<label class="check-row"><input type="radio" name="r1" class="radio" checked> Mensual</label>
|
|
1577
|
+
<label class="check-row"><input type="radio" name="r1" class="radio"> Anual</label>
|
|
1578
|
+
</div>
|
|
1579
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><label class="check-row"><input type="checkbox" class="checkbox"> Etiqueta</label>
|
|
1580
|
+
<label class="check-row"><input type="radio" name="g" class="radio"> Opción</label></code></pre></details>
|
|
1581
|
+
</section>
|
|
1582
|
+
|
|
1583
|
+
<!-- ================= SWITCH ================= -->
|
|
1584
|
+
<section id="comp-switch">
|
|
1585
|
+
<h2>Switch</h2>
|
|
1586
|
+
<div class="ds-demo" style="gap:32px;">
|
|
1587
|
+
<label class="check-row"><input type="checkbox" class="switch" checked> Modo compacto</label>
|
|
1588
|
+
</div>
|
|
1589
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><label class="check-row"><input type="checkbox" class="switch"> Activar</label></code></pre></details>
|
|
1590
|
+
</section>
|
|
1591
|
+
|
|
1592
|
+
<!-- ================= BADGES ================= -->
|
|
1593
|
+
<section id="comp-badge-tag">
|
|
1594
|
+
<h2>Badge y Tag</h2>
|
|
1595
|
+
<div class="ds-demo">
|
|
1596
|
+
<span class="badge badge--success"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>Activo</span>
|
|
1597
|
+
<span class="badge badge--warning"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.7 18-8-14a2 2 0 0 0-3.5 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3z"/><path d="M12 9v4m0 4h.01"/></svg>Pendiente</span>
|
|
1598
|
+
<span class="badge badge--danger"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 8v4m0 4h.01"/></svg>Error</span>
|
|
1599
|
+
<span class="badge badge--info"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4m0-4h.01"/></svg>Beta</span>
|
|
1600
|
+
<span class="tag">diseño <button class="tag__x" aria-label="Quitar etiqueta diseño">×</button></span>
|
|
1601
|
+
<span class="tag">frontend <button class="tag__x" aria-label="Quitar etiqueta frontend">×</button></span>
|
|
1602
|
+
</div>
|
|
1603
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><span class="badge badge--success">Activo</span>
|
|
1604
|
+
<span class="tag">diseño <button class="tag__x" aria-label="Quitar">×</button></span></code></pre></details>
|
|
1605
|
+
</section>
|
|
1606
|
+
|
|
1607
|
+
<!-- ================= AVATAR ================= -->
|
|
1608
|
+
<section id="comp-avatar">
|
|
1609
|
+
<h2>Avatar</h2>
|
|
1610
|
+
<p>Iniciales en Space Grotesk sobre índigo; punto de estado opcional.</p>
|
|
1611
|
+
<div class="ds-demo">
|
|
1612
|
+
<span class="avatar avatar--xs">hs</span>
|
|
1613
|
+
<span class="avatar avatar--sm">hs</span>
|
|
1614
|
+
<span class="avatar">hs<span class="avatar__dot avatar__dot--online"></span></span>
|
|
1615
|
+
<span class="avatar avatar--lg">hs<span class="avatar__dot avatar__dot--busy"></span></span>
|
|
1616
|
+
<span class="avatar avatar--xl">hs<span class="avatar__dot avatar__dot--away"></span></span>
|
|
1617
|
+
</div>
|
|
1618
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><span class="avatar">HS<span class="avatar__dot avatar__dot--online"></span></span>
|
|
1619
|
+
<!-- Tamaños: --xs 24 · --sm 32 · default 40 · --lg 48 · --xl 64 -->
|
|
1620
|
+
<!-- Con imagen: <span class="avatar"><img src="…" alt="Nombre"></span> --></code></pre></details>
|
|
1621
|
+
</section>
|
|
1622
|
+
|
|
1623
|
+
<!-- ================= DIVIDER ================= -->
|
|
1624
|
+
<section id="comp-divider">
|
|
1625
|
+
<h2>Divider</h2>
|
|
1626
|
+
<p>Regla hairline de 1px sobre <span class="code">--border</span>; variante con label centrado y variante vertical para separar acciones en línea.</p>
|
|
1627
|
+
<div class="ds-demo ds-demo--col" style="padding:var(--space-5);">
|
|
1628
|
+
<hr class="divider">
|
|
1629
|
+
<div class="divider--label" role="separator">o continúa con</div>
|
|
1630
|
+
<div style="display:flex;align-items:center;gap:0">
|
|
1631
|
+
<span>Filtros</span><span class="divider--vertical" role="separator"></span><span>Ordenar</span><span class="divider--vertical" role="separator"></span><span>Exportar</span>
|
|
1632
|
+
</div>
|
|
1633
|
+
</div>
|
|
1634
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><hr class="divider">
|
|
1635
|
+
<div class="divider--label" role="separator">o continúa con</div>
|
|
1636
|
+
<span class="divider--vertical" role="separator"></span></code></pre></details>
|
|
1637
|
+
</section>
|
|
1638
|
+
|
|
1639
|
+
<!-- ================= ACCORDION ================= -->
|
|
1640
|
+
<section id="comp-accordion">
|
|
1641
|
+
<h2>Accordion</h2>
|
|
1642
|
+
<div class="ds-demo ds-demo--col" style="padding:var(--space-5);">
|
|
1643
|
+
<div class="accordion">
|
|
1644
|
+
<div class="accordion__item">
|
|
1645
|
+
<button class="accordion__header" aria-expanded="true">¿Cómo se calcula la elevación?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg></button>
|
|
1646
|
+
<div class="accordion__panel"><div class="accordion__inner"><div class="accordion__content">Sobre fondo casi negro la elevación combina superficie más clara + sombra + borde sutil. Las sombras solas no bastan.</div></div></div>
|
|
1647
|
+
</div>
|
|
1648
|
+
<div class="accordion__item">
|
|
1649
|
+
<button class="accordion__header" aria-expanded="false">¿Cuándo usar el glow de acento?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg></button>
|
|
1650
|
+
<div class="accordion__panel"><div class="accordion__inner"><div class="accordion__content">Solo en interactivos clave y máximo uno por pantalla: es la firma de la marca, no una decoración repetible.</div></div></div>
|
|
1651
|
+
</div>
|
|
1652
|
+
<div class="accordion__item">
|
|
1653
|
+
<button class="accordion__header" aria-expanded="false">¿Por qué el CTA lleva texto oscuro?<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg></button>
|
|
1654
|
+
<div class="accordion__panel"><div class="accordion__inner"><div class="accordion__content">Negro nocturno sobre celeste eléctrico da ≈ 8.5:1 de contraste; blanco sobre celeste no pasa AA.</div></div></div>
|
|
1655
|
+
</div>
|
|
1656
|
+
</div>
|
|
1657
|
+
</div>
|
|
1658
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="accordion">
|
|
1659
|
+
<div class="accordion__item">
|
|
1660
|
+
<button class="accordion__header" aria-expanded="false">
|
|
1661
|
+
Pregunta <svg>chevron</svg>
|
|
1662
|
+
</button>
|
|
1663
|
+
<div class="accordion__panel"><div class="accordion__inner">
|
|
1664
|
+
<div class="accordion__content">Respuesta…</div>
|
|
1665
|
+
</div></div>
|
|
1666
|
+
</div>
|
|
1667
|
+
</div>
|
|
1668
|
+
<!-- JS: alternar aria-expanded en el header --></code></pre></details>
|
|
1669
|
+
</section>
|
|
1670
|
+
|
|
1671
|
+
<!-- ================= TOOLTIP ================= -->
|
|
1672
|
+
<section id="comp-tooltip">
|
|
1673
|
+
<h2>Tooltip</h2>
|
|
1674
|
+
<p>Delay de 400ms; máximo una línea. Pasa el cursor:</p>
|
|
1675
|
+
<div class="ds-demo">
|
|
1676
|
+
<span class="has-tooltip">
|
|
1677
|
+
<button class="btn btn--outline">Pasa el cursor</button>
|
|
1678
|
+
<span class="tooltip" role="tooltip">Exportar como CSV</span>
|
|
1679
|
+
</span>
|
|
1680
|
+
<span class="has-tooltip">
|
|
1681
|
+
<button class="icon-btn icon-btn--ghost" aria-label="Ajustes"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg></button>
|
|
1682
|
+
<span class="tooltip" role="tooltip">Ajustes</span>
|
|
1683
|
+
</span>
|
|
1684
|
+
</div>
|
|
1685
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><span class="has-tooltip">
|
|
1686
|
+
<button class="btn btn--outline">Pasa el cursor</button>
|
|
1687
|
+
<span class="tooltip" role="tooltip">Exportar como CSV</span>
|
|
1688
|
+
</span></code></pre></details>
|
|
1689
|
+
</section>
|
|
1690
|
+
|
|
1691
|
+
<!-- ================= ALERT ================= -->
|
|
1692
|
+
<section id="comp-alert">
|
|
1693
|
+
<h2>Alert</h2>
|
|
1694
|
+
<p>Banner inline y <strong>persistente</strong> (a diferencia del Toast, que es transitorio). Icono + texto + color — el estado nunca depende solo del color.</p>
|
|
1695
|
+
<div class="ds-demo ds-demo--col">
|
|
1696
|
+
<div class="alert alert--info" role="status">
|
|
1697
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4m0-4h.01"/></svg>
|
|
1698
|
+
<div>
|
|
1699
|
+
<p class="alert__title">Nueva versión disponible</p>
|
|
1700
|
+
<p class="alert__body">La versión 2.4 incluye exportación a PDF. Actualiza cuando quieras.</p>
|
|
1701
|
+
</div>
|
|
1702
|
+
<button class="alert__close js-alert-close" aria-label="Cerrar aviso"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
|
|
1703
|
+
</div>
|
|
1704
|
+
<div class="alert alert--success" role="status">
|
|
1705
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>
|
|
1706
|
+
<div>
|
|
1707
|
+
<p class="alert__title">Pago confirmado</p>
|
|
1708
|
+
<p class="alert__body">El recibo se envió a tu correo.</p>
|
|
1709
|
+
</div>
|
|
1710
|
+
<button class="alert__close js-alert-close" aria-label="Cerrar aviso"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
|
|
1711
|
+
</div>
|
|
1712
|
+
<div class="alert alert--warning" role="status">
|
|
1713
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.7 18-8-14a2 2 0 0 0-3.5 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3z"/><path d="M12 9v4m0 4h.01"/></svg>
|
|
1714
|
+
<div>
|
|
1715
|
+
<p class="alert__title">Tu plan expira en 5 días</p>
|
|
1716
|
+
<p class="alert__body">Renueva antes del 12 de julio para no perder acceso.</p>
|
|
1717
|
+
</div>
|
|
1718
|
+
<button class="alert__close js-alert-close" aria-label="Cerrar aviso"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
|
|
1719
|
+
</div>
|
|
1720
|
+
<div class="alert alert--danger" role="status">
|
|
1721
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 8v4m0 4h.01"/></svg>
|
|
1722
|
+
<div>
|
|
1723
|
+
<p class="alert__title">No se pudo guardar el formulario</p>
|
|
1724
|
+
<p class="alert__body">Revisa los campos marcados e inténtalo de nuevo.</p>
|
|
1725
|
+
</div>
|
|
1726
|
+
<button class="alert__close js-alert-close" aria-label="Cerrar aviso"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
|
|
1727
|
+
</div>
|
|
1728
|
+
</div>
|
|
1729
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="alert alert--warning" role="status">
|
|
1730
|
+
<svg>…icono…</svg>
|
|
1731
|
+
<div>
|
|
1732
|
+
<p class="alert__title">Tu plan expira en 5 días</p>
|
|
1733
|
+
<p class="alert__body">Renueva antes del 12 de julio.</p>
|
|
1734
|
+
</div>
|
|
1735
|
+
<button class="alert__close" aria-label="Cerrar aviso">…x…</button>
|
|
1736
|
+
</div>
|
|
1737
|
+
<!-- Variantes: --info · --success · --warning · --danger --></code></pre></details>
|
|
1738
|
+
</section>
|
|
1739
|
+
|
|
1740
|
+
<!-- ================= TOAST ================= -->
|
|
1741
|
+
<section id="comp-toast">
|
|
1742
|
+
<h2>Toast</h2>
|
|
1743
|
+
<p>Top-right, auto-dismiss a los 5s (pausable con hover), máximo 3 apilados.</p>
|
|
1744
|
+
<div class="ds-demo">
|
|
1745
|
+
<button class="btn btn--outline" data-toast="success">Toast de éxito</button>
|
|
1746
|
+
<button class="btn btn--outline" data-toast="info">Toast informativo</button>
|
|
1747
|
+
<button class="btn btn--outline" data-toast="warning">Toast de aviso</button>
|
|
1748
|
+
<button class="btn btn--outline" data-toast="danger">Toast de error</button>
|
|
1749
|
+
</div>
|
|
1750
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="toast-stack" role="status" aria-live="polite">
|
|
1751
|
+
<div class="toast toast--success">
|
|
1752
|
+
<svg>…</svg>
|
|
1753
|
+
<div>
|
|
1754
|
+
<div class="toast__title">Cambios guardados</div>
|
|
1755
|
+
<div class="toast__body">El proyecto se actualizó correctamente.</div>
|
|
1756
|
+
</div>
|
|
1757
|
+
</div>
|
|
1758
|
+
</div></code></pre></details>
|
|
1759
|
+
</section>
|
|
1760
|
+
|
|
1761
|
+
<!-- ================= PROGRESS ================= -->
|
|
1762
|
+
<section id="comp-progress">
|
|
1763
|
+
<h2>Progress y ProgressRing</h2>
|
|
1764
|
+
<p>Barra para procesos lineales (determinada/indeterminada); anillo circular para progreso compacto en cards y dashboards. Comparten <span class="code">--accent-400</span> y <span class="code">--data-color</span>.</p>
|
|
1765
|
+
<div class="ds-demo ds-demo--col" style="gap:24px;">
|
|
1766
|
+
<div>
|
|
1767
|
+
<div class="progress__head"><span class="progress__label">Subiendo archivos…</span><span class="progress__value" id="pgVal">64 %</span></div>
|
|
1768
|
+
<div class="progress" role="progressbar" aria-valuenow="64" aria-valuemin="0" aria-valuemax="100"><div class="progress__bar" id="pgBar" style="width:64%;"></div></div>
|
|
1769
|
+
</div>
|
|
1770
|
+
<div>
|
|
1771
|
+
<div class="progress__head"><span class="progress__label">Indeterminado</span></div>
|
|
1772
|
+
<div class="progress progress--indeterminate" role="progressbar"><div class="progress__bar"></div></div>
|
|
1773
|
+
</div>
|
|
1774
|
+
<div style="display:flex;align-items:center;gap:24px;">
|
|
1775
|
+
<div class="progress-ring" id="pgRing" data-value="64" role="progressbar" aria-valuenow="64" aria-valuemin="0" aria-valuemax="100">
|
|
1776
|
+
<svg width="56" height="56" viewBox="0 0 56 56" aria-hidden="true"><circle class="progress-ring__track" cx="28" cy="28" r="24" stroke-width="5"/><circle class="progress-ring__bar" id="pgRingBar" cx="28" cy="28" r="24" stroke-width="5"/></svg>
|
|
1777
|
+
<span class="progress-ring__value" id="pgRingVal">64%</span>
|
|
1778
|
+
</div>
|
|
1779
|
+
<span class="progress__label">Sincronización</span>
|
|
1780
|
+
</div>
|
|
1781
|
+
<button class="btn btn--outline btn--sm" id="pgRandom" style="align-self:flex-start;">Cambiar progreso</button>
|
|
1782
|
+
</div>
|
|
1783
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="progress__head">
|
|
1784
|
+
<span class="progress__label">Subiendo…</span>
|
|
1785
|
+
<span class="progress__value">64 %</span>
|
|
1786
|
+
</div>
|
|
1787
|
+
<div class="progress" role="progressbar" aria-valuenow="64" aria-valuemin="0" aria-valuemax="100">
|
|
1788
|
+
<div class="progress__bar" style="width:64%"></div>
|
|
1789
|
+
</div>
|
|
1790
|
+
<!-- Variantes: .progress--indeterminate · .progress--no-glow -->
|
|
1791
|
+
|
|
1792
|
+
<div class="progress-ring" role="progressbar" aria-valuenow="64" aria-valuemin="0" aria-valuemax="100">
|
|
1793
|
+
<svg width="56" height="56" viewBox="0 0 56 56">
|
|
1794
|
+
<circle class="progress-ring__track" cx="28" cy="28" r="24" stroke-width="5"/>
|
|
1795
|
+
<circle class="progress-ring__bar" cx="28" cy="28" r="24" stroke-width="5"/>
|
|
1796
|
+
</svg>
|
|
1797
|
+
<span class="progress-ring__value">64%</span>
|
|
1798
|
+
</div>
|
|
1799
|
+
<!-- JS: stroke-dasharray = 2πr; stroke-dashoffset = c * (1 - value/100) --></code></pre></details>
|
|
1800
|
+
</section>
|
|
1801
|
+
|
|
1802
|
+
<!-- ================= MODAL ================= -->
|
|
1803
|
+
<section id="comp-modal">
|
|
1804
|
+
<h2>Modal</h2>
|
|
1805
|
+
<p>Overlay con blur 4px; se cierra con Esc o clic fuera (excepto flujos destructivos).</p>
|
|
1806
|
+
<div class="ds-demo">
|
|
1807
|
+
<button class="btn btn--primary" id="openModal">Abrir modal</button>
|
|
1808
|
+
<button class="btn btn--outline" id="openModalLg">Abrir formulario</button>
|
|
1809
|
+
</div>
|
|
1810
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="modal-overlay">
|
|
1811
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="mTitle">
|
|
1812
|
+
<div class="modal__header">
|
|
1813
|
+
<h4 class="modal__title" id="mTitle">Título</h4>
|
|
1814
|
+
<button class="icon-btn icon-btn--ghost" aria-label="Cerrar">×</button>
|
|
1815
|
+
</div>
|
|
1816
|
+
<p>Contenido…</p>
|
|
1817
|
+
<div class="modal__footer">
|
|
1818
|
+
<button class="btn btn--outline">Cancelar</button>
|
|
1819
|
+
<button class="btn btn--primary">Confirmar</button>
|
|
1820
|
+
</div>
|
|
1821
|
+
</div>
|
|
1822
|
+
</div></code></pre></details>
|
|
1823
|
+
</section>
|
|
1824
|
+
|
|
1825
|
+
<!-- ================= MENU ================= -->
|
|
1826
|
+
<section id="comp-menu">
|
|
1827
|
+
<h2>Menu</h2>
|
|
1828
|
+
<div class="ds-demo ds-demo--grid">
|
|
1829
|
+
<div>
|
|
1830
|
+
<span class="field__label" style="display:block;margin-bottom:6px;">Menú (dropdown)</span>
|
|
1831
|
+
<button class="btn btn--outline" type="button" id="menuTrigger" aria-haspopup="true" aria-expanded="false">Acciones</button>
|
|
1832
|
+
<div class="menu" style="max-width:240px;" id="demoMenu" hidden>
|
|
1833
|
+
<button class="menu__item"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="8" y="8" width="14" height="14" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>Duplicar</button>
|
|
1834
|
+
<button class="menu__item is-selected"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>Seleccionado</button>
|
|
1835
|
+
<button class="menu__item">Archivar</button>
|
|
1836
|
+
</div>
|
|
1837
|
+
</div>
|
|
1838
|
+
</div>
|
|
1839
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="menu">
|
|
1840
|
+
<button class="menu__item">Duplicar</button>
|
|
1841
|
+
<button class="menu__item is-selected">Seleccionado</button>
|
|
1842
|
+
</div></code></pre></details>
|
|
1843
|
+
</section>
|
|
1844
|
+
|
|
1845
|
+
<!-- ================= TABLA ================= -->
|
|
1846
|
+
<section id="comp-tabla">
|
|
1847
|
+
<h2>Tabla</h2>
|
|
1848
|
+
<div class="ds-demo ds-demo--col" style="padding:0;overflow-x:auto;">
|
|
1849
|
+
<table class="table">
|
|
1850
|
+
<thead><tr><th>Proyecto</th><th>Estado</th><th class="num">Ingresos</th><th class="num">Cambio</th></tr></thead>
|
|
1851
|
+
<tbody>
|
|
1852
|
+
<tr><td style="color:var(--text-primary);">Panel analítico</td><td><span class="badge badge--success"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>Activo</span></td><td class="num">$48 210</td><td class="num" style="color:var(--success);">+8,2 %</td></tr>
|
|
1853
|
+
<tr class="is-selected"><td style="color:var(--text-primary);">API de pagos</td><td><span class="badge badge--info"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4m0-4h.01"/></svg>Beta</span></td><td class="num">$31 990</td><td class="num" style="color:var(--success);">+2,4 %</td></tr>
|
|
1854
|
+
<tr><td style="color:var(--text-primary);">App móvil</td><td><span class="badge badge--warning"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.7 18-8-14a2 2 0 0 0-3.5 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3z"/><path d="M12 9v4m0 4h.01"/></svg>Pendiente</span></td><td class="num">$12 040</td><td class="num" style="color:var(--danger);">−1,1 %</td></tr>
|
|
1855
|
+
</tbody>
|
|
1856
|
+
</table>
|
|
1857
|
+
</div>
|
|
1858
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><table class="table">
|
|
1859
|
+
<thead><tr><th>Proyecto</th><th class="num">Ingresos</th></tr></thead>
|
|
1860
|
+
<tbody>
|
|
1861
|
+
<tr><td>Panel analítico</td><td class="num">$48 210</td></tr>
|
|
1862
|
+
<tr class="is-selected">…</tr>
|
|
1863
|
+
</tbody>
|
|
1864
|
+
</table></code></pre></details>
|
|
1865
|
+
</section>
|
|
1866
|
+
|
|
1867
|
+
<!-- ================= STAT ================= -->
|
|
1868
|
+
<section id="comp-stat">
|
|
1869
|
+
<h2>Stat</h2>
|
|
1870
|
+
<p>Cifra de dashboard con count-up de 350ms al entrar en pantalla (respeta <span class="code">prefers-reduced-motion</span>).</p>
|
|
1871
|
+
<div class="ds-demo ds-demo--grid">
|
|
1872
|
+
<div class="stat">
|
|
1873
|
+
<span class="stat__label">Ingresos del mes</span>
|
|
1874
|
+
<span class="stat__value" data-countup="128450" data-prefix="$">$0</span>
|
|
1875
|
+
<span class="stat__delta stat__delta--up">▲ +12,4 %</span>
|
|
1876
|
+
</div>
|
|
1877
|
+
<div class="stat">
|
|
1878
|
+
<span class="stat__label">Usuarios activos</span>
|
|
1879
|
+
<span class="stat__value" data-countup="8342">0</span>
|
|
1880
|
+
<span class="stat__delta stat__delta--down">▼ −3,1 %</span>
|
|
1881
|
+
</div>
|
|
1882
|
+
<div class="stat">
|
|
1883
|
+
<span class="stat__label">Uptime</span>
|
|
1884
|
+
<span class="stat__value" data-countup="99.98" data-decimals="2" data-suffix=" %">0 %</span>
|
|
1885
|
+
<span class="stat__delta stat__delta--neutral">— sin cambios</span>
|
|
1886
|
+
</div>
|
|
1887
|
+
</div>
|
|
1888
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="stat">
|
|
1889
|
+
<span class="stat__label">Ingresos del mes</span>
|
|
1890
|
+
<span class="stat__value">$128 450</span>
|
|
1891
|
+
<span class="stat__delta stat__delta--up">▲ +12,4 %</span>
|
|
1892
|
+
</div></code></pre></details>
|
|
1893
|
+
</section>
|
|
1894
|
+
|
|
1895
|
+
<!-- ================= PAGINATION ================= -->
|
|
1896
|
+
<section id="comp-pagination">
|
|
1897
|
+
<h2>Pagination</h2>
|
|
1898
|
+
<p>1-indexado, bajo tablas y listas largas · trunca con elipsis a partir de 7 páginas · página activa con fondo <span class="code">--accent-400</span> + peso 700 (no depende solo del color) y <span class="code">aria-current="page"</span>.</p>
|
|
1899
|
+
<div class="ds-demo">
|
|
1900
|
+
<ul class="pagination" id="paginationDemo" aria-label="Paginación"></ul>
|
|
1901
|
+
</div>
|
|
1902
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><ul class="pagination" aria-label="Paginación">
|
|
1903
|
+
<li><button class="pagination__btn" data-page="prev" aria-label="Página anterior">‹</button></li>
|
|
1904
|
+
<li><button class="pagination__btn" data-page="1">1</button></li>
|
|
1905
|
+
<li><span class="pagination__ellipsis">…</span></li>
|
|
1906
|
+
<li><button class="pagination__btn is-active" data-page="5" aria-current="page">5</button></li>
|
|
1907
|
+
<li><button class="pagination__btn" data-page="6">6</button></li>
|
|
1908
|
+
<li><button class="pagination__btn" data-page="next" aria-label="Página siguiente">›</button></li>
|
|
1909
|
+
</ul></code></pre></details>
|
|
1910
|
+
</section>
|
|
1911
|
+
|
|
1912
|
+
<!-- ================= NAVEGACIÓN ================= -->
|
|
1913
|
+
<section id="comp-navegacion">
|
|
1914
|
+
<h2>Navegación</h2>
|
|
1915
|
+
<h3>Navbar (blur 12px)</h3>
|
|
1916
|
+
<div class="ds-demo ds-demo--col" style="padding:0;overflow-x:auto;">
|
|
1917
|
+
<div class="navbar" style="position:static;">
|
|
1918
|
+
<span class="ds-wordmark" style="font-size:var(--text-base);">higinio<span class="ds-dot">.</span>sosa</span>
|
|
1919
|
+
<nav class="navbar__links" style="margin-left:auto;">
|
|
1920
|
+
<a class="navbar__link is-active" href="#comp-navegacion">Resumen</a>
|
|
1921
|
+
<a class="navbar__link" href="#comp-navegacion">Informes</a>
|
|
1922
|
+
<a class="navbar__link" href="#comp-navegacion">Ajustes</a>
|
|
1923
|
+
</nav>
|
|
1924
|
+
</div>
|
|
1925
|
+
</div>
|
|
1926
|
+
<h3 style="margin-top:32px;">Sidebar</h3>
|
|
1927
|
+
<div class="ds-demo" style="padding:0;overflow-x:auto;">
|
|
1928
|
+
<div class="sidebar" style="height:auto;">
|
|
1929
|
+
<a class="sidebar__item is-active" href="#comp-navegacion"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M9 22V12h6v10"/></svg>Inicio</a>
|
|
1930
|
+
<a class="sidebar__item" href="#comp-navegacion"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v18h18"/><path d="M7 15v3m5-8v8m5-13v13"/></svg>Analítica</a>
|
|
1931
|
+
<a class="sidebar__item" href="#comp-navegacion"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/></svg>Proyectos</a>
|
|
1932
|
+
</div>
|
|
1933
|
+
</div>
|
|
1934
|
+
<h3 style="margin-top:32px;">Tabs y Breadcrumbs</h3>
|
|
1935
|
+
<div class="ds-demo ds-demo--col">
|
|
1936
|
+
<div class="tabs" id="demoTabs">
|
|
1937
|
+
<button class="tabs__btn is-active">Resumen</button>
|
|
1938
|
+
<button class="tabs__btn">Actividad</button>
|
|
1939
|
+
<button class="tabs__btn">Ajustes</button>
|
|
1940
|
+
<span class="tabs__indicator"></span>
|
|
1941
|
+
</div>
|
|
1942
|
+
<ul class="breadcrumbs" style="margin-top:16px;">
|
|
1943
|
+
<li><a href="#comp-navegacion">Inicio</a></li>
|
|
1944
|
+
<li><a href="#comp-navegacion">Proyectos</a></li>
|
|
1945
|
+
<li aria-current="page">Panel analítico</li>
|
|
1946
|
+
</ul>
|
|
1947
|
+
</div>
|
|
1948
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="navbar">…<a class="navbar__link is-active">Resumen</a>…</div>
|
|
1949
|
+
<div class="sidebar"><a class="sidebar__item is-active"><svg>…</svg>Inicio</a></div>
|
|
1950
|
+
<div class="tabs"><button class="tabs__btn is-active">Resumen</button>…<span class="tabs__indicator"></span></div>
|
|
1951
|
+
<ul class="breadcrumbs"><li><a>Inicio</a></li><li aria-current="page">Actual</li></ul></code></pre></details>
|
|
1952
|
+
</section>
|
|
1953
|
+
|
|
1954
|
+
<!-- ================= SKELETON ================= -->
|
|
1955
|
+
<section id="comp-skeleton">
|
|
1956
|
+
<h2>Skeleton y EmptyState</h2>
|
|
1957
|
+
<div class="ds-demo ds-demo--grid">
|
|
1958
|
+
<div style="display:flex;gap:12px;align-items:center;">
|
|
1959
|
+
<span class="skeleton skeleton--circle" style="width:40px;height:40px;"></span>
|
|
1960
|
+
<div style="flex:1;display:flex;flex-direction:column;gap:8px;">
|
|
1961
|
+
<span class="skeleton" style="height:12px;width:70%;"></span>
|
|
1962
|
+
<span class="skeleton" style="height:12px;width:45%;"></span>
|
|
1963
|
+
</div>
|
|
1964
|
+
</div>
|
|
1965
|
+
<div class="empty-state" style="padding:16px;">
|
|
1966
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"/></svg>
|
|
1967
|
+
<span class="empty-state__title">Aún no hay proyectos</span>
|
|
1968
|
+
<span class="empty-state__desc">Crea tu primer proyecto para empezar a ver métricas aquí.</span>
|
|
1969
|
+
<button class="btn btn--primary btn--sm">Crear proyecto</button>
|
|
1970
|
+
</div>
|
|
1971
|
+
</div>
|
|
1972
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><span class="skeleton" style="height:12px;width:70%"></span>
|
|
1973
|
+
<span class="skeleton skeleton--circle" style="width:40px;height:40px"></span>
|
|
1974
|
+
|
|
1975
|
+
<div class="empty-state">
|
|
1976
|
+
<svg>…</svg>
|
|
1977
|
+
<span class="empty-state__title">Aún no hay proyectos</span>
|
|
1978
|
+
<span class="empty-state__desc">Crea tu primer proyecto…</span>
|
|
1979
|
+
<button class="btn btn--primary btn--sm">Crear proyecto</button>
|
|
1980
|
+
</div></code></pre></details>
|
|
1981
|
+
</section>
|
|
1982
|
+
|
|
1983
|
+
<!-- ================= CARD, LINK Y CODE ================= -->
|
|
1984
|
+
<section id="comp-card">
|
|
1985
|
+
<h2>Card, Link y Code</h2>
|
|
1986
|
+
<h3>Card</h3>
|
|
1987
|
+
<div class="ds-demo ds-demo--grid">
|
|
1988
|
+
<div class="card">
|
|
1989
|
+
<h4 style="margin-top:0;">Tarjeta en reposo</h4>
|
|
1990
|
+
<p style="margin:0;font-size:var(--text-sm);color:var(--text-muted);">Superficie 1, borde sutil, sombra nivel 1.</p>
|
|
1991
|
+
</div>
|
|
1992
|
+
<div class="card card--interactive">
|
|
1993
|
+
<h4 style="margin-top:0;">Tarjeta interactiva</h4>
|
|
1994
|
+
<p style="margin:0;font-size:var(--text-sm);color:var(--text-muted);">Al pasar el cursor sube de nivel: −2px + superficie más clara.</p>
|
|
1995
|
+
</div>
|
|
1996
|
+
</div>
|
|
1997
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><div class="card">…</div>
|
|
1998
|
+
<div class="card card--interactive">…</div>
|
|
1999
|
+
<!-- .card--glow: firma de marca — MÁXIMO UNO POR PANTALLA --></code></pre></details>
|
|
2000
|
+
<h3 style="margin-top:32px;">Link y Code</h3>
|
|
2001
|
+
<div class="ds-demo" style="gap:32px;">
|
|
2002
|
+
<a class="link" href="#comp-card">Link con subrayado animado</a>
|
|
2003
|
+
<a class="link" href="https://lucide.dev" target="_blank" rel="noopener noreferrer">Link externo<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M7 7h10v10"/></svg></a>
|
|
2004
|
+
<span>Acento con <span class="code">var(--accent-400)</span></span>
|
|
2005
|
+
</div>
|
|
2006
|
+
<details class="ds-code"><summary>Ver código<button class="ds-copy" type="button">Copiar</button></summary><pre><code><a class="link" href="…">Link con subrayado animado</a>
|
|
2007
|
+
<span class="code">var(--accent-400)</span></code></pre></details>
|
|
2008
|
+
</section>
|
|
2009
|
+
|
|
2010
|
+
<!-- ================= MOTION ================= -->
|
|
2011
|
+
<section id="motion">
|
|
2012
|
+
<h2>Motion</h2>
|
|
2013
|
+
<p>Solo <span class="code">transform</span> y <span class="code">opacity</span>. Salida ~20% más corta que la entrada. Distancias de 4–8px. Stagger 30ms/ítem (máximo 6).</p>
|
|
2014
|
+
<div class="ds-demo ds-demo--col" style="padding:0;overflow-x:auto;">
|
|
2015
|
+
<table class="table">
|
|
2016
|
+
<thead><tr><th>Token</th><th>Valor</th><th>Uso</th></tr></thead>
|
|
2017
|
+
<tbody>
|
|
2018
|
+
<tr><td class="mono">--duration-instant</td><td class="mono">100ms</td><td>press, toggle</td></tr>
|
|
2019
|
+
<tr><td class="mono">--duration-fast</td><td class="mono">150ms</td><td>hover, focus, color</td></tr>
|
|
2020
|
+
<tr><td class="mono">--duration-base</td><td class="mono">220ms</td><td>dropdowns, tooltips, switches</td></tr>
|
|
2021
|
+
<tr><td class="mono">--duration-slow</td><td class="mono">250ms</td><td>modales, toasts</td></tr>
|
|
2022
|
+
<tr><td class="mono">--duration-page</td><td class="mono">350ms</td><td>transiciones de página</td></tr>
|
|
2023
|
+
<tr><td class="mono">--ease-out</td><td class="mono">cubic-bezier(0.2, 0, 0, 1)</td><td>entradas (default)</td></tr>
|
|
2024
|
+
<tr><td class="mono">--ease-in</td><td class="mono">cubic-bezier(0.4, 0, 1, 1)</td><td>salidas</td></tr>
|
|
2025
|
+
<tr><td class="mono">--ease-in-out</td><td class="mono">cubic-bezier(0.65, 0, 0.35, 1)</td><td>moverse de A a B (indicador de tabs)</td></tr>
|
|
2026
|
+
<tr><td class="mono">--ease-spring</td><td class="mono">cubic-bezier(0.34, 1.4, 0.64, 1)</td><td>toggles, checks</td></tr>
|
|
2027
|
+
</tbody>
|
|
2028
|
+
</table>
|
|
2029
|
+
</div>
|
|
2030
|
+
<div class="ds-demo">
|
|
2031
|
+
<div class="ds-motion-box" id="mBox1">entrada</div>
|
|
2032
|
+
<div class="ds-motion-box" id="mBox2">fade + glow</div>
|
|
2033
|
+
<button class="btn btn--outline btn--sm" id="mReplay">Reproducir</button>
|
|
2034
|
+
</div>
|
|
2035
|
+
<p style="font-size:var(--text-sm);color:var(--text-muted);">Firma de marca: los elementos con acento entran con fade + glow — solo en el elemento hero/CTA. <span class="code">prefers-reduced-motion</span> colapsa todo a 0.01ms.</p>
|
|
2036
|
+
</section>
|
|
2037
|
+
|
|
2038
|
+
<!-- ================= ACCESIBILIDAD ================= -->
|
|
2039
|
+
<section id="accesibilidad">
|
|
2040
|
+
<h2>Accesibilidad</h2>
|
|
2041
|
+
<div class="ds-demo ds-demo--col" style="padding:0;overflow-x:auto;">
|
|
2042
|
+
<table class="table">
|
|
2043
|
+
<thead><tr><th>Combinación</th><th class="num">Contraste</th><th>Veredicto</th></tr></thead>
|
|
2044
|
+
<tbody>
|
|
2045
|
+
<tr><td>night-100 sobre night-950</td><td class="num">≈ 16:1</td><td><span class="badge badge--success">AAA</span></td></tr>
|
|
2046
|
+
<tr><td>accent-400 sobre night-950</td><td class="num">≈ 8.5:1</td><td><span class="badge badge--success">AA — sirve como texto/link</span></td></tr>
|
|
2047
|
+
<tr><td>night-950 sobre accent-400 (CTA)</td><td class="num">≈ 8.5:1</td><td><span class="badge badge--success">AA — texto del CTA oscuro</span></td></tr>
|
|
2048
|
+
<tr><td>indigo-500 sobre night-950</td><td class="num">≈ 1.9:1</td><td><span class="badge badge--danger">Solo fondo, nunca texto</span></td></tr>
|
|
2049
|
+
<tr><td>night-50 sobre indigo-500</td><td class="num">≈ 9:1</td><td><span class="badge badge--success">AAA</span></td></tr>
|
|
2050
|
+
</tbody>
|
|
2051
|
+
</table>
|
|
2052
|
+
</div>
|
|
2053
|
+
<ul style="color:var(--text-secondary);line-height:1.9;font-size:var(--text-sm);">
|
|
2054
|
+
<li>Mínimos WCAG AA: 4.5:1 texto normal, 3:1 texto grande y componentes UI.</li>
|
|
2055
|
+
<li>Focus visible siempre (<span class="code">:focus-visible</span> global); estado nunca solo con color — siempre color + icono + texto.</li>
|
|
2056
|
+
<li>Touch targets de 44×44px. IconButton siempre con <span class="code">aria-label</span>.</li>
|
|
2057
|
+
<li><span class="code">role="progressbar"</span> en Progress, <span class="code">aria-expanded</span> en Accordion, <span class="code">aria-current</span> en navegación.</li>
|
|
2058
|
+
</ul>
|
|
2059
|
+
</section>
|
|
2060
|
+
|
|
2061
|
+
<!-- ================= TOKENS ================= -->
|
|
2062
|
+
<section id="tokens">
|
|
2063
|
+
<h2>Tokens y descarga</h2>
|
|
2064
|
+
<p>El sistema se distribuye en <span class="code">dist/nocturna-electrica/</span>: <strong>nocturna-electrica.css</strong> (framework completo), <strong>tokens.css</strong> (solo variables), <strong>tailwind.css</strong> (bloque <span class="code">@theme</span> para Tailwind v4) y <strong>tokens.json</strong> (formato estándar W3C DTCG 2025.10, interoperable con Figma / Tokens Studio / Style Dictionary).</p>
|
|
2065
|
+
|
|
2066
|
+
<h3>Variables CSS (núcleo)</h3>
|
|
2067
|
+
<details class="ds-code" open><summary>tokens :root (aliases semánticos)<button class="ds-copy" type="button">Copiar</button></summary><pre><code>:root {
|
|
2068
|
+
/* Superficies */
|
|
2069
|
+
--bg: #010203;
|
|
2070
|
+
--surface-1: #0b0d12; --surface-2: #14171f; --surface-3: #1e222d;
|
|
2071
|
+
--border: #3d4354; --border-strong: #2a2f3d;
|
|
2072
|
+
|
|
2073
|
+
/* Texto */
|
|
2074
|
+
--text-primary: #e8eaef; --text-secondary: #c5c9d4;
|
|
2075
|
+
--text-muted: #9aa0b0; --text-disabled: #6b7183;
|
|
2076
|
+
--text-heading: #f6f7f9; --text-on-accent: #010203;
|
|
2077
|
+
|
|
2078
|
+
/* Acento e índigo */
|
|
2079
|
+
--accent-400: #52baed; --accent-500: #2fa3dd; --accent-600: #1f87bb;
|
|
2080
|
+
--indigo-500: #353d7c; --indigo-700: #22284f; --indigo-800: #1a1e3b;
|
|
2081
|
+
--accent-ghost-hover: rgba(82,186,237,.08);
|
|
2082
|
+
--accent-selected: rgba(82,186,237,.12);
|
|
2083
|
+
|
|
2084
|
+
/* Semánticos */
|
|
2085
|
+
--success: #4ade80; --warning: #fbbf24; --danger: #f87171; --info: #52baed;
|
|
2086
|
+
|
|
2087
|
+
/* Tipografía */
|
|
2088
|
+
--font-display: "Space Grotesk", system-ui, sans-serif;
|
|
2089
|
+
--font-body: "Manrope", system-ui, sans-serif;
|
|
2090
|
+
--font-mono: "JetBrains Mono", monospace;
|
|
2091
|
+
|
|
2092
|
+
/* Radios y elevación */
|
|
2093
|
+
--radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px; --radius-full: 9999px;
|
|
2094
|
+
--shadow-1: 0 1px 2px rgba(0,0,0,.4);
|
|
2095
|
+
--shadow-2: 0 4px 12px rgba(0,0,0,.5);
|
|
2096
|
+
--shadow-3: 0 12px 32px rgba(0,0,0,.6);
|
|
2097
|
+
--glow-accent: 0 0 0 1px rgba(82,186,237,.35), 0 4px 20px rgba(82,186,237,.18);
|
|
2098
|
+
--ring: 0 0 0 3px rgba(82,186,237,.2);
|
|
2099
|
+
|
|
2100
|
+
/* Motion */
|
|
2101
|
+
--duration-fast: 150ms; --duration-base: 220ms; --duration-slow: 250ms;
|
|
2102
|
+
--ease-out: cubic-bezier(0.2, 0, 0, 1);
|
|
2103
|
+
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
|
2104
|
+
--ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
|
|
2105
|
+
}</code></pre></details>
|
|
2106
|
+
|
|
2107
|
+
<h3 style="margin-top:32px;">Tailwind CSS v4 — <span class="code">@theme</span></h3>
|
|
2108
|
+
<details class="ds-code"><summary>tailwind.css<button class="ds-copy" type="button">Copiar</button></summary><pre><code>@import "tailwindcss";
|
|
2109
|
+
|
|
2110
|
+
@theme {
|
|
2111
|
+
--color-night-950: #010203; --color-night-900: #0b0d12;
|
|
2112
|
+
--color-night-800: #14171f; --color-night-700: #1e222d;
|
|
2113
|
+
--color-night-600: #2a2f3d; --color-night-500: #3d4354;
|
|
2114
|
+
--color-night-400: #6b7183; --color-night-300: #9aa0b0;
|
|
2115
|
+
--color-night-200: #c5c9d4; --color-night-100: #e8eaef;
|
|
2116
|
+
--color-night-50: #f6f7f9;
|
|
2117
|
+
--color-accent-100: #d9f0fb; --color-accent-200: #a8ddf6;
|
|
2118
|
+
--color-accent-300: #7dccf1; --color-accent-400: #52baed;
|
|
2119
|
+
--color-accent-500: #2fa3dd; --color-accent-600: #1f87bb;
|
|
2120
|
+
--color-accent-700: #186a94;
|
|
2121
|
+
--color-indigo-300: #7a83c4; --color-indigo-400: #565fa3;
|
|
2122
|
+
--color-indigo-500: #353d7c; --color-indigo-600: #2b3264;
|
|
2123
|
+
--color-indigo-700: #22284f; --color-indigo-800: #1a1e3b;
|
|
2124
|
+
--color-success: #4ade80; --color-warning: #fbbf24;
|
|
2125
|
+
--color-danger: #f87171; --color-info: #52baed;
|
|
2126
|
+
|
|
2127
|
+
--font-display: "Space Grotesk", system-ui, sans-serif;
|
|
2128
|
+
--font-body: "Manrope", system-ui, sans-serif;
|
|
2129
|
+
--font-mono: "JetBrains Mono", monospace;
|
|
2130
|
+
|
|
2131
|
+
--radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px; --radius-xl: 24px;
|
|
2132
|
+
|
|
2133
|
+
--shadow-1: 0 1px 2px rgba(0,0,0,.4);
|
|
2134
|
+
--shadow-2: 0 4px 12px rgba(0,0,0,.5);
|
|
2135
|
+
--shadow-3: 0 12px 32px rgba(0,0,0,.6);
|
|
2136
|
+
--shadow-glow: 0 0 0 1px rgba(82,186,237,.35), 0 4px 20px rgba(82,186,237,.18);
|
|
2137
|
+
|
|
2138
|
+
--ease-out: cubic-bezier(0.2, 0, 0, 1);
|
|
2139
|
+
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
2140
|
+
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
|
2141
|
+
--ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
|
|
2142
|
+
}</code></pre></details>
|
|
2143
|
+
|
|
2144
|
+
<div class="ds-callout ds-callout--info" style="margin-top:32px;">
|
|
2145
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4m0-4h.01"/></svg>
|
|
2146
|
+
<div>Fuente de verdad completa: <span class="code">DESIGN-nocturna-electrica.md</span>. Skill de Claude: <span class="code">~/.claude/skills/nocturna-electrica-design/</span>.</div>
|
|
2147
|
+
</div>
|
|
2148
|
+
</section>
|
|
2149
|
+
|
|
2150
|
+
<!-- ================= INSTALACIÓN ================= -->
|
|
2151
|
+
<section id="instalacion">
|
|
2152
|
+
<h2>Instalación</h2>
|
|
2153
|
+
<p>El sistema se distribuye como archivos en <span class="code">dist/nocturna-electrica/</span> — cópialos a tu proyecto (aún no hay paquete npm). Elige la vía según tu stack. En todas: <strong>dark por defecto</strong>; <span class="code"><html data-theme="light"></span> activa el modo claro, y los componentes consumen <strong>solo aliases semánticos</strong>, nunca hex.</p>
|
|
2154
|
+
|
|
2155
|
+
<h3 style="margin-top:32px;">A · CSS drop-in (framework completo)</h3>
|
|
2156
|
+
<p>Para cualquier proyecto — HTML plano o cualquier framework. Trae variables + clases de componentes listas (tipo Bootstrap) y ya importa las fuentes.</p>
|
|
2157
|
+
<details class="ds-code" open><summary>index.html<button class="ds-copy" type="button">Copiar</button></summary><pre><code><link rel="stylesheet" href="/estilos/nocturna-electrica.css">
|
|
2158
|
+
<!-- luego usas las clases directo: -->
|
|
2159
|
+
<button class="btn btn--primary">Guardar</button>
|
|
2160
|
+
<div class="card">…</div></code></pre></details>
|
|
2161
|
+
|
|
2162
|
+
<h3 style="margin-top:32px;">B · Solo tokens</h3>
|
|
2163
|
+
<p>Si diseñas tus propios componentes: solo las variables, sin clases.</p>
|
|
2164
|
+
<details class="ds-code"><summary>styles.css<button class="ds-copy" type="button">Copiar</button></summary><pre><code>@import "./tokens.css";
|
|
2165
|
+
|
|
2166
|
+
.mi-panel {
|
|
2167
|
+
background: var(--surface-1);
|
|
2168
|
+
color: var(--text-primary);
|
|
2169
|
+
border: 1px solid var(--border);
|
|
2170
|
+
}</code></pre></details>
|
|
2171
|
+
|
|
2172
|
+
<h3 style="margin-top:32px;">C · Tailwind v4</h3>
|
|
2173
|
+
<p>Tailwind v4 se configura por CSS. El <span class="code">tailwind.css</span> ya incluye <span class="code">@import "tailwindcss"</span>, los tokens y el bloque <span class="code">@theme</span> — úsalo como tu hoja de entrada (mantén <span class="code">tokens.css</span> a su lado, que es lo que importa).</p>
|
|
2174
|
+
<details class="ds-code"><summary>terminal + CSS de entrada<button class="ds-copy" type="button">Copiar</button></summary><pre><code># 1) instala Tailwind v4
|
|
2175
|
+
npm i tailwindcss @tailwindcss/postcss
|
|
2176
|
+
|
|
2177
|
+
# 2) copia tailwind.css + tokens.css a tu carpeta de CSS
|
|
2178
|
+
# y usa tailwind.css como entrada. Ya tienes utilidades:
|
|
2179
|
+
<div class="bg-night-900 text-accent-400">…</div></code></pre></details>
|
|
2180
|
+
|
|
2181
|
+
<h3 style="margin-top:32px;">D · Pipelines de tokens</h3>
|
|
2182
|
+
<p>Para Figma, Tokens Studio o Style Dictionary: importa <span class="code">tokens.json</span> (formato estándar W3C DTCG 2025.10).</p>
|
|
2183
|
+
|
|
2184
|
+
<div class="ds-callout ds-callout--info" style="margin-top:32px;">
|
|
2185
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4m0-4h.01"/></svg>
|
|
2186
|
+
<div>Con Claude no copias nada: invoca la skill <span class="code">nocturna-electrica-design</span> o conecta el MCP (sección siguiente) y construye consumiendo tokens, componentes y reglas del sistema, con validación automática.</div>
|
|
2187
|
+
</div>
|
|
2188
|
+
</section>
|
|
2189
|
+
|
|
2190
|
+
<!-- ================= MCP ================= -->
|
|
2191
|
+
<section id="mcp">
|
|
2192
|
+
<h2>MCP</h2>
|
|
2193
|
+
<p>El paquete <span class="code">@higinio/design-mcp</span> expone ambos sistemas de diseño — Celeste Clásica y Nocturna Eléctrica — 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>
|
|
2194
|
+
|
|
2195
|
+
<h3>Las 8 tools</h3>
|
|
2196
|
+
<div class="ds-demo ds-demo--col" style="padding:0;overflow-x:auto;">
|
|
2197
|
+
<table class="table">
|
|
2198
|
+
<thead><tr><th>Tool</th><th>Qué hace</th></tr></thead>
|
|
2199
|
+
<tbody>
|
|
2200
|
+
<tr><td class="mono">list_design_systems</td><td>Lista los sistemas de diseño disponibles.</td></tr>
|
|
2201
|
+
<tr><td class="mono">get_token</td><td>Devuelve el valor resuelto de un token o alias de un sistema.</td></tr>
|
|
2202
|
+
<tr><td class="mono">search_tokens</td><td>Busca tokens por nombre, categoría o valor.</td></tr>
|
|
2203
|
+
<tr><td class="mono">list_components</td><td>Lista los componentes documentados de un sistema.</td></tr>
|
|
2204
|
+
<tr><td class="mono">get_component_spec</td><td>Devuelve la especificación completa de un componente: estados, medidas, variantes.</td></tr>
|
|
2205
|
+
<tr><td class="mono">get_rules</td><td>Devuelve las reglas duras (no negociables) del sistema.</td></tr>
|
|
2206
|
+
<tr><td class="mono">validate_code</td><td>Audita CSS/HTML contra las reglas del sistema — hex directos, contraste, aliases.</td></tr>
|
|
2207
|
+
<tr><td class="mono">generate_snippet</td><td>Genera un snippet de componente listo para usar, con los aliases correctos.</td></tr>
|
|
2208
|
+
</tbody>
|
|
2209
|
+
</table>
|
|
2210
|
+
</div>
|
|
2211
|
+
|
|
2212
|
+
<h3 style="margin-top:32px;">Conectar (remoto)</h3>
|
|
2213
|
+
<p>Añade el servidor a tu <span class="code">.mcp.json</span>:</p>
|
|
2214
|
+
<details class="ds-code" open><summary>.mcp.json<button class="ds-copy" type="button">Copiar</button></summary><pre><code>{
|
|
2215
|
+
"mcpServers": {
|
|
2216
|
+
"design": {
|
|
2217
|
+
"type": "http",
|
|
2218
|
+
"url": "https://design-mcp.higiniolab.tech/mcp",
|
|
2219
|
+
"headers": { "Authorization": "Bearer <tu-token>" }
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
}</code></pre></details>
|
|
2223
|
+
|
|
2224
|
+
<h3 style="margin-top:32px;">Ejemplo</h3>
|
|
2225
|
+
<p>Consultar un token de este sistema:</p>
|
|
2226
|
+
<details class="ds-code"><summary>get_token<button class="ds-copy" type="button">Copiar</button></summary><pre><code>get_token(system="nocturna", name="--accent")
|
|
2227
|
+
→ "#52baed"</code></pre></details>
|
|
2228
|
+
<p>Auditar código antes de integrarlo:</p>
|
|
2229
|
+
<details class="ds-code"><summary>validate_code<button class="ds-copy" type="button">Copiar</button></summary><pre><code>validate_code(system="nocturna", code="…")
|
|
2230
|
+
→ { ok: false, issues: ["hex directo #52baed en línea 12 — usa var(--accent-400)"] }</code></pre></details>
|
|
2231
|
+
|
|
2232
|
+
<div class="ds-callout ds-callout--info" style="margin-top:32px;">
|
|
2233
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4m0-4h.01"/></svg>
|
|
2234
|
+
<div>El MCP y las skills comparten fuente de verdad. Usa las skills dentro de Claude; el MCP para IDEs y clientes MCP externos.</div>
|
|
2235
|
+
</div>
|
|
2236
|
+
</section>
|
|
2237
|
+
|
|
2238
|
+
<footer class="ds-footer">
|
|
2239
|
+
<p style="margin:0;">Nocturna Eléctrica v2.0 — sistema de diseño de Higinio Sosa · dark-first · WCAG AA · <span class="mono">#52baed / #353d7c / #010203</span></p>
|
|
2240
|
+
</footer>
|
|
2241
|
+
</main>
|
|
2242
|
+
|
|
2243
|
+
<div class="toast-stack" id="toastStack" role="status" aria-live="polite"></div>
|
|
2244
|
+
<div class="modal-overlay" id="demoModal" hidden>
|
|
2245
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="demoModalTitle">
|
|
2246
|
+
<div class="modal__header">
|
|
2247
|
+
<h4 class="modal__title" id="demoModalTitle">Archivar proyecto</h4>
|
|
2248
|
+
<button class="icon-btn icon-btn--ghost icon-btn--sm" data-close-modal aria-label="Cerrar">
|
|
2249
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg>
|
|
2250
|
+
</button>
|
|
2251
|
+
</div>
|
|
2252
|
+
<p style="font-size:var(--text-sm);color:var(--text-secondary);">El proyecto dejará de aparecer en el panel, pero conservará sus datos. Puedes restaurarlo cuando quieras.</p>
|
|
2253
|
+
<div class="modal__footer">
|
|
2254
|
+
<button class="btn btn--outline" data-close-modal>Cancelar</button>
|
|
2255
|
+
<button class="btn btn--primary" data-close-modal>Archivar</button>
|
|
2256
|
+
</div>
|
|
2257
|
+
</div>
|
|
2258
|
+
</div>
|
|
2259
|
+
<div class="modal-overlay" id="demoModalLg" hidden>
|
|
2260
|
+
<div class="modal modal--lg" role="dialog" aria-modal="true" aria-labelledby="demoModalLgTitle">
|
|
2261
|
+
<div class="modal__header">
|
|
2262
|
+
<h4 class="modal__title" id="demoModalLgTitle">Invitar al equipo</h4>
|
|
2263
|
+
<button class="icon-btn icon-btn--ghost icon-btn--sm" data-close-modal aria-label="Cerrar">
|
|
2264
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg>
|
|
2265
|
+
</button>
|
|
2266
|
+
</div>
|
|
2267
|
+
<div style="display:flex;flex-direction:column;gap:var(--form-gap);">
|
|
2268
|
+
<div class="field">
|
|
2269
|
+
<label class="field__label" for="modalLgCorreo">Correo electrónico</label>
|
|
2270
|
+
<input class="input" id="modalLgCorreo" type="email" placeholder="colega@correo.com">
|
|
2271
|
+
</div>
|
|
2272
|
+
<div class="field">
|
|
2273
|
+
<label class="field__label" for="modalLgRol">Rol</label>
|
|
2274
|
+
<div class="select-wrap">
|
|
2275
|
+
<select id="modalLgRol" class="select">
|
|
2276
|
+
<option>Editor</option>
|
|
2277
|
+
<option>Lector</option>
|
|
2278
|
+
<option>Administrador</option>
|
|
2279
|
+
</select>
|
|
2280
|
+
</div>
|
|
2281
|
+
<span class="field__help">Podrás cambiar el rol más adelante.</span>
|
|
2282
|
+
</div>
|
|
2283
|
+
</div>
|
|
2284
|
+
<div class="modal__footer">
|
|
2285
|
+
<button class="btn btn--outline" data-close-modal>Cancelar</button>
|
|
2286
|
+
<button class="btn btn--primary" data-close-modal>Enviar invitación</button>
|
|
2287
|
+
</div>
|
|
2288
|
+
</div>
|
|
2289
|
+
</div>
|
|
2290
|
+
|
|
2291
|
+
<script>
|
|
2292
|
+
(function(){
|
|
2293
|
+
'use strict';
|
|
2294
|
+
var reduced = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
2295
|
+
|
|
2296
|
+
/* ---------- Tema ---------- */
|
|
2297
|
+
var themeBtn = document.getElementById('dsTheme');
|
|
2298
|
+
if (themeBtn) {
|
|
2299
|
+
themeBtn.addEventListener('click', function(){
|
|
2300
|
+
var root = document.documentElement;
|
|
2301
|
+
var next = root.dataset.theme === 'dark' ? 'light' : 'dark';
|
|
2302
|
+
root.dataset.theme = next;
|
|
2303
|
+
try { localStorage.setItem('ne-theme', next); } catch (e) {}
|
|
2304
|
+
});
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
/* ---------- Sidebar móvil ---------- */
|
|
2308
|
+
var sidebar = document.getElementById('dsSidebar');
|
|
2309
|
+
var hamburger = document.getElementById('dsHamburger');
|
|
2310
|
+
if (hamburger && sidebar) {
|
|
2311
|
+
hamburger.addEventListener('click', function(){
|
|
2312
|
+
sidebar.classList.toggle('is-open');
|
|
2313
|
+
});
|
|
2314
|
+
sidebar.addEventListener('click', function(e){
|
|
2315
|
+
if (e.target.tagName === 'A') sidebar.classList.remove('is-open');
|
|
2316
|
+
});
|
|
2317
|
+
document.addEventListener('click', function(e){
|
|
2318
|
+
if (sidebar.classList.contains('is-open') && !sidebar.contains(e.target) && e.target !== hamburger) {
|
|
2319
|
+
sidebar.classList.remove('is-open');
|
|
2320
|
+
}
|
|
2321
|
+
});
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
/* ---------- Hero CTAs ---------- */
|
|
2325
|
+
var heroCtaBuild = document.getElementById('heroCtaBuild');
|
|
2326
|
+
if (heroCtaBuild) {
|
|
2327
|
+
heroCtaBuild.addEventListener('click', function(){
|
|
2328
|
+
var target = document.getElementById('componentes');
|
|
2329
|
+
if (target) target.scrollIntoView({ behavior: 'smooth' });
|
|
2330
|
+
});
|
|
2331
|
+
}
|
|
2332
|
+
var heroCtaTokens = document.getElementById('heroCtaTokens');
|
|
2333
|
+
if (heroCtaTokens) {
|
|
2334
|
+
heroCtaTokens.addEventListener('click', function(){
|
|
2335
|
+
var target = document.getElementById('tokens');
|
|
2336
|
+
if (target) target.scrollIntoView({ behavior: 'smooth' });
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
/* ---------- Portapapeles ---------- */
|
|
2341
|
+
function copyText(text, feedbackFn){
|
|
2342
|
+
function done(){ if (feedbackFn) feedbackFn(); }
|
|
2343
|
+
function fallback(){
|
|
2344
|
+
var ta = document.createElement('textarea');
|
|
2345
|
+
ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0';
|
|
2346
|
+
document.body.appendChild(ta); ta.select();
|
|
2347
|
+
try { document.execCommand('copy'); done(); } catch (e) {}
|
|
2348
|
+
document.body.removeChild(ta);
|
|
2349
|
+
}
|
|
2350
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
2351
|
+
navigator.clipboard.writeText(text).then(done, fallback);
|
|
2352
|
+
} else {
|
|
2353
|
+
fallback();
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
/* ---------- Swatches ---------- */
|
|
2358
|
+
function swatches(el, items, darkText){
|
|
2359
|
+
items.forEach(function(it){
|
|
2360
|
+
var d = document.createElement('button');
|
|
2361
|
+
d.className = 'ds-swatch'; d.type = 'button';
|
|
2362
|
+
d.setAttribute('aria-label', 'Copiar var(--' + it[0] + ')');
|
|
2363
|
+
d.innerHTML = '<span class="ds-swatch__chip" style="display:block;background:' + it[1] + ';"></span>' +
|
|
2364
|
+
'<span class="ds-swatch__meta"><span class="ds-swatch__name">' + it[0] + '</span><span class="ds-swatch__hex">' + it[1] + '</span></span>';
|
|
2365
|
+
d.addEventListener('click', function(){
|
|
2366
|
+
copyText('var(--' + it[0] + ')', function(){
|
|
2367
|
+
var n = d.querySelector('.ds-swatch__name'), old = n.textContent;
|
|
2368
|
+
n.textContent = '¡Copiado!'; n.style.color = 'var(--success)';
|
|
2369
|
+
setTimeout(function(){ n.textContent = old; n.style.color = ''; }, 1200);
|
|
2370
|
+
});
|
|
2371
|
+
});
|
|
2372
|
+
el.appendChild(d);
|
|
2373
|
+
});
|
|
2374
|
+
}
|
|
2375
|
+
swatches(document.getElementById('swAccent'), [
|
|
2376
|
+
['accent-100','#d9f0fb'],['accent-200','#a8ddf6'],['accent-300','#7dccf1'],
|
|
2377
|
+
['accent-400','#52baed'],['accent-500','#2fa3dd'],['accent-600','#1f87bb'],['accent-700','#186a94']
|
|
2378
|
+
]);
|
|
2379
|
+
swatches(document.getElementById('swIndigo'), [
|
|
2380
|
+
['indigo-300','#7a83c4'],['indigo-400','#565fa3'],['indigo-500','#353d7c'],
|
|
2381
|
+
['indigo-600','#2b3264'],['indigo-700','#22284f'],['indigo-800','#1a1e3b']
|
|
2382
|
+
]);
|
|
2383
|
+
swatches(document.getElementById('swNight'), [
|
|
2384
|
+
['night-950','#010203'],['night-900','#0b0d12'],['night-800','#14171f'],['night-700','#1e222d'],
|
|
2385
|
+
['night-600','#2a2f3d'],['night-500','#3d4354'],['night-400','#6b7183'],['night-300','#9aa0b0'],
|
|
2386
|
+
['night-200','#c5c9d4'],['night-100','#e8eaef'],['night-50','#f6f7f9']
|
|
2387
|
+
]);
|
|
2388
|
+
swatches(document.getElementById('swSem'), [
|
|
2389
|
+
['success-400','#4ade80'],['warning-400','#fbbf24'],['danger-400','#f87171'],['info-400','#52baed']
|
|
2390
|
+
]);
|
|
2391
|
+
|
|
2392
|
+
/* ---------- Escala tipográfica ---------- */
|
|
2393
|
+
var scale = [
|
|
2394
|
+
['text-xs','12px','labels, overlines'],['text-sm','14px','texto secundario'],
|
|
2395
|
+
['text-base','16px','párrafos, inputs'],['text-lg','18px','lead'],
|
|
2396
|
+
['text-xl','20px','h4 (Manrope)'],['text-2xl','25px','h3'],
|
|
2397
|
+
['text-3xl','31px','h2'],['text-4xl','39px','h1'],['text-5xl','49px','cifras hero']
|
|
2398
|
+
];
|
|
2399
|
+
var ts = document.getElementById('typeScale');
|
|
2400
|
+
scale.forEach(function(s){
|
|
2401
|
+
var big = parseInt(s[1]) >= 25;
|
|
2402
|
+
var row = document.createElement('div');
|
|
2403
|
+
row.className = 'ds-type-row';
|
|
2404
|
+
row.innerHTML = '<span class="ds-type-meta">' + s[0] + ' · ' + s[1] + '<br>' + s[2] + '</span>' +
|
|
2405
|
+
'<span style="font-size:' + s[1] + ';' + (big ? 'font-family:var(--font-display);font-weight:700;letter-spacing:-0.02em;color:var(--text-heading);' : '') + 'white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">Nocturna Eléctrica</span>';
|
|
2406
|
+
ts.appendChild(row);
|
|
2407
|
+
});
|
|
2408
|
+
|
|
2409
|
+
/* ---------- Escala de espaciado ---------- */
|
|
2410
|
+
var spaces = [['space-1',4],['space-2',8],['space-3',12],['space-4',16],['space-5',20],['space-6',24],['space-8',32],['space-10',40],['space-12',48],['space-16',64],['space-20',80],['space-24',96]];
|
|
2411
|
+
var sp = document.getElementById('spaceScale');
|
|
2412
|
+
spaces.forEach(function(s){
|
|
2413
|
+
var row = document.createElement('div');
|
|
2414
|
+
row.className = 'ds-space-row';
|
|
2415
|
+
row.innerHTML = '<span class="ds-type-meta">--' + s[0] + ' · ' + s[1] + 'px</span><span class="ds-space-bar" style="width:' + s[1]*2 + 'px;"></span>';
|
|
2416
|
+
sp.appendChild(row);
|
|
2417
|
+
});
|
|
2418
|
+
|
|
2419
|
+
/* ---------- Copiar código ---------- */
|
|
2420
|
+
document.querySelectorAll('.ds-copy').forEach(function(btn){
|
|
2421
|
+
btn.addEventListener('click', function(e){
|
|
2422
|
+
e.preventDefault(); e.stopPropagation();
|
|
2423
|
+
var details = btn.closest('details');
|
|
2424
|
+
var code = details ? details.querySelector('code') : null;
|
|
2425
|
+
if (code) {
|
|
2426
|
+
copyText(code.textContent, function(){
|
|
2427
|
+
btn.textContent = '¡Copiado!'; btn.classList.add('is-done');
|
|
2428
|
+
setTimeout(function(){ btn.textContent = 'Copiar'; btn.classList.remove('is-done'); }, 1500);
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2431
|
+
});
|
|
2432
|
+
});
|
|
2433
|
+
|
|
2434
|
+
/* ---------- Resaltado de sintaxis (autocontenido, sin librerías) ---------- */
|
|
2435
|
+
(function(){
|
|
2436
|
+
function esc(s){ return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }
|
|
2437
|
+
var RE = /(<!--[\s\S]*?-->)|(\/\*[\s\S]*?\*\/)|("[^"]*"|'[^']*')|(<\/?)([a-zA-Z][\w:-]*)|(\/?>)|([A-Za-z_][\w-]*)(=)(?=")|(--[\w-]+)/g;
|
|
2438
|
+
function hl(s){
|
|
2439
|
+
return s.replace(RE, function(m, com, css, str, lt, tag, gt, attr, eq, cssvar){
|
|
2440
|
+
if (com || css) return '<span class="tok-com">' + (com || css) + '</span>';
|
|
2441
|
+
if (str) return '<span class="tok-str">' + str + '</span>';
|
|
2442
|
+
if (lt) return '<span class="tok-punct">' + lt + '</span><span class="tok-tag">' + tag + '</span>';
|
|
2443
|
+
if (gt) return '<span class="tok-punct">' + gt + '</span>';
|
|
2444
|
+
if (attr) return '<span class="tok-attr">' + attr + '</span>' + eq;
|
|
2445
|
+
if (cssvar) return '<span class="tok-var">' + cssvar + '</span>';
|
|
2446
|
+
return m;
|
|
2447
|
+
});
|
|
2448
|
+
}
|
|
2449
|
+
document.querySelectorAll('.ds-code code').forEach(function(code){
|
|
2450
|
+
code.innerHTML = hl(esc(code.textContent));
|
|
2451
|
+
});
|
|
2452
|
+
})();
|
|
2453
|
+
|
|
2454
|
+
/* ---------- Scrollspy ---------- */
|
|
2455
|
+
var links = Array.prototype.slice.call(document.querySelectorAll('.ds-nav a'));
|
|
2456
|
+
var map = {};
|
|
2457
|
+
links.forEach(function(a){ map[a.getAttribute('href').slice(1)] = a; });
|
|
2458
|
+
var spy = new IntersectionObserver(function(entries){
|
|
2459
|
+
entries.forEach(function(en){
|
|
2460
|
+
if (en.isIntersecting) {
|
|
2461
|
+
links.forEach(function(a){ a.classList.remove('is-active'); });
|
|
2462
|
+
var a = map[en.target.id]; if (a) a.classList.add('is-active');
|
|
2463
|
+
}
|
|
2464
|
+
});
|
|
2465
|
+
}, { rootMargin: '-20% 0px -70% 0px' });
|
|
2466
|
+
document.querySelectorAll('.ds-main > section').forEach(function(s){ spy.observe(s); });
|
|
2467
|
+
|
|
2468
|
+
/* ---------- Accordion ---------- */
|
|
2469
|
+
document.querySelectorAll('.accordion__header').forEach(function(h){
|
|
2470
|
+
h.addEventListener('click', function(){
|
|
2471
|
+
h.setAttribute('aria-expanded', h.getAttribute('aria-expanded') !== 'true');
|
|
2472
|
+
});
|
|
2473
|
+
});
|
|
2474
|
+
|
|
2475
|
+
/* ---------- Menu (dropdown) ---------- */
|
|
2476
|
+
var menuTrigger = document.getElementById('menuTrigger');
|
|
2477
|
+
var demoMenu = document.getElementById('demoMenu');
|
|
2478
|
+
if (menuTrigger && demoMenu) {
|
|
2479
|
+
menuTrigger.addEventListener('click', function(e){
|
|
2480
|
+
e.stopPropagation();
|
|
2481
|
+
var willOpen = demoMenu.hidden;
|
|
2482
|
+
demoMenu.hidden = !willOpen;
|
|
2483
|
+
menuTrigger.setAttribute('aria-expanded', willOpen ? 'true' : 'false');
|
|
2484
|
+
});
|
|
2485
|
+
document.addEventListener('click', function(e){
|
|
2486
|
+
if (!demoMenu.hidden && !demoMenu.contains(e.target) && e.target !== menuTrigger) {
|
|
2487
|
+
demoMenu.hidden = true;
|
|
2488
|
+
menuTrigger.setAttribute('aria-expanded', 'false');
|
|
2489
|
+
}
|
|
2490
|
+
});
|
|
2491
|
+
document.addEventListener('keydown', function(e){
|
|
2492
|
+
if (e.key === 'Escape' && !demoMenu.hidden) {
|
|
2493
|
+
demoMenu.hidden = true;
|
|
2494
|
+
menuTrigger.setAttribute('aria-expanded', 'false');
|
|
2495
|
+
}
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
/* ---------- Tabs ---------- */
|
|
2500
|
+
var tabs = document.getElementById('demoTabs');
|
|
2501
|
+
function moveIndicator(btn){
|
|
2502
|
+
var ind = tabs.querySelector('.tabs__indicator');
|
|
2503
|
+
ind.style.width = btn.offsetWidth + 'px';
|
|
2504
|
+
ind.style.transform = 'translateX(' + btn.offsetLeft + 'px)';
|
|
2505
|
+
}
|
|
2506
|
+
tabs.querySelectorAll('.tabs__btn').forEach(function(b){
|
|
2507
|
+
b.addEventListener('click', function(){
|
|
2508
|
+
tabs.querySelectorAll('.tabs__btn').forEach(function(x){ x.classList.remove('is-active'); });
|
|
2509
|
+
b.classList.add('is-active');
|
|
2510
|
+
moveIndicator(b);
|
|
2511
|
+
});
|
|
2512
|
+
});
|
|
2513
|
+
setTimeout(function(){ moveIndicator(tabs.querySelector('.is-active')); }, 100);
|
|
2514
|
+
|
|
2515
|
+
/* ---------- Alert ---------- */
|
|
2516
|
+
document.querySelectorAll('.js-alert-close').forEach(function(btn){
|
|
2517
|
+
btn.addEventListener('click', function(){
|
|
2518
|
+
var alertEl = btn.closest('.alert');
|
|
2519
|
+
if (!alertEl) return;
|
|
2520
|
+
alertEl.classList.add('is-leaving');
|
|
2521
|
+
setTimeout(function(){ if (alertEl.parentNode) alertEl.remove(); }, 200);
|
|
2522
|
+
});
|
|
2523
|
+
});
|
|
2524
|
+
|
|
2525
|
+
/* ---------- Toast ---------- */
|
|
2526
|
+
var toastIcons = {
|
|
2527
|
+
success: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/></svg>',
|
|
2528
|
+
danger: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 8v4m0 4h.01"/></svg>',
|
|
2529
|
+
info: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4m0-4h.01"/></svg>',
|
|
2530
|
+
warning: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.7 18-8-14a2 2 0 0 0-3.5 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3z"/><path d="M12 9v4m0 4h.01"/></svg>'
|
|
2531
|
+
};
|
|
2532
|
+
var toastCopy = {
|
|
2533
|
+
success: ['Cambios guardados', 'El proyecto se actualizó correctamente.'],
|
|
2534
|
+
danger: ['No se pudo guardar', 'Revisa tu conexión e inténtalo de nuevo.'],
|
|
2535
|
+
info: ['Exportación en curso', 'Te avisaremos cuando el archivo esté listo.'],
|
|
2536
|
+
warning: ['Conexión inestable', 'Los cambios se guardarán al reconectar.']
|
|
2537
|
+
};
|
|
2538
|
+
var toastCloseIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg>';
|
|
2539
|
+
var stack = document.getElementById('toastStack');
|
|
2540
|
+
document.querySelectorAll('[data-toast]').forEach(function(b){
|
|
2541
|
+
b.addEventListener('click', function(){
|
|
2542
|
+
if (!stack) return;
|
|
2543
|
+
if (stack.children.length >= 3) stack.removeChild(stack.firstChild);
|
|
2544
|
+
var kind = b.dataset.toast;
|
|
2545
|
+
var t = toastCopy[kind] || toastCopy.info;
|
|
2546
|
+
var toast = document.createElement('div');
|
|
2547
|
+
toast.className = 'toast toast--' + kind;
|
|
2548
|
+
toast.setAttribute('role', kind === 'danger' ? 'alert' : 'status');
|
|
2549
|
+
toast.innerHTML = toastIcons[kind] + '<div><div class="toast__title">' + t[0] + '</div><div class="toast__body">' + t[1] + '</div></div>' +
|
|
2550
|
+
'<button class="icon-btn icon-btn--ghost icon-btn--sm" aria-label="Cerrar notificación">' + toastCloseIcon + '</button>';
|
|
2551
|
+
stack.appendChild(toast);
|
|
2552
|
+
var timer, remaining = 5000, start = Date.now();
|
|
2553
|
+
function dismiss(){
|
|
2554
|
+
toast.classList.add('is-leaving');
|
|
2555
|
+
setTimeout(function(){ if (toast.parentNode) stack.removeChild(toast); }, 200);
|
|
2556
|
+
}
|
|
2557
|
+
function arm(ms){ timer = setTimeout(dismiss, ms); }
|
|
2558
|
+
arm(remaining);
|
|
2559
|
+
toast.addEventListener('mouseenter', function(){ clearTimeout(timer); remaining -= Date.now() - start; });
|
|
2560
|
+
toast.addEventListener('mouseleave', function(){ start = Date.now(); arm(Math.max(remaining, 800)); });
|
|
2561
|
+
var toastCloseBtn = toast.querySelector('.icon-btn');
|
|
2562
|
+
if (toastCloseBtn) {
|
|
2563
|
+
toastCloseBtn.addEventListener('click', function(){ clearTimeout(timer); dismiss(); });
|
|
2564
|
+
}
|
|
2565
|
+
});
|
|
2566
|
+
});
|
|
2567
|
+
|
|
2568
|
+
/* ---------- Modal ---------- */
|
|
2569
|
+
function wireModal(triggerId, modalId){
|
|
2570
|
+
var trigger = document.getElementById(triggerId);
|
|
2571
|
+
var modalEl = document.getElementById(modalId);
|
|
2572
|
+
if (!trigger || !modalEl) return;
|
|
2573
|
+
trigger.addEventListener('click', function(){ modalEl.hidden = false; });
|
|
2574
|
+
modalEl.addEventListener('click', function(e){
|
|
2575
|
+
if (e.target === modalEl || e.target.closest('[data-close-modal]')) modalEl.hidden = true;
|
|
2576
|
+
});
|
|
2577
|
+
document.addEventListener('keydown', function(e){
|
|
2578
|
+
if (e.key === 'Escape' && !modalEl.hidden) modalEl.hidden = true;
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2581
|
+
wireModal('openModal', 'demoModal');
|
|
2582
|
+
wireModal('openModalLg', 'demoModalLg');
|
|
2583
|
+
|
|
2584
|
+
/* ---------- Progress demo ---------- */
|
|
2585
|
+
var seq = [22, 47, 64, 81, 95], seqI = 2;
|
|
2586
|
+
function paintProgressRing(v){
|
|
2587
|
+
var ring = document.getElementById('pgRing');
|
|
2588
|
+
var ringBar = document.getElementById('pgRingBar');
|
|
2589
|
+
var ringVal = document.getElementById('pgRingVal');
|
|
2590
|
+
if (!ring || !ringBar) return;
|
|
2591
|
+
var r = parseFloat(ringBar.getAttribute('r'));
|
|
2592
|
+
var c = 2 * Math.PI * r;
|
|
2593
|
+
ringBar.style.strokeDasharray = c;
|
|
2594
|
+
ringBar.style.strokeDashoffset = c * (1 - v / 100);
|
|
2595
|
+
ring.setAttribute('aria-valuenow', v);
|
|
2596
|
+
if (ringVal) ringVal.textContent = v + '%';
|
|
2597
|
+
}
|
|
2598
|
+
var pgRingEl = document.getElementById('pgRing');
|
|
2599
|
+
if (pgRingEl) paintProgressRing(parseFloat(pgRingEl.getAttribute('data-value') || 0));
|
|
2600
|
+
var pgRandomBtn = document.getElementById('pgRandom');
|
|
2601
|
+
if (pgRandomBtn) {
|
|
2602
|
+
pgRandomBtn.addEventListener('click', function(){
|
|
2603
|
+
seqI = (seqI + 1) % seq.length;
|
|
2604
|
+
var v = seq[seqI];
|
|
2605
|
+
document.getElementById('pgBar').style.width = v + '%';
|
|
2606
|
+
document.getElementById('pgVal').textContent = v + ' %';
|
|
2607
|
+
document.getElementById('pgBar').parentNode.setAttribute('aria-valuenow', v);
|
|
2608
|
+
paintProgressRing(v);
|
|
2609
|
+
});
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
/* ---------- Slider ---------- */
|
|
2613
|
+
function paintSlider(s){
|
|
2614
|
+
var min = parseFloat(s.min || 0), max = parseFloat(s.max || 100);
|
|
2615
|
+
var pct = ((parseFloat(s.value) - min) / (max - min)) * 100;
|
|
2616
|
+
s.style.setProperty('--slider-fill', pct + '%');
|
|
2617
|
+
}
|
|
2618
|
+
document.querySelectorAll('.js-slider').forEach(function(s){
|
|
2619
|
+
paintSlider(s);
|
|
2620
|
+
s.addEventListener('input', function(){ paintSlider(s); });
|
|
2621
|
+
});
|
|
2622
|
+
var demoSlider = document.getElementById('demo-slider');
|
|
2623
|
+
var demoSliderValue = document.getElementById('demo-slider-value');
|
|
2624
|
+
if (demoSlider && demoSliderValue) {
|
|
2625
|
+
demoSlider.addEventListener('input', function(){
|
|
2626
|
+
demoSliderValue.textContent = '$ ' + Number(demoSlider.value).toLocaleString('es-MX');
|
|
2627
|
+
});
|
|
2628
|
+
}
|
|
2629
|
+
|
|
2630
|
+
/* ---------- Count-up ---------- */
|
|
2631
|
+
var fmt = {};
|
|
2632
|
+
function fmtFor(dec){ return fmt[dec] || (fmt[dec] = new Intl.NumberFormat('es-MX', { minimumFractionDigits: dec, maximumFractionDigits: dec })); }
|
|
2633
|
+
function countUp(el){
|
|
2634
|
+
var target = parseFloat(el.dataset.countup);
|
|
2635
|
+
var dec = parseInt(el.dataset.decimals || '0', 10);
|
|
2636
|
+
var prefix = el.dataset.prefix || '', suffix = el.dataset.suffix || '';
|
|
2637
|
+
if (reduced) { el.textContent = prefix + fmtFor(dec).format(target) + suffix; return; }
|
|
2638
|
+
var t0 = performance.now();
|
|
2639
|
+
function frame(t){
|
|
2640
|
+
var p = Math.min((t - t0) / 350, 1);
|
|
2641
|
+
var e = 1 - Math.pow(1 - p, 3);
|
|
2642
|
+
el.textContent = prefix + fmtFor(dec).format(target * e) + suffix;
|
|
2643
|
+
if (p < 1) requestAnimationFrame(frame);
|
|
2644
|
+
}
|
|
2645
|
+
requestAnimationFrame(frame);
|
|
2646
|
+
}
|
|
2647
|
+
var seen = new WeakSet();
|
|
2648
|
+
var cuObs = new IntersectionObserver(function(entries){
|
|
2649
|
+
entries.forEach(function(en){
|
|
2650
|
+
if (en.isIntersecting && !seen.has(en.target)) { seen.add(en.target); countUp(en.target); }
|
|
2651
|
+
});
|
|
2652
|
+
}, { threshold: .4 });
|
|
2653
|
+
document.querySelectorAll('[data-countup]').forEach(function(el){ cuObs.observe(el); });
|
|
2654
|
+
|
|
2655
|
+
/* ---------- Pagination (demo funcional) ---------- */
|
|
2656
|
+
var paginationEl = document.getElementById('paginationDemo');
|
|
2657
|
+
if (paginationEl) {
|
|
2658
|
+
var PAGINATION_TOTAL = 12;
|
|
2659
|
+
var paginationCurrent = 5;
|
|
2660
|
+
function renderPagination(){
|
|
2661
|
+
var pages = [];
|
|
2662
|
+
if (PAGINATION_TOTAL <= 7) {
|
|
2663
|
+
for (var i = 1; i <= PAGINATION_TOTAL; i++) pages.push(i);
|
|
2664
|
+
} else {
|
|
2665
|
+
pages.push(1);
|
|
2666
|
+
if (paginationCurrent > 3) pages.push('…');
|
|
2667
|
+
for (var p = Math.max(2, paginationCurrent - 1); p <= Math.min(PAGINATION_TOTAL - 1, paginationCurrent + 1); p++) pages.push(p);
|
|
2668
|
+
if (paginationCurrent < PAGINATION_TOTAL - 2) pages.push('…');
|
|
2669
|
+
pages.push(PAGINATION_TOTAL);
|
|
2670
|
+
}
|
|
2671
|
+
var html = '<li><button class="pagination__btn" data-page="prev" aria-label="Página anterior"' +
|
|
2672
|
+
(paginationCurrent === 1 ? ' disabled' : '') +
|
|
2673
|
+
'><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg></button></li>';
|
|
2674
|
+
pages.forEach(function(pg){
|
|
2675
|
+
if (pg === '…') {
|
|
2676
|
+
html += '<li><span class="pagination__ellipsis">…</span></li>';
|
|
2677
|
+
} else {
|
|
2678
|
+
html += '<li><button class="pagination__btn' + (pg === paginationCurrent ? ' is-active' : '') +
|
|
2679
|
+
'" data-page="' + pg + '"' + (pg === paginationCurrent ? ' aria-current="page"' : '') + '>' + pg + '</button></li>';
|
|
2680
|
+
}
|
|
2681
|
+
});
|
|
2682
|
+
html += '<li><button class="pagination__btn" data-page="next" aria-label="Página siguiente"' +
|
|
2683
|
+
(paginationCurrent === PAGINATION_TOTAL ? ' disabled' : '') +
|
|
2684
|
+
'><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg></button></li>';
|
|
2685
|
+
paginationEl.innerHTML = html;
|
|
2686
|
+
}
|
|
2687
|
+
paginationEl.addEventListener('click', function(e){
|
|
2688
|
+
var btn = e.target.closest('[data-page]');
|
|
2689
|
+
if (!btn || btn.disabled) return;
|
|
2690
|
+
var pg = btn.getAttribute('data-page');
|
|
2691
|
+
if (pg === 'prev') paginationCurrent = Math.max(1, paginationCurrent - 1);
|
|
2692
|
+
else if (pg === 'next') paginationCurrent = Math.min(PAGINATION_TOTAL, paginationCurrent + 1);
|
|
2693
|
+
else paginationCurrent = parseInt(pg, 10);
|
|
2694
|
+
renderPagination();
|
|
2695
|
+
});
|
|
2696
|
+
renderPagination();
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
/* ---------- Motion replay ---------- */
|
|
2700
|
+
var mReplayBtn = document.getElementById('mReplay');
|
|
2701
|
+
if (mReplayBtn) {
|
|
2702
|
+
mReplayBtn.addEventListener('click', function(){
|
|
2703
|
+
[['mBox1','ds-anim-enter'], ['mBox2','ds-anim-glow']].forEach(function(pair){
|
|
2704
|
+
var el = document.getElementById(pair[0]);
|
|
2705
|
+
el.classList.remove(pair[1]);
|
|
2706
|
+
void el.offsetWidth;
|
|
2707
|
+
el.classList.add(pair[1]);
|
|
2708
|
+
});
|
|
2709
|
+
});
|
|
2710
|
+
}
|
|
2711
|
+
})();
|
|
2712
|
+
</script>
|
|
2713
|
+
</body>
|
|
2714
|
+
</html>
|